From c8ec22a266cdd134ac99c3021003710130613a40 Mon Sep 17 00:00:00 2001 From: jyao1 Date: Tue, 29 Jul 2014 02:21:52 +0000 Subject: [PATCH] Add IntelFspPkg to support create FSP bin based on EDKII. Contributed-under: TianoCore Contribution Agreement 1.0 Signed off by: Ravi Rangarajan Reviewed by: Maurice Ma Reviewed by: Jiewen Yao Reviewed by: Giri Mudusuru Reviewed by: Liming Gao git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15705 6f19259b-4bc3-4df7-8a09-765794883524 --- IntelFspPkg/FspDxeIpl/DxeIpl.c | 464 +++++++++ IntelFspPkg/FspDxeIpl/DxeIpl.h | 192 ++++ IntelFspPkg/FspDxeIpl/FspDxeIpl.inf | 70 ++ IntelFspPkg/FspSecCore/FspSecCore.inf | 76 ++ IntelFspPkg/FspSecCore/Ia32/FspApiEntry.asm | 552 +++++++++++ IntelFspPkg/FspSecCore/Ia32/FspApiEntry.s | 611 ++++++++++++ IntelFspPkg/FspSecCore/Ia32/InitializeFpu.asm | 79 ++ IntelFspPkg/FspSecCore/Ia32/InitializeFpu.s | 73 ++ IntelFspPkg/FspSecCore/Ia32/ResetVec.asm16 | 103 ++ .../FspSecCore/Ia32/SaveRestoreSse.inc | 103 ++ IntelFspPkg/FspSecCore/Ia32/Stack.asm | 82 ++ IntelFspPkg/FspSecCore/Ia32/Stacks.s | 88 ++ IntelFspPkg/FspSecCore/Ia32/UcodeLoad.inc | 63 ++ IntelFspPkg/FspSecCore/SecFsp.c | 268 ++++++ IntelFspPkg/FspSecCore/SecFsp.h | 97 ++ IntelFspPkg/FspSecCore/SecMain.c | 208 ++++ IntelFspPkg/FspSecCore/SecMain.h | 134 +++ .../FspSecCore/Vtf0/Bin/ResetVec.ia32.raw | Bin 0 -> 68 bytes IntelFspPkg/FspSecCore/Vtf0/Build.py | 53 ++ .../FspSecCore/Vtf0/Ia16/ResetVec.asm16 | 103 ++ .../FspSecCore/Vtf0/ResetVectorCode.asm | 17 + .../Vtf0/Tools/FixupForRawSection.py | 110 +++ IntelFspPkg/Include/Guid/GuidHobFsp.h | 22 + IntelFspPkg/Include/Library/CacheAsRamLib.h | 30 + IntelFspPkg/Include/Library/CacheLib.h | 62 ++ IntelFspPkg/Include/Library/DebugDeviceLib.h | 29 + IntelFspPkg/Include/Library/FspCommonLib.h | 173 ++++ IntelFspPkg/Include/Library/FspPlatformLib.h | 64 ++ IntelFspPkg/Include/Library/FspReturnLib.h | 27 + .../Include/Library/FspSwitchStackLib.h | 45 + IntelFspPkg/Include/Private/FspGlobalData.h | 44 + .../Include/Private/FspMeasurePointId.h | 48 + IntelFspPkg/Include/Private/FspPatchTable.h | 32 + IntelFspPkg/Include/Private/GuidHobFspGfx.h | 19 + IntelFspPkg/Include/Private/GuidHobFspMisc.h | 19 + IntelFspPkg/Include/Private/GuidHobFspTseg.h | 19 + IntelFspPkg/IntelFspPkg.dec | 22 + IntelFspPkg/IntelFspPkg.dsc | 75 ++ .../BaseCacheAsRamLibNull.inf | 30 + .../DisableCacheAsRamNull.c | 41 + .../Library/BaseCacheLib/BaseCacheLib.inf | 32 + IntelFspPkg/Library/BaseCacheLib/CacheLib.c | 749 +++++++++++++++ .../Library/BaseCacheLib/CacheLibInternal.h | 59 ++ .../BaseDebugDeviceLibNull.inf | 34 + .../DebugDeviceLibNull.c | 31 + .../BaseFspCommonLib/BaseFspCommonLib.inf | 37 + .../Library/BaseFspCommonLib/FspCommonLib.c | 318 +++++++ .../BaseFspDebugLibSerialPort.inf | 49 + .../BaseFspDebugLibSerialPort/DebugLib.c | 305 ++++++ .../Ia32/FspDebug.asm | 34 + .../BaseFspDebugLibSerialPort/Ia32/FspDebug.s | 30 + .../BaseFspPlatformLib/BaseFspPlatformLib.inf | 41 + .../BaseFspPlatformLib/FspPlatformMemory.c | 155 +++ .../BaseFspPlatformLib/FspPlatformNotify.c | 178 ++++ .../BaseFspSwitchStackLib.inf | 42 + .../BaseFspSwitchStackLib/FspSwitchStackLib.c | 42 + .../BaseFspSwitchStackLib/Ia32/Stack.asm | 65 ++ .../BaseFspSwitchStackLib/Ia32/Stack.s | 64 ++ .../PlatformSecLibNull.c | 29 + .../SecPlatformSecLibNull.inf | 53 ++ IntelFspPkg/Tools/GenCfgOpt.py | 894 ++++++++++++++++++ IntelFspPkg/Tools/PatchFv.py | 567 +++++++++++ .../UserManuals/GenCfgOptUserManual.docx | Bin 0 -> 22177 bytes .../Tools/UserManuals/PatchFvUserManual.docx | Bin 0 -> 21481 bytes 64 files changed, 8155 insertions(+) create mode 100644 IntelFspPkg/FspDxeIpl/DxeIpl.c create mode 100644 IntelFspPkg/FspDxeIpl/DxeIpl.h create mode 100644 IntelFspPkg/FspDxeIpl/FspDxeIpl.inf create mode 100644 IntelFspPkg/FspSecCore/FspSecCore.inf create mode 100644 IntelFspPkg/FspSecCore/Ia32/FspApiEntry.asm create mode 100644 IntelFspPkg/FspSecCore/Ia32/FspApiEntry.s create mode 100644 IntelFspPkg/FspSecCore/Ia32/InitializeFpu.asm create mode 100644 IntelFspPkg/FspSecCore/Ia32/InitializeFpu.s create mode 100644 IntelFspPkg/FspSecCore/Ia32/ResetVec.asm16 create mode 100644 IntelFspPkg/FspSecCore/Ia32/SaveRestoreSse.inc create mode 100644 IntelFspPkg/FspSecCore/Ia32/Stack.asm create mode 100644 IntelFspPkg/FspSecCore/Ia32/Stacks.s create mode 100644 IntelFspPkg/FspSecCore/Ia32/UcodeLoad.inc create mode 100644 IntelFspPkg/FspSecCore/SecFsp.c create mode 100644 IntelFspPkg/FspSecCore/SecFsp.h create mode 100644 IntelFspPkg/FspSecCore/SecMain.c create mode 100644 IntelFspPkg/FspSecCore/SecMain.h create mode 100644 IntelFspPkg/FspSecCore/Vtf0/Bin/ResetVec.ia32.raw create mode 100644 IntelFspPkg/FspSecCore/Vtf0/Build.py create mode 100644 IntelFspPkg/FspSecCore/Vtf0/Ia16/ResetVec.asm16 create mode 100644 IntelFspPkg/FspSecCore/Vtf0/ResetVectorCode.asm create mode 100644 IntelFspPkg/FspSecCore/Vtf0/Tools/FixupForRawSection.py create mode 100644 IntelFspPkg/Include/Guid/GuidHobFsp.h create mode 100644 IntelFspPkg/Include/Library/CacheAsRamLib.h create mode 100644 IntelFspPkg/Include/Library/CacheLib.h create mode 100644 IntelFspPkg/Include/Library/DebugDeviceLib.h create mode 100644 IntelFspPkg/Include/Library/FspCommonLib.h create mode 100644 IntelFspPkg/Include/Library/FspPlatformLib.h create mode 100644 IntelFspPkg/Include/Library/FspReturnLib.h create mode 100644 IntelFspPkg/Include/Library/FspSwitchStackLib.h create mode 100644 IntelFspPkg/Include/Private/FspGlobalData.h create mode 100644 IntelFspPkg/Include/Private/FspMeasurePointId.h create mode 100644 IntelFspPkg/Include/Private/FspPatchTable.h create mode 100644 IntelFspPkg/Include/Private/GuidHobFspGfx.h create mode 100644 IntelFspPkg/Include/Private/GuidHobFspMisc.h create mode 100644 IntelFspPkg/Include/Private/GuidHobFspTseg.h create mode 100644 IntelFspPkg/IntelFspPkg.dsc create mode 100644 IntelFspPkg/Library/BaseCacheAsRamLibNull/BaseCacheAsRamLibNull.inf create mode 100644 IntelFspPkg/Library/BaseCacheAsRamLibNull/DisableCacheAsRamNull.c create mode 100644 IntelFspPkg/Library/BaseCacheLib/BaseCacheLib.inf create mode 100644 IntelFspPkg/Library/BaseCacheLib/CacheLib.c create mode 100644 IntelFspPkg/Library/BaseCacheLib/CacheLibInternal.h create mode 100644 IntelFspPkg/Library/BaseDebugDeviceLibNull/BaseDebugDeviceLibNull.inf create mode 100644 IntelFspPkg/Library/BaseDebugDeviceLibNull/DebugDeviceLibNull.c create mode 100644 IntelFspPkg/Library/BaseFspCommonLib/BaseFspCommonLib.inf create mode 100644 IntelFspPkg/Library/BaseFspCommonLib/FspCommonLib.c create mode 100644 IntelFspPkg/Library/BaseFspDebugLibSerialPort/BaseFspDebugLibSerialPort.inf create mode 100644 IntelFspPkg/Library/BaseFspDebugLibSerialPort/DebugLib.c create mode 100644 IntelFspPkg/Library/BaseFspDebugLibSerialPort/Ia32/FspDebug.asm create mode 100644 IntelFspPkg/Library/BaseFspDebugLibSerialPort/Ia32/FspDebug.s create mode 100644 IntelFspPkg/Library/BaseFspPlatformLib/BaseFspPlatformLib.inf create mode 100644 IntelFspPkg/Library/BaseFspPlatformLib/FspPlatformMemory.c create mode 100644 IntelFspPkg/Library/BaseFspPlatformLib/FspPlatformNotify.c create mode 100644 IntelFspPkg/Library/BaseFspSwitchStackLib/BaseFspSwitchStackLib.inf create mode 100644 IntelFspPkg/Library/BaseFspSwitchStackLib/FspSwitchStackLib.c create mode 100644 IntelFspPkg/Library/BaseFspSwitchStackLib/Ia32/Stack.asm create mode 100644 IntelFspPkg/Library/BaseFspSwitchStackLib/Ia32/Stack.s create mode 100644 IntelFspPkg/Library/SecPlatformSecLibNull/PlatformSecLibNull.c create mode 100644 IntelFspPkg/Library/SecPlatformSecLibNull/SecPlatformSecLibNull.inf create mode 100644 IntelFspPkg/Tools/GenCfgOpt.py create mode 100644 IntelFspPkg/Tools/PatchFv.py create mode 100644 IntelFspPkg/Tools/UserManuals/GenCfgOptUserManual.docx create mode 100644 IntelFspPkg/Tools/UserManuals/PatchFvUserManual.docx diff --git a/IntelFspPkg/FspDxeIpl/DxeIpl.c b/IntelFspPkg/FspDxeIpl/DxeIpl.c new file mode 100644 index 0000000000..24e6ef75cd --- /dev/null +++ b/IntelFspPkg/FspDxeIpl/DxeIpl.c @@ -0,0 +1,464 @@ +/** @file + + Copyright (c) 2014, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "DxeIpl.h" + + +// +// Module Globals used in the DXE to PEI hand off +// These must be module globals, so the stack can be switched +// +CONST EFI_DXE_IPL_PPI mDxeIplPpi = { + DxeLoadCore +}; + +CONST EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI mCustomGuidedSectionExtractionPpi = { + CustomGuidedSectionExtract +}; + +CONST EFI_PEI_DECOMPRESS_PPI mDecompressPpi = { + Decompress +}; + +CONST EFI_PEI_PPI_DESCRIPTOR mPpiList[] = { + { + EFI_PEI_PPI_DESCRIPTOR_PPI, + &gEfiDxeIplPpiGuid, + (VOID *) &mDxeIplPpi + }, + { + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiPeiDecompressPpiGuid, + (VOID *) &mDecompressPpi + } +}; + +CONST EFI_PEI_PPI_DESCRIPTOR gEndOfPeiSignalPpi = { + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiEndOfPeiSignalPpiGuid, + NULL +}; + +/** + Entry point of DXE IPL PEIM. + + This function installs DXE IPL PPI and Decompress PPI. It also reloads + itself to memory on non-S3 resume boot path. + + @param[in] FileHandle Handle of the file being invoked. + @param[in] PeiServices Describes the list of possible PEI Services. + + @retval EFI_SUCESS The entry point of DXE IPL PEIM executes successfully. + @retval Others Some error occurs during the execution of this function. + +**/ +EFI_STATUS +EFIAPI +PeimInitializeDxeIpl ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + EFI_GUID *ExtractHandlerGuidTable; + UINTN ExtractHandlerNumber; + EFI_PEI_PPI_DESCRIPTOR *GuidPpi; + + // + // Get custom extract guided section method guid list + // + ExtractHandlerNumber = ExtractGuidedSectionGetGuidList (&ExtractHandlerGuidTable); + + // + // Install custom extraction guid PPI + // + if (ExtractHandlerNumber > 0) { + GuidPpi = (EFI_PEI_PPI_DESCRIPTOR *) AllocatePool (ExtractHandlerNumber * sizeof (EFI_PEI_PPI_DESCRIPTOR)); + ASSERT (GuidPpi != NULL); + while (ExtractHandlerNumber-- > 0) { + GuidPpi->Flags = EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST; + GuidPpi->Ppi = (VOID *) &mCustomGuidedSectionExtractionPpi; + GuidPpi->Guid = &ExtractHandlerGuidTable[ExtractHandlerNumber]; + Status = PeiServicesInstallPpi (GuidPpi++); + ASSERT_EFI_ERROR(Status); + } + } + + // + // Install DxeIpl and Decompress PPIs. + // + Status = PeiServicesInstallPpi (mPpiList); + ASSERT_EFI_ERROR(Status); + + return Status; +} + +/** + The ExtractSection() function processes the input section and + returns a pointer to the section contents. If the section being + extracted does not require processing (if the section + GuidedSectionHeader.Attributes has the + EFI_GUIDED_SECTION_PROCESSING_REQUIRED field cleared), then + OutputBuffer is just updated to point to the start of the + section's contents. Otherwise, *Buffer must be allocated + from PEI permanent memory. + + @param[in] This Indicates the + EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI instance. + Buffer containing the input GUIDed section to be + processed. OutputBuffer OutputBuffer is + allocated from PEI permanent memory and contains + the new section stream. + @param[in] InputSection A pointer to the input buffer, which contains + the input section to be processed. + @param[out] OutputBuffer A pointer to a caller-allocated buffer, whose + size is specified by the contents of OutputSize. + @param[out] OutputSize A pointer to a caller-allocated + UINTN in which the size of *OutputBuffer + allocation is stored. If the function + returns anything other than EFI_SUCCESS, + the value of OutputSize is undefined. + @param[out] AuthenticationStatus A pointer to a caller-allocated + UINT32 that indicates the + authentication status of the + output buffer. If the input + section's GuidedSectionHeader. + Attributes field has the + EFI_GUIDED_SECTION_AUTH_STATUS_VALID + bit as clear, + AuthenticationStatus must return + zero. These bits reflect the + status of the extraction + operation. If the function + returns anything other than + EFI_SUCCESS, the value of + AuthenticationStatus is + undefined. + + @retval EFI_SUCCESS The InputSection was + successfully processed and the + section contents were returned. + + @retval EFI_OUT_OF_RESOURCES The system has insufficient + resources to process the request. + + @retval EFI_INVALID_PARAMETER The GUID in InputSection does + not match this instance of the + GUIDed Section Extraction PPI. + +**/ +EFI_STATUS +EFIAPI +CustomGuidedSectionExtract ( + IN CONST EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI *This, + IN CONST VOID *InputSection, + OUT VOID **OutputBuffer, + OUT UINTN *OutputSize, + OUT UINT32 *AuthenticationStatus +) +{ + EFI_STATUS Status; + UINT8 *ScratchBuffer; + UINT32 ScratchBufferSize; + UINT32 OutputBufferSize; + UINT16 SectionAttribute; + + // + // Init local variable + // + ScratchBuffer = NULL; + + // + // Call GetInfo to get the size and attribute of input guided section data. + // + Status = ExtractGuidedSectionGetInfo ( + InputSection, + &OutputBufferSize, + &ScratchBufferSize, + &SectionAttribute + ); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "GetInfo from guided section Failed - %r\n", Status)); + return Status; + } + + if (ScratchBufferSize != 0) { + // + // Allocate scratch buffer + // + ScratchBuffer = AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize)); + if (ScratchBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + } + + if (((SectionAttribute & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) != 0) && OutputBufferSize > 0) { + // + // Allocate output buffer + // + *OutputBuffer = AllocatePages (EFI_SIZE_TO_PAGES (OutputBufferSize) + 1); + if (*OutputBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + DEBUG ((DEBUG_INFO, "Customized Guided section Memory Size required is 0x%x and address is 0x%p\n", OutputBufferSize, *OutputBuffer)); + // + // *OutputBuffer still is one section. Adjust *OutputBuffer offset, + // skip EFI section header to make section data at page alignment. + // + *OutputBuffer = (VOID *)((UINT8 *) *OutputBuffer + EFI_PAGE_SIZE - sizeof (EFI_COMMON_SECTION_HEADER)); + } + + Status = ExtractGuidedSectionDecode ( + InputSection, + OutputBuffer, + ScratchBuffer, + AuthenticationStatus + ); + if (EFI_ERROR (Status)) { + // + // Decode failed + // + DEBUG ((DEBUG_ERROR, "Extract guided section Failed - %r\n", Status)); + return Status; + } + + *OutputSize = (UINTN) OutputBufferSize; + + return EFI_SUCCESS; +} + + + +/** + Decompresses a section to the output buffer. + + This function looks up the compression type field in the input section and + applies the appropriate compression algorithm to compress the section to a + callee allocated buffer. + + @param[in] This Points to this instance of the + EFI_PEI_DECOMPRESS_PEI PPI. + @param[in] CompressionSection Points to the compressed section. + @param[out] OutputBuffer Holds the returned pointer to the decompressed + sections. + @param[out] OutputSize Holds the returned size of the decompress + section streams. + + @retval EFI_SUCCESS The section was decompressed successfully. + OutputBuffer contains the resulting data and + OutputSize contains the resulting size. + +**/ +EFI_STATUS +EFIAPI +Decompress ( + IN CONST EFI_PEI_DECOMPRESS_PPI *This, + IN CONST EFI_COMPRESSION_SECTION *CompressionSection, + OUT VOID **OutputBuffer, + OUT UINTN *OutputSize + ) +{ + EFI_STATUS Status; + UINT8 *DstBuffer; + UINT8 *ScratchBuffer; + UINT32 DstBufferSize; + UINT32 ScratchBufferSize; + VOID *CompressionSource; + UINT32 CompressionSourceSize; + UINT32 UncompressedLength; + UINT8 CompressionType; + + if (CompressionSection->CommonHeader.Type != EFI_SECTION_COMPRESSION) { + ASSERT (FALSE); + return EFI_INVALID_PARAMETER; + } + + if (IS_SECTION2 (CompressionSection)) { + CompressionSource = (VOID *) ((UINT8 *) CompressionSection + sizeof (EFI_COMPRESSION_SECTION2)); + CompressionSourceSize = (UINT32) (SECTION2_SIZE (CompressionSection) - sizeof (EFI_COMPRESSION_SECTION2)); + UncompressedLength = ((EFI_COMPRESSION_SECTION2 *) CompressionSection)->UncompressedLength; + CompressionType = ((EFI_COMPRESSION_SECTION2 *) CompressionSection)->CompressionType; + } else { + CompressionSource = (VOID *) ((UINT8 *) CompressionSection + sizeof (EFI_COMPRESSION_SECTION)); + CompressionSourceSize = (UINT32) (SECTION_SIZE (CompressionSection) - sizeof (EFI_COMPRESSION_SECTION)); + UncompressedLength = CompressionSection->UncompressedLength; + CompressionType = CompressionSection->CompressionType; + } + + // + // This is a compression set, expand it + // + switch (CompressionType) { + case EFI_STANDARD_COMPRESSION: + if (TRUE) { + // + // Load EFI standard compression. + // For compressed data, decompress them to destination buffer. + // + Status = UefiDecompressGetInfo ( + CompressionSource, + CompressionSourceSize, + &DstBufferSize, + &ScratchBufferSize + ); + if (EFI_ERROR (Status)) { + // + // GetInfo failed + // + DEBUG ((DEBUG_ERROR, "Decompress GetInfo Failed - %r\n", Status)); + return EFI_NOT_FOUND; + } + // + // Allocate scratch buffer + // + ScratchBuffer = AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize)); + if (ScratchBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // Allocate destination buffer, extra one page for adjustment + // + DstBuffer = AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize) + 1); + if (DstBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // DstBuffer still is one section. Adjust DstBuffer offset, skip EFI section header + // to make section data at page alignment. + // + DstBuffer = DstBuffer + EFI_PAGE_SIZE - sizeof (EFI_COMMON_SECTION_HEADER); + // + // Call decompress function + // + Status = UefiDecompress ( + CompressionSource, + DstBuffer, + ScratchBuffer + ); + if (EFI_ERROR (Status)) { + // + // Decompress failed + // + DEBUG ((DEBUG_ERROR, "Decompress Failed - %r\n", Status)); + return EFI_NOT_FOUND; + } + break; + } else { + // + // PcdDxeIplSupportUefiDecompress is FALSE + // Don't support UEFI decompression algorithm. + // + ASSERT (FALSE); + return EFI_NOT_FOUND; + } + + case EFI_NOT_COMPRESSED: + // + // Allocate destination buffer + // + DstBufferSize = UncompressedLength; + DstBuffer = AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize) + 1); + if (DstBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // Adjust DstBuffer offset, skip EFI section header + // to make section data at page alignment. + // + DstBuffer = DstBuffer + EFI_PAGE_SIZE - sizeof (EFI_COMMON_SECTION_HEADER); + // + // stream is not actually compressed, just encapsulated. So just copy it. + // + CopyMem (DstBuffer, CompressionSource, DstBufferSize); + break; + + default: + // + // Don't support other unknown compression type. + // + ASSERT (FALSE); + return EFI_NOT_FOUND; + } + + *OutputSize = DstBufferSize; + *OutputBuffer = DstBuffer; + + return EFI_SUCCESS; +} + +/** + Main entry point to last PEIM. + + This function finds DXE Core in the firmware volume and transfer the control to + DXE core. + + @param[in] This Entry point for DXE IPL PPI. + @param[in] PeiServices General purpose services available to every PEIM. + @param[in] HobList Address to the Pei HOB list. + + @return EFI_SUCCESS DXE core was successfully loaded. + @return EFI_OUT_OF_RESOURCES There are not enough resources to load DXE core. + +**/ +EFI_STATUS +EFIAPI +DxeLoadCore ( + IN CONST EFI_DXE_IPL_PPI *This, + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_HOB_POINTERS HobList + ) +{ + EFI_STATUS Status; + + DEBUG ((DEBUG_INFO | DEBUG_INIT, "FSP HOB is located at 0x%08X\n", HobList)); + + // + // Give control back to bootloader after FspInit + // + DEBUG ((DEBUG_INFO | DEBUG_INIT, "FSP is waiting for NOTIFY\n")); + FspInitDone (); + + // + // Bootloader called FSP again through NotifyPhase + // + FspWaitForNotify (); + + // + // End of PEI phase signal + // + Status = PeiServicesInstallPpi (&gEndOfPeiSignalPpi); + ASSERT_EFI_ERROR (Status); + + // + // Give control back to the boot loader framework caller + // + DEBUG ((DEBUG_INFO | DEBUG_INIT, "============= PEIM FSP is Completed =============\n\n")); + + SetFspApiReturnStatus(EFI_SUCCESS); + + SetFspMeasurePoint (FSP_PERF_ID_API_NOTIFY_RDYBOOT_EXIT); + + Pei2LoaderSwitchStack(); + + // + // Should not come here + // + while (TRUE) { + DEBUG ((DEBUG_ERROR, "No FSP API should be called after FSP is DONE!\n")); + SetFspApiReturnStatus(EFI_UNSUPPORTED); + Pei2LoaderSwitchStack(); + } + + return EFI_SUCCESS; +} diff --git a/IntelFspPkg/FspDxeIpl/DxeIpl.h b/IntelFspPkg/FspDxeIpl/DxeIpl.h new file mode 100644 index 0000000000..0aded7271b --- /dev/null +++ b/IntelFspPkg/FspDxeIpl/DxeIpl.h @@ -0,0 +1,192 @@ +/** @file + + Copyright (c) 2014, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __PEI_DXEIPL_H__ +#define __PEI_DXEIPL_H__ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + Main entry point to last PEIM. + + This function finds DXE Core in the firmware volume and transfer the control to + DXE core. + + @param[in] This Entry point for DXE IPL PPI. + @param[in] PeiServices General purpose services available to every PEIM. + @param[in] HobList Address to the Pei HOB list. + + @return EFI_SUCCESS DXE core was successfully loaded. + @return EFI_OUT_OF_RESOURCES There are not enough resources to load DXE core. + +**/ +EFI_STATUS +EFIAPI +DxeLoadCore ( + IN CONST EFI_DXE_IPL_PPI *This, + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_HOB_POINTERS HobList + ); + + + +/** + Transfers control to DxeCore. + + This function performs a CPU architecture specific operations to execute + the entry point of DxeCore with the parameters of HobList. + It also installs EFI_END_OF_PEI_PPI to signal the end of PEI phase. + + @param[in] DxeCoreEntryPoint The entry point of DxeCore. + @param[in] HobList The start of HobList passed to DxeCore. + +**/ +VOID +HandOffToDxeCore ( + IN EFI_PHYSICAL_ADDRESS DxeCoreEntryPoint, + IN EFI_PEI_HOB_POINTERS HobList + ); + + + +/** + Updates the Stack HOB passed to DXE phase. + + This function traverses the whole HOB list and update the stack HOB to + reflect the real stack that is used by DXE core. + + @param[in] BaseAddress The lower address of stack used by DxeCore. + @param[in] Length The length of stack used by DxeCore. + +**/ +VOID +UpdateStackHob ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ); + +/** + The ExtractSection() function processes the input section and + returns a pointer to the section contents. If the section being + extracted does not require processing (if the section + GuidedSectionHeader.Attributes has the + EFI_GUIDED_SECTION_PROCESSING_REQUIRED field cleared), then + OutputBuffer is just updated to point to the start of the + section's contents. Otherwise, *Buffer must be allocated + from PEI permanent memory. + + @param[in] This Indicates the + EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI instance. + Buffer containing the input GUIDed section to be + processed. OutputBuffer OutputBuffer is + allocated from PEI permanent memory and contains + the new section stream. + @param[in] InputSection A pointer to the input buffer, which contains + the input section to be processed. + @param[out] OutputBuffer A pointer to a caller-allocated buffer, whose + size is specified by the contents of OutputSize. + @param[out] OutputSize A pointer to a caller-allocated + UINTN in which the size of *OutputBuffer + allocation is stored. If the function + returns anything other than EFI_SUCCESS, + the value of OutputSize is undefined. + @param[out] AuthenticationStatus A pointer to a caller-allocated + UINT32 that indicates the + authentication status of the + output buffer. If the input + section's GuidedSectionHeader. + Attributes field has the + EFI_GUIDED_SECTION_AUTH_STATUS_VALID + bit as clear, + AuthenticationStatus must return + zero. These bits reflect the + status of the extraction + operation. If the function + returns anything other than + EFI_SUCCESS, the value of + AuthenticationStatus is + undefined. + + @retval EFI_SUCCESS The InputSection was + successfully processed and the + section contents were returned. + + @retval EFI_OUT_OF_RESOURCES The system has insufficient + resources to process the request. + + @retval EFI_INVALID_PARAMETER The GUID in InputSection does + not match this instance of the + GUIDed Section Extraction PPI. + +**/ +EFI_STATUS +EFIAPI +CustomGuidedSectionExtract ( + IN CONST EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI *This, + IN CONST VOID *InputSection, + OUT VOID **OutputBuffer, + OUT UINTN *OutputSize, + OUT UINT32 *AuthenticationStatus + ); + +/** + Decompresses a section to the output buffer. + + This function looks up the compression type field in the input section and + applies the appropriate compression algorithm to compress the section to a + callee allocated buffer. + + @param[in] This Points to this instance of the + EFI_PEI_DECOMPRESS_PEI PPI. + @param[in] CompressionSection Points to the compressed section. + @param[out] OutputBuffer Holds the returned pointer to the decompressed + sections. + @param[out] OutputSize Holds the returned size of the decompress + section streams. + + @retval EFI_SUCCESS The section was decompressed successfully. + OutputBuffer contains the resulting data and + OutputSize contains the resulting size. + +**/ +EFI_STATUS +EFIAPI +Decompress ( + IN CONST EFI_PEI_DECOMPRESS_PPI *This, + IN CONST EFI_COMPRESSION_SECTION *CompressionSection, + OUT VOID **OutputBuffer, + OUT UINTN *OutputSize + ); + +#endif diff --git a/IntelFspPkg/FspDxeIpl/FspDxeIpl.inf b/IntelFspPkg/FspDxeIpl/FspDxeIpl.inf new file mode 100644 index 0000000000..49317af8e2 --- /dev/null +++ b/IntelFspPkg/FspDxeIpl/FspDxeIpl.inf @@ -0,0 +1,70 @@ +## @file +# +# Copyright (c) 2014, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = FspDxeIpl + FILE_GUID = 86D70125-BAA3-4296-A62F-602BEBBB9081 + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + + ENTRY_POINT = PeimInitializeDxeIpl + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 +# + +[Sources] + DxeIpl.h + DxeIpl.c + +[Packages] + MdePkg/MdePkg.dec + IntelFspPkg/IntelFspPkg.dec + +[LibraryClasses] + PcdLib + MemoryAllocationLib + BaseMemoryLib + ExtractGuidedSectionLib + UefiDecompressLib + ReportStatusCodeLib + PeiServicesLib + HobLib + BaseLib + PeimEntryPoint + DebugLib + FspSwitchStackLib + UefiDecompressLib + FspCommonLib + FspPlatformLib + +[Ppis] + gEfiDxeIplPpiGuid ## PRODUCES + gEfiEndOfPeiSignalPpiGuid ## SOMETIMES_PRODUCES(Not produced on S3 boot path) + gEfiPeiDecompressPpiGuid + +[Protocols] + gEfiPciEnumerationCompleteProtocolGuid # ALWAYS_PRODUCED + +[Guids] + gEfiEventReadyToBootGuid # ALWAYS_PRODUCED + +[FixedPcd] + gIntelFspPkgTokenSpaceGuid.PcdFspMaxPatchEntry + gIntelFspPkgTokenSpaceGuid.PcdFspMaxPerfEntry + +[Depex] + gEfiPeiMemoryDiscoveredPpiGuid AND gEfiPeiLoadFilePpiGuid diff --git a/IntelFspPkg/FspSecCore/FspSecCore.inf b/IntelFspPkg/FspSecCore/FspSecCore.inf new file mode 100644 index 0000000000..d3ec2fc64f --- /dev/null +++ b/IntelFspPkg/FspSecCore/FspSecCore.inf @@ -0,0 +1,76 @@ +## @file +# +# Copyright (c) 2014, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = FspSecCore + FILE_GUID = 1BA0062E-C779-4582-8566-336AE8F78F09 + MODULE_TYPE = SEC + VERSION_STRING = 1.0 + + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 +# + +[Sources] + SecMain.c + SecMain.h + SecFsp.c + SecFsp.h + +[Sources.IA32] + Ia32/ResetVec.asm16 | MSFT + Ia32/Stack.asm | MSFT + Ia32/InitializeFpu.asm | MSFT + Ia32/FspApiEntry.asm | MSFT + + Ia32/Stacks.s | GCC + Ia32/InitializeFpu.s | GCC + Ia32/FspApiEntry.s | GCC + +[Binaries.Ia32] + RAW|Vtf0/Bin/ResetVec.ia32.raw |GCC + +[Binaries.X64] + RAW|Vtf0/Bin/ResetVec.x64.raw |GCC + +[Packages] + MdePkg/MdePkg.dec + IntelFspPkg/IntelFspPkg.dec + +[LibraryClasses] + BaseMemoryLib + DebugLib + BaseLib + PciCf8Lib + SerialPortLib + FspSwitchStackLib + FspCommonLib + +[Pcd] + gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress + gIntelFspPkgTokenSpaceGuid.PcdGlobalDataPointerAddress + gIntelFspPkgTokenSpaceGuid.PcdTemporaryRamBase + gIntelFspPkgTokenSpaceGuid.PcdTemporaryRamSize + gIntelFspPkgTokenSpaceGuid.PcdFspTemporaryRamSize + +[FixedPcd] + gIntelFspPkgTokenSpaceGuid.PcdFspMaxPatchEntry + gIntelFspPkgTokenSpaceGuid.PcdFspMaxPerfEntry + +[Ppis] + gEfiTemporaryRamSupportPpiGuid # PPI ALWAYS_PRODUCED + diff --git a/IntelFspPkg/FspSecCore/Ia32/FspApiEntry.asm b/IntelFspPkg/FspSecCore/Ia32/FspApiEntry.asm new file mode 100644 index 0000000000..8ad9744ab4 --- /dev/null +++ b/IntelFspPkg/FspSecCore/Ia32/FspApiEntry.asm @@ -0,0 +1,552 @@ +;------------------------------------------------------------------------------ +; +; Copyright (c) 2014, Intel Corporation. All rights reserved.
+; This program and the accompanying materials +; are licensed and made available under the terms and conditions of the BSD License +; which accompanies this distribution. The full text of the license may be found at +; http://opensource.org/licenses/bsd-license.php. +; +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +; +; Abstract: +; +; Provide FSP API entry points. +; +;------------------------------------------------------------------------------ + + .586p + .model flat,C + .code + .xmm + +INCLUDE SaveRestoreSse.inc +INCLUDE UcodeLoad.inc + +; +; Following are fixed PCDs +; +EXTERN PcdGet32(PcdTemporaryRamBase):DWORD +EXTERN PcdGet32(PcdTemporaryRamSize):DWORD +EXTERN PcdGet32(PcdFspTemporaryRamSize):DWORD + +; +; Following functions will be provided in C +; +EXTERN FspImageSizeOffset:DWORD +EXTERN SecStartup:PROC +EXTERN FspApiCallingCheck:PROC + +; +; Following functions will be provided in PlatformSecLib +; +EXTERN GetFspBaseAddress:PROC +EXTERN GetBootFirmwareVolumeOffset:PROC +EXTERN PlatformTempRamInit:PROC +EXTERN Pei2LoaderSwitchStack:PROC +EXTERN FspSelfCheck(FspSelfCheckDflt):PROC +EXTERN PlatformBasicInit(PlatformBasicInitDflt):PROC +EXTERN LoadUcode(LoadUcodeDflt):PROC + +; +; Define the data length that we saved on the stack top +; +DATA_LEN_OF_PER0 EQU 18h +DATA_LEN_OF_MCUD EQU 18h +DATA_LEN_AT_STACK_TOP EQU (DATA_LEN_OF_PER0 + DATA_LEN_OF_MCUD + 4) + +;------------------------------------------------------------------------------ +FspSelfCheckDflt PROC NEAR PUBLIC + ; Inputs: + ; eax -> Return address + ; Outputs: + ; eax -> 0 - Successful, Non-zero - Failed. + ; Register Usage: + ; eax is cleared and ebp is used for return address. + ; All others reserved. + + ; Save return address to EBP + mov ebp, eax + + xor eax, eax +exit: + jmp ebp +FspSelfCheckDflt ENDP + +;------------------------------------------------------------------------------ +PlatformBasicInitDflt PROC NEAR PUBLIC + ; Inputs: + ; eax -> Return address + ; Outputs: + ; eax -> 0 - Successful, Non-zero - Failed. + ; Register Usage: + ; eax is cleared and ebp is used for return address. + ; All others reserved. + + ; Save return address to EBP + mov ebp, eax + + xor eax, eax +exit: + jmp ebp +PlatformBasicInitDflt ENDP + +;------------------------------------------------------------------------------ +LoadUcodeDflt PROC NEAR PUBLIC + ; Inputs: + ; esp -> LOAD_UCODE_PARAMS pointer + ; Register Usage: + ; esp Preserved + ; All others destroyed + ; Assumptions: + ; No memory available, stack is hard-coded and used for return address + ; Executed by SBSP and NBSP + ; Beginning of microcode update region starts on paragraph boundary + + ; + ; + ; Save return address to EBP + mov ebp, eax + + cmp esp, 0 + jz paramerror + mov eax, dword ptr [esp] ; Parameter pointer + cmp eax, 0 + jz paramerror + mov esp, eax + mov esi, [esp].LOAD_UCODE_PARAMS.ucode_code_addr + cmp esi, 0 + jnz check_main_header + +paramerror: + mov eax, 080000002h + jmp exit + + mov esi, [esp].LOAD_UCODE_PARAMS.ucode_code_addr + +check_main_header: + ; Get processor signature and platform ID from the installed processor + ; and save into registers for later use + ; ebx = processor signature + ; edx = platform ID + mov eax, 1 + cpuid + mov ebx, eax + mov ecx, MSR_IA32_PLATFORM_ID + rdmsr + mov ecx, edx + shr ecx, 50-32 + and ecx, 7h + mov edx, 1 + shl edx, cl + + ; Current register usage + ; esp -> stack with paramters + ; esi -> microcode update to check + ; ebx = processor signature + ; edx = platform ID + + ; Check for valid microcode header + ; Minimal test checking for header version and loader version as 1 + mov eax, dword ptr 1 + cmp [esi].ucode_hdr.version, eax + jne advance_fixed_size + cmp [esi].ucode_hdr.loader, eax + jne advance_fixed_size + + ; Check if signature and plaform ID match + cmp ebx, [esi].ucode_hdr.processor + jne @f + test edx, [esi].ucode_hdr.flags + jnz load_check ; Jif signature and platform ID match + +@@: + ; Check if extended header exists + ; First check if total_size and data_size are valid + xor eax, eax + cmp [esi].ucode_hdr.total_size, eax + je next_microcode + cmp [esi].ucode_hdr.data_size, eax + je next_microcode + + ; Then verify total size - sizeof header > data size + mov ecx, [esi].ucode_hdr.total_size + sub ecx, sizeof ucode_hdr + cmp ecx, [esi].ucode_hdr.data_size + jng next_microcode ; Jif extended header does not exist + + ; Set edi -> extended header + mov edi, esi + add edi, sizeof ucode_hdr + add edi, [esi].ucode_hdr.data_size + + ; Get count of extended structures + mov ecx, [edi].ext_sig_hdr.count + + ; Move pointer to first signature structure + add edi, sizeof ext_sig_hdr + +check_ext_sig: + ; Check if extended signature and platform ID match + cmp [edi].ext_sig.processor, ebx + jne @f + test [edi].ext_sig.flags, edx + jnz load_check ; Jif signature and platform ID match +@@: + ; Check if any more extended signatures exist + add edi, sizeof ext_sig + loop check_ext_sig + +next_microcode: + ; Advance just after end of this microcode + xor eax, eax + cmp [esi].ucode_hdr.total_size, eax + je @f + add esi, [esi].ucode_hdr.total_size + jmp check_address +@@: + add esi, dword ptr 2048 + jmp check_address + +advance_fixed_size: + ; Advance by 4X dwords + add esi, dword ptr 1024 + +check_address: + ; Is valid Microcode start point ? + cmp dword ptr [esi], 0ffffffffh + jz done + + ; Address >= microcode region address + microcode region size? + mov eax, [esp].LOAD_UCODE_PARAMS.ucode_code_addr + add eax, [esp].LOAD_UCODE_PARAMS.ucode_code_size + cmp esi, eax + jae done ;Jif address is outside of ucode region + jmp check_main_header + +load_check: + ; Get the revision of the current microcode update loaded + mov ecx, MSR_IA32_BIOS_SIGN_ID + xor eax, eax ; Clear EAX + xor edx, edx ; Clear EDX + wrmsr ; Load 0 to MSR at 8Bh + + mov eax, 1 + cpuid + mov ecx, MSR_IA32_BIOS_SIGN_ID + rdmsr ; Get current microcode signature + + ; Verify this microcode update is not already loaded + cmp [esi].ucode_hdr.revision, edx + je continue + +load_microcode: + ; EAX contains the linear address of the start of the Update Data + ; EDX contains zero + ; ECX contains 79h (IA32_BIOS_UPDT_TRIG) + ; Start microcode load with wrmsr + mov eax, esi + add eax, sizeof ucode_hdr + xor edx, edx + mov ecx, MSR_IA32_BIOS_UPDT_TRIG + wrmsr + mov eax, 1 + cpuid + +continue: + jmp next_microcode + +done: + mov eax, 1 + cpuid + mov ecx, MSR_IA32_BIOS_SIGN_ID + rdmsr ; Get current microcode signature + xor eax, eax + cmp edx, 0 + jnz exit + mov eax, 08000000Eh + +exit: + jmp ebp + +LoadUcodeDflt ENDP + +;---------------------------------------------------------------------------- +; TempRamInit API +; +; This FSP API will load the microcode update, enable code caching for the +; region specified by the boot loader and also setup a temporary stack to be +; used till main memory is initialized. +; +;---------------------------------------------------------------------------- +TempRamInitApi PROC NEAR PUBLIC + ; + ; Ensure SSE is enabled + ; + ENABLE_SSE + + ; + ; Save EBP, EBX, ESI, EDI & ESP in XMM7 & XMM6 + ; + SAVE_REGS + + ; + ; Save timestamp into XMM4 & XMM5 + ; + rdtsc + SAVE_EAX + SAVE_EDX + + ; + ; Check Parameter + ; + mov eax, dword ptr [esp + 4] + cmp eax, 0 + mov eax, 80000002h + jz NemInitExit + + ; + ; CPUID/DeviceID check + ; + mov eax, @F + jmp FspSelfCheck ; Note: ESP can not be changed. +@@: + cmp eax, 0 + jnz NemInitExit + + ; + ; Platform Basic Init. + ; + mov eax, @F + jmp PlatformBasicInit +@@: + cmp eax, 0 + jnz NemInitExit + + ; + ; Load microcode + ; + mov eax, @F + add esp, 4 + jmp LoadUcode +@@: + LOAD_ESP + cmp eax, 0 + jnz NemInitExit + + ; + ; Call platform NEM init + ; + mov eax, @F + add esp, 4 + jmp PlatformTempRamInit +@@: + LOAD_ESP + cmp eax, 0 + jnz NemInitExit + + ; + ; Save parameter pointer in edx + ; + mov edx, dword ptr [esp + 4] + + ; + ; Enable FSP STACK + ; + mov esp, PcdGet32(PcdTemporaryRamBase) + add esp, PcdGet32(PcdTemporaryRamSize) + + push DATA_LEN_OF_MCUD ; Size of the data region + push 4455434Dh ; Signature of the data region 'MCUD' + push dword ptr [edx + 4] ; Microcode size + push dword ptr [edx + 0] ; Microcode base + push dword ptr [edx + 12] ; Code size + push dword ptr [edx + 8] ; Code base + + ; + ; Save API entry/exit timestamp into stack + ; + push DATA_LEN_OF_PER0 ; Size of the data region + push 30524550h ; Signature of the data region 'PER0' + rdtsc + push edx + push eax + LOAD_EAX + LOAD_EDX + push edx + push eax + + ; + ; Terminator for the data on stack + ; + push 0 + + ; + ; Set ECX/EDX to the bootloader temporary memory range + ; + mov ecx, PcdGet32(PcdTemporaryRamBase) + mov edx, ecx + add edx, PcdGet32(PcdTemporaryRamSize) + sub edx, PcdGet32(PcdFspTemporaryRamSize) + + xor eax, eax + +NemInitExit: + ; + ; Load EBP, EBX, ESI, EDI & ESP from XMM7 & XMM6 + ; + LOAD_REGS + ret +TempRamInitApi ENDP + +;---------------------------------------------------------------------------- +; FspInit API +; +; This FSP API will perform the processor and chipset initialization. +; This API will not return. Instead, it transfers the control to the +; ContinuationFunc provided in the parameter. +; +;---------------------------------------------------------------------------- +FspInitApi PROC NEAR PUBLIC + ; + ; Stack must be ready + ; + push 087654321h + pop eax + cmp eax, 087654321h + jz @F + mov eax, 080000003h + jmp exit + +@@: + ; + ; Additional check + ; + pushad + push 1 + call FspApiCallingCheck + add esp, 4 + mov dword ptr [esp + 4 * 7], eax + popad + cmp eax, 0 + jz @F + jmp exit + +@@: + ; + ; Store the address in FSP which will return control to the BL + ; + push offset exit + + ; + ; Create a Task Frame in the stack for the Boot Loader + ; + pushfd ; 2 pushf for 4 byte alignment + cli + pushad + + ; Reserve 8 bytes for IDT save/restore + sub esp, 8 + sidt fword ptr [esp] + + ; + ; Setup new FSP stack + ; + mov eax, esp + mov esp, PcdGet32(PcdTemporaryRamBase) + add esp, PcdGet32(PcdTemporaryRamSize) + sub esp, (DATA_LEN_AT_STACK_TOP + 40h) + + ; + ; Save the bootloader's stack pointer + ; + push eax + + ; + ; Pass entry point of the PEI core + ; + call GetFspBaseAddress + mov edi, FspImageSizeOffset + mov edi, DWORD PTR [eax + edi] + add edi, eax + sub edi, 20h + add eax, DWORD PTR [edi] + push eax + + ; + ; Pass BFV into the PEI Core + ; It uses relative address to calucate the actual boot FV base + ; For FSP impleantion with single FV, PcdFlashFvRecoveryBase and + ; PcdFspAreaBaseAddress are the same. For FSP with mulitple FVs, + ; they are different. The code below can handle both cases. + ; + call GetFspBaseAddress + mov edi, eax + call GetBootFirmwareVolumeOffset + add eax, edi + push eax + + ; + ; Pass stack base and size into the PEI Core + ; + mov eax, PcdGet32(PcdTemporaryRamBase) + add eax, PcdGet32(PcdTemporaryRamSize) + sub eax, PcdGet32(PcdFspTemporaryRamSize) + push eax + push PcdGet32(PcdFspTemporaryRamSize) + + ; + ; Pass Control into the PEI Core + ; + call SecStartup + +exit: + ret + +FspInitApi ENDP + +;---------------------------------------------------------------------------- +; NotifyPhase API +; +; This FSP API will notify the FSP about the different phases in the boot +; process +; +;---------------------------------------------------------------------------- +NotifyPhaseApi PROC C PUBLIC + ; + ; Stack must be ready + ; + push 087654321h + pop eax + cmp eax, 087654321h + jz @F + mov eax, 080000003h + jmp err_exit + +@@: + ; + ; Verify the calling condition + ; + pushad + push 2 + call FspApiCallingCheck + add esp, 4 + mov dword ptr [esp + 4 * 7], eax + popad + + cmp eax, 0 + jz @F + + ; + ; Error return + ; +err_exit: + ret + +@@: + jmp Pei2LoaderSwitchStack + +NotifyPhaseApi ENDP + + +END diff --git a/IntelFspPkg/FspSecCore/Ia32/FspApiEntry.s b/IntelFspPkg/FspSecCore/Ia32/FspApiEntry.s new file mode 100644 index 0000000000..433ef921c4 --- /dev/null +++ b/IntelFspPkg/FspSecCore/Ia32/FspApiEntry.s @@ -0,0 +1,611 @@ +#------------------------------------------------------------------------------ +# +# Copyright (c) 2014, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# Abstract: +# +# Provide FSP API entry points. +# +#------------------------------------------------------------------------------ + +#.INCLUDE "UcodeLoad.inc" + +# +# Following are fixed PCDs +# + +.equ MSR_IA32_PLATFORM_ID, 0x000000017 +.equ MSR_IA32_BIOS_UPDT_TRIG, 0x000000079 +.equ MSR_IA32_BIOS_SIGN_ID, 0x00000008b + +ASM_GLOBAL ASM_PFX(_gPcd_FixedAtBuild_PcdTemporaryRamBase) +ASM_GLOBAL ASM_PFX(_gPcd_FixedAtBuild_PcdTemporaryRamSize) +ASM_GLOBAL ASM_PFX(_gPcd_FixedAtBuild_PcdFspTemporaryRamSize) +ASM_GLOBAL ASM_PFX(_gPcd_FixedAtBuild_PcdFspAreaSize) + + +# +# Following functions will be provided in C +# +#EXTERNDEF SecStartup:PROC +#EXTERNDEF FspApiCallingCheck:PROC + +# +# Following functions will be provided in PlatformSecLib +# +#EXTERNDEF GetFspBaseAddress:PROC +#EXTERNDEF GetBootFirmwareVolumeOffset:PROC +#EXTERNDEF PlatformTempRamInit:PROC +#EXTERNDEF Pei2LoaderSwitchStack:PROC +#EXTERN FspSelfCheck(FspSelfCheckDflt):PROC +#EXTERN PlatformBasicInit(PlatformBasicInitDflt):PROC + +# +# Define the data length that we saved on the stack top +# +.equ DATA_LEN_OF_PER0, 0x018 +.equ DATA_LEN_OF_MCUD, 0x018 +.equ DATA_LEN_AT_STACK_TOP, (DATA_LEN_OF_PER0 + DATA_LEN_OF_MCUD + 4) + +# +# Define SSE macros +# +.macro ENABLE_SSE + movl %cr4, %eax + orl $0x00000600,%eax # Set OSFXSR bit (bit #9) & OSXMMEXCPT bit (bit #10) + movl %eax,%cr4 +.endm + +.macro SAVE_REGS + movd %ebp, %xmm7 + pshufd $0x93, %xmm7, %xmm7 + movd %ebx, %xmm6 + por %xmm6, %xmm7 + pshufd $0x93, %xmm7, %xmm7 + movd %esi,%xmm6 + por %xmm6, %xmm7 + pshufd $0x93, %xmm7, %xmm7 + movd %edi, %xmm6 + por %xmm6, %xmm7 + movd %esp, %xmm6 +.endm + +.macro LOAD_REGS + movd %xmm6, %esp + movd %xmm7, %edi + pshufd $0x39,%xmm7, %xmm7 + movd %xmm7, %esi + pshufd $0x39,%xmm7, %xmm7 + movd %xmm7, %ebx + pshufd $0x39, %xmm7, %xmm7 + movd %xmm7, %ebp +.endm + +.macro LOAD_ESP + movd %xmm6, %esp +.endm + +#------------------------------------------------------------------------------ +ASM_GLOBAL ASM_PFX(FspSelfCheckDflt) +ASM_PFX(FspSelfCheckDflt): + # Inputs: + # eax -> Return address + # Outputs: + # eax -> 0 - Successful, Non-zero - Failed. + # Register Usage: + # eax is cleared and ebp is used for return address. + # All others reserved. + + # Save return address to EBP + movl %eax, %ebp + xorl %eax, %eax +exit: + jmp *%ebp +#FspSelfCheckDflt ENDP + +#------------------------------------------------------------------------------ +ASM_GLOBAL ASM_PFX(PlatformBasicInitDflt) +ASM_PFX(PlatformBasicInitDflt): + # Inputs: + # eax -> Return address + # Outputs: + # eax -> 0 - Successful, Non-zero - Failed. + # Register Usage: + # eax is cleared and ebp is used for return address. + # All others reserved. + + # Save return address to EBP + movl %eax, %ebp + xorl %eax, %eax +exit2: + jmp *%ebp +#PlatformBasicInitDflt ENDP + +#------------------------------------------------------------------------------ +ASM_GLOBAL ASM_PFX(LoadUcode) +ASM_PFX(LoadUcode): + # Inputs: + # esp -> LOAD_UCODE_PARAMS pointer + # Register Usage: + # esp Preserved + # All others destroyed + # Assumptions: + # No memory available, stack is hard-coded and used for return address + # Executed by SBSP and NBSP + # Beginning of microcode update region starts on paragraph boundary + + # + # + # Save return address to EBP + movl %eax, %ebp + cmpl $0, %esp + jz paramerror + movl (%esp), %eax #dword ptr [] Parameter pointer + cmpl $0, %eax + jz paramerror + movl %eax, %esp + movl (%esp), %esi #LOAD_UCODE_PARAMS.ucode_code_addr + cmpl $0, %esi + jnz L0 + +paramerror: + movl $0x080000002, %eax + jmp exit4 + + movl (%esp), %esi #.LOAD_UCODE_PARAMS.ucode_code_addr + +check_main_header: + # Get processor signature and platform ID from the installed processor + # and save into registers for later use + # ebx = processor signature + # edx = platform ID + movl $1, %eax + cpuid + movl %eax, %ebx + movl MSR_IA32_PLATFORM_ID, %ecx + rdmsr + movl %edx, %ecx + #-------------------------------------------------------------------------------------------------------------------- + shrl $18, %ecx #($50-$32) + andl $0x7, %ecx + movl $1, %edx + shll %cl,%edx + + # Current register usage + # esp -> stack with paramters + # esi -> microcode update to check + # ebx = processor signature + # edx = platform ID + + # Check for valid microcode header + # Minimal test checking for header version and loader version as 1 + movl $1, %eax + cmpl %eax, (%esi) #.ucode_hdr.version + jne advance_fixed_size + cmpl %eax, 0x18(%esi) #.ucode_hdr.loader + jne advance_fixed_size + + # Check if signature and plaform ID match + #-------------------------------------------------------------------------------------------------------------------------- + cmpl 0x10(%esi), %ebx #(%esi).ucode_hdr.processor + jne L0 + testl 0x1c(%esi) , %edx #(%esi).ucode_hdr.flags + jnz load_check # Jif signature and platform ID match + +L0: + # Check if extended header exists + # First check if total_size and data_size are valid + xorl %eax, %eax + cmpl %eax,0x24(%esi) #(%esi).ucode_hdr.total_size + je next_microcode + cmpl %eax,0x20(%esi) #(%esi) .ucode_hdr.data_size + je next_microcode + + # Then verify total size - sizeof header > data size + movl 0x24(%esi), %ecx #(%esi).ucode_hdr.total_size + subl $0x30, %ecx #sizeof ucode_hdr = 48 + cmpl 0x20(%esi), %ecx #(%esi).ucode_hdr.data_size + jz load_check + jb next_microcode # Jif extended header does not exist + + # Check if total size fits in microcode region + movl %esi , %edi + addl 0x24(%esi), %edi # (%esi).ucode_hdr.total_size + movl (%esp), %ecx # (%esp).LOAD_UCODE_PARAMS.ucode_code_addr + addl 4(%esp), %ecx #.LOAD_UCODE_PARAMS.ucode_code_size + cmpl %ecx , %edi + xorl %eax, %eax + ja exit4 # Jif address is outside of ucode region + + # Set edi -> extended header + movl %esi , %edi + addl $0x30 , %edi #sizeof ucode_hdr = 48 + addl 0x20(%esi), %edi #%esi.ucode_hdr.data_size + + # Get count of extended structures + movl (%edi), %ecx #(%edi).ext_sig_hdr.count + + # Move pointer to first signature structure + addl $0x20, %edi # sizeof ext_sig_hdr = 20 + +check_ext_sig: + # Check if extended signature and platform ID match + cmpl %ebx, (%edi) #[edi].ext_sig.processor + jne L1 + test %edx, 4(%edi) #[edi].ext_sig.flags + jnz load_check # Jif signature and platform ID match +L9: + # Check if any more extended signatures exist + addl $0xc, %edi #sizeof ext_sig = 12 + loop check_ext_sig + +next_microcode: + # Advance just after end of this microcode + xorl %eax, %eax + cmpl %eax, 0x24(%esi) #(%esi).ucode_hdr.total_size + je L2 + add 0x24(%esi) , %esi #(%esi).ucode_hdr.total_size + jmp check_address +L10: + addl $0x800, %esi + jmp check_address + +advance_fixed_size: + # Advance by 4X dwords + addl $0x400, %esi + +check_address: + # Is valid Microcode start point ? + cmp $0x0ffffffff , %esi + jz done + + # Address >= microcode region address + microcode region size? + movl (%esp), %eax #(%esp).LOAD_UCODE_PARAMS.ucode_code_addr + addl 4(%esp), %eax #(%esp).LOAD_UCODE_PARAMS.ucode_code_size + cmpl %eax, %esi + jae done #Jif address is outside of ucode region + jmp check_main_header + +load_check: + # Get the revision of the current microcode update loaded + movl MSR_IA32_BIOS_SIGN_ID, %ecx + xorl %eax, %eax # Clear EAX + xorl %edx, %edx # Clear EDX + wrmsr # Load 0 to MSR at 8Bh + + movl $1, %eax + cpuid + movl MSR_IA32_BIOS_SIGN_ID, %ecx + rdmsr # Get current microcode signature + + # Verify this microcode update is not already loaded + cmpl %edx, 4(%esi) #(%esi).ucode_hdr.revision + je continue + +load_microcode: + # EAX contains the linear address of the start of the Update Data + # EDX contains zero + # ECX contains 79h (IA32_BIOS_UPDT_TRIG) + # Start microcode load with wrmsr + mov %esi, %eax + add $0x30, %eax #sizeof ucode_hdr = 48 + xorl %edx, %edx + mov MSR_IA32_BIOS_UPDT_TRIG,%ecx + wrmsr + mov $1, %eax + cpuid + +continue: + jmp next_microcode + +done: + mov $1, %eax + cpuid + mov MSR_IA32_BIOS_SIGN_ID, %ecx + rdmsr # Get current microcode signature + xorl %eax, %eax + cmp $0 , %edx + jnz exit4 + mov $0x08000000E, %eax + +exit4: + jmp *%ebp + +#LoadUcode ENDP + +#---------------------------------------------------------------------------- +# TempRamInit API +# +# This FSP API will load the microcode update, enable code caching for the +# region specified by the boot loader and also setup a temporary stack to be +# used till main memory is initialized. +# +#---------------------------------------------------------------------------- +ASM_GLOBAL ASM_PFX(TempRamInitApi) +ASM_PFX(TempRamInitApi): + # + # Ensure SSE is enabled + # + ENABLE_SSE + + # + # Save EBP, EBX, ESI, EDI & ESP in XMM7 & XMM6 + # + SAVE_REGS + + # + # Save timestamp into XMM4 & XMM5 + # + rdtsc + movd %edx, %xmm4 + movd %eax, %xmm5 + + # + # CPUID/DeviceID check + # + movl L11, %eax + jmp ASM_PFX(FspSelfCheck) # Note: ESP can not be changed. +L11: + cmpl $0, %eax + jnz NemInitExit + + # + # Platform Basic Init. + # + movl L1, %eax + jmp ASM_PFX(PlatformBasicInitDflt) +L1: + cmp $0, %eax + jnz NemInitExit + + # + # Load microcode + # + movl L2, %eax + addl $4, %esp + jmp LoadUcode +L2: + LOAD_ESP + cmpl $0, %eax + jnz NemInitExit + + # + # Call platform NEM init + #------------------------------------------------------------------------------------------------------------------------- + movl L3, %eax + addl $4, %esp + jmp ASM_PFX(PlatformTempRamInit) +L3: + subl $4, %esp + cmpl $0, %eax + jnz NemInitExit + + # + # Save parameter pointer in edx + # + movl 4(%esp), %edx + + # + # Enable FSP STACK + # + movl ASM_PFX(_gPcd_FixedAtBuild_PcdTemporaryRamBase), %esp + addl ASM_PFX(_gPcd_FixedAtBuild_PcdTemporaryRamSize), %esp + + pushl $DATA_LEN_OF_MCUD # Size of the data region + pushl 0x4455434D # Signature of the data region 'MCUD' + pushl 12(%edx) # Code size + pushl 8(%edx) # Code base + cmpl $0, %edx # Is parameter pointer valid ? + jz InvalidMicrocodeRegion + pushl 4(%edx) # Microcode size + pushl (%edx) # Microcode base + jmp L4 + +InvalidMicrocodeRegion: + pushl $0 # Microcode size + pushl $0 # Microcode base + +L4: + # + # Save API entry/exit timestamp into stack + # + pushl DATA_LEN_OF_PER0 # Size of the data region + pushl 0x30524550 # Signature of the data region 'PER0' + movd %xmm4, %eax + pushl %eax + movd %xmm5, %eax + pushl %eax + rdtsc + pushl %edx + pushl %eax + + # + # Terminator for the data on stack + # + pushl $0 + + # + # Set ECX/EDX to the bootloader temporary memory range + # + movl ASM_PFX(_gPcd_FixedAtBuild_PcdTemporaryRamBase), %ecx + movl %ecx, %edx + addl ASM_PFX(_gPcd_FixedAtBuild_PcdTemporaryRamSize), %edx + subl ASM_PFX(_gPcd_FixedAtBuild_PcdFspTemporaryRamSize), %edx + + xorl %eax, %eax + +NemInitExit: + # + # Load EBP, EBX, ESI, EDI & ESP from XMM7 & XMM6 + # + LOAD_REGS + ret +#TempRamInitApi ENDP + +#---------------------------------------------------------------------------- +# FspInit API +# +# This FSP API will perform the processor and chipset initialization. +# This API will not return. Instead, it transfers the control to the +# ContinuationFunc provided in the parameter. +# +#---------------------------------------------------------------------------- +ASM_GLOBAL ASM_PFX(FspInitApi) +ASM_PFX(FspInitApi): + # + # Stack must be ready + # + pushl $0x087654321 + pop %eax + cmpl $0x087654321, %eax + jz L5 + movl $0x080000003, %eax + jmp exit3 + +L5: + # + # Additional check + # + pusha + pushl $1 + call ASM_PFX(FspApiCallingCheck) + addl $4, %esp + movl %eax, 28(%esp) + popa + cmpl $0 , %eax + jz L6 + jmp exit3 + +L6: + # + # Save the Platform Data Pointer in EDI + # + movl 4(%esp), %edi + + # + # Store the address in FSP which will return control to the BL + # + pushl $exit3 + + # + # Create a Task Frame in the stack for the Boot Loader + # + pushfl + pushfl # 2 pushf for 4 byte alignment + cli + pushal + + # Reserve 8 bytes for IDT save/restore + pushl $0 + pushl $0 + sidt (%esp) + + # + # Setup new FSP stack + # + movl %esp, %eax + movl ASM_PFX(_gPcd_FixedAtBuild_PcdTemporaryRamBase), %esp + addl ASM_PFX(_gPcd_FixedAtBuild_PcdTemporaryRamSize) , %esp + subl DATA_LEN_AT_STACK_TOP, %esp + addl $0x0FFFFFFC0, %esp + + # + # Save the bootloader's stack pointer + # + pushl %eax + + # + # Pass entry point of the PEI core + # + call ASM_PFX(GetFspBaseAddress) + movl %eax, %edi + addl ASM_PFX(_gPcd_FixedAtBuild_PcdFspAreaSize), %edi + subl $0x20, %edi + addl %ds:(%edi), %eax + pushl %eax + + # + # Pass BFV into the PEI Core + # It uses relative address to calucate the actual boot FV base + # For FSP impleantion with single FV, PcdFlashFvRecoveryBase and + # PcdFspAreaBaseAddress are the same. For FSP with mulitple FVs, + # they are different. The code below can handle both cases. + # + call ASM_PFX(GetFspBaseAddress) + movl %eax , %edi + call ASM_PFX(GetBootFirmwareVolumeOffset) + addl %edi ,%eax + pushl %eax + + # + # Pass stack base and size into the PEI Core + # + movl ASM_PFX(_gPcd_FixedAtBuild_PcdTemporaryRamBase), %eax + addl ASM_PFX(_gPcd_FixedAtBuild_PcdTemporaryRamSize), %eax + subl ASM_PFX(_gPcd_FixedAtBuild_PcdFspTemporaryRamSize), %eax + pushl %eax + pushl ASM_PFX(_gPcd_FixedAtBuild_PcdFspTemporaryRamSize) + + # + # Pass Control into the PEI Core + # + call ASM_PFX(SecStartup) + +exit3: + ret + +# FspInitApi ENDP + +#---------------------------------------------------------------------------- +# NotifyPhase API +# +# This FSP API will notify the FSP about the different phases in the boot +# process +# +#---------------------------------------------------------------------------- +ASM_GLOBAL ASM_PFX(NotifyPhaseApi) +ASM_PFX(NotifyPhaseApi): + # + # Stack must be ready + # + pushl $0x0087654321 + pop %eax + cmpl $0x087654321, %eax + jz L7 + movl $0x080000003, %eax + jmp err_exit + +L7: + # + # Verify the calling condition + # + pusha + pushl $2 + call ASM_PFX(FspApiCallingCheck) + add $4, %esp + mov %eax, 28(%esp) + popa + + cmpl $0, %eax + jz L8 + + # + # Error return + # +err_exit: + ret + +L8: + jmp ASM_PFX(Pei2LoaderSwitchStack) + +#NotifyPhaseApi ENDP + + +#END diff --git a/IntelFspPkg/FspSecCore/Ia32/InitializeFpu.asm b/IntelFspPkg/FspSecCore/Ia32/InitializeFpu.asm new file mode 100644 index 0000000000..07f504da4b --- /dev/null +++ b/IntelFspPkg/FspSecCore/Ia32/InitializeFpu.asm @@ -0,0 +1,79 @@ +;------------------------------------------------------------------------------ +; +; Copyright (c) 2014, Intel Corporation. All rights reserved.
+; This program and the accompanying materials +; are licensed and made available under the terms and conditions of the BSD License +; which accompanies this distribution. The full text of the license may be found at +; http://opensource.org/licenses/bsd-license.php. +; +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +; +; Abstract: +; +;------------------------------------------------------------------------------ + + .686 + .model flat,C + .const +; +; Float control word initial value: +; all exceptions masked, double-precision, round-to-nearest +; +mFpuControlWord DW 027Fh +; +; Multimedia-extensions control word: +; all exceptions masked, round-to-nearest, flush to zero for masked underflow +; +mMmxControlWord DD 01F80h + + .xmm + .code + +; +; Initializes floating point units for requirement of UEFI specification. +; +; This function initializes floating-point control word to 0x027F (all exceptions +; masked,double-precision, round-to-nearest) and multimedia-extensions control word +; (if supported) to 0x1F80 (all exceptions masked, round-to-nearest, flush to zero +; for masked underflow). +; +InitializeFloatingPointUnits PROC PUBLIC + + push ebx + + ; + ; Initialize floating point units + ; + finit + fldcw mFpuControlWord + + ; + ; Use CpuId instructuion (CPUID.01H:EDX.SSE[bit 25] = 1) to test + ; whether the processor supports SSE instruction. + ; + mov eax, 1 + cpuid + bt edx, 25 + jnc Done + + ; + ; Set OSFXSR bit 9 in CR4 + ; + mov eax, cr4 + or eax, BIT9 + mov cr4, eax + + ; + ; The processor should support SSE instruction and we can use + ; ldmxcsr instruction + ; + ldmxcsr mMmxControlWord +Done: + pop ebx + + ret + +InitializeFloatingPointUnits ENDP + +END diff --git a/IntelFspPkg/FspSecCore/Ia32/InitializeFpu.s b/IntelFspPkg/FspSecCore/Ia32/InitializeFpu.s new file mode 100644 index 0000000000..cfec8d7df5 --- /dev/null +++ b/IntelFspPkg/FspSecCore/Ia32/InitializeFpu.s @@ -0,0 +1,73 @@ +#------------------------------------------------------------------------------ +# +# Copyright (c) 2014, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# Abstract: +# +#------------------------------------------------------------------------------ + +# +# Float control word initial value: +# all exceptions masked, double-precision, round-to-nearest +# +ASM_PFX(mFpuControlWord): .word 0x027F +# +# Multimedia-extensions control word: +# all exceptions masked, round-to-nearest, flush to zero for masked underflow +# +ASM_PFX(mMmxControlWord): .long 0x01F80 + + + +# +# Initializes floating point units for requirement of UEFI specification. +# +# This function initializes floating-point control word to 0x027F (all exceptions +# masked,double-precision, round-to-nearest) and multimedia-extensions control word +# (if supported) to 0x1F80 (all exceptions masked, round-to-nearest, flush to zero +# for masked underflow). +# +ASM_GLOBAL ASM_PFX(InitializeFloatingPointUnits) +ASM_PFX(InitializeFloatingPointUnits): + + pushl %ebx + + # + # Initialize floating point units + # + finit + fldcw ASM_PFX(mFpuControlWord) + + # + # Use CpuId instructuion (CPUID.01H:EDX.SSE[bit 25] = 1) to test + # whether the processor supports SSE instruction. + # + movl $1, %eax + cpuid + btl $25, %edx + jnc Done + + # + # Set OSFXSR bit 9 in CR4 + # + movl %cr4, %eax + or BIT9, %eax + movl %eax, %cr4 + + # + # The processor should support SSE instruction and we can use + # ldmxcsr instruction + # + ldmxcsr ASM_PFX(mMmxControlWord) + +Done: + popl %ebx + + ret diff --git a/IntelFspPkg/FspSecCore/Ia32/ResetVec.asm16 b/IntelFspPkg/FspSecCore/Ia32/ResetVec.asm16 new file mode 100644 index 0000000000..f77c9a46dd --- /dev/null +++ b/IntelFspPkg/FspSecCore/Ia32/ResetVec.asm16 @@ -0,0 +1,103 @@ +;------------------------------------------------------------------------------ +; +; Copyright (c) 2014, Intel Corporation. All rights reserved.
+; This program and the accompanying materials +; are licensed and made available under the terms and conditions of the BSD License +; which accompanies this distribution. The full text of the license may be found at +; http://opensource.org/licenses/bsd-license.php. +; +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +; +; Abstract: +; +; Reset Vector Data structure +; This structure is located at 0xFFFFFFC0 +; +;------------------------------------------------------------------------------ + + .model tiny + .686p + .stack 0h + .code + +; +; The layout of this file is fixed. The build tool makes assumption of the layout. +; + + ORG 0h +; +; Reserved +; +ReservedData DD 0eeeeeeeeh, 0eeeeeeeeh + + ORG 10h +; +; This is located at 0xFFFFFFD0h +; + mov di, "AP" + jmp ApStartup + + ORG 20h +; +; Pointer to the entry point of the PEI core +; It is located at 0xFFFFFFE0, and is fixed up by some build tool +; So if the value 8..1 appears in the final FD image, tool failure occurs. +; +PeiCoreEntryPoint DD 12345678h + +; +; This is the handler for all kinds of exceptions. Since it's for debugging +; purpose only, nothing except a deadloop would be done here. Developers could +; analyze the cause of the exception if a debugger had been attached. +; +InterruptHandler PROC + jmp $ + iret +InterruptHandler ENDP + + ORG 30h +; +; For IA32, the reset vector must be at 0xFFFFFFF0, i.e., 4G-16 byte +; Execution starts here upon power-on/platform-reset. +; +ResetHandler: + nop + nop + +ApStartup: + ; + ; Jmp Rel16 instruction + ; Use machine code directly in case of the assembler optimization + ; SEC entry point relatvie address will be fixed up by some build tool. + ; + ; Typically, SEC entry point is the function _ModuleEntryPoint() defined in + ; SecEntry.asm + ; + DB 0e9h + DW -3 + + + ORG 38h +; +; Ap reset vector segment address is at 0xFFFFFFF8 +; This will be fixed up by some build tool, +; so if the value 1..8 appears in the final FD image, +; tool failure occurs +; +ApSegAddress dd 12345678h + + ORG 3ch +; +; BFV Base is at 0xFFFFFFFC +; This will be fixed up by some build tool, +; so if the value 1..8 appears in the final FD image, +; tool failure occurs. +; +BfvBase DD 12345678h + +; +; Nothing can go here, otherwise the layout of this file would change. +; + + END diff --git a/IntelFspPkg/FspSecCore/Ia32/SaveRestoreSse.inc b/IntelFspPkg/FspSecCore/Ia32/SaveRestoreSse.inc new file mode 100644 index 0000000000..a3d5c47ffa --- /dev/null +++ b/IntelFspPkg/FspSecCore/Ia32/SaveRestoreSse.inc @@ -0,0 +1,103 @@ +;------------------------------------------------------------------------------ +; +; Copyright (c) 2014, Intel Corporation. All rights reserved.
+; This program and the accompanying materials +; are licensed and made available under the terms and conditions of the BSD License +; which accompanies this distribution. The full text of the license may be found at +; http://opensource.org/licenses/bsd-license.php. +; +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +; +; Abstract: +; +; Provide macro for register save/restore using SSE registers +; +;------------------------------------------------------------------------------ + +; +; Define SSE instruction set +; +IFDEF USE_SSE41_FLAG +; +; Define SSE macros using SSE 4.1 instructions +; +SXMMN MACRO XMM, IDX, REG + pinsrd XMM, REG, (IDX AND 3) + ENDM + +LXMMN MACRO XMM, REG, IDX + pextrd REG, XMM, (IDX AND 3) + ENDM +ELSE +; +; Define SSE macros using SSE 2 instructions +; +SXMMN MACRO XMM, IDX, REG + pinsrw XMM, REG, (IDX AND 3) * 2 + ror REG, 16 + pinsrw XMM, REG, (IDX AND 3) * 2 + 1 + rol REG, 16 + ENDM + +LXMMN MACRO XMM, REG, IDX + pshufd XMM, XMM, (0E4E4E4h SHR (IDX * 2)) AND 0FFh + movd REG, XMM + pshufd XMM, XMM, (0E4E4E4h SHR (IDX * 2 + (IDX AND 1) * 4)) AND 0FFh + ENDM +ENDIF + + +SAVE_REGS MACRO + SXMMN xmm7, 0, ebp + SXMMN xmm7, 1, ebx + SXMMN xmm7, 2, esi + SXMMN xmm7, 3, edi + SAVE_ESP + ENDM + +LOAD_REGS MACRO + LXMMN xmm7, ebp, 0 + LXMMN xmm7, ebx, 1 + LXMMN xmm7, esi, 2 + LXMMN xmm7, edi, 3 + LOAD_ESP + ENDM + +LOAD_EAX MACRO + LXMMN xmm6, eax, 1 + ENDM + +SAVE_EAX MACRO + SXMMN xmm6, 1, eax + ENDM + +LOAD_EDX MACRO + LXMMN xmm6, edx, 2 + ENDM + +SAVE_EDX MACRO + SXMMN xmm6, 2, edx + ENDM + +SAVE_ECX MACRO + SXMMN xmm6, 3, ecx + ENDM + +LOAD_ECX MACRO + LXMMN xmm6, ecx, 3 + ENDM + +SAVE_ESP MACRO + SXMMN xmm6, 0, esp + ENDM + +LOAD_ESP MACRO + movd esp, xmm6 + ENDM + +ENABLE_SSE MACRO + mov eax, cr4 + or eax, 00000600h + mov cr4, eax + ENDM diff --git a/IntelFspPkg/FspSecCore/Ia32/Stack.asm b/IntelFspPkg/FspSecCore/Ia32/Stack.asm new file mode 100644 index 0000000000..f96a55f040 --- /dev/null +++ b/IntelFspPkg/FspSecCore/Ia32/Stack.asm @@ -0,0 +1,82 @@ +;------------------------------------------------------------------------------ +; +; Copyright (c) 2014, Intel Corporation. All rights reserved.
+; This program and the accompanying materials +; are licensed and made available under the terms and conditions of the BSD License +; which accompanies this distribution. The full text of the license may be found at +; http://opensource.org/licenses/bsd-license.php. +; +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +; +; Abstract: +; +; Switch the stack from temporary memory to permenent memory. +; +;------------------------------------------------------------------------------ + + .586p + .model flat,C + .code + +;------------------------------------------------------------------------------ +; VOID +; EFIAPI +; SecSwitchStack ( +; UINT32 TemporaryMemoryBase, +; UINT32 PermenentMemoryBase +; ); +;------------------------------------------------------------------------------ +SecSwitchStack PROC + ; + ; Save three register: eax, ebx, ecx + ; + push eax + push ebx + push ecx + push edx + + ; + ; !!CAUTION!! this function address's is pushed into stack after + ; migration of whole temporary memory, so need save it to permenent + ; memory at first! + ; + + mov ebx, [esp + 20] ; Save the first parameter + mov ecx, [esp + 24] ; Save the second parameter + + ; + ; Save this function's return address into permenent memory at first. + ; Then, Fixup the esp point to permenent memory + ; + mov eax, esp + sub eax, ebx + add eax, ecx + mov edx, dword ptr [esp] ; copy pushed register's value to permenent memory + mov dword ptr [eax], edx + mov edx, dword ptr [esp + 4] + mov dword ptr [eax + 4], edx + mov edx, dword ptr [esp + 8] + mov dword ptr [eax + 8], edx + mov edx, dword ptr [esp + 12] + mov dword ptr [eax + 12], edx + mov edx, dword ptr [esp + 16] ; Update this function's return address into permenent memory + mov dword ptr [eax + 16], edx + mov esp, eax ; From now, esp is pointed to permenent memory + + ; + ; Fixup the ebp point to permenent memory + ; + mov eax, ebp + sub eax, ebx + add eax, ecx + mov ebp, eax ; From now, ebp is pointed to permenent memory + + pop edx + pop ecx + pop ebx + pop eax + ret +SecSwitchStack ENDP + + END diff --git a/IntelFspPkg/FspSecCore/Ia32/Stacks.s b/IntelFspPkg/FspSecCore/Ia32/Stacks.s new file mode 100644 index 0000000000..6c36c25d2b --- /dev/null +++ b/IntelFspPkg/FspSecCore/Ia32/Stacks.s @@ -0,0 +1,88 @@ +#------------------------------------------------------------------------------ +# +# Copyright (c) 2014, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# Abstract: +# +# Switch the stack from temporary memory to permenent memory. +# +#------------------------------------------------------------------------------ + +ASM_GLOBAL ASM_PFX(SecSwitchStack) + +#------------------------------------------------------------------------------ +# VOID +# EFIAPI +# SecSwitchStack ( +# UINT32 TemporaryMemoryBase, +# UINT32 PermenentMemoryBase +# ) +#------------------------------------------------------------------------------ +ASM_GLOBAL ASM_PFX(SecSwitchStack) +ASM_PFX(SecSwitchStack): +# +# Save three register: eax, ebx, ecx +# + push %eax + push %ebx + push %ecx + push %edx + +# +# !!CAUTION!! this function address's is pushed into stack after +# migration of whole temporary memory, so need save it to permenent +# memory at first! +# + + movl 20(%esp), %ebx # Save the first parameter + movl 24(%esp), %ecx # Save the second parameter + +# +# Save this function's return address into permenent memory at first. +# Then, Fixup the esp point to permenent memory +# + + movl %esp, %eax + subl %ebx, %eax + addl %ecx, %eax + movl (%esp), %edx # copy pushed register's value to permenent memory + movl %edx, (%eax) + movl 4(%esp), %edx + movl %edx, 4(%eax) + movl 8(%esp), %edx + movl %edx, 8(%eax) + movl 12(%esp), %edx + movl %edx, 12(%eax) + movl 16(%esp), %edx # Update this function's return address into permenent memory + movl %edx, 16(%eax) + movl %eax, %esp # From now, esp is pointed to permenent memory + +# +# Fixup the ebp point to permenent memory +# + + movl %ebp, %eax + subl %ebx, %eax + addl %ecx, %eax + movl %eax, %ebp # From now, ebp is pointed to permenent memory + +# +# Fixup callee's ebp point for PeiDispatch +# + movl %ebp, %eax + subl %ebx, %eax + addl %ecx, %eax + movl %eax, %ebp # From now, ebp is pointed to permenent memory + + pop %edx + pop %ecx + pop %ebx + pop %eax + ret \ No newline at end of file diff --git a/IntelFspPkg/FspSecCore/Ia32/UcodeLoad.inc b/IntelFspPkg/FspSecCore/Ia32/UcodeLoad.inc new file mode 100644 index 0000000000..6be6ed097b --- /dev/null +++ b/IntelFspPkg/FspSecCore/Ia32/UcodeLoad.inc @@ -0,0 +1,63 @@ +;------------------------------------------------------------------------------ +; +; Copyright (c) 2014, Intel Corporation. All rights reserved.
+; This program and the accompanying materials +; are licensed and made available under the terms and conditions of the BSD License +; which accompanies this distribution. The full text of the license may be found at +; http://opensource.org/licenses/bsd-license.php. +; +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +; +; Abstract: +; +;------------------------------------------------------------------------------ + +MSR_IA32_PLATFORM_ID EQU 000000017h +MSR_IA32_BIOS_UPDT_TRIG EQU 000000079h +MSR_IA32_BIOS_SIGN_ID EQU 00000008bh + +ucode STRUCT 1t + version DWORD ? + revision DWORD ? + date DWORD ? + processor DWORD ? + checksum DWORD ? + loader DWORD ? + rsvd DWORD 6t DUP (?) + data DWORD 500t DUP (?) +ucode ENDS +ucode_t TYPEDEF ucode + +ucode_hdr STRUCT 1t + version DWORD ? + revision DWORD ? + date DWORD ? + processor DWORD ? + checksum DWORD ? + loader DWORD ? + flags DWORD ? + data_size DWORD ? + total_size DWORD ? + rsvd DWORD 3t DUP (?) +ucode_hdr ENDS +ucode_hdr_t TYPEDEF ucode_hdr + +ext_sig_hdr STRUCT 1t + count DWORD ? + checksum DWORD ? + rsvd DWORD 3t DUP (?) +ext_sig_hdr ENDS +ext_sig_hdr_t TYPEDEF ext_sig_hdr + +ext_sig STRUCT 1t + processor DWORD ? + flags DWORD ? + checksum DWORD ? +ext_sig ENDS +ext_sig_t TYPEDEF ext_sig + +LOAD_UCODE_PARAMS STRUCT 1t + ucode_code_addr DWORD ? + ucode_code_size DWORD ? +LOAD_UCODE_PARAMS ENDS diff --git a/IntelFspPkg/FspSecCore/SecFsp.c b/IntelFspPkg/FspSecCore/SecFsp.c new file mode 100644 index 0000000000..00eb224c6f --- /dev/null +++ b/IntelFspPkg/FspSecCore/SecFsp.c @@ -0,0 +1,268 @@ +/** @file + + Copyright (c) 2014, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "SecFsp.h" + +UINT32 FspImageSizeOffset = FSP_INFO_HEADER_OFF + OFFSET_IN_FSP_INFO_HEADER(ImageSize); + +/** + + Calculate the FSP IDT gate descriptor. + + @param[in] IdtEntryTemplate IDT gate descriptor template. + + @return FSP specific IDT gate descriptor. + +**/ +UINT64 +FspGetExceptionHandler( + IN UINT64 IdtEntryTemplate + ) +{ + UINT32 Entry; + UINT64 ExceptionHandler; + IA32_IDT_GATE_DESCRIPTOR *IdtGateDescriptor; + FSP_INFO_HEADER *FspInfoHeader; + + FspInfoHeader = (FSP_INFO_HEADER *)(GetFspBaseAddress() + FSP_INFO_HEADER_OFF); + ExceptionHandler = IdtEntryTemplate; + IdtGateDescriptor = (IA32_IDT_GATE_DESCRIPTOR *)&ExceptionHandler; + Entry = (IdtGateDescriptor->Bits.OffsetHigh << 16) | IdtGateDescriptor->Bits.OffsetLow; + Entry = FspInfoHeader->ImageBase + FspInfoHeader->ImageSize - (~Entry + 1); + IdtGateDescriptor->Bits.OffsetHigh = (UINT16)(Entry >> 16); + IdtGateDescriptor->Bits.OffsetLow = (UINT16)Entry; + + return ExceptionHandler; +} + +/** + This function gets the FSP UPD region offset in flash. + + @return the offset of the UPD region. + +**/ +UINT32 +EFIAPI +GetFspUpdRegionOffset ( + VOID + ) +{ + FSP_GLOBAL_DATA *FspData; + UINT32 *Offset; + + FspData = GetFspGlobalDataPointer (); + + // + // It is required to put PcdUpdRegionOffset at offset 0x000C + // for all FSPs. + // gPlatformFspPkgTokenSpaceGuid.PcdUpdRegionOffset | 0x000C | 0x12345678 + // + Offset = (UINT32 *)(FspData->FspInfoHeader->ImageBase + \ + FspData->FspInfoHeader->CfgRegionOffset + 0x0C); + + return *Offset; +} + +/** + This interface fills platform specific data. + + @param[in,out] FspData Pointer to the FSP global data. + +**/ +VOID +EFIAPI +SecGetPlatformData ( + IN OUT FSP_GLOBAL_DATA *FspData + ) +{ + FSP_PLAT_DATA *FspPlatformData; + UINT32 TopOfCar; + UINT32 *StackPtr; + UINT32 DwordSize; + + FspPlatformData = &FspData->PlatformData; + + // + // The entries of platform information, together with the number of them, + // reside in the bottom of stack, left untouched by normal stack operation. + // + TopOfCar = PcdGet32 (PcdTemporaryRamBase) + PcdGet32 (PcdTemporaryRamSize); + + FspPlatformData->DataPtr = NULL; + FspPlatformData->CodeRegionSize = 0; + FspPlatformData->CodeRegionBase = 0; + FspPlatformData->MicorcodeRegionBase = 0; + FspPlatformData->MicorcodeRegionSize = 0; + + // + // Pointer to the size field + // + StackPtr = (UINT32 *)(TopOfCar - sizeof(UINT32)); + + while (*StackPtr != 0) { + if (*(StackPtr - 1) == FSP_MCUD_SIGNATURE) { + // + // This following data was pushed onto stack after TempRamInit API + // + DwordSize = 4; + StackPtr = StackPtr - 1 - DwordSize; + CopyMem (&(FspPlatformData->CodeRegionBase), StackPtr, (DwordSize << 2)); + StackPtr--; + } else if (*(StackPtr - 1) == FSP_PER0_SIGNATURE) { + // + // This is the performance data for InitTempMemory API entry/exit + // + DwordSize = 4; + StackPtr = StackPtr - 1 - DwordSize; + CopyMem (FspData->PerfData, StackPtr, (DwordSize << 2)); + ((UINT8 *)(&FspData->PerfData[0]))[7] = FSP_PERF_ID_API_TMPRAMINIT_ENTRY; + ((UINT8 *)(&FspData->PerfData[1]))[7] = FSP_PERF_ID_API_TMPRAMINIT_EXIT; + StackPtr--; + } else { + StackPtr -= (*StackPtr); + } + } +} + +/** + + Initialize the FSP global data region. + It needs to be done as soon as possible after the stack is setup. + + @param[in,out] PeiFspData Pointer of the FSP global data. + @param[in] BootFirmwareVolume Point to the address of BootFirmwareVolume in stack. + +**/ +VOID +FspGlobalDataInit ( + IN OUT FSP_GLOBAL_DATA *PeiFspData, + IN VOID **BootFirmwareVolume + ) +{ + VOID *UpdDataRgnPtr; + FSP_INIT_PARAMS *FspInitParams; + CHAR8 ImageId[9]; + UINTN Idx; + + // + // Init PCIE_BAR with value and set global FSP data pointer. + // PciExpress Base should have been programmed by platform already. + // + SetFspGlobalDataPointer (PeiFspData); + ZeroMem ((VOID *)PeiFspData, sizeof(FSP_GLOBAL_DATA)); + + PeiFspData->Signature = FSP_GLOBAL_DATA_SIGNATURE; + PeiFspData->CoreStack = *(UINTN *)(BootFirmwareVolume + 2); + PeiFspData->PerfIdx = 2; + + SetFspMeasurePoint (FSP_PERF_ID_API_FSPINIT_ENTRY); + + // + // Get FSP Header offset + // It may have multiple FVs, so look into the last one for FSP header + // + PeiFspData->FspInfoHeader = (FSP_INFO_HEADER *)(GetFspBaseAddress() + FSP_INFO_HEADER_OFF); + SecGetPlatformData (PeiFspData); + + // + // Initialize UPD pointer. + // + FspInitParams = (FSP_INIT_PARAMS *)GetFspApiParameter (); + UpdDataRgnPtr = ((FSP_INIT_RT_COMMON_BUFFER *)FspInitParams->RtBufferPtr)->UpdDataRgnPtr; + if (UpdDataRgnPtr == NULL) { + UpdDataRgnPtr = (VOID *)(PeiFspData->FspInfoHeader->ImageBase + GetFspUpdRegionOffset()); + } + SetFspUpdDataPointer (UpdDataRgnPtr); + + // + // Initialize serial port + // It might have been done in ProcessLibraryConstructorList(), however, + // the FSP global data is not initialized at that time. So do it again + // for safe. + // + SerialPortInitialize (); + + // + // Ensure the golbal data pointer is valid + // + ASSERT (GetFspGlobalDataPointer () == PeiFspData); + + for (Idx = 0; Idx < 8; Idx++) { + ImageId[Idx] = PeiFspData->FspInfoHeader->ImageId[Idx]; + } + ImageId[Idx] = 0; + + DEBUG ((DEBUG_INFO | DEBUG_INIT, "\n============= PEIM FSP (%a 0x%08X) =============\n", \ + ImageId, PeiFspData->FspInfoHeader->ImageRevision)); + +} + +/** + + Adjust the FSP data pointers after the stack is migrated to memory. + + @param[in] OffsetGap The offset gap between the old stack and the new stack. + +**/ +VOID +FspDataPointerFixUp ( + IN UINT32 OffsetGap + ) +{ + FSP_GLOBAL_DATA *NewFspData; + + NewFspData = (FSP_GLOBAL_DATA *)((UINTN)GetFspGlobalDataPointer() + (UINTN)OffsetGap); + SetFspGlobalDataPointer (NewFspData); +} + +/** + This function check the FSP API calling condition. + + @param[in] ApiIdx Internal index of the FSP API. + +**/ +EFI_STATUS +EFIAPI +FspApiCallingCheck ( + UINT32 ApiIdx + ) +{ + EFI_STATUS Status; + FSP_GLOBAL_DATA *FspData; + + Status = EFI_SUCCESS; + FspData = GetFspGlobalDataPointer (); + if (ApiIdx == 1) { + // + // FspInit check + // + if ((UINT32)FspData != 0xFFFFFFFF) { + Status = EFI_UNSUPPORTED; + } + } else if (ApiIdx == 2) { + // + // NotifyPhase check + // + if ((FspData == NULL) || ((UINT32)FspData == 0xFFFFFFFF)) { + Status = EFI_UNSUPPORTED; + } else { + if (FspData->Signature != FSP_GLOBAL_DATA_SIGNATURE) { + Status = EFI_UNSUPPORTED; + } + } + } else { + Status = EFI_UNSUPPORTED; + } + + return Status; +} diff --git a/IntelFspPkg/FspSecCore/SecFsp.h b/IntelFspPkg/FspSecCore/SecFsp.h new file mode 100644 index 0000000000..9e129e4d5d --- /dev/null +++ b/IntelFspPkg/FspSecCore/SecFsp.h @@ -0,0 +1,97 @@ +/** @file + + Copyright (c) 2014, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _SEC_FSP_H_ +#define _SEC_FSPE_H_ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#define FSP_MCUD_SIGNATURE SIGNATURE_32 ('M', 'C', 'U', 'D') +#define FSP_PER0_SIGNATURE SIGNATURE_32 ('P', 'E', 'R', '0') + +/** + + Calculate the FSP IDT gate descriptor. + + @param[in] IdtEntryTemplate IDT gate descriptor template. + + @return FSP specific IDT gate descriptor. + +**/ +UINT64 +FspGetExceptionHandler( + IN UINT64 IdtEntryTemplate + ); + +/** + + Initialize the FSP global data region. + It needs to be done as soon as possible after the stack is setup. + + @param[in,out] PeiFspData Pointer of the FSP global data. + @param[in] BootFirmwareVolume Point to the address of BootFirmwareVolume in stack. + +**/ +VOID +FspGlobalDataInit ( + IN OUT FSP_GLOBAL_DATA *PeiFspData, + IN VOID **BootFirmwareVolume + ); + + +/** + + Adjust the FSP data pointers after the stack is migrated to memory. + + @param[in] OffsetGap The offset gap between the old stack and the new stack. + +**/ +VOID +FspDataPointerFixUp ( + IN UINT32 OffsetGap + ); + + +/** + This interface returns the base address of FSP binary. + + @return FSP binary base address. + +**/ +UINT32 +EFIAPI +GetFspBaseAddress ( + VOID + ); + +/** + This function gets the FSP UPD region offset in flash. + + @return the offset of the UPD region. + +**/ +UINT32 +EFIAPI +GetFspUpdRegionOffset ( + VOID + ); + +#endif diff --git a/IntelFspPkg/FspSecCore/SecMain.c b/IntelFspPkg/FspSecCore/SecMain.c new file mode 100644 index 0000000000..22706c8a8b --- /dev/null +++ b/IntelFspPkg/FspSecCore/SecMain.c @@ -0,0 +1,208 @@ +/** @file + + Copyright (c) 2014, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "SecMain.h" +#include "SecFsp.h" + +EFI_PEI_TEMPORARY_RAM_SUPPORT_PPI gSecTemporaryRamSupportPpi = { + SecTemporaryRamSupport +}; + +EFI_PEI_PPI_DESCRIPTOR mPeiSecPlatformInformationPpi[] = { + { + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiTemporaryRamSupportPpiGuid, + &gSecTemporaryRamSupportPpi + } +}; + +// +// These are IDT entries pointing to 08:FFFFFFE4h. +// +UINT64 mIdtEntryTemplate = 0xffff8e000008ffe4ULL; + +/** + + Entry point to the C language phase of SEC. After the SEC assembly + code has initialized some temporary memory and set up the stack, + the control is transferred to this function. + + + @param[in] SizeOfRam Size of the temporary memory available for use. + @param[in] TempRamBase Base address of tempory ram + @param[in] BootFirmwareVolume Base address of the Boot Firmware Volume. + + @return This function never returns. + +**/ +VOID +EFIAPI +SecStartup ( + IN UINT32 SizeOfRam, + IN UINT32 TempRamBase, + IN VOID *BootFirmwareVolume + ) +{ + EFI_SEC_PEI_HAND_OFF SecCoreData; + IA32_DESCRIPTOR IdtDescriptor; + SEC_IDT_TABLE IdtTableInStack; + UINT32 Index; + FSP_GLOBAL_DATA PeiFspData; + PEI_CORE_ENTRY PeiCore; + UINT64 ExceptionHandler; + + // + // Process all libraries constructor function linked to SecCore. + // + ProcessLibraryConstructorList (); + + // + // Initialize floating point operating environment + // to be compliant with UEFI spec. + // + InitializeFloatingPointUnits (); + + + // |-------------------|----> + // |Idt Table | + // |-------------------| + // |PeiService Pointer | PeiStackSize + // |-------------------| + // | | + // | Stack | + // |-------------------|----> + // | | + // | | + // | Heap | PeiTemporayRamSize + // | | + // | | + // |-------------------|----> TempRamBase + IdtTableInStack.PeiService = NULL; + ExceptionHandler = FspGetExceptionHandler(mIdtEntryTemplate); + for (Index = 0; Index < SEC_IDT_ENTRY_COUNT; Index ++) { + CopyMem ((VOID*)&IdtTableInStack.IdtTable[Index], (VOID*)&ExceptionHandler, sizeof (UINT64)); + } + + IdtDescriptor.Base = (UINTN) &IdtTableInStack.IdtTable; + IdtDescriptor.Limit = (UINT16)(sizeof (IdtTableInStack.IdtTable) - 1); + + AsmWriteIdtr (&IdtDescriptor); + + // + // Iniitalize the global FSP data region + // + FspGlobalDataInit (&PeiFspData, &BootFirmwareVolume); + + // + // Update the base address and length of Pei temporary memory + // + SecCoreData.DataSize = sizeof (EFI_SEC_PEI_HAND_OFF); + SecCoreData.BootFirmwareVolumeBase = BootFirmwareVolume; + SecCoreData.BootFirmwareVolumeSize = (UINT32)((EFI_FIRMWARE_VOLUME_HEADER *)BootFirmwareVolume)->FvLength; + SecCoreData.TemporaryRamBase = (VOID*)(UINTN) TempRamBase; + SecCoreData.TemporaryRamSize = SizeOfRam; + SecCoreData.PeiTemporaryRamBase = SecCoreData.TemporaryRamBase; + SecCoreData.PeiTemporaryRamSize = SizeOfRam >> 1; + SecCoreData.StackBase = (VOID*)(UINTN)(TempRamBase + SecCoreData.PeiTemporaryRamSize); + SecCoreData.StackSize = SizeOfRam >> 1; + + // + // Call PeiCore Entry + // + PeiCore = (PEI_CORE_ENTRY)(*(UINTN *)((&BootFirmwareVolume) + 1)); + PeiCore (&SecCoreData, mPeiSecPlatformInformationPpi); + + // + // Should never be here + // + CpuDeadLoop (); +} + +/** + This service of the TEMPORARY_RAM_SUPPORT_PPI that migrates temporary RAM into + permanent memory. + + @param[in] PeiServices Pointer to the PEI Services Table. + @param[in] TemporaryMemoryBase Source Address in temporary memory from which the SEC or PEIM will copy the + Temporary RAM contents. + @param[in] PermanentMemoryBase Destination Address in permanent memory into which the SEC or PEIM will copy the + Temporary RAM contents. + @param[in] CopySize Amount of memory to migrate from temporary to permanent memory. + + @retval EFI_SUCCESS The data was successfully returned. + @retval EFI_INVALID_PARAMETER PermanentMemoryBase + CopySize > TemporaryMemoryBase when + TemporaryMemoryBase > PermanentMemoryBase. + +**/ +EFI_STATUS +EFIAPI +SecTemporaryRamSupport ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN EFI_PHYSICAL_ADDRESS TemporaryMemoryBase, + IN EFI_PHYSICAL_ADDRESS PermanentMemoryBase, + IN UINTN CopySize + ) +{ + IA32_DESCRIPTOR IdtDescriptor; + VOID* OldHeap; + VOID* NewHeap; + VOID* OldStack; + VOID* NewStack; + + OldHeap = (VOID*)(UINTN)TemporaryMemoryBase; + NewHeap = (VOID*)((UINTN)PermanentMemoryBase + CopySize / 2); + + OldStack = (VOID*)((UINTN)TemporaryMemoryBase + CopySize / 2); + NewStack = (VOID*)(UINTN)PermanentMemoryBase; + + // + // Migrate Heap + // + CopyMem (NewHeap, OldHeap, CopySize / 2); + + // + // Migrate Stack + // + CopyMem (NewStack, OldStack, CopySize / 2); + + + // + // We need *not* fix the return address because currently, + // The PeiCore is executed in flash. + // + + // + // Rebase IDT table in permanent memory + // + AsmReadIdtr (&IdtDescriptor); + IdtDescriptor.Base = IdtDescriptor.Base - (UINTN)OldStack + (UINTN)NewStack; + + AsmWriteIdtr (&IdtDescriptor); + + // + // Fixed the FSP data pointer + // + FspDataPointerFixUp ((UINTN)NewStack - (UINTN)OldStack); + + // + // SecSwitchStack function must be invoked after the memory migration + // immediatly, also we need fixup the stack change caused by new call into + // permenent memory. + // + SecSwitchStack ( + (UINT32) (UINTN) OldStack, + (UINT32) (UINTN) NewStack + ); + + return EFI_SUCCESS; +} diff --git a/IntelFspPkg/FspSecCore/SecMain.h b/IntelFspPkg/FspSecCore/SecMain.h new file mode 100644 index 0000000000..4dfbc850b3 --- /dev/null +++ b/IntelFspPkg/FspSecCore/SecMain.h @@ -0,0 +1,134 @@ +/** @file + + Copyright (c) 2014, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _SEC_CORE_H_ +#define _SEC_CORE_H_ + + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SEC_IDT_ENTRY_COUNT 34 + +typedef VOID (*PEI_CORE_ENTRY) ( \ + IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData, \ + IN CONST EFI_PEI_PPI_DESCRIPTOR *PpiList \ +); + +typedef struct _SEC_IDT_TABLE { + EFI_PEI_SERVICES *PeiService; + UINT64 IdtTable[SEC_IDT_ENTRY_COUNT]; +} SEC_IDT_TABLE; + +/** + Switch the stack in the temporary memory to the one in the permanent memory. + + This function must be invoked after the memory migration immediately. The relative + position of the stack in the temporary and permanent memory is same. + + @param[in] TemporaryMemoryBase Base address of the temporary memory. + @param[in] PermenentMemoryBase Base address of the permanent memory. +**/ +VOID +EFIAPI +SecSwitchStack ( + IN UINT32 TemporaryMemoryBase, + IN UINT32 PermenentMemoryBase + ); + +/** + This service of the TEMPORARY_RAM_SUPPORT_PPI that migrates temporary RAM into + permanent memory. + + @param[in] PeiServices Pointer to the PEI Services Table. + @param[in] TemporaryMemoryBase Source Address in temporary memory from which the SEC or PEIM will copy the + Temporary RAM contents. + @param[in] PermanentMemoryBase Destination Address in permanent memory into which the SEC or PEIM will copy the + Temporary RAM contents. + @param[in] CopySize Amount of memory to migrate from temporary to permanent memory. + + @retval EFI_SUCCESS The data was successfully returned. + @retval EFI_INVALID_PARAMETER PermanentMemoryBase + CopySize > TemporaryMemoryBase when + TemporaryMemoryBase > PermanentMemoryBase. + +**/ +EFI_STATUS +EFIAPI +SecTemporaryRamSupport ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN EFI_PHYSICAL_ADDRESS TemporaryMemoryBase, + IN EFI_PHYSICAL_ADDRESS PermanentMemoryBase, + IN UINTN CopySize + ); + +/** + Initializes floating point units for requirement of UEFI specification. + + This function initializes floating-point control word to 0x027F (all exceptions + masked,double-precision, round-to-nearest) and multimedia-extensions control word + (if supported) to 0x1F80 (all exceptions masked, round-to-nearest, flush to zero + for masked underflow). + +**/ +VOID +EFIAPI +InitializeFloatingPointUnits ( + VOID + ); + +/** + + Entry point to the C language phase of SEC. After the SEC assembly + code has initialized some temporary memory and set up the stack, + the control is transferred to this function. + + + @param[in] SizeOfRam Size of the temporary memory available for use. + @param[in] TempRamBase Base address of tempory ram + @param[in] BootFirmwareVolume Base address of the Boot Firmware Volume. + + @return This function never returns. + +**/ +VOID +EFIAPI +SecStartup ( + IN UINT32 SizeOfRam, + IN UINT32 TempRamBase, + IN VOID *BootFirmwareVolume + ); + +/** + Autogenerated function that calls the library constructors for all of the module's + dependent libraries. This function must be called by the SEC Core once a stack has + been established. + +**/ +VOID +EFIAPI +ProcessLibraryConstructorList ( + VOID + ); + +#endif diff --git a/IntelFspPkg/FspSecCore/Vtf0/Bin/ResetVec.ia32.raw b/IntelFspPkg/FspSecCore/Vtf0/Bin/ResetVec.ia32.raw new file mode 100644 index 0000000000000000000000000000000000000000..2dc9f178d356d4ab4393963428f32ad3f0dfabf2 GIT binary patch literal 68 scmbO*VZwxWP{05M`yB&b%fdK7x+2U(==HzzaFGcUUjF?L6$i-y0C9#E0ssI2 literal 0 HcmV?d00001 diff --git a/IntelFspPkg/FspSecCore/Vtf0/Build.py b/IntelFspPkg/FspSecCore/Vtf0/Build.py new file mode 100644 index 0000000000..3018391445 --- /dev/null +++ b/IntelFspPkg/FspSecCore/Vtf0/Build.py @@ -0,0 +1,53 @@ +## @file +# Automate the process of building the various reset vector types +# +# Copyright (c) 2014, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# + +import glob +import os +import subprocess +import sys + +def RunCommand(commandLine): + #print ' '.join(commandLine) + return subprocess.call(commandLine) + +for filename in glob.glob(os.path.join('Bin', '*.raw')): + os.remove(filename) + +arch = 'ia32' +debugType = None +output = os.path.join('Bin', 'ResetVec') +output += '.' + arch +if debugType is not None: + output += '.' + debugType +output += '.raw' +commandLine = ( + 'nasm', + '-D', 'ARCH_%s' % arch.upper(), + '-D', 'DEBUG_%s' % str(debugType).upper(), + '-o', output, + 'ResetVectorCode.asm', + ) +ret = RunCommand(commandLine) +print '\tASM\t' + output +if ret != 0: sys.exit(ret) + +commandLine = ( + 'python', + 'Tools/FixupForRawSection.py', + output, + ) +print '\tFIXUP\t' + output +ret = RunCommand(commandLine) +if ret != 0: sys.exit(ret) + diff --git a/IntelFspPkg/FspSecCore/Vtf0/Ia16/ResetVec.asm16 b/IntelFspPkg/FspSecCore/Vtf0/Ia16/ResetVec.asm16 new file mode 100644 index 0000000000..585876fa86 --- /dev/null +++ b/IntelFspPkg/FspSecCore/Vtf0/Ia16/ResetVec.asm16 @@ -0,0 +1,103 @@ +;; @file +; Reset Vector Data structure +; This structure is located at 0xFFFFFFC0 +; +; Copyright (c) 2014, Intel Corporation. All rights reserved.
+; This program and the accompanying materials +; are licensed and made available under the terms and conditions of the BSD License +; which accompanies this distribution. The full text of the license may be found at +; http://opensource.org/licenses/bsd-license.php. +; +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +; +;; + +BITS 16 + + +; +; The layout of this file is fixed. The build tool makes assumption of the layout. +; + +ORG 0x0 +; +; Reserved +; +ReservedData: DD 0eeeeeeeeh, 0eeeeeeeeh + + ; ORG 0x10 + TIMES 0x10-($-$$) DB 0 +; +; This is located at 0xFFFFFFD0h +; + mov di, "AP" + jmp ApStartup + + ; ORG 0x20 + + TIMES 0x20-($-$$) DB 0 + +; Pointer to the entry point of the PEI core +; It is located at 0xFFFFFFE0, and is fixed up by some build tool +; So if the value 8..1 appears in the final FD image, tool failure occurs. +; +PeiCoreEntryPoint: DD 0x12345678 + +; +; This is the handler for all kinds of exceptions. Since it's for debugging +; purpose only, nothing except a deadloop would be done here. Developers could +; analyze the cause of the exception if a debugger had been attached. +; +InterruptHandler: + jmp $ + iret + + ; ORG 0x30 + TIMES 0x30-($-$$) DB 0 +; +; For IA32, the reset vector must be at 0xFFFFFFF0, i.e., 4G-16 byte +; Execution starts here upon power-on/platform-reset. +; +ResetHandler: + nop + nop + +ApStartup: + ; + ; Jmp Rel16 instruction + ; Use machine code directly in case of the assembler optimization + ; SEC entry point relatvie address will be fixed up by some build tool. + ; + ; Typically, SEC entry point is the function _ModuleEntryPoint() defined in + ; SecEntry.asm + ; + DB 0x0e9 + DW -3 + + ; ORG 0x38 + + TIMES 0x38-($-$$) DB 0 +; +; Ap reset vector segment address is at 0xFFFFFFF8 +; This will be fixed up by some build tool, +; so if the value 1..8 appears in the final FD image, +; tool failure occurs +; +ApSegAddress: dd 0x12345678 + + ; ORG 0x3c + TIMES 0x3c-($-$$) DB 0 +; +; BFV Base is at 0xFFFFFFFC +; This will be fixed up by some build tool, +; so if the value 1..8 appears in the final FD image, +; tool failure occurs. +; +BfvBase: DD 0x12345678 + +; +; Nothing can go here, otherwise the layout of this file would change. +; + + ; END diff --git a/IntelFspPkg/FspSecCore/Vtf0/ResetVectorCode.asm b/IntelFspPkg/FspSecCore/Vtf0/ResetVectorCode.asm new file mode 100644 index 0000000000..72b252491f --- /dev/null +++ b/IntelFspPkg/FspSecCore/Vtf0/ResetVectorCode.asm @@ -0,0 +1,17 @@ +;------------------------------------------------------------------------------ +; @file +; This file includes all other code files to assemble the reset vector code +; +; Copyright (c) 2014, Intel Corporation. All rights reserved.
+; This program and the accompanying materials +; are licensed and made available under the terms and conditions of the BSD License +; which accompanies this distribution. The full text of the license may be found at +; http://opensource.org/licenses/bsd-license.php +; +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +; +;------------------------------------------------------------------------------ + + +%include "Ia16/ResetVec.asm16" diff --git a/IntelFspPkg/FspSecCore/Vtf0/Tools/FixupForRawSection.py b/IntelFspPkg/FspSecCore/Vtf0/Tools/FixupForRawSection.py new file mode 100644 index 0000000000..8e7c20b401 --- /dev/null +++ b/IntelFspPkg/FspSecCore/Vtf0/Tools/FixupForRawSection.py @@ -0,0 +1,110 @@ +## @file +# Apply fixup to VTF binary image for FFS Raw section +# +# Copyright (c) 2014, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# + +import sys + +filename = sys.argv[1] + +if filename.lower().find('ia32') >= 0: + d = open(sys.argv[1], 'rb').read() + c = ((len(d) + 4 + 7) & ~7) - 4 + if c > len(d): + c -= len(d) + f = open(sys.argv[1], 'wb') + f.write('\x90' * c) + f.write(d) + f.close() +else: + from struct import pack + + PAGE_PRESENT = 0x01 + PAGE_READ_WRITE = 0x02 + PAGE_USER_SUPERVISOR = 0x04 + PAGE_WRITE_THROUGH = 0x08 + PAGE_CACHE_DISABLE = 0x010 + PAGE_ACCESSED = 0x020 + PAGE_DIRTY = 0x040 + PAGE_PAT = 0x080 + PAGE_GLOBAL = 0x0100 + PAGE_2M_MBO = 0x080 + PAGE_2M_PAT = 0x01000 + + def NopAlign4k(s): + c = ((len(s) + 0xfff) & ~0xfff) - len(s) + return ('\x90' * c) + s + + def PageDirectoryEntries4GbOf2MbPages(baseAddress): + + s = '' + for i in range(0x800): + i = ( + baseAddress + long(i << 21) + + PAGE_2M_MBO + + PAGE_CACHE_DISABLE + + PAGE_ACCESSED + + PAGE_DIRTY + + PAGE_READ_WRITE + + PAGE_PRESENT + ) + s += pack('Q', i) + return s + + def PageDirectoryPointerTable4GbOf2MbPages(pdeBase): + s = '' + for i in range(0x200): + i = ( + pdeBase + + (min(i, 3) << 12) + + PAGE_CACHE_DISABLE + + PAGE_ACCESSED + + PAGE_READ_WRITE + + PAGE_PRESENT + ) + s += pack('Q', i) + return s + + def PageMapLevel4Table4GbOf2MbPages(pdptBase): + s = '' + for i in range(0x200): + i = ( + pdptBase + + (min(i, 0) << 12) + + PAGE_CACHE_DISABLE + + PAGE_ACCESSED + + PAGE_READ_WRITE + + PAGE_PRESENT + ) + s += pack('Q', i) + return s + + def First4GbPageEntries(topAddress): + PDE = PageDirectoryEntries4GbOf2MbPages(0L) + pml4tBase = topAddress - 0x1000 + pdptBase = pml4tBase - 0x1000 + pdeBase = pdptBase - len(PDE) + PDPT = PageDirectoryPointerTable4GbOf2MbPages(pdeBase) + PML4T = PageMapLevel4Table4GbOf2MbPages(pdptBase) + return PDE + PDPT + PML4T + + def AlignAndAddPageTables(): + d = open(sys.argv[1], 'rb').read() + code = NopAlign4k(d) + topAddress = 0x100000000 - len(code) + d = ('\x90' * 4) + First4GbPageEntries(topAddress) + code + f = open(sys.argv[1], 'wb') + f.write(d) + f.close() + + AlignAndAddPageTables() + diff --git a/IntelFspPkg/Include/Guid/GuidHobFsp.h b/IntelFspPkg/Include/Guid/GuidHobFsp.h new file mode 100644 index 0000000000..4b1c2b175e --- /dev/null +++ b/IntelFspPkg/Include/Guid/GuidHobFsp.h @@ -0,0 +1,22 @@ +/** @file + + Copyright (c) 2014, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __GUID_HOB_FSP_GUID__ +#define __GUID_HOB_FSP_GUID__ + +#include +#include +#include +#include + +#endif diff --git a/IntelFspPkg/Include/Library/CacheAsRamLib.h b/IntelFspPkg/Include/Library/CacheAsRamLib.h new file mode 100644 index 0000000000..6f3d068b67 --- /dev/null +++ b/IntelFspPkg/Include/Library/CacheAsRamLib.h @@ -0,0 +1,30 @@ +/** @file + + Copyright (c) 2014, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _CACHE_AS_RAM_LIB_H_ +#define _CACHE_AS_RAM_LIB_H_ + +/** + This function disable CAR. + + @param[in] DisableCar TRUE means use INVD, FALSE means use WBINVD + +**/ +VOID +EFIAPI +DisableCacheAsRam ( + IN BOOLEAN DisableCar + ); + +#endif + diff --git a/IntelFspPkg/Include/Library/CacheLib.h b/IntelFspPkg/Include/Library/CacheLib.h new file mode 100644 index 0000000000..909ae928f1 --- /dev/null +++ b/IntelFspPkg/Include/Library/CacheLib.h @@ -0,0 +1,62 @@ +/** @file + + Copyright (c) 2014, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _CACHE_LIB_H_ +#define _CACHE_LIB_H_ + +// +// EFI_MEMORY_CACHE_TYPE +// +typedef INT32 EFI_MEMORY_CACHE_TYPE; + +#define EFI_CACHE_UNCACHEABLE 0 +#define EFI_CACHE_WRITECOMBINING 1 +#define EFI_CACHE_WRITETHROUGH 4 +#define EFI_CACHE_WRITEPROTECTED 5 +#define EFI_CACHE_WRITEBACK 6 + +/** + Reset all the MTRRs to a known state. + + @retval EFI_SUCCESS All MTRRs have been reset successfully. + +**/ +EFI_STATUS +EFIAPI +ResetCacheAttributes ( + VOID + ); + +/** + Given the memory range and cache type, programs the MTRRs. + + @param[in] MemoryAddress Base Address of Memory to program MTRR. + @param[in] MemoryLength Length of Memory to program MTRR. + @param[in] MemoryCacheType Cache Type. + + @retval EFI_SUCCESS Mtrr are set successfully. + @retval EFI_LOAD_ERROR No empty MTRRs to use. + @retval EFI_INVALID_PARAMETER The input parameter is not valid. + @retval others An error occurs when setting MTTR. + +**/ +EFI_STATUS +EFIAPI +SetCacheAttributes ( + IN EFI_PHYSICAL_ADDRESS MemoryAddress, + IN UINT64 MemoryLength, + IN EFI_MEMORY_CACHE_TYPE MemoryCacheType + ); + +#endif + diff --git a/IntelFspPkg/Include/Library/DebugDeviceLib.h b/IntelFspPkg/Include/Library/DebugDeviceLib.h new file mode 100644 index 0000000000..5c35eda579 --- /dev/null +++ b/IntelFspPkg/Include/Library/DebugDeviceLib.h @@ -0,0 +1,29 @@ +/** @file + + Copyright (c) 2014, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __DEBUG_DEVICE_LIB_H__ +#define __DEBUG_DEVICE_LIB_H__ + +/** + Returns the debug print device enable state. + + @return Debug print device enable state. + +**/ +UINT8 +EFIAPI +GetDebugPrintDeviceEnable ( + VOID + ); + +#endif diff --git a/IntelFspPkg/Include/Library/FspCommonLib.h b/IntelFspPkg/Include/Library/FspCommonLib.h new file mode 100644 index 0000000000..50e9b260bf --- /dev/null +++ b/IntelFspPkg/Include/Library/FspCommonLib.h @@ -0,0 +1,173 @@ +/** @file + + Copyright (c) 2014, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _FSP_COMMON_LIB_H_ +#define _FSP_COMMON_LIB_H_ + +#include +#include + +/** + This function sets the FSP global data pointer. + + @param[in] FspData Fsp global data pointer. + +**/ +VOID +EFIAPI +SetFspGlobalDataPointer ( + IN FSP_GLOBAL_DATA *FspData + ); + +/** + This function gets the FSP global data pointer. + +**/ +FSP_GLOBAL_DATA * +EFIAPI +GetFspGlobalDataPointer ( + VOID + ); + +/** + This function gets back the FSP API paramter passed by the bootlaoder. + + @retval ApiParameter FSP API paramter passed by the bootlaoder. +**/ +UINT32 +EFIAPI +GetFspApiParameter ( + VOID + ); + +/** + This function sets the FSP API paramter in the stack. + + @param[in] Value New parameter value. + +**/ +VOID +EFIAPI +SetFspApiParameter ( + IN UINT32 Value + ); + +/** + This function sets the FSP continuation function parameters in the stack. + + @param[in] Value New parameter value to set. + @param[in] Index Parameter index. +**/ +VOID +EFIAPI +SetFspContinuationFuncParameter ( + IN UINT32 Value, + IN UINT32 Index + ); + +/** + This function changes the Bootloader return address in stack. + + @param[in] ReturnAddress Address to return. + +**/ +VOID +EFIAPI +SetFspApiReturnAddress ( + IN UINT32 ReturnAddress + ); + +/** + This function set the API status code returned to the bootloader. + + @param[in] ReturnStatus Status code to return. + +**/ +VOID +EFIAPI +SetFspApiReturnStatus ( + IN UINT32 ReturnStatus + ); + +/** + This function sets the context switching stack to a new stack frame. + + @param[in] NewStackTop New core stack to be set. + +**/ +VOID +EFIAPI +SetFspCoreStackPointer ( + IN VOID *NewStackTop + ); + +/** + This function sets the platform specific data pointer. + + @param[in] PlatformData Fsp platform specific data pointer. + +**/ +VOID +EFIAPI +SetFspPlatformDataPointer ( + IN VOID *PlatformData + ); + +/** + This function gets the platform specific data pointer. + + @param[in] PlatformData Fsp platform specific data pointer. + +**/ +VOID * +EFIAPI +GetFspPlatformDataPointer ( + VOID + ); + +/** + This function sets the UPD data pointer. + + @param[in] UpdDataRgnPtr UPD data pointer. +**/ +VOID +EFIAPI +SetFspUpdDataPointer ( + IN VOID *UpdDataRgnPtr + ); + +/** + This function gets the UPD data pointer. + + @return UpdDataRgnPtr UPD data pointer. +**/ +VOID * +EFIAPI +GetFspUpdDataPointer ( + VOID + ); + +/** + Set FSP measurement point timestamp. + + @param[in] Id Measurement point ID. + + @return performance timestamp. +**/ +UINT64 +EFIAPI +SetFspMeasurePoint ( + IN UINT8 Id + ); + +#endif diff --git a/IntelFspPkg/Include/Library/FspPlatformLib.h b/IntelFspPkg/Include/Library/FspPlatformLib.h new file mode 100644 index 0000000000..855017880b --- /dev/null +++ b/IntelFspPkg/Include/Library/FspPlatformLib.h @@ -0,0 +1,64 @@ +/** @file + + Copyright (c) 2014, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _FSP_PLATFORM_LIB_H_ +#define _FSP_PLATFORM_LIB_H_ + +/** + Get system memory from HOB. + + @param[in,out] LowMemoryLength less than 4G memory length + @param[in,out] HighMemoryLength greater than 4G memory length +**/ +VOID +EFIAPI +FspGetSystemMemorySize ( + IN OUT UINT64 *LowMemoryLength, + IN OUT UINT64 *HighMemoryLength + ); + +/** + Migrate bootloader data before destroying CAR. + +**/ +VOID +EFIAPI +FspMigrateTemporaryMemory ( + VOID + ); + +/** + This function transfer control to the ContinuationFunc passed in by the + bootloader. + +**/ +VOID +EFIAPI +FspInitDone ( + VOID + ); + +/** + This function handle NotifyPhase API call from the bootloader. + It gives control back to the bootloader after it is handled. If the + Notification code is a ReadyToBoot event, this function will return + and FSP continues the remaining execution until it reaches the DxeIpl. + +**/ +VOID +EFIAPI +FspWaitForNotify ( + VOID + ); + +#endif diff --git a/IntelFspPkg/Include/Library/FspReturnLib.h b/IntelFspPkg/Include/Library/FspReturnLib.h new file mode 100644 index 0000000000..40b69a8e53 --- /dev/null +++ b/IntelFspPkg/Include/Library/FspReturnLib.h @@ -0,0 +1,27 @@ +/** @file + + Copyright (c) 2014, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _FSP_RETURN_LIB_H_ +#define _FSP_RETURN_LIB_H_ + +/** + Return the control from FSP to the Caller. + +**/ +VOID +EFIAPI +AsmFspReturn ( + VOID + ); + +#endif diff --git a/IntelFspPkg/Include/Library/FspSwitchStackLib.h b/IntelFspPkg/Include/Library/FspSwitchStackLib.h new file mode 100644 index 0000000000..e90b13e8da --- /dev/null +++ b/IntelFspPkg/Include/Library/FspSwitchStackLib.h @@ -0,0 +1,45 @@ +/** @file + + Copyright (c) 2014, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _FSP_SWITCH_STACK_LIB_H_ +#define _FSP_SWITCH_STACK_LIB_H_ + +/** + + This funciton will switch the current stack to the previous saved stack. + Before calling the previous stack has to be set in FSP_GLOBAL_DATA.CoreStack. + EIP + FLAGS 16 bit FLAGS 16 bit + EDI + ESI + EBP + ESP + EBX + EDX + ECX + EAX + DWORD IDT base1 + StackPointer: DWORD IDT base2 + + @return ReturnKey After switching to the saved stack, + this value will be saved in eax before returning. + + +**/ +UINT32 +EFIAPI +Pei2LoaderSwitchStack ( + VOID + ); + +#endif diff --git a/IntelFspPkg/Include/Private/FspGlobalData.h b/IntelFspPkg/Include/Private/FspGlobalData.h new file mode 100644 index 0000000000..7a6ec6db58 --- /dev/null +++ b/IntelFspPkg/Include/Private/FspGlobalData.h @@ -0,0 +1,44 @@ +/** @file + + Copyright (c) 2014, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _FSP_GLOBAL_DATA_H_ +#define _FSP_GLOBAL_DATA_H_ + +#include + +#pragma pack(1) + +typedef struct { + VOID *DataPtr; + UINT32 CodeRegionBase; + UINT32 CodeRegionSize; + UINT32 MicorcodeRegionBase; + UINT32 MicorcodeRegionSize; +} FSP_PLAT_DATA; + +#define FSP_GLOBAL_DATA_SIGNATURE SIGNATURE_32 ('F', 'S', 'P', 'D') + +typedef struct { + UINT32 Signature; + UINT32 CoreStack; + FSP_PLAT_DATA PlatformData; + FSP_INFO_HEADER *FspInfoHeader; + VOID *UpdDataRgnPtr; + UINT32 PerfIdx; + UINT64 PerfData[32]; +// UINT64 PerfData[FixedPcdGet32(PcdFspMaxPerfEntry)]; +} FSP_GLOBAL_DATA; + +#pragma pack() + +#endif diff --git a/IntelFspPkg/Include/Private/FspMeasurePointId.h b/IntelFspPkg/Include/Private/FspMeasurePointId.h new file mode 100644 index 0000000000..765bd0b98b --- /dev/null +++ b/IntelFspPkg/Include/Private/FspMeasurePointId.h @@ -0,0 +1,48 @@ +/** @file + + Copyright (c) 2014, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _FSP_MEASURE_POINT_ID_H_ +#define _FSP_MEASURE_POINT_ID_H_ + +// +// 0xD0 - 0xEF are reserved for FSP common measure point +// +#define FSP_PERF_ID_MRCINIT_ENTRY 0xD0 +#define FSP_PERF_ID_MRCINIT_EXIT (FSP_PERF_ID_MRCINIT_ENTRY + 1) + +#define FSP_PERF_ID_SOCINIT_ENTRY 0xD8 +#define FSP_PERF_ID_SOCINIT_EXIT (FSP_PERF_ID_SOCINIT_ENTRY + 1) + +#define FSP_PERF_ID_PCHINIT_ENTRY 0xDA +#define FSP_PERF_ID_PCHINIT_EXIT (FSP_PERF_ID_PCHINIT_ENTRY + 1) + +#define FSP_PERF_ID_CPUINIT_ENTRY 0xE0 +#define FSP_PERF_ID_CPUINIT_EXIT (FSP_PERF_ID_CPUINIT_ENTRY + 1) + + +// +// 0xF0 - 0xFF are reserved for FSP API +// +#define FSP_PERF_ID_API_TMPRAMINIT_ENTRY 0xF0 +#define FSP_PERF_ID_API_TMPRAMINIT_EXIT (FSP_PERF_ID_API_TMPRAMINIT_ENTRY + 1) + +#define FSP_PERF_ID_API_FSPINIT_ENTRY 0xF2 +#define FSP_PERF_ID_API_FSPINIT_EXIT (FSP_PERF_ID_API_FSPINIT_ENTRY + 1) + +#define FSP_PERF_ID_API_NOTIFY_POSTPCI_ENTRY 0xF4 +#define FSP_PERF_ID_API_NOTIFY_POSTPCI_EXIT (FSP_PERF_ID_API_NOTIFY_POSTPCI_ENTRY + 1) + +#define FSP_PERF_ID_API_NOTIFY_RDYBOOT_ENTRY 0xF6 +#define FSP_PERF_ID_API_NOTIFY_RDYBOOT_EXIT (FSP_PERF_ID_API_NOTIFY_RDYBOOT_ENTRY + 1) + +#endif diff --git a/IntelFspPkg/Include/Private/FspPatchTable.h b/IntelFspPkg/Include/Private/FspPatchTable.h new file mode 100644 index 0000000000..ec93994fe7 --- /dev/null +++ b/IntelFspPkg/Include/Private/FspPatchTable.h @@ -0,0 +1,32 @@ +/** @file + + Copyright (c) 2014, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _FSP_PATCH_TABLE_H_ +#define _FSP_PATCH_TABLE_H_ + +#pragma pack(1) + +#define FSP_PATCH_TABLE_SIGNATURE SIGNATURE_32 ('F', 'S', 'P', 'P') + +typedef struct { + UINT32 Signature; + UINT16 HeaderLength; + UINT8 HeaderRevision; + UINT8 Reserved; + UINT32 PatchEntryNum; + UINT32 PatchData[FixedPcdGet32(PcdFspMaxPatchEntry)]; +} FSP_PATCH_TABLE; + +#pragma pack() + +#endif diff --git a/IntelFspPkg/Include/Private/GuidHobFspGfx.h b/IntelFspPkg/Include/Private/GuidHobFspGfx.h new file mode 100644 index 0000000000..4ac47ba939 --- /dev/null +++ b/IntelFspPkg/Include/Private/GuidHobFspGfx.h @@ -0,0 +1,19 @@ +/** @file + + Copyright (c) 2014, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __GUID_HOB_FSP_GFX_GUID__ +#define __GUID_HOB_FSP_GFX_GUID__ + +extern EFI_GUID gFspReservedMemoryResourceHobGfxGuid; + +#endif diff --git a/IntelFspPkg/Include/Private/GuidHobFspMisc.h b/IntelFspPkg/Include/Private/GuidHobFspMisc.h new file mode 100644 index 0000000000..97b75af93e --- /dev/null +++ b/IntelFspPkg/Include/Private/GuidHobFspMisc.h @@ -0,0 +1,19 @@ +/** @file + + Copyright (c) 2014, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __GUID_HOB_FSP_MISC_GUID__ +#define __GUID_HOB_FSP_MISC_GUID__ + +extern EFI_GUID gFspReservedMemoryResourceHobMiscGuid; + +#endif diff --git a/IntelFspPkg/Include/Private/GuidHobFspTseg.h b/IntelFspPkg/Include/Private/GuidHobFspTseg.h new file mode 100644 index 0000000000..a44a8f6e33 --- /dev/null +++ b/IntelFspPkg/Include/Private/GuidHobFspTseg.h @@ -0,0 +1,19 @@ +/** @file + + Copyright (c) 2014, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __GUID_HOB_FSP_TSEG_GUID__ +#define __GUID_HOB_FSP_TSEG_GUID__ + +extern EFI_GUID gFspReservedMemoryResourceHobTsegGuid; + +#endif diff --git a/IntelFspPkg/IntelFspPkg.dec b/IntelFspPkg/IntelFspPkg.dec index ef942a7ac4..d16eaad346 100644 --- a/IntelFspPkg/IntelFspPkg.dec +++ b/IntelFspPkg/IntelFspPkg.dec @@ -21,11 +21,33 @@ [Includes] Include + Include/Private [Guids] + # + # GUID defined in package + # + gIntelFspPkgTokenSpaceGuid = { 0x834c0c5f, 0xadb3, 0x4372, { 0xae, 0xeb, 0x03, 0xe4, 0xe9, 0xe6, 0xc5, 0x91 } } + # Guid define in FSP EAS gFspHeaderFileGuid = { 0x912740BE, 0x2284, 0x4734, { 0xB9, 0x71, 0x84, 0xB0, 0x27, 0x35, 0x3F, 0x0C } } gFspBootLoaderTemporaryMemoryGuid = { 0xbbcff46c, 0xc8d3, 0x4113, { 0x89, 0x85, 0xb9, 0xd4, 0xf3, 0xb3, 0xf6, 0x4e } } gFspReservedMemoryResourceHobGuid = { 0x69a79759, 0x1373, 0x4367, { 0xa6, 0xc4, 0xc7, 0xf5, 0x9e, 0xfd, 0x98, 0x6e } } gFspNonVolatileStorageHobGuid = { 0x721acf02, 0x4d77, 0x4c2a, { 0xb3, 0xdc, 0x27, 0x0b, 0x7b, 0xa9, 0xe4, 0xb0 } } + # Guid defined by platform + gFspReservedMemoryResourceHobTsegGuid = { 0xd038747c, 0xd00c, 0x4980, { 0xb3, 0x19, 0x49, 0x01, 0x99, 0xa4, 0x7d, 0x55 } } + gFspReservedMemoryResourceHobGfxGuid = { 0x9c7c3aa7, 0x5332, 0x4917, { 0x82, 0xb9, 0x56, 0xa5, 0xf3, 0xe6, 0x2a, 0x07 } } + gFspReservedMemoryResourceHobMiscGuid = { 0x00d6b14b, 0x7dd0, 0x4062, { 0x88, 0x21, 0xe5, 0xf9, 0x6a, 0x2a, 0x1b, 0x00 } } + +[PcdsFixedAtBuild] + gIntelFspPkgTokenSpaceGuid.PcdGlobalDataPointerAddress|0xFED00108|UINT32|0x00000001 + gIntelFspPkgTokenSpaceGuid.PcdTemporaryRamBase |0xFEF00000|UINT32|0x10001001 + gIntelFspPkgTokenSpaceGuid.PcdTemporaryRamSize | 0x2000|UINT32|0x10001002 + gIntelFspPkgTokenSpaceGuid.PcdFspTemporaryRamSize | 0x1000|UINT32|0x10001003 + gIntelFspPkgTokenSpaceGuid.PcdFspMaxPerfEntry | 32|UINT32|0x00002001 + gIntelFspPkgTokenSpaceGuid.PcdFspMaxPatchEntry | 5|UINT32|0x00002002 + +[PcdsFixedAtBuild,PcdsDynamic,PcdsDynamicEx] + gIntelFspPkgTokenSpaceGuid.PcdFspReservedMemoryLength |0x00100000|UINT32|0x46530000 + gIntelFspPkgTokenSpaceGuid.PcdBootLoaderEntry |0xFFFFFFE4|UINT32|0x46530100 diff --git a/IntelFspPkg/IntelFspPkg.dsc b/IntelFspPkg/IntelFspPkg.dsc new file mode 100644 index 0000000000..1f497ffa28 --- /dev/null +++ b/IntelFspPkg/IntelFspPkg.dsc @@ -0,0 +1,75 @@ +## @file +# +# Copyright (c) 2014, Intel Corporation. All rights reserved.
+# This program and the accompanying materials are licensed and made available under +# the terms and conditions of the BSD License that accompanies this distribution. +# The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + PLATFORM_NAME = IntelFspPkg + PLATFORM_GUID = 29C6791F-9EBC-4470-A126-2BB47431AE5E + PLATFORM_VERSION = 0.1 + DSC_SPECIFICATION = 0x00010005 + OUTPUT_DIRECTORY = Build/IntelFspPkg + SUPPORTED_ARCHITECTURES = IA32 + BUILD_TARGETS = DEBUG|RELEASE + SKUID_IDENTIFIER = DEFAULT + +[LibraryClasses] + BaseLib|MdePkg/Library/BaseLib/BaseLib.inf + BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf + PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf + PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf + DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf + PciCf8Lib|MdePkg/Library/BasePciCf8Lib/BasePciCf8Lib.inf + IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf + UefiDecompressLib|MdePkg/Library/BaseUefiDecompressLib/BaseUefiDecompressLib.inf + + # Dummy - test build only + SerialPortLib|MdePkg/Library/BaseSerialPortLibNull/BaseSerialPortLibNull.inf + ReportStatusCodeLib|MdePkg/Library/BaseReportStatusCodeLibNull/BaseReportStatusCodeLibNull.inf + DebugDeviceLib|IntelFspPkg/Library/BaseDebugDeviceLibNull/BaseDebugDeviceLibNull.inf + + # FSP override + DebugLib|IntelFspPkg/Library/BaseFspDebugLibSerialPort/BaseFspDebugLibSerialPort.inf + + # FSP specific lib + CacheAsRamLib|IntelFspPkg/Library/BaseCacheAsRamLibNull/BaseCacheAsRamLibNull.inf + CacheLib|IntelFspPkg/Library/BaseCacheLib/BaseCacheLib.inf + FspCommonLib|IntelFspPkg/Library/BaseFspCommonLib/BaseFspCommonLib.inf + FspPlatformLib|IntelFspPkg/Library/BaseFspPlatformLib/BaseFspPlatformLib.inf + FspSwitchStackLib|IntelFspPkg/Library/BaseFspSwitchStackLib/BaseFspSwitchStackLib.inf + +[LibraryClasses.common.PEIM] + PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf + PeiServicesTablePointerLib|MdePkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.inf + PeiServicesLib|MdePkg/Library/PeiServicesLib/PeiServicesLib.inf + MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf + ExtractGuidedSectionLib|MdePkg/Library/PeiExtractGuidedSectionLib/PeiExtractGuidedSectionLib.inf + + HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf + +[Components] + IntelFspPkg/Library/BaseCacheAsRamLibNull/BaseCacheAsRamLibNull.inf + IntelFspPkg/Library/BaseCacheLib/BaseCacheLib.inf + IntelFspPkg/Library/BaseFspCommonLib/BaseFspCommonLib.inf + IntelFspPkg/Library/BaseFspDebugLibSerialPort/BaseFspDebugLibSerialPort.inf + IntelFspPkg/Library/BaseFspPlatformLib/BaseFspPlatformLib.inf + IntelFspPkg/Library/BaseFspSwitchStackLib/BaseFspSwitchStackLib.inf + + IntelFspPkg/FspSecCore/FspSecCore.inf { + + NULL|IntelFspPkg/Library/SecPlatformSecLibNull/SecPlatformSecLibNull.inf + } + IntelFspPkg/FspDxeIpl/FspDxeIpl.inf + +[PcdsFixedAtBuild.common] + gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x1f + gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|0x80080046 + gEfiMdePkgTokenSpaceGuid.PcdReportStatusCodePropertyMask|0x07 diff --git a/IntelFspPkg/Library/BaseCacheAsRamLibNull/BaseCacheAsRamLibNull.inf b/IntelFspPkg/Library/BaseCacheAsRamLibNull/BaseCacheAsRamLibNull.inf new file mode 100644 index 0000000000..7c8492cc4d --- /dev/null +++ b/IntelFspPkg/Library/BaseCacheAsRamLibNull/BaseCacheAsRamLibNull.inf @@ -0,0 +1,30 @@ +## @file +# +# Copyright (c) 2014, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[defines] + INF_VERSION = 0x00010005 + BASE_NAME = BaseCacheAsRamLibNull + FILE_GUID = FBB4A01B-947E-4d82-B27D-1E207C070053 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = CacheAsRamLib + +[sources.common] + DisableCacheAsRamNull.c + +[Packages] + MdePkg/MdePkg.dec + IntelFspPkg/IntelFspPkg.dec + +[LibraryClasses] + diff --git a/IntelFspPkg/Library/BaseCacheAsRamLibNull/DisableCacheAsRamNull.c b/IntelFspPkg/Library/BaseCacheAsRamLibNull/DisableCacheAsRamNull.c new file mode 100644 index 0000000000..9b45163c34 --- /dev/null +++ b/IntelFspPkg/Library/BaseCacheAsRamLibNull/DisableCacheAsRamNull.c @@ -0,0 +1,41 @@ +/** @file + + Copyright (c) 2014, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include + +/** + This function disable CAR. + + @param[in] DisableCar TRUE means use INVD, FALSE means use WBINVD + +**/ +VOID +EFIAPI +DisableCacheAsRam ( + IN BOOLEAN DisableCar + ) +{ + // + // Disable CAR + // + + if (DisableCar) { + AsmInvd (); + } else { + AsmWbinvd(); + } + + return ; +} diff --git a/IntelFspPkg/Library/BaseCacheLib/BaseCacheLib.inf b/IntelFspPkg/Library/BaseCacheLib/BaseCacheLib.inf new file mode 100644 index 0000000000..d76a32bc4f --- /dev/null +++ b/IntelFspPkg/Library/BaseCacheLib/BaseCacheLib.inf @@ -0,0 +1,32 @@ +## @file +# +# Copyright (c) 2014, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[defines] + INF_VERSION = 0x00010005 + BASE_NAME = BaseCacheLib + FILE_GUID = 01359d99-9446-456d-ada4-50a711c03adb + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = CacheLib + +[sources.IA32] + CacheLib.c + CacheLibInternal.h + +[Packages] + MdePkg/MdePkg.dec + IntelFspPkg/IntelFspPkg.dec + +[LibraryClasses] + BaseMemoryLib + diff --git a/IntelFspPkg/Library/BaseCacheLib/CacheLib.c b/IntelFspPkg/Library/BaseCacheLib/CacheLib.c new file mode 100644 index 0000000000..aaaeb8b97b --- /dev/null +++ b/IntelFspPkg/Library/BaseCacheLib/CacheLib.c @@ -0,0 +1,749 @@ +/** @file + + Copyright (c) 2014, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include +#include "CacheLibInternal.h" + +/** + Calculate the maximum value which is a power of 2, but less the Input. + + @param[in] Input The number to pass in. + @return The maximum value which is align to power of 2 and less the Input +**/ +UINT32 +SetPower2 ( + IN UINT32 Input + ); + +/** + Search the memory cache type for specific memory from MTRR. + + @param[in] MemoryAddress the address of target memory + @param[in] MemoryLength the length of target memory + @param[in] ValidMtrrAddressMask the MTRR address mask + @param[out] UsedMsrNum the used MSR number + @param[out] UsedMemoryCacheType the cache type for the target memory + + @retval EFI_SUCCESS The memory is found in MTRR and cache type is returned + @retval EFI_NOT_FOUND The memory is not found in MTRR + +**/ +EFI_STATUS +SearchForExactMtrr ( + IN EFI_PHYSICAL_ADDRESS MemoryAddress, + IN UINT64 MemoryLength, + IN UINT64 ValidMtrrAddressMask, + OUT UINT32 *UsedMsrNum, + OUT EFI_MEMORY_CACHE_TYPE *MemoryCacheType + ); + +/** + Check if CacheType match current default setting. + + @param[in] MemoryCacheType input cache type to be checked. + + @retval TRUE MemoryCacheType is default MTRR setting. + @retval TRUE MemoryCacheType is NOT default MTRR setting. +**/ +BOOLEAN +IsDefaultType ( + IN EFI_MEMORY_CACHE_TYPE MemoryCacheType + ); + +/** + Return MTRR alignment requirement for base address and size. + + @param[in] BaseAddress Base address. + @param[in] Size Size. + + @retval Zero Alligned. + @retval Non-Zero Not alligned. + +**/ +UINT32 +CheckMtrrAlignment ( + IN UINT64 BaseAddress, + IN UINT64 Size + ); + +typedef struct { + UINT32 Msr; + UINT32 BaseAddress; + UINT32 Length; +} EFI_FIXED_MTRR; + +EFI_FIXED_MTRR mFixedMtrrTable[] = { + { EFI_MSR_IA32_MTRR_FIX64K_00000, 0, 0x10000}, + { EFI_MSR_IA32_MTRR_FIX16K_80000, 0x80000, 0x4000}, + { EFI_MSR_IA32_MTRR_FIX16K_A0000, 0xA0000, 0x4000}, + { EFI_MSR_IA32_MTRR_FIX4K_C0000, 0xC0000, 0x1000}, + { EFI_MSR_IA32_MTRR_FIX4K_C8000, 0xC8000, 0x1000}, + { EFI_MSR_IA32_MTRR_FIX4K_D0000, 0xD0000, 0x1000}, + { EFI_MSR_IA32_MTRR_FIX4K_D8000, 0xD8000, 0x1000}, + { EFI_MSR_IA32_MTRR_FIX4K_E0000, 0xE0000, 0x1000}, + { EFI_MSR_IA32_MTRR_FIX4K_E8000, 0xE8000, 0x1000}, + { EFI_MSR_IA32_MTRR_FIX4K_F0000, 0xF0000, 0x1000}, + { EFI_MSR_IA32_MTRR_FIX4K_F8000, 0xF8000, 0x1000} +}; + +/** + Given the input, check if the number of MTRR is lesser. + if positive or subtractive. + + @param[in] Input Length of Memory to program MTRR. + + @retval Zero do positive. + @retval Non-Zero do subtractive. + +**/ +INT8 +CheckDirection ( + IN UINT64 Input + ) +{ + return 0; +} + +/** + Disable cache and its mtrr. + + @param[out] OldMtrr To return the Old MTRR value + +**/ +VOID +EfiDisableCacheMtrr ( + OUT UINT64 *OldMtrr + ) +{ + UINT64 TempQword; + + // + // Disable Cache MTRR + // + *OldMtrr = AsmReadMsr64(EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE); + TempQword = (*OldMtrr) & ~B_EFI_MSR_GLOBAL_MTRR_ENABLE & ~B_EFI_MSR_FIXED_MTRR_ENABLE; + AsmWriteMsr64(EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE, TempQword); + AsmDisableCache (); +} + +/** + Recover cache MTRR. + + @param[in] EnableMtrr Whether to enable the MTRR + @param[in] OldMtrr The saved old MTRR value to restore when not to enable the MTRR + +**/ +VOID +EfiRecoverCacheMtrr ( + IN BOOLEAN EnableMtrr, + IN UINT64 OldMtrr + ) +{ + UINT64 TempQword; + + // + // Enable Cache MTRR + // + if (EnableMtrr) { + TempQword = AsmReadMsr64(EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE); + TempQword |= (B_EFI_MSR_GLOBAL_MTRR_ENABLE | B_EFI_MSR_FIXED_MTRR_ENABLE); + } else { + TempQword = OldMtrr; + } + + AsmWriteMsr64 (EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE, TempQword); + + AsmEnableCache (); +} + +/** + Programming MTRR according to Memory address, length, and type. + + @param[in] MtrrNumber the variable MTRR index number + @param[in] MemoryAddress the address of target memory + @param[in] MemoryLength the length of target memory + @param[in] MemoryCacheType the cache type of target memory + @param[in] ValidMtrrAddressMask the MTRR address mask + +**/ +VOID +EfiProgramMtrr ( + IN UINTN MtrrNumber, + IN EFI_PHYSICAL_ADDRESS MemoryAddress, + IN UINT64 MemoryLength, + IN EFI_MEMORY_CACHE_TYPE MemoryCacheType, + IN UINT64 ValidMtrrAddressMask + ) +{ + UINT64 TempQword; + UINT64 OldMtrr; + + if (MemoryLength == 0) { + return; + } + + EfiDisableCacheMtrr (&OldMtrr); + + // + // MTRR Physical Base + // + TempQword = (MemoryAddress & ValidMtrrAddressMask) | MemoryCacheType; + AsmWriteMsr64 (MtrrNumber, TempQword); + + // + // MTRR Physical Mask + // + TempQword = ~(MemoryLength - 1); + AsmWriteMsr64 (MtrrNumber + 1, (TempQword & ValidMtrrAddressMask) | B_EFI_MSR_CACHE_MTRR_VALID); + + EfiRecoverCacheMtrr (TRUE, OldMtrr); +} + +/** + Calculate the maximum value which is a power of 2, but less the MemoryLength. + + @param[in] MemoryAddress Memory address. + @param[in] MemoryLength The number to pass in. + + @return The maximum value which is align to power of 2 and less the MemoryLength + +**/ +UINT64 +Power2MaxMemory ( + IN UINT64 MemoryAddress, + IN UINT64 MemoryLength + ) +{ + UINT64 Result; + + if (MemoryLength == 0) { + return EFI_INVALID_PARAMETER; + } + + // + // Compute inital power of 2 size to return + // + if (RShiftU64(MemoryLength, 32)) { + Result = LShiftU64((UINT64)SetPower2((UINT32) RShiftU64(MemoryLength, 32)), 32); + } else { + Result = (UINT64)SetPower2((UINT32)MemoryLength); + } + + // + // Special case base of 0 as all ranges are valid + // + if (MemoryAddress == 0) { + return Result; + } + + // + // Loop till a value that can be mapped to this base address is found + // + while (CheckMtrrAlignment (MemoryAddress, Result) != 0) { + // + // Need to try the next smaller power of 2 + // + Result = RShiftU64 (Result, 1); + } + + return Result; +} + +/** + Return MTRR alignment requirement for base address and size. + + @param[in] BaseAddress Base address. + @param[in] Size Size. + + @retval Zero Alligned. + @retval Non-Zero Not alligned. + +**/ +UINT32 +CheckMtrrAlignment ( + IN UINT64 BaseAddress, + IN UINT64 Size + ) +{ + UINT32 ShiftedBase; + UINT32 ShiftedSize; + + // + // Shift base and size right 12 bits to allow for larger memory sizes. The + // MTRRs do not use the first 12 bits so this is safe for now. Only supports + // up to 52 bits of physical address space. + // + ShiftedBase = (UINT32) RShiftU64 (BaseAddress, 12); + ShiftedSize = (UINT32) RShiftU64 (Size, 12); + + // + // Return the results to the caller of the MOD + // + return ShiftedBase % ShiftedSize; +} + +/** + Calculate the maximum value which is a power of 2, but less the Input. + + @param[in] Input The number to pass in. + + @return The maximum value which is align to power of 2 and less the Input. +**/ +UINT32 +SetPower2 ( + IN UINT32 Input + ) +{ + UINT32 Result; + + Result = 0; +#if defined(__GCC__) + asm("bsr %1, \ + %%eax; \ + bts %%eax, \ + %0;" :"=r"(Result) : + "r"(Input) + ); +#elif defined(_MSC_VER) + _asm { + bsr eax, Input + bts Result, eax + } +#endif + return Result; +} + +/** + Programs fixed MTRRs registers. + + @param[in] MemoryCacheType The memory type to set. + @param[in] Base The base address of memory range. + @param[in] Length The length of memory range. + + @retval RETURN_SUCCESS The cache type was updated successfully + @retval RETURN_UNSUPPORTED The requested range or cache type was invalid + for the fixed MTRRs. + +**/ +EFI_STATUS +ProgramFixedMtrr ( + IN EFI_MEMORY_CACHE_TYPE MemoryCacheType, + IN UINT64 *Base, + IN UINT64 *Len + ) +{ + UINT32 MsrNum; + UINT32 ByteShift; + UINT64 TempQword; + UINT64 OrMask; + UINT64 ClearMask; + + TempQword = 0; + OrMask = 0; + ClearMask = 0; + + for (MsrNum = 0; MsrNum < V_EFI_FIXED_MTRR_NUMBER; MsrNum++) { + if ((*Base >= mFixedMtrrTable[MsrNum].BaseAddress) && + (*Base < (mFixedMtrrTable[MsrNum].BaseAddress + 8 * mFixedMtrrTable[MsrNum].Length))) { + break; + } + } + if (MsrNum == V_EFI_FIXED_MTRR_NUMBER ) { + return EFI_DEVICE_ERROR; + } + // + // We found the fixed MTRR to be programmed + // + for (ByteShift=0; ByteShift < 8; ByteShift++) { + if ( *Base == (mFixedMtrrTable[MsrNum].BaseAddress + ByteShift * mFixedMtrrTable[MsrNum].Length)) { + break; + } + } + if (ByteShift == 8 ) { + return EFI_DEVICE_ERROR; + } + for (; ((ByteShift<8) && (*Len >= mFixedMtrrTable[MsrNum].Length));ByteShift++) { + OrMask |= LShiftU64((UINT64) MemoryCacheType, (UINT32) (ByteShift* 8)); + ClearMask |= LShiftU64((UINT64) 0xFF, (UINT32) (ByteShift * 8)); + *Len -= mFixedMtrrTable[MsrNum].Length; + *Base += mFixedMtrrTable[MsrNum].Length; + } + TempQword = AsmReadMsr64 (mFixedMtrrTable[MsrNum].Msr) & (~ClearMask | OrMask); + AsmWriteMsr64 (mFixedMtrrTable[MsrNum].Msr, TempQword); + + return EFI_SUCCESS; +} + +/** + Check if there is a valid variable MTRR that overlaps the given range. + + @param[in] Start Base Address of the range to check. + @param[in] End End address of the range to check. + + @retval TRUE Mtrr overlap. + @retval FALSE Mtrr not overlap. +**/ +BOOLEAN +CheckMtrrOverlap ( + IN EFI_PHYSICAL_ADDRESS Start, + IN EFI_PHYSICAL_ADDRESS End + ) +{ + return FALSE; +} + +/** + Given the memory range and cache type, programs the MTRRs. + + @param[in] MemoryAddress Base Address of Memory to program MTRR. + @param[in] MemoryLength Length of Memory to program MTRR. + @param[in] MemoryCacheType Cache Type. + + @retval EFI_SUCCESS Mtrr are set successfully. + @retval EFI_LOAD_ERROR No empty MTRRs to use. + @retval EFI_INVALID_PARAMETER The input parameter is not valid. + @retval others An error occurs when setting MTTR. + +**/ +EFI_STATUS +EFIAPI +SetCacheAttributes ( + IN EFI_PHYSICAL_ADDRESS MemoryAddress, + IN UINT64 MemoryLength, + IN EFI_MEMORY_CACHE_TYPE MemoryCacheType + ) +{ + EFI_STATUS Status; + UINT32 MsrNum, MsrNumEnd; + UINT64 TempQword; + UINT32 LastVariableMtrrForBios; + UINT64 OldMtrr; + UINT32 UsedMsrNum; + EFI_MEMORY_CACHE_TYPE UsedMemoryCacheType; + UINT64 ValidMtrrAddressMask; + UINT32 Cpuid_RegEax; + + AsmCpuid (CPUID_EXTENDED_FUNCTION, &Cpuid_RegEax, NULL, NULL, NULL); + if (Cpuid_RegEax >= CPUID_VIR_PHY_ADDRESS_SIZE) { + AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE, &Cpuid_RegEax, NULL, NULL, NULL); + ValidMtrrAddressMask = (LShiftU64((UINT64) 1, (Cpuid_RegEax & 0xFF)) - 1) & (~(UINT64)0x0FFF); + } else { + ValidMtrrAddressMask = (LShiftU64((UINT64) 1, 36) - 1) & (~(UINT64)0x0FFF); + } + + // + // Check for invalid parameter + // + if ((MemoryAddress & ~ValidMtrrAddressMask) != 0 || (MemoryLength & ~ValidMtrrAddressMask) != 0) { + return EFI_INVALID_PARAMETER; + } + + if (MemoryLength == 0) { + return EFI_INVALID_PARAMETER; + } + + switch (MemoryCacheType) { + case EFI_CACHE_UNCACHEABLE: + case EFI_CACHE_WRITECOMBINING: + case EFI_CACHE_WRITETHROUGH: + case EFI_CACHE_WRITEPROTECTED: + case EFI_CACHE_WRITEBACK: + break; + + default: + return EFI_INVALID_PARAMETER; + } + + // + // Check if Fixed MTRR + // + if ((MemoryAddress + MemoryLength) <= (1 << 20)) { + Status = EFI_SUCCESS; + EfiDisableCacheMtrr (&OldMtrr); + while ((MemoryLength > 0) && (Status == EFI_SUCCESS)) { + Status = ProgramFixedMtrr (MemoryCacheType, &MemoryAddress, &MemoryLength); + } + EfiRecoverCacheMtrr (TRUE, OldMtrr); + return Status; + } + + // + // Search if the range attribute has been set before + // + Status = SearchForExactMtrr( + MemoryAddress, + MemoryLength, + ValidMtrrAddressMask, + &UsedMsrNum, + &UsedMemoryCacheType + ); + + if (!EFI_ERROR(Status)) { + // + // Compare if it has the same type as current setting + // + if (UsedMemoryCacheType == MemoryCacheType) { + return EFI_SUCCESS; + } else { + // + // Different type + // + + // + // Check if the set type is the same as Default Type + // + if (IsDefaultType(MemoryCacheType)) { + // + // Clear the MTRR + // + AsmWriteMsr64(UsedMsrNum, 0); + AsmWriteMsr64(UsedMsrNum + 1, 0); + + return EFI_SUCCESS; + } else { + // + // Modify the MTRR type + // + EfiProgramMtrr(UsedMsrNum, + MemoryAddress, + MemoryLength, + MemoryCacheType, + ValidMtrrAddressMask + ); + return EFI_SUCCESS; + } + } + } + +#if 0 + // + // @bug - Need to create memory map so that when checking for overlap we + // can determine if an overlap exists based on all caching requests. + // + // Don't waste a variable MTRR if the caching attrib is same as default in MTRR_DEF_TYPE + // + if (MemoryCacheType == (AsmReadMsr64(EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE) & B_EFI_MSR_CACHE_MEMORY_TYPE)) { + if (!CheckMtrrOverlap (MemoryAddress, MemoryAddress+MemoryLength-1)) { + return EFI_SUCCESS; + } + } +#endif + + // + // Find first unused MTRR + // + MsrNumEnd = EFI_MSR_CACHE_VARIABLE_MTRR_BASE + (2 * (UINT32)(AsmReadMsr64(EFI_MSR_IA32_MTRR_CAP) & B_EFI_MSR_IA32_MTRR_CAP_VARIABLE_SUPPORT)); + for (MsrNum = EFI_MSR_CACHE_VARIABLE_MTRR_BASE; MsrNum < MsrNumEnd; MsrNum +=2) { + if ((AsmReadMsr64(MsrNum+1) & B_EFI_MSR_CACHE_MTRR_VALID) == 0 ) { + break; + } + } + + // + // Reserve 1 MTRR pair for OS. + // + LastVariableMtrrForBios = MsrNumEnd - 1 - (EFI_CACHE_NUM_VAR_MTRR_PAIRS_FOR_OS * 2); + if (MsrNum > LastVariableMtrrForBios) { + return EFI_LOAD_ERROR; + } + + // + // Special case for 1 MB base address + // + if (MemoryAddress == BASE_1MB) { + MemoryAddress = 0; + } + + // + // Program MTRRs + // + TempQword = MemoryLength; + + if (TempQword == Power2MaxMemory(MemoryAddress, TempQword)) { + EfiProgramMtrr(MsrNum, + MemoryAddress, + MemoryLength, + MemoryCacheType, + ValidMtrrAddressMask + ); + + } else { + // + // Fill in MTRRs with values. Direction can not be checked for this method + // as we are using WB as the default cache type and only setting areas to UC. + // + do { + // + // Do boundary check so we don't go past last MTRR register + // for BIOS use. Leave one MTRR pair for OS use. + // + if (MsrNum > LastVariableMtrrForBios) { + return EFI_LOAD_ERROR; + } + + // + // Set next power of 2 region + // + MemoryLength = Power2MaxMemory(MemoryAddress, TempQword); + EfiProgramMtrr(MsrNum, + MemoryAddress, + MemoryLength, + MemoryCacheType, + ValidMtrrAddressMask + ); + MemoryAddress += MemoryLength; + TempQword -= MemoryLength; + MsrNum += 2; + } while (TempQword != 0); + } + + return EFI_SUCCESS; +} + +/** + Reset all the MTRRs to a known state. + + @retval EFI_SUCCESS All MTRRs have been reset successfully. + +**/ +EFI_STATUS +EFIAPI +ResetCacheAttributes ( + VOID + ) +{ + UINT32 MsrNum, MsrNumEnd; + UINT16 Index; + UINT64 OldMtrr; + UINT64 CacheType; + BOOLEAN DisableCar; + Index = 0; + DisableCar = TRUE; + + // + // Determine default cache type + // + CacheType = EFI_CACHE_UNCACHEABLE; + + // + // Set default cache type + // + AsmWriteMsr64(EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE, CacheType); + + // + // Disable CAR + // + DisableCacheAsRam (DisableCar); + + EfiDisableCacheMtrr (&OldMtrr); + + // + // Reset Fixed MTRRs + // + for (Index = 0; Index < V_EFI_FIXED_MTRR_NUMBER; Index++) { + AsmWriteMsr64 (mFixedMtrrTable[Index].Msr, 0); + } + + // + // Reset Variable MTRRs + // + MsrNumEnd = EFI_MSR_CACHE_VARIABLE_MTRR_BASE + (2 * (UINT32)(AsmReadMsr64(EFI_MSR_IA32_MTRR_CAP) & B_EFI_MSR_IA32_MTRR_CAP_VARIABLE_SUPPORT)); + for (MsrNum = EFI_MSR_CACHE_VARIABLE_MTRR_BASE; MsrNum < MsrNumEnd; MsrNum++) { + AsmWriteMsr64 (MsrNum, 0); + } + + // + // Enable Fixed and Variable MTRRs + // + EfiRecoverCacheMtrr (TRUE, OldMtrr); + + return EFI_SUCCESS; +} + +/** + Search the memory cache type for specific memory from MTRR. + + @param[in] MemoryAddress the address of target memory + @param[in] MemoryLength the length of target memory + @param[in] ValidMtrrAddressMask the MTRR address mask + @param[out] UsedMsrNum the used MSR number + @param[out] UsedMemoryCacheType the cache type for the target memory + + @retval EFI_SUCCESS The memory is found in MTRR and cache type is returned + @retval EFI_NOT_FOUND The memory is not found in MTRR + +**/ +EFI_STATUS +SearchForExactMtrr ( + IN EFI_PHYSICAL_ADDRESS MemoryAddress, + IN UINT64 MemoryLength, + IN UINT64 ValidMtrrAddressMask, + OUT UINT32 *UsedMsrNum, + OUT EFI_MEMORY_CACHE_TYPE *UsedMemoryCacheType + ) +{ + UINT32 MsrNum, MsrNumEnd; + UINT64 TempQword; + + if (MemoryLength == 0) { + return EFI_INVALID_PARAMETER; + } + + MsrNumEnd = EFI_MSR_CACHE_VARIABLE_MTRR_BASE + (2 * (UINT32)(AsmReadMsr64(EFI_MSR_IA32_MTRR_CAP) & B_EFI_MSR_IA32_MTRR_CAP_VARIABLE_SUPPORT)); + for (MsrNum = EFI_MSR_CACHE_VARIABLE_MTRR_BASE; MsrNum < MsrNumEnd; MsrNum +=2) { + TempQword = AsmReadMsr64(MsrNum+1); + if ((TempQword & B_EFI_MSR_CACHE_MTRR_VALID) == 0) { + continue; + } + + if ((TempQword & ValidMtrrAddressMask) != ((~(MemoryLength - 1)) & ValidMtrrAddressMask)) { + continue; + } + + TempQword = AsmReadMsr64 (MsrNum); + if ((TempQword & ValidMtrrAddressMask) != (MemoryAddress & ValidMtrrAddressMask)) { + continue; + } + + *UsedMemoryCacheType = (EFI_MEMORY_CACHE_TYPE)(TempQword & B_EFI_MSR_CACHE_MEMORY_TYPE); + *UsedMsrNum = MsrNum; + + return EFI_SUCCESS; + } + + return EFI_NOT_FOUND; +} + +/** + Check if CacheType match current default setting. + + @param[in] MemoryCacheType input cache type to be checked. + + @retval TRUE MemoryCacheType is default MTRR setting. + @retval TRUE MemoryCacheType is NOT default MTRR setting. +**/ +BOOLEAN +IsDefaultType ( + IN EFI_MEMORY_CACHE_TYPE MemoryCacheType + ) +{ + if ((AsmReadMsr64(EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE) & B_EFI_MSR_CACHE_MEMORY_TYPE) != MemoryCacheType) { + return FALSE; + } + + return TRUE; +} + diff --git a/IntelFspPkg/Library/BaseCacheLib/CacheLibInternal.h b/IntelFspPkg/Library/BaseCacheLib/CacheLibInternal.h new file mode 100644 index 0000000000..fbbf551dde --- /dev/null +++ b/IntelFspPkg/Library/BaseCacheLib/CacheLibInternal.h @@ -0,0 +1,59 @@ +/** @file + + Copyright (c) 2014, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _CACHE_LIB_INTERNAL_H_ +#define _CACHE_LIB_INTERNAL_H_ + +#define EFI_MSR_CACHE_VARIABLE_MTRR_BASE 0x00000200 +#define EFI_MSR_CACHE_VARIABLE_MTRR_END 0x0000020F +#define V_EFI_FIXED_MTRR_NUMBER 11 + +#define EFI_MSR_IA32_MTRR_FIX64K_00000 0x00000250 +#define EFI_MSR_IA32_MTRR_FIX16K_80000 0x00000258 +#define EFI_MSR_IA32_MTRR_FIX16K_A0000 0x00000259 +#define EFI_MSR_IA32_MTRR_FIX4K_C0000 0x00000268 +#define EFI_MSR_IA32_MTRR_FIX4K_C8000 0x00000269 +#define EFI_MSR_IA32_MTRR_FIX4K_D0000 0x0000026A +#define EFI_MSR_IA32_MTRR_FIX4K_D8000 0x0000026B +#define EFI_MSR_IA32_MTRR_FIX4K_E0000 0x0000026C +#define EFI_MSR_IA32_MTRR_FIX4K_E8000 0x0000026D +#define EFI_MSR_IA32_MTRR_FIX4K_F0000 0x0000026E +#define EFI_MSR_IA32_MTRR_FIX4K_F8000 0x0000026F +#define EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE 0x000002FF +#define B_EFI_MSR_CACHE_MTRR_VALID BIT11 +#define B_EFI_MSR_GLOBAL_MTRR_ENABLE BIT11 +#define B_EFI_MSR_FIXED_MTRR_ENABLE BIT10 +#define B_EFI_MSR_CACHE_MEMORY_TYPE (BIT2 | BIT1 | BIT0) + +#define EFI_MSR_VALID_MASK 0xFFFFFFFFF +#define EFI_CACHE_VALID_ADDRESS 0xFFFFFF000 +#define EFI_SMRR_CACHE_VALID_ADDRESS 0xFFFFF000 +#define EFI_CACHE_VALID_EXTENDED_ADDRESS 0xFFFFFFFFFF000 + +// Leave one MTRR pairs for OS use +#define EFI_CACHE_NUM_VAR_MTRR_PAIRS_FOR_OS 1 +#define EFI_CACHE_LAST_VARIABLE_MTRR_FOR_BIOS (EFI_MSR_CACHE_VARIABLE_MTRR_END) - \ + (EFI_CACHE_NUM_VAR_MTRR_PAIRS_FOR_OS * 2) + +#define EFI_MSR_IA32_MTRR_CAP 0x000000FE +#define B_EFI_MSR_IA32_MTRR_CAP_EMRR_SUPPORT BIT12 +#define B_EFI_MSR_IA32_MTRR_CAP_SMRR_SUPPORT BIT11 +#define B_EFI_MSR_IA32_MTRR_CAP_WC_SUPPORT BIT10 +#define B_EFI_MSR_IA32_MTRR_CAP_FIXED_SUPPORT BIT8 +#define B_EFI_MSR_IA32_MTRR_CAP_VARIABLE_SUPPORT (BIT7 | BIT6 | BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0) + +#define CPUID_VIR_PHY_ADDRESS_SIZE 0x80000008 +#define CPUID_EXTENDED_FUNCTION 0x80000000 + +#endif + diff --git a/IntelFspPkg/Library/BaseDebugDeviceLibNull/BaseDebugDeviceLibNull.inf b/IntelFspPkg/Library/BaseDebugDeviceLibNull/BaseDebugDeviceLibNull.inf new file mode 100644 index 0000000000..58930bd82a --- /dev/null +++ b/IntelFspPkg/Library/BaseDebugDeviceLibNull/BaseDebugDeviceLibNull.inf @@ -0,0 +1,34 @@ +## @file +# Debug device library instance that retrieves the current enabling state for +# the platform debug output device. +# +# Copyright (c) 2014, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = BaseDebugDeviceLibNull + FILE_GUID = 455D16DC-E3AF-4b5f-A9AD-A4BC198085BD + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = DebugDeviceLib + +# +# VALID_ARCHITECTURES = IA32 +# + +[Sources] + DebugDeviceLibNull.c + +[Packages] + MdePkg/MdePkg.dec + IntelFspPkg/IntelFspPkg.dec + diff --git a/IntelFspPkg/Library/BaseDebugDeviceLibNull/DebugDeviceLibNull.c b/IntelFspPkg/Library/BaseDebugDeviceLibNull/DebugDeviceLibNull.c new file mode 100644 index 0000000000..95c100472c --- /dev/null +++ b/IntelFspPkg/Library/BaseDebugDeviceLibNull/DebugDeviceLibNull.c @@ -0,0 +1,31 @@ +/** @file + Debug device library instance that retrieves the current enabling state for + the platform debug output device. + + Copyright (c) 2014, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include + +/** + Returns the debug print device enable state. + + @return Debug print device enable state. + +**/ +UINT8 +EFIAPI +GetDebugPrintDeviceEnable ( + VOID + ) +{ + return 1; +} diff --git a/IntelFspPkg/Library/BaseFspCommonLib/BaseFspCommonLib.inf b/IntelFspPkg/Library/BaseFspCommonLib/BaseFspCommonLib.inf new file mode 100644 index 0000000000..0fa8c6a2dc --- /dev/null +++ b/IntelFspPkg/Library/BaseFspCommonLib/BaseFspCommonLib.inf @@ -0,0 +1,37 @@ +## @file +# +# Copyright (c) 2014, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = BaseFspCommonLib + FILE_GUID = 54607F66-D728-448e-A282-49E0404A557F + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = FspCommonLib + +[Sources] + FspCommonLib.c + +[Packages] + MdePkg/MdePkg.dec + IntelFspPkg/IntelFspPkg.dec + +[LibraryClasses] + BaseMemoryLib + +[Pcd] + gIntelFspPkgTokenSpaceGuid.PcdGlobalDataPointerAddress + +[FixedPcd] + gIntelFspPkgTokenSpaceGuid.PcdFspMaxPatchEntry + gIntelFspPkgTokenSpaceGuid.PcdFspMaxPerfEntry diff --git a/IntelFspPkg/Library/BaseFspCommonLib/FspCommonLib.c b/IntelFspPkg/Library/BaseFspCommonLib/FspCommonLib.c new file mode 100644 index 0000000000..958a7322a0 --- /dev/null +++ b/IntelFspPkg/Library/BaseFspCommonLib/FspCommonLib.c @@ -0,0 +1,318 @@ +/** @file + + Copyright (c) 2014, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include +#include +#include + +#pragma pack(1) + +// +// Cont Func Parameter 2 +0x3C +// Cont Func Parameter 1 +0x38 +// +// API Parameter +0x34 +// API return address +0x30 +// +// push offset exit +0x2C +// pushfd +0x28 +// cli +// pushad +0x24 +// sub esp, 8 +0x00 +// sidt fword ptr [esp] +// +typedef struct { + UINT16 IdtrLimit; + UINT32 IdtrBase; + UINT16 Reserved; + UINT32 Edi; + UINT32 Esi; + UINT32 Ebp; + UINT32 Esp; + UINT32 Ebx; + UINT32 Edx; + UINT32 Ecx; + UINT32 Eax; + UINT16 Flags[2]; + UINT32 ExitOff; + UINT32 ApiRet; + UINT32 ApiParam; +} CONTEXT_STACK; + +#define CONTEXT_STACK_OFFSET(x) (UINT32)&((CONTEXT_STACK *)(UINTN)0)->x + +#pragma pack() + +/** + This function sets the FSP global data pointer. + + @param[in] FspData Fsp global data pointer. + +**/ +VOID +EFIAPI +SetFspGlobalDataPointer ( + IN FSP_GLOBAL_DATA *FspData + ) +{ + ASSERT (FspData != NULL); + *((volatile UINT32 *)(UINTN)PcdGet32(PcdGlobalDataPointerAddress)) = (UINT32)(UINTN)FspData; +} + +/** + This function gets the FSP global data pointer. + +**/ +FSP_GLOBAL_DATA * +EFIAPI +GetFspGlobalDataPointer ( + VOID + ) +{ + FSP_GLOBAL_DATA *FspData; + + FspData = *(FSP_GLOBAL_DATA **)(UINTN)PcdGet32(PcdGlobalDataPointerAddress); + return FspData; +} + +/** + This function gets back the FSP API paramter passed by the bootlaoder. + + @retval ApiParameter FSP API paramter passed by the bootlaoder. +**/ +UINT32 +EFIAPI +GetFspApiParameter ( + VOID + ) +{ + FSP_GLOBAL_DATA *FspData; + + FspData = GetFspGlobalDataPointer (); + return *(UINT32 *)(UINTN)(FspData->CoreStack + CONTEXT_STACK_OFFSET(ApiParam)); +} + +/** + This function sets the FSP API paramter in the stack. + + @param[in] Value New parameter value. + +**/ +VOID +EFIAPI +SetFspApiParameter ( + IN UINT32 Value + ) +{ + FSP_GLOBAL_DATA *FspData; + + FspData = GetFspGlobalDataPointer (); + *(UINT32 *)(UINTN)(FspData->CoreStack + CONTEXT_STACK_OFFSET(ApiParam)) = Value; +} + +/** + This function sets the FSP continuation function parameters in the stack. + + @param[in] Value New parameter value to set. + @param[in] Index Parameter index. +**/ +VOID +EFIAPI +SetFspContinuationFuncParameter ( + IN UINT32 Value, + IN UINT32 Index + ) +{ + FSP_GLOBAL_DATA *FspData; + + FspData = GetFspGlobalDataPointer (); + *(UINT32 *)(UINTN)(FspData->CoreStack + CONTEXT_STACK_OFFSET(ApiParam) + (Index + 1) * sizeof(UINT32)) = Value; +} + + +/** + This function changes the Bootloader return address in stack. + + @param[in] ReturnAddress Address to return. + +**/ +VOID +EFIAPI +SetFspApiReturnAddress ( + IN UINT32 ReturnAddress + ) +{ + FSP_GLOBAL_DATA *FspData; + + FspData = GetFspGlobalDataPointer (); + *(UINT32 *)(UINTN)(FspData->CoreStack + CONTEXT_STACK_OFFSET(ApiRet)) = ReturnAddress; +} + +/** + This function set the API status code returned to the bootloader. + + @param[in] ReturnStatus Status code to return. + +**/ +VOID +EFIAPI +SetFspApiReturnStatus ( + IN UINT32 ReturnStatus + ) +{ + FSP_GLOBAL_DATA *FspData; + + FspData = GetFspGlobalDataPointer (); + *(UINT32 *)(UINTN)(FspData->CoreStack + CONTEXT_STACK_OFFSET(Eax)) = ReturnStatus; +} + +/** + This function sets the context switching stack to a new stack frame. + + @param[in] NewStackTop New core stack to be set. + +**/ +VOID +EFIAPI +SetFspCoreStackPointer ( + IN VOID *NewStackTop + ) +{ + FSP_GLOBAL_DATA *FspData; + UINT32 *OldStack; + UINT32 *NewStack; + UINT32 StackContextLen; + + FspData = GetFspGlobalDataPointer (); + StackContextLen = sizeof(CONTEXT_STACK) / sizeof(UINT32); + + // + // Reserve space for the ContinuationFunc two parameters + // + OldStack = (UINT32 *)FspData->CoreStack; + NewStack = (UINT32 *)NewStackTop - StackContextLen - 2; + FspData->CoreStack = (UINT32)NewStack; + while (StackContextLen-- != 0) { + *NewStack++ = *OldStack++; + } +} + +/** + This function sets the platform specific data pointer. + + @param[in] PlatformData Fsp platform specific data pointer. + +**/ +VOID +EFIAPI +SetFspPlatformDataPointer ( + IN VOID *PlatformData + ) +{ + FSP_GLOBAL_DATA *FspData; + + FspData = GetFspGlobalDataPointer (); + FspData->PlatformData.DataPtr = PlatformData; +} + + +/** + This function gets the platform specific data pointer. + + @param[in] PlatformData Fsp platform specific data pointer. + +**/ +VOID * +EFIAPI +GetFspPlatformDataPointer ( + VOID + ) +{ + FSP_GLOBAL_DATA *FspData; + + FspData = GetFspGlobalDataPointer (); + return FspData->PlatformData.DataPtr; +} + + +/** + This function sets the UPD data pointer. + + @param[in] UpdDataRgnPtr UPD data pointer. +**/ +VOID +EFIAPI +SetFspUpdDataPointer ( + IN VOID *UpdDataRgnPtr + ) +{ + FSP_GLOBAL_DATA *FspData; + + // + // Get the Fsp Global Data Pointer + // + FspData = GetFspGlobalDataPointer (); + + // + // Set the UPD pointer. + // + FspData->UpdDataRgnPtr = UpdDataRgnPtr; +} + +/** + This function gets the UPD data pointer. + + @return UpdDataRgnPtr UPD data pointer. +**/ +VOID * +EFIAPI +GetFspUpdDataPointer ( + VOID + ) +{ + FSP_GLOBAL_DATA *FspData; + + FspData = GetFspGlobalDataPointer (); + return FspData->UpdDataRgnPtr; +} + +/** + Set FSP measurement point timestamp. + + @param[in] Id Measurement point ID. + + @return performance timestamp. +**/ +UINT64 +EFIAPI +SetFspMeasurePoint ( + IN UINT8 Id + ) +{ + FSP_GLOBAL_DATA *FspData; + + // + // Bit [55: 0] will be the timestamp + // Bit [63:56] will be the ID + // + FspData = GetFspGlobalDataPointer (); + if (FspData->PerfIdx < sizeof(FspData->PerfData) / sizeof(FspData->PerfData[0])) { + FspData->PerfData[FspData->PerfIdx] = AsmReadTsc (); + ((UINT8 *)(&FspData->PerfData[FspData->PerfIdx]))[7] = Id; + } + + return FspData->PerfData[(FspData->PerfIdx)++]; +} diff --git a/IntelFspPkg/Library/BaseFspDebugLibSerialPort/BaseFspDebugLibSerialPort.inf b/IntelFspPkg/Library/BaseFspDebugLibSerialPort/BaseFspDebugLibSerialPort.inf new file mode 100644 index 0000000000..d3df6c3de3 --- /dev/null +++ b/IntelFspPkg/Library/BaseFspDebugLibSerialPort/BaseFspDebugLibSerialPort.inf @@ -0,0 +1,49 @@ +## @file +# +# Copyright (c) 2014, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = BaseFspDebugLibSerialPort + FILE_GUID = BB83F95F-EDBC-4884-A520-CD42AF388FAE + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = DebugLib + +# +# VALID_ARCHITECTURES = IA32 +# + +[Sources] + DebugLib.c + +[Sources.Ia32] + Ia32/FspDebug.asm | MSFT + Ia32/FspDebug.s | GCC + +[Packages] + MdePkg/MdePkg.dec + IntelFspPkg/IntelFspPkg.dec + +[LibraryClasses] + SerialPortLib + BaseMemoryLib + PcdLib + PrintLib + BaseLib + DebugDeviceLib + DebugPrintErrorLevelLib + +[Pcd] + gEfiMdePkgTokenSpaceGuid.PcdDebugClearMemoryValue + gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask + diff --git a/IntelFspPkg/Library/BaseFspDebugLibSerialPort/DebugLib.c b/IntelFspPkg/Library/BaseFspDebugLibSerialPort/DebugLib.c new file mode 100644 index 0000000000..467d59db0e --- /dev/null +++ b/IntelFspPkg/Library/BaseFspDebugLibSerialPort/DebugLib.c @@ -0,0 +1,305 @@ +/** @file + + Copyright (c) 2014, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// +// Define the maximum debug and assert message length that this library supports +// +#define MAX_DEBUG_MESSAGE_LENGTH 0x100 + +CONST CHAR8 *mHexTable = "0123456789ABCDEF"; + +/** + Get stack frame pointer of function call. + + @return StackFramePointer stack frame pointer of function call. +**/ +UINT32 * +EFIAPI +GetStackFramePointer ( + VOID + ); + + +/** + Prints a debug message to the debug output device if the specified error level is enabled. + + If any bit in ErrorLevel is also set in DebugPrintErrorLevelLib function + GetDebugPrintErrorLevel (), then print the message specified by Format and the + associated variable argument list to the debug output device. + + If Format is NULL, then ASSERT(). + + @param ErrorLevel The error level of the debug message. + @param Format Format string for the debug message to print. + @param ... Variable argument list whose contents are accessed + based on the format string specified by Format. + +**/ +VOID +EFIAPI +DebugPrint ( + IN UINTN ErrorLevel, + IN CONST CHAR8 *Format, + ... + ) +{ + CHAR8 Buffer[MAX_DEBUG_MESSAGE_LENGTH]; + VA_LIST Marker; + + // + // If Format is NULL, then ASSERT(). + // + if (!GetDebugPrintDeviceEnable ()) { + return; + } + + // + // Check driver debug mask value and global mask + // + if ((ErrorLevel & GetDebugPrintErrorLevel ()) == 0) { + return; + } + + // + // If Format is NULL, then ASSERT(). + // + ASSERT (Format != NULL); + + // + // Convert the DEBUG() message to an ASCII String + // + VA_START (Marker, Format); + AsciiVSPrint (Buffer, sizeof (Buffer), Format, Marker); + VA_END (Marker); + + // + // Send the print string to a Serial Port + // + SerialPortWrite ((UINT8 *)Buffer, AsciiStrLen (Buffer)); +} + +/** + Convert an UINT32 value into HEX string sepcified by Buffer. + + @param Value The HEX value to convert to string + @param Buffer The pointer to the target buffer to be filled with HEX string + +**/ +VOID +FillHex ( + UINT32 Value, + CHAR8 *Buffer + ) +{ + INTN Idx; + for (Idx = 7; Idx >= 0; Idx--) { + Buffer[Idx] = mHexTable[Value & 0x0F]; + Value >>= 4; + } +} + +/** + Prints an assert message containing a filename, line number, and description. + This may be followed by a breakpoint or a dead loop. + + Print a message of the form "ASSERT (): \n" + to the debug output device. If DEBUG_PROPERTY_ASSERT_BREAKPOINT_ENABLED bit of + PcdDebugProperyMask is set then CpuBreakpoint() is called. Otherwise, if + DEBUG_PROPERTY_ASSERT_DEADLOOP_ENABLED bit of PcdDebugProperyMask is set then + CpuDeadLoop() is called. If neither of these bits are set, then this function + returns immediately after the message is printed to the debug output device. + DebugAssert() must actively prevent recursion. If DebugAssert() is called while + processing another DebugAssert(), then DebugAssert() must return immediately. + + If FileName is NULL, then a string of "(NULL) Filename" is printed. + If Description is NULL, then a string of "(NULL) Description" is printed. + +**/ +VOID +DebugAssertInternal ( + VOID + ) +{ + CHAR8 Buffer[MAX_DEBUG_MESSAGE_LENGTH]; + UINT32 *Frame; + + Frame = (UINT32 *)GetStackFramePointer (); + + // + // Generate the ASSERT() message in Ascii format + // + AsciiStrCpy (Buffer, "-> EBP:0x00000000 EIP:0x00000000\n"); + SerialPortWrite ((UINT8 *)"ASSERT DUMP:\n", 13); + while (Frame != NULL) { + FillHex ((UINT32)Frame, Buffer + 9); + FillHex (Frame[1], Buffer + 9 + 8 + 8); + SerialPortWrite ((UINT8 *)Buffer, AsciiStrLen (Buffer)); + if ((Frame[0] > (UINT32)Frame) && (Frame[0] < (UINT32)Frame + 0x00100000)) { + Frame = (UINT32 *)Frame[0]; + } else { + Frame = NULL; + } + } + + // + // Dead loop + // + CpuDeadLoop (); +} + +/** + Prints an assert message containing a filename, line number, and description. + This may be followed by a breakpoint or a dead loop. + + Print a message of the form "ASSERT (): \n" + to the debug output device. If DEBUG_PROPERTY_ASSERT_BREAKPOINT_ENABLED bit of + PcdDebugProperyMask is set then CpuBreakpoint() is called. Otherwise, if + DEBUG_PROPERTY_ASSERT_DEADLOOP_ENABLED bit of PcdDebugProperyMask is set then + CpuDeadLoop() is called. If neither of these bits are set, then this function + returns immediately after the message is printed to the debug output device. + DebugAssert() must actively prevent recursion. If DebugAssert() is called while + processing another DebugAssert(), then DebugAssert() must return immediately. + + If FileName is NULL, then a string of "(NULL) Filename" is printed. + If Description is NULL, then a string of "(NULL) Description" is printed. + + @param FileName The pointer to the name of the source file that generated the assert condition. + @param LineNumber The line number in the source file that generated the assert condition + @param Description The pointer to the description of the assert condition. + +**/ +VOID +EFIAPI +DebugAssert ( + IN CONST CHAR8 *FileName, + IN UINTN LineNumber, + IN CONST CHAR8 *Description + ) +{ + DebugAssertInternal (); +} + + +/** + Fills a target buffer with PcdDebugClearMemoryValue, and returns the target buffer. + + This function fills Length bytes of Buffer with the value specified by + PcdDebugClearMemoryValue, and returns Buffer. + + If Buffer is NULL, then ASSERT(). + If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT(). + + @param Buffer The pointer to the target buffer to be filled with PcdDebugClearMemoryValue. + @param Length The number of bytes in Buffer to fill with zeros PcdDebugClearMemoryValue. + + @return Buffer The pointer to the target buffer filled with PcdDebugClearMemoryValue. + +**/ +VOID * +EFIAPI +DebugClearMemory ( + OUT VOID *Buffer, + IN UINTN Length + ) +{ + return Buffer; +} + + +/** + Returns TRUE if ASSERT() macros are enabled. + + This function returns TRUE if the DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of + PcdDebugProperyMask is set. Otherwise FALSE is returned. + + @retval TRUE The DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of PcdDebugProperyMask is set. + @retval FALSE The DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of PcdDebugProperyMask is clear. + +**/ +BOOLEAN +EFIAPI +DebugAssertEnabled ( + VOID + ) +{ + return (BOOLEAN) ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED) != 0); +} + + +/** + Returns TRUE if DEBUG() macros are enabled. + + This function returns TRUE if the DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of + PcdDebugProperyMask is set. Otherwise FALSE is returned. + + @retval TRUE The DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of PcdDebugProperyMask is set. + @retval FALSE The DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of PcdDebugProperyMask is clear. + +**/ +BOOLEAN +EFIAPI +DebugPrintEnabled ( + VOID + ) +{ + return (BOOLEAN) ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_PRINT_ENABLED) != 0); +} + +/** + Returns TRUE if DEBUG_CODE() macros are enabled. + + This function returns TRUE if the DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of + PcdDebugProperyMask is set. Otherwise FALSE is returned. + + @retval TRUE The DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of PcdDebugProperyMask is set. + @retval FALSE The DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of PcdDebugProperyMask is clear. + +**/ +BOOLEAN +EFIAPI +DebugCodeEnabled ( + VOID + ) +{ + return (BOOLEAN) ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_CODE_ENABLED) != 0); +} + + +/** + Returns TRUE if DEBUG_CLEAR_MEMORY() macro is enabled. + + This function returns TRUE if the DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED bit of + PcdDebugProperyMask is set. Otherwise FALSE is returned. + + @retval TRUE The DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED bit of PcdDebugProperyMask is set. + @retval FALSE The DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED bit of PcdDebugProperyMask is clear. + +**/ +BOOLEAN +EFIAPI +DebugClearMemoryEnabled ( + VOID + ) +{ + return (BOOLEAN) ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED) != 0); +} diff --git a/IntelFspPkg/Library/BaseFspDebugLibSerialPort/Ia32/FspDebug.asm b/IntelFspPkg/Library/BaseFspDebugLibSerialPort/Ia32/FspDebug.asm new file mode 100644 index 0000000000..8ac18ec4ec --- /dev/null +++ b/IntelFspPkg/Library/BaseFspDebugLibSerialPort/Ia32/FspDebug.asm @@ -0,0 +1,34 @@ +;------------------------------------------------------------------------------ +; +; Copyright (c) 2014, Intel Corporation. All rights reserved.
+; This program and the accompanying materials +; are licensed and made available under the terms and conditions of the BSD License +; which accompanies this distribution. The full text of the license may be found at +; http://opensource.org/licenses/bsd-license.php. +; +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +; +; Abstract: +; +; FSP Debug functions +; +;------------------------------------------------------------------------------ + + .386 + .model flat,C + .code + +;------------------------------------------------------------------------------ +; UINT32 * +; EFIAPI +; GetStackFramePointer ( +; VOID +; ); +;------------------------------------------------------------------------------ +GetStackFramePointer PROC PUBLIC + mov eax, ebp + ret +GetStackFramePointer ENDP + + END diff --git a/IntelFspPkg/Library/BaseFspDebugLibSerialPort/Ia32/FspDebug.s b/IntelFspPkg/Library/BaseFspDebugLibSerialPort/Ia32/FspDebug.s new file mode 100644 index 0000000000..0f8475fa62 --- /dev/null +++ b/IntelFspPkg/Library/BaseFspDebugLibSerialPort/Ia32/FspDebug.s @@ -0,0 +1,30 @@ +#------------------------------------------------------------------------------ +# +# Copyright (c) 2014, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# Abstract: +# +# FSP Debug functions +# +#------------------------------------------------------------------------------ + +#------------------------------------------------------------------------------ +# UINT32 * +# EFIAPI +# GetStackFramePointer ( +# VOID +# ) +#------------------------------------------------------------------------------ +ASM_GLOBAL ASM_PFX(GetStackFramePointer) +ASM_PFX(GetStackFramePointer): + mov %ebp, %eax + ret + + diff --git a/IntelFspPkg/Library/BaseFspPlatformLib/BaseFspPlatformLib.inf b/IntelFspPkg/Library/BaseFspPlatformLib/BaseFspPlatformLib.inf new file mode 100644 index 0000000000..debce76c30 --- /dev/null +++ b/IntelFspPkg/Library/BaseFspPlatformLib/BaseFspPlatformLib.inf @@ -0,0 +1,41 @@ +## @file +# +# Copyright (c) 2014, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = BaseFspPlatformLib + FILE_GUID = 7DECCDAF-361F-4ec1-9714-260BAAF6F384 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = FspPlatformLib + +[Sources] + FspPlatformMemory.c + FspPlatformNotify.c + +[Packages] + MdePkg/MdePkg.dec + IntelFspPkg/IntelFspPkg.dec + +[LibraryClasses] + BaseMemoryLib + +[Pcd] + gIntelFspPkgTokenSpaceGuid.PcdGlobalDataPointerAddress + gIntelFspPkgTokenSpaceGuid.PcdTemporaryRamBase + gIntelFspPkgTokenSpaceGuid.PcdTemporaryRamSize + gIntelFspPkgTokenSpaceGuid.PcdFspTemporaryRamSize + +[FixedPcd] + gIntelFspPkgTokenSpaceGuid.PcdFspMaxPatchEntry + gIntelFspPkgTokenSpaceGuid.PcdFspMaxPerfEntry diff --git a/IntelFspPkg/Library/BaseFspPlatformLib/FspPlatformMemory.c b/IntelFspPkg/Library/BaseFspPlatformLib/FspPlatformMemory.c new file mode 100644 index 0000000000..2f1c0b14e5 --- /dev/null +++ b/IntelFspPkg/Library/BaseFspPlatformLib/FspPlatformMemory.c @@ -0,0 +1,155 @@ +/** @file + + Copyright (c) 2014, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + Get system memory from HOB. + + @param[in,out] LowMemoryLength less than 4G memory length + @param[in,out] HighMemoryLength greater than 4G memory length +**/ +VOID +EFIAPI +FspGetSystemMemorySize ( + IN OUT UINT64 *LowMemoryLength, + IN OUT UINT64 *HighMemoryLength + ) +{ + EFI_PEI_HOB_POINTERS Hob; + + *HighMemoryLength = 0; + *LowMemoryLength = SIZE_1MB; + // + // Get the HOB list for processing + // + Hob.Raw = GetHobList (); + + // + // Collect memory ranges + // + while (!END_OF_HOB_LIST (Hob)) { + if (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) { + if (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) { + // + // Need memory above 1MB to be collected here + // + if (Hob.ResourceDescriptor->PhysicalStart >= BASE_1MB && + Hob.ResourceDescriptor->PhysicalStart < (EFI_PHYSICAL_ADDRESS) BASE_4GB) { + *LowMemoryLength += (UINT64) (Hob.ResourceDescriptor->ResourceLength); + } else if (Hob.ResourceDescriptor->PhysicalStart >= (EFI_PHYSICAL_ADDRESS) BASE_4GB) { + *HighMemoryLength += (UINT64) (Hob.ResourceDescriptor->ResourceLength); + } + } + } + Hob.Raw = GET_NEXT_HOB (Hob); + } +} + +/** + Migrate bootloader data before destroying CAR. + +**/ +VOID +EFIAPI +FspMigrateTemporaryMemory ( + VOID + ) +{ + FSP_INIT_RT_COMMON_BUFFER *FspInitRtBuffer; + UINT32 BootLoaderTempRamStart; + UINT32 BootLoaderTempRamEnd; + UINT32 BootLoaderTempRamSize; + UINT32 OffsetGap; + UINT32 FspParamPtr; + FSP_INIT_PARAMS *FspInitParams; + UINT32 *NewStackTop; + VOID *BootLoaderTempRamHob; + VOID *UpdDataRgnPtr; + VOID *PlatformDataPtr; + + // + // Get the temporary memory range used by the bootloader + // + BootLoaderTempRamStart = PcdGet32(PcdTemporaryRamBase); + BootLoaderTempRamSize = PcdGet32(PcdTemporaryRamSize) - PcdGet32(PcdFspTemporaryRamSize); + BootLoaderTempRamEnd = BootLoaderTempRamStart + BootLoaderTempRamSize; + + // + // Build a Boot Loader Temporary Memory GUID HOB + // + BootLoaderTempRamHob = BuildGuidHob (&gFspBootLoaderTemporaryMemoryGuid, BootLoaderTempRamSize); + CopyMem (BootLoaderTempRamHob, (VOID *)BootLoaderTempRamStart, BootLoaderTempRamSize); + OffsetGap = (UINT32)BootLoaderTempRamHob - BootLoaderTempRamStart; + + // + // Set a new stack frame for the continuation function + // + FspInitParams = (FSP_INIT_PARAMS *)GetFspApiParameter (); + FspInitRtBuffer = (FSP_INIT_RT_COMMON_BUFFER *)FspInitParams->RtBufferPtr; + NewStackTop = (UINT32 *)FspInitRtBuffer->StackTop - 1; + SetFspCoreStackPointer (NewStackTop); + + // + // Fix the FspInit Parameter Pointers to the new location. + // + FspParamPtr = GetFspApiParameter (); + if (FspParamPtr >= BootLoaderTempRamStart && FspParamPtr < BootLoaderTempRamEnd) { + SetFspApiParameter(FspParamPtr + OffsetGap); + } + + FspInitParams = (FSP_INIT_PARAMS *)GetFspApiParameter (); + if ((UINT32)(FspInitParams->RtBufferPtr) >= BootLoaderTempRamStart && + (UINT32)(FspInitParams->RtBufferPtr) < BootLoaderTempRamEnd) { + FspInitParams->RtBufferPtr = (VOID *)((UINT32)(FspInitParams->RtBufferPtr) + OffsetGap); + } + + if ((UINT32)(FspInitParams->NvsBufferPtr) >= BootLoaderTempRamStart && + (UINT32)(FspInitParams->NvsBufferPtr) < BootLoaderTempRamEnd) { + FspInitParams->NvsBufferPtr = (VOID *)((UINT32)(FspInitParams->NvsBufferPtr) + OffsetGap); + } + + if ((UINT32)(((FSP_INIT_RT_COMMON_BUFFER *)(FspInitParams->RtBufferPtr))->UpdDataRgnPtr) >= BootLoaderTempRamStart && + (UINT32)(((FSP_INIT_RT_COMMON_BUFFER *)(FspInitParams->RtBufferPtr))->UpdDataRgnPtr) < BootLoaderTempRamEnd) { + ((FSP_INIT_RT_COMMON_BUFFER *)(FspInitParams->RtBufferPtr))->UpdDataRgnPtr = \ + (VOID *)((UINT32)(((FSP_INIT_RT_COMMON_BUFFER *)(FspInitParams->RtBufferPtr))->UpdDataRgnPtr) + OffsetGap); + } + + // + // Update UPD pointer in FSP Global Data + // + UpdDataRgnPtr = ((FSP_INIT_RT_COMMON_BUFFER *)FspInitParams->RtBufferPtr)->UpdDataRgnPtr; + if (UpdDataRgnPtr != NULL) { + SetFspUpdDataPointer (UpdDataRgnPtr); + } + + // + // Update Platform data pointer in FSP Global Data + // + PlatformDataPtr = GetFspPlatformDataPointer (); + if (((UINT32)PlatformDataPtr >= BootLoaderTempRamStart) && + ((UINT32)PlatformDataPtr < BootLoaderTempRamEnd)) { + SetFspPlatformDataPointer ((UINT8 *)PlatformDataPtr + OffsetGap); + } + +} diff --git a/IntelFspPkg/Library/BaseFspPlatformLib/FspPlatformNotify.c b/IntelFspPkg/Library/BaseFspPlatformLib/FspPlatformNotify.c new file mode 100644 index 0000000000..3488fbc61c --- /dev/null +++ b/IntelFspPkg/Library/BaseFspPlatformLib/FspPlatformNotify.c @@ -0,0 +1,178 @@ +/** @file + + Copyright (c) 2014, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +EFI_PEI_PPI_DESCRIPTOR mPeiPostPciEnumerationPpi = { + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiPciEnumerationCompleteProtocolGuid, + NULL +}; + +EFI_PEI_PPI_DESCRIPTOR mPeiReadyToBootPpi = { + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiEventReadyToBootGuid, + NULL +}; + + +UINT32 mFspNotfifySequence[] = { + EnumInitPhaseAfterPciEnumeration, + EnumInitPhaseReadyToBoot +}; + +/** + Install FSP notification. + + @param[in] NotificatonCode FSP notification code + + @retval EFI_SUCCESS Notify FSP successfully + @retval EFI_INVALID_PARAMETER NotificatonCode is invalid + +**/ +EFI_STATUS +EFIAPI +FspNotificationHandler ( + IN UINT32 NotificatonCode + ) +{ + EFI_STATUS Status; + + Status = EFI_SUCCESS; + + switch (NotificatonCode) { + case EnumInitPhaseAfterPciEnumeration: + // + // Do POST PCI initialization if needed + // + DEBUG ((DEBUG_INFO | DEBUG_INIT, "FSP Post PCI Enumeration ...\n")); + PeiServicesInstallPpi (&mPeiPostPciEnumerationPpi); + break; + + case EnumInitPhaseReadyToBoot: + // + // Ready To Boot + // + DEBUG ((DEBUG_INFO| DEBUG_INIT, "FSP Ready To Boot ...\n")); + PeiServicesInstallPpi (&mPeiReadyToBootPpi); + break; + + default: + Status = EFI_INVALID_PARAMETER; + break; + } + + return Status; +} + +/** + This function transfer control to the ContinuationFunc passed in by the + bootloader. + +**/ +VOID +EFIAPI +FspInitDone ( + VOID + ) +{ + FSP_INIT_PARAMS *FspInitParams; + + FspInitParams = (FSP_INIT_PARAMS *)GetFspApiParameter (); + + // + // Modify the parameters for ContinuationFunc + // + SetFspContinuationFuncParameter(EFI_SUCCESS, 0); + SetFspContinuationFuncParameter((UINT32)GetHobList(), 1); + + // + // Modify the return address to ContinuationFunc + // + SetFspApiReturnAddress((UINT32)FspInitParams->ContinuationFunc); + + // + // Give control back to the boot loader framework caller after FspInit is done + // It is done throught the continuation function + // + SetFspMeasurePoint (FSP_PERF_ID_API_FSPINIT_EXIT); + Pei2LoaderSwitchStack(); +} + +/** + This function handle NotifyPhase API call from the bootloader. + It gives control back to the bootloader after it is handled. If the + Notification code is a ReadyToBoot event, this function will return + and FSP continues the remaining execution until it reaches the DxeIpl. + +**/ +VOID +FspWaitForNotify ( + VOID + ) +{ + EFI_STATUS Status; + UINT32 NotificatonValue; + UINT32 NotificatonCount; + UINT8 Count; + + NotificatonCount = 0; + while (NotificatonCount < sizeof(mFspNotfifySequence) / sizeof(UINT32)) { + + Count = (NotificatonCount << 1) & 0x07; + SetFspMeasurePoint (FSP_PERF_ID_API_NOTIFY_POSTPCI_ENTRY + Count); + + NotificatonValue = ((NOTIFY_PHASE_PARAMS *)(UINTN)GetFspApiParameter ())->Phase; + DEBUG ((DEBUG_INFO, "FSP Got Notification. Notification Value : 0x%08X\n", NotificatonValue)); + + if (mFspNotfifySequence[NotificatonCount] != NotificatonValue) { + // + // Notify code does not follow the predefined order + // + SetFspApiReturnStatus(EFI_UNSUPPORTED); + } else { + // + // Process Notification and Give control back to the boot loader framework caller + // + Status = FspNotificationHandler (NotificatonValue); + SetFspApiReturnStatus(Status); + if (!EFI_ERROR(Status)) { + NotificatonCount++; + SetFspApiReturnStatus(EFI_SUCCESS); + if (NotificatonValue == EnumInitPhaseReadyToBoot) { + break; + } + } + } + SetFspMeasurePoint (FSP_PERF_ID_API_NOTIFY_POSTPCI_EXIT + Count); + Pei2LoaderSwitchStack(); + } + + // + // Control goes back to the PEI Core and it dispatches further PEIMs. + // DXEIPL is the final one to transfer control back to the boot loader. + // +} + diff --git a/IntelFspPkg/Library/BaseFspSwitchStackLib/BaseFspSwitchStackLib.inf b/IntelFspPkg/Library/BaseFspSwitchStackLib/BaseFspSwitchStackLib.inf new file mode 100644 index 0000000000..c3b47b5dbf --- /dev/null +++ b/IntelFspPkg/Library/BaseFspSwitchStackLib/BaseFspSwitchStackLib.inf @@ -0,0 +1,42 @@ +## @file +# +# Copyright (c) 2014, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = BaseFspSwitchStackLib + FILE_GUID = 8A5EA987-27F9-4ad0-B07C-D61882BFF4FF + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = FspSwitchStackLib + +[Sources.IA32] + FspSwitchStackLib.c + +[Sources.IA32] + Ia32/Stack.asm | MSFT + Ia32/Stack.s | GCC + +[Packages] + MdePkg/MdePkg.dec + IntelFspPkg/IntelFspPkg.dec + +[LibraryClasses] + BaseLib + IoLib + +[FixedPcd] + gIntelFspPkgTokenSpaceGuid.PcdFspMaxPatchEntry + gIntelFspPkgTokenSpaceGuid.PcdFspMaxPerfEntry + + + diff --git a/IntelFspPkg/Library/BaseFspSwitchStackLib/FspSwitchStackLib.c b/IntelFspPkg/Library/BaseFspSwitchStackLib/FspSwitchStackLib.c new file mode 100644 index 0000000000..42a57a27c0 --- /dev/null +++ b/IntelFspPkg/Library/BaseFspSwitchStackLib/FspSwitchStackLib.c @@ -0,0 +1,42 @@ +/** @file + + Copyright (c) 2014, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include + +/** + + Switch the current stack to the previous saved stack. + + @param[in] NewStack The new stack to be switched. + + @return OldStack After switching to the saved stack, + this value will be saved in eax before returning. + + +**/ +UINT32 +SwapStack ( + IN UINT32 NewStack + ) +{ + FSP_GLOBAL_DATA *FspData; + UINT32 OldStack; + + FspData = GetFspGlobalDataPointer (); + OldStack = FspData->CoreStack; + FspData->CoreStack = NewStack; + return OldStack; +} + diff --git a/IntelFspPkg/Library/BaseFspSwitchStackLib/Ia32/Stack.asm b/IntelFspPkg/Library/BaseFspSwitchStackLib/Ia32/Stack.asm new file mode 100644 index 0000000000..d04f229a6b --- /dev/null +++ b/IntelFspPkg/Library/BaseFspSwitchStackLib/Ia32/Stack.asm @@ -0,0 +1,65 @@ +;------------------------------------------------------------------------------ +; +; Copyright (c) 2014, Intel Corporation. All rights reserved.
+; This program and the accompanying materials +; are licensed and made available under the terms and conditions of the BSD License +; which accompanies this distribution. The full text of the license may be found at +; http://opensource.org/licenses/bsd-license.php. +; +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +; +; Abstract: +; +; Switch the stack from temporary memory to permenent memory. +; +;------------------------------------------------------------------------------ + + .586p + .model flat,C + .code + +;------------------------------------------------------------------------------ +; UINT32 +; EFIAPI +; Pei2LoaderSwitchStack ( +; VOID +; ) +;------------------------------------------------------------------------------ +EXTERNDEF C MeasurePoint:PROC +Pei2LoaderSwitchStack PROC C PUBLIC + jmp Loader2PeiSwitchStack +Pei2LoaderSwitchStack ENDP + +;------------------------------------------------------------------------------ +; UINT32 +; EFIAPI +; Loader2PeiSwitchStack ( +; VOID +; ) +;------------------------------------------------------------------------------ +EXTERNDEF C SwapStack:PROC +Loader2PeiSwitchStack PROC C PUBLIC + ; Save current contexts + push offset exit + pushfd + cli + pushad + sub esp, 8 + sidt fword ptr [esp] + + ; Load new stack + push esp + call SwapStack + mov esp, eax + + ; Restore previous contexts + lidt fword ptr [esp] + add esp, 8 + popad + popfd +exit: + ret +Loader2PeiSwitchStack ENDP + + END diff --git a/IntelFspPkg/Library/BaseFspSwitchStackLib/Ia32/Stack.s b/IntelFspPkg/Library/BaseFspSwitchStackLib/Ia32/Stack.s new file mode 100644 index 0000000000..6932cd8448 --- /dev/null +++ b/IntelFspPkg/Library/BaseFspSwitchStackLib/Ia32/Stack.s @@ -0,0 +1,64 @@ +#------------------------------------------------------------------------------ +# +# Copyright (c) 2014, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# Abstract: +# +# Switch the stack from temporary memory to permenent memory. +# +#------------------------------------------------------------------------------ + +ASM_GLOBAL ASM_PFX(Pei2LoaderSwitchStack) +ASM_GLOBAL ASM_PFX(Loader2PeiSwitchStack) + +#------------------------------------------------------------------------------ +# UINT32 +# EFIAPI +# Pei2LoaderSwitchStack ( +# VOID +# ) +#------------------------------------------------------------------------------ +ASM_GLOBAL ASM_PFX(Pei2LoaderSwitchStack) +ASM_PFX(Pei2LoaderSwitchStack): + jmp ASM_PFX(Loader2PeiSwitchStack) + +#------------------------------------------------------------------------------ +# UINT32 +# EFIAPI +# Loader2PeiSwitchStack ( +# ) +#------------------------------------------------------------------------------ +ASM_GLOBAL ASM_PFX(Loader2PeiSwitchStack) +ASM_PFX(Loader2PeiSwitchStack): +#Save current contexts + push $exit + pushf + pushf + cli + pusha + push $0x0 + push $0x0 + sidt (%esp) + + # Load new stack + push %esp + call ASM_PFX(SwapStack) + mov %eax,%esp + + # Restore previous contexts + lidt (%esp) + add $8,%esp + popa + popf + popf +exit: + ret + + diff --git a/IntelFspPkg/Library/SecPlatformSecLibNull/PlatformSecLibNull.c b/IntelFspPkg/Library/SecPlatformSecLibNull/PlatformSecLibNull.c new file mode 100644 index 0000000000..af41a61813 --- /dev/null +++ b/IntelFspPkg/Library/SecPlatformSecLibNull/PlatformSecLibNull.c @@ -0,0 +1,29 @@ +/** @file + Null instance of Platform Sec Lib. + + Copyright (c) 2014, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include + +/** + This function provides dummy function so that SecCore can pass pass build + Validation in Ia32FamilyCpuPkg. All real platform library instances needs + to implement the real entry point in assembly. +**/ +VOID +EFIAPI +_ModuleEntryPoint ( + VOID + ) +{ + return; +} diff --git a/IntelFspPkg/Library/SecPlatformSecLibNull/SecPlatformSecLibNull.inf b/IntelFspPkg/Library/SecPlatformSecLibNull/SecPlatformSecLibNull.inf new file mode 100644 index 0000000000..72006c585c --- /dev/null +++ b/IntelFspPkg/Library/SecPlatformSecLibNull/SecPlatformSecLibNull.inf @@ -0,0 +1,53 @@ +## @file +# +# Copyright (c) 2014, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +################################################################################ +# +# Defines Section - statements that will be processed to create a Makefile. +# +################################################################################ +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = SecPlatformSecLibNull + FILE_GUID = 6695974D-968C-420b-80B9-7870CD20118F + MODULE_TYPE = SEC + VERSION_STRING = 1.0 + LIBRARY_CLASS = NULL + + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +################################################################################ +# +# Sources Section - list of files that are required for the build to succeed. +# +################################################################################ + +[Sources] + PlatformSecLibNull.c + + +################################################################################ +# +# Package Dependency Section - list of Package files that are required for +# this module. +# +################################################################################ + +[Packages] + MdePkg/MdePkg.dec + diff --git a/IntelFspPkg/Tools/GenCfgOpt.py b/IntelFspPkg/Tools/GenCfgOpt.py new file mode 100644 index 0000000000..4417bc33fe --- /dev/null +++ b/IntelFspPkg/Tools/GenCfgOpt.py @@ -0,0 +1,894 @@ +## @ GenCfgOpt.py +# +# Copyright (c) 2014, Intel Corporation. All rights reserved.
+# This program and the accompanying materials are licensed and made available under +# the terms and conditions of the BSD License that accompanies this distribution. +# The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +import os +import re +import sys +import struct +from datetime import date + +# Generated file copyright header + +__copyright_txt__ = """## @file +# +# THIS IS AUTO-GENERATED FILE BY BUILD TOOLS AND PLEASE DO NOT MAKE MODIFICATION. +# +# This file lists all VPD informations for a platform collected by build.exe. +# +# Copyright (c) %4d, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +""" + +__copyright_bsf__ = """/** @file + + Boot Setting File for Platform Configuration. + + Copyright (c) %4d, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + This file is automatically generated. Please do NOT modify !!! + +**/ + +""" + +__copyright_h__ = """/** @file + +Copyright (c) %4d, Intel Corporation. All rights reserved.
+ +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. +* Neither the name of Intel Corporation nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + THE POSSIBILITY OF SUCH DAMAGE. + + This file is automatically generated. Please do NOT modify !!! + +**/ +""" + +class CGenCfgOpt: + def __init__(self): + self.Error = '' + + self._GlobalDataDef = """ +GlobalDataDef + SKUID = 0, "DEFAULT" +EndGlobalData + +""" + self._BuidinOptionTxt = """ +List &EN_DIS + Selection 0x1 , "Enabled" + Selection 0x0 , "Disabled" +EndList + +""" + + self._BsfKeyList = ['FIND','NAME','HELP','TYPE','PAGE','OPTION','ORDER'] + self._HdrKeyList = ['HEADER','STRUCT'] + self._BuidinOption = {'$EN_DIS' : 'EN_DIS'} + + self._MacroDict = {} + self._CfgBlkDict = {} + self._CfgPageDict = {} + self._CfgItemList = [] + self._DscFile = '' + self._FvDir = '' + self._MapVer = 0 + + def ParseMacros (self, MacroDefStr): + # ['-DABC=1', '-D', 'CFG_DEBUG=1', '-D', 'CFG_OUTDIR=Build'] + self._MacroDict = {} + IsExpression = False + for Macro in MacroDefStr: + if Macro.startswith('-D'): + IsExpression = True + if len(Macro) > 2: + Macro = Macro[2:] + else : + continue + if IsExpression: + IsExpression = False + Match = re.match("(\w+)=(.+)", Macro) + if Match: + self._MacroDict[Match.group(1)] = Match.group(2) + else: + Match = re.match("(\w+)", Macro) + if Match: + self._MacroDict[Match.group(1)] = '' + if len(self._MacroDict) == 0: + self.Error = "Invalid MACRO arguments" + Error = 1 + else: + Error = 0 + return Error + + + def ParseDscFile (self, DscFile, FvDir): + self._CfgItemList = [] + self._CfgPageDict = {} + self._CfgBlkDict = {} + self._DscFile = DscFile + self._FvDir = FvDir + + IsDefSect = False + IsUpdSect = False + IsVpdSect = False + Found = False + + IfStack = [True] + ElifStack = [] + Error = 0 + + DscFd = open(DscFile, "r") + DscLines = DscFd.readlines() + DscFd.close() + + ConfigDict = {} + + for DscLine in DscLines: + Handle = False + DscLine = DscLine.strip() + Match = re.match("^\[(.+)\]", DscLine) + if Match is not None: + if Match.group(1).lower() == "Defines".lower(): + IsDefSect = True + IsVpdSect = False + IsUpdSect = False + elif Match.group(1).lower() == "PcdsDynamicVpd".lower(): + ConfigDict = {} + ConfigDict['header'] = 'ON' + ConfigDict['region'] = 'VPD' + ConfigDict['order'] = -1 + ConfigDict['page'] = '' + ConfigDict['name'] = '' + ConfigDict['find'] = '' + ConfigDict['struct'] = '' + ConfigDict['subreg'] = [] + IsDefSect = False + IsVpdSect = True + IsUpdSect = False + elif Match.group(1).lower() == "PcdsDynamicVpd.Upd".lower(): + ConfigDict = {} + ConfigDict['header'] = 'ON' + ConfigDict['region'] = 'UPD' + ConfigDict['order'] = -1 + ConfigDict['page'] = '' + ConfigDict['name'] = '' + ConfigDict['find'] = '' + ConfigDict['struct'] = '' + ConfigDict['subreg'] = [] + IsDefSect = False + IsUpdSect = True + IsVpdSect = False + Found = True + else: + IsDefSect = False + IsUpdSect = False + IsVpdSect = False + else: + if IsDefSect or IsUpdSect or IsVpdSect: + if DscLine == "!else": + IfStack[-1] = not IfStack[-1] + elif DscLine == "!endif": + IfStack.pop() + Level = ElifStack.pop() + while Level > 0: + IfStack.pop() + Level = Level - 1 + else: + Result = False + Match = re.match("!(ifdef|ifndef)\s+\$\((\w+)\)", DscLine) + if Match is not None: + if Match.group(2) in self._MacroDict: + if Match.group(1) == 'ifdef': + Result = True + else: + if Match.group(1) == 'ifndef': + Result = True + ElifStack.append(0) + IfStack.append(Result) + else: + Match = re.match("!(if|elseif)\s+\$\\((\w+)\)\s*==\s*(\w+|\$\(\w+\))", DscLine) + if Match is not None: + if Match.group(2) in self._MacroDict: + MacroName = self._MacroDict[Match.group(2)] + else: + MacroName = '' + Value = Match.group(3) + if Value.startswith('$'): + if Value[2:-1] in self._MacroDict: + Value = self._MacroDict[Value[2:-1]] + else: + Value = '' + if MacroName == Value: + Result = True + if Match.group(1) == "if": + ElifStack.append(0) + IfStack.append(Result) + else: #elseif + IfStack[-1] = not IfStack[-1] + IfStack.append(Result) + ElifStack[-1] = ElifStack[-1] + 1 + else: + if len(DscLine) > 0 and DscLine[0] == '!': + self.Error = "Invalid DscLine '%s'" % DscLine + Error = 3 + break; + else: + if reduce(lambda x,y: x and y, IfStack): + Handle = True + + if not Handle: + continue + + if IsDefSect: + #DEFINE UPD_TOOL_GUID = 8C3D856A-9BE6-468E-850A-24F7A8D38E09 + Match = re.match("^\s*(?:DEFINE\s+)*(\w+)\s*=\s*([-\w]+)", DscLine) + if Match: + self._MacroDict[Match.group(1)] = Match.group(2) + else: + Match = re.match("^\s*#\s+!(BSF|HDR)\s+(.+)", DscLine) + if Match: + Remaining = Match.group(2) + if Match.group(1) == 'BSF': + Match = re.match("(?:^|.+\s+)PAGES:{(.+?)}", Remaining) + if Match: + # !BSF PAGES:{HSW:"Haswell System Agent", LPT:"Lynx Point PCH"} + PageList = Match.group(1).split(',') + for Page in PageList: + Page = Page.strip() + Match = re.match("(\w+):\"(.+)\"", Page) + self._CfgPageDict[Match.group(1)] = Match.group(2) + + Match = re.match("(?:^|.+\s+)BLOCK:{NAME:\"(.+)\"\s*,\s*VER:\"(.+)\"\s*}", Remaining) + if Match: + self._CfgBlkDict['name'] = Match.group(1) + self._CfgBlkDict['ver'] = Match.group(2) + + for Key in self._BsfKeyList: + Match = re.match("(?:^|.+\s+)%s:{(.+?)}" % Key, Remaining) + if Match: + if Key in ['HELP', 'OPTION'] and Match.group(1).startswith('+'): + ConfigDict[Key.lower()] += Match.group(1)[1:] + else: + ConfigDict[Key.lower()] = Match.group(1) + else: + for Key in self._HdrKeyList: + Match = re.match("(?:^|.+\s+)%s:{(.+?)}" % Key, Remaining) + if Match: + ConfigDict[Key.lower()] = Match.group(1) + + # Check VPD/UPD + if IsUpdSect: + Match = re.match("^([_a-zA-Z0-9]+).([_a-zA-Z0-9]+)\s*\|\s*(0x[0-9A-F]{4})\s*\|\s*(\d+|0x[0-9a-fA-F]+)\s*\|\s*(.+)",DscLine) + else: + Match = re.match("^([_a-zA-Z0-9]+).([_a-zA-Z0-9]+)\s*\|\s*(0x[0-9A-F]+)(?:\s*\|\s*(.+))?", DscLine) + if Match: + ConfigDict['space'] = Match.group(1) + ConfigDict['cname'] = Match.group(2) + ConfigDict['offset'] = int (Match.group(3), 16) + if ConfigDict['order'] == -1: + ConfigDict['order'] = ConfigDict['offset'] << 8 + else: + (Major, Minor) = ConfigDict['order'].split('.') + ConfigDict['order'] = (int (Major, 16) << 8 ) + int (Minor, 16) + if IsUpdSect: + Value = Match.group(5).strip() + if Match.group(4).startswith("0x"): + Length = int (Match.group(4), 16) + else : + Length = int (Match.group(4)) + else: + Value = Match.group(4) + if Value is None: + Value = '' + Value = Value.strip() + if '|' in Value: + Match = re.match("^.+\s*\|\s*(.+)", Value) + if Match: + Value = Match.group(1) + Length = -1 + + ConfigDict['length'] = Length + Match = re.match("\$\((\w+)\)", Value) + if Match: + if Match.group(1) in self._MacroDict: + Value = self._MacroDict[Match.group(1)] + ConfigDict['value'] = Value + if ConfigDict['name'] == '': + # Clear BSF specific items + ConfigDict['help'] = '' + ConfigDict['type'] = '' + ConfigDict['option'] = '' + + self._CfgItemList.append(ConfigDict.copy()) + ConfigDict['name'] = '' + ConfigDict['find'] = '' + ConfigDict['struct'] = '' + ConfigDict['order'] = -1 + ConfigDict['subreg'] = [] + else: + # It could be a virtual item as below + # !BSF FIELD:{1:SerialDebugPortAddress0} + Match = re.match("^\s*#\s+!BSF\s+FIELD:{(.+):(\d+)}", DscLine) + if Match: + SubCfgDict = ConfigDict + SubCfgDict['cname'] = Match.group(1) + SubCfgDict['length'] = int (Match.group(2)) + if SubCfgDict['length'] > 0: + LastItem = self._CfgItemList[-1] + if len(LastItem['subreg']) == 0: + SubOffset = 0 + else: + SubOffset += LastItem['subreg'][-1]['length'] + SubCfgDict['offset'] = SubOffset + LastItem['subreg'].append (SubCfgDict.copy()) + ConfigDict['name'] = '' + return Error + + def UpdateSubRegionDefaultValue (self): + Error = 0 + for Item in self._CfgItemList: + if len(Item['subreg']) == 0: + continue + bytearray = [] + if Item['value'][0] == '{': + binlist = Item['value'][1:-1].split(',') + for each in binlist: + each = each.strip() + if each.startswith('0x'): + value = int(each, 16) + else: + value = int(each) + bytearray.append(value) + else: + if Item['value'].startswith('0x'): + value = int(Item['value'], 16) + else: + value = int(Item['value']) + idx = 0; + while idx < Item['length']: + bytearray.append(value & 0xFF) + value = value >> 8 + idx = idx + 1 + for SubItem in Item['subreg']: + if SubItem['length'] in (1,2,4,8): + valuelist = [b for b in bytearray[SubItem['offset']:SubItem['offset']+SubItem['length']]] + valuelist.reverse() + valuestr = "".join('%02X' % b for b in valuelist) + SubItem['value'] = '0x%s' % valuestr + else: + valuestr = ",".join('0x%02X' % b for b in bytearray[SubItem['offset']:SubItem['offset']+SubItem['length']]) + SubItem['value'] = '{%s}' % valuestr + return Error + + def UpdateVpdSizeField (self): + FvDir = self._FvDir; + + if 'VPD_TOOL_GUID' not in self._MacroDict: + self.Error = "VPD_TOOL_GUID definition is missing in DSC file" + return 1 + + VpdMapFile = os.path.join(FvDir, self._MacroDict['VPD_TOOL_GUID'] + '.map') + if not os.path.exists(VpdMapFile): + self.Error = "VPD MAP file '%s' does not exist" % VpdMapFile + return 2 + + MapFd = open(VpdMapFile, "r") + MapLines = MapFd.readlines() + MapFd.close() + + VpdDict = {} + PcdDict = {} + for MapLine in MapLines: + #gPlatformFspPkgTokenSpaceGuid.PcdVpdRegionSign | DEFAULT | 0x0000 | 8 | 0x534450565F425346 + #gPlatformFspPkgTokenSpaceGuid.PcdVpdRegionSign | 0x0000 | 8 | 0x534450565F425346 + #gPlatformFspPkgTokenSpaceGuid.PcdTest | 0x0008 | 5 | {0x01,0x02,0x03,0x04,0x05} + Match = re.match("([_a-zA-Z0-9]+).([_a-zA-Z0-9]+)(\s\|\sDEFAULT)?\s\|\s(0x[0-9A-F]{4})\s\|\s(\d+|0x[0-9a-fA-F]+)\s\|\s(\{?[x0-9a-fA-F,\s]+\}?)", MapLine) + if Match: + Space = Match.group(1) + Name = Match.group(2) + if (self._MapVer == 0) and (Match.group(3) != None): + self._MapVer = 1 + Offset = int (Match.group(4), 16) + if Match.group(5).startswith("0x"): + Length = int (Match.group(5), 16) + else : + Length = int (Match.group(5)) + PcdDict["len"] = Length + PcdDict["value"] = Match.group(6) + VpdDict[Space+'.'+Name] = dict(PcdDict) + + for Item in self._CfgItemList: + if Item['value'] == '': + Item['value'] = VpdDict[Item['space']+'.'+Item['cname']]['value'] + if Item['length'] == -1: + Item['length'] = VpdDict[Item['space']+'.'+Item['cname']]['len'] + if Item['struct'] != '': + Type = Item['struct'].strip() + if Type.endswith('*') and (Item['length'] != 4): + self.Error = "Struct pointer '%s' has invalid size" % Type + return 3 + + return 0 + + def CreateUpdTxtFile (self, UpdTxtFile): + FvDir = self._FvDir + if 'UPD_TOOL_GUID' not in self._MacroDict: + self.Error = "UPD_TOOL_GUID definition is missing in DSC file" + return 1 + + if UpdTxtFile == '': + UpdTxtFile = os.path.join(FvDir, self._MacroDict['UPD_TOOL_GUID'] + '.txt') + + ReCreate = False + if not os.path.exists(UpdTxtFile): + ReCreate = True + else: + DscTime = os.path.getmtime(self._DscFile) + TxtTime = os.path.getmtime(UpdTxtFile) + if DscTime > TxtTime: + ReCreate = True + + if not ReCreate: + # DSC has not been modified yet + # So don't have to re-generate other files + self.Error = 'No DSC file change, skip to create UPD TXT file' + return 256 + + TxtFd = open(UpdTxtFile, "w") + TxtFd.write("%s\n" % (__copyright_txt__ % date.today().year)) + + NextOffset = 0 + SpaceIdx = 0 + if self._MapVer == 1: + Default = 'DEFAULT|' + else: + Default = '' + for Item in self._CfgItemList: + if Item['region'] != 'UPD': + continue + Offset = Item['offset'] + if NextOffset < Offset: + # insert one line + TxtFd.write("%s.UnusedUpdSpace%d|%s0x%04X|0x%04X|{0}\n" % (Item['space'], SpaceIdx, Default, NextOffset, Offset - NextOffset)) + SpaceIdx = SpaceIdx + 1 + NextOffset = Offset + Item['length'] + TxtFd.write("%s.%s|%s0x%04X|%s|%s\n" % (Item['space'],Item['cname'],Default,Item['offset'],Item['length'],Item['value'])) + TxtFd.close() + return 0 + + def CreateField (self, Name, Length, Offset, Struct): + PosName = 28 + PosComment = 30 + + IsArray = False + if Length == 1: + Type = "UINT8" + elif Length == 2: + Type = "UINT16" + elif Length == 4: + Type = "UINT32" + elif Length == 8: + Type = "UINT64" + else: + Type = "UINT8" + IsArray = True + + if Struct != '': + IsArray = False + Type = Struct + + if IsArray: + Name = Name + '[%d]' % Length + + if len(Type) < PosName: + Space1 = PosName - len(Type) + else: + Space1 = 1 + + if len(Name) < PosComment: + Space2 = PosComment - len(Name) + else: + Space2 = 1 + + return " %s%s%s;%s/* Offset 0x%04X */\n" % (Type, ' ' * Space1, Name, ' ' * Space2, Offset) + + + def CreateHeaderFile (self, InputHeaderFile, IsInternal): + Error = 0 + FvDir = self._FvDir + + if IsInternal: + HeaderFile = os.path.join(FvDir, 'VpdHeader.h') + else: + HeaderFile = os.path.join(FvDir, 'fsp_vpd.h') + + # Check if header needs to be recreated + ReCreate = False + if IsInternal: + if not os.path.exists(HeaderFile): + ReCreate = True + else: + DscTime = os.path.getmtime(self._DscFile) + HeadTime = os.path.getmtime(HeaderFile) + if not os.path.exists(InputHeaderFile): + InpTime = HeadTime + else: + InpTime = os.path.getmtime(InputHeaderFile) + if DscTime > HeadTime or InpTime > HeadTime: + ReCreate = True + + if not ReCreate: + self.Error = "No DSC or input header file is changed, skip the header file generating" + return 256 + + HeaderFd = open(HeaderFile, "w") + FileBase = os.path.basename(HeaderFile) + FileName = FileBase.replace(".", "_").upper() + HeaderFd.write("%s\n" % (__copyright_h__ % date.today().year)) + HeaderFd.write("#ifndef __%s__\n" % FileName) + HeaderFd.write("#define __%s__\n\n" % FileName) + HeaderFd.write("#pragma pack(1)\n\n") + + if InputHeaderFile != '': + if not os.path.exists(InputHeaderFile): + self.Error = "Input header file '%s' does not exist" % InputHeaderFile + return 2 + + InFd = open(InputHeaderFile, "r") + IncLines = InFd.readlines() + InFd.close() + + Export = False + for Line in IncLines: + Match = re.search ("!EXPORT\s+EXTERNAL_BOOTLOADER_STRUCT_(BEGIN|END)\s+", Line) + if Match: + if Match.group(1) == "BEGIN": + Export = True + continue + else: + Export = False + continue + if Export: + HeaderFd.write(Line) + HeaderFd.write("\n\n") + + for Region in ['UPD', 'VPD']: + + # Write PcdVpdRegionSign and PcdImageRevision + if Region[0] == 'V': + if 'VPD_TOOL_GUID' not in self._MacroDict: + self.Error = "VPD_TOOL_GUID definition is missing in DSC file" + Error = 1 + break + + BinFile = os.path.join(FvDir, self._MacroDict['VPD_TOOL_GUID'] + ".bin") + if not os.path.exists(BinFile): + self.Error = "VPD binary file '%s' does not exist" % BinFile + Error = 2 + break + + BinFd = open(BinFile, "rb") + IdStr = BinFd.read(0x08) + ImageId = struct.unpack('Q', IdStr) + ImageRev = struct.unpack('L', BinFd.read(0x04)) + BinFd.close() + + HeaderFd.write("#define VPD_IMAGE_ID 0x%016X /* '%s' */\n" % (ImageId[0], IdStr)) + HeaderFd.write("#define VPD_IMAGE_REV 0x%08X \n\n" % ImageRev[0]) + + HeaderFd.write("typedef struct _" + Region[0] + "PD_DATA_REGION {\n") + NextOffset = 0 + SpaceIdx = 0 + Offset = 0 + + LastVisible = True + ResvOffset = 0 + ResvIdx = 0 + LineBuffer = [] + for Item in self._CfgItemList: + if Item['region'] != Region: + continue + + NextVisible = LastVisible + if not IsInternal: + if LastVisible and (Item['header'] == 'OFF'): + NextVisible = False + ResvOffset = Item['offset'] + elif (not LastVisible) and Item['header'] == 'ON': + NextVisible = True + Name = "Reserved" + Region[0] + "pdSpace%d" % ResvIdx + ResvIdx = ResvIdx + 1 + HeaderFd.write(self.CreateField (Name, Item["offset"] - ResvOffset, ResvOffset, '')) + + if Offset < Item["offset"]: + if IsInternal or LastVisible: + Name = "Unused" + Region[0] + "pdSpace%d" % SpaceIdx + LineBuffer.append(self.CreateField (Name, Item["offset"] - Offset, Offset, '')) + SpaceIdx = SpaceIdx + 1 + Offset = Item["offset"] + + if Offset != Item["offset"]: + print "Unsorted offset 0x%04X\n" % Item["offset"] + error = 2 + break; + + LastVisible = NextVisible + + Offset = Offset + Item["length"] + if IsInternal or LastVisible: + for Each in LineBuffer: + HeaderFd.write (Each) + LineBuffer = [] + HeaderFd.write(self.CreateField (Item["cname"], Item["length"], Item["offset"], Item['struct'])) + + HeaderFd.write("} " + Region[0] + "PD_DATA_REGION;\n\n") + HeaderFd.write("#pragma pack()\n\n") + HeaderFd.write("#endif\n") + HeaderFd.close() + + return Error + + def WriteBsfStruct (self, BsfFd, Item): + if Item['type'] == "None": + Space = "gPlatformFspPkgTokenSpaceGuid" + else: + Space = Item['space'] + Line = " $%s_%s" % (Space, Item['cname']) + Match = re.match("\s*\{([x0-9a-fA-F,\s]+)\}\s*", Item['value']) + if Match: + DefaultValue = Match.group(1).strip() + else: + DefaultValue = Item['value'].strip() + BsfFd.write(" %s%s%4d bytes $_DEFAULT_ = %s\n" % (Line, ' ' * (64 - len(Line)), Item['length'], DefaultValue)) + TmpList = [] + if Item['type'] == "Combo": + if not Item['option'] in self._BuidinOption: + OptList = Item['option'].split(',') + for Option in OptList: + Option = Option.strip() + (OpVal, OpStr) = Option.split(':') + TmpList.append((OpVal, OpStr)) + return TmpList + + def WriteBsfOption (self, BsfFd, Item): + PcdName = Item['space'] + '_' + Item['cname'] + WriteHelp = 0 + if Item['type'] == "Combo": + if Item['option'] in self._BuidinOption: + Options = self._BuidinOption[Item['option']] + else: + Options = PcdName + BsfFd.write(' %s $%s, "%s", &%s,\n' % (Item['type'], PcdName, Item['name'], Options)); + WriteHelp = 1 + elif Item['type'].startswith("EditNum"): + Match = re.match("EditNum\s*,\s*(HEX|DEC)\s*,\s*\((\d+|0x[0-9A-Fa-f]+)\s*,\s*(\d+|0x[0-9A-Fa-f]+)\)", Item['type']) + if Match: + BsfFd.write(' EditNum $%s, "%s", %s,\n' % (PcdName, Item['name'], Match.group(1))); + WriteHelp = 2 + elif Item['type'].startswith("EditText"): + BsfFd.write(' %s $%s, "%s",\n' % (Item['type'], PcdName, Item['name'])); + WriteHelp = 1 + + if WriteHelp > 0: + HelpLines = Item['help'].split('\\n\\r') + FirstLine = True + for HelpLine in HelpLines: + if FirstLine: + FirstLine = False + BsfFd.write(' Help "%s"\n' % (HelpLine)); + else: + BsfFd.write(' "%s"\n' % (HelpLine)); + if WriteHelp == 2: + BsfFd.write(' "Valid range: %s ~ %s"\n' % (Match.group(2), Match.group(3))); + + def GenerateBsfFile (self, BsfFile): + + if BsfFile == '': + self.Error = "BSF output file '%s' is invalid" % BsfFile + return 1 + + Error = 0 + OptionDict = {} + BsfFd = open(BsfFile, "w") + BsfFd.write("%s\n" % (__copyright_bsf__ % date.today().year)) + BsfFd.write("%s\n" % self._GlobalDataDef); + BsfFd.write("StructDef\n") + NextOffset = -1 + for Item in self._CfgItemList: + if Item['find'] != '': + BsfFd.write('\n Find "%s"\n' % Item['find']) + NextOffset = Item['offset'] + Item['length'] + if Item['name'] != '': + if NextOffset != Item['offset']: + BsfFd.write(" Skip %d bytes\n" % (Item['offset'] - NextOffset)) + if len(Item['subreg']) > 0: + NextOffset = Item['offset'] + for SubItem in Item['subreg']: + NextOffset += SubItem['length'] + if SubItem['name'] == '': + BsfFd.write(" Skip %d bytes\n" % (SubItem['length'])) + else: + Options = self.WriteBsfStruct(BsfFd, SubItem) + if len(Options) > 0: + OptionDict[SubItem['space']+'_'+SubItem['cname']] = Options + if (Item['offset'] + Item['length']) < NextOffset: + self.Error = "BSF sub region '%s' length does not match" % (Item['space']+'.'+Item['cname']) + return 2 + else: + NextOffset = Item['offset'] + Item['length'] + Options = self.WriteBsfStruct(BsfFd, Item) + if len(Options) > 0: + OptionDict[Item['space']+'_'+Item['cname']] = Options + BsfFd.write("\nEndStruct\n\n") + + BsfFd.write("%s" % self._BuidinOptionTxt); + + for Each in OptionDict: + BsfFd.write("List &%s\n" % Each); + for Item in OptionDict[Each]: + BsfFd.write(' Selection %s , "%s"\n' % (Item[0], Item[1])); + BsfFd.write("EndList\n\n"); + + BsfFd.write("BeginInfoBlock\n"); + BsfFd.write(' PPVer "%s"\n' % (self._CfgBlkDict['ver'])); + BsfFd.write(' Description "%s"\n' % (self._CfgBlkDict['name'])); + BsfFd.write("EndInfoBlock\n\n"); + + for Each in self._CfgPageDict: + BsfFd.write('Page "%s"\n' % self._CfgPageDict[Each]); + BsfItems = [] + for Item in self._CfgItemList: + if Item['name'] != '': + if Item['page'] != Each: + continue + if len(Item['subreg']) > 0: + for SubItem in Item['subreg']: + if SubItem['name'] != '': + BsfItems.append(SubItem) + else: + BsfItems.append(Item) + + BsfItems.sort(key=lambda x: x['order']) + + for Item in BsfItems: + self.WriteBsfOption (BsfFd, Item) + BsfFd.write("EndPage\n\n"); + + BsfFd.close() + return Error + + +def Usage(): + print "GenCfgOpt Version 0.50" + print "Usage:" + print " GenCfgOpt UPDTXT PlatformDscFile BuildFvDir [TxtOutFile] [-D Macros]" + print " GenCfgOpt HEADER PlatformDscFile BuildFvDir [InputHFile] [-D Macros]" + print " GenCfgOpt GENBSF PlatformDscFile BuildFvDir BsfOutFile [-D Macros]" + +def Main(): + # + # Parse the options and args + # + GenCfgOpt = CGenCfgOpt() + argc = len(sys.argv) + if argc < 4: + Usage() + return 1 + else: + DscFile = sys.argv[2] + if not os.path.exists(DscFile): + print "ERROR: Cannot open DSC file '%s' !" % DscFile + return 2 + + OutFile = '' + if argc > 4: + if sys.argv[4][0] == '-': + Start = 4 + else: + OutFile = sys.argv[4] + Start = 5 + if GenCfgOpt.ParseMacros(sys.argv[Start:]) != 0: + print "ERROR: %s !" % GenCfgOpt.Error + return 3 + + FvDir = sys.argv[3] + if not os.path.isdir(FvDir): + print "ERROR: FV folder '%s' is invalid !" % FvDir + return 4 + + if GenCfgOpt.ParseDscFile(DscFile, FvDir) != 0: + print "ERROR: %s !" % GenCfgOpt.Error + return 5 + + + if GenCfgOpt.UpdateVpdSizeField() != 0: + print "ERROR: %s !" % GenCfgOpt.Error + return 6 + + if GenCfgOpt.UpdateSubRegionDefaultValue() != 0: + print "ERROR: %s !" % GenCfgOpt.Error + return 7 + + if sys.argv[1] == "UPDTXT": + Ret = GenCfgOpt.CreateUpdTxtFile(OutFile) + if Ret != 0: + # No change is detected + if Ret == 256: + print "INFO: %s !" % (GenCfgOpt.Error) + else : + print "ERROR: %s !" % (GenCfgOpt.Error) + return Ret + elif sys.argv[1] == "HEADER": + Ret = GenCfgOpt.CreateHeaderFile(OutFile, True) + if Ret != 0: + # No change is detected + if Ret == 256: + print "INFO: %s !" % (GenCfgOpt.Error) + else : + print "ERROR: %s !" % (GenCfgOpt.Error) + return Ret + if GenCfgOpt.CreateHeaderFile(OutFile, False) != 0: + print "ERROR: %s !" % GenCfgOpt.Error + return 8 + elif sys.argv[1] == "GENBSF": + if GenCfgOpt.GenerateBsfFile(OutFile) != 0: + print "ERROR: %s !" % GenCfgOpt.Error + return 9 + else: + if argc < 5: + Usage() + return 1 + print "ERROR: Unknown command '%s' !" % sys.argv[1] + Usage() + return 1 + return 0 + return 0 + + +if __name__ == '__main__': + sys.exit(Main()) diff --git a/IntelFspPkg/Tools/PatchFv.py b/IntelFspPkg/Tools/PatchFv.py new file mode 100644 index 0000000000..cc22cc201e --- /dev/null +++ b/IntelFspPkg/Tools/PatchFv.py @@ -0,0 +1,567 @@ +## @ PatchFv.py +# +# Copyright (c) 2014, Intel Corporation. All rights reserved.
+# This program and the accompanying materials are licensed and made available under +# the terms and conditions of the BSD License that accompanies this distribution. +# The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +import os +import re +import sys + +def readDataFromFile (binfile, offset, len=1): + fd = open(binfile, "r+b") + fsize = os.path.getsize(binfile) + offval = offset & 0xFFFFFFFF + if (offval & 0x80000000): + offval = fsize - (0xFFFFFFFF - offval + 1) + fd.seek(offval) + bytearray = [ord(b) for b in fd.read(len)] + value = 0; + idx = len - 1; + while idx >= 0: + value = value << 8 | bytearray[idx] + idx = idx - 1 + fd.close() + return value + +def patchDataInFile (binfile, offset, value, len=1): + fd = open(binfile, "r+b") + fsize = os.path.getsize(binfile) + offval = offset & 0xFFFFFFFF + if (offval & 0x80000000): + offval = fsize - (0xFFFFFFFF - offval + 1) + bytearray = [] + idx = 0; + while idx < len: + bytearray.append(value & 0xFF) + value = value >> 8 + idx = idx + 1 + fd.seek(offval) + fd.write("".join(chr(b) for b in bytearray)) + fd.close() + return len; + + +class Symbols: + def __init__(self): + self.dictSymbolAddress = {} + self.dictGuidNameXref = {} + self.dictFfsOffset = {} + self.dictVariable = {} + self.dictModBase = {} + self.fdFile = None + self.string = "" + self.fdBase = 0xFFFFFFFF + self.fdSize = 0 + self.index = 0 + self.parenthesisOpenSet = '([{<' + self.parenthesisCloseSet = ')]}>' + + def getFdFile (self): + return self.fdFile + + def getFdSize (self): + return self.fdSize + + def createDicts (self, fvDir, fvNames): + if not os.path.isdir(fvDir): + raise Exception ("'%s' is not a valid directory!" % FvDir) + + xrefFile = os.path.join(fvDir, "Guid.xref") + if not os.path.exists(xrefFile): + raise Exception("Cannot open GUID Xref file '%s'!" % xrefFile) + + self.dictGuidNameXref = {} + self.parseGuidXrefFile(xrefFile) + + fvList = fvNames.split(":") + fdBase = fvList.pop() + if len(fvList) == 0: + fvList.append(fdBase) + + fdFile = os.path.join(fvDir, fdBase.strip() + ".fd") + if not os.path.exists(fdFile): + raise Exception("Cannot open FD file '%s'!" % fdFile) + + self.fdFile = fdFile + self.fdSize = os.path.getsize(fdFile) + + infFile = os.path.join(fvDir, fvList[0].strip()) + ".inf" + if not os.path.exists(infFile): + raise Exception("Cannot open INF file '%s'!" % infFile) + + self.parseInfFile(infFile) + + self.dictVariable = {} + self.dictVariable["FDSIZE"] = self.fdSize + self.dictVariable["FDBASE"] = self.fdBase + + self.dictSymbolAddress = {} + self.dictFfsOffset = {} + for file in fvList: + + fvFile = os.path.join(fvDir, file.strip()) + ".Fv" + mapFile = fvFile + ".map" + if not os.path.exists(mapFile): + raise Exception("Cannot open MAP file '%s'!" % mapFile) + + self.parseFvMapFile(mapFile) + + fvTxtFile = fvFile + ".txt" + if not os.path.exists(fvTxtFile): + raise Exception("Cannot open FV TXT file '%s'!" % fvTxtFile) + + self.parseFvTxtFile(fvTxtFile) + + ffsDir = os.path.join(fvDir, "Ffs") + if (os.path.isdir(ffsDir)): + for item in os.listdir(ffsDir): + if len(item) <= 0x24: + continue + mapFile =os.path.join(ffsDir, item, "%s.map" % item[0:0x24]) + if not os.path.exists(mapFile): + continue + self.parseModMapFile(item[0x24:], mapFile) + + return 0 + + def getFvOffsetInFd(self, fvFile): + fvHandle = open(fvFile, "r+b") + fdHandle = open(self.fdFile, "r+b") + offset = fdHandle.read().find(fvHandle.read(0x70)) + fvHandle.close() + fdHandle.close() + if offset == -1: + raise Exception("Could not locate FV file %s in FD!" % fvFile) + return offset + + def parseInfFile(self, infFile): + fvOffset = self.getFvOffsetInFd(infFile[0:-4] + ".Fv") + fdIn = open(infFile, "r") + rptLine = fdIn.readline() + self.fdBase = 0xFFFFFFFF + while (rptLine != "" ): + #EFI_BASE_ADDRESS = 0xFFFDF400 + match = re.match("^EFI_BASE_ADDRESS\s*=\s*(0x[a-fA-F0-9]+)", rptLine) + if match is not None: + self.fdBase = int(match.group(1), 16) - fvOffset + rptLine = fdIn.readline() + fdIn.close() + if self.fdBase == 0xFFFFFFFF: + raise Exception("Could not find EFI_BASE_ADDRESS in INF file!" % fvFile) + return 0 + + def parseFvTxtFile(self, fvTxtFile): + fvOffset = self.getFvOffsetInFd(fvTxtFile[0:-4]) + fdIn = open(fvTxtFile, "r") + rptLine = fdIn.readline() + while (rptLine != "" ): + match = re.match("(0x[a-fA-F0-9]+)\s([0-9a-fA-F\-]+)", rptLine) + if match is not None: + self.dictFfsOffset[match.group(2)] = "0x%08X" % (int(match.group(1), 16) + fvOffset) + rptLine = fdIn.readline() + fdIn.close() + return 0 + + def parseFvMapFile(self, mapFile): + fdIn = open(mapFile, "r") + rptLine = fdIn.readline() + modName = "" + while (rptLine != "" ): + if rptLine[0] != ' ': + #DxeIpl (Fixed Flash Address, BaseAddress=0x00fffb4310, EntryPoint=0x00fffb4958) + #(GUID=86D70125-BAA3-4296-A62F-602BEBBB9081 .textbaseaddress=0x00fffb4398 .databaseaddress=0x00fffb4178) + match = re.match("([_a-zA-Z0-9\-]+)\s\(.+BaseAddress=(0x[0-9a-fA-F]+),\s+EntryPoint=(0x[0-9a-fA-F]+)\)", rptLine) + if match is not None: + modName = match.group(1) + if len(modName) == 36: + modName = self.dictGuidNameXref[modName.upper()] + self.dictModBase['%s:BASE' % modName] = int (match.group(2), 16) + self.dictModBase['%s:ENTRY' % modName] = int (match.group(3), 16) + match = re.match("\(GUID=([A-Z0-9\-]+)\s+\.textbaseaddress=(0x[0-9a-fA-F]+)\s+\.databaseaddress=(0x[0-9a-fA-F]+)\)", rptLine) + if match is not None: + modName = match.group(1) + if len(modName) == 36: + modName = self.dictGuidNameXref[modName.upper()] + self.dictModBase['%s:TEXT' % modName] = int (match.group(2), 16) + self.dictModBase['%s:DATA' % modName] = int (match.group(3), 16) + else: + # 0x00fff8016c __ModuleEntryPoint + match = re.match("^\s+(0x[a-z0-9]+)\s+([_a-zA-Z0-9]+)", rptLine) + if match is not None: + self.dictSymbolAddress["%s:%s"%(modName, match.group(2))] = match.group(1) + rptLine = fdIn.readline() + fdIn.close() + return 0 + + def parseModMapFile(self, moduleName, mapFile): + modSymbols = {} + fdIn = open(mapFile, "r") + reportLine = fdIn.readline() + if reportLine.strip().find("Archive member included because of file (symbol)") != -1: + #GCC + # 0x0000000000001d55 IoRead8 + patchMapFileMatchString = "\s+(0x[0-9a-fA-F]{16})\s+([^\s][^0x][_a-zA-Z0-9\-]+)\s" + matchKeyGroupIndex = 2 + matchSymbolGroupIndex = 1 + moduleEntryPoint = "_ModuleEntryPoint" + else: + #MSFT + #0003:00000190 _gComBase 00007a50 SerialPo + patchMapFileMatchString = "^\s[0-9a-fA-F]{4}:[0-9a-fA-F]{8}\s+(\w+)\s+([0-9a-fA-F]{8}\s+)" + matchKeyGroupIndex = 1 + matchSymbolGroupIndex = 2 + moduleEntryPoint = "__ModuleEntryPoint" + while (reportLine != "" ): + match = re.match(patchMapFileMatchString, reportLine) + if match is not None: + modSymbols[match.group(matchKeyGroupIndex)] = match.group(matchSymbolGroupIndex) + reportLine = fdIn.readline() + fdIn.close() + + if not moduleEntryPoint in modSymbols: + return 1 + + modEntry = '%s:%s' % (moduleName,moduleEntryPoint) + if not modEntry in self.dictSymbolAddress: + modKey = '%s:ENTRY' % moduleName + if modKey in self.dictModBase: + baseOffset = self.dictModBase['%s:ENTRY' % moduleName] - int(modSymbols[moduleEntryPoint], 16) + else: + return 2 + else: + baseOffset = int(self.dictSymbolAddress[modEntry], 16) - int(modSymbols[moduleEntryPoint], 16) + for symbol in modSymbols: + fullSym = "%s:%s" % (moduleName, symbol) + if not fullSym in self.dictSymbolAddress: + self.dictSymbolAddress[fullSym] = "0x00%08x" % (baseOffset+ int(modSymbols[symbol], 16)) + return 0 + + def parseGuidXrefFile(self, xrefFile): + fdIn = open(xrefFile, "r") + rptLine = fdIn.readline() + while (rptLine != "" ): + match = re.match("([0-9a-fA-F\-]+)\s([_a-zA-Z0-9]+)", rptLine) + if match is not None: + self.dictGuidNameXref[match.group(1).upper()] = match.group(2) + rptLine = fdIn.readline() + fdIn.close() + return 0 + + def getCurr(self): + try: + return self.string[self.index] + except Exception: + return '' + + def isLast(self): + return self.index == len(self.string) + + def moveNext(self): + self.index += 1 + + def skipSpace(self): + while not self.isLast(): + if self.getCurr() in ' \t': + self.moveNext() + else: + return + + def parseValue(self): + self.skipSpace() + var = '' + while not self.isLast(): + char = self.getCurr() + if char.lower() in '_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789:-': + var += char + self.moveNext() + else: + break + + if ':' in var: + partList = var.split(':') + if len(partList) != 2: + raise Exception("Unrecognized expression %s" % var) + modName = partList[0] + modOff = partList[1] + if ('-' not in modName) and (modOff[0] in '0123456789'): + # MOD: OFFSET + var = self.getModGuid(modName) + ":" + modOff + if '-' in var: # GUID:OFFSET + value = self.getGuidOff(var) + else: + value = self.getSymbols(var) + self.synUsed = True + else: + if var[0] in '0123456789': + value = self.getNumber(var) + else: + value = self.getVariable(var) + return int(value) + + def parseSingleOp(self): + self.skipSpace() + char = self.getCurr() + if char == '~': + self.moveNext() + return ~self.parseBrace() + else: + return self.parseValue() + + def parseBrace(self): + self.skipSpace() + char = self.getCurr() + parenthesisType = self.parenthesisOpenSet.find(char) + if parenthesisType >= 0: + self.moveNext() + value = self.parseExpr() + self.skipSpace() + if self.getCurr() != self.parenthesisCloseSet[parenthesisType]: + raise Exception("No closing brace") + self.moveNext() + if parenthesisType == 1: # [ : Get content + value = self.getContent(value) + elif parenthesisType == 2: # { : To address + value = self.toAddress(value) + elif parenthesisType == 3: # < : To offset + value = self.toOffset(value) + return value + else: + return self.parseSingleOp() + + def parseMul(self): + values = [self.parseBrace()] + while True: + self.skipSpace() + char = self.getCurr() + if char == '*': + self.moveNext() + values.append(self.parseBrace()) + else: + break + value = 1; + for each in values: + value *= each + return value + + def parseAndOr(self): + values = [self.parseMul()] + op = None + value = 0xFFFFFFFF; + while True: + self.skipSpace() + char = self.getCurr() + if char == '&': + self.moveNext() + values.append(self.parseMul()) + op = char + elif char == '|': + div_index = self.index + self.moveNext() + values.append(self.parseMul()) + value = 0 + op = char + else: + break + + for each in values: + if op == '|': + value |= each + else: + value &= each + + return value + + def parseAddMinus(self): + values = [self.parseAndOr()] + while True: + self.skipSpace() + char = self.getCurr() + if char == '+': + self.moveNext() + values.append(self.parseAndOr()) + elif char == '-': + self.moveNext() + values.append(-1 * self.parseAndOr()) + else: + break + return sum(values) + + def parseExpr(self): + return self.parseAddMinus() + + def getResult(self): + value = self.parseExpr() + self.skipSpace() + if not self.isLast(): + raise Exception("Unexpected character found '%s'" % self.getCurr()) + return value + + def getModGuid(self, var): + guid = (guid for guid,name in self.dictGuidNameXref.items() if name==var) + try: + value = guid.next() + except Exception: + raise Exception("Unknown module name %s !" % var) + return value + + def getVariable(self, var): + value = self.dictVariable.get(var, None) + if value == None: + raise Exception("Unrecognized variable '%s'" % var) + return value + + def getNumber(self, var): + var = var.strip() + if var.startswith('0x'): # HEX + value = int(var, 16) + else: + value = int(var, 10) + return value + + def getContent(self, value): + if (value >= self.fdBase) and (value < self.fdBase + self.fdSize): + value = value - self.fdBase + if value >= self.fdSize: + raise Exception("Invalid file offset 0x%08x !" % value) + return readDataFromFile (self.fdFile, value, 4) + + def toAddress(self, value): + if value < self.fdSize: + value = value + self.fdBase + return value + + def toOffset(self, value): + if value > self.fdBase: + value = value - self.fdBase + return value + + def getGuidOff(self, value): + # GUID:Offset + symbolName = value.split(':') + if len(symbolName) == 2 and self.dictFfsOffset.has_key(symbolName[0]): + value = (int(self.dictFfsOffset[symbolName[0]], 16) + int(symbolName[1], 16)) & 0xFFFFFFFF + else: + raise Exception("Unknown GUID %s !" % value) + return value + + def getSymbols(self, value): + if self.dictSymbolAddress.has_key(value): + # Module:Function + ret = int (self.dictSymbolAddress[value], 16) + else: + raise Exception("Unknown symbol %s !" % value) + return ret + + def evaluate(self, expression, isOffset): + self.index = 0 + self.synUsed = False + self.string = expression + value = self.getResult() + if isOffset: + if self.synUsed: + # Consider it as an address first + if (value >= self.fdBase) and (value < self.fdBase + self.fdSize): + value = value - self.fdBase + if value & 0x80000000: + # Consider it as a negative offset next + offset = (~value & 0xFFFFFFFF) + 1 + if offset < self.fdSize: + value = self.fdSize - offset + if value >= self.fdSize: + raise Exception("Invalid offset expression !") + return value & 0xFFFFFFFF + +def usage(): + print "Usage: \n\tPatchFv FvBuildDir [FvFileBaseNames:]FdFileBaseNameToPatch \"Offset, Value\"" + +def main(): + # + # Parse the options and args + # + symTables = Symbols() + + if len(sys.argv) < 4: + Usage() + return 1 + + if symTables.createDicts(sys.argv[1], sys.argv[2]) != 0: + print "ERROR: Failed to create symbol dictionary!!" + return 2 + + fdFile = symTables.getFdFile() + fdSize = symTables.getFdSize() + + try: + comment = "" + for fvFile in sys.argv[3:]: + items = fvFile.split(",") + if len (items) < 2: + raise Exception("Expect more arguments for '%s'!" % fvFile) + + comment = "" + command = "" + params = [] + for item in items: + item = item.strip() + if item.startswith("@"): + comment = item[1:] + elif item.startswith("$"): + command = item[1:] + else: + if len(params) == 0: + isOffset = True + else : + isOffset = False + params.append (symTables.evaluate(item, isOffset)) + + if command == "": + # Patch a DWORD + if len (params) == 2: + offset = params[0] + value = params[1] + oldvalue = readDataFromFile(fdFile, offset, 4) + ret = patchDataInFile (fdFile, offset, value, 4) - 4 + else: + raise Exception ("Patch command needs 2 parameters !") + + if ret: + raise Exception ("Patch failed for offset 0x%08X" % offset) + else: + print "Patched offset 0x%08X:[%08X] with value 0x%08X # %s" % (offset, oldvalue, value, comment) + + elif command == "COPY": + # Copy binary block from source to destination + if len (params) == 3: + src = symTables.toOffset(params[0]) + dest = symTables.toOffset(params[1]) + clen = symTables.toOffset(params[2]) + if (dest + clen <= fdSize) and (src + clen <= fdSize): + oldvalue = readDataFromFile(fdFile, src, clen) + ret = patchDataInFile (fdFile, dest, oldvalue, clen) - clen + else: + raise Exception ("Copy command OFFSET or LENGTH parameter is invalid !") + else: + raise Exception ("Copy command needs 3 parameters !") + + if ret: + raise Exception ("Copy failed from offset 0x%08X to offset 0x%08X!" % (src, dest)) + else : + print "Copied %d bytes from offset 0x%08X ~ offset 0x%08X # %s" % (clen, src, dest, comment) + else: + raise Exception ("Unknown command %s!" % command) + return 0 + + except Exception as (ex): + print "ERROR: %s" % ex + return 1 + +if __name__ == '__main__': + sys.exit(main()) diff --git a/IntelFspPkg/Tools/UserManuals/GenCfgOptUserManual.docx b/IntelFspPkg/Tools/UserManuals/GenCfgOptUserManual.docx new file mode 100644 index 0000000000000000000000000000000000000000..e4da8e057b763ddce5c4429b4a27bb7bf66f20a2 GIT binary patch literal 22177 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Μ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 literal 0 HcmV?d00001 diff --git a/IntelFspPkg/Tools/UserManuals/PatchFvUserManual.docx b/IntelFspPkg/Tools/UserManuals/PatchFvUserManual.docx new file mode 100644 index 0000000000000000000000000000000000000000..ab1eda993e7b7d249a0390dc1db83ff4987395da GIT binary patch literal 21481 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 literal 0 HcmV?d00001 -- 2.39.2