| /** @file | |
| SMM Core Main Entry Point | |
| Copyright (c) 2009 - 2023, Intel Corporation. All rights reserved.<BR> | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| **/ | |
| #include "PiSmmCore.h" | |
| // | |
| // Physical pointer to private structure shared between SMM IPL and the SMM Core | |
| // | |
| SMM_CORE_PRIVATE_DATA *gSmmCorePrivate; | |
| // | |
| // SMM Core global variable for SMM System Table. Only accessed as a physical structure in SMRAM. | |
| // | |
| EFI_SMM_SYSTEM_TABLE2 gSmmCoreSmst = { | |
| { | |
| SMM_SMST_SIGNATURE, | |
| EFI_SMM_SYSTEM_TABLE2_REVISION, | |
| sizeof (gSmmCoreSmst.Hdr) | |
| }, | |
| NULL, // SmmFirmwareVendor | |
| 0, // SmmFirmwareRevision | |
| SmmInstallConfigurationTable, | |
| { | |
| { | |
| (EFI_SMM_CPU_IO2)SmmEfiNotAvailableYetArg5, // SmmMemRead | |
| (EFI_SMM_CPU_IO2)SmmEfiNotAvailableYetArg5 // SmmMemWrite | |
| }, | |
| { | |
| (EFI_SMM_CPU_IO2)SmmEfiNotAvailableYetArg5, // SmmIoRead | |
| (EFI_SMM_CPU_IO2)SmmEfiNotAvailableYetArg5 // SmmIoWrite | |
| } | |
| }, | |
| SmmAllocatePool, | |
| SmmFreePool, | |
| SmmAllocatePages, | |
| SmmFreePages, | |
| NULL, // SmmStartupThisAp | |
| 0, // CurrentlyExecutingCpu | |
| 0, // NumberOfCpus | |
| NULL, // CpuSaveStateSize | |
| NULL, // CpuSaveState | |
| 0, // NumberOfTableEntries | |
| NULL, // SmmConfigurationTable | |
| SmmInstallProtocolInterface, | |
| SmmUninstallProtocolInterface, | |
| SmmHandleProtocol, | |
| SmmRegisterProtocolNotify, | |
| SmmLocateHandle, | |
| SmmLocateProtocol, | |
| SmiManage, | |
| SmiHandlerRegister, | |
| SmiHandlerUnRegister | |
| }; | |
| // | |
| // Flag to determine if the platform has performed a legacy boot. | |
| // If this flag is TRUE, then the runtime code and runtime data associated with the | |
| // SMM IPL are converted to free memory, so the SMM Core must guarantee that is | |
| // does not touch of the code/data associated with the SMM IPL if this flag is TRUE. | |
| // | |
| BOOLEAN mInLegacyBoot = FALSE; | |
| // | |
| // Flag to determine if it is during S3 resume. | |
| // It will be set in S3 entry callback and cleared at EndOfS3Resume. | |
| // | |
| BOOLEAN mDuringS3Resume = FALSE; | |
| // | |
| // Flag to determine if platform enabled S3. | |
| // Get the value from PcdAcpiS3Enable. | |
| // | |
| BOOLEAN mAcpiS3Enable = FALSE; | |
| // | |
| // Table of SMI Handlers that are registered by the SMM Core when it is initialized | |
| // | |
| SMM_CORE_SMI_HANDLERS mSmmCoreSmiHandlers[] = { | |
| { SmmDriverDispatchHandler, &gEfiEventDxeDispatchGuid, NULL, TRUE }, | |
| { SmmReadyToLockHandler, &gEfiDxeSmmReadyToLockProtocolGuid, NULL, TRUE }, | |
| { SmmLegacyBootHandler, &gEfiEventLegacyBootGuid, NULL, FALSE }, | |
| { SmmExitBootServicesHandler, &gEfiEventExitBootServicesGuid, NULL, FALSE }, | |
| { SmmReadyToBootHandler, &gEfiEventReadyToBootGuid, NULL, FALSE }, | |
| { SmmEndOfDxeHandler, &gEfiEndOfDxeEventGroupGuid, NULL, TRUE }, | |
| { NULL, NULL, NULL, FALSE } | |
| }; | |
| // | |
| // Table of SMI Handlers that are registered by the SMM Core when it is initialized | |
| // | |
| SMM_CORE_SMI_HANDLERS mSmmCoreS3SmiHandlers[] = { | |
| { SmmS3SmmInitDoneHandler, &gEdkiiS3SmmInitDoneGuid, NULL, FALSE }, | |
| { SmmEndOfS3ResumeHandler, &gEdkiiEndOfS3ResumeGuid, NULL, FALSE }, | |
| { NULL, NULL, NULL, FALSE } | |
| }; | |
| UINTN mFullSmramRangeCount; | |
| EFI_SMRAM_DESCRIPTOR *mFullSmramRanges; | |
| EFI_SMM_DRIVER_ENTRY *mSmmCoreDriverEntry; | |
| EFI_LOADED_IMAGE_PROTOCOL *mSmmCoreLoadedImage; | |
| /** | |
| Place holder function until all the SMM System Table Service are available. | |
| Note: This function is only used by SMRAM invocation. It is never used by DXE invocation. | |
| @param Arg1 Undefined | |
| @param Arg2 Undefined | |
| @param Arg3 Undefined | |
| @param Arg4 Undefined | |
| @param Arg5 Undefined | |
| @return EFI_NOT_AVAILABLE_YET | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| SmmEfiNotAvailableYetArg5 ( | |
| UINTN Arg1, | |
| UINTN Arg2, | |
| UINTN Arg3, | |
| UINTN Arg4, | |
| UINTN Arg5 | |
| ) | |
| { | |
| // | |
| // This function should never be executed. If it does, then the architectural protocols | |
| // have not been designed correctly. | |
| // | |
| return EFI_NOT_AVAILABLE_YET; | |
| } | |
| /** | |
| Software SMI handler that is called when a Legacy Boot event is signalled. The SMM | |
| Core uses this signal to know that a Legacy Boot has been performed and that | |
| gSmmCorePrivate that is shared between the UEFI and SMM execution environments can | |
| not be accessed from SMM anymore since that structure is considered free memory by | |
| a legacy OS. Then the SMM Core also install SMM Legacy Boot protocol to notify SMM | |
| driver that system enter legacy boot. | |
| @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. | |
| @return Status Code | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| SmmLegacyBootHandler ( | |
| IN EFI_HANDLE DispatchHandle, | |
| IN CONST VOID *Context OPTIONAL, | |
| IN OUT VOID *CommBuffer OPTIONAL, | |
| IN OUT UINTN *CommBufferSize OPTIONAL | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_HANDLE SmmHandle; | |
| UINTN Index; | |
| // | |
| // Install SMM Legacy Boot protocol. | |
| // | |
| SmmHandle = NULL; | |
| Status = SmmInstallProtocolInterface ( | |
| &SmmHandle, | |
| &gEdkiiSmmLegacyBootProtocolGuid, | |
| EFI_NATIVE_INTERFACE, | |
| NULL | |
| ); | |
| mInLegacyBoot = TRUE; | |
| SmiHandlerUnRegister (DispatchHandle); | |
| // | |
| // It is legacy boot, unregister ExitBootService SMI handler. | |
| // | |
| for (Index = 0; mSmmCoreSmiHandlers[Index].HandlerType != NULL; Index++) { | |
| if (CompareGuid (mSmmCoreSmiHandlers[Index].HandlerType, &gEfiEventExitBootServicesGuid)) { | |
| SmiHandlerUnRegister (mSmmCoreSmiHandlers[Index].DispatchHandle); | |
| break; | |
| } | |
| } | |
| return Status; | |
| } | |
| /** | |
| Software SMI handler that is called when an Exit Boot Services event is signalled. | |
| Then the SMM Core also install SMM Exit Boot Services protocol to notify SMM driver | |
| that system enter exit boot services. | |
| @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. | |
| @return Status Code | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| SmmExitBootServicesHandler ( | |
| IN EFI_HANDLE DispatchHandle, | |
| IN CONST VOID *Context OPTIONAL, | |
| IN OUT VOID *CommBuffer OPTIONAL, | |
| IN OUT UINTN *CommBufferSize OPTIONAL | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_HANDLE SmmHandle; | |
| UINTN Index; | |
| // | |
| // Install SMM Exit Boot Services protocol. | |
| // | |
| SmmHandle = NULL; | |
| Status = SmmInstallProtocolInterface ( | |
| &SmmHandle, | |
| &gEdkiiSmmExitBootServicesProtocolGuid, | |
| EFI_NATIVE_INTERFACE, | |
| NULL | |
| ); | |
| SmiHandlerUnRegister (DispatchHandle); | |
| // | |
| // It is UEFI boot, unregister LegacyBoot SMI handler. | |
| // | |
| for (Index = 0; mSmmCoreSmiHandlers[Index].HandlerType != NULL; Index++) { | |
| if (CompareGuid (mSmmCoreSmiHandlers[Index].HandlerType, &gEfiEventLegacyBootGuid)) { | |
| SmiHandlerUnRegister (mSmmCoreSmiHandlers[Index].DispatchHandle); | |
| break; | |
| } | |
| } | |
| return Status; | |
| } | |
| /** | |
| Main entry point for an SMM handler dispatch or communicate-based callback. | |
| @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister(). | |
| @param[in] Context Points to an optional handler context which was specified when the | |
| handler was registered. | |
| @param[in,out] CommBuffer A pointer to a collection of data in memory that will | |
| be conveyed from a non-SMM environment into an SMM environment. | |
| @param[in,out] CommBufferSize The size of the CommBuffer. | |
| @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers | |
| should still be called. | |
| @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should | |
| still be called. | |
| @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still | |
| be called. | |
| @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| SmmS3EntryCallBack ( | |
| IN EFI_HANDLE DispatchHandle, | |
| IN CONST VOID *Context OPTIONAL, | |
| IN OUT VOID *CommBuffer OPTIONAL, | |
| IN OUT UINTN *CommBufferSize OPTIONAL | |
| ) | |
| { | |
| mDuringS3Resume = TRUE; | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Software SMI handler that is called when an Ready To Boot event is signalled. | |
| Then the SMM Core also install SMM Ready To Boot protocol to notify SMM driver | |
| that system enter ready to boot. | |
| @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. | |
| @return Status Code | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| SmmReadyToBootHandler ( | |
| IN EFI_HANDLE DispatchHandle, | |
| IN CONST VOID *Context OPTIONAL, | |
| IN OUT VOID *CommBuffer OPTIONAL, | |
| IN OUT UINTN *CommBufferSize OPTIONAL | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_HANDLE SmmHandle; | |
| PERF_CALLBACK_BEGIN (&gEfiEventReadyToBootGuid); | |
| // | |
| // Install SMM Ready To Boot protocol. | |
| // | |
| SmmHandle = NULL; | |
| Status = SmmInstallProtocolInterface ( | |
| &SmmHandle, | |
| &gEdkiiSmmReadyToBootProtocolGuid, | |
| EFI_NATIVE_INTERFACE, | |
| NULL | |
| ); | |
| SmiHandlerUnRegister (DispatchHandle); | |
| PERF_CALLBACK_END (&gEfiEventReadyToBootGuid); | |
| return Status; | |
| } | |
| /** | |
| Software SMI handler that is called when the DxeSmmReadyToLock protocol is added | |
| or if gEfiEventReadyToBootGuid is signalled. This function unregisters the | |
| Software SMIs that are nor required after SMRAM is locked and installs the | |
| SMM Ready To Lock Protocol so SMM Drivers are informed that SMRAM is about | |
| to be locked. It also verifies the SMM CPU I/O 2 Protocol has been installed | |
| and NULLs gBS and gST because they can not longer be used after SMRAM is locked. | |
| @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. | |
| @return Status Code | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| SmmReadyToLockHandler ( | |
| IN EFI_HANDLE DispatchHandle, | |
| IN CONST VOID *Context OPTIONAL, | |
| IN OUT VOID *CommBuffer OPTIONAL, | |
| IN OUT UINTN *CommBufferSize OPTIONAL | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| UINTN Index; | |
| EFI_HANDLE SmmHandle; | |
| VOID *Interface; | |
| PERF_CALLBACK_BEGIN (&gEfiDxeSmmReadyToLockProtocolGuid); | |
| // | |
| // Unregister SMI Handlers that are no required after the SMM driver dispatch is stopped | |
| // | |
| for (Index = 0; mSmmCoreSmiHandlers[Index].HandlerType != NULL; Index++) { | |
| if (mSmmCoreSmiHandlers[Index].UnRegister) { | |
| SmiHandlerUnRegister (mSmmCoreSmiHandlers[Index].DispatchHandle); | |
| } | |
| } | |
| // | |
| // Install SMM Ready to lock protocol | |
| // | |
| SmmHandle = NULL; | |
| Status = SmmInstallProtocolInterface ( | |
| &SmmHandle, | |
| &gEfiSmmReadyToLockProtocolGuid, | |
| EFI_NATIVE_INTERFACE, | |
| NULL | |
| ); | |
| // | |
| // Make sure SMM CPU I/O 2 Protocol has been installed into the handle database | |
| // | |
| Status = SmmLocateProtocol (&gEfiSmmCpuIo2ProtocolGuid, NULL, &Interface); | |
| // | |
| // Print a message on a debug build if the SMM CPU I/O 2 Protocol is not installed | |
| // | |
| DEBUG_CODE_BEGIN (); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_ERROR, "\nSMM: SmmCpuIo Arch Protocol not present!!\n")); | |
| } | |
| DEBUG_CODE_END (); | |
| // | |
| // Assert if the CPU I/O 2 Protocol is not installed | |
| // | |
| ASSERT_EFI_ERROR (Status); | |
| // | |
| // Display any drivers that were not dispatched because dependency expression | |
| // evaluated to false if this is a debug build | |
| // | |
| DEBUG_CODE_BEGIN (); | |
| SmmDisplayDiscoveredNotDispatched (); | |
| DEBUG_CODE_END (); | |
| // | |
| // Not allowed to use gST or gBS after lock | |
| // | |
| gST = NULL; | |
| gBS = NULL; | |
| SmramProfileReadyToLock (); | |
| PERF_CALLBACK_END (&gEfiDxeSmmReadyToLockProtocolGuid); | |
| return Status; | |
| } | |
| /** | |
| Software SMI handler that is called when the EndOfDxe event is signalled. | |
| This function installs the SMM EndOfDxe Protocol so SMM Drivers are informed that | |
| platform code will invoke 3rd part code. | |
| @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. | |
| @return Status Code | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| SmmEndOfDxeHandler ( | |
| IN EFI_HANDLE DispatchHandle, | |
| IN CONST VOID *Context OPTIONAL, | |
| IN OUT VOID *CommBuffer OPTIONAL, | |
| IN OUT UINTN *CommBufferSize OPTIONAL | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_HANDLE SmmHandle; | |
| EFI_SMM_SX_DISPATCH2_PROTOCOL *SxDispatch; | |
| EFI_SMM_SX_REGISTER_CONTEXT EntryRegisterContext; | |
| EFI_HANDLE S3EntryHandle; | |
| DEBUG ((DEBUG_INFO, "SmmEndOfDxeHandler\n")); | |
| PERF_CALLBACK_BEGIN (&gEfiEndOfDxeEventGroupGuid); | |
| // | |
| // Install SMM EndOfDxe protocol | |
| // | |
| SmmHandle = NULL; | |
| Status = SmmInstallProtocolInterface ( | |
| &SmmHandle, | |
| &gEfiSmmEndOfDxeProtocolGuid, | |
| EFI_NATIVE_INTERFACE, | |
| NULL | |
| ); | |
| if (mAcpiS3Enable) { | |
| // | |
| // Locate SmmSxDispatch2 protocol. | |
| // | |
| Status = SmmLocateProtocol ( | |
| &gEfiSmmSxDispatch2ProtocolGuid, | |
| NULL, | |
| (VOID **)&SxDispatch | |
| ); | |
| if (!EFI_ERROR (Status) && (SxDispatch != NULL)) { | |
| // | |
| // Register a S3 entry callback function to | |
| // determine if it will be during S3 resume. | |
| // | |
| EntryRegisterContext.Type = SxS3; | |
| EntryRegisterContext.Phase = SxEntry; | |
| Status = SxDispatch->Register ( | |
| SxDispatch, | |
| SmmS3EntryCallBack, | |
| &EntryRegisterContext, | |
| &S3EntryHandle | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| } | |
| } | |
| PERF_CALLBACK_END (&gEfiEndOfDxeEventGroupGuid); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Software SMI handler that is called when the S3SmmInitDone signal is triggered. | |
| This function installs the SMM S3SmmInitDone Protocol so SMM Drivers are informed that | |
| S3 SMM initialization has been done. | |
| @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. | |
| @return Status Code | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| SmmS3SmmInitDoneHandler ( | |
| IN EFI_HANDLE DispatchHandle, | |
| IN CONST VOID *Context OPTIONAL, | |
| IN OUT VOID *CommBuffer OPTIONAL, | |
| IN OUT UINTN *CommBufferSize OPTIONAL | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_HANDLE SmmHandle; | |
| DEBUG ((DEBUG_INFO, "SmmS3SmmInitDoneHandler\n")); | |
| if (!mDuringS3Resume) { | |
| DEBUG ((DEBUG_ERROR, "It is not during S3 resume\n")); | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // Install SMM S3SmmInitDone protocol | |
| // | |
| SmmHandle = NULL; | |
| Status = SmmInstallProtocolInterface ( | |
| &SmmHandle, | |
| &gEdkiiS3SmmInitDoneGuid, | |
| EFI_NATIVE_INTERFACE, | |
| NULL | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| // | |
| // Uninstall the protocol here because the comsumer just hook the | |
| // installation event. | |
| // | |
| Status = SmmUninstallProtocolInterface ( | |
| SmmHandle, | |
| &gEdkiiS3SmmInitDoneGuid, | |
| NULL | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| return Status; | |
| } | |
| /** | |
| Software SMI handler that is called when the EndOfS3Resume signal is triggered. | |
| This function installs the SMM EndOfS3Resume Protocol so SMM Drivers are informed that | |
| S3 resume has finished. | |
| @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. | |
| @return Status Code | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| SmmEndOfS3ResumeHandler ( | |
| IN EFI_HANDLE DispatchHandle, | |
| IN CONST VOID *Context OPTIONAL, | |
| IN OUT VOID *CommBuffer OPTIONAL, | |
| IN OUT UINTN *CommBufferSize OPTIONAL | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_HANDLE SmmHandle; | |
| DEBUG ((DEBUG_INFO, "SmmEndOfS3ResumeHandler\n")); | |
| if (!mDuringS3Resume) { | |
| DEBUG ((DEBUG_ERROR, "It is not during S3 resume\n")); | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // Install SMM EndOfS3Resume protocol | |
| // | |
| SmmHandle = NULL; | |
| Status = SmmInstallProtocolInterface ( | |
| &SmmHandle, | |
| &gEdkiiEndOfS3ResumeGuid, | |
| EFI_NATIVE_INTERFACE, | |
| NULL | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| // | |
| // Uninstall the protocol here because the consumer just hook the | |
| // installation event. | |
| // | |
| Status = SmmUninstallProtocolInterface ( | |
| SmmHandle, | |
| &gEdkiiEndOfS3ResumeGuid, | |
| NULL | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| mDuringS3Resume = FALSE; | |
| return Status; | |
| } | |
| /** | |
| Determine if two buffers overlap in memory. | |
| @param[in] Buff1 Pointer to first buffer | |
| @param[in] Size1 Size of Buff1 | |
| @param[in] Buff2 Pointer to second buffer | |
| @param[in] Size2 Size of Buff2 | |
| @retval TRUE Buffers overlap in memory. | |
| @retval TRUE Math error. Prevents potential math over and underflows. | |
| @retval FALSE Buffer doesn't overlap. | |
| **/ | |
| BOOLEAN | |
| InternalIsBufferOverlapped ( | |
| IN UINT8 *Buff1, | |
| IN UINTN Size1, | |
| IN UINT8 *Buff2, | |
| IN UINTN Size2 | |
| ) | |
| { | |
| UINTN End1; | |
| UINTN End2; | |
| BOOLEAN IsOverUnderflow1; | |
| BOOLEAN IsOverUnderflow2; | |
| // Check for over or underflow | |
| IsOverUnderflow1 = EFI_ERROR (SafeUintnAdd ((UINTN)Buff1, Size1, &End1)); | |
| IsOverUnderflow2 = EFI_ERROR (SafeUintnAdd ((UINTN)Buff2, Size2, &End2)); | |
| if (IsOverUnderflow1 || IsOverUnderflow2) { | |
| return TRUE; | |
| } | |
| // | |
| // If buff1's end is less than the start of buff2, then it's ok. | |
| // Also, if buff1's start is beyond buff2's end, then it's ok. | |
| // | |
| if ((End1 <= (UINTN)Buff2) || ((UINTN)Buff1 >= End2)) { | |
| return FALSE; | |
| } | |
| return TRUE; | |
| } | |
| /** | |
| The main entry point to SMM Foundation. | |
| Note: This function is only used by SMRAM invocation. It is never used by DXE invocation. | |
| @param SmmEntryContext Processor information and functionality | |
| needed by SMM Foundation. | |
| **/ | |
| VOID | |
| EFIAPI | |
| SmmEntryPoint ( | |
| IN CONST EFI_SMM_ENTRY_CONTEXT *SmmEntryContext | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_SMM_COMMUNICATE_HEADER *CommunicateHeader; | |
| BOOLEAN InLegacyBoot; | |
| BOOLEAN IsOverlapped; | |
| BOOLEAN IsOverUnderflow; | |
| VOID *CommunicationBuffer; | |
| UINTN BufferSize; | |
| PERF_FUNCTION_BEGIN (); | |
| // | |
| // Update SMST with contents of the SmmEntryContext structure | |
| // | |
| gSmmCoreSmst.SmmStartupThisAp = SmmEntryContext->SmmStartupThisAp; | |
| gSmmCoreSmst.CurrentlyExecutingCpu = SmmEntryContext->CurrentlyExecutingCpu; | |
| gSmmCoreSmst.NumberOfCpus = SmmEntryContext->NumberOfCpus; | |
| gSmmCoreSmst.CpuSaveStateSize = SmmEntryContext->CpuSaveStateSize; | |
| gSmmCoreSmst.CpuSaveState = SmmEntryContext->CpuSaveState; | |
| // | |
| // Call platform hook before Smm Dispatch | |
| // | |
| PERF_START (NULL, "PlatformHookBeforeSmmDispatch", NULL, 0); | |
| PlatformHookBeforeSmmDispatch (); | |
| PERF_END (NULL, "PlatformHookBeforeSmmDispatch", NULL, 0); | |
| // | |
| // Call memory management hook function | |
| // | |
| SmmEntryPointMemoryManagementHook (); | |
| // | |
| // If a legacy boot has occurred, then make sure gSmmCorePrivate is not accessed | |
| // | |
| InLegacyBoot = mInLegacyBoot; | |
| if (!InLegacyBoot) { | |
| // | |
| // Mark the InSmm flag as TRUE, it will be used by SmmBase2 protocol | |
| // | |
| gSmmCorePrivate->InSmm = TRUE; | |
| // | |
| // Check to see if this is a Synchronous SMI sent through the SMM Communication | |
| // Protocol or an Asynchronous SMI | |
| // | |
| CommunicationBuffer = gSmmCorePrivate->CommunicationBuffer; | |
| BufferSize = gSmmCorePrivate->BufferSize; | |
| if (CommunicationBuffer != NULL) { | |
| // | |
| // Synchronous SMI for SMM Core or request from Communicate protocol | |
| // | |
| IsOverlapped = InternalIsBufferOverlapped ( | |
| (UINT8 *)CommunicationBuffer, | |
| BufferSize, | |
| (UINT8 *)gSmmCorePrivate, | |
| sizeof (*gSmmCorePrivate) | |
| ); | |
| // | |
| // Check for over or underflows | |
| // | |
| IsOverUnderflow = EFI_ERROR (SafeUintnSub (BufferSize, OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data), &BufferSize)); | |
| if (!SmmIsBufferOutsideSmmValid ((UINTN)CommunicationBuffer, BufferSize) || | |
| IsOverlapped || IsOverUnderflow) | |
| { | |
| // | |
| // If CommunicationBuffer is not in valid address scope, | |
| // or there is overlap between gSmmCorePrivate and CommunicationBuffer, | |
| // or there is over or underflow, | |
| // return EFI_INVALID_PARAMETER | |
| // | |
| gSmmCorePrivate->CommunicationBuffer = NULL; | |
| gSmmCorePrivate->ReturnStatus = EFI_ACCESS_DENIED; | |
| } else { | |
| CommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *)CommunicationBuffer; | |
| // BufferSize was updated by the SafeUintnSub() call above. | |
| Status = SmiManage ( | |
| &CommunicateHeader->HeaderGuid, | |
| NULL, | |
| CommunicateHeader->Data, | |
| &BufferSize | |
| ); | |
| // | |
| // Update CommunicationBuffer, BufferSize and ReturnStatus | |
| // Communicate service finished, reset the pointer to CommBuffer to NULL | |
| // | |
| gSmmCorePrivate->BufferSize = BufferSize + OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data); | |
| gSmmCorePrivate->CommunicationBuffer = NULL; | |
| gSmmCorePrivate->ReturnStatus = (Status == EFI_SUCCESS) ? EFI_SUCCESS : EFI_NOT_FOUND; | |
| } | |
| } | |
| } | |
| // | |
| // Process Asynchronous SMI sources | |
| // | |
| SmiManage (NULL, NULL, NULL, NULL); | |
| // | |
| // Call platform hook after Smm Dispatch | |
| // | |
| PERF_START (NULL, "PlatformHookAfterSmmDispatch", NULL, 0); | |
| PlatformHookAfterSmmDispatch (); | |
| PERF_END (NULL, "PlatformHookAfterSmmDispatch", NULL, 0); | |
| // | |
| // If a legacy boot has occurred, then make sure gSmmCorePrivate is not accessed | |
| // | |
| if (!InLegacyBoot) { | |
| // | |
| // Clear the InSmm flag as we are going to leave SMM | |
| // | |
| gSmmCorePrivate->InSmm = FALSE; | |
| } | |
| PERF_FUNCTION_END (); | |
| } | |
| /** | |
| Install LoadedImage protocol for SMM Core. | |
| **/ | |
| VOID | |
| SmmCoreInstallLoadedImage ( | |
| VOID | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_HANDLE Handle; | |
| // | |
| // Allocate a Loaded Image Protocol in EfiBootServicesData | |
| // | |
| Status = gBS->AllocatePool (EfiBootServicesData, sizeof (EFI_LOADED_IMAGE_PROTOCOL), (VOID **)&mSmmCoreLoadedImage); | |
| ASSERT_EFI_ERROR (Status); | |
| ZeroMem (mSmmCoreLoadedImage, sizeof (EFI_LOADED_IMAGE_PROTOCOL)); | |
| // | |
| // Fill in the remaining fields of the Loaded Image Protocol instance. | |
| // Note: ImageBase is an SMRAM address that can not be accessed outside of SMRAM if SMRAM window is closed. | |
| // | |
| mSmmCoreLoadedImage->Revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION; | |
| mSmmCoreLoadedImage->ParentHandle = gSmmCorePrivate->SmmIplImageHandle; | |
| mSmmCoreLoadedImage->SystemTable = gST; | |
| mSmmCoreLoadedImage->ImageBase = (VOID *)(UINTN)gSmmCorePrivate->PiSmmCoreImageBase; | |
| mSmmCoreLoadedImage->ImageSize = gSmmCorePrivate->PiSmmCoreImageSize; | |
| mSmmCoreLoadedImage->ImageCodeType = EfiRuntimeServicesCode; | |
| mSmmCoreLoadedImage->ImageDataType = EfiRuntimeServicesData; | |
| // | |
| // Create a new image handle in the UEFI handle database for the SMM Driver | |
| // | |
| Handle = NULL; | |
| Status = gBS->InstallMultipleProtocolInterfaces ( | |
| &Handle, | |
| &gEfiLoadedImageProtocolGuid, | |
| mSmmCoreLoadedImage, | |
| NULL | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| // | |
| // Allocate a Loaded Image Protocol in SMM | |
| // | |
| Status = SmmAllocatePool (EfiRuntimeServicesData, sizeof (EFI_SMM_DRIVER_ENTRY), (VOID **)&mSmmCoreDriverEntry); | |
| ASSERT_EFI_ERROR (Status); | |
| ZeroMem (mSmmCoreDriverEntry, sizeof (EFI_SMM_DRIVER_ENTRY)); | |
| // | |
| // Fill in the remaining fields of the Loaded Image Protocol instance. | |
| // | |
| mSmmCoreDriverEntry->Signature = EFI_SMM_DRIVER_ENTRY_SIGNATURE; | |
| mSmmCoreDriverEntry->SmmLoadedImage.Revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION; | |
| mSmmCoreDriverEntry->SmmLoadedImage.ParentHandle = gSmmCorePrivate->SmmIplImageHandle; | |
| mSmmCoreDriverEntry->SmmLoadedImage.SystemTable = gST; | |
| mSmmCoreDriverEntry->SmmLoadedImage.ImageBase = (VOID *)(UINTN)gSmmCorePrivate->PiSmmCoreImageBase; | |
| mSmmCoreDriverEntry->SmmLoadedImage.ImageSize = gSmmCorePrivate->PiSmmCoreImageSize; | |
| mSmmCoreDriverEntry->SmmLoadedImage.ImageCodeType = EfiRuntimeServicesCode; | |
| mSmmCoreDriverEntry->SmmLoadedImage.ImageDataType = EfiRuntimeServicesData; | |
| mSmmCoreDriverEntry->ImageEntryPoint = gSmmCorePrivate->PiSmmCoreEntryPoint; | |
| mSmmCoreDriverEntry->ImageBuffer = gSmmCorePrivate->PiSmmCoreImageBase; | |
| mSmmCoreDriverEntry->NumberOfPage = EFI_SIZE_TO_PAGES ((UINTN)gSmmCorePrivate->PiSmmCoreImageSize); | |
| // | |
| // Create a new image handle in the SMM handle database for the SMM Driver | |
| // | |
| mSmmCoreDriverEntry->SmmImageHandle = NULL; | |
| Status = SmmInstallProtocolInterface ( | |
| &mSmmCoreDriverEntry->SmmImageHandle, | |
| &gEfiLoadedImageProtocolGuid, | |
| EFI_NATIVE_INTERFACE, | |
| &mSmmCoreDriverEntry->SmmLoadedImage | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| return; | |
| } | |
| /** | |
| The Entry Point for SMM Core | |
| Install DXE Protocols and reload SMM Core into SMRAM and register SMM Core | |
| EntryPoint on the SMI vector. | |
| Note: This function is called for both DXE invocation and SMRAM invocation. | |
| @param ImageHandle The firmware allocated handle for the EFI image. | |
| @param SystemTable A pointer to the EFI System Table. | |
| @retval EFI_SUCCESS The entry point is executed successfully. | |
| @retval Other Some error occurred when executing this entry point. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| SmmMain ( | |
| IN EFI_HANDLE ImageHandle, | |
| IN EFI_SYSTEM_TABLE *SystemTable | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| UINTN Index; | |
| // | |
| // Get SMM Core Private context passed in from SMM IPL in ImageHandle. | |
| // | |
| gSmmCorePrivate = (SMM_CORE_PRIVATE_DATA *)ImageHandle; | |
| // | |
| // Fill in SMRAM physical address for the SMM Services Table and the SMM Entry Point. | |
| // | |
| gSmmCorePrivate->Smst = &gSmmCoreSmst; | |
| gSmmCorePrivate->SmmEntryPoint = SmmEntryPoint; | |
| // | |
| // No need to initialize memory service. | |
| // It is done in constructor of PiSmmCoreMemoryAllocationLib(), | |
| // so that the library linked with PiSmmCore can use AllocatePool() in constructor. | |
| // | |
| SmramProfileInit (); | |
| // | |
| // Copy FullSmramRanges to SMRAM | |
| // | |
| mFullSmramRangeCount = gSmmCorePrivate->SmramRangeCount; | |
| mFullSmramRanges = AllocatePool (mFullSmramRangeCount * sizeof (EFI_SMRAM_DESCRIPTOR)); | |
| ASSERT (mFullSmramRanges != NULL); | |
| CopyMem (mFullSmramRanges, gSmmCorePrivate->SmramRanges, mFullSmramRangeCount * sizeof (EFI_SMRAM_DESCRIPTOR)); | |
| // | |
| // Register all SMI Handlers required by the SMM Core | |
| // | |
| for (Index = 0; mSmmCoreSmiHandlers[Index].HandlerType != NULL; Index++) { | |
| Status = SmiHandlerRegister ( | |
| mSmmCoreSmiHandlers[Index].Handler, | |
| mSmmCoreSmiHandlers[Index].HandlerType, | |
| &mSmmCoreSmiHandlers[Index].DispatchHandle | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| } | |
| mAcpiS3Enable = PcdGetBool (PcdAcpiS3Enable); | |
| if (mAcpiS3Enable) { | |
| // | |
| // Register all S3 related SMI Handlers required by the SMM Core | |
| // | |
| for (Index = 0; mSmmCoreS3SmiHandlers[Index].HandlerType != NULL; Index++) { | |
| Status = SmiHandlerRegister ( | |
| mSmmCoreS3SmiHandlers[Index].Handler, | |
| mSmmCoreS3SmiHandlers[Index].HandlerType, | |
| &mSmmCoreS3SmiHandlers[Index].DispatchHandle | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| } | |
| } | |
| RegisterSmramProfileHandler (); | |
| SmramProfileInstallProtocol (); | |
| SmmCoreInstallLoadedImage (); | |
| SmmCoreInitializeMemoryAttributesTable (); | |
| SmmCoreInitializeSmiHandlerProfile (); | |
| return EFI_SUCCESS; | |
| } |