* [edk2-devel] [RESEND 0/7] AmdPlatformPkg: Adds board independent modules @ 2024-05-15 3:50 Abdul Lateef Attar via groups.io 2024-05-15 3:50 ` [edk2-devel] [RESEND 1/7] AmdPlatformPkg: Adds LogoDxe driver Abdul Lateef Attar via groups.io ` (7 more replies) 0 siblings, 8 replies; 9+ messages in thread From: Abdul Lateef Attar via groups.io @ 2024-05-15 3:50 UTC (permalink / raw) To: devel; +Cc: Abdul Lateef Attar, Abner Chang, Paul Grimes PR: https://github.com/tianocore/edk2-platforms/pull/141 Adds various libraries and drivers for AMD Platform. Cc: Abner Chang <abner.chang@amd.com> Cc: Paul Grimes <paul.grimes@amd.com> Abdul Lateef Attar (7): AmdPlatformPkg: Adds LogoDxe driver AmdPlatformPkg: Adds BaseAlwaysFalseDepexLib Library AmdPlatformPkg: Implements SerialPortLib for simulator AmdPlatformPkg: Adds PlatformSocLib library class AmdPlatformPkg: Adds AmdConfigRouting driver AmdPlatformPkg: Adds SecureBootDefaultKeysInit driver AmdPlatformPkg: Adds ACPI common driver .../AMD/AmdPlatformPkg/AmdPlatformPkg.dec | 30 +- .../AMD/AmdPlatformPkg/AmdPlatformPkg.dsc | 56 +- .../Include/Library/AmdPlatformSocLib.h | 134 ++ .../BaseAlwaysFalseDepexLib.c | 20 + .../BaseAlwaysFalseDepexLib.inf | 35 + .../BaseAlwaysFalseDepexLib.uni | 12 + .../DxePlatformSocLib/DxePlatformSocLibNull.c | 75 + .../DxePlatformSocLibNull.inf | 26 + .../DxePlatformSocLibNull.uni | 13 + .../SimulatorSerialPortLibPort80.c | 208 +++ .../SimulatorSerialPortLibPort80.inf | 31 + .../Universal/Acpi/AcpiCommon/AcpiCommon.c | 226 +++ .../Universal/Acpi/AcpiCommon/AcpiCommon.h | 118 ++ .../Universal/Acpi/AcpiCommon/AcpiCommon.inf | 74 + .../Universal/Acpi/AcpiCommon/CpuSsdt.c | 345 ++++ .../Universal/Acpi/AcpiCommon/PciSsdt.c | 1381 +++++++++++++++++ .../Universal/Acpi/AcpiCommon/Spmi.c | 111 ++ .../HiiConfigRouting/AmdConfigRouting.inf | 45 + .../HiiConfigRouting/AmdConfigRoutingEntry.c | 57 + .../HiiConfigRouting/AmdHiiConfigRouting.c | 1101 +++++++++++++ .../HiiConfigRouting/AmdHiiConfigRouting.h | 189 +++ .../Universal/LogoDxe/LogoDxe/JpegLogo.idf | 10 + .../Universal/LogoDxe/LogoDxe/JpegLogoDxe.inf | 57 + .../Universal/LogoDxe/LogoDxe/Logo.bmp | Bin 0 -> 522054 bytes .../Universal/LogoDxe/LogoDxe/Logo.c | 194 +++ .../Universal/LogoDxe/LogoDxe/Logo.h | 23 + .../Universal/LogoDxe/LogoDxe/Logo.idf | 10 + .../Universal/LogoDxe/LogoDxe/Logo.jpg | Bin 0 -> 75403 bytes .../Universal/LogoDxe/LogoDxe/LogoDxe.inf | 58 + .../Universal/LogoDxe/LogoDxe/S3Logo.bmp | Bin 0 -> 964114 bytes .../Universal/LogoDxe/LogoDxe/S3Logo.idf | 10 + .../Universal/LogoDxe/LogoDxe/S3LogoDxe.inf | 57 + .../SecureBootDefaultKeysInit.c | 645 ++++++++ .../SecureBootDefaultKeysInit.inf | 49 + 34 files changed, 5396 insertions(+), 4 deletions(-) create mode 100644 Platform/AMD/AmdPlatformPkg/Include/Library/AmdPlatformSocLib.h create mode 100644 Platform/AMD/AmdPlatformPkg/Library/BaseAlwaysFalseDepexLib/BaseAlwaysFalseDepexLib.c create mode 100644 Platform/AMD/AmdPlatformPkg/Library/BaseAlwaysFalseDepexLib/BaseAlwaysFalseDepexLib.inf create mode 100644 Platform/AMD/AmdPlatformPkg/Library/BaseAlwaysFalseDepexLib/BaseAlwaysFalseDepexLib.uni create mode 100644 Platform/AMD/AmdPlatformPkg/Library/DxePlatformSocLib/DxePlatformSocLibNull.c create mode 100644 Platform/AMD/AmdPlatformPkg/Library/DxePlatformSocLib/DxePlatformSocLibNull.inf create mode 100644 Platform/AMD/AmdPlatformPkg/Library/DxePlatformSocLib/DxePlatformSocLibNull.uni create mode 100644 Platform/AMD/AmdPlatformPkg/Library/SimulatorSerialPortLibPort80/SimulatorSerialPortLibPort80.c create mode 100644 Platform/AMD/AmdPlatformPkg/Library/SimulatorSerialPortLibPort80/SimulatorSerialPortLibPort80.inf create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/AcpiCommon.c create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/AcpiCommon.h create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/AcpiCommon.inf create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/CpuSsdt.c create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/PciSsdt.c create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/Spmi.c create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/HiiConfigRouting/AmdConfigRouting.inf create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/HiiConfigRouting/AmdConfigRoutingEntry.c create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/HiiConfigRouting/AmdHiiConfigRouting.c create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/HiiConfigRouting/AmdHiiConfigRouting.h create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/JpegLogo.idf create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/JpegLogoDxe.inf create mode 100755 Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/Logo.bmp create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/Logo.c create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/Logo.h create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/Logo.idf create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/Logo.jpg create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/LogoDxe.inf create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/S3Logo.bmp create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/S3Logo.idf create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/S3LogoDxe.inf create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/SecureBoot/SecureBootDefaultKeysInit/SecureBootDefaultKeysInit.c create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/SecureBoot/SecureBootDefaultKeysInit/SecureBootDefaultKeysInit.inf -- 2.34.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#118900): https://edk2.groups.io/g/devel/message/118900 Mute This Topic: https://groups.io/mt/106108329/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=-=-=-=-=-=-=-=-=-=-=- ^ permalink raw reply [flat|nested] 9+ messages in thread
* [edk2-devel] [RESEND 1/7] AmdPlatformPkg: Adds LogoDxe driver 2024-05-15 3:50 [edk2-devel] [RESEND 0/7] AmdPlatformPkg: Adds board independent modules Abdul Lateef Attar via groups.io @ 2024-05-15 3:50 ` Abdul Lateef Attar via groups.io 2024-05-15 3:50 ` [edk2-devel] [RESEND 2/7] AmdPlatformPkg: Adds BaseAlwaysFalseDepexLib Library Abdul Lateef Attar via groups.io ` (6 subsequent siblings) 7 siblings, 0 replies; 9+ messages in thread From: Abdul Lateef Attar via groups.io @ 2024-05-15 3:50 UTC (permalink / raw) To: devel; +Cc: Abdul Lateef Attar, Abner Chang, Paul Grimes Adds LogoDxe driver to display AMD logo. Cc: Abner Chang <abner.chang@amd.com> Cc: Paul Grimes <paul.grimes@amd.com> Signed-off-by: Abdul Lateef Attar <AbdulLateef.Attar@amd.com> --- .../AMD/AmdPlatformPkg/AmdPlatformPkg.dec | 10 +- .../AMD/AmdPlatformPkg/AmdPlatformPkg.dsc | 31 ++- .../Universal/LogoDxe/LogoDxe/JpegLogo.idf | 10 + .../Universal/LogoDxe/LogoDxe/JpegLogoDxe.inf | 57 +++++ .../Universal/LogoDxe/LogoDxe/Logo.bmp | Bin 0 -> 522054 bytes .../Universal/LogoDxe/LogoDxe/Logo.c | 194 ++++++++++++++++++ .../Universal/LogoDxe/LogoDxe/Logo.h | 23 +++ .../Universal/LogoDxe/LogoDxe/Logo.idf | 10 + .../Universal/LogoDxe/LogoDxe/Logo.jpg | Bin 0 -> 75403 bytes .../Universal/LogoDxe/LogoDxe/LogoDxe.inf | 58 ++++++ .../Universal/LogoDxe/LogoDxe/S3Logo.bmp | Bin 0 -> 964114 bytes .../Universal/LogoDxe/LogoDxe/S3Logo.idf | 10 + .../Universal/LogoDxe/LogoDxe/S3LogoDxe.inf | 57 +++++ 13 files changed, 458 insertions(+), 2 deletions(-) create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/JpegLogo.idf create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/JpegLogoDxe.inf create mode 100755 Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/Logo.bmp create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/Logo.c create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/Logo.h create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/Logo.idf create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/Logo.jpg create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/LogoDxe.inf create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/S3Logo.bmp create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/S3Logo.idf create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/S3LogoDxe.inf diff --git a/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dec b/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dec index 1fe7f94dc7..4d811d1135 100644 --- a/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dec +++ b/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dec @@ -3,7 +3,7 @@ # This is the package provides the AMD edk2 common platform drivers # and libraries for AMD Server, Clinet and Gaming console platforms. # -# Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.<BR> +# Copyright (C) 2023 - 2024 Advanced Micro Devices, Inc. All rights reserved.<BR> # SPDX-License-Identifier: BSD-2-Clause-Patent # ## @@ -16,3 +16,11 @@ [Guids] gAmdPlatformPkgTokenSpaceGuid = { 0x663DE733, 0x70E0, 0x4D37, { 0xBB, 0x30, 0x7D, 0x9E, 0xAF, 0x9B, 0xDA, 0xE9 }} + +[PcdsDynamic] + ## Event GUID to trigger logo displaying + # Default set to gMinPlatformPkgTokenSpaceGuid.gBdsEventAfterConsoleReadyBeforeBootOptionGuid + # {0x8eb3d5dc, 0xf4e7, 0x4b57, { 0xa9, 0xe7, 0x27, 0x39, 0x10, 0xf2, 0x18, 0x9f}} + # Platform DSC can set this value to another event GUID. + # + gAmdPlatformPkgTokenSpaceGuid.PcdAmdDisplayLogoEventGuid|{0xdc, 0xd5, 0xb3, 0x8e, 0xe7, 0xf4, 0x57, 0x4b, 0xa9, 0xe7, 0x27, 0x39, 0x10, 0xf2, 0x18, 0x9f}|VOID*|0x00010001 diff --git a/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dsc b/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dsc index d3368c87ee..151235b791 100644 --- a/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dsc +++ b/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dsc @@ -3,7 +3,7 @@ # This is the package provides the AMD edk2 common platform drivers # and libraries for AMD Server, Clinet and Gaming console platforms. # -# Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.<BR> +# Copyright (C) 2023 - 2024 Advanced Micro Devices, Inc. All rights reserved.<BR> # SPDX-License-Identifier: BSD-2-Clause-Patent # ## @@ -20,3 +20,32 @@ [Packages] AmdPlatformPkg/AmdPlatformPkg.dec + +!include MdePkg/MdeLibs.dsc.inc + +[LibraryClasses.Common] + BaseLib|MdePkg/Library/BaseLib/BaseLib.inf + BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf + DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf + DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf + PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf + PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf + SerialPortLib|MdePkg/Library/BaseSerialPortLibNull/BaseSerialPortLibNull.inf + UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf + UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf + UefiLib|MdePkg/Library/UefiLib/UefiLib.inf + UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf + !if $(TARGET) == RELEASE + DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf + !else + DebugLib|MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf + !endif + +[LibraryClasses.common.DXE_DRIVER] + BootLogoLib|MdeModulePkg/Library/BootLogoLib/BootLogoLib.inf + MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf + +[Components] + AmdPlatformPkg/Universal/LogoDxe/JpegLogoDxe.inf # Server platform JPEG logo driver + AmdPlatformPkg/Universal/LogoDxe/LogoDxe.inf # Server platfrom Bitmap logo driver + AmdPlatformPkg/Universal/LogoDxe/S3LogoDxe.inf diff --git a/Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/JpegLogo.idf b/Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/JpegLogo.idf new file mode 100644 index 0000000000..2d12b78c5c --- /dev/null +++ b/Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/JpegLogo.idf @@ -0,0 +1,10 @@ +// /** @file +// Platform Logo image definition file. +// +// Copyright (C) 2023 - 2024 Advanced Micro Devices, Inc. All rights reserved. +// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#image IMG_LOGO Logo.jpg diff --git a/Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/JpegLogoDxe.inf b/Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/JpegLogoDxe.inf new file mode 100644 index 0000000000..6a3bbb8d5b --- /dev/null +++ b/Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/JpegLogoDxe.inf @@ -0,0 +1,57 @@ +## @file +# The default logo JPEG picture shown on setup screen. +# +# Copyright (C) 2023 - 2024 Advanced Micro Devices, Inc. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = JpegLogoDxe + FILE_GUID = 319CFE1D-8F15-4A7A-BF40-EECA953D87EF + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = InitializeLogo +# +# This flag specifies whether HII resource section is generated into PE image. +# + UEFI_HII_RESOURCE_SECTION = TRUE + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + JpegLogo.idf + Logo.c + Logo.jpg + +[Packages] + AmdPlatformPkg/AmdPlatformPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + +[LibraryClasses] + BootLogoLib + DebugLib + PcdLib + UefiBootServicesTableLib + UefiDriverEntryPoint + +[Protocols] + gEdkiiPlatformLogoProtocolGuid ## PRODUCES + gEfiHiiDatabaseProtocolGuid ## CONSUMES + gEfiHiiImageExProtocolGuid ## CONSUMES + gEfiHiiPackageListProtocolGuid ## PRODUCES CONSUMES + +[Pcd] + gAmdPlatformPkgTokenSpaceGuid.PcdAmdDisplayLogoEventGuid + +[Depex] + gEfiHiiDatabaseProtocolGuid AND + gEfiHiiImageExProtocolGuid diff --git a/Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/Logo.bmp b/Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/Logo.bmp new file mode 100755 index 0000000000000000000000000000000000000000..9bc467b3484c970064b92f55a220e4c50ccd5a13 GIT binary patch literal 522054 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 YfdB$ShYl5==TS450CX@Q(+r&Yf5}9TWB>pF literal 0 HcmV?d00001 diff --git a/Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/Logo.c b/Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/Logo.c new file mode 100644 index 0000000000..69fa1dc0e5 --- /dev/null +++ b/Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/Logo.c @@ -0,0 +1,194 @@ +/** @file + Logo DXE Driver, install Edk2 Platform Logo protocol. + + Copyright (c) 2016 - 2020, Intel Corporation. All rights reserved.<BR> + Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include <Library/BootLogoLib.h> +#include <Library/DebugLib.h> +#include <Library/PcdLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Protocol/GraphicsOutput.h> +#include <Protocol/HiiDatabase.h> +#include <Protocol/HiiImageEx.h> +#include <Protocol/HiiPackageList.h> +#include <Protocol/PlatformLogo.h> +#include <Uefi.h> +#include "Logo.h" + +EFI_HII_IMAGE_EX_PROTOCOL *mHiiImageEx; +EFI_HII_HANDLE mHiiHandle; +LOGO_ENTRY mLogos[] = { + { + IMAGE_TOKEN (IMG_LOGO), + EdkiiPlatformLogoDisplayAttributeCenter, + 0, + 0 + } +}; + +/** + Load a platform logo image and return its data and attributes. + + @param[in] This The pointer to this protocol instance. + @param[in, out] Instance The visible image instance is found. + @param[out] Image Points to the image. + @param[out] Attribute The display attributes of the image returned. + @param[out] OffsetX The X offset of the image regarding the Attribute. + @param[out] OffsetY The Y offset of the image regarding the Attribute. + + @retval EFI_SUCCESS The image was fetched successfully. + @retval EFI_NOT_FOUND The specified image could not be found. + @retval EFI_INVALID_PARAMETER One of the given input parameters are incorrect +**/ +EFI_STATUS +EFIAPI +GetImage ( + IN EDKII_PLATFORM_LOGO_PROTOCOL *This, + IN OUT UINT32 *Instance, + OUT EFI_IMAGE_INPUT *Image, + OUT EDKII_PLATFORM_LOGO_DISPLAY_ATTRIBUTE *Attribute, + OUT INTN *OffsetX, + OUT INTN *OffsetY + ) +{ + UINT32 Current; + + if ((Instance == NULL) || (Image == NULL) || + (Attribute == NULL) || (OffsetX == NULL) || (OffsetY == NULL)) + { + return EFI_INVALID_PARAMETER; + } + + Current = *Instance; + if (Current >= ARRAY_SIZE (mLogos)) { + return EFI_NOT_FOUND; + } + + (*Instance)++; // Advance to next logo. + *Attribute = mLogos[Current].Attribute; + *OffsetX = mLogos[Current].OffsetX; + *OffsetY = mLogos[Current].OffsetY; + return mHiiImageEx->GetImageEx (mHiiImageEx, mHiiHandle, mLogos[Current].ImageId, Image); +} + +EDKII_PLATFORM_LOGO_PROTOCOL mPlatformLogo = { + GetImage +}; + +// AMD_EDKII_OVERRIDE START + +/** + After console ready before boot option event callback + + @param[in] Event The Event this notify function registered to. + @param[in] Context Pointer to the context data registered to the Event. +**/ +VOID +EFIAPI +LogoDxeDisplayEventCallback ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + DEBUG ((DEBUG_INFO, "AMD logo is displaying.\n")); + + BootLogoEnableLogo (); + gBS->CloseEvent (Event); +} + +/** + Entrypoint of this module. + + This function is the entrypoint of this module. It installs the Edkii + Platform Logo protocol. + + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + +**/ +EFI_STATUS +EFIAPI +InitializeLogo ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HII_PACKAGE_LIST_HEADER *PackageList; + EFI_HII_DATABASE_PROTOCOL *HiiDatabase; + EFI_HANDLE Handle; + EFI_EVENT AfterConsoleReadyBeforeBootOptionEvent; + + Status = gBS->LocateProtocol ( + &gEfiHiiDatabaseProtocolGuid, + NULL, + (VOID **)&HiiDatabase + ); + ASSERT_EFI_ERROR (Status); + + Status = gBS->LocateProtocol ( + &gEfiHiiImageExProtocolGuid, + NULL, + (VOID **)&mHiiImageEx + ); + ASSERT_EFI_ERROR (Status); + + // + // Retrieve HII package list from ImageHandle + // + Status = gBS->OpenProtocol ( + ImageHandle, + &gEfiHiiPackageListProtocolGuid, + (VOID **)&PackageList, + ImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "HII Image Package with logo not found in PE/COFF resource section\n")); + return Status; + } + + // + // Publish HII package list to HII Database. + // + Status = HiiDatabase->NewPackageList ( + HiiDatabase, + PackageList, + NULL, + &mHiiHandle + ); + if (!EFI_ERROR (Status)) { + Handle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces ( + &Handle, + &gEdkiiPlatformLogoProtocolGuid, + &mPlatformLogo, + NULL + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Install protocol failed.\n")); + return Status; + } + } + + // + // Create AfterConsoleReadyBeforeBootOption event callback + // + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + LogoDxeDisplayEventCallback, + NULL, + (EFI_GUID *)PcdGetPtr (PcdAmdDisplayLogoEventGuid), + &AfterConsoleReadyBeforeBootOptionEvent + ); + ASSERT_EFI_ERROR (Status); + return Status; +} diff --git a/Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/Logo.h b/Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/Logo.h new file mode 100644 index 0000000000..7f72f5f57b --- /dev/null +++ b/Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/Logo.h @@ -0,0 +1,23 @@ +/** @file + LogoDxe header file + + Copyright (C) 2023 - 2024 Advanced Micro Devices, Inc. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef AMD_LOGO_H_ +#define AMD_LOGO_H_ + +/// +/// Logo display attributes structure +/// +typedef struct { + EFI_IMAGE_ID ImageId; ///< Image ID + EDKII_PLATFORM_LOGO_DISPLAY_ATTRIBUTE Attribute; ///< Logo display location + INTN OffsetX; ///< Logo display X coordination + INTN OffsetY; ///< Logo display Y coordination +} LOGO_ENTRY; + +#endif //AMD_LOGO_H_ diff --git a/Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/Logo.idf b/Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/Logo.idf new file mode 100644 index 0000000000..3ef07a229f --- /dev/null +++ b/Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/Logo.idf @@ -0,0 +1,10 @@ +// /** @file +// Platform Logo image definition file. +// +// Copyright (C) 2023 - 2024 Advanced Micro Devices, Inc. All rights reserved. +// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#image IMG_LOGO Logo.bmp diff --git a/Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/Logo.jpg b/Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/Logo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..10d40b400fcf57cdb348f92b10bdb1eb9c695e3c GIT binary patch literal 75403 zcmeEv2|Sc--}VUEo9xjtvZO32k%|mS$SqpzF_ASPl~A~f5M?bCWs<eTl(mq_UL@H= z%%DiN8Os=E=JK7R`+nZG=Xsy!zMtRwzTfwLZdYcmduCkAdH(;$|2U5SY3cnE5wZH< z0fPew78Vx73Gg3csTZMxSi!=={Qmumm7SIOwUUjEm7QZH2M2TG<l^Dt<mBe$;Na%t z=H}rAUmRSkkbJzWn2(ts!hAdPUErISlY^7_ihu2E=_P`nlT~b`11pOpVg)}7D?iIp z4FZKgu&{%pWghVFUo0zF+1OWtL*nKEFDP0K4xg2E1vprCHa76;0Pz12Z2as38@Fq( z6g+IlA?YQgd?hxOQ)=JSO5r0dB<UUYXM?!7MMT$#iOXz~-MmFkMRljzuHAcd_Uj(d z(>FMH^q8rcxrL?GNe4$KXBXE~=gxay@bUG#7<@G(H0)Y<MBL3=@d=5y?<74)OV7y6 z%6|ALzo4+Fxa8UM(yHp3+PeBzuNzw1+B-VC-goy53=Vz#G(7To^b2`<W_FG;PhD7K zo)-&(_3LT<?aY2SFMe=dE5JQq<6xc_%L*T`vGTLAZ`{68K>IL<otL1b@)b^@eX*%e zE4ie093ctYpKak5kyaUyAu~^H`ON;g6ASuNXZE)f`;YVLLGZG&fSbq4k3b_}=<|aJ z#OD8HoBW(Q%s0G*2oCkeP&Y+KJcfno$I9DPahLaWbZ<W>Jn2!+;U%ANDaS#~PoeL9 zIpq}>Tj9IljS2GDM)A$8v~d#lx(a>+)!eA-yrQ9TXQ9!lR(S^6<jFI`WNVtAiN;Y~ zIf1wXpBoy!=%3JL3$_xbXD=Zt%L$}2Z*!IqY%OF{Y!yBtF)6f	>voY0JJBO<k8K zWzIHxpAJ@%NiGvj>1L5gNLuZnTzigT>}y<`go*Z-&m1ci$;cYB+EnB!3}dq`j>|OV zGRm_zY<UpRWgvCl(a~Fan?#WIeLn8Z4=(@Z4c5XFKTj<j!q=l|m!U7{O!GM!=9MUY z{rV-umM-eZ65<S!p*P!rpstA6eE+|6t7u+A1et*=%B`saRoc+yhxmL3nnr@@>JNN( zPWDs<=+r6`tgOC>3Q9-4>osJ5JSrXYpsqDl&gA&ZGy8)ow&5mrz?{)Ej^j|}t|bI9 z3C&lrc1*-70Cyvy)yS>Z$kUZgdFMmlVL$sj1AYR7h7K-|YX;sMtiS7cA+y~CS&gCw zWl=Jh5UDf@1P)^uw}fbDKo4?bdy?U>sqQ7j5`rTMzl4yNUkrS38GZZzir3RC8ISNz z(ZYdsONc_BNKFxHPuqClCX!~(&UnA#Eoq@+Cj%#kk-Md0bBAxFx9GpBa5z#&v<rcJ z;^|ay6-Egp<36S8r0D9Yo|8J!#!t(;^4ea)TdwTW-IR9biIG=UUx>bToHm=NiJ?M% zoK$En|IW14EL167ArqE=wAohD*aK^A<-ko35A4(wqN)?`=~ORb!prR_%}@K>&NZ=L z#W)qDOdD?>h_GCFvgFLpx^DaXM2Bb;4%`G{7YdBxm(8^3CBzr>!*?8DUyU%jNR5Fc z6f7ZNq$&iP9bQ7LJ_ffFX3>FQa8WfnmJkb;n6^0~7W&Ko@|T-`imso!tf|aMs8FVc z4NTQ2Ax~`(CMSk?G$mwZ+HMxGu3+85o1Pw9s$8lck`||?cfi5%BxBfogoD1$5d;`; zHertf-|noCAgxRspa$;o<(Mzs`{^A`qhGQusG;?9lh=!rMy<ONMDHr=$>n=o+3I`? z0ZAV-3%jl%`-sX@Yn2d^H<}cBJ@<3T+4rZ!0~lq!HWtVCf07BcxXTf>-`mmQ1b2)! zBBJ@9nD~E-wthtz>J}dmZRPxr6|}2hF7Hw7=HD+ikyq~LB^ZCn+IfxdcuRZw{AO)w zm2I&S3Dzf8=}<&Kn6_F%xZ-;2DPApsn_YMKqe-YRy5XI|OVAoje>dUF1;=Cc{;}Gw zn!SE!{flGL^mB&gZl`QPbuA(OhfT?aYMA@V5@O{n-31J0BmWgGu$2D+GP;W4w!gDn z8yQLruD%#K*VKC4(EZ$*yvDtEH%oE3Nl5SBEk7M&fO_v9s0Ak47sB*)B@kk|P22FZ zEssq&W>~+OJ{)87bnT<GqtH7B4Gl*BjQJAclOu}EZaiVMgwUBEXGW*sCd?8dKAwR- ztc7}m{Qs~2cV3@{=sG-gM;qlO)qKD@Kxbd{092FnI<K>DwwaF_n>%@bUsT-%_XBJ7 z{hyc~3yDpCbN#BESmG-UOE54R;SYg4q`ZvBw*H*$n+jUpWnQGHBL!Sa<`2cDUf{Q` z^qn!<hzN<2c3n4MYI%)=#s|_%C^`Z|GWLwdvzBuO3}V;%BdL|dB?RwiAf{I}z_YS6 z3Tx*&tp8MR*jPng+#|MS<)HH0`)9RqDBRR^`4VC%Yy2LmfN~#hTtbB0A+-&FfM-08 zR->uG0ua*b6c}l+N3+^%+J4VZQ`2dEC2PwI-(I+ZfH=>a&y~>(!H|52eOfZXPbrI3 zue6n*VscK2=X@zKhxxi>N@mm+LMGxmKOeWO^sv&Z+9eU~d@CYkwUFmqWbY1`H=7zw z#7?ZYCSq!)kkm2b=!tnR7fsnKg#o6LzwN!3uC{$4q03xg>*pRz-CNonYq|6KO*jVm zgeOr&BXmK`P}jI<b`!F;ImC7w$>y%wnfF_By__kL;=_X$d{sKDQn@Y}q;C(Ck&KVH z{gG{DWEC|4A#_;xA8x{n_rR@~fhw!_;OK&SwPp}EEN6R4yzAxqQ{%TYxaZYuS)au> z?(N9uEl=<mx4q=R7G&k39n&b>{3%k1g+cij0b4FNd<-J?ds25fn}V?5LVeUcfT=ZX z(y^kl=Gxp8O0^vxd+8(a+_|(^J29@Q?|Sp;%Q1#VoXTSM&*7|c*}*2I`U>GT?>?R* zZF9MTR)rBu2;+8ztpdZHaQ`u+P|Lxq%v6zI8n<S(w#2)YAwq|>*#F7~Nnl9ledt-3 zAuQu1dJfelzsSIS<bhX3Eg^1=(a$X*o^ilwi;f8Yf0)<530nWI*KzbNAxIu0<BHC- z05B{~VU(|@Z3|SQAvl0iuiLP><m9P$FYd)0<vmw>=5ax9lRw35x+?ok%W;EwEmuL> zdfY1%b%z@TK#dRpbJ=KQ(K`8DoeA-<dZS|jDV<y9t6j5Pci42-zTiE0WFRkvUMwBU zi*b@V=@*2@WFsC#Z2oS;p%{4d$y^SYn}xR4e;-wSa7#sf7Io;Ln?CM>fh@&wP`Sz3 z=Tp7(0gU9A&6}ogMCAKfubFV-c)$5Rk{CT$U)6Vs=u?Xp^p&mMiS7nqEHKCW!6{1M z`E!i8=^p1$-||=8X#x3CTR%D-y%BVP@7&xX17Ocf;M`T9fjjuq_s~OGA%)lis_f8# zsR<~*XS}%0Uxzyy?UT4d7uCCw=S<nhIM<Qr!!g9oxL4x;uoRS^0?0_U9zKdA?SO}t z5R1`Yyh-ffI)mBr3?N`{cqQ}!T0$IV9J-9g_54tTpw~gf&&|}0TXSfqea#3%C6y5G z=sZ@aT;5gE7pMQE$m=1szfxd3Z!Ej}O<OBzkDLw7dj>`Ma|*0`UoIiuL_$zJodiy- z72IO2rb`B7!gchi=Bs-k3NCC8L%rj#P3nuh>(%t&;M446iz||*GwvUI97|s**UKB8 zX_7v2(ET!+)8!wQx)m|Z!UC$?K?f*`-IkH3LI|lqR<zAp3>5~P#B|~~U1s-g-69#~ z7Q5=xrEs+-Ay@9zwgyMf>8**gc)1sXIlaKB*+ovI3y%%S+t}<(9l!*^!ez(EdJzKK zr0<b%jAXlVp*V8Ot%B7py>(;KSFY>uE+M)+tDull<jbj$6fu%<$YUs<zJth+>)PL{ zKp&N*$=oa4!prX$w?m(HQrG6~n|d+nyGb)ki1*eM5i0XHerDV~j|o{q@XTVyamZ22 zq`^V^e9V~njYl#S<+tP(N(9`G7q58q=)m=LhwH^@?B9hy;RRMOWOASeg>vw~(frU7 zqV2#_46fss`vG3y`zCgv2%o-r_Mb+Tz%zk;Xp)=Wcoyx1%VNh!C|!05!R=hv6Dm{E z>5odj#F=4e79<^@fPKoq`ov3zdn8Q1YH@z6BYlIAHfzE$%?|F%R)AkT@GetSSy@WS zHS`l`z{Ov=jXoAlJxG`5`4AA%q1h&T2XYSHo7s2?+G)96=CSQ5*&drne-;ekQ=kh} zX^$rMpsqrsBYf%>WbBoRSuo!ran0A>iWO;D)_U$~z6lgd_#MVPbl3IQQf0qoPAdGy zSGU0aDq@!w$F!qv01G$_ZZKBt=?>sujQ`OhQb}zy&k_PWbqjc4Bxqjn%=(3V&1#+P z;hDwvAmS?fTY4I<Dx37vW`t1K&)-FfpQ1+l6jd!5UM1E65tB6K3aIAfBQqwQ6^Jo& zhuY2N&r3<`Yw|27b7LGo7WmlD^h!tzwC&>!wa9}MT<#;M3aSDXTIrVtY}9Pt6)B>v zT2yoNakGqlRRdeyJtsbCk&T414;rjZlb3(E@d}#&pNsi)+MmsLb9)ESBCdgZNqNb6 zpRE$Gxh_c^>E?@psdi@)ca~75@B3y(9FvibY>AI=k9iryweqscUm=_17gm6KpN9Xm zX9=-x2{8$7LpFQ|(>3u^M%v6u{L2i;4*~2Se%>7NeHI1N0l6FZ3=K3_1*|XP^wbC# z<T2V{ShjcfoR~_ZpY)2s*_V$qhDw5)?oBtaoq6u0%N~~4HR(eaI|--=--02f8dQ&( zMSk0-77bY!n3ptk+)CSPV~6bOW<M{U#2NSWpm()gc54LcAL-|85;%4O`B{AcUDd}y z^r>p*rOH-yf)pV}3XFGq;3^V${w5>tZI4hWXZdTf^nj-i@<yCa-iSM7bpG$mSCj-) zc^)F(Ly=~%R9V!Ga@NdVMp|8uCP9#@HlOU{CK4{2$kC*-9ZIj3sm)xtT`$^0Z%waz z25-xu(QzLQ;Z-0M1qFV=KSk1o*VgU%QlD+(t2SiX*Bqr{v+vAg=HM5nfCKLuKh}%h z;p;8qjCpmWfACFNV$3^^k$(tDewkq^5WlSL=V-q`6&%ymAi_z4+`+0k^<H!^<psH5 zpaRQyNK&d3f1K!ZfwI%962u{Rde~k!t(N<-YgS>DK#!@Z#dN|n0{$%#eM^-w>2E=` zzEAg}S`K=$Q8VjlN2@irwdNHX**3q8Ll$*^s3J9s-dU><UaIE!;l|?~G1`^Pi^2m~ zhvkeQAUY)1XH}d!hzo+{${a}ehz;8uu8^7;$<PzFC^ElA4&v#D1Ci2p2b*{iD9*#W zLWrL?7hmJ5i@0ci)6CCSB6qUgton<5ghR1e@2y`nbueo31UB1;v-nB-IGXCRJ(WNh z+(&9Lu7jwA77Ogh7J|70^V88`#>usTDrJ{09l)20bQZr}XRI;P@KHc2f-@sNNM656 znSXsl8f1qh9Yj-QP}R{?Y25gbXpq04C<S*-6(ctWxR}xsiz&L1?<1`Xh?02E4I>ur z9T7E;YwpOzxn|5DsT=F*tA{G_Bz;V<k@xu?D565e_fgBy+6|laUq`Vu;3@8*qz&pS z-bdc-d+jBu5Xa8LyDfn5Gb;U6y=y);_p9AMmcjE2zZePs8P4Ru!T?_6<Eo>3r3M@c zL4jL*m8#)gq^4mCZ9~qff`A0GQ2oFbPua!BOCeFNrm`V%7V~jYSxNA5JP}|Zl84d_ zJn>f2S^7RwATHZqpQ_|{;hpir7cpTbq?@nR6$?ebFu}Nre#ted$l(u>LhM9K=y6Xo z+4<@$lTkkMuBdOvS4P>IPsbQv@|96ef6^!z1Q_Kvk8g0E(3c3-LcP2vOal;=1E7b> zB5`xN;Ml;uk$R;dwZ)LGs$TUcDVs>}Q~#SbzQ_A)u1%yD#s|HqO<71Snf|DJ{D6On z^F4=HFqr=_eS<%W|C412{VAwRE1J2e1%~9Qkn?>$``Qbc97nDszHN?&=j!t!d`UcO zt;&(qEz%x09_OWpvaQxvO~o`s)7LgJ&*}@FWP}p7q{~wu`enOe5Z*cY_P69e^!ctD zG*_56d!;;WS@zU#B1VAAHFc$qf;qZ<{wm!vgF0VT>QR<@$||tvfty(@W^^$mr0RGN zp||16VA2+oTXAX!%*>DItl*RuN4)zn@BXvTe^u&0m?HWWsIrAHeGiI)<^d#bhkm<{ zy!=<P-M{)?dD?LhfOiH~bwZ>=1Q5fkmBP^P@$V}(*~lqkYF}?GN*J~|J1Sz`qR{z8 z3fmCFNK$KzWiR9!-lbK)@Bl;yfO_q5RCg3rKJ0Q}OLjo80o5q_+B|$5Hf?IAcsJp@ z?XPdw&n;baLvOcsIw3gW9dHN6yZl`=gKI)k_f%6>J!3otOjP2YlJG)#MNLm(x<Hwy zSgll#R@YHiuWHFt7swy<Kil2VGMnfy6gzZJfV2CJBV_m))Ih5u7K33PSsITmRH+UT z)3AbpAo1ISZ>poWr8mTx?)1gl^}KqP>*=dUk8h5H<aSV8QCrz4ZCSTJ@t_j_KGOO{ z`sjKoJimmXiw`X;9AZldkkA-<b9)fr9Dh+a$k#6+Jh1Pr2kPlU7>ZYCg(%&m1uF7K zKN@tqbnRe0^q^nvNyOsYBe|cB>pg$+Uap~e?c-PjY4>p<6ArQ-fRN1lb(jtw1s#N2 zTB)*iEzl_{WIE$fE<c!KeIcs4rt{QGK$rWO^H1s~_1!M~twB3(%f=*3;@I-N&Vwp9 z!|R|*E4;Iqzu=GyKEGT$!>`0vm~5I``WhNYt~24umhtcP+xei$<Bf=^sYJcPnI=*4 z2+bw%RiH8>2oS4Fh&BFF)GMp7$OyXVg@k!`yYpM!J&x$d`O1dBWUE&YsFe#djop8F zk5s5GVtVmMPy}b;iM=?ggi|nW1zq7?;7))2wk1T7<{sbbgHe;M{flq)(E}Ke9k~ki zGfiVvS4K7*Z)nKfVB5b<@NL`(P~oVmXqeM5Ln-7ukWYq`LcO_EpKt9P8z>ITv3k%` z=^>zY9kV?_Njhr0s{P<KDSn<?0%GnN*XK)rt#Q$>fPvhB|0H4y&|!W~7Bre>f$RG6 ztKIjJ!z;hhu8>pH-#l9Z9wPxq)djD*Oa)~J+XUmWzd6aLuAiS;`N%gJ0EUw^$IkE! z*S7bDl;mAXQq%ozpVN0m4Y2fy4+OKs2KfiWQf7<<=(9HCKANPL4o$zsOQ3%c)m{R^ z2o2SoBIGwSIMIb1Fz0MEY}vAe;LizcM9)gV?@&~!R`h~12Gm{u(o4<#g}{}l0*AST zh)9up);8Czx!GT}Ahab<@F-a}wDXeXhdrCGm>)`-^xPKe#GYnBUh7ybY&N%q-~vgd z3H4+oQUd@D3bcNf>Z$7X>@hKJ2~mBqBjk}r6#s7}g5Bxc>bTg`<2zNvoE%N`VU6tj z$jJg?)<hWzL%BsZtqUQI49<fCK#g5Uh=eq;19)MJFC`|uIS*8tgapbS+kK2QjJ@n| z`0kVDY;zI^Mk}xpOENX?QKxK$tHTDcb<x*0h`0KyQKHBDkTlaNm9?JeCS|}*77x8C zaBotH^M7|&zyCz_<(I59{|EScsQ2nH@(?-k>fBmI6eW@xkVP%nAJNKlfs6{?C}Q=> z_kN7VOm~w~w}(T@VHQczf+z_`N4>R@m~K!@PSJ(2L?yaVTh&89QdYfHU`B4O%how0 zFJQ`3-4^w^SQ48G&%H>CoU{+m+c=~6=IWz^A5Az~e`FJ#sRdORnR4wz7puuTU*%fG z(9|qKZ^p7*d&I&qyb{Q@PG$$#wn?wn#(e_F8JtuQxaie6<vwm?seunmh|^Tjp-6L@ zW>xE#sW*61<^yu$uD18jXSOQ#>~eB(Ubw4Zw66YQdKao=0z@fP1%j$Z$)KtZqQda2 z%lBqcb1Ez33U^wi-0@AXKXZpST{(vQD(cawq;TAB{`F!urk6QL&bk2`K@d6$ez!BV z5$4jN9Y2NP@wW@e8aw>jC8_R8u4T;Av83bqhU?Tet$#zA_6)V?7nM$r)$EMhu`b{L z7kKU4+9EIu`je9P!bx2O6p$iFc1j!~aF3QwhCFm#><rJf(uK0Vh=_8XbAvqPI3ip! z_8rmh6SK52;N_HvaodNFNBzmV`Qg;RhE!BoQvU?FWcihR4&&W^S=4HwegXe~RTBI= z_FW7cKT1>jf-laR@FI;2Xh!v1RZGz%vu8%j^rhTgypiNs9>?N!@r2nCa&P7E+XcrJ zyN(w~2EAlm1Y}Y0KD3=%b9WfbRi6#Std-XpiG!X|;*Y*irZ$#F4I8cM=CwMLAZ7{# z$GvlJJXhN(h{o)W4ec=Q_%Z?u(iPtYa`-EdnuGimPcjk*upFairJG`%M-0&23KOaN zC$7JVP15TXmz%ucwClC>$1d$}sswX1`Q%_iFiCyDIlSC`FnMYm&r3xgEbW}T)V#?6 ze(mhe)1*;x{8X#v`<CQW^4seWvMVlY;9p`%CR2be<6lB}qSpmB^_b;k8<GtNrotvP z403ujv2s?q<*?<Jbsybbr3{m0y<XPNYKwKtS_D+#Z=k!+!Q8!rxKIMgQV~fhB)3Do zi$(Pjld722J#_^(epcQek92?NwUq8+35z|cUhBH<=6Lk$5;K|A!Hkselx~h8Bz=P$ zjmMIHm=RgNg*>F+;@>Rjuh?PVs#-=hdc6DH)a|;=vkjZD4fvf8xus%Jy_3m}8}GC& zq~fN|G1*~`q3EjSuk3J7iWoUG{wq5i6Oi|ISag{kb}(uw+xpSb?rzX3K4=wGTr!S- z1lK}E^);SX7pqSR+WK<Th+fq2@ku&2+6sW!E8Q2LuiS~y^Wuo#V|RPa@V>`ibXFsk z{vI~|>nMtea^(k*)UD{RC8Iem*wFh_4-^up;%nA&vkKnq`zq>uBbwq4zqB<}yI}vA z)xcA#FgBD=We0-*0tFi+qA4;)V6E6fO|I13@)T|)s|C+l=K>CHCJj5Dn9!!NqjvZ} z)7ptxF&`=AyAA@|+_1PWm*7>pAo8trL6>w@HC-BVt`0!cl!mf`XCH2zoESg-5etj3 z-z${9t`{NfiZZcyCsX+7ajTu;M|O=niui>8pvvVbz)b`+k060jOmTfgo~F9L3+ZjD zAE~6O#49UA<vQ({xO3!G%SS<j%}xZ>dueqME#uQ3o6fCOSA0=}B%(;3YIJ@#ru35u zw^1%mT`xyx8<03&&O4TyXY-Uiv9TiVw_PvSV|rv-fAU@7pmM1Eg_Fb8(#5nTL@t4g zYHUan1vM7WzBUzx=>8UW$tP{IG@kRtMNdk?SLpH{mf%|F67eYeK07ey3H|-Zg^59v zE|$<AG`>VrOwUg-RNRCY89(o2IwD&BgPdStz(3FwEI$`QxXa7h!5(#>9gv%0B5E;u zG@kT54b9A>!l{5xJXNuRY_?1%ral<EsQBS4ok;026XoB<q!Tv|#jZDvZx2de!6{h) zYJ?9{R4F`tecvOxd|M$DhA!HFF)Um|-Okl5b2MddTW-pj<>hdSN@=Oeozh4N?@hjf z6KjeV(n=GYVxiQ3G4QL>xw;6T%-2Oxm9RAsRYtFNuaZG$5puQf5Yc8>Q5C~!=-URJ ztZ6flw;7d}^1Cq4Bi;I{Wku}qDaV+cg>zLbjKG%T&`VTwKOf^^AfNB0LD6c$>QPvZ z<Qb96K78k4_tWhkHXVE-_fq4mRE|{LfJ4;&^WNrWhu?o6I!40i>+S(m`nUv)n>e^K zDdB0VYiY=QZS+-<#EVl`r3w=+xNEO{eTjh{C+lr|7B|S_xcb5Um=C%h5B5iXLej&{ z=NB*yz|RHX1KZ~%L@1!ugQ9GFX}TrT<$~my2~F7|#_&{u8}}$9m!nxFu6Q&vV#?2A z2-UOUnA^2g2=uo9tU#5Y1&YXPP|j~$u5o_z6*MDl$QZy=tx>#rYJDz?eEo$zr~B8H z`>8chN;H3?xqo^SDf9dWE@^-ENhfSGod{S22tT;Hd9jE<e~n^{rNL5nmk>ENKo5#t zLiCr?S^n3(B5kT0pxiCshTUg8gvI@LfJa_1AUH$92VW>vqk1qTEF*`8o+$CM_JhqS zr~HyN`g+y!CZ2tG{)$n78$`lf>Y%_iVkAN1kEj6M9-<U6D!v<C%QV^lP_$zH=LvJq zYH_#=O^n1oDZ<hPO8{UYH4ZdWlqgE!i3hKnlh5kAJ3dc5UaFfgYp7a!ZDcwf?G!ov zQQLimU)1XDh{d39%R~HTh&ToHX3kLTz{K$yT|%t#N9RJ0)a0SiM?Jb#2TBfqc%9lS zk$8B!k)VQWsovA#SQ!PGpy~7cPd>a}e1Ull=AIJme1G736v-44@%3o7g5QyhE3wqH zSvTK=FKg_}uWjj&_RVz1yU=`+J=zXj%hz>uj~oy=fS?m`V?HpS3#0TjC>4+(4qc_I z`Q<_`zP-d|`r*Z<@*Fqb7Rwro(X-Mf#Zv{0u!a)L^!=_f`On`@M@m7`ri<Xlugrq` zfsOKMJ>csNNN>yhvULWGBNMI@U!OF5-r2eSh(TI_@}Qw_OHHd-wUyMi!>ijJ&q>~o z*~T%K{4M^)G)L1nFoO}JmA*ThuF1$$*)>aB+jMb4137qGNczYrH6FGu@qqWou8M(* z$D1v`af{@x(}x95ZAZQH_FY0uEYQ}wph+gk_q~Inl>~kx%3gH6_)#m}OZf)q0ww+g zH+B5h-IB@+qKCEBZaJ9VY<OSqwoL+6y<Yeola|N%ucBuCPRlFR^dmbwmTCDYDBsrl zw`E#h#j|)npyeC9V)QHX0)NdMfOHD;foKRU41iSyY%cIH+yj~+1ghaYG$8h_VCPXx zV(;jE<QV1KvGC(#JSRjPg_xvBj;~-Xw#d0^J(?z818CacDkP{Lb#Dzeb`H7<89mmD zm1lB0%6$%;>EVvgoT4l~siDi-O*lv#x`Fk8PsEb;*~n95$)@;v&mdT=T>%!MKAPN5 zwvDwr74{oRmsV~sCdu79P*CQ#-fVA*QTZz=bJJ%fSJ3NR5V&kK@fHMF{A(a%nc;f& zD6vsDDKQ0NThp$Ha#L@QRtsOJrrVdtSui^Xjq;xK=B$j558qz9u1$Aj3Gt+4T#<}| zxs_;oE_fbT^fSJvLZaiGYHdwz+LM;k9k&bv{5G3S=MH^%ep<xIAyUM^A!;Ywh$h~{ zJn;#Jh{@P|^i^1hs@!NCwO6E7t<ziml8(D<xT=o0VrPbO!7JF|?H%scT@l;Y>F@WF zyo}VMvXVF|@%deqIHdnx>ZO4RbX5f(DffPUn@Xdqr26^SPBOO><Mb{#`>iXC)1RDt zGydih_doC+<0T;CoacgW;$;x&MhS~9o$_;wKkwYkx^U$ie9KCsfAfsVZL<EdLc<`; z3E;whZ-gOo|6L0OBM{U|7&NgIO{&ER4N=#Vuh(IKSD3Bb2oLkqnhex>ebE*Pj&`NQ zXSA(YuToDnIdZ+a-j?aZlNp|)i}=fXU_8Vm+qU@7H9SG|y1#^|($0Zg{EeuXPgL_- z$fb0~Q^`Lab+SF3pizMDaj%+6u}N`n7cDy`XTm|4{l@qtOaflf7Md_r4XlWjQuF{y zfX=vhN!4k(-jf;G>D)Z1AU995L+Dw=0r$=wwtlC|cI*m1_sFxE0AzSDI+v+~i;S3w zC4?Ok98sNdNU8sxfV}Vl!fFGr2UgvE#@_1_5`Du1>{#Nwh6`hRj#sWtQ1GvTQnbT7 zlm9+1%e?k^RlP*yjl2pLTmK^%<SEvHiRfz*q{pRW*@k8vn~IZ06{VzurGq#(=y9$& zAg=hy|8ofg%u=>pAQG?hZG^e!$nkl3$tEORCB)tL$TzK)YmLAmsyW>Bq@UZs_j7~g zHJ6DY?>Md6)KCameW~gviO68c5l5ButU`w2!SKtXnpai`Q{ywcU6UM>V%L{K4r2;6 z1p)wqznPLsh%;E<*M0BKHIA8+-$ue;Jmz?ZA{h`C4tkCQUewVX&|!-{MYxG+{53RH zdWxQ*Msa2Glmie$y{C(^@J)65yG!dQZTr97ZN&lLB3--%kn&%17Z){dM)&vJ^;k7I z+^Bt9t>0?9jJmk0vcML~l-z(_Y>Pug!-#s7iaW!j>r*scT!+SC4L4#)Mr#74Pl;HC z;BHi?16b#7tN1CM5@$Vn0jDB<T6=v1Fe(`P-h6bxA^NcPOuE-|#-Z;tD<l%!@>_vj z#UNf`#>L3ygCE;mN&P^zoB7}>54r7a%6<EAlSCUaUP4l5T}fPTO^tGhfPjsVC}!X- z{{9qoZ#CsbNpKZ@CA`9-DXYoP+ea;WF59*fDzZ#>RSdn`(iF=Tb#!a?dW0)W@inZX z{tOx`j*!;@CW{V#_QBj`lZB3M=dAU!uO^F$yvJK5&oE6EI`xu!a^xSf>$9!ab#Bo@ z^^VX5>M5PTn;i~SYQmy)`<upaW4nf325Q34H277h;(;Dlg(?55GmerU`mEpB6Qp)u ztFz{NhP*GoFaUyw9NHrp%}t#e^cg4P+%V2dh^uLh<glx!GpsG_lBU<t?;TQ!z2lrP zXy~0EYj;@k+T*PbjQ%cVNT>Z<GHKb;UfB;~ml2BU<k>50OdTC?mmP<>s4ZnQ%y@B` zVj*F5Ra$f3r<bvMlvn#cY+aB}@*8S**u^bBy%JwQpl*$(3#P#vK-J4OL{7YXz85O= z?bYiYgjT{c9uxL0($mC+%uuD-+YZkP2|Lyd(lANKZg-*Tguinh{Xw1nT6LkWs93ft zABUKB4_5Rfn(6k)(n57jd`mMj9}81;0Gg?QDqj*vPc-n|1WFLO`I@Td+EYC_jYLlo z-^3#{3<Y<u1eR_)uCGBT^y@#_TRv?tyg+a^yHW2hgfIL43SkGExkj0`mW))lQm3!B zmSXWxEab6lYe_Y*OORy;ww61VYgWIE(O!v9Kv5O5=xeivl)7~&GbC&n1nv$ywYm<4 z3{<hX4smN;+bXKtvG#48`v${=nAmkD`#p|a!YKsYJ!oa1`PyqQWD2r=9g3s_<aV<} za9x8LvAtC{zwCj+H8=X^Pk2X*x+QdmuRHsJvqLJsB<8^z%7q~)ab#WL&Ep3}ly=o% zom+mewVDGzFUho-DmPO7Rl`?`EO%F0*6??BRaFQV-8+dVs}5$%2*vc9mS2j^eC8-G zkbhY^LEkR%C7Rf+)SESkW=dOH)Td;f!O$W`&LE%pU|uTUi*mV^_b$b58Lpe;*Y3Km z1{?sxRUZp>XhgLdO2=*E_{{kB4*g24|Fa_gvIC4m4+3Vx-AjlMtW39|^6y@d@4J;= z{(WN9{4+#fyB^%16&;X0iYliTT(~J<-&iGHJa3{Lnd?dt^;Q!-D(Bi|ue4`Z`74h; zp@zYI3G<>?R+k6iHGnJxgd#G?8nPo3N=pd7SQ^q_hMFNm2%AzxuJbiF?(jAqH}G%d zvC$<O7x(JTyfS}XD!A{Yk8|V$hm+5(UIcxIKhbwl)V(7_XSx*7&CtN=7>?~p@uAD~ z3%?-MQ#`wi88>Ol<Hr|Zj~RRu+|^rPKTgy1*-4ij<b%u!B%j2W%~WfMbfC`-*oUwH zP>^!y=4n*yE1Fs|BWt)}(Kxp3;(`U-Hsdoe^YL_#+7#x~%I}WgJ7*IO|L0tcBY?gG z?;KL1%6HY7m6p2eRN>j_@)sTsMhi)wFi;=B&~{e)Zjl*E+v2n_tt7J3fK?<EXso$} z%V>oETAHH2IBC9`5LU6FjV@0laQE;i?)a_Xh*ZgM3HFxZz|-R76WeGY9W^=r_Dv1q zPe4UT;m@GKUuoN{pOL>x-Iy8_UBCxEl1x)!HfNCV@VyB)n*VqCY6Y`Yz{e<2zvsdj zfn7{%<BtRTvgWUT{l9%5?gZm9kO^}yF@4Go^u1K|f$oa>Y~LYMYXi><dcdcgByZ&B z^XawpK8$4Nmf`8E5v_jKLX(ah^<(pwfQO$E@|bQqgbybaYQA{DNQ3zyrAnB;{8mpB zui8z$kyB@-Pv>fw^Y<3ra#OzDUJIQ=O{wj=!MeDLgax)27GHCtcZG^Oj9bndiL}b| zp^cxE7`j>W_{K<^)CwSC>#jX|6oD`SeZyAYh7}?6DirA~G;zt3CIKKUszUBif$LZ< zUB7SxqE&H9(K$uEzCC`h%*0-*F;-;`e`mu1{%{E`pE#*A$YCCU5oxx)a37d1N2YFI zg$fr6X)gq8Y$f6d`%4RoQaaW9wl)dWRh?Tm(qt)JSRACsE3^=`gpfYTiC6nQ(k{y; zCa3UEF-+NHur8|fYF7#ikWHS-WTZS;JfC#0{4A@NgR`l9><8`PmkVYqci&Ymjmx6l zpc<16wW&j-f@;m3q@sCBR;a&ShSk_b-I1HpD7S*=A)A6QTXii3&wJz+byzsFvBqL5 z*F#4MBp1DjHb0s%=v$mahG|N4;)^tlNN7_V$v$c8hg(m+n>1<65_5`AQtOq(SRaTL z=GS&!v8LVK8Nsmqwy60lcD=5-Ud(MY$-ABj0oLk)I>dWuLWIynE_sPAq^5MuCkM8r z<;zkEQ5r2ZWp<(RFFrW{U$yhX;XLQv2-xJ8R*Ju7EeDm+R~v#-N-!<JAJ`DM==$yG ze0Yy9`e0OR>)_(F!4hKNgk|qOmNEk;r`S36NS+ThZ<;o37*sy`HmY~QE*A+TKvR-v zL?P3xRKzE0-QqF0Y*q>@E`9PWyqalNLaw{^1(=nDC01)Q`#cU~IHAf_XyP-N51`N& z{^D-d=^%KK)2fOi;LW5`{r%@MP0@vq)#89#DL?dxm7(AIlQB<RoUoINf45AO2U*)4 z*)v~>2Y|M62zed5dQ<yGQdZD}z~IDbMWd#U#@BM%Z2S@uVlpWf4~~pKeHbHpUhD0P zu-fPdt7Q-QCUQxHC;qF4e9XFIO5@J5hg?Zzdci9Pc*qa9XFslAgSg8L@BivrI}V9K zm9`bixw(%(qajskz`7XXq1t?0VL;%;_L$SS43yT31!XI)FZXDvvnXsk#4-#xD<-l4 z9Jsvs#QLwu!aQsi_dBvke?n?X-Ug6Gg?ml%VSp_7<mE0)MeMS>&I}k20m)+NOM@Ho z(v}dJksI*0#bGR-*nkDKdNh9g(HHchOUq~0xy5gZm7fdu|ITWj$$i5)cw)10<V9Sq zF;!~zqDZP|R<$#!tFE*pbhe(E;U+#>2OLhZe^Z%0Gq<H(m|LUphP#4T^4uOg8$_&Y z7CBXtBFxAr+)|{t&qmOwjMT@-OqpNRSzIERnSHZq-TrY)X+t+}AB4#2{ahPGQ7^s+ zsWT8=1O>bXk$~nw7sjVN&2(KXx{K!XrcsIIB?d!=*WESUuKNW&kuVS<>&or=BpoTH z@5lxTcr##NxA?izWJcEjz-j!cI{Mt7gAGfF&Z(EE%bI+k*%hcE15?!mq$?~;@(gij zPq>q5`H;Ui({Q^&O?jMpf%>aY>2Z2K7o45!L2D6}l}PAzBX$AAK;KKEU<WWOsb=pi ze=pY^3IyI50`LBg@+d0<X&)b_3r>4OK%?=`g4REya(!Dq{qdM(mg86H{{L!%-JG%j zZvRt81b(0oPcp^>k(|S!9bKe~<QUbX9T|0=8Av?*Jjt+;u#uh}ULtBP$XQaCC&?e$ z=pno8Ahcq70eV?sZrlJ`z}5xdvw@2W6bj+c0<SHlp=)rGyeiLHEzCW8H2XdsS5V%g z5NmmS#P>iXKDXz)h$z1R^qt^lyjw4Holt_k0`rd+xX$l{IQ%uc#DirXll!bsCE?;V zp6E~RKYKud*ygAs5W`oKdhhn>=*2^zUIFQKJ*l9ke<#^!o`MPWM`hT!U3>x3D{w;> z6o(9_V798dqE5Rs6$#%SLI_^LRADE0$T(9*hNdQUXmDqlXI76}An-r{Jg&;AAmuw@ z_pJPR+~Bcrn|qzxrni~AtwAW)Ol$4>n<I_}!F(T<3HcMoR5^V0lz<x`bWlP5HY2|1 zT2bEO9B#}0kkzj>N_cbF%hg^xdMPw~X%sHU`iext5<thoH^_ek)@dJ5a{XRflRTq~ z<fECTb>Bd=Sl|@1w3eEYU9ej&txL+fxo?Bg`qrA;y(rAPZ@tYNWLZ$&fD)AH$0z-U z?`^KfaC=I%%e1KU;!CI}P0Cg^<+!wcn%Fe++qU#pIVZ6cY5wciw(=WrVbr>20hiB# z4Xo@!38S5mtn|QlkAZi**k8WPU9_fECY`^}ID^nAU~MQ<z2_CVx8FTd!Zc>&Sc3Ma zN3X0Gp8gDYe_6=?&Y!wP)3Y!{XGZ-JVh+{*nRSuzEl>fES*fhdf7{XaONgHNI?NNy z1e&;nxQ;~*w+)anL6iN1EuIs)O}PyQf|VKqsS>w81zFnL-^kw_bL;$>Jp6lSx<E9{ z{hTxeb9c~o)ed>GH8SD{`Q#gl$mSs)S(Zxl9lj0v2PBk|JvVi^cnI%nc=YnxrzjVD zc=Om7psk?j!skFCEMQKFx?b1Ml}IzMUc|+_4dS@_4z;}ZO=_};xuNALH@NrhyAN^+ z;dibG=t{q9U}5APw#Cpy;jRik#tU#AIq1i!(9Tq~5DizCd6DbTDfhhGl-;&m#CR@d zfHo8qa*Dj+kX9;uVeVHXG9HTpURs!^=ut^Tk!QCvu`9fgI;%e+-ZgmWdHRPk8{;#! z`xCVU*qLg7=I5G82jyhv?bq_`Z?Q5>mb*n^o)KIi0V6aw6$J6kA;<Ao0+AgKg=Np4 zmPbKU3(<tO)m!^5EYkw^I%rW^<dt7veHN2AeX^LI%5-QfGTCc62-qq$nRI3L5@Iw> z4>!CLpEX5Q&Vmm+4o%VIN~7T<m5T^Q;J3Gs*;BdK8oYvt0<Z9alT;%Zfxp;^fKPl2 z4dJEl0>W~>{b@;(uZG<pmn5OC`1|E8@UNoX@WfY3h{%h1Av70%2kJS#ij*GNh;m_M z_|_5M4}E%GnFL+W6$dJVIJ;G?gNUip=@yPG!H_`*b1jI<c=Yrw0t)JuYlmj1(z<3D z-zQRNB~++XX=F}uqtb?=!}d(nVSRF`tTm$W+IHC|K5?CH*VXSRe)7H3u|7>{t*}Cb zzLXr2mG*|2H@It;h1m=Mfv5l(9hyJJGV>jk^1mTNGdcACpQV2=)%*cEz|Tt@;~cd0 zZUi8g_R0=SRT5S;QTFQ8i$Cfyyp+EiU7*ln<<^MbY9J}FAoA2$?Uu9|kV~`9ZI(c_ z`ur8%{W0(b|4UvY;neSD1`7C#{FEkgL8FyA%r!qi2re##dQ_27Ne^kd?N2;I+YYrl z6_zKS3_q4pZL|0C@p{QM6|Jl4rkkK`s!U%#kgMFj%2mfTfLw(h7dNi*r|)_)BQc%l z0TtwVXm%((OVD-iYP0n_UA6-ed{%y{`Fk3Wg|-(E#g2h}YFHlpX{<1vqhk)IRE-uo z|Ij-?pvti{S^QH(_!=$Y8{7PfSBwt(XgSc>A1z#d1ZJaQ2c4fTOU+mon+LFKeXVG; zWwF`a`-SAp>#t(-O>Lz_$wDADoArEY@CxF5g_}G_0ic2|Pjd)-tI0#nASUCBeVyyY zkL}4#8MTXZvl*i`y3!NlRG)=vks8Iz{La=&3dXCjeEx$SXZ{34J21I@24+PO;5=uV z+}cUaH&k+#O>XJI6Bm58l`~CljglUb-9A$CydPJeaigC6^9%Yg8?C<pO{EAM;_m}! z$gp?kF$F+wJUk4rOjqpMuX@9TvR<U=vfl6_GV>(R8x+$R{p|vXz}4S4#FmHdvQ+wg zsvjeA|59;BK$yaBgi7Y=Lx}Ug@A+GKGQ@N&^N{0nJ#Lzi%_|{cn;dFd)u@EB7WEk1 z`lNrKp6|6sVg?qIQo2$5GVGF&WAp!FUo5o3dlAq>D;vP2xKM<7A3e17I!S3T5v1Kf zR%-s_vHW(`oWv+J3*puJPW_CYN`*<;D#LZjb`b^@Z50w*{fWpgd%i7TBjkxlU>l>0 zlvUwL2cx^|O<K<1J30Za*YL_P7QL#Hqr-dCh1M}><234EAZ6|Az*ZM06_9Ch<6xPH z-$n!p^wJ<<9xxJlO-cF2R|p*bjtnfhq^1`=AW`0SG@v<n*3ZsK-Genc|BL9_)afTU z=`$*E(K7v=X7C9&o!S(jSX~;-HMHsSR@AZToXdIcImfpT9+>pNfwjk`n-ubv3#J`U zWx}Q7jGVs$N=(~4UF;~x#rfoUM!b#Q62eG)FPM;^X@QvuuPcE}XbLi6OWHe*vAJ*g zx&LvrKM1KTH0B-M>1%9QPBx!V%xlVYogTaBo)tQ-sLD}tptPvu-ke^_nom*}>!o_F z3+_v750cd0{0t7xA?v}s(bO#&pD|CNI^%2aKAhsqrRLN<p?XYmoZtDhceHr>aV>JT z$>4ziGve;8+FT;S`u2pP?<#f#v&o@<<WKN4oZsu^xH8aA6~+{czVbFj9c{n!Hburl zzNu1xw*lSh-NkDwnZ%9Zc0NGd<m;~~-1c^vuL|41>^FGf@9373*{&f^!c>)<O4&@_ zcYy6?h42!h;Ivv$ob4Xv1bcCH-#&+!?JjoM#lAnmxN9N*b!xx<$v2%=^3xnJ5;&9q zS;PUzB2boOM%v>sIltNsmRS@3u{r67=bC`!4g!w#hNF-ZmL^vr3RXIJkqddo)3w1I zmxVrU!50`a;xV9)f3&|7U()as0{x%WfX)CIId~J=9=9L|mTYqzPGwAmi5uMj^>$ZE zT7UxiHhz5FlYGM^1X{a|VQo%~zDftHd(GEcd4#08g2e}O$IQJfTo(gE%0BdAJ{%m7 z4BZ?f3j8&u$4m?b5Nt^>0ZmK-Xn#F^T$HxbUyiEByT@NGg@;5JSuC)yF+S&Z?vcTr zIj%v!mofE<A4>$X<x=-wX47R6V*S9x>wj$WBcK40^I@j`RTJPA1kg>WwHrYHbvB@9 zQQa4EIk3E?k#AbMyZuIoYmA<iKD*kOuj{osCePXhtz`~WQEOwW^l%O+X+x;&1L&}A z^n-2i+RrH{GJ-7gVQRpq(*x%rRh-n%78x>8sw<w+RC(sezK^w`H>9`_=tw#Fc^WKn z5*SAx0OP3V5`u6LJ-8CRSgJ&?108;|_mMBf|I1ziN8^caaMaCsx&rQsraU7_L))v& zjCyXEimk$ed2OBc;RCW*dwQRcpJ?0T<WKSGH)+PFvJC?@fFbSslUUS&xqv9Xvg{O| zWN6&$Rt<^Hf*N^;30XDerfY!RLuw$QN-4b_XZ^w2K)hNdC;K3;*V_}%I9r}6TOT;H zMt(ELnD@6K`%hc(G%G=pUJ<B3O35KA37@hODa$-1zP02*U!z^N>pW%3-5achdMiQ9 z{>+Bm{2lSJmjQ#lLS7SZjVFS%COer(Qw;3CC|c{eN-yjEXY7XDt)5dV)D;Ih7n>4e z65BY_LikTUGrVqaz2LQUqJXV>JntQP?DsrF#jnf){~E{ehp@&9h6^9abV0!9QjZ(Q zlXL1YGZT&^+~M{%#;m&lV8<5+6=K`qi&}tAiq@B(Up8j}2D_`7X^q&4t9k`<_}h~c zDPeU4UZ8DU4V*b*l&HC_WiZ6T<Js20j%@3R<fex7IIX7*{v(DDkNv@Qf9)yl%>q58 zf@#d2(#`%RouI7~ongQBlCP-)z7r>AQG3#v-*Lu6y664z5L5Hmo?U5ix`-L(92)^t z1$Zl<D!dZw`ga1VqDCB->^6Ym?s@x^Kusba6Nu3Fl<VL7s_nRPe7L2SfT8rZM!FZ= zfhojC;7>>QsMmoddE9*{psQraG}*MgSD{tM?FHV)o#XDbele*|U`?8{=hn?>T4x@- z(1E$Lz?|I1T<_)*<ym{h7T>CR<Cc?AEh+)5x&<t0?`EH+C+NH1=rx^`CaC0Vyk+r| z3CLMzzbkE_;y+6CpQ-<`g)6vG+Rr+{Wi%%H+qm+pJn+w@2SB#{kQ~rIiL$@1ZS<ok zTY>m~;C&DAKKvds>nBEOe)Q##d9^c8h0L}bGPT{k-81T!LuTa-1L3>oAY|6wIKg&d z;~Lh*CNSbynby-#AMj`=+#HC4+u`@XSoPReb_Q;uKuR=QOI1%P4@&b*3PC>b09au( zu)XhTApV<+!VJ0#XqYF1j5A#BTMcA9Q0=oPm^?42AeqjG4jJxh`6w#>C~|AxE2qPs z9?!?_h%w;Li8nhT1d0rAh8|S;36ILt1k!xv*7K;9t`!?WJ4ti6t!h44v@y{|e9XLc zVq?nmQSn{MoP*`pjhy2Ygp~w#uqV1LA-1agtxz=wNQ>!a*;o%&M8ILhtiFsEA-U<I zq}-mY2o00iE7DUT(0DH&F+DNrM#k;XsD3p|X<n-}&I`d5NdUCqR%~%t6^coqq`E!; zk*Tg!Ep(1+e7#g@X#e!$T0h%O-sde>=+_!bA+#D|D`A2rg3dzn94{id0SzH=1ND+I z2^Z`y@1juHq}-$*)u(J3?j-Xuw(m~Ao}zS|dRc+`j@7J0<V(~_U_@J4zLzu)I=}$Y z$xT(ODh_J=txci*+C-bo?F4&UgZ16_KAvqgkSZ(NQLugdhoQs$tLEZ=uIG5gccbU4 zmlb&*O}vQ*BvW@5+<*fV{Opt)ruP%H8v3P?@INNfABP41#FPDZE!~T31yM;AO<7g4 zyaGUWk8yZWui`#WZhwJ7j98<j)uGOUQ?X6rt_jn}4}9JjbI58!_&V2tdva^Kc|*Xu z81#1l;ehJn#8~wEA(-o2IyKoQpUL{x^%jxu=F6n>c&|#7-ky2KQ>Mma*yRmNUW>)U zYhRR8BaiD_&wdkQ{<t*%#7|AFuaUoU4|-q(O*(`Y^W`uqq3J~y22{wBJg0U}b}9-O zZ$&1#07BXz)bP5|%=RdyqJ<2DNH4k_v#SQIlDzIZ&{0}|)$c4+si!(c)tkkRgNcn1 z(r6a;JvvUQFuj+UG%}HN`jSKh8%?#+Jw_MbP?XYmPUPYb3o8E`^BUq`6}g46AgyEY zB&}wuqE84!d<2SvDC~nTJz3qL!5?)nNJ(_m+-c2l=T5o(Jx!15V(U6*^tEH9bZIL2 z*X~?U5ipu(K%7uMZbE4g_nttBB4KKk*!mdJHT@hNb{(hZ4OPzco%ZavHvU+CR<*n( zG1Q`?>rI5^>bu)<y;Ibvb8s#Qg~}imU;NBEuRb(iKlOF4>X3N`MX#OzeXfSi9BrRk z1Lo?+W9%l(xq4Vi3(VCAk_Gt>nG$y?ie&lX63oL#)3Z2rcoa>Fq$`t9J-HfUX-(^# z7?SrM%uG(n93LKpBn9jbY~T0v!Nv;$#%lMWN+(cfef;X5hgP_1vbOoFf!~Q8h_7hO zJ*i#TnS3O<#wUCeHRa35>tOG4i^#MR{*W2%_%}D6_@VB8??5x3WdN*p43r-V<pE49 z@L}dcYtf*uA2KG89F0NeT|I$f>WyNkxXiLFGQRZ^|2aPN-`bnU<YAbbFoOfCOhALR zp3SS1e1PTb<nd^erv+WPsF$$FmEhV9X&wdDUfDMBzFKkHHAJ51DjbQC4qaHUCK*eu z29x3oBe>iVpav;Mo`x(bt1`jrYMh(7S4F|Y-X5OYbhV6devhIp@hK|P1A4E_VtMn| z4DNG?2f4`&iwI<Pxm!_HL7e^%k9MJmmD3%kbUlwdzw&3>eR~;og@LgXtXH-I7(4UE zN)xaTJ|`)rmn?>+LT3^>i$%yA{hSiaH%dkFTi$tp`M!Yuip%IE6jg%;Ji^o$G(Re8 zU_<gw>^WzWPxXXXwz5_8`i|m<j~0$LvPFH=leT}$xAWNcEr<^X#kxa*!m!S*9qsPf z6Ku*TLc2v@BZ#Pmv~MgY&tKa*cWpvRRkYoqP4Qz)@}-UHa*0v>NIABuZ2qb%rb6r+ zFn?oCQCiTiDpObjjLcsoiJ$zne`$5UU#;i&mk;O{?V)3opDb~=SV+J6?f<rYm%_m6 zu@s$WK$`PJhhR7d!c3By>ry0w2xe|P*@}6&h0kU*Q#FitZ4Z|$h!`|ww|II35mh7Q z8xXjJfGTgIo|@C+p&sQK6L`Kla#J0EOJmK4D-wL)U?{6BEM=Au*!!b!ZZ_+DSyiB5 zE1eyz$G7iYVG~-nMa5eGu?j=8s!uWZwBn#vtd5ZW3O#YjM~^nMXdw{nF27H-KPKEi z`%`!!7|6C@NqdmD3L)ZMA6v~9cRFFMKP$~Rd;;<-nb@N)3At&{G_5l%USnU@Z)Sj` zK=I<k=df*GmQ~i}<u3~W?n8Tnzl(sG7#YHasKtH}_?+ZU=%sJZwh43UD0H2s-1N&_ zbHr762XC_gXKjrrXZls#Hw_(sttA{reEtE<{=p)A`}6+^IdYr{SjmYKhUCQG0V`m# zZ<L!}SO%=xaRVd(SeJuQzn=U$ue7rK2L-EwDLRbn@Mf@_o0uIHB1Km&hDB<atEP8N zxOz&Pk$bIcSo|_mob~N)2wdA>ZqjNXzQT6D8H|Iz@`WqG-Q5_-r`plx3d>Pj26J?m z3Bygh1ObHv2*a0P3HA=d?L0Cy*Yfp+6t=x&Nd++*xSWHOL4%$iwi^&8MmGT^cNHx1 z5UtthGql%UOj-n~z@rrF>MVFtgyc8FBA*R<tNVhsL~#ZZez=+P)AjJGenvT<f<U*; zrW*vlSz6P+t~$*6JkW@Ey65fWB?HCTGV{=YgGWAx0Ehkk0$;HqWxed@3$43X!&&C! zFpxU{unGbItNJZi5h_KQOiA{lM6-RS`EMr@`X>6)dNfkN%1SER8sVENiK3S_9hJto zO<(61C$bLx&8-1|;J<+m{5u8cOfXn9h!Iqw09EeCpTKZZWr<TE=z(qIor&ZX&DNy_ za9cqeJ!jYK#6i)-H>C-i-%39Vxe%)0^O1K2SYT9F7vKZ%2MM0Reb`wYXnF>yF-r(p zfERw;Wy0}Nh$*d*d7>w}mk|2_I#EI+mk`t5sGoN+mt+2a{DYqb_7X^kjBhYuyRgee z(K-z8D7?CpuIn;S*>lnN`fu%%Nqs2id(vh;f*RWkCXe~;3+Fw1RpI1K&#-rYw^J(= zO_eRFRRrs7PRx<eb^Ti^;6_q&Ff8G+ryu9{@ilX$lA^VKS&5C2R$!@;9qzhLyI!&p z&F97b^6IGnV+dyz4cURc=JgeFZRZtvers3F^|UIBs5WjJSL`4D0uP#V32onh8JP6) zA3X@Nh(Sn$RyGhgx|SORPvGD07%;EeW!E-PPQru{OFELOzFbPSzIWue=4@lZw``%i zJ!PK7YnyUQBP2I-;+qob;?dyUfPM>QPW31&D$S~7#$S+x9PgJcWegJv$9Sh0H#uIb zoXzV_O_=hvltOpI$F7IhK{?<1$TmN~-vP_nb<x-5&<^>_gAYsecK}fnAKnvo6>tPf zH3GgK^@io7yzq0<q9U6U67!@J`d!6$D{Xup%k#=OQPT0~<Ytc9K3&j;M;7vA&NAJ` zC4@pVbC&U;e%{5DFU^@|e*Oc@>3bYM{bqUkN`N!@ao0NzuwLo^;~zYXq>BTcm)(y{ zpbH}@USvuv*=nA4Zcwe7&x|m!=Yy5ai>rGw?*$g@&6~UY*lBRLVqQzJj)0%x=|Df; zTujz?5*iEB7xNdqX@73r9A2o%e7xmr2}{nZBCNFvST13mT5&sTmrK~b50xX*%o6ri z(iSn%HxU*ec(>h0qW|zg{jbJEi!Z<}+W=MWt<a=<ff@ML-+^o#6v#n8K@JNAty0EM zzbwiId#~SDHP!fTmYP025-Ji&c@-7ry365&ADej%nlwrPe_1Iqi*gwxeZL$q^Y$YA z!9--P!@cSr<01ZY59ETRt1<uPk`$O{Kka+R(L8Go8gYOAoL}wx`q_4*qcEp6?Sy|I zSjsLsHSjG#NI^+4SA6axc~eZkc+uwn!`_z%Lb<m8k5md}Pe@at#S)=ih9o4>f)H~m z`-D_N;St%lC`2bCvSpbHDP)qJBuj*BBZ@3DXbiLTyPwfHr_lMH&ilUK@B4e-{%IbM zJjOluecku<xjxtDljXnnt?l|w!Rzvyc+z8*a26j(<N-1e^KZN!b#5|nwN6=ikg@wg z9x1O3@@623FXF7)WhXS6oPwxs`^!<An=zQ<?>g3~?@rOV_oBp6FJzK!=m~%gEIeMK z*irXK8S7ne1h%r<#wEkZHUr2;hfVdh^HjRv^q$9<%EDah_P(OscY_?KR+gzCYq_3x zT?MDS-rfQvhs%Z%<uxR~fLvXLp-cM%Qgl+$9aD}u4_(jh%@i9B5q<gUY-%ZSDem<s za73dC^N_BSV;EH=-3lEw20z}*Ug;KYC?v><ka=J+Rk6S=c*<b4x%{D9Ssc0xUlFwB zmt&?k)1!ebC-y4z0PSO<LD40?FJ`c0$2K%qkLVx|hH_-;$Q+Jfbw0~>+i4x!wW;d` zl?NlXoO)S0?Sla5?vN9eg(d=K2Snj@SWXiK?f;<Zb71naN2|<TyRD3rM_PBoh7GSP zynQ=mr}P}POJnSHb@J=yVZY2eVQx$)LW9QuX-q?9AdM*j0clLTUK^mxsd{hfQIP;K zGvlKuAobz|R5#xBh2;xEww7!<9(jXB{Gl3WJaP#*A$N2U^>;(9CFEbi$mfa4NvX!P zy_8&=W&KaYd34#|xL|4{#TWF5tM;4L+1tHvi8StTSfQ^gzYex3xQIj+p<HT!7+(zm z>5t|vR7-V9FE^7c*d7~~;_|HOEQLK@(i3iK3J_itx}%;);IO_1^7ninPH_Lx6#LII zMggK9O%MrWsk^%<;<Cj_xw$&1GPJOgzI9y>#8G&)Vu8hV>H)Z^Uo>{tef>q|kHdv` zRQtqQGZnf7ku##s+8Eo|FQU%a=L|vDrJ)OJHjpD3&tXyLU+%F3QD;TRNDjqUkU09s zheL&hMD3jn#@nKUi`G(nNF1fR`~nLt2<h3bX@kzeoY7pK_ZFnWJlE9l_~X4HJUsdW z#~dd>_riaV=HS1LIu9I!XF3K5Xri934~X@kW8mQg(3Q1Kfm;T~)(0JW<jZUsNK<*d z?a?@B8K|__;`@AL4ePWih>38|0O}2>ZZADN(=^b^*hT@xFlN(0Zmi9jK51stfO9LO z1a2DGopY}9?fa7#Lm-V0-x?h%JAjq{)T1R2c^|+#8oe9JWR&gpHkuGe{odu(Z_XJ0 zB|oC(SmA{S_kXR}ITpKPWaO9dlEtfyQB`Z7ZzpX)7jzLX;fEWo2slyN7J8hbC}tQ* z44R6QBRSpB#wf~l>L9Nt?;n#=B%RQ(Z+WOFEp}9Zo`WrX>x+8+halY7K*ev@|44HH zNQ~PUh>ujTe|WKYz=}OYJv2q4t^~`c<C=<g!9Cv=&|SAe3v%8w+?1bmb&J>uZAZzq zvD!C<JBM!yvfEb+iPqO5+_7Inq3AlGJ%|I^gA~IGh!e7QXH%!5XcDWfylJMcJh{F? zxV2#~8^v8-8@Sqw=b5}|vy|T$_`D6(F|4{_VviY$>fupg%thm8C2ynn5S>epx`*kK z%5OA>n+-+i4%L)e#J(J@3DpcPQg71J=@Sw#AA7W=?Zpx{VuiZ33s6YKc^2w36;e~J z^E-o_XB1MO=DzkRJp?PHK681eVPLQyk+zU~NybdG+&^eP<GJfE)PC6iJ!;Y4G-QAG zZR5ax+no*+bL#*VObgvwjuvrgLl2|5ZHw%1K5kN&T@?@kQ>J%d)7rvxmq{_5v(*L? z76>irYb6`m;(-xMo-Pmu*q|}go9U)UxdXJTT%ZG`+sMRwRZymx{DZ*qm+NZ!-)iOF zf5LtbCzj)=Asz%*I*Sca;MekiU!IB1xlpu?l!I?ILpBt)quD72%@-p|O17POcH_ui z*mh=rY|jnFjC+XCjXl0%pa}yc0w*XSw_9XOPfQ}^g(NYmiHykpHj3f%N7*@1tA(;H z7bZjq);_*&tJuPMC&@x@p`!-p7B~Di8|1%oll;%#Ab(@~{C8}W|0bKH;lv)e^5^lq zB~F02p>(tjX;u&0j4suP?*5Ee(s{uCPAq1J`FQS5-fj9`Ca#-TRBw$r7%XxBN!aA& z6IwJ1<;Pq<a3cz2R(fa-lCl9DtnG-C-J^b%R7-5P`zBy0*eVXSIfvG6?dysbkGNS# zO|!aH%`0EgKXf$r7=jBNr#Jq_gF*nx{|c9ESYFgg#@Q5DIKc9v68NUA9Mr2!c~OoU z#fMMegV>9grHc>|Dgt-Vzaohj;60Rz1d&2g$*8Ab4~B{=?-Ifj!s;^#CPv9oFOQ@g z3n#?nxnqZv?Fw{+cWcNDKiVc}#Lqev0rof`=aYxbOBsI8RP(XrGomz>@-fwX7UjNv z6up|M=Cgi_xPhZdX{o}BEfJ<~q8+&Aqyc~M58+K1R%zwz1y8?Xi(ibl%QPfIO-Q{W zVoJG`*62hfe_{B5ajj2I^fEbvnA3qfhk9;HI0d|m(7r5Cov;NNy7iUY4^#hvPRO}H zK+9@1Bu5i*!{O8&6hI&MvS+mRU{~4b4L-V@<g1nGj2o3n88g#tCJ3>XNZStg)$sct zI@S{ZjUXf27<lV!o=`FB0=^YP9)DFN<#KM1a>YK%C!6z-Ysxd;ZF$XS3a=L3RA03* zNc8y$<AbJgTH=o*NN-ck>)wSxR(PT*m<}2=rT3s=zgHG9@aQwbn)E0vuavQj-rvzy zmY~&FJg&ou9+0bYv?;ROQbxurrftbW1xqq{oIiKpKX^7Uj~{5TtqP*<0CRjNDmRB~ zc$8v{<O76+U0n>2BEE=5p32wFsp#wKJijQpCJ2%|J}%K@W{YaQt>Xc({9<i<_d9gk zZU*~ydS*Q206oW1EK*&Y!O<?z#lR|$YL`w=Mr~${2aHU%zjZxQadX&WES&Kocq1#2 z=V!2kS;b~f+d&UkZtupnPBOq|4C)~~iPTk@SySom-5tuC6vWfsw;y_Fc4A2>=HcSw z*WOwr%d1K}VVs3*ptf`ZYB-#9XtcbGztDyNL~CNlFVVC0^KFW1_;kd(tn$L>rcd*$ z6f>^vP2;~@x$kh9EB#wG!<YV~f4B+y>oe(Z*RZSt0E)ioD(s~Ro0uGHr0J6q%M5}U zf<youoLz5(%E6JjNv(<Li}Vb%19%dHQ;m`VJmduyO0gr1BrNoyC_Z|W2Bh$NH3Bn* zXtF)d*KT$nd<fZ~ht~FHYZ$P{XGHUgX$a|M>wuce-$*$Te=F7hLp%8ouH2yW-}SwT zQq*IcZ2iGHLypwcVUT#a;=6lp8#0zA64FsVkbvygWti^exfc%}@wt2p$MW_-U)*5p zVpwxqcF)5FsxpdeDlG!vPsb6lL5g_bRix8$K}LJVt4NBD(!2k7#;Zu_sJbLC@G7dV z9@P9rb)mP4Fq1a&e_r-Srgaf*xQ0X>sYl=ic!v_6YGgBMwv57OL(g@|i@Ii7;dswf z{FTjvh0Z|e<KrH}p|mxjIy>1a$M*M5XW=T4lx>CthoKTGynq!i7=am?-VJohH@O`w zh%Qy$l=oW6H9q;ynOmJQ%CD;rNQ5fp9Pg(py=YL|+V^VRHp>u54c{|_21XyN@&FkO zki)n%KO^1+BBmDvf?^3{bs1IqGoro*J{nNY0vixbAh9;*UOZR)MjRHXnauMf)O<I8 z`0-LxC&A<Zpe<0FYXh1<J5y*oiHux&S`YTh^idnZrNV7hcB`M9Bbe?hQ#=T?^&86D z_T5Meyu9<({*?2mQJ_IhkzpIkCMLqN{6~Q;<#;y$+)zCt4OzM9p%9MpY4!f}dsEzn zc*`8`VJVPe<e59Zv%h#a{MQzeA1vwrlvF{$&Pe(X>+-pj=+8*{?@(@WJ+Hu&^nZ{% zAbQJIGW8{bb%E#3ugkjMOP){(pi{YmJeEhYD#rPvvZEfjrfO$W4h_?+ddeOb#1Ryd zUY_(C>*U|mXQHvFHSkn|ipBL~;Zbr&3?1GMGB$#M6oSpuc~9dj0AoU|A#5kNkY#-h z^@B7?=PUD$v}@n#*j0AP!nfn<^{K<yobsDzH$1vR%i9RJOD0$%S+>=R5o$t)0EF!a zykOK3?kws6#Qu!nIt81=^x>^QkK>L@8bD(REY7(%_1IqV8-l4Z_esdPxBkY%1>hB0 ziHAi2oj1_<&zpfFKcvN|qgasCUVu({<vL8CQLAf~M{9D$!zJ;$*(X-CE;ON~8x7@c zvBC{Z&NEkWwV-ER0Szqfy6=EyLJPcqAs1=1+XGM1?jC*{TOO41#)YaK_tEe^wnk@v z^~Rz${|5e0j>zZQ3b%MTwe!zk<LWPm8M5CaLAHb8ut%0**=fr`=zr-ZLedQ>)ae1c zBgIOa(N49*We&;>kXOW6`lYHPW0YRN(}vq#OnQ(_oE^cau>RMsq<`%~B`lwZJUoX` zJWqo@=mwnL43@Y$%C5@`P&&~xK8Nx)!BU5yE)E(?W(Vy69`CJ7+7Os=Aw4a#UArON z@_0%lXjfkqxQdfcgtPAu0(Cz1-)!jSkp~(brCb&q%KnVdkfEYL#4G_mO6%}I25to3 z?%a(Z-UJQ_?ZiW0*%V=UGi2X4(zX-QMGXc;oEknIvx(g(;e5QLN;p~!QJJ{&<TbAM z`@b4?SPJmpDR%#BXWYMf=lSlt2mXja>xisJM1xH9)HpeUf`nU~WZse9xHRhG^Dl&O z+z;$rYG!kH4fli65V2n+)3+cz-PfwSu`sLd&mm?Zp2YSUv8Lsw8wO1N=S*WP9}mgA z#)(b980$cGY`s15D6z}8ndA7Xg0w5qhhrNY<Q5r7oVF&d>#13+kDwn)z;k+R1-n1d zjOA6Kz5`bY*3(0dWZ>T%INm|IUV5<;nIGDF**D}DFOeqe=SwQDRo{&|d4CaS7m@~O zgWffeEh-?^+5bWpupQxG2)7OjT1;f_tvhh*X!C_2#~l}fYn&9?bk+vD>WUeq{_?Ui ze2b|kvdPH>8g>Pk*+vQnb<seh4(U7r=S>rIU3Pc-$GdOMT&HVm3$t%sh!s`lo;<(b zd^txM-y)t$Ee?@L#y;Ti22o_T4;xWU=~*aIw~Lf3t|^1Nj(&)4GmCUn+#{uz4asQ< zltl&>+im+4S>LAFdV9%!3H@ULazoZn4#$94noiq6)Fp>rC(8DO`71f4YLKa#xubk9 z^ObKzB=f!;5wWJ#+)8&9xe&siT&))v6lvukHKs-;fsp(e;n4&U^-TAZk$i6Zo0P<Q zv_EPMi4(Ej61UXrlk(!0^gQ-;G7`pA_VGj<88PyTNm|0QD#`8SEG^SnoJeNT;WlUt zO=i>rw-Ptm&xn-E#*8j0iZ}SB^R#&0`2DQ?C2^VaHLNCh0s=NPK)U=IesNUuYei6k zaI+@qC!&04o5%Q8EsfG0mZD!(x@bLEd`uvMu+O?za)k|O)_4qdp%c&-YMo5xy)V?d z{Y(utK&_L8HPn{C%sQ`BDZs3&FFz*Ts7ecW^PtdsW!s{AW&J(Yy6q(`2j;LsF878y zZ7<#KWtAxDmIQS!m>DW=y<$i2zJ2=Y`Utj)(XdW=U>zb)@goS9%5o2`mLx?7X4Uqm zq;<;4pHN<q${sK7m>`+3|H|o5#eM3>^bc3me}6Ourok{S9*2rccHuzDq|5+fXGoga z3b#BHwH>;d#6G#*jP-G3&7Ri}ISZrghs-XUFZ43DR=rjuP}dg%i{QEFmc_z$XUQM) zS0v5Yoe40osmD)9FzwD(Z%T+<3hd4-ES$vU)_AFAvNMiBf74Zzky5yUP%B$eB+%&8 z!EvPVQzoBrPT*&RZj<z8-u`Ar=P@q+`U9}Ps{F(Jh?U%`YhEq(`S+90{#vN%KlS>% zT)Mxidj1<w4Zpgr1;MWZ&h07Nf#?I##?J1jF3GSwOu$%yf_^@_cFVIEb4COHjar3e zXoi5Q(Pr`eq4IYuV_BK@%Zn<A4m4iD?uNFuWGn#}vRX37iir2=+<W?pd=)(jy6+cS zD|%eg>){E_kX06YYZZ}If<L~>^bmhzIj?dDVmH6R9^ZRKgTxhBM6FT)?Kj1WZu(Y4 z93iRyPNo}6b5>QL9`3wT_wIlb*&QZpYN{+p%HBUx(UeHOD#ZEV1mif69q+RGL1$dJ zW#(Hg<rMIX3%iJCUjpjQ!g`WE_BlQ<8Z?j-*^CR;Z`%8`w#5@DNYpu<@s^diRUjDG z%CaUZmfKvu?EE_<@jMp{7l0>VisUfA$B3SSKOh6Qok@kWL4)r(V9$#}%?ak;3-bS^ z_gUU})S-nxp<8jiqgNPW)&|q=oq63z?&B`kb-ftdnVM8LN7iZS3xPwvurK?d<_1nK zu}`~U|58A%Ql$gDfv5rVu7HE7bv#$gC?&*%oD7UH+2DM(cs1@bqGlJ0u+;(3w5}ps z;jDJyB|M->ejHmI2=u@{Bm7_EZ5^h$VOew<&mj0G8+bYW*FSwo83pKN%oc!B6nD{D z7r!qp01jLC93ou-EdT;4`YfOyNuO7dW0hmVI?054p~_!XXuhu2{Jj37a`kg8evZY@ zIq-81{G0<n=fKZ7@N*9QoC81Sz`x}jz#qk1;V6nn$q_(#oW%u6*yhvgaD^PZA&iDP zNzhT|pr1Y#Iw*3v#v0Dg6yK{~6AxS|b${WiEvw>67;Dnt{LF)ypE3Jl9(tnISmQu` z=9R+C&tRLiO)zv5hI~L?;exuC%j16v<k=n=#5;SIhCJBN349P4)uC@jFSw`Z| zr~e$8pL6E_W;IbX80=R7h=M0g(s(hwBVoW_XdAAZjxlL2L~#YI!In51Zr_&XAX8hL zpQuROOHd&{<Xynyh2J9X$ujQ#HG2BZwc*D}n(9&NQRo#NE{S%J8-7OgSs*-A>e09^ z(jwhqozDohNhUkRyB7T!5qSeD6+q=~r*n0IIx2%}E5tC+V|%v@m}Y=(^ka;st_c*A zuc8EOG^dO-em?x?u>5Du79^pLvh_5%m-s#~S4O$6XEhdQ^roZ6VR6dI-em$ZPW&2@ z*`?VX>T;nftQ(_tykqfwXHXsXE6Nr{kw6cNQda;Tl@3Xv8(+$`Y(QC<iXul9&~Hq} zF3ZFAEx{8k9QutO^~dgD7=?;ENcR-$&7=7L`wBMv=zJ9{+FEp*_Lm|UA#A8C(>nI` zUBhXQJK(%<<o7aItj$+dw|K59VX05ld3N-$`A!N5+LZ)68b9B80U)_^P73i{mH#JC zF9bd_x}bX5NplCqAv2GcVua|BTwOolz4hW!W>F-lnJ>BhGSPio^!toB)7rY*7MzYI zF+6L>g@EhOTNO`U!rw92V{(za&OpU^cqG)F3S|cXQTN+N0qMwxrm#NUG06z%q#K=2 zeN%hSl>-@b-tJwi&Z<WQ4HvgE=+mR|JBT|t=-+7+|9LZ@pbSg2#0^Vy%d!s|j}(wJ z$PP?PKNGr|9-g#5%?@+Yfmblf#=>0@RH&sCc60MD&_Wo#3z?%@^+yM*sb8^f>u5z+ zPD)^wqO6}X8_6&1Q-St=JXV+38FKz!hnjtsf1{$FSbq6x&88<S7pn`^aC$mU7y@b- z2XM=-Ysd7mU6FQEze{5!EsDdYPQ@KF?#xWKb{=@RKX@w2IZy6wS=3&Q7~zp48BYuh zl)FINH|GTXzOtl?L9brRX$qRyJSOrePe-9NP8<`I_G+EnZIeU3BS`5e3zoY^3L+K@ zA}tZL2me1Tn19|!{ht;}evZt)JcJK$Q6zz58jw`(B5L8n@=+yN|2Dk$C!i!lq$!I7 zQ=*O&Z`+az^R{mr3~nsu2w-ii)LgQkomLvb0!*KQi<2`j5uyTCPOBvFR*jXxd|;n~ zyM}ke?gaE$XeiPJoLF^M<W4O5lYsJlD$E~2XYT(IU|RnSb^%pZP}^*kY{XBDW&lM; z^b62Nn+d!25V`0Pnc%G)nl6Kn)AO+W;o>ta5Bf|Lg8pYd(qAl9vy6R43^#&I;SBv( zs5`+}ITyq|k)CM3_R_XyaY)c+MO88-VpGHG%#$}eOB1wcsntV)?`u78CUo%mH*u9C zVI^{*$X>i}mvzf$gk_ij*uBad3>|1k;x;_VYy9*9-`k0L+j(mD?q9P{RCoT8GX@&& z-6nw=xdw2oCT;*u*@Hz3NCr%&>^lh`FUh=}ampsQ7zpz0gq^Zkdc#GHj8-nV%dN65 z`y=%r*sOsAWU(mRwo+_Zw9M8R6|CrvQYXE=7_j0>Z~7kPZOs?9`&Se1T<^Oav}gQ) zS^eAn1Vf80)nc)zK3!%T>B2;~jdWooXd@-+h9odv6B+6K9WI7t29JhC{Q@#xdv1=8 z8p{%U8??1xi*?KmZ}B5)it$L<*&mGI2r$JF1N;*IJc=P94P^oOx0Pd0_H^-@)}~T8 zjyB~kEm6I9kR<gXJl)<$?6I;r(eotIT0wR+sUXCVSPonu!Sut`aZ$G4VsL0DLB+sa zfMX9wS?8L@cNBW}<-J8xjb#bPw`JN(Y+9af$NK;r%d8E~uT&K%ksG@cY66ZfcP73e zFc_jpr+e(ZNfj`Co{w+~IjqY`DLIf|zx6U|m!@)y)p?E*B{TCg57&R_h(0HO|D`J1 z;(T_X;8y|$wgoEQ_-T|Pjvu~$&t-cxX>k(qy$NWh_j1!pGbzWnZ@YY2{&^kGmfW(8 z2v_;w{k8u6V+o-yS11g8P8~&BgT|W;Bp&ofTam|!9)K-PqKvBN<Ub{D#!Dx+>2Mv} z!WdGjSrta!d3&9<|MML#&nym0>s291De!xKO56?8_Tl$Dgy(ZX>Ce39os241I|b%@ zt}klki9V;Wsa#cT@n56uGwJ+PR>qP<@Np-$;JY)Cj}Aq5cS)5BJCxk!6J%^7t-s|U z0-ZJ*zE;Lwcz1uE;1P{?rCY={o8PLA+93hEpLqg@X$$HRn#C7~=_V!pUReRtAlPAA z&-}65ic?1Zn!WoBoWrXtR#}e>rDl{+SAj7D%eh!eNd)}jJM{1gi0#9)J$6Irr*v(T zE>R5WfW3LkR#oKaf`j$tfK2Msc`PqDVPSBTg?x=-1j2nS5eq&=;_e<RUpKxU3>Xnk z3hF>^y<!k*mlmVS%8p%ap_zFw=%1)JJfFR#Tx-L6@F~vH7MFsh<m8#3YYCwLSc#yy zD6Gebv@TI4cWUP9mmlZ}4$BA1ER39@^4@^K<yL1uq%R&BLw*_6SgL|jLUoUfQl!=K zWx4_yR4LldW<@HH#{s4#q8b(Xako+r8M_}5j6Aw8-0+O7=##PcH~HkKDn8J8nY)2q zzKVc*^?UB|)wMf}OaO5%FF}uba9qM>51IktZ8FNsemhiVL2!28u6oA(4s?EfMbzkI zbHm;)^FRm5y<TW((GtKZS)vV&>?s4<J!npv1wAe2_Ff%(?Z-}bTs^rB>)ML#d4jD> z0$u?rv7B>se|{c+uM@7mMs^AG&L1?3RzcoG-Df&pDSFfxJ4M|gtrJ!2%?r-7?|y1h zi}ARfXi}(9wQfny8;eci_947AqVJ*)SDx%SEZU1o>f-R=qZoEOgOj67H<ptE6*Ghy zXmt+;gxB9*jy-A9uh~%5SInMalds{tTcu_<Ulsh}{oXkH4?@kXQ(%O>U*r2W6|n&S z4gC~opzC--7;K|=<QA~elQ4E>-2N1}5jHBAZ~J4ml`I6r&KpJ^fFFCHP!>3+1Q}2N zxi8-L8fX6WKI0drtNH;4Pq6>mbWJ-q18q)R{}<nuWC|Oj$^g8P6!%jwGX0$<T`4LJ z*S#E%um0UK<Tu@nf8=$>OW}<PFht--!(Ix4G`)JD1BALqz+Cn}Pyr=$O5P8get9Ib z?}Wya`)?$x>qIibwZ!d)`1ROG8emU20p|E&8o2U0z^HGaY$&gXY$=fbxP74%A>HI+ zXh~_a?K43=ZC68{5%t)Pn>h!oRU<a7jYUV#>~f{hO!!!2Mi2iK#`aOz9*Yc}Fwsu$ zTJUkK+V1YFPin}Kk{1suLHLMi5Puvj<`=wJpSO%N{4+ur0*+rFyI6}hQDz*!YDn9? zKbbHczY?)S(NT>`u;W*)$Z)ujvzYv^=Dc#&tk_u-kM#}eq(gfOaIXYz5~1}T8{K4K zHwo1wOOYVg$h-HOGg@!doOb257`J=Z_T+@G!Le}Rou@<98I3b;o5lFNl%ZnKy#>2% zHmxV7gvhLh-8OY{UuRcH6$7_T@ulnHHUYQI`Uk-`ocCsRJ-_V%WGRYsP{iXwVU+dY zaN_9D4GDb|_M>fr0;3&m+CmERudbMed~>zTeK$JgDf9q(lUusi!+o66;*erni4cO3 zJ$s@^k^C6T0nOSAbYYd~(4_N0u|#OV1NnfISMpS{f4t&s?@*rd#`@u&{U$iM#{pT= zCj$=&?YpkhzA)HsxEpF6WD4Bk0b0=A4^h@l(srLFhlUX}ybNDb)Jd21pFYXX$!k=u z<MPhs?R1MhDOdie%D#G}Ij{g-?PXn!%oa+bJ)0GqXUA&zYpDrvB3*V9yi-}IqzbfH z4=9Vfw7OxhqL(<CNZqQ@4pA89rc@kW_P!#SRnhJYc`!BPV&)TCT2JsAs%GpOu6kH7 zAIaS9IID;cTgW#kF-a5;YIzrrVmhX7fm&GZ2?|={u}^DO;j?~;$3?!!Df;qi3x?!3 zJ$`%zWtIA^A`ZNEl_2r}J>LU}VeLX$iDC$TWy>&Bsgh}fwRw3y2HJF6Qe?2fHpdm{ zZ3LZ6pGtjwSJA}4o#N<TF6PgH!%?w1_)CVr{3Ngx$%22<c=xguwMNXJgdIg{eX1-i zT}AIkX^A`Fz%cj90?l~Zo}=W@T%dpGxmA~2jVSvJm0v$J64u&7T9F{EA8mwj4+4&L zrFwV!;&w!0&v2brQXBXBqtW_n=@VF)1=y<qd)zICz+Pns?G)H@pz<z02iRVv?uh%O zGFN?{&oTSFjmkBtC+u(4)+mKPt1oqnzMOiC07g~OkFjLbkyOwtjmnuUl|ky|5gj}? zle$eV*D5cSF4VopqIjf}b@TfzZ+09B4fnJU<iEM+?gQ+=uKC~3*YE8IuTeLdj;P;+ z@_FLDCkn#D8s9;(zzCws5GX56)ML;p%pO3kE?|{D1kU~D>7bEi+Bz2(|4-X}e&5CB z4deKf!MQP?Sw@_1J%D>4ti$R>w7;-=zVn2y`mGjxeU1MWXtTF4mV!0I-qM@rgR+6R z+J_rF#9Yl*lF*~5*O(Q}?}yIQ##bo22QOP)nQ*+9@#5_ZvtI0n=^`*~fK*haGcpfi zN<}^IP!`?$(S#)E_wI4M%$bq++=$6z*%ylLdsgiji`uz)I6kCCV6_RpPN*am*elON z)@Fl!lNVnD%jJ{|W4oKMANeH3C&Px!kS8uncH?k#P1Thc4VbuZ8D%0T@zz&+Av+JR zicXr!wW~Q%YE)BnG4eSSXgv9BG|)qcl;?xPKcwk&(+yfo8f2AjzNbp`<y0y1PMwq5 zPc>J!%gRVuxh6P}Q2})aqKNvnYz+2#s)&t;{J0w`nYO=v%gJ7cWdqrjU2j@$-Q_u$ zwvkunX_Mnr{i@3Jn6={;5lb}@(~PeN6I^r2(sNMesKty<Y&Ki4G7n9~Pw&?AIK>?8 z%a88oZ)-8ATa~87SK7@j9_W$~sg}OKTuxM!LkwC85f7u^>@G(Wb?VxBK{uwGl|`z? z`XFbq4{f*0;va>T#u|k;w;b`&f2X_I{9vTfs<Jf^8`f#w)|eDR12J_V@TloPxl}iF z2Gz6TAyuPX*SGUxVmDUd7*!zm{jaawA3ZmHR_aFi1ucWEX;;#-v`(<eLqKbe8TbV$ z0Y@{AGUF(ptbthHpv(_>=ib-~yVDEWO^=`0*C*k7{8zTneNGnUzp!6ZMFiIU$t09g z148XgheW1OJJTWY@r+PA(;@LJEY!{cEafHdZIlQ=EYLw*W~1??la~YgBmOY*V<PbH zT5M#?tCeY5KK(Mq!Fuy)VrP`NdVW)~flFhJ4|1*XKKaVi0ZSu}9i=CGRO7QXe4x`% zYeg}{;l^h}MsZS*2mB6Xckpkib$S4~o<~K5m$&d~n%S5iL(3bPpOY^yQUPJY8Q*=a zi#X`;<_*Zyk6MtSU@WiOZH@9yvovx$1|^X~6}W1m;_u4+vh(zYn0!~O(uUIe!&JuH zFb3P+dFMjiIcQ=MZE2cEwKBr4b3G|5a#3A~6EKuMZGGv&LkH6>20{yi9GzDE@*>+4 zd-}0{>&E;Jt}eg`Hy))(_Ira|Aes(fcOlmzWK)qC#`Qi?*Z0$=cWB^nRUcq!?k^<V z*}PL};LvG<(z8<!w3I+kny{HP$uhmS3s{AX6r|Y-H|J%V)<CJYf|Fe5oghc4XaEwQ zgPlBLZU;zfiAPwoD$km$%s}vz6?m)0D(M4n)%s2jib?k^-A69BDugq3>BoIYju0^& zrq;yJZbYc(`O1xJuS;}wR2K{P+4}wybq`pnCtwA$a$urM*ibHG=CE6jqL5_VW*ucB zZW<k%-?_KN<5Xq*)Wt_FdQ-Y0>F#+RhZBydpze$UJr`>tZpZ=FbLnyLvQw_;!LknM z4H#Tb@ZFj9NOp9y)!308Z3G*RTIs-`er@T{{l{D4XLYds8QAn!zX!>oh?nwcN!y=+ zGk(q}efLNH!*IJERDINq72X;^BV1$A19b%8-!ok#R-l2uVFZo?_!}lP7kR=Ryz^`@ z|8qymJi+fzyIAH$$spYsKkZqd8eCnTFX@EuK~N-(rDbwz{<QRaKlK;yBTIobD{J?% zilH)a^xseU)Lm7$Cxvq4Wkq>@$jJ4i<I+npR!JQ%T4G%S)~w&ryX}1Y!*aRPoZR;w zMk2Sj3_vu|Y~oRU3aF?rN+kIfq@J)DH=-RNGC~MCTVy)gG-Z0Tbz~xbslH=AKGFJS zk+f1?@Cc`o;rQOUD|5O8oK?Vcj)K_2>qmZEPdk}7XnZwpVRP2-8JbhPI`@;X6Ah)< z!c81n!tM|GUClc8emJsM|7MwVebtyd=*t^{^@`$YjufLWR>en4l;s*SnO4OST)C}p zpEIqBGXnCr1FPZ;1uvG$EH6ATI{}AJ4pZPUTSGe30zAxP?zwnTi%~pVO)#hhI@nwj z7xeMRF->h#Cpps{+!Y^;Wt{eP>O6he(Qy}~-SiEP1rSUY8aVqEx8aHENXlNP5N+~9 zid7N?(jnHigbS9MN;bJinKxPGk6ky?w;Fp#-FLm1vx+w{VDC$VqkBrjJ-AyYTLHc} z;IRi7w%ozwTVk2D&KZ0$dRrcO><)}CE&@IQF-9x7pIuX3j1QBAJ$89R#~Dj?sAmU- z*T)FnBGy#ILH<etjsj0#`M#`8IooDZvjvhT)NM)Rkq)lcvXdIJq2(edUh@SR_#XZ; zzPkZQS=SudtFsH)mQ9HEo1h!N6nTp07`7_V>eUXi>G%DpANyw00?ibEjWgzMcf;#s zZwT30BIA&-eUgMIu;#NO_cTuE9FmpliT0$0al14VOfDxb>x+GP<w8yrZ=7jazqtDP z<E^Jc`;T?La<!xT!n$8*&qAr>55_BEQa<Fb53&*P#iqP5Ny^RiDb(cMcq#w^a4UU% zb;L#l0ujG#PO9F^01YNHrf6RpOum?+F&j+$fhihjFj)jl(IR;jmx)L0S|_zzGVVF7 znZBz8z?t_LjYy=ELu*A(o&Q!2v=5$Zq^+c!M<TH`&)-cIbADY7XJ~B^X17M@)_t3V zw?5ZizyA2Jg&vnD@QQ+nN4bDKtsx#0qD_bnmcBq=v16D|<CUU`obVnl?Ld(Jy{XML zBj}84i@oR;j4*6_P%ajTy7ggh2E+Wb7&v_QtF9|pVj8MDBwyAam5a(j^;o;$j+0Q~ zWCtm#LUp7fR_r2q{5(CTfAsn3y4IYb&aUcZkR6t&5e8-vh<jdojM_(+lw(o`ww-s| z`bzel*UOGIAtReFQ0zCamyBl>&#sZqdLJF3VJUGlf@Q+zFUF2}VY2W1EONe*0Y6kc zD-Hq~U^%x9V1o`rof*B-#i69ojpcANXF3l|q?__-0zS@FZ8hvr)WuhK<<$GN%)dbr zxhR3#$$-a`(DxY;W#tFRIg5)B!1Drb&GJu#?CYjCqo*ugKqdN`^_)AHZU85P_%rtz zVRLW&eC*G${W-z@$5n>u=V~`3f1*49+d2;=C56)7D;NkwNnlf$B#i{)PRP<|fT92E zc^!H6zP2)cE8Y_a+XJI^6AvL+D?WTbZ(-6=X07O->lcKzpM&rpGzfT5H0tiaQFfvU ze#2O*?gtdu{wk!Fp~{520%c^8B@DTSp;PzsF+na_xTG*WFZrlpp}gR`=S<3k)D}qH zO}30hz2DDVE8ZudzFoju05yX8j7Vjq0B*tXtgU+9E!sn+1(0Xw6#G3?Ud@~PpkGhY zM7Ds%o&bd2t}|ZByKN_ByP^a=xCaajTB4nWv2E)~p}z`Nh8<mCBiuJ45WZsg);ZVg zk~NOxa87jfvP*tLXsQ{dhRi`vp&?1<duVNL%2Gtr_P53|^wcN0Pqfy#Z16fJ&bR8m zw)DZnQR=+Bp`ijztkjHzLKI`^YpScub_Tl!Rg9ub$n%y}oDyr!6w|Rfm{+h}-o@b< zPok+!wt~1r|K3s0TH&Rqw^VypNN$;A|E2`PbZ+0&LgQ<Bjwc>NzG*K*E}<QDqF<+H z_L<oTzr85e@s<J|_Q@-D;;lq=2C9UJR4r^Q7Y}<Ot?ZfLiSkB;b-|@q88-_OS4o$@ z+3F@Gsa{$3j$1Oi2MhJY^V}965z>N*iWkB;G{o&ggDa~m!f=C^8Os5#z(o5Y+S2R2 z8YLaFz{$G2%lFa|qmsKeiNh#jr1i(M4OO=H6@pKwzJGgS-^s;VkSkZTLKREU)XBN= z@^51WbX}+zhlMkkU%0Mpp;=RWk|^E>DD5PL1DAK^glM|oV(^%XX013rY`p0FtpHlk z<$#0Fv;;?b#(G@d%X_*%1po=iD7`LGfYhQpRm26|gY?P5=i(o_wb!CeBFaUyvD~%_ z+ond6j#p40>=(W3((SwCMTG0guvfF@<)Rq@xTC;69u4eRL80YAUZC=3m*f_z33Wqt zc7vkk=$)J=q{WE}XS|x%11R#Tw9g8S&?Q#aG&V#X^K?@K@BjdPiZS>ePvwPGM0C$c z8ey4KuS4n6O|olWPc)JpDC!q3KDNG_Z`8Wne#6*i83K2>IJ)rG3!h$3ZQA{oc#pqh z6<#<G`t%!U&gf#=9e;~*mx@9TSlI6PTa+6XKm4kO$ef;%&clF!vwRo~u{%wVQnngP zPfK+{9YD5T%w)rI=7+qfZ*6rQ=r7fIod5W0%|mrZ?rT{l)+iOjXF#ghnHHbei={t9 zeOlAFk(H<cD2z_1;R*r@KvO>0vRagCc2PkTVVQhM@w8OiK;?+hF99jJQKwh^;&W6w zLUV7(%i5@&!1QH~H54#gL%74I?b)VJ0Ii;VtK}J}I08g%?o;M5nELtP-|e@44#oe@ zP+VpkPN!a?9S2LypLVp7W=9GtgNQd>ZfQ3p*2_4cvZX=UQ}X4`<d}71!>0lj0yeL= zE7KOGY(O9k!|MMfXx)!w+<)u;GS}{6P;;(!Vl0N<f<*Z+{ZJ8N9w#rRi`%z4K5XLv zf1LxwqOWa*+h*puuQ(ex`|WF%X(T|ZfjpNDuw<2p9!6Q+aVaPjz6v4S94{J{U2@5} z{Hej7Q+@4gy95JRwU+(m>E#xA2CI)Xs5@j&cl@AMFZ$VSNDav38q!u2F!=0{I`r!v z>uuxKG!^P#-q#R6>gS_ueI`E0xV6;BL@HG>>Q?d9a#X+cUH59SzpBHkcw|A-ESy__ z28OV>5$vCtQe-wtO)|}bV$wrLsZw^6Rt%q!y-<V6IX=O~z2kAroxI$(WT~CqS8Ig# zn`_<;?b)&rvJ3{}{<?zZL1FFgYK!h}@%LCw+e;(^9jC>Vd#_q;FIf<-i#|7(zgDeQ zv2IuTU4H}3cl$0_I2j<2#kU0}*l7G88B0GBa1@Ej;p>F3s~(&38O@BUF`QzE{cfR5 znL^c+g9Y9B0p`e2^)>s$#o~l|dA0hYP^hm?bpjK9fELGCiUl=o$;n~IWSR`oos3PW z5Ka6j%*b_7)3`I>sKtN&guk=YTdgANL`^-fu>-eaca%nyvrGaC5}>Ir1cIBsuPG_W z3S_X^GR7;4M9*zdLJ4af)P2}qE?jz4GNieWt1XA>p6&X?JXEWBN7%0cPJk_|3;uc* z_^)rpbhr2wt)}e(e|-;nF~#7Okxi^cY`AE?c{cA0ZBUp}C=4~$5_fjCylA<{XAT9{ zijobK+5noEhRGjEnn4p~7<W?9ZzY&$qM1=rWF^dkv%I)w<H868uD6E4@g5vtPZWZ6 zpTT&$%Qr7syUz_+r(=7-ZIiM+^}b`ZR_EFh%j9%76UKQ8SoqI8(6HkhwN@$zG&9C> z&=Up-iO=maY|#%LO7<KrnU40ga|`fTH~1)J_^5K?qL$cL`RonR$kumWOOst<-c}nd zs9(8RESl&$7Zd;Oya2!cBWDI6-o9%$L+>!Dj?s;rzGf3SNrzP;*)*VPc4e@YzXeP8 z$TE3P)HTVkf8~GMHT(fCa|9H!k2KED2(XA5iPN{;SkNF47H6TxZbMhFlOQ%VK}X}c zK9Xkv=Unp<!0>A@paqEw_!r&ynimEXrG94|%%U$LGP#ygvh|6AfjJ${dz*5X37XW~ z6Y!0nI5_+s<==lCP*SFN<PHdXgBe+O1=et@3SiX{kOiKo7DkcE0>|S;ZuIc>vhxFN zkS}Ac%c0>5kf8O&7A<kd6Dwc$KFtd*I2h&33Pr!?%((V;pD<dy8c-}-V3knjiQR{i z&R7aj%_(TYd!I~*d1Bv#-WM^A(RSdrY1~{jY++qTeOPX4uKC_~Dd#!Yle**>B3tjI zH)M<UHd_shktR!bL4k!LgmhKcWZR2p4mvN5$Y8$@zvD{MV<WL}QBnQZHxL(RSNz;g zg7;nlR*$+3L^P~x6?NORI5CCdKoGn-(tey6`sBQIgoZ$INQAajzyif8tFzl&<Fu-) zmK7#hjP28<IsTx-5^nS%ehJh)jHav$qpfdKPNEvQDKyYj(_CU(DuW1{BW;yma}2yP zp3=&=mpv6ukK3`v*F3<KQ{766+l!#3f{GLVvOIp=CU!R%>>XeJQcYB=XyGPh@RwdE z2nKC#IZnFx#LharLgrb>k=;_R?9z2s_S>gC9BZ_;mfkrv9;`J50@30~sF)w>Sz15Q z)mB5Wj3zAGUfN>jhF+eNeusSg=%KilYIloB^o#4mJatNPcklVHTeib!A9+lj`gHEe zgc%9A!4x-xdYZZ(+y@xDG29L-q%1zw=IrHGD?9wC*+W~E+&<;Z!#%e4wp%WwaAB<Y zrbU2d`zL7l4#?QIgN*&A(n+Awy0Go4GC$EY;e=_XPui3GC$18jYrMo4!c_+T1Ex`1 z<rj?j3$-wL+kuQuGnnTa&S+UJP08%tUAtFnYx)zu{f(P9m%Z>1X($bC&OalaChU4P zvHM}UuMua&WBCI^DoRjUoHUcQpl#aXB*SDaJaPE6Y%imS$yzu!Rx6#w+#D1hNCb#S z=ve)U7$`gq1?WX{YsGl~UGs%p;8gf^o5GxgN@{eP!pc}43RXP7+j$U0*cf+(Enw!x ztW(15`Tw8%wZJ4$R}k(6JtHj?q0a~qV(A*6c2VZnIR6)cQ@<7P(V1OD43f4Y`T+e3 zLw*pwxM-7$x9%&C<uvsI3{~b(fBlL*tfk9kdW^C*=WPmn>9Uqbb8IQ^Cb2xXVq}{+ zDgt(&m{Rx911kn#B!CbCXjK3t5v2IsbMe-vv=bW-T&~J>*QBQ~cr!)qS8N=Kby5xT zSE62a-B(&AJJLVC-gN_y2ku+Wfe}NR7#H2!1=<K#6eQbBHwR=IYoAQDnIsRK$3PB} z{82)u&K}Y15Q+@H!nt%IH)bzr!vLz4Jy=kpO$PzxAw6YuYu6GAq!-rB6}q{^<*43v z2akN6Vt=JJ{TCT`Ktqb9^+KN)j|Nj}V>Pq3dAI<xZV++>=-!1Q;8lzsPBQ}DKo^bO z!ao{BD2JrIH5Q3c+J0|Ihn>?#eY5T3Yn`j~!xuh?S$FPqWE1c@gdX_~`Sr@aktJhE ze$P?<+yg`kuGrbe;bODk-u~u3@qi6pF25oUo-39<lImo{ugRLQ!(5L`7WWF2*+A>a zl3YOV2fZUU)IH8+oyaC}aOAuEuv4mOQTv<CnP=C@E|0X6Omh`?wl;PYQWGfHGJZ0` z1mq}dJOH-z5E+bj&~1Z?LBlHpS&~vqzzdr`eVT~w;J}!ehi-^-?K`)Wr)=So>SBSr zCxw=T_8rD&*HJbY4v7LA(Dm<!!g^3X%A5}yd&AUoLO$I-)cLAii=d-d9^{mEFk=iA zqmaBeCv;t~1~1Pl&3M+gUt=&c*LZ%geK0!>ijm$&Jzk)=oI;d)%gvN?>O!-mKP~Nj zN-U2$C|_o|&qPnl!^b<ZQZsk?YTjr^O$6Me064iaf;1&8;N<q;y-cbo>O?>Nr;oA= z@|qa+T)|G<o%>>AxGS6M?C*s>3NFA_$Jua%<=i|)d-fF?H1}NvGQmtKD&WI2MWLnf zmRPEUnINFWsAodlPV<F2PXJs7{=uchd7@x3R8@@%6x9<NR82PQ`b1=-iHd@*pN$l7 zJU+`s*Ho-VFjP|i!dv;?Tm0reZWwSEz_vK2sSQG00R3a&g!6CxIxpGhPg>#*tAlnp z78*-Ex~mTmM*h!UTYw3Vunu*#3zd*U6Ho(dNg#*Lrsvl)T4JJOX{T%U_~8>%<;wwz z?;n~hu{YS}gHuRT-QsgwHzESHL*HRAe`dCQ{ZY;(%1Vtb#v9_h$8-aYxk|YxQogtD z4hVLgX;R`Menx25Z+%=CBSsbIecOf3FtT77$GBtGzmvv4ZNFVzjlc0-l;C%?;Efv# zEGgcK>6P^>TI;q4NQ(EMg<K4V%xq$B-(ry{=uTgd!LB8eD6eEMyi?3s!(hJ!s?CZ9 z+NjtCd(fakbI7g-3W{5i%cx>BkDvME&a3^we#8xx`n-KZZe${Aq(;ao<eitb_?C+P zMaWW7cRYx;AV2WRGJ}dY;q66HCQW_g9zrhTmEaEwvFnTbpk`&+c*pecx~r%dN2?f7 z)xiDMcb^1oQ)Ha-gihxeKtHHX{OVh1A1?=eVf2IO;mBn4S5XRxeh0oV`s=p`U+6Ak zGWuI&&t`-IM*sENIO}SzoR|c<GAL0fqPp9V6tSmx8XrW~$Rkw*Pq?EPf*NJonz^F; z3E&fVS1U0-@t{O{mskLiR2f=i_v|=fy(JGmR_5e2M)aKH6lfYL3j-hTvr(V8^`yK& z2f*W1=%!14G<iL$6tjUUaXUv=acs&lU6Xoxzg=oZ#Y)7l?1(8mgM$a`JV#-zYCp0@ zv(m{7TVuDl-OZVsGiV&~+B{FLpLo3xDv)Kb5}}6*y2KGwKJdy59IuhyQbn_&9j7GW z+#D$>1P2k9WGeM&X{X$4``o8y<5i(txt%9ojO)rq3&ZV7mTiIe6g&~naCcGN50FHC z)EAD<>2l%nq*RS=ofRX4b<gq_KH#vP*dtv<eMroR*wDUyU%-g?^1gR0`d1IDt%5du zg^qlSe0@_3L$|-5+qFyao;SeduuOb|)6JKYgZkZ^c&x`Zw&=Ix%s=?bMxFw*8Nf2L z+op;@(mQtpac7yEKg=oEeAPDhSH3rw(kVbk8P1C)svxf^e&-l1KxY^d*+4v<0|Ncy z2kR5iFb4^zO^;=;xbzaX6*#1teu!fs(t*R%)+N$nTAP#evL8hdjs=*83-1lTulF)O zLjKt~1nQbBWruUGSu|;q!J$D_!Q}5Lx?^W`ny`eneVy6<fVGbsGKMD#{8)_qq8eMP zE43DuR~qRD947eyyWp}|T$r0a6Sqpm7<cA6&)`;jYG2b!vtZn+3LK0qEiZ~c5RcIM zVi){%9G>r*J_5K^nt=SAZ|F7g0kS{^nyqP^xV1BD(oHr$t{x_ZS;b;9B{A2Y2}#5q zmbf1-Kc=N*W@DLq^)o{CHEk&c7$3kc#!Tab85iRj<AXg+7h~A?U<q(B*0*q4lZNnG zg8P`qSk?*V5kS*QnxWIDf&Zt@Xq&RU+qSU_qav=C&~GwvO8wX&Lz3NkvG*mcu7Po8 ztpqH08K2r?*3tjb;fi4mb$<lLTh27ama^TrR$Nb98i513khc4^{TZ6`Hjf%RLddC3 z^TU|F8@#zs0qe0wF4U&oCB)}x;pns~0KgQ$0n{4b(~iszhL+KIJDtnAg4*<lb8mMP zrI1|<MN<UE#G5L8)t_klS~=xdw8fp_(>y`HSt2{;{nr=5yk$KcVL3jpjv_uvOQ<2+ zz#Wf05M9yu6>z-zYK9BUbMB%tia?3YI}zWv2)XJrVua;0B5iSu3bIn*udKGe@PCl= zg|MH(17FD-81@1Q1Pt{;D{V79q;L}vso7kJ=W{#!`qb-B1xpN?&sblSHb1<>QbD!9 zE6C8N9&vq0P`e+I5jNccdoFrI7C3LSwG<x`2f)gF+(ddz)LhdBorCvX9JqFGL8`2H z=um2Syp4ExJ&#fAvCjy8xZ9+?26USoLBZW70)<wtsaorEo!42nS(Lqb5>|5Qcz9cj zj!&eR?q+_s6~|xItc@^StYzxY<~O_h|7-N(>ubZupji&@APe@!?I=vxQkntLqW{jS zSedsr83R$1r`k}wHkSJ^ncFPQ!<C+d%Lyf(=l9yFw{+e9)kttYcg8-%4a@eR+r`L^ zM0A<#!VY?NiSmwyJFm}7YI9yU9z}PW=)Nlq&n%T^^F98$y(VfC_pfO<6<i<3O!Htp zRPqP~dIv=)t%ajk(So@qQka^85ZxgnW%ps3cN%F|6obx04P^ygtj(pRuD!OCD(8zH zB!3??2Zu4rM%-}UmvoO%7ucy#$V~Ub7475+Lo?~#FedqVbp)L5aY);*3)Yglvg%OD z8zm!Py7J6SpeeV*`AFl0DW7^y)MtcVlk5m@Tl4cyaarkx>UUoY`ix0{Xu>@MqJ2a? z(qw{Y!^p)95!V?EZOCwY+__>HL*v^t-hTyPXtHN`RBxV&On%EU=EnrlYRD6S_A&#a zxphjBlG<PpE%j0EBTWJmL<?V~rw%~0*!?_SBO^xbH6Ol18=eohpAXAI|3%8d|9<%Z zHBV@4c_lCoV5E5@QNH2t%(wCV=sl_Vn$d9s)A+evjIeIlSGn`o*SOI!yyq?k$ZEd} z_J94~|MGP<?MG+lxEMHQ0}_UJJWZc!3wo$5h|b*?u*6^*Z_~Dcytp-EmU%6OCl^cw zoqb}7v}hdJzGlqrfl_!`fGMx5-7(fM@T1ZA?#Giz;^DgBJR}=!d8`|H5o0CA%P<cg zs3|K>x|oKDZ5q^4vZz1vTuZ(^<IukFYRhX8q%w!8(_cl-uOrU)t_>%i0*E^iEGEF& zNiJGp%&3L<w(4@dp|tmOM%r0*Yh{y7u>96!Vty_zihEzn3b`_*<a4cfyZ&w4Ci(E= zYNmeAkg#P`RFOR8GC{DU3s^=8kfMF;%lc!|TJQ6k6tUlzd<IOD6vWDV5+k->a5A?% z!b0yqjFttz6_j|o?@n{k1hmPkiCv|&itgCb71Rs5f^TGQMBN|Ae<!CV@m7z`b-PL4 z?NtxtBGmeHR-ThE;!%$OHcw*~h@=QyaC3&hxjMKxgUeR9^Oo!_(st0C;YSm2;3p?w zc9&nNu?^!drqx_lDj!;SL`qvCNB4o%I6v!n31c~Yd}<gh;%Ks@-(akuc<VJdtk3Bn z?H%OM@Y2Y8;w6-MA=O@c!Re@_2cy?1mQ;xIxF#77^3f>Gpi$819%T|V3KnDy8vEvE zel$GSH7M*uFL~R622Qtqu|_8V>;Iyq)hTUWE%DetYZRQPOLe}}3#cQ_m;YF^e)y(K zV;+Fq{WAh?i>&V&^9l=vCcy!x$@^eD*E{xERkj6x^J}i}089WTn?L{gc3**Y6&%p* zCV&!nsH=5%8MLy{E`{QKj9BN*s36yv@-DH$M-OkmW>nF4x1mg^G<wOQ0YUba!N0Oj zl>qKjx<?IaVh!UJNV<U^qm>F0*JSvPi?%-#cE5e)O;v%q!@!o&cN<9(&V$_>_i_z` zW1ZI?ux_I+uuRj{Jybp;N^QG<k?s;y4jW?$u*x+83;O4ie~!k##oU;;uhH-W+dOmJ zV+U0Hyo-2@3#`0iBgl@6(``THd?KYpy<QQ$$e3d9qNIhfv%4_KgGRqqxL2%Hd3ux6 z%7u@2E*tY?S@V69tncZJxpjff4=f+Aco#Ot(yc@e4N3?}M1$m;n}9J}<5zN4wWq)Y zbL;NosJ8wd(<s*-)s@;tENiQ(&^Nq5$N1hr+7-|(^cru01zt|pTr{2m<QFF=U}3CE zk4F(TfVc5WPZT;8SBZpOqKud>QJ&z>TOIzJOB8TIzKU#P1;GZkJC^>y`f2*-ga1p0 zq8u5BCSFE8lM#Cs-LiTq<uJ*+boKhM8mg%8qu7gKCmmz>wfarf&O3=;KE1i*4A+y$ zW5b-L9%#w{NGb|x$4G2sG))QxrXd$i?A;W;4Nbg0*y6E{YIf1pOt-bn?|L4ueMkRj z=grofQ3N9_9URy<In!1JQ31=Kcqb}1hYJ*{jFEg7J|lK@F?e*@UqmBM<?H5D^mTQf zUzA)E1W6trmuNDxMYZ16f#lJ-pmXyhIhtNDF_7~a5r|$%J4uk?9cd8Royps2-jIW7 z@;&b;6#KmPWNxf_G^cpPw(DCe#!o47jJqS;PlDwp2cKGKm%zVSw%g=rx}?QeOpng$ z(cx*Us}mx+_dm3`S6sW6Q*0Cm>}z*&IZ7uhIPM58kB~R4n)pHZ@C%@U`~{{&bf?Dx z@o+S`s)1(FPw_rNIiE==Den|%v<iV9ogr7Qi#eiq8WUtBKAx~M<QA`5f7z<B>-5kc zZyd&ThvI=$Nevdz(gO=sGh7<Ur(S15IfV)dHijO%UpZ}ZNVds=Ceo!axA&|&RUhOk z{zQ;nY>a%s-sozwTR97rJ`1^J!!lr+`HVh7IhMcB&Ur>3;g)`3yEIcD!P$=OR}!p` zaAako70^dGt#a-;J{Uy--3t7&WoQsm+c%UU1(l9snB59S1H$6Yji&7`&>^3Tsu(^^ zs55GBkg%3gW2IQw3rUn3zIzl;+2j{ow8i6%VOO@~n}KQFlCG<HmpmRwt>H7pv?aZ~ zc|GYx=&_ZjeL3FytX1=skq)iP7xyNWe|tQdFX5bh@4qGio#%85t<i@KCuSXQaqrlF zd>CgB>z{oMQco!gD@a4X{Wb7@1}m+tFk=C@V>(b;OFWKi8JzESJXinXzj@;RyC-$# z&jBUw?rQAR0f#XBP^2wt+PNOMD$c$6fpywrR@%%uwO|Gu1^rH6(9u*z3>skwP62T1 zLkfDP^#R!^)%|Vb&tCxv{y(d$&%5USnwk>p9MFe$#qbkgNX{mW;;%{m)A5(DKZ^N< z@}$PT$n6<{LtS+iC}1UroWi5i=ezBRy7?Pd@0&FA&z8<V<9qOu_m+f!qM<U3@23I@ zk}eHgrSQD><GBW=XRS1@cN{ZBvX8VGB3a_J#TPaz$dhkFU-D$=AkOp05vF+ylDRb1 zmiY^Ui0N<E^L!NuG}JP;yJ%{`to8YKp)l6@87=NCXcP#n8=$^fLNDJyF<f&PEn|z& zEu(WNEr8MTci-P%`nm5Qf^gaZbS@8D0G&(8d}l`NR^Y-j&rJm57wdl(<K_pR1G^}2 zrZFkZR3L2$fVmX+)iccIIk!DgDTA}t4qOHW?DM0z8TNVDKqPSyfO}>li4$Yz4E_8t zUA_qM&4>2QgqyWAe*fNo6AGma#%y-k4_zq$q4D4L^hr%E`0;`K-T=>ce|~v8{2Hb# zs(Lh#MZGuBHErE2^=W$U&5c0m^`8_I{?eNJ?RUWrVe%<JOtyCvh{=XAZckjIU76=5 zf`Lt)wKy0mv)#d;F&V8eBMvZHXBcrB6V;Rj-yXDPErfYDpLw_F|HQfs=`*6eg)B+L z(fGB=he+t+E)m<+YZ_<@y<89I4?pgUTPaJRZha>hKINczq+CHFpEZA5brdVxLXWcm z`V>F`=##4pK%ZQSVGIMqkDvHirU04({Fnf=it+%^suF-!XWW=zP?ZjYs^c)IYT<zg z!ZO!T!0HKxR@Ek9Xw|zGK&vxOPd^|0b144pW(7JFNj#eeTSq)Y0qcl%wG!lVk5z*V zx#k=lOtC?ccpSuQYI34OqBO6CJQVm!m3_%`<8qaahqT>Fx!K4fKgvj*A3TMN6tMck z#)rV_A<`5ObajNwJn-}0MnH1k<7R!$X!&PfGhNvh1C9g`00gHB^Yp{80ASdczSFti zP(e0+n#F-ZRthptg5QSnBKU{`Z@04&$!}@<vp}40sDQtHZ@!Wk22cWrCK*e(NR13( zF~*X1>K=+WRhEjRqMko+IbBKBZBwcn3NUYQqqhsLc79XXadWp)$1SWqd6tGL=u!&< zdJ`f*>R<Sa-b5o!zq?DoSOnIaICA>&LEj@nnlLNtLO6TXD*w>nta~N*0Si>z4dB#^ zPkL0Z76VomsYaB<USDr3cW0SWVGCb;%G0c0L;IqZ#9m%%xutxGzI>JV)s1h5T2Eu= z23<4`*kXXG0$lcHg<j-5K{pbVvj8`GZcqoG-0X1v^T}UtZa+uke{nQOeIP^OfQn^l z;Fz&6mY$=uh4{YbC9ZcFW?yrm0EVFTo+R-)x3=MgwmW2BnYoZVK3F2de8JUsc`sBE z0u#_&-5h>^`p#c%{?B0B3cx2axYb{}5L{Ro9s;3w{{uAc^}P30kT1TgdO9mYf5Vdg zN5AKRhl(Rnz|{x|wMsTY6QhYO@0QKI`HF2~4n#k;XuhnKsgD2}W)9(J8fH+*hR^ta z>reR0uZ9yHARPa~Xvsqg;(w`I<tEmY+_c$2c{$~Zy(0PYak1P-4WH24T;fAs1&CiW zQ%yV2uP@Hw?^Up|6*(@3P6Y5KMq{|qm5Ky-h(2vYPeCn)iYi74;R#{Qc6}ykccRAh zDzwAb`8=X04tMJ3*RI=DAu#;%BAX3A>vYF&Y0^LO^{1r=jAQ;pD*r*G63j?esthP4 zg2QmJ-UN;!DLW+8gXJ;9TylS3Cd=NYmPnb@)zULH=}La5-Ma30!oJW?>$Y#|+Yph| z=VKJxse=a%?tUQff&+$E76w?cLG2r~Nzu0m%d~r5<^^$yxH#y<ZDq7(x33Ab_<!?s z>|LjuGWlG`GqW5|{@EhMr~JQ3Qe}rbrA=SVjS?gB>}ycd5p;5Fw?43eelrw!E#1X6 z!0`ZV!U4cTX<)5zdeXp)r9Y(l15YVGe*c@-R{6iyFTVa{#uWU*_}3n75hUZEM(`>) zlsu#T9=MbleF&ATeJ-NE<^n4j;MqEdt=0ptfH)df&-G6$E=%hA0oklKGnR6FH;-f9 zG4-_V)lEEmrschft4?8Qipp@Da9Z^I(_Ziq+qyqCKaB6QW7+u8zp2LeA#fXTMS93* zyW^{0%<8dfZM{ET*;ReIjSlG2vkPz4d3yL2x?X7ixCG33uJs2C|LN5qRQMCR;^0G< z%fQ{n-;Yc$xbu3R;5C&AQKw#g?9|Iuah@H0yphK)@1}A>ve9Al$pZc_zXOk<0j?=n z`U7~FF>B1_^$UL_KH_z{ezeMV`R%XvoUgCVPrO$0yWaL;WY=mNV>b_{xO<T<Nsky6 zd!K|X;9rA0nM5fYb9bZ0V$9<`x)}Zfr(Ut`o&sKk2n@x4frFgJzWXYEf(h=<FL37- zaE~r{Ydj7*eggRD{za#ONB4)8y#H&G4ZLA;fKJN7Z0-TufP`ZPbc_M!pf8T)-^8?} z$T{q#Zh76o`ya}_zt#V(n`IVNf20$*MyKx{@766%XLG);omI9uZ^A*9jHD|IJ3u$e z`RYucc-K>*z0JLR!oL-DXXQUsEPu27WAmG7`>eMAX#CJ0AQcpQKPGFJ<yDg<d;Z>- zbm?BSu<4l{=|z)HW^-+F@#eU(CjDn3aKK>Oc}`%-n+R;#^Gj8P`(6X~^)vMwKiqtE zZDO3GEO6_q$#3o@o&r{#xzDGnwK;I`%B<L=cxuyXCiY9Bz&*|m^7o$(4jNcGqun79 J4vPK%HvzN5X1M?W literal 0 HcmV?d00001 diff --git a/Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/LogoDxe.inf b/Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/LogoDxe.inf new file mode 100644 index 0000000000..ea07e15d1a --- /dev/null +++ b/Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/LogoDxe.inf @@ -0,0 +1,58 @@ +## @file +# The default logo bitmap picture shown on setup screen. +# +# Copyright (C) 2023 - 2024 Advanced Micro Devices, Inc. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = LogoDxe + FILE_GUID = 76ED6631-44FE-4ED2-8B5D-1B5355BB25E8 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = InitializeLogo +# +# This flag specifies whether HII resource section is generated into PE image. +# + UEFI_HII_RESOURCE_SECTION = TRUE + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + Logo.bmp + Logo.c + Logo.h + Logo.idf + +[Packages] + AmdPlatformPkg/AmdPlatformPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + +[LibraryClasses] + BootLogoLib + DebugLib + PcdLib + UefiBootServicesTableLib + UefiDriverEntryPoint + +[Protocols] + gEdkiiPlatformLogoProtocolGuid ## PRODUCES + gEfiHiiDatabaseProtocolGuid ## CONSUMES + gEfiHiiImageExProtocolGuid ## CONSUMES + gEfiHiiPackageListProtocolGuid ## PRODUCES CONSUMES + +[Pcd] + gAmdPlatformPkgTokenSpaceGuid.PcdAmdDisplayLogoEventGuid + +[Depex] + gEfiHiiDatabaseProtocolGuid AND + gEfiHiiImageExProtocolGuid diff --git a/Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/S3Logo.bmp b/Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/S3Logo.bmp new file mode 100644 index 0000000000000000000000000000000000000000..137f4dcebe4ebd77d50f35ed3b31bf76c0f5f55d GIT binary patch literal 964114 zcmeI*zjE`um)LP-CmE~SVz0nu`pl&EZ0BMdw`zPTz7I7nJn7S<c9AM=+F#*I*h((8 z@E(#P2?7V_fFLD{^4IUnM<gW@;0M4V_(#;g{@cI&pMTypfB*Bp?sorOUjN5`+wK1U zKkat^Ww&qV|KorE^X~u3N19>!_qN-~|GT%h?nVBU(cS0g=kD_#pSyqmfB$Q@dwi1N zRR($E@m+>b8NPPAr=1LsGRVl&s|;^4yvy(@!`E*2x|88ih9?<h;`L32cNsoq_&TTi zD6da4yvpz<!@CThGJNfJGP-+zl;KH+R~g=9c$eW*hA+wFPKHMro@98H;Z25j89rtB z+U?~3-PfZGPcpp9@Fv5%44*Q5?Vfg$&E2C6&3~^lyvgt`!>0^i-KIT0%IlL1uQI&J z@Girr3}4-5KRwFplMJsiyvgt`!>0^i9m(sXygteBD#M!$?=pPK@YQj>J<98o46ic0 z$?z`2rwm^m<@=+&KFRPZ!<!86GJMML)iHlQ%IlL1uQI&J@Girr3}0;#JbgXN>yr$x zGQ7#~F2kn`U%NNi{<qzu49%9m%Fz7xF2kn`U%R)*oeYmMJjw7X!<!86GJMML)fL;* zqr5)J@G8Tb4DT|0%J9_{>FcAsKFRPZ!<!86GJMML)fKlS^7i&5!>bH$GQ7+1DZ^J+ z72Y4^^+|?T8Qx@gm*G=}udbSWKFaHp46ic0$?z`2rwm_h6?*%6l-DO2US)Wb;a!GL z8NPO(vi+aCM;V@Ec$MKzhIbj7|Gv7a_4p{SPcpp9@Fv5%44*Q5b=B_aQC^>9c$MKz zhIbi0W%%l<<m;onKFRPZ!<!86GJMML)m7KGM|pjc;Z=q=8Qx|1l;NwZ%I}Zz`Xs}v z3~w^L%kU|~S69tHALaE)hF2NhWO(2G`+xlGKIC(6vcBE!r~QBT^V5vUApbS9nt%91 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 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 z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILC>Quo DNG4Z* literal 0 HcmV?d00001 diff --git a/Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/S3Logo.idf b/Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/S3Logo.idf new file mode 100644 index 0000000000..3735ad0b66 --- /dev/null +++ b/Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/S3Logo.idf @@ -0,0 +1,10 @@ +// /** @file +// Platform Logo image definition file. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved. +// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#image IMG_LOGO S3Logo.bmp diff --git a/Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/S3LogoDxe.inf b/Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/S3LogoDxe.inf new file mode 100644 index 0000000000..be4c5ad59d --- /dev/null +++ b/Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/S3LogoDxe.inf @@ -0,0 +1,57 @@ +## @file +# The default logo bitmap picture shown on setup screen. +# +# Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = S3LogoDxe + FILE_GUID = A3193794-FCBC-E9A4-1AE0-DAEA9A499808 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = InitializeLogo +# +# This flag specifies whether HII resource section is generated into PE image. +# + UEFI_HII_RESOURCE_SECTION = TRUE + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + Logo.c + S3Logo.bmp + S3Logo.idf + +[Packages] + AmdPlatformPkg/AmdPlatformPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + +[LibraryClasses] + BootLogoLib + DebugLib + PcdLib + UefiBootServicesTableLib + UefiDriverEntryPoint + +[Protocols] + gEdkiiPlatformLogoProtocolGuid ## PRODUCES + gEfiHiiDatabaseProtocolGuid ## CONSUMES + gEfiHiiImageExProtocolGuid ## CONSUMES + gEfiHiiPackageListProtocolGuid ## PRODUCES CONSUMES + +[Pcd] + gAmdPlatformPkgTokenSpaceGuid.PcdAmdDisplayLogoEventGuid + +[Depex] + gEfiHiiDatabaseProtocolGuid AND + gEfiHiiImageExProtocolGuid -- 2.34.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#118901): https://edk2.groups.io/g/devel/message/118901 Mute This Topic: https://groups.io/mt/106108330/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=-=-=-=-=-=-=-=-=-=-=- ^ permalink raw reply related [flat|nested] 9+ messages in thread
* [edk2-devel] [RESEND 2/7] AmdPlatformPkg: Adds BaseAlwaysFalseDepexLib Library 2024-05-15 3:50 [edk2-devel] [RESEND 0/7] AmdPlatformPkg: Adds board independent modules Abdul Lateef Attar via groups.io 2024-05-15 3:50 ` [edk2-devel] [RESEND 1/7] AmdPlatformPkg: Adds LogoDxe driver Abdul Lateef Attar via groups.io @ 2024-05-15 3:50 ` Abdul Lateef Attar via groups.io 2024-05-15 3:50 ` [edk2-devel] [RESEND 3/7] AmdPlatformPkg: Implements SerialPortLib for simulator Abdul Lateef Attar via groups.io ` (5 subsequent siblings) 7 siblings, 0 replies; 9+ messages in thread From: Abdul Lateef Attar via groups.io @ 2024-05-15 3:50 UTC (permalink / raw) To: devel; +Cc: Abdul Lateef Attar, Abner Chang, Paul Grimes Adds BaseAlwaysFalseDepexLib Library which always adds DEPEX to FALSE. Using this library will prevent module/driver being dispatched. Usage: MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf { <LibraryClasses> NULL|AmdPlatformPkg/Library/BaseAlwaysFalseDepexLib/BaseAlwaysFalseDepexLib.inf } Cc: Abner Chang <abner.chang@amd.com> Cc: Paul Grimes <paul.grimes@amd.com> Signed-off-by: Abdul Lateef Attar <AbdulLateef.Attar@amd.com> --- .../AMD/AmdPlatformPkg/AmdPlatformPkg.dsc | 2 ++ .../BaseAlwaysFalseDepexLib.c | 20 +++++++++++ .../BaseAlwaysFalseDepexLib.inf | 35 +++++++++++++++++++ .../BaseAlwaysFalseDepexLib.uni | 12 +++++++ 4 files changed, 69 insertions(+) create mode 100644 Platform/AMD/AmdPlatformPkg/Library/BaseAlwaysFalseDepexLib/BaseAlwaysFalseDepexLib.c create mode 100644 Platform/AMD/AmdPlatformPkg/Library/BaseAlwaysFalseDepexLib/BaseAlwaysFalseDepexLib.inf create mode 100644 Platform/AMD/AmdPlatformPkg/Library/BaseAlwaysFalseDepexLib/BaseAlwaysFalseDepexLib.uni diff --git a/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dsc b/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dsc index 151235b791..e39ad93c83 100644 --- a/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dsc +++ b/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dsc @@ -24,6 +24,7 @@ !include MdePkg/MdeLibs.dsc.inc [LibraryClasses.Common] + AlwaysFalseDepexLib|AmdPlatformPkg/Library/BaseAlwaysFalseDepexLib/BaseAlwaysFalseDepexLib.inf BaseLib|MdePkg/Library/BaseLib/BaseLib.inf BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf @@ -46,6 +47,7 @@ MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf [Components] + AmdPlatformPkg/Library/BaseAlwaysFalseDepexLib/BaseAlwaysFalseDepexLib.inf AmdPlatformPkg/Universal/LogoDxe/JpegLogoDxe.inf # Server platform JPEG logo driver AmdPlatformPkg/Universal/LogoDxe/LogoDxe.inf # Server platfrom Bitmap logo driver AmdPlatformPkg/Universal/LogoDxe/S3LogoDxe.inf diff --git a/Platform/AMD/AmdPlatformPkg/Library/BaseAlwaysFalseDepexLib/BaseAlwaysFalseDepexLib.c b/Platform/AMD/AmdPlatformPkg/Library/BaseAlwaysFalseDepexLib/BaseAlwaysFalseDepexLib.c new file mode 100644 index 0000000000..e9f176223d --- /dev/null +++ b/Platform/AMD/AmdPlatformPkg/Library/BaseAlwaysFalseDepexLib/BaseAlwaysFalseDepexLib.c @@ -0,0 +1,20 @@ +/** @file + No functionality of this file. + + Copyright (C) 2023 - 2024 Advanced Micro Devices, Inc. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <Base.h> + +/** + Empty function to allow Library Class to be valid. +**/ +VOID +AlwaysFalsePlaceHolderFunction ( + VOID + ) +{ +} diff --git a/Platform/AMD/AmdPlatformPkg/Library/BaseAlwaysFalseDepexLib/BaseAlwaysFalseDepexLib.inf b/Platform/AMD/AmdPlatformPkg/Library/BaseAlwaysFalseDepexLib/BaseAlwaysFalseDepexLib.inf new file mode 100644 index 0000000000..4e86256497 --- /dev/null +++ b/Platform/AMD/AmdPlatformPkg/Library/BaseAlwaysFalseDepexLib/BaseAlwaysFalseDepexLib.inf @@ -0,0 +1,35 @@ +## @file +# This is the module used to consume the always false dependency. +# Used to not dispatching the specific module included by using +# external DSC/FDF include file. +# For example: MinPlatformPkg/Include/Dsc/CoreCommonLib.dsc +# +# The module linked with the NULL class BaseAlwaysFalseDepexLib is still +# put in the FV however it won't be executed. +# +# Copyright (C) 2023 - 2024 Advanced Micro Devices, Inc. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = BaseAlwaysFalseDepexLib + MODULE_UNI_FILE = BaseAlwaysFalseDepexLib.uni + FILE_GUID = 74DC464F-BC11-4E7D-8829-DD2F911988A8 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = AlwaysFalseDepexLib + +# +# VALID_ARCHITECTURES = X64 +# + +[Sources] + BaseAlwaysFalseDepexLib.c + +[Packages] + MdePkg/MdePkg.dec + +[Depex] + FALSE diff --git a/Platform/AMD/AmdPlatformPkg/Library/BaseAlwaysFalseDepexLib/BaseAlwaysFalseDepexLib.uni b/Platform/AMD/AmdPlatformPkg/Library/BaseAlwaysFalseDepexLib/BaseAlwaysFalseDepexLib.uni new file mode 100644 index 0000000000..5c7ccf1840 --- /dev/null +++ b/Platform/AMD/AmdPlatformPkg/Library/BaseAlwaysFalseDepexLib/BaseAlwaysFalseDepexLib.uni @@ -0,0 +1,12 @@ +## @file +# +# Copyright (C) 2023 - 2024 Advanced Micro Devices, Inc. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +#string STR_MODULE_ABSTRACT #language en-US "Library instance to provide FALSE Depex to prevent running of driver." + +#string STR_MODULE_DESCRIPTION #language en-US "Library instance to provide FALSE Depex to prevent running of driver." + -- 2.34.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#118903): https://edk2.groups.io/g/devel/message/118903 Mute This Topic: https://groups.io/mt/106108332/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=-=-=-=-=-=-=-=-=-=-=- ^ permalink raw reply related [flat|nested] 9+ messages in thread
* [edk2-devel] [RESEND 3/7] AmdPlatformPkg: Implements SerialPortLib for simulator 2024-05-15 3:50 [edk2-devel] [RESEND 0/7] AmdPlatformPkg: Adds board independent modules Abdul Lateef Attar via groups.io 2024-05-15 3:50 ` [edk2-devel] [RESEND 1/7] AmdPlatformPkg: Adds LogoDxe driver Abdul Lateef Attar via groups.io 2024-05-15 3:50 ` [edk2-devel] [RESEND 2/7] AmdPlatformPkg: Adds BaseAlwaysFalseDepexLib Library Abdul Lateef Attar via groups.io @ 2024-05-15 3:50 ` Abdul Lateef Attar via groups.io 2024-05-15 3:50 ` [edk2-devel] [RESEND 4/7] AmdPlatformPkg: Adds PlatformSocLib library class Abdul Lateef Attar via groups.io ` (4 subsequent siblings) 7 siblings, 0 replies; 9+ messages in thread From: Abdul Lateef Attar via groups.io @ 2024-05-15 3:50 UTC (permalink / raw) To: devel; +Cc: Abdul Lateef Attar, Abner Chang, Paul Grimes Implements SerialPortLib library class for simulator. It redirects the output to the port 80. Cc: Abner Chang <abner.chang@amd.com> Cc: Paul Grimes <paul.grimes@amd.com> Signed-off-by: Abdul Lateef Attar <AbdulLateef.Attar@amd.com> --- .../AMD/AmdPlatformPkg/AmdPlatformPkg.dsc | 3 +- .../SimulatorSerialPortLibPort80.c | 208 ++++++++++++++++++ .../SimulatorSerialPortLibPort80.inf | 31 +++ 3 files changed, 241 insertions(+), 1 deletion(-) create mode 100644 Platform/AMD/AmdPlatformPkg/Library/SimulatorSerialPortLibPort80/SimulatorSerialPortLibPort80.c create mode 100644 Platform/AMD/AmdPlatformPkg/Library/SimulatorSerialPortLibPort80/SimulatorSerialPortLibPort80.inf diff --git a/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dsc b/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dsc index e39ad93c83..2c959fb614 100644 --- a/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dsc +++ b/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dsc @@ -48,6 +48,7 @@ [Components] AmdPlatformPkg/Library/BaseAlwaysFalseDepexLib/BaseAlwaysFalseDepexLib.inf + AmdPlatformPkg/Library/SimulatorSerialPortLibPort80/SimulatorSerialPortLibPort80.inf AmdPlatformPkg/Universal/LogoDxe/JpegLogoDxe.inf # Server platform JPEG logo driver AmdPlatformPkg/Universal/LogoDxe/LogoDxe.inf # Server platfrom Bitmap logo driver - AmdPlatformPkg/Universal/LogoDxe/S3LogoDxe.inf + AmdPlatformPkg/Universal/LogoDxe/S3LogoDxe.inf \ No newline at end of file diff --git a/Platform/AMD/AmdPlatformPkg/Library/SimulatorSerialPortLibPort80/SimulatorSerialPortLibPort80.c b/Platform/AMD/AmdPlatformPkg/Library/SimulatorSerialPortLibPort80/SimulatorSerialPortLibPort80.c new file mode 100644 index 0000000000..35842ecddc --- /dev/null +++ b/Platform/AMD/AmdPlatformPkg/Library/SimulatorSerialPortLibPort80/SimulatorSerialPortLibPort80.c @@ -0,0 +1,208 @@ +/** @file + AMD simulator port80 serial port library functions. + + Copyright (C) 2023 - 2024 Advanced Micro Devices, Inc. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <Base.h> +#include <Library/BaseLib.h> +#include <Library/IoLib.h> +#include <Library/SerialPortLib.h> +#include <Uefi.h> + +/** + Initialize the serial device hardware. + + If no initialization is required, then return RETURN_SUCCESS. + If the serial device was successfully initialized, then return RETURN_SUCCESS. + If the serial device could not be initialized, then return RETURN_DEVICE_ERROR. + + @retval RETURN_SUCCESS The serial device was initialized. + @retval RETURN_DEVICE_ERROR The serial device could not be initialized. + +**/ +RETURN_STATUS +EFIAPI +SerialPortInitialize ( + VOID + ) +{ + // Chipset defaults properly decoding port 80 to eSPI + return EFI_SUCCESS; +} + +/** + Write data from buffer to serial device. + + Writes NumberOfBytes data bytes from Buffer to the serial device. + The number of bytes actually written to the serial device is returned. + If the return value is less than NumberOfBytes, then the write operation failed. + If Buffer is NULL, then ASSERT(). + If NumberOfBytes is zero, then return 0. + + @param[in] Buffer The pointer to the data buffer to be written. + @param[in] NumberOfBytes The number of bytes to written to the serial device. + + @retval 0 NumberOfBytes is 0. + @retval >0 The number of bytes written to the serial device. + If this value is less than NumberOfBytes, then the read operation failed. + +**/ +UINTN +EFIAPI +SerialPortWrite ( + IN UINT8 *Buffer, + IN UINTN NumberOfBytes + ) +{ + UINTN ByteCount; + + if ((Buffer == NULL) || (NumberOfBytes == 0)) { + return 0; + } + + IoWrite32 (0x80, SIGNATURE_32 ('R', 'T', 'S', '_')); + + ByteCount = NumberOfBytes; + for ( ; ByteCount != 0; ByteCount--, Buffer++) { + IoWrite8 (0x80, *Buffer); + } + + IoWrite32 (0x80, SIGNATURE_32 ('D', 'N', 'E', '_')); + + return NumberOfBytes; +} + +/** + Read data from serial device and save the data in buffer. + + Reads NumberOfBytes data bytes from a serial device into the buffer + specified by Buffer. The number of bytes actually read is returned. + If the return value is less than NumberOfBytes, then the rest operation failed. + If Buffer is NULL, then ASSERT(). + If NumberOfBytes is zero, then return 0. + + @param[out] Buffer The pointer to the data buffer to store the data read from the serial device. + @param[in] NumberOfBytes The number of bytes which will be read. + + @retval 0 Read data failed; No data is to be read. + @retval >0 The actual number of bytes read from serial device. + +**/ +UINTN +EFIAPI +SerialPortRead ( + OUT UINT8 *Buffer, + IN UINTN NumberOfBytes + ) +{ + return 0; +} + +/** + Polls a serial device to see if there is any data waiting to be read. + + Polls a serial device to see if there is any data waiting to be read. + If there is data waiting to be read from the serial device, then TRUE is returned. + If there is no data waiting to be read from the serial device, then FALSE is returned. + + @retval TRUE Data is waiting to be read from the serial device. + @retval FALSE There is no data waiting to be read from the serial device. + +**/ +BOOLEAN +EFIAPI +SerialPortPoll ( + VOID + ) +{ + return FALSE; +} + +/** + Sets the control bits on a serial device. + + @param[in] Control Sets the bits of Control that are settable. + + @retval RETURN_SUCCESS The new control bits were set on the serial device. + @retval RETURN_UNSUPPORTED The serial device does not support this operation. + @retval RETURN_DEVICE_ERROR The serial device is not functioning correctly. + +**/ +RETURN_STATUS +EFIAPI +SerialPortSetControl ( + IN UINT32 Control + ) +{ + return RETURN_UNSUPPORTED; +} + +/** + Retrieve the status of the control bits on a serial device. + + @param[out] Control A pointer to return the current control signals from the serial device. + + @retval RETURN_SUCCESS The control bits were read from the serial device. + @retval RETURN_UNSUPPORTED The serial device does not support this operation. + @retval RETURN_DEVICE_ERROR The serial device is not functioning correctly. + +**/ +RETURN_STATUS +EFIAPI +SerialPortGetControl ( + OUT UINT32 *Control + ) +{ + return RETURN_UNSUPPORTED; +} + +/** + Sets the baud rate, receive FIFO depth, transmit/receive time out, parity, + data bits, and stop bits on a serial device. + + @param[in,out] BaudRate The requested baud rate. A BaudRate value of 0 will use the + device's default interface speed. + On output, the value actually set. + @param[in,out] ReceiveFifoDepth The requested depth of the FIFO on the receive side of the + serial interface. A ReceiveFifoDepth value of 0 will use + the device's default FIFO depth. + On output, the value actually set. + @param[in,out] Timeout The requested time out for a single character in microseconds. + This timeout applies to both the transmit and receive side of the + interface. A Timeout value of 0 will use the device's default time + out value. + On output, the value actually set. + @param[in,out] Parity The type of parity to use on this serial device. A Parity value of + DefaultParity will use the device's default parity value. + On output, the value actually set. + @param[in,out] DataBits The number of data bits to use on the serial device. A DataBits + value of 0 will use the device's default data bit setting. + On output, the value actually set. + @param[in,out] StopBits The number of stop bits to use on this serial device. A StopBits + value of DefaultStopBits will use the device's default number of + stop bits. + On output, the value actually set. + + @retval RETURN_SUCCESS The new attributes were set on the serial device. + @retval RETURN_UNSUPPORTED The serial device does not support this operation. + @retval RETURN_INVALID_PARAMETER One or more of the attributes has an unsupported value. + @retval RETURN_DEVICE_ERROR The serial device is not functioning correctly. + +**/ +RETURN_STATUS +EFIAPI +SerialPortSetAttributes ( + IN OUT UINT64 *BaudRate, + IN OUT UINT32 *ReceiveFifoDepth, + IN OUT UINT32 *Timeout, + IN OUT EFI_PARITY_TYPE *Parity, + IN OUT UINT8 *DataBits, + IN OUT EFI_STOP_BITS_TYPE *StopBits + ) +{ + return RETURN_UNSUPPORTED; +} diff --git a/Platform/AMD/AmdPlatformPkg/Library/SimulatorSerialPortLibPort80/SimulatorSerialPortLibPort80.inf b/Platform/AMD/AmdPlatformPkg/Library/SimulatorSerialPortLibPort80/SimulatorSerialPortLibPort80.inf new file mode 100644 index 0000000000..61e2d77f46 --- /dev/null +++ b/Platform/AMD/AmdPlatformPkg/Library/SimulatorSerialPortLibPort80/SimulatorSerialPortLibPort80.inf @@ -0,0 +1,31 @@ +## @file +# Simlator port80 instance of serial port library functions. +# +# Copyright (C) 2023 - 2024 Advanced Micro Devices, Inc. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = SimulatorSerialPortLibPort80 + FILE_GUID = 35217E20-489E-64F9-4E42-1EAFABE0A86F + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = SerialPortLib + +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + SimulatorSerialPortLibPort80.c + +[Packages] + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + +[LibraryClasses] + BaseLib + IoLib -- 2.34.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#118902): https://edk2.groups.io/g/devel/message/118902 Mute This Topic: https://groups.io/mt/106108331/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=-=-=-=-=-=-=-=-=-=-=- ^ permalink raw reply related [flat|nested] 9+ messages in thread
* [edk2-devel] [RESEND 4/7] AmdPlatformPkg: Adds PlatformSocLib library class 2024-05-15 3:50 [edk2-devel] [RESEND 0/7] AmdPlatformPkg: Adds board independent modules Abdul Lateef Attar via groups.io ` (2 preceding siblings ...) 2024-05-15 3:50 ` [edk2-devel] [RESEND 3/7] AmdPlatformPkg: Implements SerialPortLib for simulator Abdul Lateef Attar via groups.io @ 2024-05-15 3:50 ` Abdul Lateef Attar via groups.io 2024-05-15 3:50 ` [edk2-devel] [RESEND 5/7] AmdPlatformPkg: Adds AmdConfigRouting driver Abdul Lateef Attar via groups.io ` (3 subsequent siblings) 7 siblings, 0 replies; 9+ messages in thread From: Abdul Lateef Attar via groups.io @ 2024-05-15 3:50 UTC (permalink / raw) To: devel; +Cc: Abdul Lateef Attar, Abner Chang, Paul Grimes Adds PlatformSocLib library class. Implements null instance of PlatformSocLib. PlatformSocLib provides interface to the SoC specific functionality. Cc: Abner Chang <abner.chang@amd.com> Cc: Paul Grimes <paul.grimes@amd.com> Signed-off-by: Abdul Lateef Attar <AbdulLateef.Attar@amd.com> --- .../AMD/AmdPlatformPkg/AmdPlatformPkg.dec | 7 + .../AMD/AmdPlatformPkg/AmdPlatformPkg.dsc | 2 + .../Include/Library/AmdPlatformSocLib.h | 134 ++++++++++++++++++ .../DxePlatformSocLib/DxePlatformSocLibNull.c | 75 ++++++++++ .../DxePlatformSocLibNull.inf | 26 ++++ .../DxePlatformSocLibNull.uni | 13 ++ 6 files changed, 257 insertions(+) create mode 100644 Platform/AMD/AmdPlatformPkg/Include/Library/AmdPlatformSocLib.h create mode 100644 Platform/AMD/AmdPlatformPkg/Library/DxePlatformSocLib/DxePlatformSocLibNull.c create mode 100644 Platform/AMD/AmdPlatformPkg/Library/DxePlatformSocLib/DxePlatformSocLibNull.inf create mode 100644 Platform/AMD/AmdPlatformPkg/Library/DxePlatformSocLib/DxePlatformSocLibNull.uni diff --git a/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dec b/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dec index 4d811d1135..4cb66d2a36 100644 --- a/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dec +++ b/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dec @@ -14,6 +14,13 @@ PACKAGE_GUID = 2CB1238B-18E2-4837-B714-9DAB2B30A3C2 PACKAGE_VERSION = 1.0 +[Includes] + Include + +[LibraryClasses] + ## @libraryclass Defines a get/set interface for platform specific data. + PlatformSocLib|Include/Library/AmdPlatformSocLib.h + [Guids] gAmdPlatformPkgTokenSpaceGuid = { 0x663DE733, 0x70E0, 0x4D37, { 0xBB, 0x30, 0x7D, 0x9E, 0xAF, 0x9B, 0xDA, 0xE9 }} diff --git a/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dsc b/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dsc index 2c959fb614..a717263c58 100644 --- a/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dsc +++ b/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dsc @@ -45,9 +45,11 @@ [LibraryClasses.common.DXE_DRIVER] BootLogoLib|MdeModulePkg/Library/BootLogoLib/BootLogoLib.inf MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf + PlatformSocLib|AmdPlatformPkg/Library/DxePlatformSocLib/DxePlatformSocLibNull.inf [Components] AmdPlatformPkg/Library/BaseAlwaysFalseDepexLib/BaseAlwaysFalseDepexLib.inf + AmdPlatformPkg/Library/DxePlatformSocLib/DxePlatformSocLibNull.inf AmdPlatformPkg/Library/SimulatorSerialPortLibPort80/SimulatorSerialPortLibPort80.inf AmdPlatformPkg/Universal/LogoDxe/JpegLogoDxe.inf # Server platform JPEG logo driver AmdPlatformPkg/Universal/LogoDxe/LogoDxe.inf # Server platfrom Bitmap logo driver diff --git a/Platform/AMD/AmdPlatformPkg/Include/Library/AmdPlatformSocLib.h b/Platform/AMD/AmdPlatformPkg/Include/Library/AmdPlatformSocLib.h new file mode 100644 index 0000000000..f57e5d4989 --- /dev/null +++ b/Platform/AMD/AmdPlatformPkg/Include/Library/AmdPlatformSocLib.h @@ -0,0 +1,134 @@ +/** @file + AMD Platform SoC Library. + Provides interface to Get/Set platform specific data. + + Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef AMD_PLATFORM_SOC_LIB_H_ +#define AMD_PLATFORM_SOC_LIB_H_ + +#include <IndustryStandard/Acpi65.h> +#include <IndustryStandard/SmBios.h> +#include <Uefi/UefiBaseType.h> + +#define PCIE_MAX_FUNCTIONS 8 +#define PCIE_MAX_DEVICES 32 +#define PCIE_MAX_ROOTPORT (PCIE_MAX_DEVICES * PCIE_MAX_FUNCTIONS) + +typedef struct { + UINTN Index; + BOOLEAN Enabled; + UINT8 PortPresent; + UINTN Device; + UINTN Function; + UINTN SlotNum; + // Interrupts are relative to IOAPIC 0->n + UINTN BridgeInterrupt; // Redirection table entry for mapped bridge interrupt + UINTN EndpointInterruptArray[4]; // Redirection table entries for mapped INT A/B/C/D +} AMD_PCI_ROOT_PORT_OBJECT; + +typedef struct { + UINTN Index; + UINT8 SocketId; + UINTN Segment; + UINTN BaseBusNumber; +} AMD_PCI_ROOT_BRIDGE_OBJECT; + +/// Extended PCI address format +typedef struct { + IN OUT UINT32 Register : 12; ///< Register offset + IN OUT UINT32 Function : 3; ///< Function number + IN OUT UINT32 Device : 5; ///< Device number + IN OUT UINT32 Bus : 8; ///< Bus number + IN OUT UINT32 Segment : 4; ///< Segment +} AMD_EXT_PCI_ADDR; + +/// Union type for PCI address +typedef union { + IN UINT32 AddressValue; ///< Formal address + IN AMD_EXT_PCI_ADDR Address; ///< Extended address +} AMD_PCI_ADDR; + +/// Port Information Structure +typedef struct { + AMD_PCI_ADDR EndPointBDF; ///< Bus/Device/Function of Root Port in PCI_ADDR format + BOOLEAN IsCxl2; +} AMD_CXL_PORT_INFO; + +typedef struct { + EFI_HANDLE Handle; + UINTN Uid; + UINTN GlobalInterruptStart; + VOID *Configuration; // Never free this buffer + AMD_PCI_ROOT_BRIDGE_OBJECT *Object; // Never free this object + UINTN RootPortCount; + AMD_PCI_ROOT_PORT_OBJECT *RootPort[PCIE_MAX_ROOTPORT]; // Never free this object + UINTN CxlCount; + AMD_CXL_PORT_INFO CxlPortInfo; + UINTN PxmDomain; // Proximity domain +} AMD_PCI_ROOT_BRIDGE_OBJECT_INSTANCE; + +/** + Get the platform specific IOAPIC information. + + NOTE: Caller will need to free structure once finished. + + @param IoApicInfo The IOAPIC information + @param IoApicCount Number of IOAPIC present + + @retval EFI_SUCCESS Successfully retrieve the IOAPIC information. + EFI_INVALID_PARAMETERS Incorrect parameters provided. + EFI_UNSUPPORTED Platform do not support this function. + Other value Returns other EFI_STATUS in case of failure. + +**/ +EFI_STATUS +EFIAPI +GetIoApicInfo ( + IN OUT EFI_ACPI_6_5_IO_APIC_STRUCTURE **IoApicInfo, + IN OUT UINT8 *IoApicCount + ); + +/** + Get the platform PCIe configuration information. + + NOTE: Caller will need to free structure once finished. + + @param RootBridge The root bridge information + @param RootBridgeCount Number of root bridges present + + @retval EFI_SUCCESS Successfully retrieve the root bridge information. + EFI_INVALID_PARAMETERS Incorrect parameters provided. + EFI_UNSUPPORTED Platform do not support this function. + Other value Returns other EFI_STATUS in case of failure. + +**/ +EFI_STATUS +EFIAPI +GetPcieInfo ( + IN OUT AMD_PCI_ROOT_BRIDGE_OBJECT_INSTANCE **RootBridge, + IN OUT UINTN *RootBridgeCount + ); + +/** + Get the platform specific System Slot information. + + NOTE: Caller will need to free structure once finished. + + @param[in, out] SystemSlotInfo The System Slot information + @param[in, out] SystemSlotCount Number of System Slot present + + @retval EFI_UNSUPPORTED Platform do not support this function. +**/ +EFI_STATUS +EFIAPI +GetSystemSlotInfo ( + IN OUT SMBIOS_TABLE_TYPE9 **SystemSlotInfo, + IN OUT UINTN *SystemSlotCount + ); + +#endif diff --git a/Platform/AMD/AmdPlatformPkg/Library/DxePlatformSocLib/DxePlatformSocLibNull.c b/Platform/AMD/AmdPlatformPkg/Library/DxePlatformSocLib/DxePlatformSocLibNull.c new file mode 100644 index 0000000000..142c3b66a7 --- /dev/null +++ b/Platform/AMD/AmdPlatformPkg/Library/DxePlatformSocLib/DxePlatformSocLibNull.c @@ -0,0 +1,75 @@ +/** @file + Implements AMD Platform SoC Library. + Provides interface to Get/Set platform specific data. + + Copyright (C) 2023 - 2024 Advanced Micro Devices, Inc. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include <Uefi/UefiBaseType.h> +#include <IndustryStandard/Acpi65.h> +#include <Library/AmdPlatformSocLib.h> +#include <IndustryStandard/SmBios.h> + +/** + Get the platform specific IOAPIC information. + + NOTE: Caller will need to free structure once finished. + + @param IoApicInfo The IOAPIC information + @param IoApicCount Number of IOAPIC present + + @retval EFI_UNSUPPORTED Platform do not support this function. + +**/ +EFI_STATUS +EFIAPI +GetIoApicInfo ( + IN OUT EFI_ACPI_6_5_IO_APIC_STRUCTURE **IoApicInfo, + IN OUT UINT8 *IoApicCount + ) +{ + return EFI_UNSUPPORTED; +} + +/** + Get the platform PCIe configuration information. + + NOTE: Caller will need to free structure once finished. + + @param RootBridge The root bridge information + @param RootBridgeCount Number of root bridges present + + @retval EFI_UNSUPPORTED Platform do not support this function. + +**/ +EFI_STATUS +EFIAPI +GetPcieInfo ( + IN OUT AMD_PCI_ROOT_BRIDGE_OBJECT_INSTANCE **RootBridge, + IN OUT UINTN *RootBridgeCount + ) +{ + return EFI_UNSUPPORTED; +} + +/** + Get the platform specific System Slot information. + + NOTE: Caller will need to free structure once finished. + + @param[in, out] SystemSlotInfo The System Slot information + @param[in, out] SystemSlotCount Number of System Slot present + + @retval EFI_UNSUPPORTED Platform do not support this function. +**/ +EFI_STATUS +EFIAPI +GetSystemSlotInfo ( + IN OUT SMBIOS_TABLE_TYPE9 **SystemSlotInfo, + IN OUT UINTN *SystemSlotCount + ) +{ + return EFI_UNSUPPORTED; +} diff --git a/Platform/AMD/AmdPlatformPkg/Library/DxePlatformSocLib/DxePlatformSocLibNull.inf b/Platform/AMD/AmdPlatformPkg/Library/DxePlatformSocLib/DxePlatformSocLibNull.inf new file mode 100644 index 0000000000..df8eb6b604 --- /dev/null +++ b/Platform/AMD/AmdPlatformPkg/Library/DxePlatformSocLib/DxePlatformSocLibNull.inf @@ -0,0 +1,26 @@ +## @file +# INF file of AMD Platform SoC library +# +# Copyright (C) 2023 - 2024 Advanced Micro Devices, Inc. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 1.29 + BASE_NAME = DxePlatformSocLibNull + MODULE_UNI_FILE = DxePlatformSocLibNull.uni + FILE_GUID = AFF6B33C-B084-4B35-BC1F-D077CDB3B464 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = PlatformSocLib + +[Sources] + DxePlatformSocLibNull.c + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + BaseLib + diff --git a/Platform/AMD/AmdPlatformPkg/Library/DxePlatformSocLib/DxePlatformSocLibNull.uni b/Platform/AMD/AmdPlatformPkg/Library/DxePlatformSocLib/DxePlatformSocLibNull.uni new file mode 100644 index 0000000000..aa2ce2bc2f --- /dev/null +++ b/Platform/AMD/AmdPlatformPkg/Library/DxePlatformSocLib/DxePlatformSocLibNull.uni @@ -0,0 +1,13 @@ +## @file +# UNI file of AMD Platform SoC library +# +# Copyright (C) 2023 - 2024 Advanced Micro Devices, Inc. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +#string STR_MODULE_ABSTRACT #language en-US "AMD DXE Platform SoC null library instance." + +#string STR_MODULE_DESCRIPTION #language en-US "AMD DXE Platform SoC null library instance." + -- 2.34.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#118904): https://edk2.groups.io/g/devel/message/118904 Mute This Topic: https://groups.io/mt/106108333/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=-=-=-=-=-=-=-=-=-=-=- ^ permalink raw reply related [flat|nested] 9+ messages in thread
* [edk2-devel] [RESEND 5/7] AmdPlatformPkg: Adds AmdConfigRouting driver 2024-05-15 3:50 [edk2-devel] [RESEND 0/7] AmdPlatformPkg: Adds board independent modules Abdul Lateef Attar via groups.io ` (3 preceding siblings ...) 2024-05-15 3:50 ` [edk2-devel] [RESEND 4/7] AmdPlatformPkg: Adds PlatformSocLib library class Abdul Lateef Attar via groups.io @ 2024-05-15 3:50 ` Abdul Lateef Attar via groups.io 2024-05-15 3:50 ` [edk2-devel] [RESEND 6/7] AmdPlatformPkg: Adds SecureBootDefaultKeysInit driver Abdul Lateef Attar via groups.io ` (2 subsequent siblings) 7 siblings, 0 replies; 9+ messages in thread From: Abdul Lateef Attar via groups.io @ 2024-05-15 3:50 UTC (permalink / raw) To: devel; +Cc: Abdul Lateef Attar, Abner Chang, Paul Grimes Adds AmdConfigRouting driver to improve HII performance. Cc: Abner Chang <abner.chang@amd.com> Cc: Paul Grimes <paul.grimes@amd.com> Signed-off-by: Abdul Lateef Attar <AbdulLateef.Attar@amd.com> --- .../AMD/AmdPlatformPkg/AmdPlatformPkg.dsc | 1 + .../HiiConfigRouting/AmdConfigRouting.inf | 45 + .../HiiConfigRouting/AmdConfigRoutingEntry.c | 57 + .../HiiConfigRouting/AmdHiiConfigRouting.c | 1101 +++++++++++++++++ .../HiiConfigRouting/AmdHiiConfigRouting.h | 189 +++ 5 files changed, 1393 insertions(+) create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/HiiConfigRouting/AmdConfigRouting.inf create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/HiiConfigRouting/AmdConfigRoutingEntry.c create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/HiiConfigRouting/AmdHiiConfigRouting.c create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/HiiConfigRouting/AmdHiiConfigRouting.h diff --git a/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dsc b/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dsc index a717263c58..3d13c9e41d 100644 --- a/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dsc +++ b/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dsc @@ -51,6 +51,7 @@ AmdPlatformPkg/Library/BaseAlwaysFalseDepexLib/BaseAlwaysFalseDepexLib.inf AmdPlatformPkg/Library/DxePlatformSocLib/DxePlatformSocLibNull.inf AmdPlatformPkg/Library/SimulatorSerialPortLibPort80/SimulatorSerialPortLibPort80.inf + AmdPlatformPkg/Universal/HiiConfigRouting/AmdConfigRouting.inf AmdPlatformPkg/Universal/LogoDxe/JpegLogoDxe.inf # Server platform JPEG logo driver AmdPlatformPkg/Universal/LogoDxe/LogoDxe.inf # Server platfrom Bitmap logo driver AmdPlatformPkg/Universal/LogoDxe/S3LogoDxe.inf \ No newline at end of file diff --git a/Platform/AMD/AmdPlatformPkg/Universal/HiiConfigRouting/AmdConfigRouting.inf b/Platform/AMD/AmdPlatformPkg/Universal/HiiConfigRouting/AmdConfigRouting.inf new file mode 100644 index 0000000000..6cfb1dcceb --- /dev/null +++ b/Platform/AMD/AmdPlatformPkg/Universal/HiiConfigRouting/AmdConfigRouting.inf @@ -0,0 +1,45 @@ +## @file +# AMD HII Config routing driver INF file. +# This module provides better performance of BlockToConfig and ConfigToBlock +# functions. +# +# Copyright (C) 2021 - 2024 Advanced Micro Devices, Inc. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = AmdConfigRouting + FILE_GUID = 64302048-7006-49C4-AF0A-5ACE61257437 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = AmdConfigRoutingEntry + +[Sources] + AmdConfigRoutingEntry.c + AmdHiiConfigRouting.c + AmdHiiConfigRouting.h + +[Packages] + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + MemoryAllocationLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiLib + +[Protocols] + gEfiHiiConfigRoutingProtocolGuid + +[Pcd] + gEfiMdePkgTokenSpaceGuid.PcdMaximumUnicodeStringLength + +[Depex] + gEfiHiiConfigRoutingProtocolGuid diff --git a/Platform/AMD/AmdPlatformPkg/Universal/HiiConfigRouting/AmdConfigRoutingEntry.c b/Platform/AMD/AmdPlatformPkg/Universal/HiiConfigRouting/AmdConfigRoutingEntry.c new file mode 100644 index 0000000000..29246ac1b2 --- /dev/null +++ b/Platform/AMD/AmdPlatformPkg/Universal/HiiConfigRouting/AmdConfigRoutingEntry.c @@ -0,0 +1,57 @@ +/** @file + AMD implementation of interface functions for EFI_HII_CONFIG_ROUTING_PROTOCOL. + This module overrides BlockToConfig and ConfigToBlock for the better performance. + + Copyright (C) 2023 - 2024 Advanced Micro Devices, Inc. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "AmdHiiConfigRouting.h" + +/** + Entry point for the AMD HII Config Routing driver. + + @param[in] ImageHandle The image handle. + @param[in] SystemTable The system table. + + @retval EFI_SUCCESS The entry point is executed successfully. + @retval Others Some error occurs when executing this entry point. +**/ +EFI_STATUS +EFIAPI +AmdConfigRoutingEntry ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting; + + HiiConfigRouting = NULL; + + Status = gBS->LocateProtocol ( + &gEfiHiiConfigRoutingProtocolGuid, + NULL, + (VOID **)&HiiConfigRouting + ); + if (!EFI_ERROR (Status)) { + ASSERT (HiiConfigRouting != NULL); + DEBUG (( + DEBUG_INFO, + "HiiConfigRouting->BlockToConfig: 0x%lX\n", + (UINTN)HiiBlockToConfig + )); + DEBUG (( + DEBUG_INFO, + "HiiConfigRouting->ConfigToBlock: 0x%lX\n", + (UINTN)HiiConfigToBlock + )); + + HiiConfigRouting->BlockToConfig = HiiBlockToConfig; + HiiConfigRouting->ConfigToBlock = HiiConfigToBlock; + } + + return Status; +} diff --git a/Platform/AMD/AmdPlatformPkg/Universal/HiiConfigRouting/AmdHiiConfigRouting.c b/Platform/AMD/AmdPlatformPkg/Universal/HiiConfigRouting/AmdHiiConfigRouting.c new file mode 100644 index 0000000000..0a28d887e9 --- /dev/null +++ b/Platform/AMD/AmdPlatformPkg/Universal/HiiConfigRouting/AmdHiiConfigRouting.c @@ -0,0 +1,1101 @@ +/** @file + AMD implementation of interfaces function for EFI_HII_CONFIG_ROUTING_PROTOCOL. + This file provides better performance of BlockToConfig and ConfigToBlock + functions. + + Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR> + Copyright (C) 2023 - 2024 Advanced Micro Devices, Inc. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "AmdHiiConfigRouting.h" + +HII_ELEMENT gElementInfo[] = { + { L"GUID=", FIXED_STR_LEN (L"GUID=") }, + { L"NAME=", FIXED_STR_LEN (L"NAME=") }, + { L"PATH=", FIXED_STR_LEN (L"PATH=") }, + { L"OFFSET=", FIXED_STR_LEN (L"OFFSET=") }, + { L"WIDTH=", FIXED_STR_LEN (L"WIDTH=") }, + { L"VALUE=", FIXED_STR_LEN (L"VALUE=") } +}; + +/** + Converts the unicode character of the string from uppercase to lowercase. + This is a internal function. + + @param ConfigString String to be converted + +**/ +VOID +EFIAPI +HiiToLower ( + IN EFI_STRING ConfigString + ) +{ + EFI_STRING String; + BOOLEAN Lower; + + ASSERT (ConfigString != NULL); + + // + // Convert all hex digits in range [A-F] in the configuration header to [a-f] + // + for (String = ConfigString, Lower = FALSE; *String != L'\0'; String++) { + if (*String == L'=') { + Lower = TRUE; + } else if (*String == L'&') { + Lower = FALSE; + } else if (Lower && (*String >= L'A') && (*String <= L'F')) { + *String = (CHAR16)(*String - L'A' + L'a'); + } + } + + return; +} + +// +// Updated EDK2 functions to improve performance. +// + +/** + Returns the length of a Null-terminated Unicode string. + + This function returns the number of Unicode characters in the Null-terminated + Unicode string specified by String. + + @param String A pointer to a Null-terminated Unicode string. + + @retval The length of String. + +**/ +UINTN +EFIAPI +HiiStrLen ( + IN EFI_STRING String + ) +{ + UINTN Length; + + ASSERT (String != NULL); + + for (Length = 0; String[Length] != L'\0'; Length++) { + } + + // + // If PcdMaximumUnicodeStringLength is not zero, + // length should not more than PcdMaximumUnicodeStringLength + // + if (PcdGet32 (PcdMaximumUnicodeStringLength) != 0) { + ASSERT (Length < PcdGet32 (PcdMaximumUnicodeStringLength)); + } + + return Length; +} + +/** + Compares up to a specified length the contents of two Null-terminated Unicode + strings, and returns the difference between the first mismatched Unicode + characters. + + This function compares the Null-terminated Unicode string FirstString to the + Null-terminated Unicode string SecondString. At most, Length Unicode + characters will be compared. If Length is 0, then 0 is returned. If + FirstString is identical to SecondString, then 0 is returned. Otherwise, the + value returned is the first mismatched Unicode character in SecondString + subtracted from the first mismatched Unicode character in FirstString. + + @param[in] FirstString A pointer to a Null-terminated Unicode string. + @param[in] SecondString A pointer to a Null-terminated Unicode string. + @param[in] Length The maximum number of Unicode characters to compare. + + @retval 0 FirstString is identical to SecondString. + @retval others FirstString is not identical to SecondString. + +**/ +INTN +EFIAPI +HiiStrnCmp ( + IN EFI_STRING FirstString, + IN EFI_STRING SecondString, + IN UINTN Length + ) +{ + if (Length == 0) { + return 0; + } + + ASSERT (FirstString != NULL); + ASSERT (SecondString != NULL); + if (PcdGet32 (PcdMaximumUnicodeStringLength) != 0) { + ASSERT (Length <= PcdGet32 (PcdMaximumUnicodeStringLength)); + } + + while ((*FirstString != L'\0') && + (*SecondString != L'\0') && + (*FirstString == *SecondString) && + (Length > 1)) + { + FirstString++; + SecondString++; + Length--; + } + + return *FirstString - *SecondString; +} + +/** + Initializes HII_NUMBER instance to 0. + + @param[in, out] This Pointer to HII_NUMBER instances. + +**/ +VOID +HiiNumberInit ( + IN OUT HII_NUMBER *This + ) +{ + ASSERT (This != NULL); + + This->NumberPtr = 0; + This->NumberPtrLength = 0; + This->Value = 0; + This->PrivateBufferSize = 0; +} + +/** + Frees buffer in HII_NUMBER instance. + + @param[in, out] This Pointer to HII_NUMBER instance. + +**/ +VOID +HiiNumberFree ( + IN OUT HII_NUMBER *This + ) +{ + ASSERT (This != NULL); + + if (This->NumberPtr != NULL) { + FreePool (This->NumberPtr); + This->NumberPtr = NULL; + This->PrivateBufferSize = 0; + } +} + +/** + If buffer doesn't exist, allocate it. If the existing buffer is less than + requested, allocate a larger one. + + @param[in, out] This Pointer to HII_NUMBER instance. + @param[in] Size Requested buffer size. + + @retval EFI_SUCCESS Buffer allocated. + @retval EFI_OUT_OF_RESOURCES OUt of memory. + +**/ +EFI_STATUS +HiiNumberSetMinBufferSize ( + IN OUT HII_NUMBER *This, + IN UINTN Size + ) +{ + ASSERT (This != NULL); + + if (This->PrivateBufferSize < Size) { + Size += MAX_STRING_LENGTH; + This->NumberPtr = ReallocatePool (This->PrivateBufferSize, Size, This->NumberPtr); + if (This->NumberPtr == NULL) { + This->PrivateBufferSize = 0; + return EFI_OUT_OF_RESOURCES; + } + + This->PrivateBufferSize = Size; + } + + return EFI_SUCCESS; +} + +/** + Get value of number from string and update HII_NUMBER instance. + + @param[in, out] This Pointer to HII_NUMBER instance. + @param[in] String String to get value from. String may end in \0 or &. + + @retval EFI_SUCCESS Buffer allocated. + @retval EFI_OUT_OF_RESOURCES OUt of memory. + +**/ +EFI_STATUS +GetValueOfNumber ( + IN OUT HII_NUMBER *This, + IN EFI_STRING String + ) +{ + EFI_STATUS Status; + UINTN Index; + UINTN StringLength; + UINTN NumLen; + CHAR16 Digit; + UINT8 DigitUint8; + EFI_STRING EndOfString; + + if ((This == NULL) || (String == NULL) || (*String == L'\0')) { + return EFI_INVALID_PARAMETER; + } + + EndOfString = String; + StringLength = 0; + + while (*EndOfString != L'\0' && *EndOfString != L'&') { + EndOfString++; + StringLength++; + } + + This->StringLength = StringLength; + + NumLen = (StringLength + 1) / 2; + + Status = HiiNumberSetMinBufferSize (This, NumLen); + if (EFI_ERROR (Status)) { + return Status; + } + + for (Index = 0; Index < StringLength; Index++) { + Digit = String[StringLength - Index - 1]; + if (Digit < L'0') { + DigitUint8 = 0; + } else if (Digit <= L'9') { + DigitUint8 = (UINT8)(Digit - L'0'); + } else if (Digit < L'A') { + DigitUint8 = 0; + } else if (Digit <= L'F') { + DigitUint8 = (UINT8)(Digit - L'A' + 0xa); + } else if (Digit < L'a') { + DigitUint8 = 0; + } else if (Digit <= L'f') { + DigitUint8 = (UINT8)(Digit - L'a' + 0xa); + } else { + DigitUint8 = 0; + } + + if ((Index & 1) == 0) { + This->NumberPtr[Index / 2] = DigitUint8; + } else { + This->NumberPtr[Index / 2] = (UINT8)((DigitUint8 << 4) + This->NumberPtr[Index / 2]); + } + } + + This->NumberPtrLength = StringLength; + This->Value = 0; + + if (StringLength <= sizeof (UINTN) * sizeof (CHAR16)) { + CopyMem ( + &This->Value, + This->NumberPtr, + NumLen < sizeof (UINTN) ? NumLen : sizeof (UINTN) + ); + } + + return EFI_SUCCESS; +} + +/** + Initializes HII_STRING instance allocating buffer. + + @param[in, out] This Pointer to HII_STRING instance. + @param[in] Size Size of initial allocation. + + @retval EFI_SUCCESS Allocated buffer successfully. + @retval EFI_OUT_OF_RESOURCES Out of memory. +**/ +EFI_STATUS +HiiStringInit ( + IN OUT HII_STRING *This, + IN UINTN Size + ) +{ + ASSERT (This != NULL); + + This->StringLength = 0; + + if (Size == 0) { + This->String = NULL; + This->PrivateBufferSize = 0; + return EFI_SUCCESS; + } + + This->String = (EFI_STRING)AllocatePool (Size); + + if (This->String != NULL) { + This->String[0] = L'\0'; + This->PrivateBufferSize = Size; + } else { + This->PrivateBufferSize = 0; + return EFI_OUT_OF_RESOURCES; + } + + return EFI_SUCCESS; +} + +/** + Frees HiiString Buffer + + @param[in, out] This Pointer to HII_STRING instance. + +**/ +VOID +HiiStringFree ( + IN OUT HII_STRING *This + ) +{ + ASSERT (This != NULL); + + if (This->String != NULL) { + FreePool (This->String); + This->String = NULL; + This->PrivateBufferSize = 0; + } +} + +/** + If buffer doesn't exist, allocate it. If the existing buffer is less than + requested, allocate a larger one. + + @param[in, out] This Pointer to HII_STRING instance. + @param[in] Size Requested buffer size. + + @retval EFI_SUCCESS Buffer allocated. + @retval EFI_OUT_OF_RESOURCES OUt of memory. + +**/ +EFI_STATUS +HiiStringSetMinBufferSize ( + IN OUT HII_STRING *This, + IN UINTN Size + ) +{ + UINTN ThisStringSize; + EFI_STRING NewAlloc; + + ThisStringSize = (This->StringLength + 1) * sizeof (CHAR16); + + if (Size > This->PrivateBufferSize) { + NewAlloc = (EFI_STRING)AllocatePool (Size); + if (NewAlloc == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + CopyMem (NewAlloc, This->String, ThisStringSize); + FreePool (This->String); + This->String = NewAlloc; + This->PrivateBufferSize = Size; + } + + return EFI_SUCCESS; +} + +/** + Append a string to the string in HII_STRING instance. + + @param[in, out] This Pointer to HII_STRING instance. + @param[in] String String to append. + + @retval EFI_SUCCESS String is appended. + @retval EFI_OUT_OF_RESOURCES OUt of memory. + +**/ +EFI_STATUS +HiiStringAppend ( + IN OUT HII_STRING *This, + IN EFI_STRING String + ) +{ + EFI_STATUS Status; + UINTN ThisStringSize; + UINTN StringSize; + UINTN MaxLen; + + if ((This == NULL) || (String == NULL)) { + return EFI_INVALID_PARAMETER; + } + + ThisStringSize = (This->StringLength + 1) * sizeof (CHAR16); + StringSize = HII_STR_SIZE (String); + + if (ThisStringSize + StringSize > This->PrivateBufferSize) { + MaxLen = (ThisStringSize + StringSize) * 2; + Status = HiiStringSetMinBufferSize (This, MaxLen); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // Append the incoming string + // + CopyMem (&This->String[This->StringLength], String, StringSize); + This->StringLength += StringSize / sizeof (CHAR16) - 1; + + return EFI_SUCCESS; +} + +/** + Append a number to the string in HII_STRING instance. + + @param[in, out] This Pointer to HII_STRING instance. + @param[in] Number Number to append. + @param[in] Length Length of Number. + + @retval EFI_SUCCESS Number is appended. + @retval EFI_OUT_OF_RESOURCES OUt of memory. +**/ +EFI_STATUS +HiiStringAppendValue ( + IN OUT HII_STRING *This, + IN UINT8 *Number, + IN UINTN Length + ) +{ + EFI_STATUS Status; + UINTN ThisStringSize; + UINTN Index; + UINTN Index2; + UINT8 Nibble; + UINTN MaxLen; + + CHAR16 *String; + + if (Length == 0) { + return EFI_INVALID_PARAMETER; + } + + ThisStringSize = (This->StringLength + 1) * sizeof (CHAR16); + + if (ThisStringSize + Length * 2 * sizeof (CHAR16) > This->PrivateBufferSize) { + MaxLen = (ThisStringSize + Length * 2 * sizeof (CHAR16)) * 2; // Double requested string length. + Status = HiiStringSetMinBufferSize (This, MaxLen); + if (EFI_ERROR (Status)) { + return Status; + } + } + + String = This->String + This->StringLength; + This->StringLength += Length * 2; + + Index = Length; + + do { + Index--; + Nibble = Number[Index] >> 4; + + for (Index2 = 0; Index2 < 2; Index2++) { + if (Nibble < 0xa) { + *String = '0' + Nibble; + } else { + *String = 'a' + Nibble - 0xa; + } + + Nibble = Number[Index] & 0xf; + String++; + } + } while (Index > 0); + + *String = '\0'; + + return EFI_SUCCESS; +} + +/** + Find an element header in the input string, and return pointer it is value. + + This is a internal function. + + @param[in] Hdr Element Header to search for. + @param[in] String Search for element header in this string. + + @retval Pointer to value in element header. + @retval NULL if element header not found or end of string. + +**/ +EFI_STRING +FindElmentValue ( + IN ELEMENT_HDR Hdr, + IN EFI_STRING String + ) +{ + ASSERT (String != NULL); + + if (HiiStrnCmp (String, gElementInfo[Hdr].ElementString, gElementInfo[Hdr].ElementLength) != 0) { + return NULL; + } + + return String + gElementInfo[Hdr].ElementLength; +} + +/** + Find pointer after value for element header in string. + + This is a internal function. + + @param[in] String String to search. + + @retval Pointer after value in element header. + +**/ +EFI_STRING +SkipElementValue ( + IN EFI_STRING String + ) +{ + ASSERT (String != NULL); + + while (*String != 0 && *String != L'&') { + String++; + } + + if (*String == L'&') { + String++; // Skip '&' + } + + return String; +} + +/** + Return pointer after ConfigHdr. + + This is a internal function. + + @param[in] String String to search. + + @retval Pointer after ConfigHdr. + @retval NULL if Config header not formed correctly. + +**/ +EFI_STRING +GetEndOfConfigHdr ( + IN EFI_STRING String + ) +{ + ASSERT (String != NULL); + + String = FindElmentValue (ElementGuidHdr, String); + if (String == NULL) { + return NULL; + } + + String = SkipElementValue (String); + if (*String == 0) { + return NULL; + } + + while (*String != 0 && + HiiStrnCmp ( + String, + gElementInfo[ElementPathHdr].ElementString, + gElementInfo[ElementPathHdr].ElementLength + ) + != 0) + { + String++; + } + + if (*String != 0) { + String = String + gElementInfo[ElementPathHdr].ElementLength; + } + + String = SkipElementValue (String); + return String; +} + +/** + This helper function is to be called by drivers to map configuration data + stored in byte array ("block") formats such as UEFI Variables into current + configuration strings. + + @param[in] This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL + instance. + @param[in] ConfigRequest A null-terminated Unicode string in + <ConfigRequest> format. + @param[in] Block Array of bytes defining the block's configuration. + @param[in] BlockSize Length in bytes of Block. + @param[out] Config Filled-in configuration string. String allocated + by the function. Returned only if call is + successful. It is <ConfigResp> string format. + @param[out] Progress A pointer to a string filled in with the offset of + the most recent & before the first failing + name/value pair (or the beginning of the string if + the failure is in the first name/value pair) or + the terminating NULL if all was successful. + + @retval EFI_SUCCESS The request succeeded. Progress points to the null + terminator at the end of the ConfigRequest + string. + @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. Progress + points to the first character of ConfigRequest. + @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigRequest or + Block parameter would result in this type of + error. Progress points to the first character of + ConfigRequest. + @retval EFI_DEVICE_ERROR Block not large enough. Progress undefined. + @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted string. + Block is left updated and Progress points at + the "&" preceding the first non-<BlockName>. + +**/ +EFI_STATUS +EFIAPI +HiiBlockToConfig ( + IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This, + IN CONST EFI_STRING ConfigRequest, + IN CONST UINT8 *Block, + IN CONST UINTN BlockSize, + OUT EFI_STRING *Config, + OUT EFI_STRING *Progress + ) +{ + EFI_STATUS Status; + EFI_STRING StringPtr; + EFI_STRING OrigPtr; + CHAR16 CharBackup; + UINTN Offset; + UINTN Width; + UINT8 *Value; + HII_STRING HiiString; + HII_NUMBER HiiNumber; + + if ((This == NULL) || (Progress == NULL) || (Config == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if ((Block == NULL) || (ConfigRequest == NULL)) { + *Progress = ConfigRequest; + return EFI_INVALID_PARAMETER; + } + + StringPtr = ConfigRequest; + + Status = HiiStringInit (&HiiString, MAX_STRING_LENGTH); + if (EFI_ERROR (Status)) { + *Progress = ConfigRequest; + return Status; + } + + HiiNumberInit (&HiiNumber); + + // + // Jump <ConfigHdr> + // + StringPtr = GetEndOfConfigHdr (StringPtr); + if (StringPtr == NULL) { + // + // Invalid header. + // + *Progress = ConfigRequest; + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + if (*StringPtr == L'\0') { + *Progress = StringPtr; + HiiStringAppend (&HiiString, ConfigRequest); + HiiToLower (HiiString.String); + + // + // Do not free HiiString.String with HiiStringFree; + // + *Config = HiiString.String; + return EFI_SUCCESS; + } + + // + // Copy <ConfigHdr> and an additional '&' to <ConfigResp> + // + CharBackup = StringPtr[0]; + StringPtr[0] = L'\0'; // Temporarily change & to L'\0' + Status = HiiStringAppend (&HiiString, ConfigRequest); + if (EFI_ERROR (Status)) { + *Progress = ConfigRequest; + goto Exit; + } + + StringPtr[0] = CharBackup; + + // + // Parse each <RequestElement> if exists + // Only <BlockName> format is supported by this help function. + // <BlockName> ::= 'OFFSET='<Number>&'WIDTH='<Number> + // + + // + // while search for "OFFSET=" + // When "OFFSET=" is found, OrigPtr starts at "OFFSET=", and StringPtr points to value. + // + while (*StringPtr != 0 && + (OrigPtr = StringPtr, (StringPtr = FindElmentValue (ElementOffsetHdr, StringPtr)) != NULL) + ) + { + // + // Get Offset + // + Status = GetValueOfNumber (&HiiNumber, StringPtr); + if (EFI_ERROR (Status)) { + if (Status == EFI_OUT_OF_RESOURCES) { + *Progress = ConfigRequest; // Out of memory + } else { + *Progress = OrigPtr - 1; + } + + goto Exit; + } + + Offset = HiiNumber.Value; + StringPtr += HiiNumber.StringLength + 1; + + // + // Get Width + // + StringPtr = FindElmentValue (ElementWidthHdr, StringPtr); + if (StringPtr == NULL) { + *Progress = OrigPtr - 1; + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + Status = GetValueOfNumber (&HiiNumber, StringPtr); + if (EFI_ERROR (Status)) { + if (Status == EFI_OUT_OF_RESOURCES) { + *Progress = ConfigRequest; // Out of memory + } else { + *Progress = OrigPtr - 1; + } + + goto Exit; + } + + Width = HiiNumber.Value; + StringPtr += HiiNumber.StringLength; + + if ((*StringPtr != 0) && (*StringPtr != L'&')) { + *Progress = OrigPtr - 1; + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + // + // Calculate Value and convert it to hex string. + // + if (Offset + Width > BlockSize) { + *Progress = StringPtr; + Status = EFI_DEVICE_ERROR; + goto Exit; + } + + Value = (UINT8 *)Block + Offset; + + CharBackup = *StringPtr; + *StringPtr = L'\0'; + + Status = HiiStringAppend (&HiiString, OrigPtr); + if (EFI_ERROR (Status)) { + *Progress = ConfigRequest; // Out of memory + goto Exit; + } + + *StringPtr = CharBackup; // End of section of string OrigPtr + + Status = HiiStringAppend (&HiiString, L"&VALUE="); + if (EFI_ERROR (Status)) { + *Progress = ConfigRequest; // Out of memory + goto Exit; + } + + Status = HiiStringAppendValue (&HiiString, Value, Width); + if (EFI_ERROR (Status)) { + if (Status == EFI_OUT_OF_RESOURCES) { + *Progress = ConfigRequest; // Out of memory + } else { + *Progress = OrigPtr - 1; + } + + goto Exit; + } + + // + // If L'\0', parsing is finished. Otherwise skip L'&' to continue + // + if (*StringPtr == L'\0') { + break; + } + + Status = HiiStringAppend (&HiiString, L"&"); + if (EFI_ERROR (Status)) { + *Progress = ConfigRequest; // Out of memory + goto Exit; + } + + StringPtr++; // Skip L'&' + } + + if (*StringPtr != L'\0') { + *Progress = StringPtr - 1; + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + HiiToLower (HiiString.String); + *Progress = StringPtr; + + HiiNumberFree (&HiiNumber); + + // + // Do not free HiiString.String with HiiStringFree. The caller will + // consume it when EFI_SUCCESS. + // + *Config = HiiString.String; + + return EFI_SUCCESS; + +Exit: + HiiStringFree (&HiiString); + HiiNumberFree (&HiiNumber); + + *Config = NULL; + + return Status; +} + +/** + This helper function is to be called by drivers to map configuration strings + to configurations stored in byte array ("block") formats such as UEFI Variables. + + @param[in] This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL + instance. + @param[in] ConfigResp A null-terminated Unicode string in <ConfigResp> + format. + @param[in, out] Block A possibly null array of bytes representing the + current block. Only bytes referenced in the + ConfigResp string in the block are modified. If + this parameter is null or if the *BlockSize + parameter is (on input) shorter than required by + the Configuration string, only the BlockSize + parameter is updated and an appropriate status + (see below) is returned. + @param[in, out] BlockSize The length of the Block in units of UINT8. On + input, this is the size of the Block. On output, + if successful, contains the largest index of the + modified byte in the Block, or the required buffer + size if the Block is not large enough. + @param[out] Progress On return, points to an element of the ConfigResp + string filled in with the offset of the most + recent '&' before the first failing name / value + pair (or the beginning of the string if the + failure is in the first name / value pair) or the + terminating NULL if all was successful. + + @retval EFI_SUCCESS The request succeeded. Progress points to the null + terminator at the end of the ConfigResp string. + @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. Progress + points to the first character of ConfigResp. + @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigResp or + Block parameter would result in this type of + error. Progress points to the first character of + ConfigResp. + @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted name / + value pair. Block is left updated and + Progress points at the '&' preceding the first + non-<BlockName>. + @retval EFI_BUFFER_TOO_SMALL Block not large enough. Progress undefined. + BlockSize is updated with the required buffer size. + @retval EFI_NOT_FOUND Target for the specified routing data was not found. + Progress points to the "G" in "GUID" of the errant + routing data. + +**/ +EFI_STATUS +EFIAPI +HiiConfigToBlock ( + IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This, + IN CONST EFI_STRING ConfigResp, + IN OUT UINT8 *Block, + IN OUT UINTN *BlockSize, + OUT EFI_STRING *Progress + ) +{ + EFI_STATUS Status; + EFI_STRING StringPtr; + EFI_STRING OrigPtr; + UINTN Offset; + UINTN Width; + UINTN BufferSize; + UINTN MaxBlockSize; + HII_NUMBER HiiNumber; + + if ((This == NULL) || (BlockSize == NULL) || (Progress == NULL)) { + return EFI_INVALID_PARAMETER; + } + + *Progress = ConfigResp; + if (ConfigResp == NULL) { + return EFI_INVALID_PARAMETER; + } + + StringPtr = ConfigResp; + BufferSize = *BlockSize; + MaxBlockSize = 0; + + HiiNumberInit (&HiiNumber); + // + // Jump <ConfigHdr> + // + StringPtr = GetEndOfConfigHdr (StringPtr); + if (StringPtr == NULL) { + // + // Invalid header. + // + *Progress = ConfigResp; + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + if (*StringPtr == L'\0') { + *Progress = StringPtr; + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + // + // Parse each <ConfigElement> if exists + // Only '&'<BlockConfig> format is supported by this help function. + // <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE='<Number> + // + while (*StringPtr != L'\0' && + (OrigPtr = StringPtr, (StringPtr = FindElmentValue (ElementOffsetHdr, StringPtr)) != NULL) + ) + { + // + // Get Offset + // + Status = GetValueOfNumber (&HiiNumber, StringPtr); + if (EFI_ERROR (Status)) { + if (Status == EFI_OUT_OF_RESOURCES) { + *Progress = ConfigResp; // Out of memory + } else { + *Progress = OrigPtr - 1; + } + + goto Exit; + } + + Offset = HiiNumber.Value; + StringPtr += HiiNumber.StringLength + 1; + + // + // Get Width + // + StringPtr = FindElmentValue (ElementWidthHdr, StringPtr); + if (StringPtr == NULL) { + *Progress = OrigPtr - 1; + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + Status = GetValueOfNumber (&HiiNumber, StringPtr); + if (EFI_ERROR (Status)) { + if (Status == EFI_OUT_OF_RESOURCES) { + *Progress = ConfigResp; // Out of memory + } else { + *Progress = OrigPtr - 1; + } + + goto Exit; + } + + Width = HiiNumber.Value; + StringPtr += HiiNumber.StringLength + 1; + + // + // Get Value + // + StringPtr = FindElmentValue (ElementValueHdr, StringPtr); + if (StringPtr == NULL) { + *Progress = OrigPtr - 1; + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + Status = GetValueOfNumber (&HiiNumber, StringPtr); + if (EFI_ERROR (Status)) { + if (Status == EFI_OUT_OF_RESOURCES) { + *Progress = ConfigResp; // Out of memory + } else { + *Progress = OrigPtr - 1; + } + + goto Exit; + } + + // + // Update the Block with configuration info + // + if ((Block != NULL) && (Offset + Width <= BufferSize)) { + CopyMem (Block + Offset, HiiNumber.NumberPtr, Width); + } + + if (Offset + Width > MaxBlockSize) { + MaxBlockSize = Offset + Width; + } + + StringPtr += HiiNumber.StringLength; + + if ((*StringPtr != L'\0') && (*StringPtr != L'&')) { + *Progress = OrigPtr - 1; + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + // + // If L'\0', parsing is finished. + // + if (*StringPtr == L'\0') { + break; + } + + StringPtr++; // Skip L'&' + } + + // + // The input string is not ConfigResp format, return error. + // + if (*StringPtr != L'\0') { + *Progress = StringPtr; + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + *Progress = StringPtr + HiiStrLen (StringPtr); + *BlockSize = MaxBlockSize - 1; + + if (MaxBlockSize > BufferSize) { + *BlockSize = MaxBlockSize; + if (Block != NULL) { + Status = EFI_BUFFER_TOO_SMALL; + goto Exit; + } + } + + if (Block == NULL) { + *Progress = ConfigResp; + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + Status = EFI_SUCCESS; + +Exit: + + HiiNumberFree (&HiiNumber); + + return Status; +} diff --git a/Platform/AMD/AmdPlatformPkg/Universal/HiiConfigRouting/AmdHiiConfigRouting.h b/Platform/AMD/AmdPlatformPkg/Universal/HiiConfigRouting/AmdHiiConfigRouting.h new file mode 100644 index 0000000000..bce606f7dd --- /dev/null +++ b/Platform/AMD/AmdPlatformPkg/Universal/HiiConfigRouting/AmdHiiConfigRouting.h @@ -0,0 +1,189 @@ +/** @file + Provide optimized implementation of HII_CONFIG_ROUTING Protocol + functions HiiBlockToConfig and HiiConfigToBlock. + + Copyright (C) 2023 - 2024 Advanced Micro Devices, Inc. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef AMD_HII_CONFIG_ROUTING_H_ +#define AMD_HII_CONFIG_ROUTING_H_ + +#include <Library/DebugLib.h> +#include <Library/BaseMemoryLib.h> +#include <Protocol/HiiConfigRouting.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/UefiDriverEntryPoint.h> +#include <Library/UefiBootServicesTableLib.h> + +#define MAX_STRING_LENGTH 1024 + +/// +/// Returns the size of a Null-terminated Unicode string in bytes, including the +/// Null terminator. +/// +#define HII_STR_SIZE(str) ((HiiStrLen (str) + 1) * sizeof (*str)) + +/// +/// HII_NUMBER definitions +/// +typedef struct { + // Public variables + UINT8 *NumberPtr; ///< Pointer to a number in array of bytes. + UINTN NumberPtrLength; ///< 2 * number of bytes. Note: changing this to + ///< number of bytes will impact existing code and + ///< hard to test. + UINTN Value; ///< If Value is less than or equal to 64-bits, + ///< store value here as an unsigned integer. + UINTN StringLength; ///< Input string length. + + // Private variables + UINTN PrivateBufferSize; ///< Size of allocated NumberPtr. This reduces + ///< reallocations as this can be used for + ///< multiple numbers. +} HII_NUMBER; + +/// +/// HII_STRING definitions +/// +typedef struct { + // Public variables + EFI_STRING String; ///< String that is maintained here, and futures + ///< calls will append to it. + UINTN StringLength; ///< Length of String. + + // Private variables + UINTN PrivateBufferSize; ///< Length of allocated String. This reduces + ///< reallocations as strings are appended. +} HII_STRING; + +#define FIXED_STR_LEN(String) (sizeof (String) / sizeof (CHAR16) - 1) + +typedef enum { + ElementGuidHdr = 0, + ElementNameHdr = 1, + ElementPathHdr = 2, + ElementOffsetHdr = 3, + ElementWidthHdr = 4, + ElementValueHdr = 5 +} ELEMENT_HDR; + +typedef struct { + EFI_STRING ElementString; + UINTN ElementLength; +} HII_ELEMENT; + +/** + This helper function is to be called by drivers to map configuration data + stored in byte array ("block") formats such as UEFI Variables into current + configuration strings. + + @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL + instance. + @param ConfigRequest A null-terminated Unicode string in + <ConfigRequest> format. + @param Block Array of bytes defining the block's + configuration. + @param BlockSize Length in bytes of Block. + @param Config Filled-in configuration string. String allocated + by the function. Returned only if call is + successful. + @param Progress A pointer to a string filled in with the offset + of the most recent & before the first failing + name/value pair (or the beginning of the string + if the failure is in the first name / value pair) + or the terminating NULL if all was successful. + + @retval EFI_SUCCESS The request succeeded. Progress points to the + null terminator at the end of the ConfigRequest + string. + @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. + Progress points to the first character of + ConfigRequest. + @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigRequest or + Block parameter would result in this type of + error. Progress points to the first character + of ConfigRequest. + @retval EFI_NOT_FOUND Target for the specified routing data was not + found. Progress points to the "G" in "GUID" of + the errant routing data. + @retval EFI_DEVICE_ERROR Block not large enough. Progress undefined. + @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted string. + Block is left updated and Progress points at + the '&' preceding the first non-<BlockName>. + +**/ +EFI_STATUS +EFIAPI +HiiBlockToConfig ( + IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This, + IN CONST EFI_STRING ConfigRequest, + IN CONST UINT8 *Block, + IN CONST UINTN BlockSize, + OUT EFI_STRING *Config, + OUT EFI_STRING *Progress + ); + +/** + This helper function is to be called by drivers to map configuration strings + to configurations stored in byte array ("block") formats such as UEFI Variables. + + @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL + instance. + @param ConfigResp A null-terminated Unicode string in <ConfigResp> + format. + @param Block A possibly null array of bytes representing the + current block. Only bytes referenced in the + ConfigResp string in the block are modified. If + this parameter is null or if the *BlockSize + parameter is (on input) shorter than required by + the Configuration string, only the BlockSize + parameter is updated and an appropriate status + (see below) is returned. + @param BlockSize The length of the Block in units of UINT8. On + input, this is the size of the Block. On output, + if successful, contains the largest index of + the modified byte in the Block, or the required + buffer. + size if the Block is not large enough. + @param Progress On return, points to an element of the ConfigResp + string filled in with the offset of the most + recent '&' before the first failing name/value + pair (or the beginning of the string if the + failure is in the first name/value pair) or + the terminating NULL if all was successful. + + @retval EFI_SUCCESS The request succeeded. Progress points to the + null terminator at the end of the ConfigResp + string. + @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. Progress + points to the first character of ConfigResp. + @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigResp or Block + parameter would result in this type of error. + Progress points to the first character of + ConfigResp. + @retval EFI_NOT_FOUND Target for the specified routing data was not + found. Progress points to the "G" in "GUID" of + the errant routing data. + @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted name/ + value pair. Block is left updated and Progress + points at the '&' preceding the first + non-<BlockName>. + @retval EFI_BUFFER_TOO_SMALL Block not large enough. Progress undefined. + BlockSize is updated with the required buffer + size. + +**/ +EFI_STATUS +EFIAPI +HiiConfigToBlock ( + IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This, + IN CONST EFI_STRING ConfigResp, + IN OUT UINT8 *Block, + IN OUT UINTN *BlockSize, + OUT EFI_STRING *Progress + ); + +#endif // AMD_HII_CONFIG_ROUTING_H_ -- 2.34.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#118905): https://edk2.groups.io/g/devel/message/118905 Mute This Topic: https://groups.io/mt/106108334/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=-=-=-=-=-=-=-=-=-=-=- ^ permalink raw reply related [flat|nested] 9+ messages in thread
* [edk2-devel] [RESEND 6/7] AmdPlatformPkg: Adds SecureBootDefaultKeysInit driver 2024-05-15 3:50 [edk2-devel] [RESEND 0/7] AmdPlatformPkg: Adds board independent modules Abdul Lateef Attar via groups.io ` (4 preceding siblings ...) 2024-05-15 3:50 ` [edk2-devel] [RESEND 5/7] AmdPlatformPkg: Adds AmdConfigRouting driver Abdul Lateef Attar via groups.io @ 2024-05-15 3:50 ` Abdul Lateef Attar via groups.io 2024-05-15 3:50 ` [edk2-devel] [RESEND 7/7] AmdPlatformPkg: Adds ACPI common driver Abdul Lateef Attar via groups.io 2024-05-15 3:59 ` [edk2-devel] [RESEND 0/7] AmdPlatformPkg: Adds board independent modules Chang, Abner via groups.io 7 siblings, 0 replies; 9+ messages in thread From: Abdul Lateef Attar via groups.io @ 2024-05-15 3:50 UTC (permalink / raw) To: devel; +Cc: Abdul Lateef Attar, Abner Chang, Paul Grimes Adds SecureBootDefaultKeysInit driver to enroll secure boot default keys. Cc: Abner Chang <abner.chang@amd.com> Cc: Paul Grimes <paul.grimes@amd.com> Signed-off-by: Abdul Lateef Attar <AbdulLateef.Attar@amd.com> --- .../AMD/AmdPlatformPkg/AmdPlatformPkg.dsc | 12 + .../SecureBootDefaultKeysInit.c | 645 ++++++++++++++++++ .../SecureBootDefaultKeysInit.inf | 49 ++ 3 files changed, 706 insertions(+) create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/SecureBoot/SecureBootDefaultKeysInit/SecureBootDefaultKeysInit.c create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/SecureBoot/SecureBootDefaultKeysInit/SecureBootDefaultKeysInit.inf diff --git a/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dsc b/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dsc index 3d13c9e41d..40ed5ea07c 100644 --- a/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dsc +++ b/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dsc @@ -25,17 +25,28 @@ [LibraryClasses.Common] AlwaysFalseDepexLib|AmdPlatformPkg/Library/BaseAlwaysFalseDepexLib/BaseAlwaysFalseDepexLib.inf + BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf BaseLib|MdePkg/Library/BaseLib/BaseLib.inf BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf + DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf + HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf + IntrinsicLib|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf + OpensslLib|CryptoPkg/Library/OpensslLib/OpensslLib.inf PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf + PlatformPKProtectionLib|SecurityPkg/Library/PlatformPKProtectionLibVarPolicy/PlatformPKProtectionLibVarPolicy.inf PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf + RngLib|MdePkg/Library/BaseRngLib/BaseRngLib.inf + SecureBootVariableLib|SecurityPkg/Library/SecureBootVariableLib/SecureBootVariableLib.inf + SecureBootVariableProvisionLib|SecurityPkg/Library/SecureBootVariableProvisionLib/SecureBootVariableProvisionLib.inf SerialPortLib|MdePkg/Library/BaseSerialPortLibNull/BaseSerialPortLibNull.inf + TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf UefiLib|MdePkg/Library/UefiLib/UefiLib.inf UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf + !if $(TARGET) == RELEASE DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf !else @@ -51,6 +62,7 @@ AmdPlatformPkg/Library/BaseAlwaysFalseDepexLib/BaseAlwaysFalseDepexLib.inf AmdPlatformPkg/Library/DxePlatformSocLib/DxePlatformSocLibNull.inf AmdPlatformPkg/Library/SimulatorSerialPortLibPort80/SimulatorSerialPortLibPort80.inf + AmdPlatformPkg/Universal/SecureBoot/SecureBootDefaultKeysInit/SecureBootDefaultKeysInit.inf AmdPlatformPkg/Universal/HiiConfigRouting/AmdConfigRouting.inf AmdPlatformPkg/Universal/LogoDxe/JpegLogoDxe.inf # Server platform JPEG logo driver AmdPlatformPkg/Universal/LogoDxe/LogoDxe.inf # Server platfrom Bitmap logo driver diff --git a/Platform/AMD/AmdPlatformPkg/Universal/SecureBoot/SecureBootDefaultKeysInit/SecureBootDefaultKeysInit.c b/Platform/AMD/AmdPlatformPkg/Universal/SecureBoot/SecureBootDefaultKeysInit/SecureBootDefaultKeysInit.c new file mode 100644 index 0000000000..071bfe5b68 --- /dev/null +++ b/Platform/AMD/AmdPlatformPkg/Universal/SecureBoot/SecureBootDefaultKeysInit/SecureBootDefaultKeysInit.c @@ -0,0 +1,645 @@ +/** @file + This driver init default Secure Boot variables + + Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR> + (C) Copyright 2018 Hewlett Packard Enterprise Development LP<BR> + Copyright (c) 2021, ARM Ltd. All rights reserved.<BR> + Copyright (c) 2021, Semihalf All rights reserved.<BR> + Copyright (c) 2021, Ampere Computing LLC. All rights reserved.<BR> + Copyright (C) 2023 - 2024 Advanced Micro Devices, Inc. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <Uefi.h> +#include <UefiSecureBoot.h> +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> +#include <Library/DxeServicesLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/UefiRuntimeServicesTableLib.h> +#include <Library/UefiLib.h> +#include <Guid/AuthenticatedVariableFormat.h> +#include <Guid/ImageAuthentication.h> +#include <Library/SecureBootVariableLib.h> +#include <Library/SecureBootVariableProvisionLib.h> + +/** + Set PKDefault Variable. + + @param[in] X509Data X509 Certificate data. + @param[in] X509DataSize X509 Certificate data size. + + @retval EFI_SUCCESS PKDefault is set successfully. + +**/ +EFI_STATUS +SetPkDefault ( + IN UINT8 *X509Data, + IN UINTN X509DataSize + ) +{ + EFI_STATUS Status; + UINT32 Attr; + UINTN DataSize; + EFI_SIGNATURE_LIST *PkCert; + EFI_SIGNATURE_DATA *PkCertData; + + PkCert = NULL; + + // + // Allocate space for PK certificate list and initialize it. + // Create PK database entry with SignatureHeaderSize equals 0. + // + PkCert = (EFI_SIGNATURE_LIST *)AllocateZeroPool ( + sizeof (EFI_SIGNATURE_LIST) + sizeof (EFI_SIGNATURE_DATA) - 1 + + X509DataSize + ); + if (PkCert == NULL) { + Status = EFI_OUT_OF_RESOURCES; + DEBUG ((DEBUG_ERROR, "%a: Cannot initialize PKDefault: %r\n", __func__, Status)); + goto ON_EXIT; + } + + PkCert->SignatureListSize = (UINT32)(sizeof (EFI_SIGNATURE_LIST) + + sizeof (EFI_SIGNATURE_DATA) - 1 + + X509DataSize); + PkCert->SignatureSize = (UINT32)(sizeof (EFI_SIGNATURE_DATA) - 1 + X509DataSize); + PkCert->SignatureHeaderSize = 0; + CopyGuid (&PkCert->SignatureType, &gEfiCertX509Guid); + PkCertData = (EFI_SIGNATURE_DATA *)((UINTN)PkCert + + sizeof (EFI_SIGNATURE_LIST) + + PkCert->SignatureHeaderSize); + CopyGuid (&PkCertData->SignatureOwner, &gEfiGlobalVariableGuid); + // + // Fill the PK database with PKpub data from X509 certificate file. + // + CopyMem (&(PkCertData->SignatureData[0]), X509Data, X509DataSize); + + Attr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS; + DataSize = PkCert->SignatureListSize; + + Status = gRT->SetVariable ( + EFI_PK_DEFAULT_VARIABLE_NAME, + &gEfiGlobalVariableGuid, + Attr, + DataSize, + PkCert + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Cannot initialize PKDefault: %r\n", __func__, Status)); + goto ON_EXIT; + } + +ON_EXIT: + + if (PkCert != NULL) { + FreePool (PkCert); + } + + return Status; +} + +/** + Set KDKDefault Variable. + + @param[in] X509Data X509 Certificate data. + @param[in] X509DataSize X509 Certificate data size. + + @retval EFI_SUCCESS KEKDefault is set successfully. + +**/ +EFI_STATUS +SetKekDefault ( + IN UINT8 *X509Data, + IN UINTN X509DataSize + ) +{ + EFI_STATUS Status; + EFI_SIGNATURE_DATA *KEKSigData; + EFI_SIGNATURE_LIST *KekSigList; + UINTN DataSize; + UINTN KekSigListSize; + UINT32 Attr; + + KekSigList = NULL; + KekSigListSize = 0; + DataSize = 0; + KEKSigData = NULL; + + KekSigListSize = sizeof (EFI_SIGNATURE_LIST) + sizeof (EFI_SIGNATURE_DATA) - 1 + X509DataSize; + KekSigList = (EFI_SIGNATURE_LIST *)AllocateZeroPool (KekSigListSize); + if (KekSigList == NULL) { + Status = EFI_OUT_OF_RESOURCES; + DEBUG ((DEBUG_ERROR, "%a: Cannot initialize KEKDefault: %r\n", __func__, Status)); + goto ON_EXIT; + } + + // + // Fill Certificate Database parameters. + // + KekSigList->SignatureListSize = (UINT32)KekSigListSize; + KekSigList->SignatureHeaderSize = 0; + KekSigList->SignatureSize = (UINT32)(sizeof (EFI_SIGNATURE_DATA) - 1 + X509DataSize); + CopyGuid (&KekSigList->SignatureType, &gEfiCertX509Guid); + + KEKSigData = (EFI_SIGNATURE_DATA *)((UINT8 *)KekSigList + sizeof (EFI_SIGNATURE_LIST)); + CopyGuid (&KEKSigData->SignatureOwner, &gEfiGlobalVariableGuid); + CopyMem (KEKSigData->SignatureData, X509Data, X509DataSize); + + // + // Check if KEK been already existed. + // If true, use EFI_VARIABLE_APPEND_WRITE attribute to append the + // new kek to original variable + // + Attr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS; + + Status = gRT->GetVariable ( + EFI_KEK_DEFAULT_VARIABLE_NAME, + &gEfiGlobalVariableGuid, + NULL, + &DataSize, + NULL + ); + if (Status == EFI_BUFFER_TOO_SMALL) { + Attr |= EFI_VARIABLE_APPEND_WRITE; + } else if (Status != EFI_NOT_FOUND) { + DEBUG ((DEBUG_ERROR, "%a: Cannot get the value of KEK: %r\n", __func__, Status)); + goto ON_EXIT; + } + + Status = gRT->SetVariable ( + EFI_KEK_DEFAULT_VARIABLE_NAME, + &gEfiGlobalVariableGuid, + Attr, + KekSigListSize, + KekSigList + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Cannot initialize KEKDefault: %r\n", __func__, Status)); + goto ON_EXIT; + } + +ON_EXIT: + + if (KekSigList != NULL) { + FreePool (KekSigList); + } + + return Status; +} + +/** + Checks if the file content complies with EFI_VARIABLE_AUTHENTICATION_2 format + + @param[in] Data Data. + @param[in] DataSize Data size. + + @retval TRUE The content is EFI_VARIABLE_AUTHENTICATION_2 format. + @retval FALSE The content is NOT a EFI_VARIABLE_AUTHENTICATION_2 format. + +**/ +BOOLEAN +IsAuthentication2Format ( + IN UINT8 *Data, + IN UINTN DataSize + ) +{ + EFI_VARIABLE_AUTHENTICATION_2 *Auth2; + BOOLEAN IsAuth2Format; + + IsAuth2Format = FALSE; + + Auth2 = (EFI_VARIABLE_AUTHENTICATION_2 *)Data; + if (Auth2->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) { + goto ON_EXIT; + } + + if (CompareGuid (&gEfiCertPkcs7Guid, &Auth2->AuthInfo.CertType)) { + IsAuth2Format = TRUE; + } + +ON_EXIT: + + return IsAuth2Format; +} + +/** + Set signature database with the data of EFI_VARIABLE_AUTHENTICATION_2 format. + + @param[in] AuthData AUTHENTICATION_2 data. + @param[in] AuthDataSize AUTHENTICATION_2 data size. + @param[in] VariableName Variable name of signature database, must be + EFI_DB_DEFAULT_VARIABLE_NAME or EFI_DBX_DEFAULT_VARIABLE_NAME or EFI_DBT_DEFAULT_VARIABLE_NAME. + + @retval EFI_SUCCESS New signature is set successfully. + @retval EFI_INVALID_PARAMETER The parameter is invalid. + @retval EFI_UNSUPPORTED Unsupported command. + @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources. + +**/ +EFI_STATUS +SetAuthentication2ToSigDb ( + IN UINT8 *AuthData, + IN UINTN AuthDataSize, + IN CHAR16 *VariableName + ) +{ + EFI_STATUS Status; + UINTN DataSize; + UINT32 Attr; + UINT8 *Data; + + Attr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS; + + // + // Check if SigDB variable has been already existed. + // If true, use EFI_VARIABLE_APPEND_WRITE attribute to append the + // new signature data to original variable + // + DataSize = 0; + Status = gRT->GetVariable ( + VariableName, + &gEfiGlobalVariableGuid, + NULL, + &DataSize, + NULL + ); + if (Status == EFI_BUFFER_TOO_SMALL) { + Attr |= EFI_VARIABLE_APPEND_WRITE; + } else if (Status != EFI_NOT_FOUND) { + DEBUG ((DEBUG_ERROR, "%a: Cannot get the value of signature database: %r\n", __func__, Status)); + return Status; + } + + // + // Ignore AUTHENTICATION_2 region. Only the actual certificate is needed. + // + DataSize = AuthDataSize - ((EFI_VARIABLE_AUTHENTICATION_2 *)AuthData)->AuthInfo.Hdr.dwLength - sizeof (EFI_TIME); + Data = AuthData + (AuthDataSize - DataSize); + + Status = gRT->SetVariable ( + VariableName, + &gEfiGlobalVariableGuid, + Attr, + DataSize, + Data + ); + + DEBUG ((DEBUG_INFO, "Set AUTH_2 data to Var:%s Status: %x\n", VariableName, Status)); + return Status; +} + +/** + + Set signature database with the data of X509 format. + + @param[in] X509Data X509 Certificate data. + @param[in] X509DataSize X509 Certificate data size. + @param[in] VariableName Variable name of signature database, must be + EFI_DB_DEFAULT_VARIABLE_NAME or EFI_DBX_DEFAULT_VARIABLE_NAME or EFI_DBT_DEFAULT_VARIABLE_NAME. + @param[in] SignatureOwnerGuid Guid of the signature owner. + + @retval EFI_SUCCESS New X509 is enrolled successfully. + @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources. + +**/ +EFI_STATUS +SetX509ToSigDb ( + IN UINT8 *X509Data, + IN UINTN X509DataSize, + IN CHAR16 *VariableName, + IN EFI_GUID *SignatureOwnerGuid + ) +{ + EFI_STATUS Status; + EFI_SIGNATURE_LIST *SigDBCert; + EFI_SIGNATURE_DATA *SigDBCertData; + VOID *Data; + UINTN DataSize; + UINTN SigDBSize; + UINT32 Attr; + + SigDBSize = 0; + DataSize = 0; + SigDBCert = NULL; + SigDBCertData = NULL; + Data = NULL; + + SigDBSize = sizeof (EFI_SIGNATURE_LIST) + sizeof (EFI_SIGNATURE_DATA) - 1 + X509DataSize; + + Data = AllocateZeroPool (SigDBSize); + if (Data == NULL) { + Status = EFI_OUT_OF_RESOURCES; + DEBUG ((DEBUG_ERROR, "%a: Cannot allocate memory: %r\n", __func__, Status)); + goto ON_EXIT; + } + + // + // Fill Certificate Database parameters. + // + SigDBCert = (EFI_SIGNATURE_LIST *)Data; + SigDBCert->SignatureListSize = (UINT32)SigDBSize; + SigDBCert->SignatureHeaderSize = 0; + SigDBCert->SignatureSize = (UINT32)(sizeof (EFI_SIGNATURE_DATA) - 1 + X509DataSize); + CopyGuid (&SigDBCert->SignatureType, &gEfiCertX509Guid); + + SigDBCertData = (EFI_SIGNATURE_DATA *)((UINT8 *)SigDBCert + sizeof (EFI_SIGNATURE_LIST)); + CopyGuid (&SigDBCertData->SignatureOwner, SignatureOwnerGuid); + CopyMem ((UINT8 *)(SigDBCertData->SignatureData), X509Data, X509DataSize); + + // + // Check if signature database entry has been already existed. + // If true, use EFI_VARIABLE_APPEND_WRITE attribute to append the + // new signature data to original variable + // + Attr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS; + + Status = gRT->GetVariable ( + VariableName, + &gEfiGlobalVariableGuid, + NULL, + &DataSize, + NULL + ); + if (Status == EFI_BUFFER_TOO_SMALL) { + Attr |= EFI_VARIABLE_APPEND_WRITE; + } else if (Status != EFI_NOT_FOUND) { + goto ON_EXIT; + } + + Status = gRT->SetVariable ( + VariableName, + &gEfiGlobalVariableGuid, + Attr, + SigDBSize, + Data + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Cannot set signature database: %r\n", __func__, Status)); + goto ON_EXIT; + } + +ON_EXIT: + + if (Data != NULL) { + FreePool (Data); + } + + return Status; +} + +/** + + Set signature database. + + @param[in] Data Data. + @param[in] DataSize Data size. + @param[in] VariableName Variable name of signature database, must be + EFI_DB_DEFAULT_VARIABLE_NAME or EFI_DBX_DEFAULT_VARIABLE_NAME or EFI_DBT_DEFAULT_VARIABLE_NAME. + @param[in] SignatureOwnerGuid Guid of the signature owner. + + @retval EFI_SUCCESS Signature is set successfully. + @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources. + +**/ +EFI_STATUS +SetSignatureDatabase ( + IN UINT8 *Data, + IN UINTN DataSize, + IN CHAR16 *VariableName, + IN EFI_GUID *SignatureOwnerGuid + ) +{ + if (IsAuthentication2Format (Data, DataSize)) { + return SetAuthentication2ToSigDb (Data, DataSize, VariableName); + } else { + return SetX509ToSigDb (Data, DataSize, VariableName, SignatureOwnerGuid); + } +} + +/** Initializes PKDefault variable with data from FFS section. + + @retval EFI_SUCCESS Variable was initialized successfully. + @retval EFI_UNSUPPORTED Variable already exists. +**/ +EFI_STATUS +InitPkDefault ( + IN VOID + ) +{ + EFI_STATUS Status; + UINT8 *Data; + UINTN DataSize; + + // + // Check if variable exists, if so do not change it + // + Status = GetVariable2 (EFI_PK_DEFAULT_VARIABLE_NAME, &gEfiGlobalVariableGuid, (VOID **)&Data, &DataSize); + if (Status == EFI_SUCCESS) { + DEBUG ((DEBUG_INFO, "Variable %s exists. Old value is preserved\n", EFI_PK_DEFAULT_VARIABLE_NAME)); + FreePool (Data); + return EFI_UNSUPPORTED; + } + + // + // Variable does not exist, can be initialized + // + DEBUG ((DEBUG_INFO, "Variable %s does not exist.\n", EFI_PK_DEFAULT_VARIABLE_NAME)); + + // + // Enroll default PK. + // + Status = GetSectionFromFv ( + &gDefaultPKFileGuid, + EFI_SECTION_RAW, + 0, + (VOID **)&Data, + &DataSize + ); + if (!EFI_ERROR (Status)) { + SetPkDefault (Data, DataSize); + } + + return EFI_SUCCESS; +} + +/** Initializes KEKDefault variable with data from FFS section. + + @retval EFI_SUCCESS Variable was initialized successfully. + @retval EFI_UNSUPPORTED Variable already exists. +**/ +EFI_STATUS +InitKekDefault ( + IN VOID + ) +{ + EFI_STATUS Status; + UINTN Index; + UINT8 *Data; + UINTN DataSize; + + // + // Check if variable exists, if so do not change it + // + Status = GetVariable2 (EFI_KEK_DEFAULT_VARIABLE_NAME, &gEfiGlobalVariableGuid, (VOID **)&Data, &DataSize); + if (Status == EFI_SUCCESS) { + DEBUG ((DEBUG_INFO, "Variable %s exists. Old value is preserved\n", EFI_KEK_DEFAULT_VARIABLE_NAME)); + FreePool (Data); + return EFI_UNSUPPORTED; + } + + Index = 0; + do { + Status = GetSectionFromFv ( + &gDefaultKEKFileGuid, + EFI_SECTION_RAW, + Index, + (VOID **)&Data, + &DataSize + ); + if (!EFI_ERROR (Status)) { + SetKekDefault (Data, DataSize); + Index++; + } + } while (Status == EFI_SUCCESS); + + return EFI_SUCCESS; +} + +/** Initializes dbDefault variable with data from FFS section. + + @retval EFI_SUCCESS Variable was initialized successfully. + @retval EFI_UNSUPPORTED Variable already exists. +**/ +EFI_STATUS +InitDbDefault ( + IN VOID + ) +{ + EFI_STATUS Status; + UINTN Index; + UINT8 *Data; + UINTN DataSize; + + Status = GetVariable2 (EFI_DB_DEFAULT_VARIABLE_NAME, &gEfiGlobalVariableGuid, (VOID **)&Data, &DataSize); + if (Status == EFI_SUCCESS) { + DEBUG ((DEBUG_INFO, "Variable %s exists. Old value is preserved\n", EFI_DB_DEFAULT_VARIABLE_NAME)); + FreePool (Data); + return EFI_UNSUPPORTED; + } + + DEBUG ((DEBUG_INFO, "Variable %s does not exist.\n", EFI_DB_DEFAULT_VARIABLE_NAME)); + + Index = 0; + do { + Status = GetSectionFromFv ( + &gDefaultdbFileGuid, + EFI_SECTION_RAW, + Index, + (VOID **)&Data, + &DataSize + ); + if (!EFI_ERROR (Status)) { + SetSignatureDatabase (Data, DataSize, EFI_DB_DEFAULT_VARIABLE_NAME, &gEfiGlobalVariableGuid); + Index++; + } + } while (Status == EFI_SUCCESS); + + return EFI_SUCCESS; +} + +/** Initializes dbxDefault variable with data from FFS section. + + @retval EFI_SUCCESS Variable was initialized successfully. + @retval EFI_UNSUPPORTED Variable already exists. +**/ +EFI_STATUS +InitDbxDefault ( + IN VOID + ) +{ + EFI_STATUS Status; + UINTN Index; + UINT8 *Data; + UINTN DataSize; + + // + // Check if variable exists, if so do not change it + // + Status = GetVariable2 (EFI_DBX_DEFAULT_VARIABLE_NAME, &gEfiGlobalVariableGuid, (VOID **)&Data, &DataSize); + if (Status == EFI_SUCCESS) { + DEBUG ((DEBUG_INFO, "Variable %s exists. Old value is preserved\n", EFI_DBX_DEFAULT_VARIABLE_NAME)); + FreePool (Data); + return EFI_UNSUPPORTED; + } + + // + // Variable does not exist, can be initialized + // + DEBUG ((DEBUG_INFO, "Variable %s does not exist.\n", EFI_DBX_DEFAULT_VARIABLE_NAME)); + + Index = 0; + do { + Status = GetSectionFromFv ( + &gDefaultdbxFileGuid, + EFI_SECTION_RAW, + Index, + (VOID **)&Data, + &DataSize + ); + if (!EFI_ERROR (Status)) { + SetSignatureDatabase (Data, DataSize, EFI_DBX_DEFAULT_VARIABLE_NAME, &gEfiGlobalVariableGuid); + Index++; + } + } while (Status == EFI_SUCCESS); + + return EFI_SUCCESS; +} + +/** + Initializes default SecureBoot certificates with data from FFS section. + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS Variable was initialized successfully. +**/ +EFI_STATUS +EFIAPI +SecureBootDefaultKeysInitEntry ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + Status = InitPkDefault (); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Cannot initialize PKDefault: %r\n", __func__, Status)); + return Status; + } + + Status = InitKekDefault (); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Cannot initialize KEKDefault: %r\n", __func__, Status)); + return Status; + } + + Status = InitDbDefault (); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Cannot initialize dbDefault: %r\n", __func__, Status)); + return Status; + } + + Status = InitDbxDefault (); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Cannot initialize dbxDefault: %r\n", __func__, Status)); + return Status; + } + + return EFI_SUCCESS; +} diff --git a/Platform/AMD/AmdPlatformPkg/Universal/SecureBoot/SecureBootDefaultKeysInit/SecureBootDefaultKeysInit.inf b/Platform/AMD/AmdPlatformPkg/Universal/SecureBoot/SecureBootDefaultKeysInit/SecureBootDefaultKeysInit.inf new file mode 100644 index 0000000000..345fbdc6ae --- /dev/null +++ b/Platform/AMD/AmdPlatformPkg/Universal/SecureBoot/SecureBootDefaultKeysInit/SecureBootDefaultKeysInit.inf @@ -0,0 +1,49 @@ +## @file +# Initializes Secure Boot default keys +# +# Copyright (c) 2021, ARM Ltd. All rights reserved.<BR> +# Copyright (c) 2021, Semihalf All rights reserved.<BR> +# Copyright (C) 2023 - 2024 Advanced Micro Devices, Inc. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 1.29 + BASE_NAME = SecureBootDefaultKeysInit + FILE_GUID = ADB0EEA2-8945-4ADF-94A0-3B0B935B4268 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = SecureBootDefaultKeysInitEntry + +[Sources] + SecureBootDefaultKeysInit.c + +[Packages] + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + DebugLib + DxeServicesLib + SecureBootVariableLib + SecureBootVariableProvisionLib + UefiBootServicesTableLib + UefiDriverEntryPoint + +[Guids] + gDefaultdbFileGuid + gDefaultdbxFileGuid + gDefaultKEKFileGuid + gDefaultPKFileGuid + gEfiCertPkcs7Guid + gEfiCertX509Guid + gEfiCustomModeEnableGuid + gEfiImageSecurityDatabaseGuid + gEfiSecureBootEnableDisableGuid + +[Depex] + gEfiVariableArchProtocolGuid AND + gEfiVariableWriteArchProtocolGuid -- 2.34.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#118907): https://edk2.groups.io/g/devel/message/118907 Mute This Topic: https://groups.io/mt/106108338/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=-=-=-=-=-=-=-=-=-=-=- ^ permalink raw reply related [flat|nested] 9+ messages in thread
* [edk2-devel] [RESEND 7/7] AmdPlatformPkg: Adds ACPI common driver 2024-05-15 3:50 [edk2-devel] [RESEND 0/7] AmdPlatformPkg: Adds board independent modules Abdul Lateef Attar via groups.io ` (5 preceding siblings ...) 2024-05-15 3:50 ` [edk2-devel] [RESEND 6/7] AmdPlatformPkg: Adds SecureBootDefaultKeysInit driver Abdul Lateef Attar via groups.io @ 2024-05-15 3:50 ` Abdul Lateef Attar via groups.io 2024-05-15 3:59 ` [edk2-devel] [RESEND 0/7] AmdPlatformPkg: Adds board independent modules Chang, Abner via groups.io 7 siblings, 0 replies; 9+ messages in thread From: Abdul Lateef Attar via groups.io @ 2024-05-15 3:50 UTC (permalink / raw) To: devel; +Cc: Abdul Lateef Attar, Abner Chang, Paul Grimes Adds ACPI common driver which generates. Generates CPU topology SSDT table. Generates PCIe topology SSDT table. Generates SPMI table. Cc: Abner Chang <abner.chang@amd.com> Cc: Paul Grimes <paul.grimes@amd.com> Signed-off-by: Abdul Lateef Attar <AbdulLateef.Attar@amd.com> --- .../AMD/AmdPlatformPkg/AmdPlatformPkg.dec | 13 +- .../AMD/AmdPlatformPkg/AmdPlatformPkg.dsc | 7 +- .../Universal/Acpi/AcpiCommon/AcpiCommon.c | 226 +++ .../Universal/Acpi/AcpiCommon/AcpiCommon.h | 118 ++ .../Universal/Acpi/AcpiCommon/AcpiCommon.inf | 74 + .../Universal/Acpi/AcpiCommon/CpuSsdt.c | 345 ++++ .../Universal/Acpi/AcpiCommon/PciSsdt.c | 1381 +++++++++++++++++ .../Universal/Acpi/AcpiCommon/Spmi.c | 111 ++ 8 files changed, 2273 insertions(+), 2 deletions(-) create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/AcpiCommon.c create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/AcpiCommon.h create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/AcpiCommon.inf create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/CpuSsdt.c create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/PciSsdt.c create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/Spmi.c diff --git a/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dec b/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dec index 4cb66d2a36..83f57f6d0a 100644 --- a/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dec +++ b/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dec @@ -1,7 +1,7 @@ ## @file # AMD Platform common Package DEC file # This is the package provides the AMD edk2 common platform drivers -# and libraries for AMD Server, Clinet and Gaming console platforms. +# and libraries for AMD Server, Client and Gaming console platforms. # # Copyright (C) 2023 - 2024 Advanced Micro Devices, Inc. All rights reserved.<BR> # SPDX-License-Identifier: BSD-2-Clause-Patent @@ -31,3 +31,14 @@ # Platform DSC can set this value to another event GUID. # gAmdPlatformPkgTokenSpaceGuid.PcdAmdDisplayLogoEventGuid|{0xdc, 0xd5, 0xb3, 0x8e, 0xe7, 0xf4, 0x57, 0x4b, 0xa9, 0xe7, 0x27, 0x39, 0x10, 0xf2, 0x18, 0x9f}|VOID*|0x00010001 + +[PcdsFixedAtBuild] + # + # IPMI Interface Type + # + # 0 - Unknown + # 1 - KCS + # 2 - SMIC + # 3 - BT + # 4 - SSIF + gAmdPlatformPkgTokenSpaceGuid.PcdIpmiInterfaceType|0|UINT8|0x00020001 diff --git a/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dsc b/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dsc index 40ed5ea07c..99dd5b341f 100644 --- a/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dsc +++ b/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dsc @@ -1,7 +1,7 @@ ## @file # AMD Platform common Package DSC file # This is the package provides the AMD edk2 common platform drivers -# and libraries for AMD Server, Clinet and Gaming console platforms. +# and libraries for AMD Server, Client and Gaming console platforms. # # Copyright (C) 2023 - 2024 Advanced Micro Devices, Inc. All rights reserved.<BR> # SPDX-License-Identifier: BSD-2-Clause-Patent @@ -24,6 +24,8 @@ !include MdePkg/MdeLibs.dsc.inc [LibraryClasses.Common] + AmlLib|DynamicTablesPkg/Library/Common/AmlLib/AmlLib.inf + AcpiHelperLib|DynamicTablesPkg/Library/Common/AcpiHelperLib/AcpiHelperLib.inf AlwaysFalseDepexLib|AmdPlatformPkg/Library/BaseAlwaysFalseDepexLib/BaseAlwaysFalseDepexLib.inf BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf BaseLib|MdePkg/Library/BaseLib/BaseLib.inf @@ -33,6 +35,7 @@ DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf IntrinsicLib|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf + IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf OpensslLib|CryptoPkg/Library/OpensslLib/OpensslLib.inf PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf PlatformPKProtectionLib|SecurityPkg/Library/PlatformPKProtectionLibVarPolicy/PlatformPKProtectionLibVarPolicy.inf @@ -41,6 +44,7 @@ SecureBootVariableLib|SecurityPkg/Library/SecureBootVariableLib/SecureBootVariableLib.inf SecureBootVariableProvisionLib|SecurityPkg/Library/SecureBootVariableProvisionLib/SecureBootVariableProvisionLib.inf SerialPortLib|MdePkg/Library/BaseSerialPortLibNull/BaseSerialPortLibNull.inf + SortLib|MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf @@ -62,6 +66,7 @@ AmdPlatformPkg/Library/BaseAlwaysFalseDepexLib/BaseAlwaysFalseDepexLib.inf AmdPlatformPkg/Library/DxePlatformSocLib/DxePlatformSocLibNull.inf AmdPlatformPkg/Library/SimulatorSerialPortLibPort80/SimulatorSerialPortLibPort80.inf + AmdPlatformPkg/Universal/Acpi/AcpiCommon/AcpiCommon.inf AmdPlatformPkg/Universal/SecureBoot/SecureBootDefaultKeysInit/SecureBootDefaultKeysInit.inf AmdPlatformPkg/Universal/HiiConfigRouting/AmdConfigRouting.inf AmdPlatformPkg/Universal/LogoDxe/JpegLogoDxe.inf # Server platform JPEG logo driver diff --git a/Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/AcpiCommon.c b/Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/AcpiCommon.c new file mode 100644 index 0000000000..f373115a5f --- /dev/null +++ b/Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/AcpiCommon.c @@ -0,0 +1,226 @@ +/** @file + + FV block I/O protocol driver for SPI flash libary. + + Copyright (C) 2023-2024 Advanced Micro Devices, Inc. All rights reserved. + + SPDX-License-Identifier BSD-2-Clause-Patent +**/ + +#include "AcpiCommon.h" + +EFI_ACPI_TABLE_PROTOCOL *mAcpiTableProtocol; +EFI_ACPI_SDT_PROTOCOL *mAcpiSdtProtocol; + +/** + Locates an existing ACPI Table + + @param[in] Signature - The Acpi table signature + @param[in] OemTableId - The Acpi table OEM Table ID. Ignored if 0 + @param[out] Table - Table if Found or NULL + + @retval EFI_SUCCESS, various EFI FAILUREs. +**/ +EFI_STATUS +EFIAPI +GetExistingAcpiTable ( + IN UINT32 Signature, + IN UINT64 OemTableId, + OUT EFI_ACPI_SDT_HEADER **Table + ) +{ + EFI_STATUS Status; + UINTN Index; + EFI_ACPI_SDT_HEADER *LocalTable; + EFI_ACPI_TABLE_VERSION LocalVersion; + UINTN LocalTableKey; + + Status = EFI_NOT_FOUND; + *Table = NULL; + + for (Index = 0; ; Index++) { + Status = mAcpiSdtProtocol->GetAcpiTable (Index, &LocalTable, &LocalVersion, &LocalTableKey); + if (EFI_ERROR (Status)) { + return Status; + } + + if (!(LocalTable->Signature == Signature)) { + continue; + } + + // Accept table if OemTableId is zero. + if ((OemTableId == 0) || + (CompareMem (&LocalTable->OemTableId, &OemTableId, 8) == 0)) + { + *Table = LocalTable; + return EFI_SUCCESS; + } + } +} + +/** + Appends generated AML to an existing ACPI Table + + 1. Locate the existing ACPI table + 2. Allocate pool for original table plus new data size + 3. Copy original table to new buffer + 4. Append new data to buffer + 5. Update Table header length (Checksum will be calculated on install) + 6. Uninstall original ACPI table + 7. Install appended table + 8. Free new table buffer since ACPI made a copy. + + @param[in] Signature - The Acpi table signature + @param[in] OemId - The Acpi table OEM ID + @param[in] AmlData - The AML data to append + + @retval EFI_SUCCESS, various EFI FAILUREs. +**/ +EFI_STATUS +EFIAPI +AppendExistingAcpiTable ( + IN UINT32 Signature, + IN UINT64 OemId, + IN EFI_ACPI_DESCRIPTION_HEADER *AmlData + ) +{ + EFI_STATUS Status; + UINTN Index; + EFI_ACPI_SDT_HEADER *Table; + EFI_ACPI_TABLE_VERSION Version; + UINTN TableKey; + EFI_ACPI_SDT_HEADER *ReplacementAcpiTable; + UINT32 ReplacementAcpiTableLength; + UINTN TableHandle; + + for (Index = 0; ; Index++) { + Status = mAcpiSdtProtocol->GetAcpiTable (Index, &Table, &Version, &TableKey); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "ERROR: ACPI table not found with signature=0x%X\n", Signature)); + return Status; + } + + if ((Table->Signature == Signature) && + (CompareMem (&Table->OemTableId, &OemId, 8) == 0)) + { + break; + } + } + + // Calculate new DSDT Length and allocate space + ReplacementAcpiTableLength = Table->Length + (UINT32)(AmlData->Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)); + ReplacementAcpiTable = AllocatePool (ReplacementAcpiTableLength); + if (ReplacementAcpiTable == NULL) { + DEBUG ((DEBUG_ERROR, "ERROR: Unable to allocate Replacement Table space.\n")); + return EFI_OUT_OF_RESOURCES; + } + + // Copy the old DSDT to the new buffer + CopyMem (ReplacementAcpiTable, Table, Table->Length); + // Append new data to DSDT + CopyMem ( + (UINT8 *)ReplacementAcpiTable + Table->Length, + (UINT8 *)AmlData + sizeof (EFI_ACPI_DESCRIPTION_HEADER), + AmlData->Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER) + ); + ReplacementAcpiTable->Length = ReplacementAcpiTableLength; + + // Uninstall the original DSDT + Status = mAcpiTableProtocol->UninstallAcpiTable ( + mAcpiTableProtocol, + TableKey + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "ERROR: Unable to uninstall original ACPI Table signature=0x%X\n", Signature)); + } else { + // Install ACPI table + Status = mAcpiTableProtocol->InstallAcpiTable ( + mAcpiTableProtocol, + ReplacementAcpiTable, + ReplacementAcpiTableLength, + &TableHandle + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "ERROR: Unable to re-install ACPI Table signature=0x%X\n", Signature)); + } + } + + // Release this copy of table + FreePool (ReplacementAcpiTable); + return Status; +} + +/** + Install common platform SSDTs and DSDT additions + + Place to install all generically identifiable SSDT tables. These tables will + be programmatically created from UEFI or other resources and should cover + many different Processor Family IPs. + + Might need to split this driver into LibraryClasses for each + functionality/SSDT while keeping a single driver to reduce the AmlLib overhead. + + @param[in] ImageHandle - Standard UEFI entry point Image Handle + @param[in] SystemTable - Standard UEFI entry point System Table + + @retval EFI_SUCCESS, various EFI FAILUREs. +**/ +EFI_STATUS +EFIAPI +InstallAllAcpiTables ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + DEBUG ((DEBUG_INFO, "%a: Entry\n", __FUNCTION__)); + + // Get Acpi Table Protocol + Status = gBS->LocateProtocol ( + &gEfiAcpiTableProtocolGuid, + NULL, + (VOID **)&mAcpiTableProtocol + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // Get Acpi SDT Protocol + Status = gBS->LocateProtocol ( + &gEfiAcpiSdtProtocolGuid, + NULL, + (VOID **)&mAcpiSdtProtocol + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = InstallCpuAcpi (ImageHandle, SystemTable); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "%a: CPU SSDT install error: Status=%r\n", + __FUNCTION__, + Status + )); + ASSERT_EFI_ERROR (Status); + return Status; + } + + Status = InstallPciAcpi (ImageHandle, SystemTable); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "%a: PCI SSDT install error: Status=%r\n", + __FUNCTION__, + Status + )); + ASSERT_EFI_ERROR (Status); + return Status; + } + + InstallAcpiSpmiTable (); + + return Status; +} diff --git a/Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/AcpiCommon.h b/Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/AcpiCommon.h new file mode 100644 index 0000000000..b9db33ac76 --- /dev/null +++ b/Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/AcpiCommon.h @@ -0,0 +1,118 @@ +/** @file + + FV block I/O protocol driver for SPI flash libary. + + Copyright (C) 2023-2024 Advanced Micro Devices, Inc. All rights reserved. + + SPDX-License-Identifier BSD-2-Clause-Patent +**/ + +#ifndef ACPI_COMMON_H_ +#define ACPI_COMMON_H_ + +#include <IndustryStandard/Acpi.h> +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/PcdLib.h> +#include <Library/PrintLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Protocol/AcpiSystemDescriptionTable.h> +#include <Protocol/AcpiTable.h> +#include <Uefi.h> + +#define AMD_DSDT_OEMID SIGNATURE_64 ('A', 'm', 'd', 'T','a','b','l','e') +#define CREATOR_REVISION 2 +#define MAX_LOCAL_STRING_SIZE 20 +#define OEM_REVISION_NUMBER 0 +#define CXL_EARLY_DISCOVERY_TABLE_SIGNATURE SIGNATURE_32 ('C', 'E', 'D', 'T') /// "CEDT" CXL Early Discovery Table + +extern EFI_ACPI_TABLE_PROTOCOL *mAcpiTableProtocol; +extern EFI_ACPI_SDT_PROTOCOL *mAcpiSdtProtocol; + +/** + Locates an existing ACPI Table + + @param[in] Signature - The Acpi table signature + @param[in] OemTableId - The Acpi table OEM Table ID. Ignored if 0 + @param[out] Table - Table if Found or NULL + + @retval EFI_SUCCESS, various EFI FAILUREs. +**/ +EFI_STATUS +EFIAPI +GetExistingAcpiTable ( + IN UINT32 Signature, + IN UINT64 OemTableId, + OUT EFI_ACPI_SDT_HEADER **Table + ); + +/** + Appends generated AML to an existing ACPI Table + + 1. Locate the existing ACPI table + 2. Allocate pool for original table plus new data size + 3. Copy original table to new buffer + 4. Append new data to buffer + 5. Update Table header length (Checksum will be calculated on install) + 6. Uninstall original ACPI table + 7. Install appended table + 8. Free new table buffer since ACPI made a copy. + + @param[in] Signature - The Acpi table signature + @param[in] OemId - The Acpi table OEM ID + @param[in] AmlData - The AML data to append + + @retval EFI_SUCCESS, various EFI FAILUREs. +**/ +EFI_STATUS +EFIAPI +AppendExistingAcpiTable ( + IN UINT32 Signature, + IN UINT64 OemId, + IN EFI_ACPI_DESCRIPTION_HEADER *AmlData + ); + +/** + Install CPU devices scoped under \_SB into DSDT + + Determine all the CPU threads and create ACPI Device nodes for each thread. + + @param[in] ImageHandle - Standard UEFI entry point Image Handle + @param[in] SystemTable - Standard UEFI entry point System Table + + @retval EFI_SUCCESS, various EFI FAILUREs. +**/ +EFI_STATUS +EFIAPI +InstallCpuAcpi ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Install PCI devices scoped under \_SB into DSDT + + Determine all the PCI Root Bridges and PCI root ports and install resources + including needed _HID, _CID, _UID, _ADR, _CRS and _PRT Nodes. + + @param[in] ImageHandle - Standard UEFI entry point Image Handle + @param[in] SystemTable - Standard UEFI entry point System Table + + @retval EFI_SUCCESS, various EFI FAILUREs. +**/ +EFI_STATUS +EFIAPI +InstallPciAcpi ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +VOID +EFIAPI +InstallAcpiSpmiTable ( + VOID + ); + +#endif // ACPI_COMMON_H__ diff --git a/Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/AcpiCommon.inf b/Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/AcpiCommon.inf new file mode 100644 index 0000000000..2c17dbb500 --- /dev/null +++ b/Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/AcpiCommon.inf @@ -0,0 +1,74 @@ +## @file +# Creates ACPI tables for AMD platforms. +# +# Copyright (C) 2023 - 2024 Advanced Micro Devices, Inc. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = AcpiCommon + FILE_GUID = 66838F31-1062-415C-957A-CC2871D9E6B7 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = InstallAllAcpiTables + +[Sources.common] + AcpiCommon.c + AcpiCommon.h + CpuSsdt.c + PciSsdt.c + Spmi.c + +[Packages] + AmdPlatformPkg/AmdPlatformPkg.dec + DynamicTablesPkg/DynamicTablesPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + MinPlatformPkg/MinPlatformPkg.dec + PcAtChipsetPkg/PcAtChipsetPkg.dec + +[LibraryClasses] + AmlLib + BaseLib + BaseMemoryLib + DebugLib + HobLib + IoLib + MemoryAllocationLib + PcdLib + PlatformSocLib + SortLib + UefiDriverEntryPoint + +[Protocols] + gEfiAcpiSdtProtocolGuid ## CONSUMES + gEfiAcpiTableProtocolGuid ## CONSUMES + gEfiMpServiceProtocolGuid ## CONSUMES + gEfiPciRootBridgeIoProtocolGuid ## CONSUMES + +[Pcd] + gAmdPlatformPkgTokenSpaceGuid.PcdIpmiInterfaceType ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorId ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorRevision ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemId ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemRevision ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemTableId ## CONSUMES + gEfiMdePkgTokenSpaceGuid.PcdIpmiKcsIoBaseAddress ## CONSUMES + gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress ## CONSUMES + gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseSize ## CONSUMES + gMinPlatformPkgTokenSpaceGuid.PcdIoApicAddress ## CONSUMES + gMinPlatformPkgTokenSpaceGuid.PcdMaxCpuSocketCount ## CONSUMES + gMinPlatformPkgTokenSpaceGuid.PcdPcIoApicAddressBase + +[Guids] + gEfiHobListGuid + +[Depex] + gEfiMpServiceProtocolGuid AND + gEfiAcpiTableProtocolGuid AND + gEfiPciRootBridgeIoProtocolGuid AND + gEfiPciEnumerationCompleteProtocolGuid + diff --git a/Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/CpuSsdt.c b/Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/CpuSsdt.c new file mode 100644 index 0000000000..345fb4f8c9 --- /dev/null +++ b/Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/CpuSsdt.c @@ -0,0 +1,345 @@ +/** @file + + FV block I/O protocol driver for SPI flash libary. + + Copyright (C) 2023 - 2024 Advanced Micro Devices, Inc. All rights reserved. + + SPDX-License-Identifier BSD-2-Clause-Patent +**/ +#include "AcpiCommon.h" + +#include <Library/AmlLib/AmlLib.h> +#include <Library/SortLib.h> +#include <Protocol/MpService.h> +#include <Register/Intel/Cpuid.h> // for CPUID_EXTENDED_TOPOLOGY + +#define AMD_CPUID_EXTENDED_TOPOLOGY_V2 0x26 +#define AMD_CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_CCD 0x04 +#define AMD_CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_CCX 0x03 +#define AMD_CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE 0x05 +#define CREATOR_REVISION 2 +#define DEVICE_BATTERY_BIT 0x0010// Control Method Battery Device Only +#define DEVICE_ENABLED_BIT 0x0002 +#define DEVICE_HEALTH_BIT 0x0008 +#define DEVICE_IN_UI_BIT 0x0004 +#define DEVICE_PRESENT_BIT 0x0001 +#define MAX_TEST_CPU_STRING_SIZE 20 +#define OEM_REVISION_NUMBER 0 + +EFI_PROCESSOR_INFORMATION *mApicIdtoUidMap = NULL; +UINT32 mCcdOrder[16] = { 0, 4, 8, 12, 2, 6, 10, 14, 3, 7, 11, 15, 1, 5, 9, 13 }; +UINTN mNumberOfCpus = 0; +UINTN mNumberOfEnabledCPUs = 0; + +/** + Callback compare function. + Compares CCD number of provided arguments. + + @param[in] LocalX2ApicLeft Pointer to Left Buffer. + @param[in] LocalX2ApicRight Pointer to Right Buffer. + @return 0 If both are same + -1 If left value is less than righ value. + 1 If left value is greater than righ value. + +**/ +INTN +EFIAPI +SortByCcd ( + IN CONST VOID *LocalX2ApicLeft, + IN CONST VOID *LocalX2ApicRight + ) +{ + EFI_PROCESSOR_INFORMATION *Left; + EFI_PROCESSOR_INFORMATION *Right; + UINT32 Index; + UINT32 LeftCcdIndex; + UINT32 RightCcdIndex; + + Left = (EFI_PROCESSOR_INFORMATION *)LocalX2ApicLeft; + Right = (EFI_PROCESSOR_INFORMATION *)LocalX2ApicRight; + + // Get the CCD Index number + LeftCcdIndex = MAX_UINT32; + for (Index = 0; Index < ARRAY_SIZE (mCcdOrder); Index++) { + if (Left->ExtendedInformation.Location2.Die == mCcdOrder[Index]) { + LeftCcdIndex = Index; + break; + } + } + + RightCcdIndex = MAX_UINT32; + for (Index = 0; Index < ARRAY_SIZE (mCcdOrder); Index++) { + if (Right->ExtendedInformation.Location2.Die == mCcdOrder[Index]) { + RightCcdIndex = Index; + break; + } + } + + // Now compare for quick sort + if (LeftCcdIndex < RightCcdIndex) { + return -1; + } + + if (LeftCcdIndex > RightCcdIndex) { + return 1; + } + + return 0; +} + +/** + Generate ApicId to Processor UID map. + + @retval EFI_SUCCESS - ApicId to Processor UID map generated successfully. + @retval EFI_NOT_FOUND - MP Service Protocol not found. + @retval EFI_OUT_OF_RESOURCES - Memory allocation failed. +**/ +EFI_STATUS +GenerateApicIdtoUidMap ( + VOID + ) +{ + EFI_MP_SERVICES_PROTOCOL *MpService; + EFI_STATUS Status; + UINTN Index; + + // Get MP service + Status = gBS->LocateProtocol (&gEfiMpServiceProtocolGuid, NULL, (VOID **)&MpService); + if (EFI_ERROR (Status) || (MpService == NULL)) { + return EFI_NOT_FOUND; + } + + // Load MpServices + Status = MpService->GetNumberOfProcessors (MpService, &mNumberOfCpus, &mNumberOfEnabledCPUs); + if (EFI_ERROR (Status)) { + return Status; + } + + DEBUG ((DEBUG_ERROR, "%a: NumberOfCpus = %d mNumberOfEnabledCPUs = %d\n", __func__, mNumberOfCpus, mNumberOfEnabledCPUs)); + + mApicIdtoUidMap = AllocateZeroPool (mNumberOfCpus * sizeof (EFI_PROCESSOR_INFORMATION)); + if (mApicIdtoUidMap == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + for (Index = 0; Index < mNumberOfCpus; Index++) { + Status = MpService->GetProcessorInfo ( + MpService, + Index | CPU_V2_EXTENDED_TOPOLOGY, + &mApicIdtoUidMap[Index] + ); + } + + if (FixedPcdGet32 (PcdMaxCpuSocketCount) > 1) { + /// Sort by CCD location + PerformQuickSort (mApicIdtoUidMap, mNumberOfCpus/2, sizeof (EFI_PROCESSOR_INFORMATION), SortByCcd); + PerformQuickSort (mApicIdtoUidMap+(mNumberOfCpus/2), mNumberOfCpus/2, sizeof (EFI_PROCESSOR_INFORMATION), SortByCcd); + } else { + /// Sort by CCD location + PerformQuickSort (mApicIdtoUidMap, mNumberOfCpus, sizeof (EFI_PROCESSOR_INFORMATION), SortByCcd); + } + + // Now allocate the Uid + for (Index = 0; Index < mNumberOfCpus; Index++) { + // Now make Processor as Uid + mApicIdtoUidMap[Index].ProcessorId = Index; + } + + return EFI_SUCCESS; +} + +/** + Install CPU devices scoped under \_SB into DSDT + + Determine all the CPU threads and create ACPI Device nodes for each thread. + + @param[in] ImageHandle - Standard UEFI entry point Image Handle + @param[in] SystemTable - Standard UEFI entry point System Table + + @retval EFI_SUCCESS, various EFI FAILUREs. +**/ +EFI_STATUS +EFIAPI +InstallCpuAcpi ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + AML_OBJECT_NODE_HANDLE CpuInstanceNode; + AML_OBJECT_NODE_HANDLE CpuNode; + AML_OBJECT_NODE_HANDLE ScopeNode; + AML_ROOT_NODE_HANDLE RootNode; + CHAR8 *String; + CHAR8 Identifier[MAX_TEST_CPU_STRING_SIZE]; + EFI_ACPI_DESCRIPTION_HEADER *Table; + EFI_MP_SERVICES_PROTOCOL *MpServices; + EFI_STATUS Status; + EFI_STATUS Status1; + UINTN DeviceStatus; + UINTN Index; + UINTN NumberOfEnabledProcessors; + UINTN NumberOfLogicProcessors; + + DEBUG ((DEBUG_INFO, "%a: Entry\n", __FUNCTION__)); + + String = &Identifier[0]; + + // Get MP service + MpServices = NULL; + Status = gBS->LocateProtocol (&gEfiMpServiceProtocolGuid, NULL, (VOID **)&MpServices); + if (EFI_ERROR (Status) || (MpServices == NULL)) { + return EFI_NOT_FOUND; + } + + // Generate ACPI UID Map + Status = GenerateApicIdtoUidMap (); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Could not generate ApicId to ProcessorUid map.\n", __func__)); + return EFI_NOT_FOUND; + } + + // Load MpServices + Status = MpServices->GetNumberOfProcessors (MpServices, &NumberOfLogicProcessors, &NumberOfEnabledProcessors); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = AmlCodeGenDefinitionBlock ( + "SSDT", + "AMD ", + "SSDTPROC", + 0x00, + &RootNode + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + Status = AmlCodeGenScope ("\\_SB_", RootNode, &ScopeNode); // START: Scope (\_SB) + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + CpuNode = ScopeNode; + + for (Index = 0; Index < NumberOfLogicProcessors; Index++) { + // Check for valid Processor under the current socket + if (!mApicIdtoUidMap[Index].StatusFlag) { + continue; + } + + AsciiSPrint (String, MAX_TEST_CPU_STRING_SIZE, "C%03X", Index); + Status = AmlCodeGenDevice (String, CpuNode, &CpuInstanceNode); // START: Device (CXXX) + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // _HID + Status = AmlCodeGenNameString ("_HID", "ACPI0007", CpuInstanceNode, NULL); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + DeviceStatus = DEVICE_PRESENT_BIT | DEVICE_IN_UI_BIT; + if (mApicIdtoUidMap[Index].StatusFlag & PROCESSOR_ENABLED_BIT) { + DeviceStatus |= DEVICE_ENABLED_BIT; + } + + if (mApicIdtoUidMap[Index].StatusFlag & PROCESSOR_HEALTH_STATUS_BIT) { + DeviceStatus |= DEVICE_HEALTH_BIT; + } + + // _UID - Must match ACPI Processor UID in MADT + Status = AmlCodeGenNameInteger ("_UID", mApicIdtoUidMap[Index].ProcessorId, CpuInstanceNode, NULL); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // _STA - As defined by 6.3.7 + Status = AmlCodeGenMethodRetInteger ("_STA", DeviceStatus, 0, FALSE, 0, CpuInstanceNode, NULL); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // PACK -> Package + Status = AmlCodeGenNameInteger ("PACK", mApicIdtoUidMap[Index].ExtendedInformation.Location2.Package, CpuInstanceNode, NULL); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // CCD_ -> Ccd + Status = AmlCodeGenNameInteger ("CCD_", mApicIdtoUidMap[Index].ExtendedInformation.Location2.Die, CpuInstanceNode, NULL); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // CCX_ -> Ccx + Status = AmlCodeGenNameInteger ("CCX_", mApicIdtoUidMap[Index].ExtendedInformation.Location2.Module, CpuInstanceNode, NULL); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // CORE -> Core Number + Status = AmlCodeGenNameInteger ("CORE", mApicIdtoUidMap[Index].ExtendedInformation.Location2.Core, CpuInstanceNode, NULL); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // THRD -> Thread + Status = AmlCodeGenNameInteger ("THRD", mApicIdtoUidMap[Index].ExtendedInformation.Location2.Thread, CpuInstanceNode, NULL); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + } + + Table = NULL; + // Serialize the tree. + Status = AmlSerializeDefinitionBlock ( + RootNode, + &Table + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: SSDT-PCI: Failed to Serialize SSDT Table Data." + " Status = %r\n", + Status + )); + return (Status); + } + + // Cleanup + Status1 = AmlDeleteTree (RootNode); + if (EFI_ERROR (Status1)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: SSDT-PCI: Failed to cleanup AML tree." + " Status = %r\n", + Status1 + )); + // If Status was success but we failed to delete the AML Tree + // return Status1 else return the original error code, i.e. Status. + if (!EFI_ERROR (Status)) { + return Status1; + } + } + + Status = AppendExistingAcpiTable ( + EFI_ACPI_6_5_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE, + AMD_DSDT_OEMID, + Table + ); + + return Status; +} diff --git a/Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/PciSsdt.c b/Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/PciSsdt.c new file mode 100644 index 0000000000..a9d3c83a5e --- /dev/null +++ b/Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/PciSsdt.c @@ -0,0 +1,1381 @@ +/** @file + Creates SSDT table for PCIe devices + + Copyright (C) 2023 - 2024 Advanced Micro Devices, Inc. All rights reserved. + + SPDX-License-Identifier BSD-2-Clause-Patent +**/ +#include <Library/AcpiHelperLib.h> +#include <Library/AmdPlatformSocLib.h> +#include <Library/AmlLib/AmlLib.h> +#include <Library/DebugLib.h> +#include <Library/IoLib.h> +#include <Library/PcdLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Protocol/PciRootBridgeIo.h> +#include <Register/IoApic.h> +#include <Uefi/UefiSpec.h> +#include "AcpiCommon.h" + +#define MAX_PCI_BUS_NUMBER_PER_SEGMENT 0x100 + +EFI_HANDLE mDriverHandle; + +/** + Collect and sort the root bridge devices + + Does not include the Root Bridge resources + + @param[in, out] RootBridge - RootBridge information pointer + @param[in, out] RootBridgeCount - Number of root bridges + @retval EFI_SUCCESS, various EFI FAILUREs. +**/ +EFI_STATUS +EFIAPI +InternalCollectSortedRootBridges ( + IN OUT AMD_PCI_ROOT_BRIDGE_OBJECT_INSTANCE **RootBridge, + IN OUT UINTN *RootBridgeCount + ) +{ + UINTN Index; + AMD_PCI_ROOT_BRIDGE_OBJECT_INSTANCE *LocalRootBridge; // do not free + AMD_PCI_ROOT_BRIDGE_OBJECT_INSTANCE *SortedRb; + AMD_PCI_ROOT_BRIDGE_OBJECT_INSTANCE *UnsortedRb; + AMD_PCI_ROOT_BRIDGE_OBJECT_INSTANCE TempRootBridge; + UINTN LocalRootBridgeCount; + UINTN SortedIndex; + UINTN UnsortedIndex; + EFI_STATUS Status; + + if ((RootBridge == NULL) || (RootBridgeCount == NULL)) { + return EFI_INVALID_PARAMETER; + } + + LocalRootBridge = NULL; + LocalRootBridgeCount = 0; + Status = GetPcieInfo (&LocalRootBridge, &LocalRootBridgeCount); + if (EFI_ERROR (Status) || (LocalRootBridge == NULL) || (LocalRootBridgeCount == 0)) { + DEBUG ((DEBUG_ERROR, "%a:%d Cannot obtain Platform PCIe configuration information.\n", __func__, __LINE__)); + return EFI_NOT_FOUND; + } + + // Sort by PCIe bus number + for (SortedIndex = 0, SortedRb = LocalRootBridge; SortedIndex < LocalRootBridgeCount; SortedIndex++, SortedRb++) { + for (UnsortedIndex = 0, UnsortedRb = LocalRootBridge; UnsortedIndex < LocalRootBridgeCount; UnsortedIndex++, UnsortedRb++) { + if (SortedRb->Object->BaseBusNumber < UnsortedRb->Object->BaseBusNumber) { + CopyMem (&TempRootBridge, UnsortedRb, sizeof (AMD_PCI_ROOT_BRIDGE_OBJECT_INSTANCE)); + CopyMem (UnsortedRb, SortedRb, sizeof (AMD_PCI_ROOT_BRIDGE_OBJECT_INSTANCE)); + CopyMem (SortedRb, &TempRootBridge, sizeof (AMD_PCI_ROOT_BRIDGE_OBJECT_INSTANCE)); + } + } + } + + for (Index = 0; Index < LocalRootBridgeCount; Index++) { + // Assign Uid values + LocalRootBridge[Index].Uid = Index; + } + + *RootBridge = LocalRootBridge; + *RootBridgeCount = LocalRootBridgeCount; + return EFI_SUCCESS; +} + +/** + Insert Root Bridge interrupts into AML table + + @param[in] RootBridge - Single Root Bridge instance + @param[in, out] GlobalInterruptBase - Global interrupt base + @param[in, out] PciNode - AML tree node + + @retval EFI_SUCCESS, various EFI FAILUREs. +**/ +EFI_STATUS +EFIAPI +InternalInsertRootBridgeInterrupts ( + IN AMD_PCI_ROOT_BRIDGE_OBJECT_INSTANCE *RootBridge, + IN OUT UINTN *GlobalInterruptBase, + IN OUT AML_OBJECT_NODE_HANDLE PciNode + ) +{ + AML_OBJECT_NODE_HANDLE PrtNode; + EFI_STATUS Status; + UINTN Index; + + Status = AmlCodeGenNamePackage ("_PRT", NULL, &PrtNode); + ASSERT_EFI_ERROR (Status); + + if ((RootBridge->Object->BaseBusNumber == 0) && (RootBridge->Object->Segment == 0)) { + // Package () {0x0014FFFF, 0, 0, 16}, // 0 + 16 + Status = AmlAddPrtEntry ( + 0x0014FFFF, + 0, + NULL, + 16, + PrtNode + ); + ASSERT_EFI_ERROR (Status); + + // Package () {0x0014FFFF, 1, 0, 17}, // 0 + 17 + Status = AmlAddPrtEntry ( + 0x0014FFFF, + 1, + NULL, + 17, + PrtNode + ); + ASSERT_EFI_ERROR (Status); + + // Package () {0x0014FFFF, 2, 0, 18}, // 0 + 18 + Status = AmlAddPrtEntry ( + 0x0014FFFF, + 2, + NULL, + 18, + PrtNode + ); + ASSERT_EFI_ERROR (Status); + + // Package () {0x0014FFFF, 3, 0, 19}, // 0 + 19 + Status = AmlAddPrtEntry ( + 0x0014FFFF, + 3, + NULL, + 19, + PrtNode + ); + ASSERT_EFI_ERROR (Status); + } + + /// Add interrupt for Device 0 function 3 (generic to all function) + /// Value is taken from CRB BIOS + /// Fix the "pcie port 0000:XX:XX.3: can't derive routing for PCI INT A" error + Status = AmlAddPrtEntry ( + 0xFFFF, + 0, + NULL, + (UINT32)(RootBridge->GlobalInterruptStart + 1), + PrtNode + ); + ASSERT_EFI_ERROR (Status); + + for (Index = 1; Index <= RootBridge->RootPortCount; Index++) { + if ((RootBridge->RootPort[Index]->PortPresent == 0) && (RootBridge->RootPort[Index]->Enabled == 0)) { + continue; + } + + // Only insert for Functions 1 - 4 (minus 1) + if (((RootBridge->RootPort[Index]->Function - 1) & ~0x3) == 0) { + Status = AmlAddPrtEntry ( + (UINT32)((RootBridge->RootPort[Index]->Device << 16) | 0x0000FFFF), + (UINT8)(RootBridge->RootPort[Index]->Function - 1), + NULL, + (UINT32)(RootBridge->GlobalInterruptStart + RootBridge->RootPort[Index]->EndpointInterruptArray[RootBridge->RootPort[Index]->Function - 1]), + PrtNode + ); + ASSERT_EFI_ERROR (Status); + } + } + + // Attach the _PRT entry. + Status = AmlAttachNode (PciNode, PrtNode); + if (EFI_ERROR (Status)) { + AmlDeleteTree (PrtNode); + ASSERT_EFI_ERROR (Status); + } + + PrtNode = NULL; + + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + return Status; +} + +/** + Insert Root Bridge resources into AML table + + @param[in] RootBridge - Single Root Bridge instance + @param[in, out] CrsNode - AML tree node + + @retval EFI_SUCCESS, various EFI FAILUREs. +**/ +EFI_STATUS +EFIAPI +InternalInsertRootBridgeResources ( + IN AMD_PCI_ROOT_BRIDGE_OBJECT_INSTANCE *RootBridge, + IN OUT AML_OBJECT_NODE_HANDLE CrsNode + ) +{ + EFI_STATUS Status; + EFI_HANDLE *HandleBuffer; + UINTN NumHandles; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *Io; + UINTN Index; + VOID *Configuration; // Never free this buffer + EFI_ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR *LocalBuffer; + UINTN BaseBusNumber; + + BaseBusNumber = ~(UINTN)0; + // Get EFI Pci Root Bridge I/O Protocols + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiPciRootBridgeIoProtocolGuid, + NULL, + &NumHandles, + &HandleBuffer + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // Locate the Root Bridge IO protocol for this root bridge. + LocalBuffer = NULL; + Configuration = NULL; + for (Index = 0; Index < NumHandles; Index++) { + Status = gBS->OpenProtocol ( + HandleBuffer[Index], + &gEfiPciRootBridgeIoProtocolGuid, + (VOID **)&Io, + mDriverHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + if (Io->SegmentNumber == RootBridge->Object->Segment) { + Status = Io->Configuration (Io, &Configuration); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: ERROR: Retrieve Root Bridge Configuration failed\n", __func__)); + return Status; + } + + LocalBuffer = Configuration; + while (TRUE) { + if (LocalBuffer->Header.Header.Byte == ACPI_END_TAG_DESCRIPTOR) { + LocalBuffer = NULL; + break; + } else if (LocalBuffer->Header.Header.Byte == ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR) { + if ((LocalBuffer->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) && + (LocalBuffer->AddrRangeMin == RootBridge->Object->BaseBusNumber)) + { + BaseBusNumber = LocalBuffer->AddrRangeMin; + break; + } + } + + LocalBuffer++; + } + + if (BaseBusNumber == RootBridge->Object->BaseBusNumber) { + break; + } + } + } + + if ((Configuration == NULL) || (LocalBuffer == NULL)) { + DEBUG ((DEBUG_ERROR, "%a: ERROR: Retrieve Root Bridge Configuration failed\n", __func__)); + return EFI_NOT_FOUND; + } + + LocalBuffer = Configuration; + + // All Elements are sizeof (EFI_ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR) except + // for the End Tag + // Parse through Root Bridge resources and insert them in the ACPI Table + while (TRUE) { + if (LocalBuffer->Header.Header.Byte == ACPI_END_TAG_DESCRIPTOR) { + break; + } else if (LocalBuffer->Header.Header.Byte == ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR) { + if (LocalBuffer->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) { + BaseBusNumber = LocalBuffer->AddrRangeMin; + Status = AmlCodeGenRdWordBusNumber ( + FALSE, + TRUE, + TRUE, + TRUE, + 0, + (UINT16)LocalBuffer->AddrRangeMin, + (UINT16)LocalBuffer->AddrRangeMax, + (UINT16)LocalBuffer->AddrTranslationOffset, + (UINT16)LocalBuffer->AddrLen, + 0, + NULL, + CrsNode, + NULL + ); + } else if (LocalBuffer->ResType == ACPI_ADDRESS_SPACE_TYPE_IO) { + Status = AmlCodeGenRdWordIo ( + FALSE, + TRUE, + TRUE, + TRUE, + 3, // entire ranges + 0, + (UINT16)LocalBuffer->AddrRangeMin, + (UINT16)LocalBuffer->AddrRangeMax, + (UINT16)LocalBuffer->AddrTranslationOffset, + (UINT16)LocalBuffer->AddrLen, + 0, + NULL, + TRUE, + TRUE, + CrsNode, + NULL + ); + } else if (LocalBuffer->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) { + Status = AmlCodeGenRdQWordMemory ( + FALSE, + TRUE, + TRUE, + TRUE, + FALSE, // non cacheable + TRUE, + 0, + LocalBuffer->AddrRangeMin, + LocalBuffer->AddrRangeMax, + LocalBuffer->AddrTranslationOffset, + LocalBuffer->AddrLen, + 0, + NULL, + 0, + TRUE, + CrsNode, + NULL + ); + } + } else { + DEBUG ((DEBUG_ERROR, "%a: ERROR: Invalid Configuration Entry\n", __func__)); + return EFI_NOT_FOUND; + } + + LocalBuffer++; + } + + if ((RootBridge->Object->Segment == 0) && (BaseBusNumber == 0)) { + Status = AmlCodeGenRdWordIo ( + FALSE, + TRUE, + TRUE, + FALSE, + 3, // entire ranges + 0, + 0, + 0x0FFF, + 0, + 0x1000, + 0, + NULL, + TRUE, + TRUE, + CrsNode, + NULL + ); + + Status = AmlCodeGenRdQWordMemory ( + FALSE, + TRUE, + TRUE, + TRUE, + FALSE, // non cacheable + TRUE, + 0, + PcdGet32 (PcdPcIoApicAddressBase), + 0xFED3FFFF, + 0x0, + 0x140000, + 0, + NULL, + 0, + TRUE, + CrsNode, + NULL + ); + + Status = AmlCodeGenRdQWordMemory ( + FALSE, + TRUE, + TRUE, + TRUE, + FALSE, // non cacheable + TRUE, + 0, + 0xFED45000, + 0xFEDC1FFF, + 0x0, + 0x7D000, + 0, + NULL, + 0, + TRUE, + CrsNode, + NULL + ); + + Status = AmlCodeGenRdQWordMemory ( + FALSE, + TRUE, + TRUE, + TRUE, + FALSE, // non cacheable + TRUE, + 0, + 0xFEDC7000, + 0xFEDCAFFF, + 0x0, + 0x4000, + 0, + NULL, + 0, + TRUE, + CrsNode, + NULL + ); + + Status = AmlCodeGenRdQWordMemory ( + FALSE, + TRUE, + TRUE, + TRUE, + FALSE, // non cacheable + TRUE, + 0, + 0xFEDCC000, + 0xFEDFFFFF, + 0x0, + 0x34000, + 0, + NULL, + 0, + TRUE, + CrsNode, + NULL + ); + + Status = AmlCodeGenRdQWordMemory ( + FALSE, + TRUE, + TRUE, + TRUE, + FALSE, // non cacheable + TRUE, + 0, + 0xFEE01000, + 0xFEFFFFFF, + 0x0, + 0x1FF000, + 0, + NULL, + 0, + TRUE, + CrsNode, + NULL + ); + } + + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + return Status; + } + + return EFI_SUCCESS; +} + +/** + Insert Root Port into the AML table + + @param[in] RootBridge - Single Root Bridge instance + @param[in] GlobalInterruptBase - Base to add to IOAPIC interrupt offset + @param[in,out] PciNode - AmlLib table node + + @retval EFI_SUCCESS, various EFI FAILUREs. +**/ +EFI_STATUS +EFIAPI +InternalInsertRootPorts ( + IN AMD_PCI_ROOT_BRIDGE_OBJECT_INSTANCE *RootBridge, + IN UINTN GlobalInterruptBase, + IN OUT AML_OBJECT_NODE_HANDLE PciNode + ) +{ + EFI_STATUS Status; + CHAR8 NameSeg[5]; + CHAR8 RpName[15]; + UINTN RPIndex; + UINTN Index; + AML_OBJECT_NODE_HANDLE DeviceNode; + AML_OBJECT_NODE_HANDLE PrtNode; + AML_OBJECT_NODE_HANDLE DsmMethod; + AML_OBJECT_NODE_HANDLE OstMethod; + AML_METHOD_PARAM MethodParam[7]; + + for (RPIndex = 1; RPIndex <= RootBridge->RootPortCount; RPIndex++) { + if ((RootBridge->RootPort[RPIndex]->PortPresent == 0) && (RootBridge->RootPort[RPIndex]->Enabled == 0)) { + continue; + } + + CopyMem (NameSeg, "RPxx", AML_NAME_SEG_SIZE + 1); + NameSeg[AML_NAME_SEG_SIZE - 2] = AsciiFromHex (RootBridge->RootPort[RPIndex]->Device & 0xF); + NameSeg[AML_NAME_SEG_SIZE - 1] = AsciiFromHex (RootBridge->RootPort[RPIndex]->Function & 0xF); + + Status = AmlCodeGenDevice (NameSeg, PciNode, &DeviceNode); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + Status = AmlCodeGenNameInteger ( + "_ADR", + (RootBridge->RootPort[RPIndex]->Device << 16) + RootBridge->RootPort[RPIndex]->Function, + DeviceNode, + NULL + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // Insert Slot User Number _SUN Record. + if (RootBridge->RootPort[RPIndex]->SlotNum != 0) { + Status = AmlCodeGenNameInteger ( + "_SUN", + RootBridge->RootPort[RPIndex]->SlotNum, + DeviceNode, + NULL + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + } + + // _DSM and _OST, handling for root port EDR feature. + // Device 1 to 4 are external PCIe ports, only include them. + if ((RootBridge->RootPort[RPIndex]->Device > 0) && (RootBridge->RootPort[RPIndex]->Device < 5)) { + DEBUG (( + DEBUG_INFO, + "%a:Add EDR support for Uid 0x%x Addr 0x%x\n", + __func__, + RootBridge->Uid, + ((RootBridge->RootPort[RPIndex]->Device << 16) + RootBridge->RootPort[RPIndex]->Function) + )); + + AsciiSPrint ( + RpName, + 5, + "P%01X%01X%01X", + RootBridge->Uid, + RootBridge->RootPort[RPIndex]->Device, + RootBridge->RootPort[RPIndex]->Function + ); + + Status = AmlCodeGenNameString ( + "RSTR", + RpName, + DeviceNode, + NULL + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + Status = AmlCodeGenNameInteger ( + "BRB_", + RootBridge->Object->BaseBusNumber, + DeviceNode, + NULL + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + /// Create a _DSM method for the root port + Status = AmlCodeGenMethodRetNameString ( + "_DSM", + NULL, + 4, + TRUE, + 0, + DeviceNode, + &DsmMethod + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + /// fill the AML_METHOD_PARAM structure to call the \\_SB.HDSM method + ZeroMem (MethodParam, sizeof (MethodParam)); + MethodParam[0].Type = AmlMethodParamTypeArg; + MethodParam[0].Data.Arg = 0x0; // Arg0 is the first argument to the method + MethodParam[1].Type = AmlMethodParamTypeArg; + MethodParam[1].Data.Arg = 0x1; // Arg1 is the second argument to the method + MethodParam[2].Type = AmlMethodParamTypeArg; + MethodParam[2].Data.Arg = 0x2; // Arg2 is the third argument to the method + MethodParam[3].Type = AmlMethodParamTypeArg; + MethodParam[3].Data.Arg = 0x3; // Arg3 is the fourth argument to the method + MethodParam[4].Type = AmlMethodParamTypeInteger; + MethodParam[4].Data.Integer = RootBridge->Object->BaseBusNumber; + MethodParam[5].Type = AmlMethodParamTypeInteger; + MethodParam[5].Data.Integer = (RootBridge->RootPort[RPIndex]->Device << 16) + RootBridge->RootPort[RPIndex]->Function; + MethodParam[6].Type = AmlMethodParamTypeString; + MethodParam[6].Data.Buffer = RpName; + /// Call the \\_SB.HDSM method + Status = AmlCodeGenInvokeMethod ( + "\\_SB.HDSM", + 7, + MethodParam, + DsmMethod + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + /// Create a _OST method for the root port + Status = AmlCodeGenMethodRetNameString ( + "_OST", + NULL, + 3, + TRUE, + 0, + DeviceNode, + &OstMethod + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // fill the AML_METHOD_PARAM structure to call the \\_SB._OST method + ZeroMem (MethodParam, sizeof (MethodParam)); + MethodParam[0].Type = AmlMethodParamTypeArg; + MethodParam[0].Data.Arg = 0x0; // Arg0 is the first argument to the method + MethodParam[1].Type = AmlMethodParamTypeArg; + MethodParam[1].Data.Arg = 0x1; // Arg1 is the second argument to the method + MethodParam[2].Type = AmlMethodParamTypeInteger; + MethodParam[2].Data.Integer = RootBridge->Object->BaseBusNumber; + MethodParam[3].Type = AmlMethodParamTypeInteger; + MethodParam[3].Data.Integer = (RootBridge->RootPort[RPIndex]->Device << 16) + RootBridge->RootPort[RPIndex]->Function; + // call the \\_SB._OST method + Status = AmlCodeGenInvokeMethod ( + "\\_SB.HOST", + 4, + MethodParam, + OstMethod + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + } + + // Build Root Port _PRT entry and insert in main ACPI Object list + Status = AmlCodeGenNamePackage ("_PRT", NULL, &PrtNode); + ASSERT_EFI_ERROR (Status); + + for (Index = 0; Index <= 3; Index++) { + Status = AmlAddPrtEntry ( + 0x0000FFFF, + (UINT8)Index, + NULL, + (UINT32)(GlobalInterruptBase + RootBridge->RootPort[RPIndex]->EndpointInterruptArray[Index]), + PrtNode + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + } + } + + // Attach the _PRT entry. + Status = AmlAttachNode (DeviceNode, PrtNode); + if (EFI_ERROR (Status)) { + AmlDeleteTree (PrtNode); + ASSERT_EFI_ERROR (Status); + } + + PrtNode = NULL; + } + + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + } + + return Status; +} + +/** + Insert CXL Root Bridge into the AML table + + @param[in] RootBridgeHead - RootBridge information pointer + @param[in] RootBridgeCount - Number of root bridges + @param[in,out] PciNode - AmlLib table node + + @retval EFI_SUCCESS, various EFI FAILUREs. +**/ +EFI_STATUS +EFIAPI +InternalInsertCxlRootBridge ( + IN AMD_PCI_ROOT_BRIDGE_OBJECT_INSTANCE *RootBridgeHead, + IN UINTN RootBridgeCount, + IN OUT AML_OBJECT_NODE_HANDLE PciNode + ) +{ + AMD_PCI_ADDR PciAddr; + AMD_PCI_ROOT_BRIDGE_OBJECT_INSTANCE *RootBridge; + AML_OBJECT_NODE_HANDLE CrsNode; + AML_OBJECT_NODE_HANDLE DeviceNode; + AML_OBJECT_NODE_HANDLE PackageNode; + CHAR8 NameSeg[5]; + EFI_STATUS Status; + UINT32 EisaId; + UINT8 DevIndex; + UINT8 Index; + AML_METHOD_PARAM MethodParam[7]; + AML_OBJECT_NODE_HANDLE OscMethod; + + DEBUG ((DEBUG_INFO, "%a: Entry\n", __func__)); + ZeroMem ((VOID *)&PciAddr, sizeof (PciAddr)); + + // + // Populate the data structure for the CXL devices in the system to add to + // the ACPI Table + // + DevIndex = 0; + for (Index = 0, RootBridge = RootBridgeHead; Index < RootBridgeCount; Index++, RootBridge++) { + if ((RootBridge->CxlCount == 0) || (RootBridge->CxlPortInfo.IsCxl2 == TRUE)) { + continue; + } + + DevIndex++; + + CopyMem (NameSeg, "CXLx", AML_NAME_SEG_SIZE + 1); + if (DevIndex < 0x10) { + NameSeg[AML_NAME_SEG_SIZE - 1] = AsciiFromHex (DevIndex); + } else { + NameSeg[AML_NAME_SEG_SIZE - 2] = AsciiFromHex (DevIndex); + } + + Status = AmlCodeGenDevice (NameSeg, PciNode, &DeviceNode); // RootBridge + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + Status = AmlCodeGenNameString ("_HID", "ACPI0016", DeviceNode, NULL); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + Status = AmlCodeGenNamePackage ("_CID", DeviceNode, &PackageNode); + ASSERT_EFI_ERROR (Status); + + // Name (_CID, EISAID("PNP0A03")) + Status = AmlGetEisaIdFromString ("PNP0A03", &EisaId); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + Status = AmlAddIntegerToNamedPackage (EisaId, PackageNode); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // Name (_CID, EISAID("PNP0A03")) + Status = AmlGetEisaIdFromString ("PNP0A08", &EisaId); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + Status = AmlAddIntegerToNamedPackage (EisaId, PackageNode); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // Name (_ADR, <address>) + Status = AmlCodeGenNameInteger ( + "_ADR", + (RootBridge->CxlPortInfo.EndPointBDF.Address.Device << 16) + RootBridge->CxlPortInfo.EndPointBDF.Address.Function, + DeviceNode, + NULL + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // Name (_UID, <root bridge number>) + Status = AmlCodeGenNameInteger ("_UID", DevIndex, DeviceNode, NULL); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // Name (_BBN, <base bus number>) + Status = AmlCodeGenNameInteger ( + "_BBN", + RootBridge->CxlPortInfo.EndPointBDF.Address.Bus, + DeviceNode, + NULL + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // Name (_SEG, <segment number>) + Status = AmlCodeGenNameInteger ( + "_SEG", + RootBridge->Object->BaseBusNumber / MAX_PCI_BUS_NUMBER_PER_SEGMENT, + DeviceNode, + NULL + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // Name (_PXM, <RootBridge->SocketId>) + PciAddr.Address.Bus = (UINT32)RootBridge->Object->BaseBusNumber; + PciAddr.Address.Segment = (UINT32)RootBridge->Object->Segment; + + Status = AmlCodeGenNameInteger ( + "_PXM", + RootBridge->PxmDomain, + DeviceNode, + NULL + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // Name (_CRS, <CRS Resource Template>) + Status = AmlCodeGenNameResourceTemplate ("_CRS", DeviceNode, &CrsNode); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + Status = InternalInsertRootBridgeResources (RootBridge, CrsNode); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + /// Create AML code for below method + /// Method (_OSC, 4, NotSerialized, 4) // _OSC: Operating System Capabilities + /// { + /// \_SB.OSCI (Arg0, Arg1, Arg2, Arg3) + /// } + Status = AmlCodeGenMethodRetNameString ( + "_OSC", + NULL, + 4, + TRUE, + 0, + DeviceNode, + &OscMethod + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // fill the AML_METHOD_PARAM structure to call the \\_SB.OSCI method + ZeroMem (MethodParam, sizeof (MethodParam)); + MethodParam[0].Type = AmlMethodParamTypeArg; + MethodParam[0].Data.Arg = 0x0; // Arg0 is the first argument to the method + MethodParam[1].Type = AmlMethodParamTypeArg; + MethodParam[1].Data.Arg = 0x1; // Arg1 is the second argument to the method + MethodParam[2].Type = AmlMethodParamTypeArg; + MethodParam[2].Data.Arg = 0x2; // Arg2 is the third argument to the method + MethodParam[3].Type = AmlMethodParamTypeArg; + MethodParam[3].Data.Arg = 0x3; // Arg3 is the fourth argument to the method + // call the \\_SB.OSCI method + Status = AmlCodeGenInvokeMethod ( + "\\_SB.OSCI", + 4, + MethodParam, + OscMethod + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + } + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "%a: Failed with Status: %r, Not Critical return SUCCESS\n", __func__, Status)); + Status = EFI_SUCCESS; + } + + return Status; +} + +/** + Insert Pcie base size into the AML table + + @param[in,out] CrsNode - AmlLib table node + + @retval EFI_SUCCESS, various EFI FAILUREs. +**/ +EFI_STATUS +EFIAPI +InternalInsertPciExpressBaseSize ( + IN OUT AML_OBJECT_NODE_HANDLE CrsNode + ) +{ + EFI_STATUS Status; + UINT64 RangeLen; + UINT64 RangeMax; + UINT64 RangeMin; + + RangeMin = PcdGet64 (PcdPciExpressBaseAddress); + RangeLen = PcdGet64 (PcdPciExpressBaseSize); + RangeMax = RangeMin + RangeLen - 1; + + Status = AmlCodeGenRdQWordMemory ( + FALSE, + TRUE, + TRUE, + TRUE, + FALSE, // non cacheable + TRUE, + 0x0, + RangeMin, + RangeMax, + 0x0, + RangeLen, + 0, + NULL, + 0, + TRUE, + CrsNode, + NULL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + return EFI_SUCCESS; +} + +/** + Install PCI devices scoped under \_SB into DSDT + + Determine all the PCI Root Bridges and PCI root ports and install resources + including needed _HID, _CID, _UID, _ADR, _CRS and _PRT Nodes. + + @param[in] ImageHandle - Standard UEFI entry point Image Handle + @param[in] SystemTable - Standard UEFI entry point System Table + + @retval EFI_SUCCESS, various EFI FAILUREs. +**/ +EFI_STATUS +EFIAPI +InstallPciAcpi ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + AMD_PCI_ADDR PciAddr; + AMD_PCI_ROOT_BRIDGE_OBJECT_INSTANCE *RootBridge; + AMD_PCI_ROOT_BRIDGE_OBJECT_INSTANCE *RootBridgeHead; + AML_OBJECT_NODE_HANDLE AmdmNode; + AML_OBJECT_NODE_HANDLE CrsNode; + AML_OBJECT_NODE_HANDLE PackageNode; + AML_OBJECT_NODE_HANDLE PciNode; + AML_OBJECT_NODE_HANDLE ScopeNode; + AML_OBJECT_NODE_HANDLE CxldNode; + AML_OBJECT_NODE_HANDLE DsmMethod; + AML_ROOT_NODE_HANDLE RootNode; + CHAR8 AslName[AML_NAME_SEG_SIZE + 1]; + EFI_ACPI_DESCRIPTION_HEADER *Table; + EFI_ACPI_SDT_HEADER *SdtTable; + EFI_STATUS Status; + EFI_STATUS Status1; + UINT32 EisaId; + UINTN GlobalInterruptBase; + UINTN RbIndex; + UINTN RootBridgeCount; + AML_METHOD_PARAM MethodParam[7]; + AML_OBJECT_NODE_HANDLE OscMethod; + + DEBUG ((DEBUG_INFO, "%a: Entry\n", __func__)); + + Status = AmlCodeGenDefinitionBlock ( + "SSDT", + "AMD ", + "AmdTable", + 0x00, + &RootNode + ); + ASSERT_EFI_ERROR (Status); + + ZeroMem ((VOID *)&PciAddr, sizeof (PciAddr)); + mDriverHandle = ImageHandle; + GlobalInterruptBase = 0; + + Status = InternalCollectSortedRootBridges (&RootBridgeHead, &RootBridgeCount); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + Status = AmlCodeGenScope ("\\_SB_", RootNode, &ScopeNode); // START: Scope (\_SB) + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // Create Root Bridge PCXX devices + for (RbIndex = 0, RootBridge = RootBridgeHead; RbIndex < RootBridgeCount; RbIndex++, RootBridge++) { + GlobalInterruptBase = RootBridge->GlobalInterruptStart; + // Make sure there is always PCI0 since this is a defacto standard. And + // therefore PCI0-PCIF and then PC10-PCFF + CopyMem (AslName, "PCIx", AML_NAME_SEG_SIZE + 1); + AslName[AML_NAME_SEG_SIZE - 1] = AsciiFromHex (RootBridge->Uid & 0xF); + if (RootBridge->Uid > 0xF) { + AslName[AML_NAME_SEG_SIZE - 2] = AsciiFromHex ((RootBridge->Uid >> 4) & 0xF); + } + + Status = AmlCodeGenDevice (AslName, ScopeNode, &PciNode); // RootBridge + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + if ((RootBridge->CxlCount > 0) && (RootBridge->CxlPortInfo.IsCxl2 == TRUE)) { + Status = AmlCodeGenNameString ("_HID", "ACPI0016", PciNode, NULL); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + Status = AmlCodeGenNamePackage ("_CID", PciNode, &PackageNode); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + } + + // Name (_CID, EISAID("PNP0A03")) + Status = AmlGetEisaIdFromString ("PNP0A03", &EisaId); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + Status = AmlAddIntegerToNamedPackage (EisaId, PackageNode); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // Name (_CID, EISAID("PNP0A03")) + Status = AmlGetEisaIdFromString ("PNP0A08", &EisaId); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + Status = AmlAddIntegerToNamedPackage (EisaId, PackageNode); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + } else { + // Name (_HID, EISAID("PNP0A08")) + Status = AmlGetEisaIdFromString ("PNP0A08", &EisaId); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + Status = AmlCodeGenNameInteger ("_HID", EisaId, PciNode, NULL); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // Name (_CID, EISAID("PNP0A03")) + Status = AmlGetEisaIdFromString ("PNP0A03", &EisaId); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + Status = AmlCodeGenNameInteger ("_CID", EisaId, PciNode, NULL); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + } + + // Name (_UID, <root bridge number>) + Status = AmlCodeGenNameInteger ("_UID", RootBridge->Uid, PciNode, NULL); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // Name (_BBN, <base bus number>) + Status = AmlCodeGenNameInteger ( + "_BBN", + RootBridge->Object->BaseBusNumber, + PciNode, + NULL + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // Name (_SEG, <segment number>) + Status = AmlCodeGenNameInteger ( + "_SEG", + RootBridge->Object->Segment, + PciNode, + NULL + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // Name (_PXM, <RootBridge->SocketId>) + PciAddr.Address.Bus = (UINT32)RootBridge->Object->BaseBusNumber; + PciAddr.Address.Segment = (UINT32)RootBridge->Object->Segment; + + Status = AmlCodeGenNameInteger ( + "_PXM", + RootBridge->PxmDomain, + PciNode, + NULL + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // Name (_CRS, <CRS Resource Template>) + Status = AmlCodeGenNameResourceTemplate ("_CRS", PciNode, &CrsNode); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + Status = InternalInsertRootBridgeResources (RootBridge, CrsNode); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // Name (_PRT, <Interrupt Packages>) + Status = InternalInsertRootBridgeInterrupts (RootBridge, &GlobalInterruptBase, PciNode); + ASSERT_EFI_ERROR (Status); + + // Create Root Port PXXX devices + // Name (_ADR, <pci address>) + // Name (_PRT, <Interrupt Packages>) + // Needs to be offset by previous IOAPICs interrupt count + InternalInsertRootPorts (RootBridge, RootBridge->GlobalInterruptStart, PciNode); + + /// AML code to generate _OSC method + /// Method (_OSC, 4, NotSerialized, 4) // _OSC: Operating System Capabilities + /// { + /// \_SB.OSCI (Arg0, Arg1, Arg2, Arg3) + /// } + Status = AmlCodeGenMethodRetNameString ( + "_OSC", + NULL, + 4, + TRUE, + 0, + PciNode, + &OscMethod + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // fill the AML_METHOD_PARAM structure to call the \\_SB.OSCI method + ZeroMem (MethodParam, sizeof (MethodParam)); + MethodParam[0].Type = AmlMethodParamTypeArg; + MethodParam[0].Data.Arg = 0x0; // Arg0 is the first argument to the method + MethodParam[1].Type = AmlMethodParamTypeArg; + MethodParam[1].Data.Arg = 0x1; // Arg1 is the second argument to the method + MethodParam[2].Type = AmlMethodParamTypeArg; + MethodParam[2].Data.Arg = 0x2; // Arg2 is the third argument to the method + MethodParam[3].Type = AmlMethodParamTypeArg; + MethodParam[3].Data.Arg = 0x3; // Arg3 is the fourth argument to the method + // call the \\_SB.OSCI method + Status = AmlCodeGenInvokeMethod ( + "\\_SB.OSCI", + 4, + MethodParam, + OscMethod + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + } + + Status = GetExistingAcpiTable ( + CXL_EARLY_DISCOVERY_TABLE_SIGNATURE, + 0, + &SdtTable + ); + if (!EFI_ERROR (Status)) { + // CXL Root Device Specific Methods (_DSM) + Status = AmlCodeGenDevice ("CXLD", ScopeNode, &CxldNode); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // _DSM Functions that are associated with the CXL Root Device (HID="ACPI0017") + Status = AmlCodeGenNameString ("_HID", "ACPI0017", CxldNode, NULL); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // Create a _DSM method + Status = AmlCodeGenMethodRetNameString ( + "_DSM", + NULL, + 4, + TRUE, + 0, + CxldNode, + &DsmMethod + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // fill the AML_METHOD_PARAM structure to call the \\_SB.HDSM method + ZeroMem (MethodParam, sizeof (MethodParam)); + MethodParam[0].Type = AmlMethodParamTypeArg; + MethodParam[0].Data.Arg = 0x0; // Arg0 is the first argument to the method + MethodParam[1].Type = AmlMethodParamTypeArg; + MethodParam[1].Data.Arg = 0x1; // Arg1 is the second argument to the method + MethodParam[2].Type = AmlMethodParamTypeArg; + MethodParam[2].Data.Arg = 0x2; // Arg2 is the third argument to the method + MethodParam[3].Type = AmlMethodParamTypeArg; + MethodParam[3].Data.Arg = 0x3; // Arg3 is the fourth argument to the method + // + // Call the \\_SB.HDSM method + // The CXL DSM will look for UUID: f365f9a6-a7de-4071-a66a-b40c0b4f8e52 + // + Status = AmlCodeGenInvokeMethod ( + "\\_SB.HDSM", + 4, + MethodParam, + DsmMethod + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + } + + // + // CXL device are added as Root Bridges but are not part of + // the AMD PCI Resource Protocol + // + InternalInsertCxlRootBridge (RootBridgeHead, RootBridgeCount, ScopeNode); + + // Add Pcie Base Size + Status = AmlCodeGenDevice ("AMDM", ScopeNode, &AmdmNode); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // Name (_HID, EISAID("PNP0C02")) + Status = AmlGetEisaIdFromString ("PNP0C02", &EisaId); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + Status = AmlCodeGenNameInteger ("_HID", EisaId, AmdmNode, NULL); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // Name (_UID, <root bridge number>) + Status = AmlCodeGenNameInteger ("_UID", 0, AmdmNode, NULL); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + Status = AmlCodeGenNameResourceTemplate ("_CRS", AmdmNode, &CrsNode); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + Status = InternalInsertPciExpressBaseSize (CrsNode); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + Table = NULL; + // Serialize the tree. + Status = AmlSerializeDefinitionBlock ( + RootNode, + &Table + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: SSDT-PCI: Failed to Serialize SSDT Table Data." + " Status = %r\n", + Status + )); + return (Status); + } + + // Cleanup + Status1 = AmlDeleteTree (RootNode); + if (EFI_ERROR (Status1)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: SSDT-PCI: Failed to cleanup AML tree." + " Status = %r\n", + Status1 + )); + // If Status was success but we failed to delete the AML Tree + // return Status1 else return the original error code, i.e. Status. + if (!EFI_ERROR (Status)) { + return Status1; + } + } + + FreePool (RootBridgeHead); + + Status = AppendExistingAcpiTable ( + EFI_ACPI_6_5_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE, + AMD_DSDT_OEMID, + Table + ); + + return Status; +} diff --git a/Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/Spmi.c b/Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/Spmi.c new file mode 100644 index 0000000000..3520f29631 --- /dev/null +++ b/Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/Spmi.c @@ -0,0 +1,111 @@ +/** @file + + FV block I/O protocol driver for SPI flash libary. + + Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved. + + SPDX-License-Identifier BSD-2-Clause-Patent +**/ +#include <IndustryStandard/ServiceProcessorManagementInterfaceTable.h> +#include <IndustryStandard/Acpi65.h> +#include "AcpiCommon.h" + +EFI_ACPI_SERVICE_PROCESSOR_MANAGEMENT_INTERFACE_TABLE gSpmi = { + { + EFI_ACPI_6_5_SERVER_PLATFORM_MANAGEMENT_INTERFACE_TABLE_SIGNATURE, + sizeof (EFI_ACPI_SERVICE_PROCESSOR_MANAGEMENT_INTERFACE_TABLE), + 5, + // + // Checksum will be updated at runtime + // + 0x00, + // + // It is expected that these values will be programmed at runtime + // + { 'A', 'M', 'D', 'I', 'N', 'C' }, + SIGNATURE_64 ('S', 'P', 'M', 'I', 'T', 'a', 'b', 'l'), // updated during installation + 0x00, // Spmi revision, + SIGNATURE_32 ('A', 'M', 'D', ' '), + 0x00 // OEM Revision + }, + 0x00, // Interface type + 0x01, // Reserved + 0x0200, // IPMI specification revision + 0x00, // InterruptType + 0x00, // Gpe + 0x00, // Reserved2 + 0x00, // PciDeviceFlag or _UID + 0x00, // GlobalSystemInterrupt + { // BaseAddress + EFI_ACPI_6_5_SYSTEM_IO, + 0x08, // BASE_ADDRESS_BIT_WIDTH, + 0x00, // BASE_ADDRESS_BIT_OFFSET, + 0x00, // RESERVED_BYTE, + 0x0CA2 // BASE_ADDRESS_ADDRESS, + }, + { + { 0x00000000 } + }, + 0x00 +}; + +/** + Installs the ACPI SPMI Table to the System Table. +**/ +VOID +EFIAPI +InstallAcpiSpmiTable ( + VOID + ) +{ + UINT64 AcpiTableOemId; + UINTN TurnKey; + EFI_STATUS Status; + EFI_ACPI_TABLE_PROTOCOL *AcpiTablProtocol; + + if (!PcdGet8 (PcdIpmiInterfaceType)) { + return; + } + + Status = gBS->LocateProtocol ( + &gEfiAcpiTableProtocolGuid, + NULL, + (VOID **)&AcpiTablProtocol + ); + if (EFI_ERROR (Status)) { + // return if ACPI protocol not found + return; + } + + DEBUG ((DEBUG_ERROR, "Installing ACPI SPMI Table.\n")); + // OEM info + CopyMem ( + (VOID *)&gSpmi.Header.OemId, + PcdGetPtr (PcdAcpiDefaultOemId), + sizeof (gSpmi.Header.OemId) + ); + + AcpiTableOemId = PcdGet64 (PcdAcpiDefaultOemTableId); + CopyMem ( + (VOID *)&gSpmi.Header.OemTableId, + (VOID *)&AcpiTableOemId, + sizeof (gSpmi.Header.OemTableId) + ); + + gSpmi.Header.OemRevision = 0; + gSpmi.Header.CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId); + gSpmi.Header.CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision); + + gSpmi.InterfaceType = PcdGet8 (PcdIpmiInterfaceType); + gSpmi.BaseAddress.Address = PcdGet16 (PcdIpmiKcsIoBaseAddress); + // + // Add table + // + Status = AcpiTablProtocol->InstallAcpiTable ( + AcpiTablProtocol, + &gSpmi, + sizeof (EFI_ACPI_SERVICE_PROCESSOR_MANAGEMENT_INTERFACE_TABLE), + &TurnKey + ); + ASSERT_EFI_ERROR (Status); +} -- 2.34.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#118906): https://edk2.groups.io/g/devel/message/118906 Mute This Topic: https://groups.io/mt/106108335/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=-=-=-=-=-=-=-=-=-=-=- ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [edk2-devel] [RESEND 0/7] AmdPlatformPkg: Adds board independent modules 2024-05-15 3:50 [edk2-devel] [RESEND 0/7] AmdPlatformPkg: Adds board independent modules Abdul Lateef Attar via groups.io ` (6 preceding siblings ...) 2024-05-15 3:50 ` [edk2-devel] [RESEND 7/7] AmdPlatformPkg: Adds ACPI common driver Abdul Lateef Attar via groups.io @ 2024-05-15 3:59 ` Chang, Abner via groups.io 7 siblings, 0 replies; 9+ messages in thread From: Chang, Abner via groups.io @ 2024-05-15 3:59 UTC (permalink / raw) To: Attar, AbdulLateef (Abdul Lateef), devel@edk2.groups.io Cc: Attar, AbdulLateef (Abdul Lateef), Grimes, Paul [AMD Official Use Only - AMD Internal Distribution Only] Already reviewed off-line. For this patch set, Reviewed-by: Abner Chang <abner.chang@amd.com> > -----Original Message----- > From: Abdul Lateef Attar <AbdulLateef.Attar@amd.com> > Sent: Wednesday, May 15, 2024 11:50 AM > To: devel@edk2.groups.io > Cc: Attar, AbdulLateef (Abdul Lateef) <AbdulLateef.Attar@amd.com>; Chang, > Abner <Abner.Chang@amd.com>; Grimes, Paul <Paul.Grimes@amd.com> > Subject: [RESEND 0/7] AmdPlatformPkg: Adds board independent modules > > PR: https://github.com/tianocore/edk2-platforms/pull/141 > Adds various libraries and drivers for AMD Platform. > > Cc: Abner Chang <abner.chang@amd.com> > Cc: Paul Grimes <paul.grimes@amd.com> > > Abdul Lateef Attar (7): > AmdPlatformPkg: Adds LogoDxe driver > AmdPlatformPkg: Adds BaseAlwaysFalseDepexLib Library > AmdPlatformPkg: Implements SerialPortLib for simulator > AmdPlatformPkg: Adds PlatformSocLib library class > AmdPlatformPkg: Adds AmdConfigRouting driver > AmdPlatformPkg: Adds SecureBootDefaultKeysInit driver > AmdPlatformPkg: Adds ACPI common driver > > .../AMD/AmdPlatformPkg/AmdPlatformPkg.dec | 30 +- > .../AMD/AmdPlatformPkg/AmdPlatformPkg.dsc | 56 +- > .../Include/Library/AmdPlatformSocLib.h | 134 ++ > .../BaseAlwaysFalseDepexLib.c | 20 + > .../BaseAlwaysFalseDepexLib.inf | 35 + > .../BaseAlwaysFalseDepexLib.uni | 12 + > .../DxePlatformSocLib/DxePlatformSocLibNull.c | 75 + > .../DxePlatformSocLibNull.inf | 26 + > .../DxePlatformSocLibNull.uni | 13 + > .../SimulatorSerialPortLibPort80.c | 208 +++ > .../SimulatorSerialPortLibPort80.inf | 31 + > .../Universal/Acpi/AcpiCommon/AcpiCommon.c | 226 +++ > .../Universal/Acpi/AcpiCommon/AcpiCommon.h | 118 ++ > .../Universal/Acpi/AcpiCommon/AcpiCommon.inf | 74 + > .../Universal/Acpi/AcpiCommon/CpuSsdt.c | 345 ++++ > .../Universal/Acpi/AcpiCommon/PciSsdt.c | 1381 +++++++++++++++++ > .../Universal/Acpi/AcpiCommon/Spmi.c | 111 ++ > .../HiiConfigRouting/AmdConfigRouting.inf | 45 + > .../HiiConfigRouting/AmdConfigRoutingEntry.c | 57 + > .../HiiConfigRouting/AmdHiiConfigRouting.c | 1101 +++++++++++++ > .../HiiConfigRouting/AmdHiiConfigRouting.h | 189 +++ > .../Universal/LogoDxe/LogoDxe/JpegLogo.idf | 10 + > .../Universal/LogoDxe/LogoDxe/JpegLogoDxe.inf | 57 + > .../Universal/LogoDxe/LogoDxe/Logo.bmp | Bin 0 -> 522054 bytes > .../Universal/LogoDxe/LogoDxe/Logo.c | 194 +++ > .../Universal/LogoDxe/LogoDxe/Logo.h | 23 + > .../Universal/LogoDxe/LogoDxe/Logo.idf | 10 + > .../Universal/LogoDxe/LogoDxe/Logo.jpg | Bin 0 -> 75403 bytes > .../Universal/LogoDxe/LogoDxe/LogoDxe.inf | 58 + > .../Universal/LogoDxe/LogoDxe/S3Logo.bmp | Bin 0 -> 964114 bytes > .../Universal/LogoDxe/LogoDxe/S3Logo.idf | 10 + > .../Universal/LogoDxe/LogoDxe/S3LogoDxe.inf | 57 + > .../SecureBootDefaultKeysInit.c | 645 ++++++++ > .../SecureBootDefaultKeysInit.inf | 49 + > 34 files changed, 5396 insertions(+), 4 deletions(-) > create mode 100644 > Platform/AMD/AmdPlatformPkg/Include/Library/AmdPlatformSocLib.h > create mode 100644 > Platform/AMD/AmdPlatformPkg/Library/BaseAlwaysFalseDepexLib/BaseAlwa > ysFalseDepexLib.c > create mode 100644 > Platform/AMD/AmdPlatformPkg/Library/BaseAlwaysFalseDepexLib/BaseAlwa > ysFalseDepexLib.inf > create mode 100644 > Platform/AMD/AmdPlatformPkg/Library/BaseAlwaysFalseDepexLib/BaseAlwa > ysFalseDepexLib.uni > create mode 100644 > Platform/AMD/AmdPlatformPkg/Library/DxePlatformSocLib/DxePlatformSocL > ibNull.c > create mode 100644 > Platform/AMD/AmdPlatformPkg/Library/DxePlatformSocLib/DxePlatformSocL > ibNull.inf > create mode 100644 > Platform/AMD/AmdPlatformPkg/Library/DxePlatformSocLib/DxePlatformSocL > ibNull.uni > create mode 100644 > Platform/AMD/AmdPlatformPkg/Library/SimulatorSerialPortLibPort80/Simula > torSerialPortLibPort80.c > create mode 100644 > Platform/AMD/AmdPlatformPkg/Library/SimulatorSerialPortLibPort80/Simula > torSerialPortLibPort80.inf > create mode 100644 > Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/AcpiCommon. > c > create mode 100644 > Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/AcpiCommon. > h > create mode 100644 > Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/AcpiCommon. > inf > create mode 100644 > Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/CpuSsdt.c > create mode 100644 > Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/PciSsdt.c > create mode 100644 > Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/Spmi.c > create mode 100644 > Platform/AMD/AmdPlatformPkg/Universal/HiiConfigRouting/AmdConfigRou > ting.inf > create mode 100644 > Platform/AMD/AmdPlatformPkg/Universal/HiiConfigRouting/AmdConfigRou > tingEntry.c > create mode 100644 > Platform/AMD/AmdPlatformPkg/Universal/HiiConfigRouting/AmdHiiConfigR > outing.c > create mode 100644 > Platform/AMD/AmdPlatformPkg/Universal/HiiConfigRouting/AmdHiiConfigR > outing.h > create mode 100644 > Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/JpegLogo.idf > create mode 100644 > Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/JpegLogoDxe.i > nf > create mode 100755 > Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/Logo.bmp > create mode 100644 > Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/Logo.c > create mode 100644 > Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/Logo.h > create mode 100644 > Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/Logo.idf > create mode 100644 > Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/Logo.jpg > create mode 100644 > Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/LogoDxe.inf > create mode 100644 > Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/S3Logo.bmp > create mode 100644 > Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/S3Logo.idf > create mode 100644 > Platform/AMD/AmdPlatformPkg/Universal/LogoDxe/LogoDxe/S3LogoDxe.inf > create mode 100644 > Platform/AMD/AmdPlatformPkg/Universal/SecureBoot/SecureBootDefaultKe > ysInit/SecureBootDefaultKeysInit.c > create mode 100644 > Platform/AMD/AmdPlatformPkg/Universal/SecureBoot/SecureBootDefaultKe > ysInit/SecureBootDefaultKeysInit.inf > > -- > 2.34.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#118908): https://edk2.groups.io/g/devel/message/118908 Mute This Topic: https://groups.io/mt/106108329/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=-=-=-=-=-=-=-=-=-=-=- ^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2024-05-15 3:59 UTC | newest] Thread overview: 9+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2024-05-15 3:50 [edk2-devel] [RESEND 0/7] AmdPlatformPkg: Adds board independent modules Abdul Lateef Attar via groups.io 2024-05-15 3:50 ` [edk2-devel] [RESEND 1/7] AmdPlatformPkg: Adds LogoDxe driver Abdul Lateef Attar via groups.io 2024-05-15 3:50 ` [edk2-devel] [RESEND 2/7] AmdPlatformPkg: Adds BaseAlwaysFalseDepexLib Library Abdul Lateef Attar via groups.io 2024-05-15 3:50 ` [edk2-devel] [RESEND 3/7] AmdPlatformPkg: Implements SerialPortLib for simulator Abdul Lateef Attar via groups.io 2024-05-15 3:50 ` [edk2-devel] [RESEND 4/7] AmdPlatformPkg: Adds PlatformSocLib library class Abdul Lateef Attar via groups.io 2024-05-15 3:50 ` [edk2-devel] [RESEND 5/7] AmdPlatformPkg: Adds AmdConfigRouting driver Abdul Lateef Attar via groups.io 2024-05-15 3:50 ` [edk2-devel] [RESEND 6/7] AmdPlatformPkg: Adds SecureBootDefaultKeysInit driver Abdul Lateef Attar via groups.io 2024-05-15 3:50 ` [edk2-devel] [RESEND 7/7] AmdPlatformPkg: Adds ACPI common driver Abdul Lateef Attar via groups.io 2024-05-15 3:59 ` [edk2-devel] [RESEND 0/7] AmdPlatformPkg: Adds board independent modules Chang, Abner via groups.io
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox