From 1e6146eb5e1fe99e7960eb66455f05cba1045f66 Mon Sep 17 00:00:00 2001 From: Jeff Fan Date: Fri, 28 Aug 2015 07:00:31 +0000 Subject: [PATCH 001/525] Create UDK2015 branch from EDKII trunk r18350 Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18351 6f19259b-4bc3-4df7-8a09-765794883524 From 8a4fbdefadaba444a44a8b3ac6f117d3e2d6cf2a Mon Sep 17 00:00:00 2001 From: Hao Wu Date: Fri, 28 Aug 2015 07:50:47 +0000 Subject: [PATCH 002/525] MdePkg: Modify string expression of BMC device path to follow UEFI spec According to UEFI 2.5 spec, the string expression of a BMC device node should be displayed as: BMC(Type,Address). However, current code displays it as: Bmc(Type,Address). (Sync patch r18353 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Hao Wu Reviewed-by: Feng Tian git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18356 6f19259b-4bc3-4df7-8a09-765794883524 --- MdePkg/Library/UefiDevicePathLib/DevicePathFromText.c | 2 +- MdePkg/Library/UefiDevicePathLib/DevicePathToText.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/MdePkg/Library/UefiDevicePathLib/DevicePathFromText.c b/MdePkg/Library/UefiDevicePathLib/DevicePathFromText.c index e5f6a1f0621a..2dccfcf472c2 100644 --- a/MdePkg/Library/UefiDevicePathLib/DevicePathFromText.c +++ b/MdePkg/Library/UefiDevicePathLib/DevicePathFromText.c @@ -3458,7 +3458,7 @@ GLOBAL_REMOVE_IF_UNREFERENCED DEVICE_PATH_FROM_TEXT_TABLE mUefiDevicePathLibDevP {L"MemoryMapped", DevPathFromTextMemoryMapped }, {L"VenHw", DevPathFromTextVenHw }, {L"Ctrl", DevPathFromTextCtrl }, - {L"Bmc", DevPathFromTextBmc }, + {L"BMC", DevPathFromTextBmc }, {L"AcpiPath", DevPathFromTextAcpiPath }, {L"Acpi", DevPathFromTextAcpi }, diff --git a/MdePkg/Library/UefiDevicePathLib/DevicePathToText.c b/MdePkg/Library/UefiDevicePathLib/DevicePathToText.c index 627308c340be..08cc3e87f271 100644 --- a/MdePkg/Library/UefiDevicePathLib/DevicePathToText.c +++ b/MdePkg/Library/UefiDevicePathLib/DevicePathToText.c @@ -333,7 +333,7 @@ DevPathToTextBmc ( Bmc = DevPath; UefiDevicePathLibCatPrint ( Str, - L"Bmc(0x%x,0x%lx)", + L"BMC(0x%x,0x%lx)", Bmc->InterfaceType, ReadUnaligned64 ((UINT64 *) (&Bmc->BaseAddress)) ); From 6896bb7f4e9c2d81c5121ff94e7b931d5764249e Mon Sep 17 00:00:00 2001 From: Hao Wu Date: Fri, 28 Aug 2015 07:51:16 +0000 Subject: [PATCH 003/525] MdePkg: Modify string expression of Wi-Fi device path to follow UEFI spec According to UEFI 2.5 spec, the string expression of a Wi-Fi device node should be displayed as: Wi-Fi(SSID). However, current code displays it as: WiFi(SSID). (Sync patch r18354 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Hao Wu Reviewed-by: Feng Tian git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18357 6f19259b-4bc3-4df7-8a09-765794883524 --- MdePkg/Library/UefiDevicePathLib/DevicePathFromText.c | 2 +- MdePkg/Library/UefiDevicePathLib/DevicePathToText.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/MdePkg/Library/UefiDevicePathLib/DevicePathFromText.c b/MdePkg/Library/UefiDevicePathLib/DevicePathFromText.c index 2dccfcf472c2..9c5436d33763 100644 --- a/MdePkg/Library/UefiDevicePathLib/DevicePathFromText.c +++ b/MdePkg/Library/UefiDevicePathLib/DevicePathFromText.c @@ -3519,7 +3519,7 @@ GLOBAL_REMOVE_IF_UNREFERENCED DEVICE_PATH_FROM_TEXT_TABLE mUefiDevicePathLibDevP {L"Vlan", DevPathFromTextVlan }, {L"Uri", DevPathFromTextUri }, {L"Bluetooth", DevPathFromTextBluetooth }, - {L"WiFi", DevPathFromTextWiFi }, + {L"Wi-Fi", DevPathFromTextWiFi }, {L"MediaPath", DevPathFromTextMediaPath }, {L"HD", DevPathFromTextHD }, {L"CDROM", DevPathFromTextCDROM }, diff --git a/MdePkg/Library/UefiDevicePathLib/DevicePathToText.c b/MdePkg/Library/UefiDevicePathLib/DevicePathToText.c index 08cc3e87f271..0774fd8c17a4 100644 --- a/MdePkg/Library/UefiDevicePathLib/DevicePathToText.c +++ b/MdePkg/Library/UefiDevicePathLib/DevicePathToText.c @@ -1618,7 +1618,7 @@ DevPathToTextWiFi ( WIFI_DEVICE_PATH *WiFi; WiFi = DevPath; - UefiDevicePathLibCatPrint (Str, L"WiFi(%a)", WiFi->SSId); + UefiDevicePathLibCatPrint (Str, L"Wi-Fi(%a)", WiFi->SSId); } /** From 889f1f4cffe3889074d26bc53e2484784c760844 Mon Sep 17 00:00:00 2001 From: Hao Wu Date: Fri, 28 Aug 2015 07:51:45 +0000 Subject: [PATCH 004/525] MdePkg UefiDevicePathLib: Fix possible memory read/write cross boundary The SSID field of a Wi-Fi device path node may not contain a NULL termination. Additonal handle is added to make sure no cross-boundary memory read/write will occur. (Sync patch r18355 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Hao Wu Reviewed-by: Feng Tian git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18358 6f19259b-4bc3-4df7-8a09-765794883524 --- .../UefiDevicePathLib/DevicePathFromText.c | 15 ++++++++++++--- .../Library/UefiDevicePathLib/DevicePathToText.c | 7 ++++++- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/MdePkg/Library/UefiDevicePathLib/DevicePathFromText.c b/MdePkg/Library/UefiDevicePathLib/DevicePathFromText.c index 9c5436d33763..6a9b389ca5c5 100644 --- a/MdePkg/Library/UefiDevicePathLib/DevicePathFromText.c +++ b/MdePkg/Library/UefiDevicePathLib/DevicePathFromText.c @@ -2827,7 +2827,8 @@ DevPathFromTextWiFi ( ) { CHAR16 *SSIdStr; - CHAR8 *AsciiStr; + CHAR8 AsciiStr[33]; + UINTN DataLen; WIFI_DEVICE_PATH *WiFiDp; SSIdStr = GetNextParamStr (&TextDeviceNode); @@ -2837,8 +2838,16 @@ DevPathFromTextWiFi ( (UINT16) sizeof (WIFI_DEVICE_PATH) ); - AsciiStr = (CHAR8 *) WiFiDp->SSId; - StrToAscii (SSIdStr, &AsciiStr); + if (NULL != SSIdStr) { + DataLen = StrLen (SSIdStr); + if (StrLen (SSIdStr) > 32) { + SSIdStr[32] = L'\0'; + DataLen = 32; + } + + UnicodeStrToAsciiStr (SSIdStr, AsciiStr); + CopyMem (WiFiDp->SSId, AsciiStr, DataLen); + } return (EFI_DEVICE_PATH_PROTOCOL *) WiFiDp; } diff --git a/MdePkg/Library/UefiDevicePathLib/DevicePathToText.c b/MdePkg/Library/UefiDevicePathLib/DevicePathToText.c index 0774fd8c17a4..363830bd32ca 100644 --- a/MdePkg/Library/UefiDevicePathLib/DevicePathToText.c +++ b/MdePkg/Library/UefiDevicePathLib/DevicePathToText.c @@ -1616,9 +1616,14 @@ DevPathToTextWiFi ( ) { WIFI_DEVICE_PATH *WiFi; + UINT8 SSId[33]; WiFi = DevPath; - UefiDevicePathLibCatPrint (Str, L"Wi-Fi(%a)", WiFi->SSId); + + SSId[32] = '\0'; + CopyMem (SSId, WiFi->SSId, 32); + + UefiDevicePathLibCatPrint (Str, L"Wi-Fi(%a)", SSId); } /** From 727048b5fc68382dad540f2a8548d29905e38278 Mon Sep 17 00:00:00 2001 From: Jiaxin Wu Date: Fri, 28 Aug 2015 08:37:19 +0000 Subject: [PATCH 005/525] NetworkPkg: Fix IpSec run into infinite loop issue in some case v2: * Update the copyright year and conditional judgment for removing. When edit one SPEntry in SPD database, the corresponding SA entry will be updated to the sas list of the new SPD entry. But before that, all of them should be removed from the original sas list. If not, the list will be broken into infinite loop. (Sync patch r18352 from main trunk.) Cc: Ye Ting Cc: Fu Siyuan Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiaxin Wu Reviewed-by: Ye Ting Reviewed-by: Fu Siyuan git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18361 6f19259b-4bc3-4df7-8a09-765794883524 --- NetworkPkg/IpSecDxe/IpSecConfigImpl.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/NetworkPkg/IpSecDxe/IpSecConfigImpl.c b/NetworkPkg/IpSecDxe/IpSecConfigImpl.c index 6eabfe45dee8..bd49245190bd 100644 --- a/NetworkPkg/IpSecDxe/IpSecConfigImpl.c +++ b/NetworkPkg/IpSecDxe/IpSecConfigImpl.c @@ -1,7 +1,7 @@ /** @file The implementation of IPSEC_CONFIG_PROTOCOL. - Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+ Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License @@ -1199,6 +1199,9 @@ SetSpdEntry ( (EFI_IPSEC_CONFIG_SELECTOR *) &SpdData->SaId[Index], (EFI_IPSEC_CONFIG_SELECTOR *) SadEntry->Id )) { + if (SadEntry->Data->SpdEntry != NULL) { + RemoveEntryList (&SadEntry->BySpd); + } InsertTailList (&SpdEntry->Data->Sas, &SadEntry->BySpd); SadEntry->Data->SpdEntry = SpdEntry; DuplicateSpdSelector ( From f0e92f2f4f04e831bfcecabd8bdce3161f0b988b Mon Sep 17 00:00:00 2001 From: Jeff Fan Date: Sat, 29 Aug 2015 14:43:31 +0000 Subject: [PATCH 006/525] Update BaseTools binary to match main trunk r18339. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18362 6f19259b-4bc3-4df7-8a09-765794883524 --- BaseTools/Bin/externals.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BaseTools/Bin/externals.txt b/BaseTools/Bin/externals.txt index c2c4ab729732..f47774936432 100644 --- a/BaseTools/Bin/externals.txt +++ b/BaseTools/Bin/externals.txt @@ -1 +1 @@ -Win32 https://svn.code.sf.net/p/edk2-toolbinaries/code/trunk/Win32 +Win32 -r92 https://svn.code.sf.net/p/edk2-toolbinaries/code/trunk/Win32 From 24542d59049bdc7684835a4b820e21638433adaa Mon Sep 17 00:00:00 2001 From: Jiaxin Wu Date: Mon, 31 Aug 2015 06:03:10 +0000 Subject: [PATCH 007/525] ShellPkg: Get media status in ifconfig command v2: * Update to use NetLibDetectMedia() directly. This patch is used to get media status in ifconfig command. (Sync patch r18363 from main trunk.) Cc: Ye Ting Cc: Fu Siyuan Cc: Jaben Carsey Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiaxin Wu Reviewed-by: Ye Ting Reviewed-by: Fu Siyuan git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18364 6f19259b-4bc3-4df7-8a09-765794883524 --- .../UefiShellNetwork1CommandsLib/Ifconfig.c | 25 +++++++++++++----- .../UefiShellNetwork1CommandsLib.uni | Bin 20910 -> 21094 bytes 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/ShellPkg/Library/UefiShellNetwork1CommandsLib/Ifconfig.c b/ShellPkg/Library/UefiShellNetwork1CommandsLib/Ifconfig.c index 273f1a85dd72..e16d46a8ec4d 100644 --- a/ShellPkg/Library/UefiShellNetwork1CommandsLib/Ifconfig.c +++ b/ShellPkg/Library/UefiShellNetwork1CommandsLib/Ifconfig.c @@ -596,11 +596,14 @@ IfConfigShowInterfaceInfo ( IN LIST_ENTRY *IfList ) { - LIST_ENTRY *Entry; - LIST_ENTRY *Next; - IFCONFIG_INTERFACE_CB *IfCb; - EFI_IPv4_ADDRESS Gateway; - UINT32 Index; + LIST_ENTRY *Entry; + LIST_ENTRY *Next; + IFCONFIG_INTERFACE_CB *IfCb; + BOOLEAN MediaPresent; + EFI_IPv4_ADDRESS Gateway; + UINT32 Index; + + MediaPresent = TRUE; if (IsListEmpty (IfList)) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INVALID_INTERFACE), gShellNetwork1HiiHandle); @@ -617,7 +620,17 @@ IfConfigShowInterfaceInfo ( // // Print interface name. // - ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_IF_NAME), gShellNetwork1HiiHandle, IfCb->IfInfo->Name); + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_IF_NAME), gShellNetwork1HiiHandle, IfCb->IfInfo->Name); + + // + // Get Media State. + // + NetLibDetectMedia (IfCb->NicHandle, &MediaPresent); + if (!MediaPresent) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_MEDIA_STATE), gShellNetwork1HiiHandle, L"Media disconnected"); + } else { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_MEDIA_STATE), gShellNetwork1HiiHandle, L"Media present"); + } // // Print interface config policy. diff --git a/ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.uni b/ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.uni index 7cc7b7d672246a62ef97a8b002a780003d3da330..43259591820582cc38937ad680739fcff21b96c5 100644 GIT binary patch delta 66 zcmZ3tnDN;X#toCSgnb!Y8C)1V85|kn8G;!?fON>@hnk|30}QmpJs5l$QW;VhG8qyX S6o9fNK)Qq>b+fZpwmJY$n-Ez5 delta 14 WcmaF1gmK+s#toCSHhXEyr~?2p Date: Tue, 1 Sep 2015 00:37:24 +0000 Subject: [PATCH 008/525] MdeModulePkg/NetworkPkg: Locate IpSec on IP packet processing only if it's installed. Modified the logic in Ip4Dxe and Ip6Dxe to not locate EFI_IPSEC2_PROTOCOL on each message transmit/receive. Instead, register a callback in the drivers entry points on the IpSec protocol installation, and process only if the protocol is installed. This speeds up the network stacks when IpSec is not installed since there is a penalty associated with searching the entire handle database on each packet processing. (Sync patch r18365 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Samer El-Haj-Mahmoud Reviewed-by: Fu Siyuan git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18367 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Universal/Network/Ip4Dxe/Ip4Driver.c | 36 ++++++++++++++++++ .../Universal/Network/Ip4Dxe/Ip4Impl.h | 3 ++ .../Universal/Network/Ip4Dxe/Ip4Input.c | 7 ++++ NetworkPkg/Ip6Dxe/Ip6Driver.c | 38 +++++++++++++++++++ NetworkPkg/Ip6Dxe/Ip6Impl.h | 2 + NetworkPkg/Ip6Dxe/Ip6Input.c | 6 +++ 6 files changed, 92 insertions(+) diff --git a/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Driver.c b/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Driver.c index d8ab948457c7..3dc4d88f13b7 100644 --- a/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Driver.c +++ b/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Driver.c @@ -2,6 +2,8 @@ The driver binding and service binding protocol for IP4 driver. Copyright (c) 2005 - 2015, Intel Corporation. All rights reserved.
+(C) Copyright 2015 Hewlett-Packard Development Company, L.P.
+ This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -23,6 +25,30 @@ EFI_DRIVER_BINDING_PROTOCOL gIp4DriverBinding = { NULL }; +BOOLEAN mIpSec2Installed = FALSE; + +/** + Callback function for IpSec2 Protocol install. + + @param[in] Event Event whose notification function is being invoked + @param[in] Context Pointer to the notification function's context + +**/ +VOID +EFIAPI +IpSec2InstalledCallback ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + // + // Close the event so it does not get called again. + // + gBS->CloseEvent (Event); + + mIpSec2Installed = TRUE; +} + /** This is the declaration of an EFI image entry point. This entry point is the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including @@ -45,6 +71,16 @@ Ip4DriverEntryPoint ( IN EFI_SYSTEM_TABLE *SystemTable ) { + VOID *Registration; + + EfiCreateProtocolNotifyEvent ( + &gEfiIpSec2ProtocolGuid, + TPL_CALLBACK, + IpSec2InstalledCallback, + NULL, + &Registration + ); + return EfiLibInstallDriverBindingComponentName2 ( ImageHandle, SystemTable, diff --git a/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Impl.h b/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Impl.h index a1a76bd612b9..e802b9516bcd 100644 --- a/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Impl.h +++ b/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Impl.h @@ -2,6 +2,8 @@ Ip4 internal functions and type defintions. Copyright (c) 2005 - 2015, Intel Corporation. All rights reserved.
+(C) Copyright 2015 Hewlett-Packard Development Company, L.P.
+ This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -396,5 +398,6 @@ Ip4FreeTxToken ( ); extern EFI_IPSEC2_PROTOCOL *mIpSec; +extern BOOLEAN mIpSec2Installed; #endif diff --git a/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Input.c b/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Input.c index 38ad1c39daf4..09b8f2bac235 100644 --- a/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Input.c +++ b/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Input.c @@ -2,6 +2,8 @@ IP4 input process. Copyright (c) 2005 - 2014, Intel Corporation. All rights reserved.
+(C) Copyright 2015 Hewlett-Packard Development Company, L.P.
+ This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -512,6 +514,11 @@ Ip4IpSecProcessPacket ( IP4_HEAD ZeroHead; Status = EFI_SUCCESS; + + if (!mIpSec2Installed) { + goto ON_EXIT; + } + Packet = *Netbuf; RecycleEvent = NULL; IpSecWrap = NULL; diff --git a/NetworkPkg/Ip6Dxe/Ip6Driver.c b/NetworkPkg/Ip6Dxe/Ip6Driver.c index 69587849cc77..4fde47601cdf 100644 --- a/NetworkPkg/Ip6Dxe/Ip6Driver.c +++ b/NetworkPkg/Ip6Dxe/Ip6Driver.c @@ -2,6 +2,7 @@ The driver binding and service binding protocol for IP6 driver. Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.
+ (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License @@ -24,6 +25,33 @@ EFI_DRIVER_BINDING_PROTOCOL gIp6DriverBinding = { NULL }; +BOOLEAN mIpSec2Installed = FALSE; + +/** + Callback function for IpSec2 Protocol install. + + @param[in] Event Event whose notification function is being invoked + @param[in] Context Pointer to the notification function's context + + @retval EFI_SUCCESS Callback successful. +**/ +VOID +EFIAPI +IpSec2InstalledCallback ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + // + // Close the event so it does not get called again. + // + gBS->CloseEvent (Event); + + mIpSec2Installed = TRUE; + + return; +} + /** This is the declaration of an EFI image entry point. This entry point is the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including @@ -46,6 +74,16 @@ Ip6DriverEntryPoint ( IN EFI_SYSTEM_TABLE *SystemTable ) { + VOID *Registration; + + EfiCreateProtocolNotifyEvent ( + &gEfiIpSec2ProtocolGuid, + TPL_CALLBACK, + IpSec2InstalledCallback, + NULL, + &Registration + ); + return EfiLibInstallDriverBindingComponentName2 ( ImageHandle, SystemTable, diff --git a/NetworkPkg/Ip6Dxe/Ip6Impl.h b/NetworkPkg/Ip6Dxe/Ip6Impl.h index 8f114bbb10a5..d30246b2db3e 100644 --- a/NetworkPkg/Ip6Dxe/Ip6Impl.h +++ b/NetworkPkg/Ip6Dxe/Ip6Impl.h @@ -2,6 +2,7 @@ Implementation of EFI_IP6_PROTOCOL protocol interfaces and type definitions. Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.
+ (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License @@ -89,6 +90,7 @@ #define IP6_NO_MAPPING(IpInstance) (!(IpInstance)->Interface->Configured) extern EFI_IPSEC2_PROTOCOL *mIpSec; +extern BOOLEAN mIpSec2Installed; // // IP6_TXTOKEN_WRAP wraps the upper layer's transmit token. diff --git a/NetworkPkg/Ip6Dxe/Ip6Input.c b/NetworkPkg/Ip6Dxe/Ip6Input.c index cf88884e381b..e53e0874b9b5 100644 --- a/NetworkPkg/Ip6Dxe/Ip6Input.c +++ b/NetworkPkg/Ip6Dxe/Ip6Input.c @@ -2,6 +2,7 @@ IP6 internal functions to process the incoming packets. Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.
+ (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License @@ -525,6 +526,11 @@ Ip6IpSecProcessPacket ( EFI_IP6_HEADER ZeroHead; Status = EFI_SUCCESS; + + if (!mIpSec2Installed) { + goto ON_EXIT; + } + Packet = *Netbuf; RecycleEvent = NULL; IpSecWrap = NULL; From 1f90b7bf9346cfb1bd1a1a2c6d355106af53e090 Mon Sep 17 00:00:00 2001 From: Eric Dong Date: Tue, 1 Sep 2015 05:21:48 +0000 Subject: [PATCH 009/525] ShellPkg: Replace use case of deprecated function GetVariable with GetVariable2. (Sync patch r18368 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Eric Dong Reviewed-by: Jaben Carsey git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18371 6f19259b-4bc3-4df7-8a09-765794883524 --- ShellPkg/Application/Shell/ShellProtocol.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ShellPkg/Application/Shell/ShellProtocol.c b/ShellPkg/Application/Shell/ShellProtocol.c index 6a248522b56d..28521ecc154b 100644 --- a/ShellPkg/Application/Shell/ShellProtocol.c +++ b/ShellPkg/Application/Shell/ShellProtocol.c @@ -3221,6 +3221,7 @@ EfiShellGetAlias( UINT32 Attribs; EFI_STATUS Status; CHAR16 *AliasLower; + CHAR16 *AliasVal; // Convert to lowercase to make aliases case-insensitive if (Alias != NULL) { @@ -3229,7 +3230,8 @@ EfiShellGetAlias( ToLower (AliasLower); if (Volatile == NULL) { - return (AddBufferToFreeList(GetVariable(AliasLower, &gShellAliasGuid))); + GetVariable2 (AliasLower, &gShellAliasGuid, (VOID **)&AliasVal, NULL); + return (AddBufferToFreeList(AliasVal)); } RetSize = 0; RetVal = NULL; From 091269232629660ef5b1997d66658c94b58b009d Mon Sep 17 00:00:00 2001 From: Jeff Fan Date: Wed, 2 Sep 2015 03:15:20 +0000 Subject: [PATCH 010/525] UefiCpuPkg/CpuMpPei: Update the old/new BSP state in SwitchBsp() (Sync patch r18372 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan Reviewed-by: Feng Tian git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18380 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/CpuMpPei/PeiMpServices.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/UefiCpuPkg/CpuMpPei/PeiMpServices.c b/UefiCpuPkg/CpuMpPei/PeiMpServices.c index 503778fd9350..625c24a6f40e 100644 --- a/UefiCpuPkg/CpuMpPei/PeiMpServices.c +++ b/UefiCpuPkg/CpuMpPei/PeiMpServices.c @@ -804,6 +804,16 @@ PeiSwitchBSP ( ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE_ADDRESS); ApicBaseMsr.Bits.Bsp = 1; AsmWriteMsr64 (MSR_IA32_APIC_BASE_ADDRESS, ApicBaseMsr.Uint64); + // + // Set old BSP enable state + // + if (!EnableOldBSP) { + PeiCpuMpData->CpuData[PeiCpuMpData->BspNumber].State = CpuStateDisabled; + } + // + // Save new BSP number + // + PeiCpuMpData->BspNumber = (UINT32) ProcessorNumber; return EFI_SUCCESS; } From 5b70667c58a29ac4d7fa526fd8b0c180f35a8202 Mon Sep 17 00:00:00 2001 From: Jeff Fan Date: Wed, 2 Sep 2015 03:15:44 +0000 Subject: [PATCH 011/525] UefiCpuPkg/CpuMpPei: Check Function pointer in PeiStartupAllAPs () (Sync patch r18373 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan Reviewed-by: Feng Tian git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18381 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/CpuMpPei/PeiMpServices.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/UefiCpuPkg/CpuMpPei/PeiMpServices.c b/UefiCpuPkg/CpuMpPei/PeiMpServices.c index 625c24a6f40e..4215f9e51b19 100644 --- a/UefiCpuPkg/CpuMpPei/PeiMpServices.c +++ b/UefiCpuPkg/CpuMpPei/PeiMpServices.c @@ -441,6 +441,10 @@ PeiStartupAllAPs ( return EFI_NOT_FOUND; } + if (Procedure == NULL) { + return EFI_INVALID_PARAMETER; + } + // // Check whether caller processor is BSP // From 81ae98cc176cb6c8be13f7f776663fd99d9ad60a Mon Sep 17 00:00:00 2001 From: Jeff Fan Date: Wed, 2 Sep 2015 03:16:05 +0000 Subject: [PATCH 012/525] UefiCpuPkg/CpuMpPei: Fix CPU Healthy issue in PeiGetProcessorInfo () CPU Healthy state maybe changed by software. We should return Healthy state from Healthy bit instead of from CPU BIST hardware information. (Sync patch r18374 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan Reviewed-by: Feng Tian git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18382 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/CpuMpPei/CpuBist.c | 5 ++++- UefiCpuPkg/CpuMpPei/PeiMpServices.c | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/UefiCpuPkg/CpuMpPei/CpuBist.c b/UefiCpuPkg/CpuMpPei/CpuBist.c index 2bee7a4a665b..56292452a9c7 100644 --- a/UefiCpuPkg/CpuMpPei/CpuBist.c +++ b/UefiCpuPkg/CpuMpPei/CpuBist.c @@ -226,7 +226,10 @@ CollectBistDataFromPpi ( CpuData->Health = CpuInstance[CpuIndex].InfoRecord.IA32HealthFlags; } } - if (CpuData->Health.Uint32 != 0) { + if (CpuData->Health.Uint32 == 0) { + CpuData->CpuHealthy = TRUE; + } else { + CpuData->CpuHealthy = FALSE; // // Report Status Code that self test is failed // diff --git a/UefiCpuPkg/CpuMpPei/PeiMpServices.c b/UefiCpuPkg/CpuMpPei/PeiMpServices.c index 4215f9e51b19..5dd2c153f46a 100644 --- a/UefiCpuPkg/CpuMpPei/PeiMpServices.c +++ b/UefiCpuPkg/CpuMpPei/PeiMpServices.c @@ -334,7 +334,7 @@ PeiGetProcessorInfo ( if (PeiCpuMpData->CpuData[ProcessorNumber].ApicId == GetInitialApicId()) { ProcessorInfoBuffer->StatusFlag |= PROCESSOR_AS_BSP_BIT; } - if (PeiCpuMpData->CpuData[ProcessorNumber].Health.Uint32 == 0) { + if (PeiCpuMpData->CpuData[ProcessorNumber].CpuHealthy) { ProcessorInfoBuffer->StatusFlag |= PROCESSOR_HEALTH_STATUS_BIT; } if (PeiCpuMpData->CpuData[ProcessorNumber].State == CpuStateDisabled) { From 353938e942b2ac12332012f93e353b21900d0ecf Mon Sep 17 00:00:00 2001 From: "Yao, Jiewen" Date: Wed, 2 Sep 2015 08:32:00 +0000 Subject: [PATCH 013/525] Add more strict check for MOR variable, besides MOR lock variable. (Sync patch r18383 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: "Yao, Jiewen" Reviewed-by: "Zhang, Chao B" git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18386 6f19259b-4bc3-4df7-8a09-765794883524 --- .../TcgMorLock.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLock.c b/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLock.c index 7ca707915e25..c6f3edc75631 100644 --- a/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLock.c +++ b/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLock.c @@ -143,20 +143,21 @@ SetVariableCheckHandlerMor ( return EFI_INVALID_PARAMETER; } + // + // Delete not OK + // + if ((DataSize != sizeof(UINT8)) || (Data == NULL) || (Attributes == 0)) { + return EFI_INVALID_PARAMETER; + } + // // check format // if (IsMorLockVariable(VariableName, VendorGuid)) { - // - // Delete not OK - // - if ((DataSize == 0) || (Data == NULL) || (Attributes == 0)) { - return EFI_INVALID_PARAMETER; - } // // set to any other value not OK // - if ((DataSize != sizeof(UINT8)) || ((*(UINT8 *)Data != 1) && (*(UINT8 *)Data != 0))) { + if ((*(UINT8 *)Data != 1) && (*(UINT8 *)Data != 0)) { return EFI_INVALID_PARAMETER; } } From bbe8770845724e629f4d79d3813bbb953d693296 Mon Sep 17 00:00:00 2001 From: Fu Siyuan Date: Wed, 2 Sep 2015 08:32:20 +0000 Subject: [PATCH 014/525] NetworkPkg: remove redundant words in function comment. A function with void return type doesn't need @retval line in its function comment. This patch removes one redundant line from Ip6 driver in r18365. (Sync patch r18384 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Fu Siyuan git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18387 6f19259b-4bc3-4df7-8a09-765794883524 --- NetworkPkg/Ip6Dxe/Ip6Driver.c | 1 - 1 file changed, 1 deletion(-) diff --git a/NetworkPkg/Ip6Dxe/Ip6Driver.c b/NetworkPkg/Ip6Dxe/Ip6Driver.c index 4fde47601cdf..076dc605e6df 100644 --- a/NetworkPkg/Ip6Dxe/Ip6Driver.c +++ b/NetworkPkg/Ip6Dxe/Ip6Driver.c @@ -33,7 +33,6 @@ BOOLEAN mIpSec2Installed = FALSE; @param[in] Event Event whose notification function is being invoked @param[in] Context Pointer to the notification function's context - @retval EFI_SUCCESS Callback successful. **/ VOID EFIAPI From 09bcbf6219e3e22a308781ecf447489246be2a44 Mon Sep 17 00:00:00 2001 From: Qin Long Date: Sat, 5 Sep 2015 02:19:06 +0000 Subject: [PATCH 015/525] CryptoPkg: Replace string wrapper functions with safe string functions EDKII core suggests to retire unsafe string functions. This patch is to replace string wrapper functions with new-added safe string functions for consistency. (Sync patch r18385 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Qin Long Reviewed-by: Eric Dong git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18397 6f19259b-4bc3-4df7-8a09-765794883524 --- CryptoPkg/Include/OpenSslSupport.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/CryptoPkg/Include/OpenSslSupport.h b/CryptoPkg/Include/OpenSslSupport.h index b5a8b58148cc..2c6e23cee3fe 100644 --- a/CryptoPkg/Include/OpenSslSupport.h +++ b/CryptoPkg/Include/OpenSslSupport.h @@ -21,6 +21,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include +#define MAX_STRING_SIZE 0x1000 + // // File operations are not required for building Open SSL, // so FILE is mapped to VOID * to pass build @@ -236,10 +238,10 @@ extern FILE *stdout; #define memmove(dest,source,count) CopyMem(dest,source,(UINTN)(count)) #define strcmp AsciiStrCmp #define strncmp(string1,string2,count) (int)(AsciiStrnCmp(string1,string2,(UINTN)(count))) -#define strcpy(strDest,strSource) AsciiStrCpy(strDest,strSource) -#define strncpy(strDest,strSource,count) AsciiStrnCpy(strDest,strSource,(UINTN)count) -#define strlen(str) (size_t)(AsciiStrLen(str)) -#define strcat(strDest,strSource) AsciiStrCat(strDest,strSource) +#define strcpy(strDest,strSource) AsciiStrCpyS(strDest,MAX_STRING_SIZE,strSource) +#define strncpy(strDest,strSource,count) AsciiStrnCpyS(strDest,MAX_STRING_SIZE,strSource,(UINTN)count) +#define strlen(str) (size_t)(AsciiStrnLenS(str,MAX_STRING_SIZE)) +#define strcat(strDest,strSource) AsciiStrCatS(strDest,MAX_STRING_SIZE,strSource) #define strchr(str,ch) ScanMem8((VOID *)(str),AsciiStrSize(str),(UINT8)ch) #define abort() ASSERT (FALSE) #define assert(expression) From 59f1fa8dec6ab2b48f5f00a5080af1aa85464fda Mon Sep 17 00:00:00 2001 From: Qin Long Date: Sat, 5 Sep 2015 02:19:31 +0000 Subject: [PATCH 016/525] CryptoPkg: Fix one wrong parameter for weak key checking Fix one wrong offset which is passed into DES weak key checking in TdesInit(). (Sync patch r18389 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Qin Long Reviewed-by: Jiaxin Wu git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18398 6f19259b-4bc3-4df7-8a09-765794883524 --- CryptoPkg/Library/BaseCryptLib/Cipher/CryptTdes.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CryptoPkg/Library/BaseCryptLib/Cipher/CryptTdes.c b/CryptoPkg/Library/BaseCryptLib/Cipher/CryptTdes.c index f89094a58117..8025a49cc8bc 100644 --- a/CryptoPkg/Library/BaseCryptLib/Cipher/CryptTdes.c +++ b/CryptoPkg/Library/BaseCryptLib/Cipher/CryptTdes.c @@ -1,7 +1,7 @@ /** @file TDES Wrapper Implementation over OpenSSL. -Copyright (c) 2010 - 2012, Intel Corporation. All rights reserved.
+Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -90,7 +90,7 @@ TdesInit ( return TRUE; } - if (DES_is_weak_key ((const_DES_cblock *) Key + 8) == 1) { + if (DES_is_weak_key ((const_DES_cblock *) (Key + 8)) == 1) { return FALSE; } @@ -101,7 +101,7 @@ TdesInit ( return TRUE; } - if (DES_is_weak_key ((const_DES_cblock *) Key + 16) == 1) { + if (DES_is_weak_key ((const_DES_cblock *) (Key + 16)) == 1) { return FALSE; } From 472adcec6fc2d4c5bf94f140781bd4f9dd18785b Mon Sep 17 00:00:00 2001 From: Jeff Fan Date: Sat, 5 Sep 2015 02:19:52 +0000 Subject: [PATCH 017/525] UefiCpuPkg/MtrrLib: MtrrValidBitsMask and MtrrValidAddressMask wrong Per IA32 SDM, if CPUID.80000008H is not available, software may assume that the processor supports a 36-bit physical address size. However, for such old processors (For example, Quark processor), MtrrValidBitsMask and MtrrValidAddressMask values are reverted and wrong in MtrrLib. MtrrValidBitsMask should be 0xFFFFFFFFFULL and MtrrValidAddressMask should be 0xFFFFFF000ULL. (Sync patch r18396 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan Reviewed-by: Jiewen Yao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18399 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/Library/MtrrLib/MtrrLib.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/UefiCpuPkg/Library/MtrrLib/MtrrLib.c b/UefiCpuPkg/Library/MtrrLib/MtrrLib.c index d9449bcca5d9..a65560542c88 100644 --- a/UefiCpuPkg/Library/MtrrLib/MtrrLib.c +++ b/UefiCpuPkg/Library/MtrrLib/MtrrLib.c @@ -1,7 +1,7 @@ /** @file MTRR setting library - Copyright (c) 2008 - 2014, Intel Corporation. All rights reserved.
+ Copyright (c) 2008 - 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -840,8 +840,8 @@ MtrrLibInitializeMtrrMask ( *MtrrValidBitsMask = LShiftU64 (1, PhysicalAddressBits) - 1; *MtrrValidAddressMask = *MtrrValidBitsMask & 0xfffffffffffff000ULL; } else { - *MtrrValidBitsMask = MTRR_LIB_CACHE_VALID_ADDRESS; - *MtrrValidAddressMask = 0xFFFFFFFF; + *MtrrValidBitsMask = MTRR_LIB_MSR_VALID_MASK; + *MtrrValidAddressMask = MTRR_LIB_CACHE_VALID_ADDRESS; } } From 3751df6c38a201e4ceb8f284737164bbacdb8d1d Mon Sep 17 00:00:00 2001 From: Dandan Bi Date: Sun, 6 Sep 2015 02:17:49 +0000 Subject: [PATCH 018/525] MdeModulePkg:Support orderedList with default value Our tool can support OrderedList which has default value,but doesn't update the source code in HiiDatabase when parse the ifr data.Now update the code and add test case in DriverSample. (Sync patch r18388 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Dandan Bi Reviewed-by: Liming Gao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18401 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Universal/DriverSampleDxe/Vfr.vfr | 1 + .../Universal/HiiDatabaseDxe/ConfigRouting.c | 21 +++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/MdeModulePkg/Universal/DriverSampleDxe/Vfr.vfr b/MdeModulePkg/Universal/DriverSampleDxe/Vfr.vfr index 8da0d4b30bda..bd28797a555f 100644 --- a/MdeModulePkg/Universal/DriverSampleDxe/Vfr.vfr +++ b/MdeModulePkg/Universal/DriverSampleDxe/Vfr.vfr @@ -234,6 +234,7 @@ formset option text = STRING_TOKEN(STR_ONE_OF_TEXT1), value = 3, flags = 0; option text = STRING_TOKEN(STR_ONE_OF_TEXT2), value = 2, flags = 0; option text = STRING_TOKEN(STR_ONE_OF_TEXT3), value = 1, flags = 0; + default = {1,2,3}, endlist; endif; diff --git a/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigRouting.c b/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigRouting.c index 1081e7592116..b618903b6a5b 100644 --- a/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigRouting.c +++ b/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigRouting.c @@ -1599,6 +1599,7 @@ ParseIfrData ( UINT16 VarWidth; UINT16 VarDefaultId; BOOLEAN FirstOneOfOption; + BOOLEAN FirstOrderedList; LIST_ENTRY *LinkData; LIST_ENTRY *LinkDefault; EFI_IFR_VARSTORE_NAME_VALUE *IfrNameValueVarStore; @@ -1610,6 +1611,7 @@ ParseIfrData ( DefaultDataPtr = NULL; FirstOneOfOption = FALSE; VarStoreId = 0; + FirstOrderedList = FALSE; ZeroMem (&DefaultData, sizeof (IFR_DEFAULT_DATA)); // @@ -1856,9 +1858,9 @@ ParseIfrData ( // // offset by question header // width by EFI_IFR_ORDERED_LIST MaxContainers * OneofOption Type - // no default value and default id, how to define its default value? // + FirstOrderedList = TRUE; // // OrderedList question is not in IFR Form. This IFR form is not valid. // @@ -2102,6 +2104,10 @@ ParseIfrData ( IfrOneOfOption = (EFI_IFR_ONE_OF_OPTION *) IfrOpHdr; if (BlockData->OpCode == EFI_IFR_ORDERED_LIST_OP) { + + if (!FirstOrderedList){ + break; + } // // Get ordered list option data type. // @@ -2158,10 +2164,9 @@ ParseIfrData ( // Add Block Data into VarStorageData BlockEntry // InsertBlockData (&VarStorageData->BlockEntry, &BlockData); - // - // No default data for OrderedList. - // - BlockData = NULL; + + FirstOrderedList = FALSE; + break; } @@ -2222,12 +2227,6 @@ ParseIfrData ( break; } - if (BlockData->OpCode == EFI_IFR_ORDERED_LIST_OP) { - // - // OrderedList Opcode is no default value. - // - break; - } // // Get the DefaultId // From 7027b268bf1887f7393487574dba309fda84bb74 Mon Sep 17 00:00:00 2001 From: Zhang Lubo Date: Sun, 6 Sep 2015 02:18:22 +0000 Subject: [PATCH 019/525] NetworkPkg: Fix the HttpCloseConnection fail issue When HTTP server is unavailable,HttpCloseConnection will enter infinite loop to wait for TCP4->close Event return, So we need to decide the Http Instance state whether in the appropriate state before close it. (Sync patch r18400 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Zhang Lubo Reviewed-by: Fu Siyuan Reviewed-by: Ye Ting Reviewed-by: Wu Jiaxin git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18402 6f19259b-4bc3-4df7-8a09-765794883524 --- NetworkPkg/HttpDxe/HttpImpl.c | 1 + NetworkPkg/HttpDxe/HttpProto.c | 25 ++++++++++++++----------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/NetworkPkg/HttpDxe/HttpImpl.c b/NetworkPkg/HttpDxe/HttpImpl.c index 5b3c5d058cb1..dc06b9855c27 100644 --- a/NetworkPkg/HttpDxe/HttpImpl.c +++ b/NetworkPkg/HttpDxe/HttpImpl.c @@ -516,6 +516,7 @@ EfiHttpRequest ( HttpCloseTcp4ConnCloseEvent (HttpInstance); if (NULL != Wrap->TcpWrap.TxToken.CompletionToken.Event) { gBS->CloseEvent (Wrap->TcpWrap.TxToken.CompletionToken.Event); + Wrap->TcpWrap.TxToken.CompletionToken.Event = NULL; } Error1: diff --git a/NetworkPkg/HttpDxe/HttpProto.c b/NetworkPkg/HttpDxe/HttpProto.c index 829758ad5ea4..e8ce9879f309 100644 --- a/NetworkPkg/HttpDxe/HttpProto.c +++ b/NetworkPkg/HttpDxe/HttpProto.c @@ -243,10 +243,12 @@ HttpCloseTcp4ConnCloseEvent ( if (NULL != HttpInstance->ConnToken.CompletionToken.Event) { gBS->CloseEvent (HttpInstance->ConnToken.CompletionToken.Event); + HttpInstance->ConnToken.CompletionToken.Event = NULL; } if (NULL != HttpInstance->CloseToken.CompletionToken.Event) { gBS->CloseEvent(HttpInstance->CloseToken.CompletionToken.Event); + HttpInstance->CloseToken.CompletionToken.Event = NULL; } } @@ -581,21 +583,22 @@ HttpCloseConnection ( { EFI_STATUS Status; - HttpInstance->CloseToken.AbortOnClose = TRUE; - HttpInstance->IsCloseDone = FALSE; - - - Status = HttpInstance->Tcp4->Close (HttpInstance->Tcp4, &HttpInstance->CloseToken); - if (EFI_ERROR (Status)) { - return Status; - } + if (HttpInstance->State == HTTP_STATE_TCP_CONNECTED) { + HttpInstance->CloseToken.AbortOnClose = TRUE; + HttpInstance->IsCloseDone = FALSE; + + Status = HttpInstance->Tcp4->Close (HttpInstance->Tcp4, &HttpInstance->CloseToken); + if (EFI_ERROR (Status)) { + return Status; + } - while (!HttpInstance->IsCloseDone) { - HttpInstance->Tcp4->Poll (HttpInstance->Tcp4); + while (!HttpInstance->IsCloseDone) { + HttpInstance->Tcp4->Poll (HttpInstance->Tcp4); + } } HttpInstance->State = HTTP_STATE_TCP_CLOSED; - return Status; + return EFI_SUCCESS; } /** From 75e4a0767e964a05987da4dce0f75de166636517 Mon Sep 17 00:00:00 2001 From: Qiu Shumin Date: Mon, 7 Sep 2015 01:00:49 +0000 Subject: [PATCH 020/525] SecurityPkg: Use pointer instead of array to make code readable. (Sync patch r18403 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Qiu Shumin Reviewed-by: Yao Jiewen Reviewed-by: Chao Zhang git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18407 6f19259b-4bc3-4df7-8a09-765794883524 --- SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c | 35 +++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c b/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c index 56a8613c59f1..9ad970a47be6 100644 --- a/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c +++ b/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c @@ -1456,6 +1456,7 @@ SetupEventLog ( UINT8 TempBuf[sizeof(TCG_EfiSpecIDEventStruct) + (HASH_COUNT * sizeof(TCG_EfiSpecIdEventAlgorithmSize)) + sizeof(UINT8)]; TCG_PCR_EVENT_HDR FirstPcrEvent; TCG_EfiSpecIdEventAlgorithmSize *DigestSize; + TCG_EfiSpecIdEventAlgorithmSize *TempDigestSize; UINT8 *VendorInfoSize; UINT32 NumberOfAlgorithms; @@ -1501,32 +1502,44 @@ SetupEventLog ( NumberOfAlgorithms = 0; DigestSize = (TCG_EfiSpecIdEventAlgorithmSize *)((UINT8 *)TcgEfiSpecIdEventStruct + sizeof(*TcgEfiSpecIdEventStruct) + sizeof(NumberOfAlgorithms)); if ((mTcgDxeData.BsCap.ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA1) != 0) { - DigestSize[NumberOfAlgorithms].algorithmId = TPM_ALG_SHA1; - DigestSize[NumberOfAlgorithms].digestSize = SHA1_DIGEST_SIZE; + TempDigestSize = DigestSize; + TempDigestSize += NumberOfAlgorithms; + TempDigestSize->algorithmId = TPM_ALG_SHA1; + TempDigestSize->digestSize = SHA1_DIGEST_SIZE; NumberOfAlgorithms++; } if ((mTcgDxeData.BsCap.ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA256) != 0) { - DigestSize[NumberOfAlgorithms].algorithmId = TPM_ALG_SHA256; - DigestSize[NumberOfAlgorithms].digestSize = SHA256_DIGEST_SIZE; + TempDigestSize = DigestSize; + TempDigestSize += NumberOfAlgorithms; + TempDigestSize->algorithmId = TPM_ALG_SHA256; + TempDigestSize->digestSize = SHA256_DIGEST_SIZE; NumberOfAlgorithms++; } if ((mTcgDxeData.BsCap.ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA384) != 0) { - DigestSize[NumberOfAlgorithms].algorithmId = TPM_ALG_SHA384; - DigestSize[NumberOfAlgorithms].digestSize = SHA384_DIGEST_SIZE; + TempDigestSize = DigestSize; + TempDigestSize += NumberOfAlgorithms; + TempDigestSize->algorithmId = TPM_ALG_SHA384; + TempDigestSize->digestSize = SHA384_DIGEST_SIZE; NumberOfAlgorithms++; } if ((mTcgDxeData.BsCap.ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA512) != 0) { - DigestSize[NumberOfAlgorithms].algorithmId = TPM_ALG_SHA512; - DigestSize[NumberOfAlgorithms].digestSize = SHA512_DIGEST_SIZE; + TempDigestSize = DigestSize; + TempDigestSize += NumberOfAlgorithms; + TempDigestSize->algorithmId = TPM_ALG_SHA512; + TempDigestSize->digestSize = SHA512_DIGEST_SIZE; NumberOfAlgorithms++; } if ((mTcgDxeData.BsCap.ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SM3_256) != 0) { - DigestSize[NumberOfAlgorithms].algorithmId = TPM_ALG_SM3_256; - DigestSize[NumberOfAlgorithms].digestSize = SM3_256_DIGEST_SIZE; + TempDigestSize = DigestSize; + TempDigestSize += NumberOfAlgorithms; + TempDigestSize->algorithmId = TPM_ALG_SM3_256; + TempDigestSize->digestSize = SM3_256_DIGEST_SIZE; NumberOfAlgorithms++; } CopyMem (TcgEfiSpecIdEventStruct + 1, &NumberOfAlgorithms, sizeof(NumberOfAlgorithms)); - VendorInfoSize = (UINT8 *)&DigestSize[NumberOfAlgorithms]; + TempDigestSize = DigestSize; + TempDigestSize += NumberOfAlgorithms; + VendorInfoSize = (UINT8 *)TempDigestSize; *VendorInfoSize = 0; // From 79a12b0b18bca465a1fbd2c0023710e2ea99a142 Mon Sep 17 00:00:00 2001 From: "Yao, Jiewen" Date: Mon, 7 Sep 2015 01:01:11 +0000 Subject: [PATCH 021/525] Handle extra module patchable PCD variable in Linux map. Add comment for python function, too. (Sync patch r18406 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: "Yao, Jiewen" Reviewed-by: "Mudusuru, Giri P" git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18408 6f19259b-4bc3-4df7-8a09-765794883524 --- IntelFspPkg/Tools/PatchFv.py | 346 +++++++++++++++++++++++++++++++++-- 1 file changed, 334 insertions(+), 12 deletions(-) diff --git a/IntelFspPkg/Tools/PatchFv.py b/IntelFspPkg/Tools/PatchFv.py index 4421a83bd802..b6dab5591b83 100644 --- a/IntelFspPkg/Tools/PatchFv.py +++ b/IntelFspPkg/Tools/PatchFv.py @@ -15,6 +15,15 @@ import re import sys +# +# Read data from file +# +# param [in] binfile Binary file +# param [in] offset Offset +# param [in] len Length +# +# retval value Value +# def readDataFromFile (binfile, offset, len=1): fd = open(binfile, "r+b") fsize = os.path.getsize(binfile) @@ -31,11 +40,18 @@ def readDataFromFile (binfile, offset, len=1): fd.close() return value +# +# Check FSP header is valid or not +# +# param [in] binfile Binary file +# +# retval boolean True: valid; False: invalid +# def IsFspHeaderValid (binfile): fd = open (binfile, "rb") - bindat = fd.read(0x200) + bindat = fd.read(0x200) # only read first 0x200 bytes fd.close() - HeaderList = ['FSPH' , 'FSPP' , 'FSPE'] + HeaderList = ['FSPH' , 'FSPP' , 'FSPE'] # Check 'FSPH', 'FSPP', and 'FSPE' in the FSP header OffsetList = [] for each in HeaderList: if each in bindat: @@ -43,13 +59,26 @@ def IsFspHeaderValid (binfile): else: idx = 0 OffsetList.append(idx) - if not OffsetList[0] or not OffsetList[1]: + if not OffsetList[0] or not OffsetList[1]: # If 'FSPH' or 'FSPP' is missing, it will return false return False Revision = ord(bindat[OffsetList[0] + 0x0B]) + # + # if revision is bigger than 1, it means it is FSP v1.1 or greater revision, which must contain 'FSPE'. + # if Revision > 1 and not OffsetList[2]: - return False + return False # If FSP v1.1 or greater without 'FSPE', then return false return True +# +# Patch data in file +# +# param [in] binfile Binary file +# param [in] offset Offset +# param [in] value Patch value +# param [in] len Length +# +# retval len Length +# def patchDataInFile (binfile, offset, value, len=1): fd = open(binfile, "r+b") fsize = os.path.getsize(binfile) @@ -83,49 +112,98 @@ def __init__(self): self.parenthesisOpenSet = '([{<' self.parenthesisCloseSet = ')]}>' + # + # Get FD file + # + # retval self.fdFile Retrieve FD file + # def getFdFile (self): return self.fdFile + # + # Get FD size + # + # retval self.fdSize Retrieve the size of FD file + # def getFdSize (self): return self.fdSize + # + # Create dictionaries + # + # param [in] fvDir FV's directory + # param [in] fvNames All FV's names + # + # retval 0 Created dictionaries successfully + # def createDicts (self, fvDir, fvNames): + # + # If the fvDir is not a dirctory, then raise an exception + # if not os.path.isdir(fvDir): raise Exception ("'%s' is not a valid directory!" % FvDir) + # + # If the Guid.xref is not existing in fvDir, then raise an exception + # xrefFile = os.path.join(fvDir, "Guid.xref") if not os.path.exists(xrefFile): raise Exception("Cannot open GUID Xref file '%s'!" % xrefFile) + # + # Add GUID reference to dictionary + # self.dictGuidNameXref = {} self.parseGuidXrefFile(xrefFile) + # + # Split up each FV from fvNames and get the fdBase + # fvList = fvNames.split(":") fdBase = fvList.pop() if len(fvList) == 0: fvList.append(fdBase) + # + # If the FD file is not existing, then raise an exception + # fdFile = os.path.join(fvDir, fdBase.strip() + ".fd") if not os.path.exists(fdFile): raise Exception("Cannot open FD file '%s'!" % fdFile) + # + # Get the size of the FD file + # self.fdFile = fdFile self.fdSize = os.path.getsize(fdFile) + # + # If the INF file, which is the first element of fvList, is not existing, then raise an exception + # infFile = os.path.join(fvDir, fvList[0].strip()) + ".inf" if not os.path.exists(infFile): raise Exception("Cannot open INF file '%s'!" % infFile) + # + # Parse INF file in order to get fdBase and then assign those values to dictVariable + # self.parseInfFile(infFile) - self.dictVariable = {} self.dictVariable["FDSIZE"] = self.fdSize self.dictVariable["FDBASE"] = self.fdBase + # + # Collect information from FV MAP file and FV TXT file then + # put them into dictionaries + # self.dictSymbolAddress = {} self.dictFfsOffset = {} for file in fvList: + # + # If the .Fv.map file is not existing, then raise an exception. + # Otherwise, parse FV MAP file + # fvFile = os.path.join(fvDir, file.strip()) + ".Fv" mapFile = fvFile + ".map" if not os.path.exists(mapFile): @@ -133,12 +211,19 @@ def createDicts (self, fvDir, fvNames): self.parseFvMapFile(mapFile) + # + # If the .Fv.txt file is not existing, then raise an exception. + # Otherwise, parse FV TXT file + # fvTxtFile = fvFile + ".txt" if not os.path.exists(fvTxtFile): raise Exception("Cannot open FV TXT file '%s'!" % fvTxtFile) self.parseFvTxtFile(fvTxtFile) + # + # Search all MAP files in FFS directory if it exists then parse MOD MAP file + # ffsDir = os.path.join(fvDir, "Ffs") if (os.path.isdir(ffsDir)): for item in os.listdir(ffsDir): @@ -151,7 +236,17 @@ def createDicts (self, fvDir, fvNames): return 0 + # + # Get FV offset in FD file + # + # param [in] fvFile FV file + # + # retval offset Got FV offset successfully + # def getFvOffsetInFd(self, fvFile): + # + # Check if the first 0x70 bytes of fvFile can be found in fdFile + # fvHandle = open(fvFile, "r+b") fdHandle = open(self.fdFile, "r+b") offset = fdHandle.read().find(fvHandle.read(0x70)) @@ -161,7 +256,18 @@ def getFvOffsetInFd(self, fvFile): raise Exception("Could not locate FV file %s in FD!" % fvFile) return offset + # + # Parse INF file + # + # param [in] infFile INF file + # + # retval 0 Parsed INF file successfully + # def parseInfFile(self, infFile): + # + # Get FV offset and search EFI_BASE_ADDRESS in the FD file + # then assign the value of EFI_BASE_ADDRESS to fdBase + # fvOffset = self.getFvOffsetInFd(infFile[0:-4] + ".Fv") fdIn = open(infFile, "r") rptLine = fdIn.readline() @@ -177,7 +283,19 @@ def parseInfFile(self, infFile): raise Exception("Could not find EFI_BASE_ADDRESS in INF file!" % fvFile) return 0 + # + # Parse FV TXT file + # + # param [in] fvTxtFile .Fv.txt file + # + # retval 0 Parsed FV TXT file successfully + # def parseFvTxtFile(self, fvTxtFile): + # + # Get information from .Fv.txt in order to create a dictionary + # For example, + # self.dictFfsOffset[912740BE-2284-4734-B971-84B027353F0C] = 0x000D4078 + # fvOffset = self.getFvOffsetInFd(fvTxtFile[0:-4]) fdIn = open(fvTxtFile, "r") rptLine = fdIn.readline() @@ -189,7 +307,23 @@ def parseFvTxtFile(self, fvTxtFile): fdIn.close() return 0 + # + # Parse FV MAP file + # + # param [in] mapFile .Fv.map file + # + # retval 0 Parsed FV MAP file successfully + # def parseFvMapFile(self, mapFile): + # + # Get information from .Fv.map in order to create dictionaries + # For example, + # self.dictModBase[FspSecCore:BASE] = 4294592776 (0xfffa4908) + # self.dictModBase[FspSecCore:ENTRY] = 4294606552 (0xfffa7ed8) + # self.dictModBase[FspSecCore:TEXT] = 4294593080 (0xfffa4a38) + # self.dictModBase[FspSecCore:DATA] = 4294612280 (0xfffa9538) + # self.dictSymbolAddress[FspSecCore:_SecStartup] = 0x00fffa4a38 + # fdIn = open(mapFile, "r") rptLine = fdIn.readline() modName = "" @@ -220,30 +354,65 @@ def parseFvMapFile(self, mapFile): fdIn.close() return 0 + # + # Parse MOD MAP file + # + # param [in] moduleName Module name + # param [in] mapFile .Fv.map file + # + # retval 0 Parsed MOD MAP file successfully + # retval 1 There is no moduleEntryPoint in modSymbols + # def parseModMapFile(self, moduleName, mapFile): + # + # Get information from mapFile by moduleName in order to create a dictionary + # For example, + # self.dictSymbolAddress[FspSecCore:___guard_fids_count] = 0x00fffa4778 + # modSymbols = {} fdIn = open(mapFile, "r") - reportLine = fdIn.readline() + reportLines = fdIn.readlines() + fdIn.close() + + moduleEntryPoint = "__ModuleEntryPoint" + reportLine = reportLines[0] if reportLine.strip().find("Archive member included") != -1: #GCC # 0x0000000000001d55 IoRead8 patchMapFileMatchString = "\s+(0x[0-9a-fA-F]{16})\s+([^\s][^0x][_a-zA-Z0-9\-]+)\s" matchKeyGroupIndex = 2 matchSymbolGroupIndex = 1 - moduleEntryPoint = "_ModuleEntryPoint" + prefix = '_' else: #MSFT #0003:00000190 _gComBase 00007a50 SerialPo patchMapFileMatchString = "^\s[0-9a-fA-F]{4}:[0-9a-fA-F]{8}\s+(\w+)\s+([0-9a-fA-F]{8}\s+)" matchKeyGroupIndex = 1 matchSymbolGroupIndex = 2 - moduleEntryPoint = "__ModuleEntryPoint" - while (reportLine != "" ): + prefix = '' + + for reportLine in reportLines: match = re.match(patchMapFileMatchString, reportLine) if match is not None: - modSymbols[match.group(matchKeyGroupIndex)] = match.group(matchSymbolGroupIndex) - reportLine = fdIn.readline() - fdIn.close() + modSymbols[prefix + match.group(matchKeyGroupIndex)] = match.group(matchSymbolGroupIndex) + + # Handle extra module patchable PCD variable in Linux map since it might have different format + # .data._gPcd_BinaryPatch_PcdVpdBaseAddress + # 0x0000000000003714 0x4 /tmp/ccmytayk.ltrans1.ltrans.o + handleNext = False + if matchSymbolGroupIndex == 1: + for reportLine in reportLines: + if handleNext: + handleNext = False + pcdName = match.group(1) + match = re.match("\s+(0x[0-9a-fA-F]{16})\s+", reportLine) + if match is not None: + modSymbols[prefix + pcdName] = match.group(1) + else: + match = re.match("^\s\.data\.(_gPcd_BinaryPatch[_a-zA-Z0-9\-]+)", reportLine) + if match is not None: + handleNext = True + continue if not moduleEntryPoint in modSymbols: return 1 @@ -263,7 +432,19 @@ def parseModMapFile(self, moduleName, mapFile): self.dictSymbolAddress[fullSym] = "0x00%08x" % (baseOffset+ int(modSymbols[symbol], 16)) return 0 + # + # Parse Guid.xref file + # + # param [in] xrefFile the full directory of Guid.xref file + # + # retval 0 Parsed Guid.xref file successfully + # def parseGuidXrefFile(self, xrefFile): + # + # Get information from Guid.xref in order to create a GuidNameXref dictionary + # The dictGuidNameXref, for example, will be like + # dictGuidNameXref [1BA0062E-C779-4582-8566-336AE8F78F09] = FspSecCore + # fdIn = open(xrefFile, "r") rptLine = fdIn.readline() while (rptLine != "" ): @@ -274,18 +455,35 @@ def parseGuidXrefFile(self, xrefFile): fdIn.close() return 0 + # + # Get current character + # + # retval elf.string[self.index] + # retval '' Exception + # def getCurr(self): try: return self.string[self.index] except Exception: return '' + # + # Check to see if it is last index + # + # retval self.index + # def isLast(self): return self.index == len(self.string) + # + # Move to next index + # def moveNext(self): self.index += 1 + # + # Skip space + # def skipSpace(self): while not self.isLast(): if self.getCurr() in ' \t': @@ -293,6 +491,11 @@ def skipSpace(self): else: return + # + # Parse value + # + # retval value + # def parseValue(self): self.skipSpace() var = '' @@ -325,6 +528,11 @@ def parseValue(self): value = self.getVariable(var) return int(value) + # + # Parse single operation + # + # retval ~self.parseBrace() or self.parseValue() + # def parseSingleOp(self): self.skipSpace() char = self.getCurr() @@ -334,6 +542,11 @@ def parseSingleOp(self): else: return self.parseValue() + # + # Parse symbol of Brace([, {, <) + # + # retval value or self.parseSingleOp() + # def parseBrace(self): self.skipSpace() char = self.getCurr() @@ -355,6 +568,11 @@ def parseBrace(self): else: return self.parseSingleOp() + # + # Parse symbol of Multiplier(*) + # + # retval value or self.parseSingleOp() + # def parseMul(self): values = [self.parseBrace()] while True: @@ -370,6 +588,11 @@ def parseMul(self): value *= each return value + # + # Parse symbol of And(&) and Or(|) + # + # retval value + # def parseAndOr(self): values = [self.parseMul()] op = None @@ -398,6 +621,11 @@ def parseAndOr(self): return value + # + # Parse symbol of Add(+) and Minus(-) + # + # retval sum(values) + # def parseAddMinus(self): values = [self.parseAndOr()] while True: @@ -413,9 +641,19 @@ def parseAddMinus(self): break return sum(values) + # + # Parse expression + # + # retval self.parseAddMinus() + # def parseExpr(self): return self.parseAddMinus() + # + # Get result + # + # retval value + # def getResult(self): value = self.parseExpr() self.skipSpace() @@ -423,6 +661,11 @@ def getResult(self): raise Exception("Unexpected character found '%s'" % self.getCurr()) return value + # + # Get module GUID + # + # retval value + # def getModGuid(self, var): guid = (guid for guid,name in self.dictGuidNameXref.items() if name==var) try: @@ -431,12 +674,22 @@ def getModGuid(self, var): raise Exception("Unknown module name %s !" % var) return value + # + # Get variable + # + # retval value + # def getVariable(self, var): value = self.dictVariable.get(var, None) if value == None: raise Exception("Unrecognized variable '%s'" % var) return value + # + # Get number + # + # retval value + # def getNumber(self, var): var = var.strip() if var.startswith('0x'): # HEX @@ -445,6 +698,13 @@ def getNumber(self, var): value = int(var, 10) return value + # + # Get content + # + # param [in] value + # + # retval value + # def getContent(self, value): if (value >= self.fdBase) and (value < self.fdBase + self.fdSize): value = value - self.fdBase @@ -452,16 +712,37 @@ def getContent(self, value): raise Exception("Invalid file offset 0x%08x !" % value) return readDataFromFile (self.fdFile, value, 4) + # + # Change value to address + # + # param [in] value + # + # retval value + # def toAddress(self, value): if value < self.fdSize: value = value + self.fdBase return value + # + # Change value to offset + # + # param [in] value + # + # retval value + # def toOffset(self, value): if value > self.fdBase: value = value - self.fdBase return value + # + # Get GUID offset + # + # param [in] value + # + # retval value + # def getGuidOff(self, value): # GUID:Offset symbolName = value.split(':') @@ -471,6 +752,13 @@ def getGuidOff(self, value): raise Exception("Unknown GUID %s !" % value) return value + # + # Get symbols + # + # param [in] value + # + # retval ret + # def getSymbols(self, value): if self.dictSymbolAddress.has_key(value): # Module:Function @@ -479,6 +767,14 @@ def getSymbols(self, value): raise Exception("Unknown symbol %s !" % value) return ret + # + # Evaluate symbols + # + # param [in] expression + # param [in] isOffset + # + # retval value & 0xFFFFFFFF + # def evaluate(self, expression, isOffset): self.index = 0 self.synUsed = False @@ -498,6 +794,9 @@ def evaluate(self, expression, isOffset): raise Exception("Invalid offset expression !") return value & 0xFFFFFFFF +# +# Print out the usage +# def usage(): print "Usage: \n\tPatchFv FvBuildDir [FvFileBaseNames:]FdFileBaseNameToPatch \"Offset, Value\"" @@ -507,23 +806,38 @@ def main(): # symTables = Symbols() + # + # If the arguments are less than 4, then return an error. + # if len(sys.argv) < 4: Usage() return 1 + # + # If it fails to create dictionaries, then return an error. + # if symTables.createDicts(sys.argv[1], sys.argv[2]) != 0: print "ERROR: Failed to create symbol dictionary!!" return 2 + # + # Get FD file and size + # fdFile = symTables.getFdFile() fdSize = symTables.getFdSize() try: + # + # Check to see if FSP header is valid + # ret = IsFspHeaderValid(fdFile) if ret == False: raise Exception ("The FSP header is not valid. Stop patching FD.") comment = "" for fvFile in sys.argv[3:]: + # + # Check to see if it has enough arguments + # items = fvFile.split(",") if len (items) < 2: raise Exception("Expect more arguments for '%s'!" % fvFile) @@ -542,8 +856,14 @@ def main(): isOffset = True else : isOffset = False + # + # Parse symbols then append it to params + # params.append (symTables.evaluate(item, isOffset)) + # + # Patch a new value into FD file if it is not a command + # if command == "": # Patch a DWORD if len (params) == 2: @@ -560,7 +880,9 @@ def main(): print "Patched offset 0x%08X:[%08X] with value 0x%08X # %s" % (offset, oldvalue, value, comment) elif command == "COPY": + # # Copy binary block from source to destination + # if len (params) == 3: src = symTables.toOffset(params[0]) dest = symTables.toOffset(params[1]) From bcb9fdb5baeb9d9df6ad391129e95027d0f645cc Mon Sep 17 00:00:00 2001 From: Jiaxin Wu Date: Tue, 8 Sep 2015 06:01:04 +0000 Subject: [PATCH 022/525] NetworkPkg: Fix suspicious dereference of pointer 'FieldCount' This patch is used to fix suspicious dereference of pointer 'FieldCount' before NULL check. (Sync patch r18409 from main trunk.) Cc: Ye Ting Cc: Fu Siyuan Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiaxin Wu Reviewed-by: Fu Siyuan git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18410 6f19259b-4bc3-4df7-8a09-765794883524 --- NetworkPkg/HttpUtilitiesDxe/HttpUtilitiesProtocol.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NetworkPkg/HttpUtilitiesDxe/HttpUtilitiesProtocol.c b/NetworkPkg/HttpUtilitiesDxe/HttpUtilitiesProtocol.c index 8c29f20adfe2..a83c9633fc02 100644 --- a/NetworkPkg/HttpUtilitiesDxe/HttpUtilitiesProtocol.c +++ b/NetworkPkg/HttpUtilitiesDxe/HttpUtilitiesProtocol.c @@ -307,7 +307,6 @@ HttpUtilitiesParse ( Status = EFI_SUCCESS; TempHttpMessage = NULL; - *FieldCount = 0; Token = NULL; NextToken = NULL; FieldName = NULL; @@ -328,6 +327,7 @@ HttpUtilitiesParse ( // // Get header number // + *FieldCount = 0; Token = TempHttpMessage; while (TRUE) { FieldName = NULL; From c9d0fe0817a87313a28b800e001ecf2b5d4bbb5a Mon Sep 17 00:00:00 2001 From: Ruiyu Ni Date: Wed, 9 Sep 2015 07:50:09 +0000 Subject: [PATCH 023/525] MdeModulePkg: Fix a performance data buffer overrun issue The mBmPerfHeader.Count isn't reset to 0 in BmWriteBootToOsPerformanceData() so when the actual performance data entry count exceeds the LimitCount, the performance data collection breaks on condition if (mBmPerfHeader.Count == LimitCount), but 2nd time calling this function will not break on condition if (mBmPerfHeader.Count == LimitCount) because the mBmPerfHeader.Count always bigger than LimitCount, which results buffer overrun. (Sync patch r18417 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ruiyu Ni Reviewed-by: Star Zeng git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18420 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Library/UefiBootManagerLib/BmPerformance.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/MdeModulePkg/Library/UefiBootManagerLib/BmPerformance.c b/MdeModulePkg/Library/UefiBootManagerLib/BmPerformance.c index 7b13ec663c68..e45c0bd23a5b 100644 --- a/MdeModulePkg/Library/UefiBootManagerLib/BmPerformance.c +++ b/MdeModulePkg/Library/UefiBootManagerLib/BmPerformance.c @@ -185,6 +185,11 @@ BmWriteBootToOsPerformanceData ( // PERF_END(NULL, "BDS", NULL, 0); + // + // Reset the entry count + // + mBmPerfHeader.Count = 0; + // // Retrieve time stamp count as early as possible // From 6c6967d4a6073313fe7b53b881eaba6014c7f72b Mon Sep 17 00:00:00 2001 From: Qiu Shumin Date: Thu, 10 Sep 2015 05:24:32 +0000 Subject: [PATCH 024/525] MdePkg: Refine UefiFileHandleLib to avoid write non-ASCII char into ASCII file. (Sync patch r18430 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Qiu Shumin Reviewed-by: Liming Gao Reviewed-by: Jaben Carsey git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18432 6f19259b-4bc3-4df7-8a09-765794883524 --- MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.c b/MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.c index 04a2f189eceb..dfec5fa4d47d 100644 --- a/MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.c +++ b/MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.c @@ -1079,6 +1079,7 @@ FileHandleWriteLine( EFI_STATUS Status; CHAR16 CharBuffer; UINTN Size; + UINTN Index; UINTN CharSize; UINT64 FileSize; UINT64 OriginalFilePosition; @@ -1136,6 +1137,12 @@ FileHandleWriteLine( return EFI_OUT_OF_RESOURCES; } UnicodeStrToAsciiStr (Buffer, AsciiBuffer); + for (Index = 0; Index < Size; Index++) { + if (!((AsciiBuffer[Index] >= 0) && (AsciiBuffer[Index] < 128))){ + FreePool(AsciiBuffer); + return EFI_INVALID_PARAMETER; + } + } Size = AsciiStrSize(AsciiBuffer) - sizeof(CHAR8); Status = FileHandleWrite(Handle, &Size, AsciiBuffer); From c554140290c61d7f9af7e563815dd15e31aa5c52 Mon Sep 17 00:00:00 2001 From: Qiu Shumin Date: Thu, 10 Sep 2015 05:25:06 +0000 Subject: [PATCH 025/525] ShellPkg: Fix Shell fail with redundant space following delay number. When boot from Shell we can use '-delay [num]' as optional data. If blank space exist after '[num]' Shell will fail. This patch add error handling to avoid this failure. (Sync patch r18431 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Qiu Shumin Reviewed-by: Jaben Carsey git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18433 6f19259b-4bc3-4df7-8a09-765794883524 --- ShellPkg/Application/Shell/Shell.h | 11 +++++++++++ ShellPkg/Application/Shell/ShellParametersProtocol.c | 1 + 2 files changed, 12 insertions(+) diff --git a/ShellPkg/Application/Shell/Shell.h b/ShellPkg/Application/Shell/Shell.h index 4d804fc45bb3..b6686256aac3 100644 --- a/ShellPkg/Application/Shell/Shell.h +++ b/ShellPkg/Application/Shell/Shell.h @@ -360,5 +360,16 @@ FindFirstCharacter( IN CONST CHAR16 EscapeCharacter ); +/** + Cleans off leading and trailing spaces and tabs. + + @param[in] String pointer to the string to trim them off. +**/ +EFI_STATUS +EFIAPI +TrimSpaces( + IN CHAR16 **String + ); + #endif //_SHELL_INTERNAL_HEADER_ diff --git a/ShellPkg/Application/Shell/ShellParametersProtocol.c b/ShellPkg/Application/Shell/ShellParametersProtocol.c index 1c1367bdf89c..bc19df7e931e 100644 --- a/ShellPkg/Application/Shell/ShellParametersProtocol.c +++ b/ShellPkg/Application/Shell/ShellParametersProtocol.c @@ -359,6 +359,7 @@ CreatePopulateInstallShellParametersProtocol ( // // Populate Argc and Argv // + TrimSpaces (&FullCommandLine); Status = ParseCommandLineToArgs(FullCommandLine, &(*NewShellParameters)->Argv, &(*NewShellParameters)->Argc); From 130fd7399bcbf13bd386f419fb66dc8f066df212 Mon Sep 17 00:00:00 2001 From: Feng Tian Date: Fri, 11 Sep 2015 00:52:06 +0000 Subject: [PATCH 026/525] MdePkg/UefiScsiLib: comments update to add EFI_INVALID_PARAMETER status EFI_SCSI_IO_PROTOCOL has alignment requirement on any data buffer used in SCSI data transfer. As a wrap of this protocol, UefiScsiLib have same request. Adding EFI_INVALID_PARAMETER return status in function comments to ask the caller to guarantee this alignment. (Sync patch r18434 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Feng Tian Reviewed-by: Star Zeng git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18439 6f19259b-4bc3-4df7-8a09-765794883524 --- MdePkg/Include/Library/UefiScsiLib.h | 379 +++++++++++++--------- MdePkg/Library/UefiScsiLib/UefiScsiLib.c | 385 ++++++++++++++--------- 2 files changed, 469 insertions(+), 295 deletions(-) diff --git a/MdePkg/Include/Library/UefiScsiLib.h b/MdePkg/Include/Library/UefiScsiLib.h index 768a912a22fc..26e4aa4e0f02 100644 --- a/MdePkg/Include/Library/UefiScsiLib.h +++ b/MdePkg/Include/Library/UefiScsiLib.h @@ -5,7 +5,7 @@ for hard drive, CD and DVD devices that are the most common SCSI boot targets used by UEFI platforms. This library class depends on SCSI I/O Protocol defined in UEFI Specification and SCSI-2 industry standard. -Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.
+Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -32,6 +32,9 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. If HostAdapterStatus is NULL, then ASSERT(). If TargetStatus is NULL, then ASSERT(). + If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. @param[in] ScsiIo A pointer to the SCSI I/O Protocol instance for the specific SCSI target. @@ -61,27 +64,28 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. Protocol in the UEFI Specification for details on the possible return values. - @retval EFI_SUCCESS The command was executed successfully. - See HostAdapterStatus, TargetStatus, SenseDataLength, - and SenseData in that order for additional status - information. - @retval EFI_NOT_READY The SCSI Request Packet could not be sent because - there are too many SCSI Command Packets already - queued. The SCSI Request Packet was not sent, so - no additional status information is available. - The caller may retry again later. - @retval EFI_DEVICE_ERROR A device error occurred while attempting to send - SCSI Request Packet. See HostAdapterStatus, - TargetStatus, SenseDataLength, and SenseData in that - order for additional status information. - @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet - is not supported by the SCSI initiator(i.e., SCSI - Host Controller). The SCSI Request Packet was not - sent, so no additional status information is available. - @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request - Packet to execute. See HostAdapterStatus, TargetStatus, - SenseDataLength, and SenseData in that order for - additional status information. + @retval EFI_SUCCESS The command was executed successfully. + See HostAdapterStatus, TargetStatus, SenseDataLength, + and SenseData in that order for additional status + information. + @retval EFI_NOT_READY The SCSI Request Packet could not be sent because + there are too many SCSI Command Packets already + queued. The SCSI Request Packet was not sent, so + no additional status information is available. + The caller may retry again later. + @retval EFI_DEVICE_ERROR A device error occurred while attempting to send + SCSI Request Packet. See HostAdapterStatus, + TargetStatus, SenseDataLength, and SenseData in that + order for additional status information. + @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet + is not supported by the SCSI initiator(i.e., SCSI + Host Controller). The SCSI Request Packet was not + sent, so no additional status information is available. + @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request + Packet to execute. See HostAdapterStatus, TargetStatus, + SenseDataLength, and SenseData in that order for + additional status information. + @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid. **/ EFI_STATUS @@ -108,6 +112,14 @@ ScsiTestUnitReadyCommand ( If TargetStatus is NULL, then ASSERT(). If InquiryDataLength is NULL, then ASSERT(). + If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. + + If InquiryDataLength is non-zero and InquiryDataBuffer is not NULL, InquiryDataBuffer + must meet buffer alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise + EFI_INVALID_PARAMETER gets returned. + @param[in] ScsiIo A pointer to the SCSI I/O Protocol instance for the specific SCSI target. @param[in] Timeout The timeout in 100 ns units to use for the @@ -150,28 +162,29 @@ ScsiTestUnitReadyCommand ( If FALSE, then the standard inquiry data is returned in InquiryDataBuffer. - @retval EFI_SUCCESS The command was executed successfully. See HostAdapterStatus, - TargetStatus, SenseDataLength, and SenseData in that order - for additional status information. - @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire - InquiryDataBuffer could not be transferred. The actual - number of bytes transferred is returned in InquiryDataLength. - @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there - are too many SCSI Command Packets already queued. - The SCSI Request Packet was not sent, so no additional - status information is available. The caller may retry again later. - @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI - Request Packet. See HostAdapterStatus, TargetStatus, - SenseDataLength, and SenseData in that order for additional - status information. - @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not - supported by the SCSI initiator(i.e., SCSI Host Controller). - The SCSI Request Packet was not sent, so no additional - status information is available. - @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request - Packet to execute. See HostAdapterStatus, TargetStatus, - SenseDataLength, and SenseData in that order for - additional status information. + @retval EFI_SUCCESS The command was executed successfully. See HostAdapterStatus, + TargetStatus, SenseDataLength, and SenseData in that order + for additional status information. + @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire + InquiryDataBuffer could not be transferred. The actual + number of bytes transferred is returned in InquiryDataLength. + @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there + are too many SCSI Command Packets already queued. + The SCSI Request Packet was not sent, so no additional + status information is available. The caller may retry again later. + @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI + Request Packet. See HostAdapterStatus, TargetStatus, + SenseDataLength, and SenseData in that order for additional + status information. + @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not + supported by the SCSI initiator(i.e., SCSI Host Controller). + The SCSI Request Packet was not sent, so no additional + status information is available. + @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request + Packet to execute. See HostAdapterStatus, TargetStatus, + SenseDataLength, and SenseData in that order for + additional status information. + @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid. **/ EFI_STATUS @@ -201,6 +214,14 @@ ScsiInquiryCommand ( If TargetStatus is NULL, then ASSERT(). If InquiryDataLength is NULL, then ASSERT(). + If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. + + If InquiryDataLength is non-zero and InquiryDataBuffer is not NULL, InquiryDataBuffer + must meet buffer alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise + EFI_INVALID_PARAMETER gets returned. + @param[in] ScsiIo A pointer to the SCSI I/O Protocol instance for the specific SCSI target. @param[in] Timeout The timeout in 100 ns units to use for the @@ -245,28 +266,29 @@ ScsiInquiryCommand ( @param[in] PageCode The page code of the vital product data. It's ignored if EnableVitalProductData is FALSE. - @retval EFI_SUCCESS The command executed successfully. See HostAdapterStatus, - TargetStatus, SenseDataLength, and SenseData in that order - for additional status information. - @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire - InquiryDataBuffer could not be transferred. The actual - number of bytes transferred is returned in InquiryDataLength. - @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there - are too many SCSI Command Packets already queued. - The SCSI Request Packet was not sent, so no additional - status information is available. The caller may retry again later. - @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI - Request Packet. See HostAdapterStatus, TargetStatus, - SenseDataLength, and SenseData in that order for additional - status information. - @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not - supported by the SCSI initiator(i.e., SCSI Host Controller). - The SCSI Request Packet was not sent, so no additional - status information is available. - @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request - Packet to execute. See HostAdapterStatus, TargetStatus, - SenseDataLength, and SenseData in that order for - additional status information. + @retval EFI_SUCCESS The command executed successfully. See HostAdapterStatus, + TargetStatus, SenseDataLength, and SenseData in that order + for additional status information. + @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire + InquiryDataBuffer could not be transferred. The actual + number of bytes transferred is returned in InquiryDataLength. + @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there + are too many SCSI Command Packets already queued. + The SCSI Request Packet was not sent, so no additional + status information is available. The caller may retry again later. + @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI + Request Packet. See HostAdapterStatus, TargetStatus, + SenseDataLength, and SenseData in that order for additional + status information. + @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not + supported by the SCSI initiator(i.e., SCSI Host Controller). + The SCSI Request Packet was not sent, so no additional + status information is available. + @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request + Packet to execute. See HostAdapterStatus, TargetStatus, + SenseDataLength, and SenseData in that order for + additional status information. + @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid. **/ EFI_STATUS @@ -299,6 +321,13 @@ ScsiInquiryCommandEx ( If TargetStatus is NULL, then ASSERT(). If DataLength is NULL, then ASSERT(). + If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. + + If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. @param[in] ScsiIo A pointer to the SCSI I/O Protocol instance for the specific SCSI target. @@ -340,30 +369,31 @@ ScsiInquiryCommandEx ( @param[in] PageControl Specifies the PC field of the CDB for this SCSI Command. @param[in] PageCode Specifies the Page Control field of the CDB for this SCSI Command. - @retval EFI_SUCCESS The command was executed successfully. - See HostAdapterStatus, TargetStatus, SenseDataLength, - and SenseData in that order for additional status information. - @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the - entire DataBuffer could not be transferred. - The actual number of bytes transferred is returned - in DataLength. - @retval EFI_NOT_READY The SCSI Request Packet could not be sent because - there are too many SCSI Command Packets already queued. - The SCSI Request Packet was not sent, so no additional - status information is available. The caller may retry - again later. - @retval EFI_DEVICE_ERROR A device error occurred while attempting to send - SCSI Request Packet. See HostAdapterStatus, TargetStatus, - SenseDataLength, and SenseData in that order for - additional status information. - @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet - is not supported by the SCSI initiator(i.e., SCSI - Host Controller). The SCSI Request Packet was not - sent, so no additional status information is available. - @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI - Request Packet to execute. See HostAdapterStatus, - TargetStatus, SenseDataLength, and SenseData in that - order for additional status information. + @retval EFI_SUCCESS The command was executed successfully. + See HostAdapterStatus, TargetStatus, SenseDataLength, + and SenseData in that order for additional status information. + @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the + entire DataBuffer could not be transferred. + The actual number of bytes transferred is returned + in DataLength. + @retval EFI_NOT_READY The SCSI Request Packet could not be sent because + there are too many SCSI Command Packets already queued. + The SCSI Request Packet was not sent, so no additional + status information is available. The caller may retry + again later. + @retval EFI_DEVICE_ERROR A device error occurred while attempting to send + SCSI Request Packet. See HostAdapterStatus, TargetStatus, + SenseDataLength, and SenseData in that order for + additional status information. + @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet + is not supported by the SCSI initiator(i.e., SCSI + Host Controller). The SCSI Request Packet was not + sent, so no additional status information is available. + @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI + Request Packet to execute. See HostAdapterStatus, + TargetStatus, SenseDataLength, and SenseData in that + order for additional status information. + @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid. **/ EFI_STATUS @@ -395,6 +425,10 @@ ScsiModeSense10Command ( If HostAdapterStatus is NULL, then ASSERT(). If TargetStatus is NULL, then ASSERT(). + If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. + @param[in] ScsiIo A pointer to SCSI IO protocol. @param[in] Timeout The length of timeout period. @param[in, out] SenseData A pointer to output sense data. @@ -409,6 +443,7 @@ ScsiModeSense10Command ( @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported by the SCSI initiator(i.e., SCSI Host Controller) @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute. + @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid. **/ EFI_STATUS @@ -436,6 +471,14 @@ ScsiRequestSenseCommand ( If TargetStatus is NULL, then ASSERT(). If DataLength is NULL, then ASSERT(). + If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. + + If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. + @param[in] ScsiIo A pointer to SCSI IO protocol. @param[in] Timeout The length of timeout period. @param[in, out] SenseData A pointer to output sense data. @@ -446,16 +489,17 @@ ScsiRequestSenseCommand ( @param[in, out] DataLength The length of data buffer. @param[in] Pmi Partial medium indicator. - @retval EFI_SUCCESS Command is executed successfully. - @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire - DataBuffer could not be transferred. The actual - number of bytes transferred is returned in DataLength. - @retval EFI_NOT_READY The SCSI Request Packet could not be sent because - there are too many SCSI Command Packets already queued. - @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet. - @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet - is not supported by the SCSI initiator(i.e., SCSI Host Controller) - @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute. + @retval EFI_SUCCESS Command is executed successfully. + @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire + DataBuffer could not be transferred. The actual + number of bytes transferred is returned in DataLength. + @retval EFI_NOT_READY The SCSI Request Packet could not be sent because + there are too many SCSI Command Packets already queued. + @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet. + @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet + is not supported by the SCSI initiator(i.e., SCSI Host Controller) + @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute. + @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid. **/ EFI_STATUS @@ -486,6 +530,14 @@ ScsiReadCapacityCommand ( If TargetStatus is NULL, then ASSERT(). If DataLength is NULL, then ASSERT(). + If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. + + If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. + @param[in] ScsiIo A pointer to SCSI IO protocol. @param[in] Timeout The length of timeout period. @param[in, out] SenseData A pointer to output sense data. @@ -496,16 +548,17 @@ ScsiReadCapacityCommand ( @param[in, out] DataLength The length of data buffer. @param[in] Pmi Partial medium indicator. - @retval EFI_SUCCESS Command is executed successfully. - @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire - DataBuffer could not be transferred. The actual - number of bytes transferred is returned in DataLength. - @retval EFI_NOT_READY The SCSI Request Packet could not be sent because - there are too many SCSI Command Packets already queued. - @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet. - @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet - is not supported by the SCSI initiator(i.e., SCSI Host Controller) - @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute. + @retval EFI_SUCCESS Command is executed successfully. + @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire + DataBuffer could not be transferred. The actual + number of bytes transferred is returned in DataLength. + @retval EFI_NOT_READY The SCSI Request Packet could not be sent because + there are too many SCSI Command Packets already queued. + @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet. + @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet + is not supported by the SCSI initiator(i.e., SCSI Host Controller) + @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute. + @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid. **/ EFI_STATUS @@ -537,6 +590,13 @@ ScsiReadCapacity16Command ( If TargetStatus is NULL, then ASSERT(). If DataLength is NULL, then ASSERT(). + If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. + + If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. @param[in] ScsiIo A pointer to SCSI IO protocol. @param[in] Timeout The length of timeout period. @@ -549,15 +609,16 @@ ScsiReadCapacity16Command ( @param[in] StartLba The start address of LBA. @param[in] SectorSize The number of contiguous logical blocks of data that shall be transferred. - @retval EFI_SUCCESS Command is executed successfully. - @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire DataBuffer could - not be transferred. The actual number of bytes transferred is returned in DataLength. - @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are too many - SCSI Command Packets already queued. - @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet. - @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported by - the SCSI initiator(i.e., SCSI Host Controller) - @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute. + @retval EFI_SUCCESS Command is executed successfully. + @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire DataBuffer could + not be transferred. The actual number of bytes transferred is returned in DataLength. + @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are too many + SCSI Command Packets already queued. + @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet. + @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported by + the SCSI initiator(i.e., SCSI Host Controller) + @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute. + @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid. **/ EFI_STATUS @@ -590,6 +651,14 @@ ScsiRead10Command ( If TargetStatus is NULL, then ASSERT(). If DataLength is NULL, then ASSERT(). + If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. + + If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. + @param[in] ScsiIo SCSI IO Protocol to use @param[in] Timeout The length of timeout period. @param[in, out] SenseData A pointer to output sense data. @@ -601,15 +670,16 @@ ScsiRead10Command ( @param[in] StartLba The start address of LBA. @param[in] SectorSize The number of contiguous logical blocks of data that shall be transferred. - @retval EFI_SUCCESS Command is executed successfully. - @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire DataBuffer could - not be transferred. The actual number of bytes transferred is returned in DataLength. - @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are too many - SCSI Command Packets already queued. - @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet. - @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported by - the SCSI initiator(i.e., SCSI Host Controller) - @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute. + @retval EFI_SUCCESS Command is executed successfully. + @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire DataBuffer could + not be transferred. The actual number of bytes transferred is returned in DataLength. + @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are too many + SCSI Command Packets already queued. + @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet. + @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported by + the SCSI initiator(i.e., SCSI Host Controller) + @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute. + @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid. **/ EFI_STATUS @@ -641,6 +711,13 @@ ScsiWrite10Command ( If TargetStatus is NULL, then ASSERT(). If DataLength is NULL, then ASSERT(). + If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. + + If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. @param[in] ScsiIo A pointer to SCSI IO protocol. @param[in] Timeout The length of timeout period. @@ -653,15 +730,16 @@ ScsiWrite10Command ( @param[in] StartLba The start address of LBA. @param[in] SectorSize The number of contiguous logical blocks of data that shall be transferred. - @retval EFI_SUCCESS Command is executed successfully. - @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire DataBuffer could - not be transferred. The actual number of bytes transferred is returned in DataLength. - @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are too many - SCSI Command Packets already queued. - @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet. - @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported by - the SCSI initiator(i.e., SCSI Host Controller) - @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute. + @retval EFI_SUCCESS Command is executed successfully. + @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire DataBuffer could + not be transferred. The actual number of bytes transferred is returned in DataLength. + @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are too many + SCSI Command Packets already queued. + @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet. + @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported by + the SCSI initiator(i.e., SCSI Host Controller) + @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute. + @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid. **/ EFI_STATUS @@ -694,6 +772,14 @@ ScsiRead16Command ( If TargetStatus is NULL, then ASSERT(). If DataLength is NULL, then ASSERT(). + If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. + + If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. + @param[in] ScsiIo SCSI IO Protocol to use @param[in] Timeout The length of timeout period. @param[in, out] SenseData A pointer to output sense data. @@ -705,15 +791,16 @@ ScsiRead16Command ( @param[in] StartLba The start address of LBA. @param[in] SectorSize The number of contiguous logical blocks of data that shall be transferred. - @retval EFI_SUCCESS Command is executed successfully. - @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire DataBuffer could - not be transferred. The actual number of bytes transferred is returned in DataLength. - @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are too many - SCSI Command Packets already queued. - @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet. - @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported by - the SCSI initiator(i.e., SCSI Host Controller) - @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute. + @retval EFI_SUCCESS Command is executed successfully. + @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire DataBuffer could + not be transferred. The actual number of bytes transferred is returned in DataLength. + @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are too many + SCSI Command Packets already queued. + @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet. + @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported by + the SCSI initiator(i.e., SCSI Host Controller) + @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute. + @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid. **/ EFI_STATUS diff --git a/MdePkg/Library/UefiScsiLib/UefiScsiLib.c b/MdePkg/Library/UefiScsiLib/UefiScsiLib.c index 8a073db5f3ab..89f261777bb6 100644 --- a/MdePkg/Library/UefiScsiLib/UefiScsiLib.c +++ b/MdePkg/Library/UefiScsiLib/UefiScsiLib.c @@ -1,7 +1,7 @@ /** @file UEFI SCSI Library implementation - Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.
+ Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -42,6 +42,9 @@ If HostAdapterStatus is NULL, then ASSERT(). If TargetStatus is NULL, then ASSERT(). + If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. @param[in] ScsiIo A pointer to the SCSI I/O Protocol instance for the specific SCSI target. @@ -71,27 +74,28 @@ Protocol in the UEFI Specification for details on the possible return values. - @retval EFI_SUCCESS The command was executed successfully. - See HostAdapterStatus, TargetStatus, SenseDataLength, - and SenseData in that order for additional status - information. - @retval EFI_NOT_READY The SCSI Request Packet could not be sent because - there are too many SCSI Command Packets already - queued. The SCSI Request Packet was not sent, so - no additional status information is available. - The caller may retry again later. - @retval EFI_DEVICE_ERROR A device error occurred while attempting to send - SCSI Request Packet. See HostAdapterStatus, - TargetStatus, SenseDataLength, and SenseData in that - order for additional status information. - @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet - is not supported by the SCSI initiator(i.e., SCSI - Host Controller). The SCSI Request Packet was not - sent, so no additional status information is available. - @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request - Packet to execute. See HostAdapterStatus, TargetStatus, - SenseDataLength, and SenseData in that order for - additional status information. + @retval EFI_SUCCESS The command was executed successfully. + See HostAdapterStatus, TargetStatus, SenseDataLength, + and SenseData in that order for additional status + information. + @retval EFI_NOT_READY The SCSI Request Packet could not be sent because + there are too many SCSI Command Packets already + queued. The SCSI Request Packet was not sent, so + no additional status information is available. + The caller may retry again later. + @retval EFI_DEVICE_ERROR A device error occurred while attempting to send + SCSI Request Packet. See HostAdapterStatus, + TargetStatus, SenseDataLength, and SenseData in that + order for additional status information. + @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet + is not supported by the SCSI initiator(i.e., SCSI + Host Controller). The SCSI Request Packet was not + sent, so no additional status information is available. + @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request + Packet to execute. See HostAdapterStatus, TargetStatus, + SenseDataLength, and SenseData in that order for + additional status information. + @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid. **/ EFI_STATUS @@ -153,6 +157,14 @@ ScsiTestUnitReadyCommand ( If TargetStatus is NULL, then ASSERT(). If InquiryDataLength is NULL, then ASSERT(). + If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. + + If InquiryDataLength is non-zero and InquiryDataBuffer is not NULL, InquiryDataBuffer + must meet buffer alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise + EFI_INVALID_PARAMETER gets returned. + @param[in] ScsiIo A pointer to the SCSI I/O Protocol instance for the specific SCSI target. @param[in] Timeout The timeout in 100 ns units to use for the @@ -197,28 +209,29 @@ ScsiTestUnitReadyCommand ( @param[in] PageCode The page code of the vital product data. It's ignored if EnableVitalProductData is FALSE. - @retval EFI_SUCCESS The command executed successfully. See HostAdapterStatus, - TargetStatus, SenseDataLength, and SenseData in that order - for additional status information. - @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire - InquiryDataBuffer could not be transferred. The actual - number of bytes transferred is returned in InquiryDataLength. - @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there - are too many SCSI Command Packets already queued. - The SCSI Request Packet was not sent, so no additional - status information is available. The caller may retry again later. - @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI - Request Packet. See HostAdapterStatus, TargetStatus, - SenseDataLength, and SenseData in that order for additional - status information. - @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not - supported by the SCSI initiator(i.e., SCSI Host Controller). - The SCSI Request Packet was not sent, so no additional - status information is available. - @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request - Packet to execute. See HostAdapterStatus, TargetStatus, - SenseDataLength, and SenseData in that order for - additional status information. + @retval EFI_SUCCESS The command executed successfully. See HostAdapterStatus, + TargetStatus, SenseDataLength, and SenseData in that order + for additional status information. + @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire + InquiryDataBuffer could not be transferred. The actual + number of bytes transferred is returned in InquiryDataLength. + @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there + are too many SCSI Command Packets already queued. + The SCSI Request Packet was not sent, so no additional + status information is available. The caller may retry again later. + @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI + Request Packet. See HostAdapterStatus, TargetStatus, + SenseDataLength, and SenseData in that order for additional + status information. + @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not + supported by the SCSI initiator(i.e., SCSI Host Controller). + The SCSI Request Packet was not sent, so no additional + status information is available. + @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request + Packet to execute. See HostAdapterStatus, TargetStatus, + SenseDataLength, and SenseData in that order for + additional status information. + @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid. **/ EFI_STATUS @@ -293,6 +306,14 @@ ScsiInquiryCommandEx ( If TargetStatus is NULL, then ASSERT(). If InquiryDataLength is NULL, then ASSERT(). + If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. + + If InquiryDataLength is non-zero and InquiryDataBuffer is not NULL, InquiryDataBuffer + must meet buffer alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise + EFI_INVALID_PARAMETER gets returned. + @param[in] ScsiIo A pointer to the SCSI I/O Protocol instance for the specific SCSI target. @param[in] Timeout The timeout in 100 ns units to use for the @@ -335,28 +356,29 @@ ScsiInquiryCommandEx ( If FALSE, then the standard inquiry data is returned in InquiryDataBuffer. - @retval EFI_SUCCESS The command executed successfully. See HostAdapterStatus, - TargetStatus, SenseDataLength, and SenseData in that order - for additional status information. - @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire - InquiryDataBuffer could not be transferred. The actual - number of bytes transferred is returned in InquiryDataLength. - @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there - are too many SCSI Command Packets already queued. - The SCSI Request Packet was not sent, so no additional - status information is available. The caller may retry again later. - @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI - Request Packet. See HostAdapterStatus, TargetStatus, - SenseDataLength, and SenseData in that order for additional - status information. - @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not - supported by the SCSI initiator(i.e., SCSI Host Controller). - The SCSI Request Packet was not sent, so no additional - status information is available. - @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request - Packet to execute. See HostAdapterStatus, TargetStatus, - SenseDataLength, and SenseData in that order for - additional status information. + @retval EFI_SUCCESS The command was executed successfully. See HostAdapterStatus, + TargetStatus, SenseDataLength, and SenseData in that order + for additional status information. + @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire + InquiryDataBuffer could not be transferred. The actual + number of bytes transferred is returned in InquiryDataLength. + @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there + are too many SCSI Command Packets already queued. + The SCSI Request Packet was not sent, so no additional + status information is available. The caller may retry again later. + @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI + Request Packet. See HostAdapterStatus, TargetStatus, + SenseDataLength, and SenseData in that order for additional + status information. + @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not + supported by the SCSI initiator(i.e., SCSI Host Controller). + The SCSI Request Packet was not sent, so no additional + status information is available. + @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request + Packet to execute. See HostAdapterStatus, TargetStatus, + SenseDataLength, and SenseData in that order for + additional status information. + @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid. **/ EFI_STATUS @@ -401,6 +423,13 @@ ScsiInquiryCommand ( If TargetStatus is NULL, then ASSERT(). If DataLength is NULL, then ASSERT(). + If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. + + If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. @param[in] ScsiIo A pointer to the SCSI I/O Protocol instance for the specific SCSI target. @@ -442,30 +471,31 @@ ScsiInquiryCommand ( @param[in] PageControl Specifies the PC field of the CDB for this SCSI Command. @param[in] PageCode Specifies the Page Control field of the CDB for this SCSI Command. - @retval EFI_SUCCESS The command executed successfully. - See HostAdapterStatus, TargetStatus, SenseDataLength, - and SenseData in that order for additional status information. - @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the - entire DataBuffer could not be transferred. - The actual number of bytes transferred is returned - in DataLength. - @retval EFI_NOT_READY The SCSI Request Packet could not be sent because - there are too many SCSI Command Packets already queued. - The SCSI Request Packet was not sent, so no additional - status information is available. The caller may retry - again later. - @retval EFI_DEVICE_ERROR A device error occurred while attempting to send - SCSI Request Packet. See HostAdapterStatus, TargetStatus, - SenseDataLength, and SenseData in that order for - additional status information. - @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet - is not supported by the SCSI initiator(i.e., SCSI - Host Controller). The SCSI Request Packet was not - sent, so no additional status information is available. - @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI - Request Packet to execute. See HostAdapterStatus, - TargetStatus, SenseDataLength, and SenseData in that - order for additional status information. + @retval EFI_SUCCESS The command was executed successfully. + See HostAdapterStatus, TargetStatus, SenseDataLength, + and SenseData in that order for additional status information. + @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the + entire DataBuffer could not be transferred. + The actual number of bytes transferred is returned + in DataLength. + @retval EFI_NOT_READY The SCSI Request Packet could not be sent because + there are too many SCSI Command Packets already queued. + The SCSI Request Packet was not sent, so no additional + status information is available. The caller may retry + again later. + @retval EFI_DEVICE_ERROR A device error occurred while attempting to send + SCSI Request Packet. See HostAdapterStatus, TargetStatus, + SenseDataLength, and SenseData in that order for + additional status information. + @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet + is not supported by the SCSI initiator(i.e., SCSI + Host Controller). The SCSI Request Packet was not + sent, so no additional status information is available. + @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI + Request Packet to execute. See HostAdapterStatus, + TargetStatus, SenseDataLength, and SenseData in that + order for additional status information. + @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid. **/ EFI_STATUS @@ -543,6 +573,10 @@ ScsiModeSense10Command ( If HostAdapterStatus is NULL, then ASSERT(). If TargetStatus is NULL, then ASSERT(). + If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. + @param[in] ScsiIo A pointer to SCSI IO protocol. @param[in] Timeout The length of timeout period. @param[in, out] SenseData A pointer to output sense data. @@ -550,13 +584,14 @@ ScsiModeSense10Command ( @param[out] HostAdapterStatus The status of Host Adapter. @param[out] TargetStatus The status of the target. - @retval EFI_SUCCESS The command executed successfully. + @retval EFI_SUCCESS Command is executed successfully. @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are too many SCSI Command Packets already queued. @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet. @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported by the SCSI initiator(i.e., SCSI Host Controller) @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute. + @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid. **/ EFI_STATUS @@ -620,6 +655,14 @@ ScsiRequestSenseCommand ( If TargetStatus is NULL, then ASSERT(). If DataLength is NULL, then ASSERT(). + If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. + + If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. + @param[in] ScsiIo A pointer to SCSI IO protocol. @param[in] Timeout The length of timeout period. @param[in, out] SenseData A pointer to output sense data. @@ -628,18 +671,19 @@ ScsiRequestSenseCommand ( @param[out] TargetStatus The status of the target. @param[in, out] DataBuffer A pointer to a data buffer. @param[in, out] DataLength The length of data buffer. - @param[in] Pmi A partial medium indicator. - - @retval EFI_SUCCESS The command executed successfully. - @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire - DataBuffer could not be transferred. The actual - number of bytes transferred is returned in DataLength. - @retval EFI_NOT_READY The SCSI Request Packet could not be sent because - there are too many SCSI Command Packets already queued. - @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet. - @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet - is not supported by the SCSI initiator(i.e., SCSI Host Controller) - @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute. + @param[in] Pmi Partial medium indicator. + + @retval EFI_SUCCESS Command is executed successfully. + @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire + DataBuffer could not be transferred. The actual + number of bytes transferred is returned in DataLength. + @retval EFI_NOT_READY The SCSI Request Packet could not be sent because + there are too many SCSI Command Packets already queued. + @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet. + @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet + is not supported by the SCSI initiator(i.e., SCSI Host Controller) + @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute. + @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid. **/ EFI_STATUS @@ -715,6 +759,14 @@ ScsiReadCapacityCommand ( If TargetStatus is NULL, then ASSERT(). If DataLength is NULL, then ASSERT(). + If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. + + If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. + @param[in] ScsiIo A pointer to SCSI IO protocol. @param[in] Timeout The length of timeout period. @param[in, out] SenseData A pointer to output sense data. @@ -725,16 +777,17 @@ ScsiReadCapacityCommand ( @param[in, out] DataLength The length of data buffer. @param[in] Pmi Partial medium indicator. - @retval EFI_SUCCESS The command executed successfully. - @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire - DataBuffer could not be transferred. The actual - number of bytes transferred is returned in DataLength. - @retval EFI_NOT_READY The SCSI Request Packet could not be sent because - there are too many SCSI Command Packets already queued. - @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet. - @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet - is not supported by the SCSI initiator(i.e., SCSI Host Controller) - @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute. + @retval EFI_SUCCESS Command is executed successfully. + @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire + DataBuffer could not be transferred. The actual + number of bytes transferred is returned in DataLength. + @retval EFI_NOT_READY The SCSI Request Packet could not be sent because + there are too many SCSI Command Packets already queued. + @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet. + @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet + is not supported by the SCSI initiator(i.e., SCSI Host Controller) + @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute. + @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid. **/ EFI_STATUS @@ -813,6 +866,13 @@ ScsiReadCapacity16Command ( If TargetStatus is NULL, then ASSERT(). If DataLength is NULL, then ASSERT(). + If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. + + If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. @param[in] ScsiIo A pointer to SCSI IO protocol. @param[in] Timeout The length of timeout period. @@ -825,15 +885,16 @@ ScsiReadCapacity16Command ( @param[in] StartLba The start address of LBA. @param[in] SectorSize The number of contiguous logical blocks of data that shall be transferred. - @retval EFI_SUCCESS The command is executed successfully. - @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire DataBuffer could - not be transferred. The actual number of bytes transferred is returned in DataLength. - @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are too many - SCSI Command Packets already queued. - @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet. - @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported by - the SCSI initiator(i.e., SCSI Host Controller) - @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute. + @retval EFI_SUCCESS Command is executed successfully. + @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire DataBuffer could + not be transferred. The actual number of bytes transferred is returned in DataLength. + @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are too many + SCSI Command Packets already queued. + @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet. + @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported by + the SCSI initiator(i.e., SCSI Host Controller) + @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute. + @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid. **/ EFI_STATUS @@ -905,6 +966,14 @@ ScsiRead10Command ( If TargetStatus is NULL, then ASSERT(). If DataLength is NULL, then ASSERT(). + If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. + + If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. + @param[in] ScsiIo SCSI IO Protocol to use @param[in] Timeout The length of timeout period. @param[in, out] SenseData A pointer to output sense data. @@ -916,15 +985,16 @@ ScsiRead10Command ( @param[in] StartLba The start address of LBA. @param[in] SectorSize The number of contiguous logical blocks of data that shall be transferred. - @retval EFI_SUCCESS The command executed successfully. - @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire DataBuffer could - not be transferred. The actual number of bytes transferred is returned in DataLength. - @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are too many - SCSI Command Packets already queued. - @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet. - @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported by - the SCSI initiator(i.e., SCSI Host Controller) - @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute. + @retval EFI_SUCCESS Command is executed successfully. + @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire DataBuffer could + not be transferred. The actual number of bytes transferred is returned in DataLength. + @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are too many + SCSI Command Packets already queued. + @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet. + @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported by + the SCSI initiator(i.e., SCSI Host Controller) + @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute. + @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid. **/ EFI_STATUS @@ -995,6 +1065,13 @@ ScsiWrite10Command ( If TargetStatus is NULL, then ASSERT(). If DataLength is NULL, then ASSERT(). + If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. + + If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. @param[in] ScsiIo A pointer to SCSI IO protocol. @param[in] Timeout The length of timeout period. @@ -1007,15 +1084,16 @@ ScsiWrite10Command ( @param[in] StartLba The start address of LBA. @param[in] SectorSize The number of contiguous logical blocks of data that shall be transferred. - @retval EFI_SUCCESS The command executed successfully. - @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire DataBuffer could - not be transferred. The actual number of bytes transferred is returned in DataLength. - @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are too many - SCSI Command Packets already queued. - @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet. - @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported by - the SCSI initiator(i.e., SCSI Host Controller) - @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute. + @retval EFI_SUCCESS Command is executed successfully. + @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire DataBuffer could + not be transferred. The actual number of bytes transferred is returned in DataLength. + @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are too many + SCSI Command Packets already queued. + @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet. + @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported by + the SCSI initiator(i.e., SCSI Host Controller) + @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute. + @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid. **/ EFI_STATUS @@ -1087,6 +1165,14 @@ ScsiRead16Command ( If TargetStatus is NULL, then ASSERT(). If DataLength is NULL, then ASSERT(). + If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. + + If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. + @param[in] ScsiIo SCSI IO Protocol to use @param[in] Timeout The length of timeout period. @param[in, out] SenseData A pointer to output sense data. @@ -1098,15 +1184,16 @@ ScsiRead16Command ( @param[in] StartLba The start address of LBA. @param[in] SectorSize The number of contiguous logical blocks of data that shall be transferred. - @retval EFI_SUCCESS The command is executed successfully. - @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire DataBuffer could - not be transferred. The actual number of bytes transferred is returned in DataLength. - @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are too many - SCSI Command Packets already queued. - @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet. - @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported by - the SCSI initiator(i.e., SCSI Host Controller) - @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute. + @retval EFI_SUCCESS Command is executed successfully. + @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire DataBuffer could + not be transferred. The actual number of bytes transferred is returned in DataLength. + @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are too many + SCSI Command Packets already queued. + @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet. + @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported by + the SCSI initiator(i.e., SCSI Host Controller) + @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute. + @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid. **/ EFI_STATUS From 21170d1fba4d45d16ddb03e331da704ec0d44266 Mon Sep 17 00:00:00 2001 From: Zhang Lubo Date: Fri, 11 Sep 2015 00:52:31 +0000 Subject: [PATCH 027/525] MdeModulePkg: PXE Driver's LoadFile protocol should check FilePath PXE driver's LoadFile protocol should check the input parameter FilePath to see whether it's a supported device path.If not, it should return invalid parameter, do not continue PXE boot. (Sync patch r18435 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Zhang Lubo Reviewed-by: Fu Siyuan Reviewed-by: Ye Ting git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18440 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Universal/Network/UefiPxeBcDxe/PxeBcImpl.c | 4 ++++ MdeModulePkg/Universal/Network/UefiPxeBcDxe/PxeBcImpl.h | 1 + 2 files changed, 5 insertions(+) diff --git a/MdeModulePkg/Universal/Network/UefiPxeBcDxe/PxeBcImpl.c b/MdeModulePkg/Universal/Network/UefiPxeBcDxe/PxeBcImpl.c index 4dd7944e6a9a..72923f1b38a4 100644 --- a/MdeModulePkg/Universal/Network/UefiPxeBcDxe/PxeBcImpl.c +++ b/MdeModulePkg/Universal/Network/UefiPxeBcDxe/PxeBcImpl.c @@ -2776,6 +2776,10 @@ EfiPxeLoadFile ( UINT64 TmpBufSize; BOOLEAN MediaPresent; + if (FilePath == NULL || !IsDevicePathEnd (FilePath)) { + return EFI_INVALID_PARAMETER; + } + Private = PXEBC_PRIVATE_DATA_FROM_LOADFILE (This); PxeBc = &Private->PxeBc; NewMakeCallback = FALSE; diff --git a/MdeModulePkg/Universal/Network/UefiPxeBcDxe/PxeBcImpl.h b/MdeModulePkg/Universal/Network/UefiPxeBcDxe/PxeBcImpl.h index 6e88deae47f3..ce8d8add3fff 100644 --- a/MdeModulePkg/Universal/Network/UefiPxeBcDxe/PxeBcImpl.h +++ b/MdeModulePkg/Universal/Network/UefiPxeBcDxe/PxeBcImpl.h @@ -33,6 +33,7 @@ typedef struct _PXEBC_PRIVATE_DATA PXEBC_PRIVATE_DATA; #include #include +#include #include #include #include From a687f448f938f0660356f3c07e393f93ef7166c4 Mon Sep 17 00:00:00 2001 From: Zhang Lubo Date: Fri, 11 Sep 2015 00:52:51 +0000 Subject: [PATCH 028/525] NetworkPkg: PXE Driver's LoadFile protocol should check FilePath PXE driver's LoadFile protocol should check the input parameter FilePath to see whether it's a supported device path.If not, it should return invalid parameter, do not continue PXE boot. (Sync patch r18436 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Zhang Lubo Reviewed-by: Fu Siyuan Reviewed-by: Ye Ting git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18441 6f19259b-4bc3-4df7-8a09-765794883524 --- NetworkPkg/UefiPxeBcDxe/PxeBcImpl.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/NetworkPkg/UefiPxeBcDxe/PxeBcImpl.c b/NetworkPkg/UefiPxeBcDxe/PxeBcImpl.c index cdcf2f0d3ead..367a1356abcc 100644 --- a/NetworkPkg/UefiPxeBcDxe/PxeBcImpl.c +++ b/NetworkPkg/UefiPxeBcDxe/PxeBcImpl.c @@ -2328,6 +2328,10 @@ EfiPxeLoadFile ( EFI_STATUS Status; BOOLEAN MediaPresent; + if (FilePath == NULL || !IsDevicePathEnd (FilePath)) { + return EFI_INVALID_PARAMETER; + } + VirtualNic = PXEBC_VIRTUAL_NIC_FROM_LOADFILE (This); Private = VirtualNic->Private; PxeBc = &Private->PxeBc; From e5a9019a501bdde2fa22f5ca4d5ac651dd2d89cf Mon Sep 17 00:00:00 2001 From: Qiu Shumin Date: Fri, 11 Sep 2015 03:13:01 +0000 Subject: [PATCH 029/525] ShellPkg: Fix 'for' command fail with multiple fields. When multiple fields are found in 'for' command return invalid parameters error. (Sync patch r18416 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Qiu Shumin Reviewed-by: Jaben Carsey git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18442 6f19259b-4bc3-4df7-8a09-765794883524 --- ShellPkg/Library/UefiShellLevel1CommandsLib/For.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ShellPkg/Library/UefiShellLevel1CommandsLib/For.c b/ShellPkg/Library/UefiShellLevel1CommandsLib/For.c index 2ecc5cd9ef48..cbf05170135d 100644 --- a/ShellPkg/Library/UefiShellLevel1CommandsLib/For.c +++ b/ShellPkg/Library/UefiShellLevel1CommandsLib/For.c @@ -438,6 +438,11 @@ ShellCommandRunFor ( gEfiShellParametersProtocol->Argv[2]) == 0) { for (LoopVar = 0x3 ; LoopVar < gEfiShellParametersProtocol->Argc ; LoopVar++) { ASSERT((ArgSet == NULL && ArgSize == 0) || (ArgSet != NULL)); + if (StrStr (gEfiShellParametersProtocol->Argv[LoopVar], L")") != NULL && + (LoopVar + 1) < gEfiShellParametersProtocol->Argc + ) { + return (SHELL_INVALID_PARAMETER); + } if (ArgSet == NULL) { // ArgSet = StrnCatGrow(&ArgSet, &ArgSize, L"\"", 0); } else { From a565ec4117d31256151d8ce343a7c943c97bae40 Mon Sep 17 00:00:00 2001 From: Fu Siyuan Date: Tue, 15 Sep 2015 05:38:43 +0000 Subject: [PATCH 030/525] NetworkPkg: Enlarge receive block size of HTTP boot driver. HTTP boot driver uses block size of 1024 when receiving HTTP message body, but typically the MTU of Ethernet is 1500 bytes so it makes 1 TCP segment data split into 2 Http.Response call. This patch enlarges the block size to avoid this issue. (Sync patch r18447 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Fu Siyuan Reviewed-by: Ye Ting git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18457 6f19259b-4bc3-4df7-8a09-765794883524 --- NetworkPkg/HttpBootDxe/HttpBootClient.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NetworkPkg/HttpBootDxe/HttpBootClient.h b/NetworkPkg/HttpBootDxe/HttpBootClient.h index 2dfafab93681..06b91098fc38 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootClient.h +++ b/NetworkPkg/HttpBootDxe/HttpBootClient.h @@ -16,7 +16,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #define __EFI_HTTP_BOOT_HTTP_H__ #define HTTP_BOOT_REQUEST_TIMEOUT 5000 // 5 seconds in uints of millisecond. -#define HTTP_BOOT_BLOCK_SIZE 1024 +#define HTTP_BOOT_BLOCK_SIZE 1500 #define HTTP_FIELD_NAME_USER_AGENT "User-Agent" #define HTTP_FIELD_NAME_HOST "Host" From 1e4de20d3a2273df954f061561a43e2def3d313b Mon Sep 17 00:00:00 2001 From: Fu Siyuan Date: Tue, 15 Sep 2015 05:39:05 +0000 Subject: [PATCH 031/525] NetworkPkg: Update cache management in HTTP boot driver. The original HTTP boot driver always save the received message body in its cache, it bring a large of memory allocation during HTTP download. This patch updates the HTTP boot driver to only cache data when caller doesn't provide a buffer for download (which is usually used when caller want to get the required buffer size). (Sync patch r18448 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Fu Siyuan Reviewed-by: Ye Ting git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18458 6f19259b-4bc3-4df7-8a09-765794883524 --- NetworkPkg/HttpBootDxe/HttpBootClient.c | 63 ++++++++++++++----------- 1 file changed, 35 insertions(+), 28 deletions(-) diff --git a/NetworkPkg/HttpBootDxe/HttpBootClient.c b/NetworkPkg/HttpBootDxe/HttpBootClient.c index 3b4afc396f01..5669c5f37ce1 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootClient.c +++ b/NetworkPkg/HttpBootDxe/HttpBootClient.c @@ -458,22 +458,6 @@ HttpBootGetBootFileCallback ( } CallbackData = (HTTP_BOOT_CALLBACK_DATA *) Context; - - // - // Save the data into cache list. - // - NewEntityData = AllocatePool (sizeof (HTTP_BOOT_ENTITY_DATA)); - if (NewEntityData == NULL) { - return EFI_OUT_OF_RESOURCES; - } - if (CallbackData->NewBlock) { - NewEntityData->Block = CallbackData->Block; - CallbackData->Block = NULL; - } - NewEntityData->DataLength = Length; - NewEntityData->DataStart = (UINT8*) Data; - InsertTailList (&CallbackData->Cache->EntityDataList, &NewEntityData->Link); - // // Copy data if caller has provided a buffer. // @@ -486,6 +470,22 @@ HttpBootGetBootFileCallback ( CallbackData->CopyedSize += MIN (Length, CallbackData->BufferSize - CallbackData->CopyedSize); } + // + // The caller doesn't provide a buffer, save the block into cache list. + // + if (CallbackData->Cache != NULL) { + NewEntityData = AllocatePool (sizeof (HTTP_BOOT_ENTITY_DATA)); + if (NewEntityData == NULL) { + return EFI_OUT_OF_RESOURCES; + } + if (CallbackData->NewBlock) { + NewEntityData->Block = CallbackData->Block; + CallbackData->Block = NULL; + } + NewEntityData->DataLength = Length; + NewEntityData->DataStart = (UINT8*) Data; + InsertTailList (&CallbackData->Cache->EntityDataList, &NewEntityData->Link); + } return EFI_SUCCESS; } @@ -566,10 +566,10 @@ HttpBootGetBootFile ( // // - // 1. Create a temp cache item for the requested URI. + // 1. Create a temp cache item for the requested URI if caller doesn't provide buffer. // Cache = NULL; - if (!HeaderOnly) { + if ((!HeaderOnly) && (*BufferSize == 0)) { Cache = AllocateZeroPool (sizeof (HTTP_BOOT_CACHE_CONTENT)); if (Cache == NULL) { Status = EFI_OUT_OF_RESOURCES; @@ -659,7 +659,7 @@ HttpBootGetBootFile ( // // 2.3 Record the request info in a temp cache item. // - if (!HeaderOnly) { + if (Cache != NULL) { Cache->RequestData = RequestData; } @@ -703,7 +703,7 @@ HttpBootGetBootFile ( // // 3.2 Cache the response header. // - if (!HeaderOnly) { + if (Cache != NULL) { Cache->ResponseData = ResponseData; } @@ -733,17 +733,26 @@ HttpBootGetBootFile ( // // 3.4 Continue to receive and parse message-body if needed. // + Block = NULL; if (!HeaderOnly) { ZeroMem (&ResponseBody, sizeof (HTTP_IO_RESOPNSE_DATA)); while (!HttpIsMessageComplete (Parser)) { // - // Allocate a new block to hold the message-body. + // Allocate a block to hold the message-body, if caller doesn't provide + // a buffer, the block will be cached and we will allocate a new one here. // - Block = AllocatePool (HTTP_BOOT_BLOCK_SIZE); - if (Block == NULL) { - Status = EFI_OUT_OF_RESOURCES; - goto ERROR_6; + if (Block == NULL || Context.BufferSize == 0) { + Block = AllocatePool (HTTP_BOOT_BLOCK_SIZE); + if (Block == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ERROR_6; + } + Context.NewBlock = TRUE; + Context.Block = Block; + } else { + Context.NewBlock = FALSE; } + ResponseBody.Body = (CHAR8*) Block; ResponseBody.BodyLength = HTTP_BOOT_BLOCK_SIZE; Status = HttpIoRecvResponse ( @@ -758,8 +767,6 @@ HttpBootGetBootFile ( // // Parse the new received block of the message-body, the block will be saved in cache. // - Context.NewBlock = TRUE; - Context.Block = Block; Status = HttpParseMessageBody ( Parser, ResponseBody.BodyLength, @@ -787,7 +794,7 @@ HttpBootGetBootFile ( // // 4. Save the cache item to driver's cache list and return. // - if (!HeaderOnly) { + if (Cache != NULL) { Cache->EntityLength = ContentLength; InsertTailList (&Private->CacheList, &Cache->Link); } From d277707a56041fad7a99dd345e9d151b87bf0519 Mon Sep 17 00:00:00 2001 From: Fu Siyuan Date: Tue, 15 Sep 2015 05:39:28 +0000 Subject: [PATCH 032/525] NetworkPkg: Avoid memory allocation for each HTTP message exchange. This patch updates the HTTP driver to use a shared buffer for URL parsing to avoid memory allocation for each HTTP request. (Sync patch r18449 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Fu Siyuan Reviewed-by: Ye Ting git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18459 6f19259b-4bc3-4df7-8a09-765794883524 --- NetworkPkg/HttpDxe/HttpImpl.c | 19 ++++++++++--------- NetworkPkg/HttpDxe/HttpProto.c | 11 +++++++++++ NetworkPkg/HttpDxe/HttpProto.h | 4 ++++ 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/NetworkPkg/HttpDxe/HttpImpl.c b/NetworkPkg/HttpDxe/HttpImpl.c index dc06b9855c27..c5b2be430e29 100644 --- a/NetworkPkg/HttpDxe/HttpImpl.c +++ b/NetworkPkg/HttpDxe/HttpImpl.c @@ -224,6 +224,7 @@ EfiHttpRequest ( BOOLEAN ReConfigure; CHAR8 *RequestStr; CHAR8 *Url; + UINTN UrlLen; CHAR16 *HostNameStr; HTTP_TOKEN_WRAP *Wrap; HTTP_TCP_TOKEN_WRAP *TcpWrap; @@ -283,10 +284,15 @@ EfiHttpRequest ( // // Parse the URI of the remote host. // - Url = AllocatePool (StrLen (Request->Url) + 1); - if (Url == NULL) { - return EFI_OUT_OF_RESOURCES; - } + UrlLen = StrLen (Request->Url) + 1; + if (UrlLen > HTTP_URL_BUFFER_LEN) { + Url = AllocateZeroPool (UrlLen); + if (Url == NULL) { + return EFI_OUT_OF_RESOURCES; + } + FreePool (HttpInstance->Url); + HttpInstance->Url = Url; + } UnicodeStrToAsciiStr (Request->Url, Url); UrlParser = NULL; @@ -347,7 +353,6 @@ EfiHttpRequest ( Wrap->TcpWrap.Method = Request->Method; - FreePool (Url); FreePool (HostName); // @@ -480,7 +485,6 @@ EfiHttpRequest ( goto Error4; } - FreePool (Url); if (HostName != NULL) { FreePool (HostName); } @@ -520,9 +524,6 @@ EfiHttpRequest ( } Error1: - if (Url != NULL) { - FreePool (Url); - } if (HostName != NULL) { FreePool (HostName); } diff --git a/NetworkPkg/HttpDxe/HttpProto.c b/NetworkPkg/HttpDxe/HttpProto.c index e8ce9879f309..99f907e10c7f 100644 --- a/NetworkPkg/HttpDxe/HttpProto.c +++ b/NetworkPkg/HttpDxe/HttpProto.c @@ -431,6 +431,12 @@ HttpInitProtocol ( goto ON_ERROR; } + HttpInstance->Url = AllocateZeroPool (HTTP_URL_BUFFER_LEN); + if (HttpInstance->Url == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; + } + NetMapInit (&HttpInstance->TxTokens); NetMapInit (&HttpInstance->RxTokens); @@ -496,6 +502,11 @@ HttpCleanProtocol ( HttpInstance->MsgParser = NULL; } + if (HttpInstance->Url != NULL) { + FreePool (HttpInstance->Url); + HttpInstance->Url = NULL; + } + NetMapClean (&HttpInstance->TxTokens); NetMapClean (&HttpInstance->RxTokens); diff --git a/NetworkPkg/HttpDxe/HttpProto.h b/NetworkPkg/HttpDxe/HttpProto.h index ca4b7b60353d..c37b80c8ec74 100644 --- a/NetworkPkg/HttpDxe/HttpProto.h +++ b/NetworkPkg/HttpDxe/HttpProto.h @@ -51,6 +51,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #define HTTP_KEEP_ALIVE_TIME 7200 #define HTTP_KEEP_ALIVE_INTERVAL 30 +#define HTTP_URL_BUFFER_LEN 4096 + typedef struct _HTTP_SERVICE { UINT32 Signature; EFI_SERVICE_BINDING_PROTOCOL ServiceBinding; @@ -120,6 +122,8 @@ typedef struct _HTTP_PROTOCOL { NET_MAP TxTokens; NET_MAP RxTokens; + + CHAR8 *Url; } HTTP_PROTOCOL; typedef struct { From 07e11eedfc6edff2a03df5105e7a8ae9946c16f6 Mon Sep 17 00:00:00 2001 From: Fu Siyuan Date: Tue, 15 Sep 2015 05:39:48 +0000 Subject: [PATCH 033/525] NetworkPkg: RxToken event not closed in Http.Response(). This patch contains a bug fix in HTTP driver that the RxToken is not closed, this is one of the main reasons which lower the HTTP download speed. (Sync patch r18450 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Fu Siyuan Reviewed-by: Ye Ting git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18460 6f19259b-4bc3-4df7-8a09-765794883524 --- NetworkPkg/HttpDxe/HttpProto.c | 1 + 1 file changed, 1 insertion(+) diff --git a/NetworkPkg/HttpDxe/HttpProto.c b/NetworkPkg/HttpDxe/HttpProto.c index 99f907e10c7f..9b06e24bed0e 100644 --- a/NetworkPkg/HttpDxe/HttpProto.c +++ b/NetworkPkg/HttpDxe/HttpProto.c @@ -104,6 +104,7 @@ HttpTcpReceiveNotify ( } Wrap = (HTTP_TOKEN_WRAP *) Context; + gBS->CloseEvent (Wrap->TcpWrap.RxToken.CompletionToken.Event); if (EFI_ERROR (Wrap->TcpWrap.RxToken.CompletionToken.Status)) { return ; } From 38ada0e8aff0f447dc98a1f37af40f0a65b0fb59 Mon Sep 17 00:00:00 2001 From: Fu Siyuan Date: Tue, 15 Sep 2015 05:40:12 +0000 Subject: [PATCH 034/525] NetworkPkg: Update Http driver to use DPC mechanism. This patch updates the HttpDxe driver to use the DPC mechanism to avoid long time delay when single event. (Sync patch r18451 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Fu Siyuan Reviewed-by: Ye Ting git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18461 6f19259b-4bc3-4df7-8a09-765794883524 --- NetworkPkg/HttpDxe/HttpDriver.h | 2 +- NetworkPkg/HttpDxe/HttpDxe.inf | 1 + NetworkPkg/HttpDxe/HttpImpl.c | 9 +++++- NetworkPkg/HttpDxe/HttpProto.c | 54 ++++++++++++++++++++++++++++----- 4 files changed, 56 insertions(+), 10 deletions(-) diff --git a/NetworkPkg/HttpDxe/HttpDriver.h b/NetworkPkg/HttpDxe/HttpDriver.h index d95b05b63492..eea8d5169e71 100644 --- a/NetworkPkg/HttpDxe/HttpDriver.h +++ b/NetworkPkg/HttpDxe/HttpDriver.h @@ -28,7 +28,7 @@ #include #include #include -#include +#include // // UEFI Driver Model Protocols diff --git a/NetworkPkg/HttpDxe/HttpDxe.inf b/NetworkPkg/HttpDxe/HttpDxe.inf index e8117006d6e7..0d3bd00cf7b7 100644 --- a/NetworkPkg/HttpDxe/HttpDxe.inf +++ b/NetworkPkg/HttpDxe/HttpDxe.inf @@ -48,6 +48,7 @@ DebugLib NetLib HttpLib + DpcLib [Protocols] gEfiHttpServiceBindingProtocolGuid ## BY_START diff --git a/NetworkPkg/HttpDxe/HttpImpl.c b/NetworkPkg/HttpDxe/HttpImpl.c index c5b2be430e29..2b62dc5db299 100644 --- a/NetworkPkg/HttpDxe/HttpImpl.c +++ b/NetworkPkg/HttpDxe/HttpImpl.c @@ -502,6 +502,8 @@ EfiHttpRequest ( goto Error5; } + DispatchDpc (); + return EFI_SUCCESS; Error5: @@ -1330,6 +1332,7 @@ EfiHttpPoll ( ) { HTTP_PROTOCOL *HttpInstance; + EFI_STATUS Status; if (This == NULL) { return EFI_INVALID_PARAMETER; @@ -1346,5 +1349,9 @@ EfiHttpPoll ( return EFI_NOT_STARTED; } - return HttpInstance->Tcp4->Poll (HttpInstance->Tcp4); + Status = HttpInstance->Tcp4->Poll (HttpInstance->Tcp4); + + DispatchDpc (); + + return Status; } diff --git a/NetworkPkg/HttpDxe/HttpProto.c b/NetworkPkg/HttpDxe/HttpProto.c index 9b06e24bed0e..8fbd45411064 100644 --- a/NetworkPkg/HttpDxe/HttpProto.c +++ b/NetworkPkg/HttpDxe/HttpProto.c @@ -38,20 +38,18 @@ HttpCommonNotify ( /** The notify function associated with TxToken for Tcp4->Transmit(). - @param[in] Event The event signaled. @param[in] Context The context. **/ VOID EFIAPI -HttpTcpTransmitNotify ( - IN EFI_EVENT Event, +HttpTcpTransmitNotifyDpc ( IN VOID *Context ) { HTTP_TOKEN_WRAP *Wrap; - if ((Event == NULL) || (Context == NULL)) { + if (Context == NULL) { return ; } @@ -79,17 +77,36 @@ HttpTcpTransmitNotify ( } +/** + Request HttpTcpTransmitNotifyDpc as a DPC at TPL_CALLBACK. + + @param Event The receive event delivered to TCP for transmit. + @param Context Context for the callback. + +**/ +VOID +EFIAPI +HttpTcpTransmitNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + // + // Request HttpTcpTransmitNotifyDpc as a DPC at TPL_CALLBACK + // + QueueDpc (TPL_CALLBACK, HttpTcpTransmitNotifyDpc, Context); +} + + /** The notify function associated with RxToken for Tcp4->Receive (). - @param[in] Event The event signaled. @param[in] Context The context. **/ VOID EFIAPI -HttpTcpReceiveNotify ( - IN EFI_EVENT Event, +HttpTcpReceiveNotifyDpc ( IN VOID *Context ) { @@ -99,7 +116,7 @@ HttpTcpReceiveNotify ( EFI_STATUS Status; HTTP_PROTOCOL *HttpInstance; - if ((Event == NULL) || (Context == NULL)) { + if (Context == NULL) { return ; } @@ -173,6 +190,27 @@ HttpTcpReceiveNotify ( FreePool (Wrap); } +/** + Request HttpTcpReceiveNotifyDpc as a DPC at TPL_CALLBACK. + + @param Event The receive event delivered to TCP for receive. + @param Context Context for the callback. + +**/ +VOID +EFIAPI +HttpTcpReceiveNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + // + // Request HttpTcpTransmitNotifyDpc as a DPC at TPL_CALLBACK + // + QueueDpc (TPL_CALLBACK, HttpTcpReceiveNotifyDpc, Context); +} + + /** Create events for the TCP4 connection token and TCP4 close token. From 43b3c498bda4f1e2c96772d1e1af956cabae6cf5 Mon Sep 17 00:00:00 2001 From: Qiu Shumin Date: Tue, 15 Sep 2015 05:40:43 +0000 Subject: [PATCH 035/525] ShellPkg: Fix Shell does not support ASCII pipe(|a). (Sync patch r18452 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Qiu Shumin Reviewed-by: Jaben Carsey git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18462 6f19259b-4bc3-4df7-8a09-765794883524 --- ShellPkg/Application/Shell/Shell.c | 36 +++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/ShellPkg/Application/Shell/Shell.c b/ShellPkg/Application/Shell/Shell.c index 78a64de19eae..03f5e4f05fe8 100644 --- a/ShellPkg/Application/Shell/Shell.c +++ b/ShellPkg/Application/Shell/Shell.c @@ -1578,11 +1578,18 @@ RunSplitCommand( SHELL_FREE_NON_NULL(OurCommandLine); SHELL_FREE_NON_NULL(NextCommandLine); return (EFI_INVALID_PARAMETER); - } else if (NextCommandLine[0] != CHAR_NULL && - NextCommandLine[0] == L'a' && - NextCommandLine[1] == L' ' - ){ + } else if (NextCommandLine[0] == L'a' && + (NextCommandLine[1] == L' ' || NextCommandLine[1] == CHAR_NULL) + ){ CopyMem(NextCommandLine, NextCommandLine+1, StrSize(NextCommandLine) - sizeof(NextCommandLine[0])); + while (NextCommandLine[0] == L' ') { + CopyMem(NextCommandLine, NextCommandLine+1, StrSize(NextCommandLine) - sizeof(NextCommandLine[0])); + } + if (NextCommandLine[0] == CHAR_NULL) { + SHELL_FREE_NON_NULL(OurCommandLine); + SHELL_FREE_NON_NULL(NextCommandLine); + return (EFI_INVALID_PARAMETER); + } Unicode = FALSE; } else { Unicode = TRUE; @@ -1884,24 +1891,31 @@ VerifySplit( EFI_STATUS Status; // - // Verify up to the pipe or end character + // If this was the only item, then get out // - Status = IsValidSplit(CmdLine); - if (EFI_ERROR(Status)) { - return (Status); + if (!ContainsSplit(CmdLine)) { + return (EFI_SUCCESS); } // - // If this was the only item, then get out + // Verify up to the pipe or end character // - if (!ContainsSplit(CmdLine)) { - return (EFI_SUCCESS); + Status = IsValidSplit(CmdLine); + if (EFI_ERROR(Status)) { + return (Status); } // // recurse to verify the next item // TempSpot = FindFirstCharacter(CmdLine, L"|", L'^') + 1; + if (*TempSpot == L'a' && + (*(TempSpot + 1) == L' ' || *(TempSpot + 1) == CHAR_NULL) + ) { + // If it's an ASCII pipe '|a' + TempSpot += 1; + } + return (VerifySplit(TempSpot)); } From 19af298bc451bef3661ccdc81dca1c8c6af93444 Mon Sep 17 00:00:00 2001 From: Fu Siyuan Date: Tue, 15 Sep 2015 05:44:16 +0000 Subject: [PATCH 036/525] NetworkPkg: Correct the missed code in r18449. The fix r18449 missed 1 line which will cause Http.Request() ASSERT. This patch will correct this error. (Sync patch r18453 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Fu Siyuan Reviewed-by: Ye Ting git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18463 6f19259b-4bc3-4df7-8a09-765794883524 --- NetworkPkg/HttpDxe/HttpImpl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NetworkPkg/HttpDxe/HttpImpl.c b/NetworkPkg/HttpDxe/HttpImpl.c index 2b62dc5db299..76c95b2bb66a 100644 --- a/NetworkPkg/HttpDxe/HttpImpl.c +++ b/NetworkPkg/HttpDxe/HttpImpl.c @@ -275,7 +275,6 @@ EfiHttpRequest ( return EFI_ACCESS_DENIED; } - Url = NULL; HostName = NULL; Wrap = NULL; HostNameStr = NULL; @@ -284,6 +283,7 @@ EfiHttpRequest ( // // Parse the URI of the remote host. // + Url = HttpInstance->Url; UrlLen = StrLen (Request->Url) + 1; if (UrlLen > HTTP_URL_BUFFER_LEN) { Url = AllocateZeroPool (UrlLen); From 9f00fa9165ebc8da0cc604e7f475f3f2ad7735ca Mon Sep 17 00:00:00 2001 From: Qiu Shumin Date: Tue, 15 Sep 2015 05:44:39 +0000 Subject: [PATCH 037/525] ShellPkg: Update the help information for 'setvar' command to follow Shell behavior. Since Shell will remove the quotes in parameters, setvar cannot receive the quotes from ="ascii" or =L"unicode". User should add ^ to escape quotes in setvar data. (Sync patch r18454 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Qiu Shumin Reviewed-by: Jaben Carsey git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18464 6f19259b-4bc3-4df7-8a09-765794883524 --- .../UefiShellDebug1CommandsLib.uni | Bin 140668 -> 140676 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.uni b/ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.uni index 167cacc70dc5fe582a8c3b4d47ed042f7994879c..e16175a6174fbd08275d14d88eaa385e42ae4781 100644 GIT binary patch delta 40 tcmex!ilgN;N5d9IpSg^2)4k_1N&~6Xxs2UF>it|sNyfPC?DH5)+W|?A4;BCb delta 51 zcmZoU&GF|HN5d9IpSjch<}yl6&zj5FC9cE}%HYfp%wWWz%TUZv!cfGJ$&km8zMX#_ HV`)18$NLY3 From 9a36457f943e1a758fdb4b39205022a55bf74cdc Mon Sep 17 00:00:00 2001 From: Fu Siyuan Date: Tue, 15 Sep 2015 05:45:03 +0000 Subject: [PATCH 038/525] MdeModulePkg: Change the algorithm in SNP to use the first found BAR index. The driver binding start function in SNP.c goes through all the BARs and get the last BAR index for use. Theoretically it should work with all valid BARs, but we got reports some device did always use the first valid BAR, so we change the logic in SNP to use the first found BAR index instead of the last one. (Sync patch r18455 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Fu Siyuan Reviewed-by: Ye Ting git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18465 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Universal/Network/SnpDxe/Snp.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/MdeModulePkg/Universal/Network/SnpDxe/Snp.c b/MdeModulePkg/Universal/Network/SnpDxe/Snp.c index a63dd10b296d..db5b6267a613 100644 --- a/MdeModulePkg/Universal/Network/SnpDxe/Snp.c +++ b/MdeModulePkg/Universal/Network/SnpDxe/Snp.c @@ -1,7 +1,7 @@ /** @file Implementation of driver entry point and driver binding protocol. -Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.
+Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -273,6 +273,8 @@ SimpleNetworkDriverStart ( PXE_STATFLAGS InitStatFlags; EFI_PCI_IO_PROTOCOL *PciIo; EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *BarDesc; + BOOLEAN FoundIoBar; + BOOLEAN FoundMemoryBar; DEBUG ((EFI_D_NET, "\nSnpNotifyNetworkInterfaceIdentifier() ")); @@ -403,7 +405,7 @@ SimpleNetworkDriverStart ( Snp->TxRxBuffer = NULL; if (Nii->Revision >= EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION) { - Snp->IfNum = Nii->IfNum; + Snp->IfNum = Nii->IfNum; } else { Snp->IfNum = (UINT8) (Nii->IfNum & 0xFF); @@ -463,6 +465,8 @@ SimpleNetworkDriverStart ( // Snp->MemoryBarIndex = 0; Snp->IoBarIndex = 1; + FoundMemoryBar = FALSE; + FoundIoBar = FALSE; for (BarIndex = 0; BarIndex < PCI_MAX_BAR; BarIndex++) { Status = PciIo->GetBarAttributes ( PciIo, @@ -476,13 +480,19 @@ SimpleNetworkDriverStart ( goto Error_DeleteSNP; } - if (BarDesc->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) { + if ((!FoundMemoryBar) && (BarDesc->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM)) { Snp->MemoryBarIndex = BarIndex; - } else if (BarDesc->ResType == ACPI_ADDRESS_SPACE_TYPE_IO) { + FoundMemoryBar = TRUE; + } else if ((!FoundIoBar) && (BarDesc->ResType == ACPI_ADDRESS_SPACE_TYPE_IO)) { Snp->IoBarIndex = BarIndex; + FoundIoBar = TRUE; } FreePool (BarDesc); + + if (FoundMemoryBar && FoundIoBar) { + break; + } } Status = PxeStart (Snp); From 737acfa88d985fb096a750288b9beff775369b11 Mon Sep 17 00:00:00 2001 From: Samer El-Haj-Mahmoud Date: Tue, 15 Sep 2015 05:45:27 +0000 Subject: [PATCH 039/525] ShellPkg: Rename some functions in Dp to avoid build errors. There are other libraries with similarly named functions that could be linked with the Shell (Sync patch r18456 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Samer El-Haj-Mahmoud Reviewed-by: Jaben Carsey Reviewed-by: Qiu Shumin git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18466 6f19259b-4bc3-4df7-8a09-765794883524 --- ShellPkg/Library/UefiDpLib/DpInternal.h | 5 +++-- ShellPkg/Library/UefiDpLib/DpTrace.c | 5 +++-- ShellPkg/Library/UefiDpLib/DpUtilities.c | 7 ++++--- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/ShellPkg/Library/UefiDpLib/DpInternal.h b/ShellPkg/Library/UefiDpLib/DpInternal.h index c7d9a592fe71..9b8163aaa0f7 100644 --- a/ShellPkg/Library/UefiDpLib/DpInternal.h +++ b/ShellPkg/Library/UefiDpLib/DpInternal.h @@ -7,6 +7,7 @@ DpUtilities.c, DpTrace.c, and DpProfile.c are included here. Copyright (c) 2009 - 2013, Intel Corporation. All rights reserved. + (C) Copyright 2015 Hewlett Packard Enterprise Development LP
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -96,7 +97,7 @@ IsPhase( **/ VOID -GetShortPdbFileName ( +DpGetShortPdbFileName ( IN CHAR8 *PdbFileName, OUT CHAR16 *UnicodeBuffer ); @@ -118,7 +119,7 @@ GetShortPdbFileName ( **/ VOID -GetNameFromHandle ( +DpGetNameFromHandle ( IN EFI_HANDLE Handle ); diff --git a/ShellPkg/Library/UefiDpLib/DpTrace.c b/ShellPkg/Library/UefiDpLib/DpTrace.c index de1d45aa8b7d..cf8200c6f1a2 100644 --- a/ShellPkg/Library/UefiDpLib/DpTrace.c +++ b/ShellPkg/Library/UefiDpLib/DpTrace.c @@ -2,6 +2,7 @@ Trace reporting for the Dp utility. Copyright (c) 2009 - 2013, Intel Corporation. All rights reserved. + (C) Copyright 2015 Hewlett Packard Enterprise Development LP
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -216,7 +217,7 @@ DumpAllTrace( // See if the Handle is in the HandleBuffer for (TIndex = 0; TIndex < (Size / sizeof(HandleBuffer[0])); TIndex++) { if (Measurement.Handle == HandleBuffer[TIndex]) { - GetNameFromHandle (HandleBuffer[TIndex]); + DpGetNameFromHandle (HandleBuffer[TIndex]); break; } } @@ -582,7 +583,7 @@ ProcessHandles( // See if the Handle is in the HandleBuffer for (Index = 0; Index < (Size / sizeof(HandleBuffer[0])); Index++) { if (Measurement.Handle == HandleBuffer[Index]) { - GetNameFromHandle (HandleBuffer[Index]); // Name is put into mGaugeString + DpGetNameFromHandle (HandleBuffer[Index]); // Name is put into mGaugeString break; } } diff --git a/ShellPkg/Library/UefiDpLib/DpUtilities.c b/ShellPkg/Library/UefiDpLib/DpUtilities.c index 063eb658c896..5237459e5b00 100644 --- a/ShellPkg/Library/UefiDpLib/DpUtilities.c +++ b/ShellPkg/Library/UefiDpLib/DpUtilities.c @@ -2,6 +2,7 @@ Utility functions used by the Dp application. Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved. + (C) Copyright 2015 Hewlett Packard Enterprise Development LP
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -131,7 +132,7 @@ IsPhase( **/ VOID -GetShortPdbFileName ( +DpGetShortPdbFileName ( IN CHAR8 *PdbFileName, OUT CHAR16 *UnicodeBuffer ) @@ -188,7 +189,7 @@ GetShortPdbFileName ( **/ VOID -GetNameFromHandle ( +DpGetNameFromHandle ( IN EFI_HANDLE Handle ) { @@ -236,7 +237,7 @@ GetNameFromHandle ( PdbFileName = PeCoffLoaderGetPdbPointer (Image->ImageBase); if (PdbFileName != NULL) { - GetShortPdbFileName (PdbFileName, mGaugeString); + DpGetShortPdbFileName (PdbFileName, mGaugeString); return; } } From a6c273bb633cca00c0fa0f79fbf95704a8fec5e9 Mon Sep 17 00:00:00 2001 From: Star Zeng Date: Tue, 15 Sep 2015 08:46:29 +0000 Subject: [PATCH 040/525] MdeModulePkg PiDxeS3BootScriptLib: Remove a hidden assumption. What to do: 1. Remove a hidden assumption "No SMM driver writes BootScript between SmmReadyToLock and S3SleepEntryCallback". 1.1. Use SmmExitBootServices and SmmLegacyBoot notification to record AtRuntime flag. 1.2. Use mBootScriptDataBootTimeGuid LockBox to save boot time boot script data to handle potential INSERT boot script at runtime in SMM. 2. Do not depend on OS to help restore ACPINvs data and use EfiReservedMemoryType instead of EfiACPIMemoryNVS. 2.1. Use mBootScriptSmmPrivateDataGuid LockBox to save boot script SMM private data with BackFromS3 = TRUE at runtime. S3 resume will help restore it to tell the Library the system is back from S3. Why to do: 1. The hidden assumption "No SMM driver writes BootScript between SmmReadyToLock and S3SleepEntryCallback" will cause confusion to the library's consumer and block the usage of "SMM driver writes BootScript after SmmReadyToLock". So Remove the assumption. 2. In original code, there might be a corner case that malicious code patch ACPINvs boot TableLength field same as SMM boot script. So that it can skip the table restore. The impact is that BootScript in SMM may be overridden by malicious code. -------------------- CopyMem ((VOID*)&TableHeader, (VOID*)mS3BootScriptTablePtr->TableBase, sizeof(EFI_BOOT_SCRIPT_TABLE_HEADER)); if (mS3BootScriptTablePtr->TableLength + sizeof(EFI_BOOT_SCRIPT_TERMINATE) != TableHeader.TableLength) { // TableLength is in NVS ...... // // NOTE: We should NOT use TableHeader.TableLength, because it is already updated to be whole length. // mS3BootScriptTablePtr->TableLength = (UINT32)(mLockBoxLength - sizeof(EFI_BOOT_SCRIPT_TERMINATE)); ? This line can be skipped. -------------------- So use EfiReservedMemoryType instead of EfiACPIMemoryNVS as the code has been updated to not depend on OS to help restore ACPINvs data. (Sync patch r18467 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Star Zeng Reviewed-by: Jiewen Yao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18474 6f19259b-4bc3-4df7-8a09-765794883524 --- .../PiDxeS3BootScriptLib/BootScriptSave.c | 477 ++++++++++++------ .../DxeS3BootScriptLib.inf | 4 +- .../InternalBootScriptLib.h | 17 +- MdeModulePkg/MdeModulePkg.dec | 8 +- MdeModulePkg/MdeModulePkg.uni | Bin 183916 -> 184014 bytes 5 files changed, 345 insertions(+), 161 deletions(-) diff --git a/MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptSave.c b/MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptSave.c index 586a205a532a..24c67984ca16 100644 --- a/MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptSave.c +++ b/MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptSave.c @@ -19,45 +19,111 @@ Data structure usage: - +------------------------------+<-- PcdS3BootScriptTablePrivateDataPtr + +------------------------------+<------- PcdS3BootScriptTablePrivateDataPtr + | SCRIPT_TABLE_PRIVATE_DATA | (mS3BootScriptTablePtr, Before SmmReadyToLock) + | TableBase |--- PcdS3BootScriptTablePrivateSmmDataPtr + | TableLength |--|-- (mS3BootScriptTablePtr = mS3BootScriptTableSmmPtr, After SmmReadyToLock InSmm) + | TableMemoryPageNumber |--|-|---- + | AtRuntime | | | | + | InSmm | | | | + | BootTimeScriptLength |--|-|---|--- + | SmmLocked | | | | | + | BackFromS3 | | | | | + +------------------------------+ | | | | + | | | | + +------------------------------+<-- | | | + | EFI_BOOT_SCRIPT_TABLE_HEADER | | | | + | TableLength |----|-- | | + +------------------------------+ | | | | + | ...... | | | | | + +------------------------------+<---- | | | + | EFI_BOOT_SCRIPT_TERMINATE | | | | + +------------------------------+<------ | | + | | + | | + mBootScriptDataBootTimeGuid LockBox: | | + Used to restore data after back from S3| | + to handle potential INSERT boot script | | + at runtime. | | + +------------------------------+ | | + | Boot Time Boot Script | | | + | Before SmmReadyToLock | | | + | | | | + | | | | + +------------------------------+ | | + | Boot Time Boot Script | | | + | After SmmReadyToLock InSmm | | | + | | | | + +------------------------------+<-------|--| + | | + | | + mBootScriptDataGuid LockBox: (IN_PLACE) | | + Used to restore data at S3 resume. | | + +------------------------------+ | | + | Boot Time Boot Script | | | + | Before SmmReadyToLock | | | + | | | | + | | | | + +------------------------------+ | | + | Boot Time Boot Script | | | + | After SmmReadyToLock InSmm | | | + | | | | + +------------------------------+<-------|--- + | Runtime Boot Script | | + | After SmmReadyToLock InSmm | | + +------------------------------+ | + | ...... | | + +------------------------------+<-------- + + + mBootScriptTableBaseGuid LockBox: (IN_PLACE) + +------------------------------+ + | mS3BootScriptTablePtr-> | + | TableBase | + +------------------------------+ + + + mBootScriptSmmPrivateDataGuid LockBox: (IN_PLACE) + SMM private data with BackFromS3 = TRUE + at runtime. S3 will help restore it to + tell the Library the system is back from S3. + +------------------------------+ | SCRIPT_TABLE_PRIVATE_DATA | - | TableBase |--- - | TableLength |--|-- - | AtRuntime | | | - | InSmm | | | - +------------------------------+ | | - | | - +------------------------------+<-- | - | EFI_BOOT_SCRIPT_TABLE_HEADER | | - | TableLength |----|-- - +------------------------------+ | | - | ...... | | | - +------------------------------+<---- | - | EFI_BOOT_SCRIPT_TERMINATE | | - +------------------------------+<------ + | TableBase | + | TableLength | + | TableMemoryPageNumber | + | AtRuntime | + | InSmm | + | BootTimeScriptLength | + | SmmLocked | + | BackFromS3 = TRUE | + +------------------------------+ **/ SCRIPT_TABLE_PRIVATE_DATA *mS3BootScriptTablePtr; -EFI_EVENT mEnterRuntimeEvent; + // -// Allocate SMM copy because we can not use mS3BootScriptTablePtr when we AtRuntime in InSmm. +// Allocate SMM copy because we can not use mS3BootScriptTablePtr after SmmReadyToLock in InSmm. // SCRIPT_TABLE_PRIVATE_DATA *mS3BootScriptTableSmmPtr; -UINTN mLockBoxLength; EFI_GUID mBootScriptDataGuid = { 0xaea6b965, 0xdcf5, 0x4311, { 0xb4, 0xb8, 0xf, 0x12, 0x46, 0x44, 0x94, 0xd2 } }; -EFI_GUID mBootScriptDataOrgGuid = { +EFI_GUID mBootScriptDataBootTimeGuid = { 0xb5af1d7a, 0xb8cf, 0x4eb3, { 0x89, 0x25, 0xa8, 0x20, 0xe1, 0x6b, 0x68, 0x7d } }; -EFI_GUID mBootScriptHeaderDataGuid = { +EFI_GUID mBootScriptTableBaseGuid = { 0x1810ab4a, 0x2314, 0x4df6, { 0x81, 0xeb, 0x67, 0xc6, 0xec, 0x5, 0x85, 0x91 } }; +EFI_GUID mBootScriptSmmPrivateDataGuid = { + 0x627ee2da, 0x3bf9, 0x439b, { 0x92, 0x9f, 0x2e, 0xe, 0x6e, 0x9d, 0xba, 0x62 } +}; + /** This is an internal function to add a terminate node the entry, recalculate the table length and fill into the table. @@ -97,18 +163,15 @@ S3BootScriptInternalCloseTable ( return S3TableBase; // // NOTE: Here we did NOT adjust the mS3BootScriptTablePtr->TableLength to - // mS3BootScriptTablePtr->TableLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE). Because - // maybe in runtime, we still need add entries into the table, and the runtime entry should be - // added start before this TERMINATE node. + // mS3BootScriptTablePtr->TableLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE). + // Because maybe after SmmReadyToLock, we still need add entries into the table, + // and the entry should be added start before this TERMINATE node. // } /** This function save boot script data to LockBox. - 1. BootSriptPrivate data, BootScript data - Image and DispatchContext are handled by platform. - 2. BootScriptExecutor, BootScriptExecutor context - - ACPI variable - (PI version) sould be handled by SMM driver. S3 Page table is handled here. - - ACPI variable - framework version is already handled by Framework CPU driver. + **/ VOID SaveBootScriptDataToLockBox ( @@ -118,49 +181,37 @@ SaveBootScriptDataToLockBox ( EFI_STATUS Status; // - // mS3BootScriptTablePtr->TableLength does not include EFI_BOOT_SCRIPT_TERMINATE, because we need add entry at runtime. - // Save all info here, just in case that no one will add boot script entry in SMM. + // Save whole memory copy into LockBox. + // It will be used to restore data at S3 resume. // Status = SaveLockBox ( &mBootScriptDataGuid, (VOID *)mS3BootScriptTablePtr->TableBase, - mS3BootScriptTablePtr->TableLength + sizeof(EFI_BOOT_SCRIPT_TERMINATE) + EFI_PAGES_TO_SIZE (mS3BootScriptTablePtr->TableMemoryPageNumber) ); ASSERT_EFI_ERROR (Status); Status = SetLockBoxAttributes (&mBootScriptDataGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE); ASSERT_EFI_ERROR (Status); - // - // We need duplicate the original copy, because it may have INSERT boot script at runtime in SMM. - // If so, we should use original copy to restore data after OS rewrites the ACPINvs region. - // Or the data inserted may cause some original boot script data lost. - // - Status = SaveLockBox ( - &mBootScriptDataOrgGuid, - (VOID *)mS3BootScriptTablePtr->TableBase, - mS3BootScriptTablePtr->TableLength + sizeof(EFI_BOOT_SCRIPT_TERMINATE) - ); - ASSERT_EFI_ERROR (Status); - // // Just need save TableBase. // Do not update other field because they will NOT be used in S3. // Status = SaveLockBox ( - &mBootScriptHeaderDataGuid, + &mBootScriptTableBaseGuid, (VOID *)&mS3BootScriptTablePtr->TableBase, sizeof(mS3BootScriptTablePtr->TableBase) ); ASSERT_EFI_ERROR (Status); - Status = SetLockBoxAttributes (&mBootScriptHeaderDataGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE); + Status = SetLockBoxAttributes (&mBootScriptTableBaseGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE); ASSERT_EFI_ERROR (Status); } /** This is the Event call back function to notify the Library the system is entering - run time phase. + SmmLocked phase. @param Event Pointer to this event @param Context Event handler private data @@ -189,28 +240,29 @@ S3BootScriptEventCallBack ( } // - // Here we should tell the library that we are enter into runtime phase. and - // the memory page number occupied by the table should not grow anymore. + // Here we should tell the library that we are entering SmmLocked phase. + // and the memory page number occupied by the table should not grow anymore. // - if (!mS3BootScriptTablePtr->AtRuntime) { + if (!mS3BootScriptTablePtr->SmmLocked) { // - // In boot time, we need not write the terminate node when adding a node to boot scipt table - // or else, that will impact the performance. However, in runtime, we should append terminate - // node on every add to boot script table + // Before SmmReadyToLock, we need not write the terminate node when adding a node to boot scipt table + // or else, that will impact the performance. However, after SmmReadyToLock, we should append terminate + // node on every add to boot script table. // S3BootScriptInternalCloseTable (); - mS3BootScriptTablePtr->AtRuntime = TRUE; + mS3BootScriptTablePtr->SmmLocked = TRUE; // // Save BootScript data to lockbox // SaveBootScriptDataToLockBox (); } -} +} + /** - This is the Event call back function is triggered in SMM to notify the Library the system is entering - run time phase and set InSmm flag. - + This is the Event call back function is triggered in SMM to notify the Library + the system is entering SmmLocked phase and set InSmm flag. + @param Protocol Points to the protocol's unique identifier @param Interface Points to the interface instance @param Handle The handle on which the interface was installed @@ -233,7 +285,7 @@ S3BootScriptSmmEventCallBack ( } // - // Last chance to call-out, just make sure AtRuntime is set + // Last chance to call-out, just make sure SmmLocked is set. // S3BootScriptEventCallBack (NULL, NULL); @@ -242,22 +294,117 @@ S3BootScriptSmmEventCallBack ( // if (mS3BootScriptTableSmmPtr->TableBase == NULL) { CopyMem (mS3BootScriptTableSmmPtr, mS3BootScriptTablePtr, sizeof(*mS3BootScriptTablePtr)); + + // + // Set InSmm, we allow boot script update when InSmm, but not allow boot script outside SMM. + // InSmm will only be checked if SmmLocked is TRUE. + // + mS3BootScriptTableSmmPtr->InSmm = TRUE; } // - // We should not use ACPINvs copy, because it is not safe. + // We should not use ACPI Reserved copy, because it is not safe. // mS3BootScriptTablePtr = mS3BootScriptTableSmmPtr; + return EFI_SUCCESS; +} + +/** + This function is to save boot time boot script data to LockBox. + + Because there may be INSERT boot script at runtime in SMM. + The boot time copy will be used to restore data after back from S3. + Otherwise the data inserted may cause some boot time boot script data lost + if only BootScriptData used. + +**/ +VOID +SaveBootTimeDataToLockBox ( + VOID + ) +{ + EFI_STATUS Status; + + // + // ACPI Reserved copy is not safe, restore from BootScriptData LockBox first, + // and then save the data to BootScriptDataBootTime LockBox. + // + Status = RestoreLockBox ( + &mBootScriptDataGuid, + NULL, + NULL + ); + ASSERT_EFI_ERROR (Status); + // - // Set InSmm, we allow boot script update when InSmm, but not allow boot script outside SMM. - // InSmm will only be checked if AtRuntime is TRUE. + // Save BootScriptDataBootTime + // It will be used to restore data after back from S3. // - mS3BootScriptTablePtr->InSmm = TRUE; + Status = SaveLockBox ( + &mBootScriptDataBootTimeGuid, + (VOID *) mS3BootScriptTablePtr->TableBase, + mS3BootScriptTablePtr->BootTimeScriptLength + ); + ASSERT_EFI_ERROR (Status); +} + +/** + This function save boot script SMM private data to LockBox with BackFromS3 = TRUE at runtime. + S3 resume will help restore it to tell the Library the system is back from S3. + +**/ +VOID +SaveSmmPriviateDataToLockBoxAtRuntime ( + VOID + ) +{ + EFI_STATUS Status; // - // Record LockBoxLength + // Save boot script SMM private data with BackFromS3 = TRUE. // - mLockBoxLength = mS3BootScriptTableSmmPtr->TableLength + sizeof(EFI_BOOT_SCRIPT_TERMINATE); + mS3BootScriptTablePtr->BackFromS3 = TRUE; + Status = SaveLockBox ( + &mBootScriptSmmPrivateDataGuid, + (VOID *) mS3BootScriptTablePtr, + sizeof (SCRIPT_TABLE_PRIVATE_DATA) + ); + ASSERT_EFI_ERROR (Status); + + Status = SetLockBoxAttributes (&mBootScriptSmmPrivateDataGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE); + ASSERT_EFI_ERROR (Status); + + // + // Set BackFromS3 flag back to FALSE to indicate that now is not back from S3. + // + mS3BootScriptTablePtr->BackFromS3 = FALSE; +} + +/** + This is the Event call back function is triggered in SMM to notify the Library + the system is entering runtime phase. + + @param[in] Protocol Points to the protocol's unique identifier + @param[in] Interface Points to the interface instance + @param[in] Handle The handle on which the interface was installed + + @retval EFI_SUCCESS SmmAtRuntimeCallBack runs successfully + **/ +EFI_STATUS +EFIAPI +S3BootScriptSmmAtRuntimeCallBack ( + IN CONST EFI_GUID *Protocol, + IN VOID *Interface, + IN EFI_HANDLE Handle + ) +{ + if (!mS3BootScriptTablePtr->AtRuntime) { + mS3BootScriptTablePtr->BootTimeScriptLength = (UINT32) (mS3BootScriptTablePtr->TableLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE)); + SaveBootTimeDataToLockBox (); + + mS3BootScriptTablePtr->AtRuntime = TRUE; + SaveSmmPriviateDataToLockBoxAtRuntime (); + } return EFI_SUCCESS; } @@ -288,6 +435,7 @@ S3BootScriptLibInitialize ( BOOLEAN InSmm; EFI_SMM_SYSTEM_TABLE2 *Smst; EFI_PHYSICAL_ADDRESS Buffer; + EFI_EVENT Event; S3TablePtr = (SCRIPT_TABLE_PRIVATE_DATA*)(UINTN)PcdGet64(PcdS3BootScriptTablePrivateDataPtr); // @@ -297,7 +445,7 @@ S3BootScriptLibInitialize ( Buffer = SIZE_4GB - 1; Status = gBS->AllocatePages ( AllocateMaxAddress, - EfiACPIMemoryNVS, + EfiReservedMemoryType, EFI_SIZE_TO_PAGES(sizeof(SCRIPT_TABLE_PRIVATE_DATA)), &Buffer ); @@ -309,17 +457,17 @@ S3BootScriptLibInitialize ( PcdSet64 (PcdS3BootScriptTablePrivateDataPtr, (UINT64) (UINTN)S3TablePtr); ZeroMem (S3TablePtr, sizeof(SCRIPT_TABLE_PRIVATE_DATA)); // - // create event to notify the library system enter the runtime phase + // Create event to notify the library system enter the SmmLocked phase. // - mEnterRuntimeEvent = EfiCreateProtocolNotifyEvent ( - &gEfiDxeSmmReadyToLockProtocolGuid, - TPL_CALLBACK, - S3BootScriptEventCallBack, - NULL, - &Registration - ); - ASSERT (mEnterRuntimeEvent != NULL); - } + Event = EfiCreateProtocolNotifyEvent ( + &gEfiDxeSmmReadyToLockProtocolGuid, + TPL_CALLBACK, + S3BootScriptEventCallBack, + NULL, + &Registration + ); + ASSERT (Event != NULL); + } mS3BootScriptTablePtr = S3TablePtr; // @@ -360,11 +508,30 @@ S3BootScriptLibInitialize ( PcdSet64 (PcdS3BootScriptTablePrivateSmmDataPtr, (UINT64) (UINTN)S3TableSmmPtr); ZeroMem (S3TableSmmPtr, sizeof(SCRIPT_TABLE_PRIVATE_DATA)); + + // + // Register SmmExitBootServices and SmmLegacyBoot notification. + // + Registration = NULL; + Status = Smst->SmmRegisterProtocolNotify ( + &gEdkiiSmmExitBootServicesProtocolGuid, + S3BootScriptSmmAtRuntimeCallBack, + &Registration + ); + ASSERT_EFI_ERROR (Status); + + Registration = NULL; + Status = Smst->SmmRegisterProtocolNotify ( + &gEdkiiSmmLegacyBootProtocolGuid, + S3BootScriptSmmAtRuntimeCallBack, + &Registration + ); + ASSERT_EFI_ERROR (Status); } mS3BootScriptTableSmmPtr = S3TableSmmPtr; // - // Then register event after lock + // Register SmmReadyToLock notification. // Registration = NULL; Status = Smst->SmmRegisterProtocolNotify ( @@ -401,14 +568,14 @@ S3BootScriptGetBootTimeEntryAddAddress ( S3TableBase = (EFI_PHYSICAL_ADDRESS)(UINTN)(mS3BootScriptTablePtr->TableBase); if (S3TableBase == 0) { + // // The table is not exist. This is the first to add entry. - // Allocate ACPI script table space under 4G memory. We need it to save - // some settings done by CSM, which runs after normal script table closed + // Allocate ACPI script table space under 4G memory. // S3TableBase = 0xffffffff; Status = gBS->AllocatePages ( AllocateMaxAddress, - EfiACPIMemoryNVS, + EfiReservedMemoryType, 2 + PcdGet16(PcdS3BootScriptRuntimeTableReservePageNumber), (EFI_PHYSICAL_ADDRESS*)&S3TableBase ); @@ -431,16 +598,16 @@ S3BootScriptGetBootTimeEntryAddAddress ( } // Here we do not count the reserved memory for runtime script table. - PageNumber = (UINT16)(mS3BootScriptTablePtr->TableMemoryPageNumber - PcdGet16(PcdS3BootScriptRuntimeTableReservePageNumber)); + PageNumber = (UINT16) (mS3BootScriptTablePtr->TableMemoryPageNumber - PcdGet16(PcdS3BootScriptRuntimeTableReservePageNumber)); TableLength = mS3BootScriptTablePtr->TableLength; - if ((UINT32)(PageNumber * EFI_PAGE_SIZE) < (TableLength + EntryLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE))) { + if ((UINTN) EFI_PAGES_TO_SIZE ((UINTN) PageNumber) < (UINTN) (TableLength + EntryLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE))) { // // The buffer is too small to hold the table, Reallocate the buffer // NewS3TableBase = 0xffffffff; Status = gBS->AllocatePages ( AllocateMaxAddress, - EfiACPIMemoryNVS, + EfiReservedMemoryType, 2 + PageNumber + PcdGet16(PcdS3BootScriptRuntimeTableReservePageNumber), (EFI_PHYSICAL_ADDRESS*)&NewS3TableBase ); @@ -476,12 +643,12 @@ S3BootScriptGetBootTimeEntryAddAddress ( return NewEntryPtr; } /** - To get the start address from which a new runtime s3 boot script entry will write into. + To get the start address from which a new runtime(after SmmReadyToLock) s3 boot script entry will write into. In this case, it should be ensured that there is enough buffer to hold the entry. @param EntryLength the new entry length. - @retval the address from which the a new s3 runtime script entry will write into + @retval the address from which the a new s3 runtime(after SmmReadyToLock) script entry will write into **/ UINT8* S3BootScriptGetRuntimeEntryAddAddress ( @@ -494,7 +661,7 @@ S3BootScriptGetRuntimeEntryAddAddress ( // // Check if the memory range reserved for S3 Boot Script table is large enough to hold the node. // - if (mS3BootScriptTablePtr->TableLength + EntryLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE) <= EFI_PAGES_TO_SIZE((UINT32)(mS3BootScriptTablePtr->TableMemoryPageNumber))) { + if ((UINTN) (mS3BootScriptTablePtr->TableLength + EntryLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE)) <= (UINTN) EFI_PAGES_TO_SIZE ((UINTN) (mS3BootScriptTablePtr->TableMemoryPageNumber))) { NewEntryPtr = mS3BootScriptTablePtr->TableBase + mS3BootScriptTablePtr->TableLength; mS3BootScriptTablePtr->TableLength = mS3BootScriptTablePtr->TableLength + EntryLength; // @@ -504,12 +671,53 @@ S3BootScriptGetRuntimeEntryAddAddress ( } return (UINT8*)NewEntryPtr; } + +/** + This function is to restore boot time boot script data from LockBox. + +**/ +VOID +RestoreBootTimeDataFromLockBox ( + VOID + ) +{ + EFI_STATUS Status; + UINTN LockBoxLength; + + // + // Restore boot time boot script data from LockBox. + // + LockBoxLength = mS3BootScriptTablePtr->BootTimeScriptLength; + Status = RestoreLockBox ( + &mBootScriptDataBootTimeGuid, + (VOID *) mS3BootScriptTablePtr->TableBase, + &LockBoxLength + ); + ASSERT_EFI_ERROR (Status); + + // + // Update the data to BootScriptData LockBox. + // + Status = UpdateLockBox ( + &mBootScriptDataGuid, + 0, + (VOID *) mS3BootScriptTablePtr->TableBase, + LockBoxLength + ); + ASSERT_EFI_ERROR (Status); + + // + // Update TableLength. + // + mS3BootScriptTablePtr->TableLength = (UINT32) (mS3BootScriptTablePtr->BootTimeScriptLength - sizeof (EFI_BOOT_SCRIPT_TERMINATE)); +} + /** To get the start address from which a new s3 boot script entry will write into. @param EntryLength the new entry length. - @retval the address from which the a new s3 runtime script entry will write into + @retval the address from which the a new s3 boot script entry will write into **/ UINT8* S3BootScriptGetEntryAddAddress ( @@ -517,78 +725,31 @@ S3BootScriptGetEntryAddAddress ( ) { UINT8* NewEntryPtr; - EFI_BOOT_SCRIPT_TABLE_HEADER TableHeader; - EFI_STATUS Status; - UINTN OrgLockBoxLength; - if (mS3BootScriptTablePtr->AtRuntime) { + if (mS3BootScriptTablePtr->SmmLocked) { // - // We need check InSmm when AtRuntime, because after SmmReadyToLock, only SMM driver is allowed to write boot script. + // We need check InSmm, because after SmmReadyToLock, only SMM driver is allowed to write boot script. // if (!mS3BootScriptTablePtr->InSmm) { // - // Add DEBUG ERROR, so that we can find it at boot time. - // Do not use ASSERT, because we may have test invoke this interface. + // Add DEBUG ERROR, so that we can find it after SmmReadyToLock. + // Do not use ASSERT, because we may have test to invoke this interface. // - DEBUG ((EFI_D_ERROR, "FATAL ERROR: Set boot script after ReadyToLock!!!\n")); + DEBUG ((EFI_D_ERROR, "FATAL ERROR: Set boot script outside SMM after SmmReadyToLock!!!\n")); return NULL; } - // - // NOTE: OS will restore ACPINvs data. After S3, the table length in mS3BootScriptTableSmmPtr (SMM) is different with - // table length in BootScriptTable header (ACPINvs). - // So here we need sync them. We choose ACPINvs table length, because we want to override the boot script saved - // in SMM every time. - // - ASSERT (mS3BootScriptTablePtr == mS3BootScriptTableSmmPtr); - CopyMem ((VOID*)&TableHeader, (VOID*)mS3BootScriptTablePtr->TableBase, sizeof(EFI_BOOT_SCRIPT_TABLE_HEADER)); - if (mS3BootScriptTablePtr->TableLength + sizeof(EFI_BOOT_SCRIPT_TERMINATE) != TableHeader.TableLength) { - // - // Restore it to use original value - // - OrgLockBoxLength = mLockBoxLength; - Status = RestoreLockBox ( - &mBootScriptDataOrgGuid, - (VOID *)mS3BootScriptTablePtr->TableBase, - &OrgLockBoxLength - ); - ASSERT_EFI_ERROR (Status); - ASSERT (OrgLockBoxLength == mLockBoxLength); - - // - // Update the current BootScriptData into LockBox as well - // - Status = UpdateLockBox ( - &mBootScriptDataGuid, - 0, - (VOID *)mS3BootScriptTablePtr->TableBase, - OrgLockBoxLength - ); - ASSERT_EFI_ERROR (Status); - + if (mS3BootScriptTablePtr->BackFromS3) { // - // NOTE: We should NOT use TableHeader.TableLength, because it is already updated to be whole length. + // Back from S3, restore boot time boot script data from LockBox + // and set BackFromS3 flag back to FALSE. // - mS3BootScriptTablePtr->TableLength = (UINT32)(mLockBoxLength - sizeof(EFI_BOOT_SCRIPT_TERMINATE)); + RestoreBootTimeDataFromLockBox (); + mS3BootScriptTablePtr->BackFromS3 = FALSE; } NewEntryPtr = S3BootScriptGetRuntimeEntryAddAddress (EntryLength); - - if (EntryLength != 0) { - // - // Now the length field is updated, need sync to lockbox. - // So in S3 resume, the data can be restored correctly. - // - CopyMem ((VOID*)&TableHeader, (VOID*)mS3BootScriptTablePtr->TableBase, sizeof(EFI_BOOT_SCRIPT_TABLE_HEADER)); - Status = UpdateLockBox ( - &mBootScriptDataGuid, - OFFSET_OF(EFI_BOOT_SCRIPT_TABLE_HEADER, TableLength), - &TableHeader.TableLength, - sizeof(TableHeader.TableLength) - ); - ASSERT_EFI_ERROR (Status); - } - } else { + } else { NewEntryPtr = S3BootScriptGetBootTimeEntryAddAddress (EntryLength); } return NewEntryPtr; @@ -607,17 +768,21 @@ SyncBootScript ( ) { EFI_STATUS Status; - UINTN ScriptOffset; + UINT32 ScriptOffset; + UINT32 TotalScriptLength; - ScriptOffset = (UINTN) (Script - mS3BootScriptTablePtr->TableBase); - - if (!mS3BootScriptTablePtr->AtRuntime || !mS3BootScriptTablePtr->InSmm || ScriptOffset >= mLockBoxLength) { + if (!mS3BootScriptTablePtr->SmmLocked || !mS3BootScriptTablePtr->InSmm) { // - // If it is not at runtime in SMM or in the range that needs to be synced in LockBox, just return. + // If it is not after SmmReadyToLock in SMM, + // just return. // return ; } + ScriptOffset = (UINT32) (Script - mS3BootScriptTablePtr->TableBase); + + TotalScriptLength = (UINT32) (mS3BootScriptTablePtr->TableLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE)); + // // Update BootScriptData // So in S3 resume, the data can be restored correctly. @@ -626,7 +791,19 @@ SyncBootScript ( &mBootScriptDataGuid, ScriptOffset, (VOID *)((UINTN)mS3BootScriptTablePtr->TableBase + ScriptOffset), - mLockBoxLength - ScriptOffset + TotalScriptLength - ScriptOffset + ); + ASSERT_EFI_ERROR (Status); + + // + // Now the length field is updated, need sync to lockbox. + // So at S3 resume, the data can be restored correctly. + // + Status = UpdateLockBox ( + &mBootScriptDataGuid, + OFFSET_OF (EFI_BOOT_SCRIPT_TABLE_HEADER, TableLength), + &TotalScriptLength, + sizeof (TotalScriptLength) ); ASSERT_EFI_ERROR (Status); } @@ -649,7 +826,7 @@ SyncBootScript ( for Framework Spec compatibility. If anyone does call CloseTable() on a real platform, then the caller is responsible for figuring out - how to get the script to run on an S3 resume because the boot script maintained by the lib will be + how to get the script to run at S3 resume because the boot script maintained by the lib will be destroyed. @return the base address of the new copy of the boot script table. diff --git a/MdeModulePkg/Library/PiDxeS3BootScriptLib/DxeS3BootScriptLib.inf b/MdeModulePkg/Library/PiDxeS3BootScriptLib/DxeS3BootScriptLib.inf index 3e12372be4b0..6b7540a5eab9 100644 --- a/MdeModulePkg/Library/PiDxeS3BootScriptLib/DxeS3BootScriptLib.inf +++ b/MdeModulePkg/Library/PiDxeS3BootScriptLib/DxeS3BootScriptLib.inf @@ -1,7 +1,7 @@ ## @file # DXE S3 boot script Library. # -# Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.
+# Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
# # This program and the accompanying materials are # licensed and made available under the terms and conditions of the BSD License @@ -59,6 +59,8 @@ gEfiSmmBase2ProtocolGuid ## SOMETIMES_CONSUMES gEfiDxeSmmReadyToLockProtocolGuid ## NOTIFY gEfiSmmReadyToLockProtocolGuid ## NOTIFY + gEdkiiSmmExitBootServicesProtocolGuid ## NOTIFY + gEdkiiSmmLegacyBootProtocolGuid ## NOTIFY [Pcd] ## CONSUMES diff --git a/MdeModulePkg/Library/PiDxeS3BootScriptLib/InternalBootScriptLib.h b/MdeModulePkg/Library/PiDxeS3BootScriptLib/InternalBootScriptLib.h index 3e2a0d2bacf5..e54027848346 100644 --- a/MdeModulePkg/Library/PiDxeS3BootScriptLib/InternalBootScriptLib.h +++ b/MdeModulePkg/Library/PiDxeS3BootScriptLib/InternalBootScriptLib.h @@ -2,7 +2,7 @@ Support for S3 boot script lib. This file defined some internal macro and internal data structure - Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.
+ Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include @@ -70,11 +72,14 @@ typedef union { // The boot script private data. // typedef struct { - UINT8 *TableBase; - UINT32 TableLength; // Record the actual memory length - UINT16 TableMemoryPageNumber; // Record the page number Allocated for the table - BOOLEAN AtRuntime; // Record if current state is after SmmReadyToLock - BOOLEAN InSmm; // Record if this library is in SMM. + UINT8 *TableBase; + UINT32 TableLength; // Record the actual memory length + UINT16 TableMemoryPageNumber; // Record the page number Allocated for the table + BOOLEAN InSmm; // Record if this library is in SMM. + BOOLEAN AtRuntime; // Record if current state is after SmmExitBootServices or SmmLegacyBoot. + UINT32 BootTimeScriptLength; // Maintain boot time script length in LockBox after SmmReadyToLock in SMM. + BOOLEAN SmmLocked; // Record if current state is after SmmReadyToLock + BOOLEAN BackFromS3; // Indicate that the system is back from S3. } SCRIPT_TABLE_PRIVATE_DATA; typedef diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec index 5c1d29a68afe..24d13f4e3916 100644 --- a/MdeModulePkg/MdeModulePkg.dec +++ b/MdeModulePkg/MdeModulePkg.dec @@ -1222,10 +1222,10 @@ # @Prompt SATA spin-up delay time in second for recovery path. gEfiMdeModulePkgTokenSpaceGuid.PcdSataSpinUpDelayInSecForRecoveryPath|15|UINT16|0x0001005B - ## This PCD is used to specify memory size with page number for a pre-allocated ACPI NVS memory to hold - # runtime created S3 boot script entries. The default page number is 2. When changing the value of this - # PCD, the platform developer should make sure the memory size is large enough to hold the S3 boot - # script node created in runtime phase. + ## This PCD is used to specify memory size with page number for a pre-allocated ACPI reserved memory + # to hold runtime(after SmmReadyToLock) created S3 boot script entries. The default page number is 2. + # When changing the value of this PCD, the platform developer should make sure the memory size is + # large enough to hold the S3 boot script node created in runtime(after SmmReadyToLock) phase. # @Prompt Reserved page number for S3 Boot Script Runtime Table. gEfiMdeModulePkgTokenSpaceGuid.PcdS3BootScriptRuntimeTableReservePageNumber|0x2|UINT16|0x0001005C diff --git a/MdeModulePkg/MdeModulePkg.uni b/MdeModulePkg/MdeModulePkg.uni index 9db6e58e165898f02e3dbad097d0fd84f3f8ea03..b1fd210d2b93664435762262a67efa34006061b1 100644 GIT binary patch delta 129 zcmaDehx^=I?uIRlHZ7Bv#0X7~kznMT9@N4pr>((|$dJZR!jQ^P#Gt?s%#aI&K|o$2 nLkdGBLkL4YgAWiVGh{PpZqILF+{;Lcj&|)f#_if|OpYD^llUJO delta 47 zcmX>%m;22e?uIRlHZ81v3}FnxlRxeko*vi2C^OxOiAiYtjuysMjO~4GjNAL#m>fI+ DvC Date: Tue, 15 Sep 2015 08:47:05 +0000 Subject: [PATCH 041/525] MdeModulePkg: Enhance PCI capability looking up logic to avoid hang Certain PCI device may have capability pointing to itself. Update LocateCapabilityRegBlock() to break when detecting such loop. (Sync patch r18473 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ruiyu Ni Reviewed-by: Feng Tian git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18475 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Bus/Pci/PciBusDxe/PciCommand.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciCommand.c b/MdeModulePkg/Bus/Pci/PciBusDxe/PciCommand.c index 8a8b4b8faca8..0bc1fbfefffe 100644 --- a/MdeModulePkg/Bus/Pci/PciBusDxe/PciCommand.c +++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciCommand.c @@ -173,6 +173,14 @@ LocateCapabilityRegBlock ( return EFI_SUCCESS; } + // + // Certain PCI device may incorrectly have capability pointing to itself, + // break to avoid dead loop. + // + if (CapabilityPtr == (UINT8) (CapabilityEntry >> 8)) { + break; + } + CapabilityPtr = (UINT8) (CapabilityEntry >> 8); } From 9f97f1253778216c41e9e4796333526669f24b0a Mon Sep 17 00:00:00 2001 From: Laszlo Ersek Date: Wed, 16 Sep 2015 02:55:23 +0000 Subject: [PATCH 042/525] MdeModulePkg: PcdSetNxForStack: enable dynamism Allow platforms to instantiate this PCD as PcdsDynamic and PcdsDynamicEx too, not just PcdsFixedAtBuild and PcdsPatchableInModule. (Sync patch r18468 from main trunk.) Cc: Star Zeng Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Laszlo Ersek Reviewed-by: Star Zeng Reviewed-by: Jordan Justen git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18477 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/MdeModulePkg.dec | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec index 24d13f4e3916..3dfcd6a77f64 100644 --- a/MdeModulePkg/MdeModulePkg.dec +++ b/MdeModulePkg/MdeModulePkg.dec @@ -969,15 +969,6 @@ # @Prompt Serial Port Register Stride in Bytes gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterStride|1|UINT32|0x0001006d - ## Indicates if to set NX for stack.

- # For the DxeIpl and the DxeCore are both X64, set NX for stack feature also require PcdDxeIplBuildPageTables be TRUE.
- # For the DxeIpl and the DxeCore are both IA32 (PcdDxeIplSwitchToLongMode is FALSE), set NX for stack feature also require - # IA32 PAE is supported and Execute Disable Bit is available.
- # TRUE - to set NX for stack.
- # FALSE - Not to set NX for stack.
- # @Prompt Set NX for stack. - gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack|FALSE|BOOLEAN|0x0001006f - ## This PCD to include the driver guid of VFR drivers for VarCheckHiiBin generation.

# Default is gZeroGuid that means no VFR driver will be parsed for VarCheckHiiBin generation.
# If it is set to an all FFs GUID, it means all modules in all FVs will be parsed for VarCheckHiiBin generation.
@@ -1373,6 +1364,15 @@ # @Prompt Default Creator Revision for ACPI table creation. gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorRevision|0x01000013|UINT32|0x30001038 + ## Indicates if to set NX for stack.

+ # For the DxeIpl and the DxeCore are both X64, set NX for stack feature also require PcdDxeIplBuildPageTables be TRUE.
+ # For the DxeIpl and the DxeCore are both IA32 (PcdDxeIplSwitchToLongMode is FALSE), set NX for stack feature also require + # IA32 PAE is supported and Execute Disable Bit is available.
+ # TRUE - to set NX for stack.
+ # FALSE - Not to set NX for stack.
+ # @Prompt Set NX for stack. + gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack|FALSE|BOOLEAN|0x0001006f + [PcdsPatchableInModule] ## Specify memory size with page number for PEI code when # Loading Module at Fixed Address feature is enabled. From a42b7ff22dd12b231bff598970888e8f91ffc6a1 Mon Sep 17 00:00:00 2001 From: Ruiyu Ni Date: Wed, 16 Sep 2015 08:16:16 +0000 Subject: [PATCH 043/525] Nt32Pkg: Fix PlatformBootManagerLib to respect PcdShellFile. Fix the code to use PcdShellFile instead of using hard code GUID which always points to new UEFI shell. (Sync patch r18478 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ruiyu Ni Reviewed-by: Eric Jin git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18479 6f19259b-4bc3-4df7-8a09-765794883524 --- Nt32Pkg/Library/PlatformBootManagerLib/PlatformBootManager.c | 5 +---- .../PlatformBootManagerLib/PlatformBootManagerLib.inf | 5 +++-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/Nt32Pkg/Library/PlatformBootManagerLib/PlatformBootManager.c b/Nt32Pkg/Library/PlatformBootManagerLib/PlatformBootManager.c index 3f634fcff981..e944105b3925 100644 --- a/Nt32Pkg/Library/PlatformBootManagerLib/PlatformBootManager.c +++ b/Nt32Pkg/Library/PlatformBootManagerLib/PlatformBootManager.c @@ -15,9 +15,6 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include "PlatformBootManager.h" - -EFI_GUID mUefiShellFileGuid = { 0x7C04A583, 0x9E3E, 0x4f1c, 0xAD, 0x65, 0xE0, 0x52, 0x68, 0xD0, 0xB4, 0xD1 }; - /** Perform the platform diagnostic, such like test memory. OEM/IBV also can customize this function to support specific platform diagnostic. @@ -220,7 +217,7 @@ PlatformBootManagerBeforeConsole ( // // Register UEFI Shell // - PlatformRegisterFvBootOption (&mUefiShellFileGuid, L"UEFI Shell", LOAD_OPTION_ACTIVE); + PlatformRegisterFvBootOption (PcdGetPtr (PcdShellFile), L"UEFI Shell", LOAD_OPTION_ACTIVE); } /** diff --git a/Nt32Pkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf b/Nt32Pkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf index d6175380583b..9b1eeaba02ed 100644 --- a/Nt32Pkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf +++ b/Nt32Pkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf @@ -65,9 +65,10 @@ [Pcd] gEfiMdePkgTokenSpaceGuid.PcdPlatformBootTimeOut + gEfiMdePkgTokenSpaceGuid.PcdUgaConsumeSupport gEfiMdeModulePkgTokenSpaceGuid.PcdConOutRow gEfiMdeModulePkgTokenSpaceGuid.PcdConOutColumn - gEfiMdePkgTokenSpaceGuid.PcdUgaConsumeSupport + gEfiMdeModulePkgTokenSpaceGuid.PcdConInConnectOnDemand gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdBootlogoOnlyEnable gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdLogoFile - gEfiMdeModulePkgTokenSpaceGuid.PcdConInConnectOnDemand + gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdShellFile From b2953a39cc17d49974ebbd66fb4449f326f323fc Mon Sep 17 00:00:00 2001 From: Samer El-Haj-Mahmoud Date: Wed, 16 Sep 2015 08:40:20 +0000 Subject: [PATCH 044/525] ShellPkg: Fix a command line unicode string type. (Sync patch r18480 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Samer El-Haj-Mahmoud Reviewed-by: Jaben Carsey Reviewed-by: Qiu Shumin git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18481 6f19259b-4bc3-4df7-8a09-765794883524 --- ShellPkg/Library/UefiShellDriver1CommandsLib/Reconnect.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ShellPkg/Library/UefiShellDriver1CommandsLib/Reconnect.c b/ShellPkg/Library/UefiShellDriver1CommandsLib/Reconnect.c index 092e2c974bcb..d2ae8e82719d 100644 --- a/ShellPkg/Library/UefiShellDriver1CommandsLib/Reconnect.c +++ b/ShellPkg/Library/UefiShellDriver1CommandsLib/Reconnect.c @@ -1,8 +1,9 @@ /** @file Main file for Reconnect shell Driver1 function. - (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.
+ (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
+ (C) Copyright 2015 Hewlett Packard Enterprise Development LP
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -75,7 +76,7 @@ ShellCommandRunReconnect ( Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE); if (EFI_ERROR(Status)) { if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { - ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDriver1HiiHandle, "reconnect", ProblemParam); + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDriver1HiiHandle, L"reconnect", ProblemParam); FreePool(ProblemParam); ShellStatus = SHELL_INVALID_PARAMETER; } else { From 3d4bfa3c396c5b6e10652b03ea13238d45bc4abb Mon Sep 17 00:00:00 2001 From: Fu Siyuan Date: Thu, 17 Sep 2015 00:54:45 +0000 Subject: [PATCH 045/525] NetworkPkg: Enhance the NULL pointer check before dereference it. This patch enhances the NULL pointer check of the HttpInstance->RemoteHost pointer before dereference it. (Sync patch r18482 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Fu Siyuan Reviewed-by: Ye Ting git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18485 6f19259b-4bc3-4df7-8a09-765794883524 --- NetworkPkg/HttpDxe/HttpImpl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/NetworkPkg/HttpDxe/HttpImpl.c b/NetworkPkg/HttpDxe/HttpImpl.c index 76c95b2bb66a..50c061743665 100644 --- a/NetworkPkg/HttpDxe/HttpImpl.c +++ b/NetworkPkg/HttpDxe/HttpImpl.c @@ -316,7 +316,7 @@ EfiHttpRequest ( Configure = TRUE; ReConfigure = TRUE; - if (HttpInstance->RemoteHost == NULL && HttpInstance->RemotePort == 0) { + if (HttpInstance->RemoteHost == NULL) { // // Request() is called the first time. // @@ -373,6 +373,7 @@ EfiHttpRequest ( if (HttpInstance->RemoteHost != NULL) { FreePool (HttpInstance->RemoteHost); HttpInstance->RemoteHost = NULL; + HttpInstance->RemotePort = 0; } } } From b175ea532fc48be3d926a6c1630138598904ad52 Mon Sep 17 00:00:00 2001 From: Fu Siyuan Date: Thu, 17 Sep 2015 00:55:10 +0000 Subject: [PATCH 046/525] NetworkPkg: TrafficDirection not saved in IPsecConfig. Fix a bug that the TrafficDirection field is not saved in IPsecConfig.SetData. (Sync patch r18483 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Fu Siyuan Reviewed-by: Ye Ting git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18486 6f19259b-4bc3-4df7-8a09-765794883524 --- NetworkPkg/IpSecDxe/IpSecConfigImpl.c | 14 ++++++++------ NetworkPkg/IpSecDxe/IpSecImpl.h | 1 + 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/NetworkPkg/IpSecDxe/IpSecConfigImpl.c b/NetworkPkg/IpSecDxe/IpSecConfigImpl.c index bd49245190bd..6aa47aababfe 100644 --- a/NetworkPkg/IpSecDxe/IpSecConfigImpl.c +++ b/NetworkPkg/IpSecDxe/IpSecConfigImpl.c @@ -1167,9 +1167,10 @@ SetSpdEntry ( SpdData->Name, sizeof (SpdData->Name) ); - SpdEntry->Data->PackageFlag = SpdData->PackageFlag; - SpdEntry->Data->Action = SpdData->Action; - + SpdEntry->Data->PackageFlag = SpdData->PackageFlag; + SpdEntry->Data->TrafficDirection = SpdData->TrafficDirection; + SpdEntry->Data->Action = SpdData->Action; + // // Fix the address of ProcessingPolicy and copy it if need, which is continous // memory and close to the base structure of SAD data. @@ -1690,9 +1691,10 @@ GetSpdEntry ( // CopyMem (SpdData->Name, SpdEntry->Data->Name, sizeof (SpdData->Name)); - SpdData->PackageFlag = SpdEntry->Data->PackageFlag; - SpdData->Action = SpdEntry->Data->Action; - + SpdData->PackageFlag = SpdEntry->Data->PackageFlag; + SpdData->TrafficDirection = SpdEntry->Data->TrafficDirection; + SpdData->Action = SpdEntry->Data->Action; + if (SpdData->Action != EfiIPsecActionProtect) { SpdData->ProcessingPolicy = NULL; } else { diff --git a/NetworkPkg/IpSecDxe/IpSecImpl.h b/NetworkPkg/IpSecDxe/IpSecImpl.h index 8b63d24b5200..89597bdc807b 100644 --- a/NetworkPkg/IpSecDxe/IpSecImpl.h +++ b/NetworkPkg/IpSecDxe/IpSecImpl.h @@ -76,6 +76,7 @@ typedef struct _EFI_ESP_TAIL { struct _IPSEC_SPD_DATA { CHAR16 Name[100]; UINT32 PackageFlag; + EFI_IPSEC_TRAFFIC_DIR TrafficDirection; EFI_IPSEC_ACTION Action; EFI_IPSEC_PROCESS_POLICY *ProcessingPolicy; LIST_ENTRY Sas; From 0fb361d8281b4b5cf919c7fbbd3b5f72f6403990 Mon Sep 17 00:00:00 2001 From: Jiaxin Wu Date: Thu, 17 Sep 2015 00:55:32 +0000 Subject: [PATCH 047/525] NetworkPkg: Fix connection issue after correct SPD and re-enable IPsec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch is used to fix connection failure issue after correct the SPD and re-enable IPsec. The driver should not update the SadEntry's SpdSelector when doing SpdEntry modification. SadEntry's SpdSelector may not equal to this edited SpdEntry’s Selector. (Sync patch r18484 from main trunk.) Cc: Ye Ting Cc: Fu Siyuan Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiaxin Wu Reviewed-by: Ye Ting Reviewed-by: Fu Siyuan git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18487 6f19259b-4bc3-4df7-8a09-765794883524 --- NetworkPkg/IpSecDxe/IpSecConfigImpl.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/NetworkPkg/IpSecDxe/IpSecConfigImpl.c b/NetworkPkg/IpSecDxe/IpSecConfigImpl.c index 6aa47aababfe..8c7724c7da80 100644 --- a/NetworkPkg/IpSecDxe/IpSecConfigImpl.c +++ b/NetworkPkg/IpSecDxe/IpSecConfigImpl.c @@ -1204,12 +1204,7 @@ SetSpdEntry ( RemoveEntryList (&SadEntry->BySpd); } InsertTailList (&SpdEntry->Data->Sas, &SadEntry->BySpd); - SadEntry->Data->SpdEntry = SpdEntry; - DuplicateSpdSelector ( - (EFI_IPSEC_CONFIG_SELECTOR *)SadEntry->Data->SpdSelector, - (EFI_IPSEC_CONFIG_SELECTOR *)SpdEntry->Selector, - NULL - ); + SadEntry->Data->SpdEntry = SpdEntry; } } } From 1e15a0e60edae01782782ea3b5012c7032a660b2 Mon Sep 17 00:00:00 2001 From: Eric Dong Date: Thu, 17 Sep 2015 02:11:22 +0000 Subject: [PATCH 048/525] MdeModulePkg/HiiDatabase: Fix Progress not point to the correct place issue. (Sync patch r18488 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Eric Dong Reviewed-by: Liming Gao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18492 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Universal/HiiDatabaseDxe/ConfigKeywordHandler.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigKeywordHandler.c b/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigKeywordHandler.c index e88a0c45975f..ccd6f820c68e 100644 --- a/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigKeywordHandler.c +++ b/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigKeywordHandler.c @@ -2979,6 +2979,8 @@ EfiConfigKeywordHandlerSetData ( *ProgressErr = KEYWORD_HANDLER_NO_ERROR; Done: + *Progress = KeywordString + (StringPtr - TempString); + ASSERT (TempString != NULL); FreePool (TempString); if (NameSpace != NULL) { @@ -2998,8 +3000,8 @@ EfiConfigKeywordHandlerSetData ( } if (MultiConfigResp != NULL && MultiConfigResp != ConfigResp) { FreePool (MultiConfigResp); - } - *Progress = StringPtr; + } + return Status; } @@ -3271,6 +3273,8 @@ EfiConfigKeywordHandlerGetData ( *ProgressErr = KEYWORD_HANDLER_NO_ERROR; Done: + *Progress = KeywordString + (StringPtr - TempString); + if (TempString != NULL) { FreePool (TempString); } @@ -3283,6 +3287,6 @@ EfiConfigKeywordHandlerGetData ( if (KeywordData != NULL) { FreePool (KeywordData); } - *Progress = StringPtr; + return Status; } From 0c9da39b512058153731ba35542ee781f33f5477 Mon Sep 17 00:00:00 2001 From: Eric Dong Date: Thu, 17 Sep 2015 02:11:53 +0000 Subject: [PATCH 049/525] MdeModulePkg/HiiDatabase: Refine KeywordHandlerProtocol->GetData(). Update this function to follow UEFI spec requirement. (Sync patch r18489 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Eric Dong Reviewed-by: Liming Gao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18493 6f19259b-4bc3-4df7-8a09-765794883524 --- .../HiiDatabaseDxe/ConfigKeywordHandler.c | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigKeywordHandler.c b/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigKeywordHandler.c index ccd6f820c68e..b97866968714 100644 --- a/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigKeywordHandler.c +++ b/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigKeywordHandler.c @@ -1340,8 +1340,7 @@ GetStringIdFromRecord ( if (AsciiStrnCmp(Name, StringPackage->StringPkgHdr->Language, AsciiStrLen (Name)) == 0) { Status = GetStringIdFromString (StringPackage, KeywordValue, StringId); if (EFI_ERROR (Status)) { - RetVal = KEYWORD_HANDLER_KEYWORD_NOT_FOUND; - continue; + return KEYWORD_HANDLER_KEYWORD_NOT_FOUND; } else { if (*NameSpace == NULL) { *NameSpace = AllocateCopyPool (AsciiStrSize (StringPackage->StringPkgHdr->Language), StringPackage->StringPkgHdr->Language); @@ -2556,6 +2555,7 @@ MergeToMultiKeywordResp ( @param NameSpace The namespace used to search the string. @param MultiResp Return the MultiKeywordResp string for the system. + @param ProgressErr Return the error status. @retval EFI_OUT_OF_RESOURCES The memory can't be allocated. @retval EFI_SUCCESS Generate the MultiKeywordResp string. @@ -2565,7 +2565,8 @@ MergeToMultiKeywordResp ( EFI_STATUS EnumerateAllKeywords ( IN CHAR8 *NameSpace, - OUT EFI_STRING *MultiResp + OUT EFI_STRING *MultiResp, + OUT UINT32 *ProgressErr ) { LIST_ENTRY *Link; @@ -2585,6 +2586,7 @@ EnumerateAllKeywords ( CHAR16 *MultiKeywordResp; CHAR16 *KeywordData; BOOLEAN ReadOnly; + BOOLEAN FindKeywordPackages; DataBaseRecord = NULL; Status = EFI_SUCCESS; @@ -2594,6 +2596,7 @@ EnumerateAllKeywords ( ConfigRequest = NULL; ValueElement = NULL; KeywordResp = NULL; + FindKeywordPackages = FALSE; if (NameSpace == NULL) { NameSpace = UEFI_CONFIG_LANG; @@ -2616,6 +2619,7 @@ EnumerateAllKeywords ( // Check whether has keyword string package. // if (AsciiStrnCmp(NameSpace, StringPackage->StringPkgHdr->Language, AsciiStrLen (NameSpace)) == 0) { + FindKeywordPackages = TRUE; // // Keep the NameSpace string. // @@ -2718,6 +2722,11 @@ EnumerateAllKeywords ( // if (MultiKeywordResp == NULL) { Status = EFI_NOT_FOUND; + if (!FindKeywordPackages) { + *ProgressErr = KEYWORD_HANDLER_NAMESPACE_ID_NOT_FOUND; + } else { + *ProgressErr = KEYWORD_HANDLER_KEYWORD_NOT_FOUND; + } } else { Status = EFI_SUCCESS; } @@ -2857,7 +2866,7 @@ EfiConfigKeywordHandlerSetData ( // 1.1 Check whether the input namespace is valid. // if (AsciiStrnCmp(NameSpace, UEFI_CONFIG_LANG, AsciiStrLen (UEFI_CONFIG_LANG)) != 0) { - *ProgressErr = KEYWORD_HANDLER_UNDEFINED_PROCESSING_ERROR; + *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING; Status = EFI_INVALID_PARAMETER; goto Done; } @@ -3133,7 +3142,7 @@ EfiConfigKeywordHandlerGetData ( TempString = NULL; } if (EFI_ERROR (Status)) { - *ProgressErr = KEYWORD_HANDLER_NAMESPACE_ID_NOT_FOUND; + *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING; return Status; } // @@ -3141,7 +3150,7 @@ EfiConfigKeywordHandlerGetData ( // if (NameSpace != NULL){ if (AsciiStrnCmp(NameSpace, UEFI_CONFIG_LANG, AsciiStrLen (UEFI_CONFIG_LANG)) != 0) { - *ProgressErr = KEYWORD_HANDLER_UNDEFINED_PROCESSING_ERROR; + *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING; return EFI_INVALID_PARAMETER; } } @@ -3263,7 +3272,7 @@ EfiConfigKeywordHandlerGetData ( // // Enumerate all keyword in the system. // - Status = EnumerateAllKeywords(NameSpace, &MultiKeywordResp); + Status = EnumerateAllKeywords(NameSpace, &MultiKeywordResp, ProgressErr); if (EFI_ERROR (Status)) { goto Done; } From 873ad3b80c39a28895ec1550f4b39e0c3fcd0907 Mon Sep 17 00:00:00 2001 From: Eric Dong Date: Thu, 17 Sep 2015 02:17:53 +0000 Subject: [PATCH 050/525] MdeModulePkg/HiiDatabase: Refine KeywordHandlerProtocol->SetData(). Update this function to follow UEFI spec requirement. (Sync patch r18490 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Eric Dong Reviewed-by: Liming Gao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18494 6f19259b-4bc3-4df7-8a09-765794883524 --- .../HiiDatabaseDxe/ConfigKeywordHandler.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigKeywordHandler.c b/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigKeywordHandler.c index b97866968714..6923d6c47316 100644 --- a/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigKeywordHandler.c +++ b/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigKeywordHandler.c @@ -2829,6 +2829,7 @@ EfiConfigKeywordHandlerSetData ( BOOLEAN ReadOnly; EFI_STRING InternalProgress; CHAR16 *TempString; + CHAR16 *KeywordStartPos; if (This == NULL || Progress == NULL || ProgressErr == NULL || KeywordString == NULL) { return EFI_INVALID_PARAMETER; @@ -2843,6 +2844,7 @@ EfiConfigKeywordHandlerSetData ( KeywordData = NULL; ValueElement = NULL; ConfigResp = NULL; + KeywordStartPos = NULL; KeywordStringId = 0; // @@ -2886,6 +2888,7 @@ EfiConfigKeywordHandlerSetData ( // // 3. Extract keyword from the KeywordRequest string. // + KeywordStartPos = StringPtr; Status = ExtractKeyword(StringPtr, &KeywordData, &NextStringPtr); if (EFI_ERROR (Status)) { // @@ -2942,8 +2945,8 @@ EfiConfigKeywordHandlerSetData ( // 8. Check the readonly flag. // if (ExtractReadOnlyFromOpCode (OpCode) != ReadOnly) { - *ProgressErr = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED; - Status = EFI_INVALID_PARAMETER; + *ProgressErr = KEYWORD_HANDLER_ACCESS_NOT_PERMITTED; + Status = EFI_ACCESS_DENIED; goto Done; } @@ -2970,6 +2973,7 @@ EfiConfigKeywordHandlerSetData ( FreePool (ConfigResp); ConfigResp = NULL; } + KeywordStartPos = NULL; } // @@ -2988,7 +2992,11 @@ EfiConfigKeywordHandlerSetData ( *ProgressErr = KEYWORD_HANDLER_NO_ERROR; Done: - *Progress = KeywordString + (StringPtr - TempString); + if (KeywordStartPos != NULL) { + *Progress = KeywordString + (KeywordStartPos - TempString); + } else { + *Progress = KeywordString + (StringPtr - TempString); + } ASSERT (TempString != NULL); FreePool (TempString); @@ -3010,7 +3018,7 @@ EfiConfigKeywordHandlerSetData ( if (MultiConfigResp != NULL && MultiConfigResp != ConfigResp) { FreePool (MultiConfigResp); } - + return Status; } From 43f4250c100629e13cd1692a8c36989c0a18b5e5 Mon Sep 17 00:00:00 2001 From: Jeff Fan Date: Thu, 17 Sep 2015 05:33:07 +0000 Subject: [PATCH 051/525] MdePkg/SmmServicesTableLib: Return TRUE in InSmm () SmmServicesTableLib instance only supports DXE_SMM_DRIVER type drivers that will be loaded into SMM range. InSmm() could return TRUE directly. (Sync patch r18495 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan Reviewed-by: Jiewen Yao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18496 6f19259b-4bc3-4df7-8a09-765794883524 --- .../SmmServicesTableLib/SmmServicesTableLib.c | 30 ++++++------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/MdePkg/Library/SmmServicesTableLib/SmmServicesTableLib.c b/MdePkg/Library/SmmServicesTableLib/SmmServicesTableLib.c index 23a85a0c68e5..81e5ce8e3f4e 100644 --- a/MdePkg/Library/SmmServicesTableLib/SmmServicesTableLib.c +++ b/MdePkg/Library/SmmServicesTableLib/SmmServicesTableLib.c @@ -1,7 +1,7 @@ /** @file SMM Services Table Library. - Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+ Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -18,7 +18,6 @@ #include EFI_SMM_SYSTEM_TABLE2 *gSmst = NULL; -EFI_SMM_BASE2_PROTOCOL *mInternalSmmBase2 = NULL; /** The constructor function caches the pointer of SMM Services Table. @@ -36,8 +35,10 @@ SmmServicesTableLibConstructor ( IN EFI_SYSTEM_TABLE *SystemTable ) { - EFI_STATUS Status; + EFI_STATUS Status; + EFI_SMM_BASE2_PROTOCOL *InternalSmmBase2; + InternalSmmBase2 = NULL; // // Retrieve SMM Base2 Protocol, Do not use gBS from UefiBootServicesTableLib on purpose // to prevent inclusion of gBS, gST, and gImageHandle from SMM Drivers unless the @@ -46,25 +47,15 @@ SmmServicesTableLibConstructor ( Status = SystemTable->BootServices->LocateProtocol ( &gEfiSmmBase2ProtocolGuid, NULL, - (VOID **)&mInternalSmmBase2 + (VOID **)&InternalSmmBase2 ); ASSERT_EFI_ERROR (Status); - ASSERT (mInternalSmmBase2 != NULL); - - // - // Check to see if we are already in SMM - // - if (!InSmm ()) { - // - // We are not in SMM, so SMST is not needed - // - return EFI_SUCCESS; - } + ASSERT (InternalSmmBase2 != NULL); // // We are in SMM, retrieve the pointer to SMM System Table // - mInternalSmmBase2->GetSmstLocation (mInternalSmmBase2, &gSmst); + InternalSmmBase2->GetSmstLocation (InternalSmmBase2, &gSmst); ASSERT (gSmst != NULL); return EFI_SUCCESS; @@ -87,11 +78,8 @@ InSmm ( VOID ) { - BOOLEAN InSmm; - // - // Check to see if we are already in SMM + // We are already in SMM // - mInternalSmmBase2->InSmm (mInternalSmmBase2, &InSmm); - return InSmm; + return TRUE; } From b523178555ad499ccd223b88258ec48f899edbad Mon Sep 17 00:00:00 2001 From: Dandan Bi Date: Thu, 17 Sep 2015 07:37:44 +0000 Subject: [PATCH 052/525] MdeModulePkg:Fix the bug the incorrect change of StrCpyS function The pointer to the destination string changed,the max length also changed.Previous change neglect this point. And base on the code logic,we can use StrCatS to replace StrCpyS.Now this patch is to fix this bug. (Sync patch r18497 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Dandan Bi Reviewed-by: Eric Dong git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18498 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Library/UefiHiiLib/HiiLib.c | 4 +- .../HiiDatabaseDxe/ConfigKeywordHandler.c | 65 ++++++------------- 2 files changed, 23 insertions(+), 46 deletions(-) diff --git a/MdeModulePkg/Library/UefiHiiLib/HiiLib.c b/MdeModulePkg/Library/UefiHiiLib/HiiLib.c index bee5e0d22cfa..66d72acf2755 100644 --- a/MdeModulePkg/Library/UefiHiiLib/HiiLib.c +++ b/MdeModulePkg/Library/UefiHiiLib/HiiLib.c @@ -662,7 +662,7 @@ HiiConstructConfigHdr ( // // Append L"&NAME=" // - StrCpyS (String, MaxLen, L"&NAME="); + StrCatS (ReturnString, MaxLen, L"&NAME="); String += StrLen (String); if (Name != NULL) { @@ -677,7 +677,7 @@ HiiConstructConfigHdr ( // // Append L"&PATH=" // - StrCpyS (String, MaxLen, L"&PATH="); + StrCatS (ReturnString, MaxLen, L"&PATH="); String += StrLen (String); // diff --git a/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigKeywordHandler.c b/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigKeywordHandler.c index 6923d6c47316..52aa4d8bcf0b 100644 --- a/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigKeywordHandler.c +++ b/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigKeywordHandler.c @@ -1758,7 +1758,7 @@ ConstructConfigHdr ( // // Append L"&NAME=" // - StrCpyS (String, MaxLen, L"&NAME="); + StrCatS (ReturnString, MaxLen, L"&NAME="); String += StrLen (String); if (Name != NULL) { @@ -1773,7 +1773,7 @@ ConstructConfigHdr ( // // Append L"&PATH=" // - StrCpyS (String, MaxLen, L"&PATH="); + StrCatS (ReturnString, MaxLen, L"&PATH="); String += StrLen (String); // @@ -2044,14 +2044,10 @@ ExtractConfigRequest ( StringPtr = *ConfigRequest; StrCpyS (StringPtr, MaxLen, ConfigHdr); - StringPtr += StrLen (StringPtr); - *StringPtr = L'&'; - StringPtr++; + StrCatS (StringPtr, MaxLen, L"&"); - StrCpyS (StringPtr, MaxLen, RequestElement); - StringPtr += StrLen (StringPtr); - *StringPtr = L'\0'; + StrCatS (StringPtr, MaxLen, RequestElement); FreePool (ConfigHdr); FreePool (RequestElement); @@ -2152,23 +2148,17 @@ ExtractConfigResp ( StringPtr = *ConfigResp; StrCpyS (StringPtr, MaxLen, ConfigHdr); - StringPtr += StrLen (StringPtr); - *StringPtr = L'&'; - StringPtr++; + StrCatS (StringPtr, MaxLen, L"&"); - StrCpyS (StringPtr, MaxLen, RequestElement); - StringPtr += StrLen (StringPtr); - - *StringPtr = L'&'; - StringPtr++; - StrCpyS (StringPtr, MaxLen, L"VALUE="); - StringPtr += StrLen (StringPtr); + StrCatS (StringPtr, MaxLen, RequestElement); + + StrCatS (StringPtr, MaxLen, L"&"); + + StrCatS (StringPtr, MaxLen, L"VALUE="); - StrCpyS (StringPtr, MaxLen, ValueElement); - StringPtr += StrLen (StringPtr); - *StringPtr = L'\0'; + StrCatS (StringPtr, MaxLen, ValueElement); FreePool (ConfigHdr); FreePool (RequestElement); @@ -2452,43 +2442,33 @@ GenerateKeywordResp ( // 2.1 Copy NameSpaceId section. // StrCpyS (RespStr, RespStrLen, L"NAMESPACE="); - RespStr += StrLen (RespStr); - StrCpyS (RespStr, RespStrLen, UnicodeNameSpace); - RespStr += StrLen (RespStr); + + StrCatS (RespStr, RespStrLen, UnicodeNameSpace); // // 2.2 Copy PathHdr section. // - StrCpyS (RespStr, RespStrLen, PathHdr); - RespStr += StrLen (RespStr); + StrCatS (RespStr, RespStrLen, PathHdr); // // 2.3 Copy Keyword section. // - StrCpyS (RespStr, RespStrLen, L"KEYWORD="); - RespStr += StrLen (RespStr); - StrCpyS (RespStr, RespStrLen, KeywordData); - RespStr += StrLen (RespStr); + StrCatS (RespStr, RespStrLen, L"KEYWORD="); + + StrCatS (RespStr, RespStrLen, KeywordData); // // 2.4 Copy the Value section. // - StrCpyS (RespStr, RespStrLen, ValueStr); - RespStr += StrLen (RespStr); + StrCatS (RespStr, RespStrLen, ValueStr); // // 2.5 Copy ReadOnly section if exist. // if (ReadOnly) { - StrCpyS (RespStr, RespStrLen, L"&READONLY"); - RespStr += StrLen (RespStr); + StrCatS (RespStr, RespStrLen, L"&READONLY"); } - // - // 2.6 Add the end. - // - *RespStr = L'\0'; - if (UnicodeNameSpace != NULL) { FreePool (UnicodeNameSpace); } @@ -2536,12 +2516,9 @@ MergeToMultiKeywordResp ( FreePool (*MultiKeywordResp); *MultiKeywordResp = StringPtr; - StringPtr += StrLen (StringPtr); - - *StringPtr = L'&'; - StringPtr++; + StrCatS (StringPtr, MultiKeywordRespLen / sizeof (CHAR16), L"&"); - StrCpyS (StringPtr, MultiKeywordRespLen / sizeof (CHAR16), *KeywordResp); + StrCatS (StringPtr, MultiKeywordRespLen / sizeof (CHAR16), *KeywordResp); return EFI_SUCCESS; } From ef89277916d65046c9853e23aaf7db67ab34956f Mon Sep 17 00:00:00 2001 From: Yang Jadis Date: Fri, 18 Sep 2015 01:18:34 +0000 Subject: [PATCH 053/525] ShellPkg: Fix Shell fail when execute command in ShellProtocol.Execute(). When execute a command with tailing blank spaces in ShellProtocol.Execute() Shell will fail. This patch move the TrimSpaces operation into ParseCommandLineToArgs function to fix the problem. (Sync patch r18491 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Yang Jadis Signed-off-by: Qiu Shumin Reviewed-by: Jaben Carsey git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18501 6f19259b-4bc3-4df7-8a09-765794883524 --- ShellPkg/Application/Shell/ShellParametersProtocol.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ShellPkg/Application/Shell/ShellParametersProtocol.c b/ShellPkg/Application/Shell/ShellParametersProtocol.c index bc19df7e931e..b40498734044 100644 --- a/ShellPkg/Application/Shell/ShellParametersProtocol.c +++ b/ShellPkg/Application/Shell/ShellParametersProtocol.c @@ -206,6 +206,7 @@ ParseCommandLineToArgs( return (EFI_SUCCESS); } + TrimSpaces(&(CHAR16*)CommandLine); Size = StrSize(CommandLine); TempParameter = AllocateZeroPool(Size); if (TempParameter == NULL) { @@ -359,7 +360,6 @@ CreatePopulateInstallShellParametersProtocol ( // // Populate Argc and Argv // - TrimSpaces (&FullCommandLine); Status = ParseCommandLineToArgs(FullCommandLine, &(*NewShellParameters)->Argv, &(*NewShellParameters)->Argc); From 3465020defae51cb5af69a6f65a2c3de8e06e08e Mon Sep 17 00:00:00 2001 From: Qiu Shumin Date: Fri, 18 Sep 2015 01:19:00 +0000 Subject: [PATCH 054/525] ShellPkg: Fix GCC build fail and code refine. 1. Fix GCC build fail. 2. It's not correct to cast away constness to allow TrimSpaces() to modify 'commandline'. This patch makes a copy of 'commandLine' and work with that in the remainder of the function. (Sync patch r18500 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Qiu Shumin Reviewed-by: Ard Biesheuvel git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18502 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Shell/ShellParametersProtocol.c | 34 +++++++++++++------ 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/ShellPkg/Application/Shell/ShellParametersProtocol.c b/ShellPkg/Application/Shell/ShellParametersProtocol.c index b40498734044..bbe026b644b2 100644 --- a/ShellPkg/Application/Shell/ShellParametersProtocol.c +++ b/ShellPkg/Application/Shell/ShellParametersProtocol.c @@ -195,7 +195,9 @@ ParseCommandLineToArgs( CHAR16 *TempParameter; CHAR16 *Walker; CHAR16 *NewParam; + CHAR16 *NewCommandLine; UINTN Size; + EFI_STATUS Status; ASSERT(Argc != NULL); ASSERT(Argv != NULL); @@ -206,15 +208,21 @@ ParseCommandLineToArgs( return (EFI_SUCCESS); } - TrimSpaces(&(CHAR16*)CommandLine); - Size = StrSize(CommandLine); + NewCommandLine = AllocateCopyPool(StrSize(CommandLine), CommandLine); + if (NewCommandLine == NULL){ + return (EFI_OUT_OF_RESOURCES); + } + + TrimSpaces(&NewCommandLine); + Size = StrSize(NewCommandLine); TempParameter = AllocateZeroPool(Size); if (TempParameter == NULL) { + SHELL_FREE_NON_NULL(NewCommandLine); return (EFI_OUT_OF_RESOURCES); } for ( Count = 0 - , Walker = (CHAR16*)CommandLine + , Walker = (CHAR16*)NewCommandLine ; Walker != NULL && *Walker != CHAR_NULL ; Count++ ) { @@ -228,30 +236,34 @@ ParseCommandLineToArgs( // (*Argv) = AllocateZeroPool((Count)*sizeof(CHAR16*)); if (*Argv == NULL) { - SHELL_FREE_NON_NULL(TempParameter); - return (EFI_OUT_OF_RESOURCES); + Status = EFI_OUT_OF_RESOURCES; + goto Done; } *Argc = 0; - Walker = (CHAR16*)CommandLine; + Walker = (CHAR16*)NewCommandLine; while(Walker != NULL && *Walker != CHAR_NULL) { SetMem16(TempParameter, Size, CHAR_NULL); if (EFI_ERROR(GetNextParameter(&Walker, &TempParameter, Size))) { - SHELL_FREE_NON_NULL(TempParameter); - return (EFI_INVALID_PARAMETER); + Status = EFI_INVALID_PARAMETER; + goto Done; } NewParam = AllocateCopyPool(StrSize(TempParameter), TempParameter); if (NewParam == NULL){ - SHELL_FREE_NON_NULL(TempParameter); - return (EFI_OUT_OF_RESOURCES); + Status = EFI_OUT_OF_RESOURCES; + goto Done; } ((CHAR16**)(*Argv))[(*Argc)] = NewParam; (*Argc)++; } ASSERT(Count >= (*Argc)); + Status = EFI_SUCCESS; + +Done: SHELL_FREE_NON_NULL(TempParameter); - return (EFI_SUCCESS); + SHELL_FREE_NON_NULL(NewCommandLine); + return (Status); } /** From b2024e34bef646cd76f8cc251f58dabf38ba21d8 Mon Sep 17 00:00:00 2001 From: Star Zeng Date: Fri, 18 Sep 2015 02:33:47 +0000 Subject: [PATCH 055/525] MdeModulePkg DxeCore: Relocate HOB List after other tested memory resources added The HOB List relocation should be at after all the tested memory resources added (except the memory space that covers HOB List) to the memory services, because the memory resource found in CoreInitializeMemoryServices() may have not enough remaining resource for HOB List. And the memory space that covers HOB List should be processed after HOB List relocation to avoid the resources allocated by others to corrupt HOB List before its relocation. (Sync patch r18499 from main trunk.) Cc: Jiewen Yao Cc: Liming Gao Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Star Zeng Reviewed-by: Jiewen Yao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18504 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Core/Dxe/Gcd/Gcd.c | 65 +++++++++++++++++++++++++++------ 1 file changed, 53 insertions(+), 12 deletions(-) diff --git a/MdeModulePkg/Core/Dxe/Gcd/Gcd.c b/MdeModulePkg/Core/Dxe/Gcd/Gcd.c index a50fda2466da..77586a9ac8f3 100644 --- a/MdeModulePkg/Core/Dxe/Gcd/Gcd.c +++ b/MdeModulePkg/Core/Dxe/Gcd/Gcd.c @@ -2311,6 +2311,7 @@ CoreInitializeGcdServices ( UINTN Index; UINT64 Capabilities; EFI_HOB_CPU * CpuHob; + EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMapHobList; // // Cache the PHIT HOB for later use @@ -2493,24 +2494,13 @@ CoreInitializeGcdServices ( } } - // - // Relocate HOB List to an allocated pool buffer. - // - NewHobList = AllocateCopyPool ( - (UINTN)PhitHob->EfiFreeMemoryBottom - (UINTN)(*HobStart), - *HobStart - ); - ASSERT (NewHobList != NULL); - - *HobStart = NewHobList; - gHobList = NewHobList; - // // Add and allocate the remaining unallocated system memory to the memory services. // Status = CoreGetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap); ASSERT (Status == EFI_SUCCESS); + MemorySpaceMapHobList = NULL; for (Index = 0; Index < NumberOfDescriptors; Index++) { if ((MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeSystemMemory) || (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeMoreReliable)) { @@ -2520,6 +2510,16 @@ CoreInitializeGcdServices ( if (Length == 0 || MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length < BaseAddress) { continue; } + if (((UINTN) MemorySpaceMap[Index].BaseAddress <= (UINTN) (*HobStart)) && + ((UINTN) (MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length) >= (UINTN) PhitHob->EfiFreeMemoryBottom)) { + // + // Skip the memory space that covers HOB List, it should be processed + // after HOB List relocation to avoid the resources allocated by others + // to corrupt HOB List before its relocation. + // + MemorySpaceMapHobList = &MemorySpaceMap[Index]; + continue; + } CoreAddMemoryDescriptor ( EfiConventionalMemory, BaseAddress, @@ -2538,6 +2538,47 @@ CoreInitializeGcdServices ( } } } + + // + // Relocate HOB List to an allocated pool buffer. + // The relocation should be at after all the tested memory resources added + // (except the memory space that covers HOB List) to the memory services, + // because the memory resource found in CoreInitializeMemoryServices() + // may have not enough remaining resource for HOB List. + // + NewHobList = AllocateCopyPool ( + (UINTN) PhitHob->EfiFreeMemoryBottom - (UINTN) (*HobStart), + *HobStart + ); + ASSERT (NewHobList != NULL); + + *HobStart = NewHobList; + gHobList = NewHobList; + + if (MemorySpaceMapHobList != NULL) { + // + // Add and allocate the memory space that covers HOB List to the memory services + // after HOB List relocation. + // + BaseAddress = PageAlignAddress (MemorySpaceMapHobList->BaseAddress); + Length = PageAlignLength (MemorySpaceMapHobList->BaseAddress + MemorySpaceMapHobList->Length - BaseAddress); + CoreAddMemoryDescriptor ( + EfiConventionalMemory, + BaseAddress, + RShiftU64 (Length, EFI_PAGE_SHIFT), + MemorySpaceMapHobList->Capabilities & (~EFI_MEMORY_RUNTIME) + ); + Status = CoreAllocateMemorySpace ( + EfiGcdAllocateAddress, + MemorySpaceMapHobList->GcdMemoryType, + 0, + Length, + &BaseAddress, + gDxeCoreImageHandle, + NULL + ); + } + CoreFreePool (MemorySpaceMap); return EFI_SUCCESS; From 8c5f576fe1dbac6ad49bda3c17912321d0d1fff9 Mon Sep 17 00:00:00 2001 From: Star Zeng Date: Fri, 18 Sep 2015 02:35:23 +0000 Subject: [PATCH 056/525] MdeModulePkg DxeCore: Take the range in resource HOB for PHIT as higher priority Take the range in the resource descriptor HOB for the memory region described by the PHIT as higher priority if it is big enough. It can make the memory bin allocated to be at the same memory region with PHIT that has more better compatibility to avoid memory fragmentation for some code practices assume and allocate <4G ACPI memory. Also let the minimal memory size needed include the total memory bin size needed to make sure memory bin could be allocated successfully. (Sync patch r18503 from main trunk.) Cc: Jiewen Yao Cc: Liming Gao Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Star Zeng Reviewed-by: Jiewen Yao Reviewed-by: Liming Gao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18505 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Core/Dxe/Gcd/Gcd.c | 163 +++++++++++++++++++------------- 1 file changed, 95 insertions(+), 68 deletions(-) diff --git a/MdeModulePkg/Core/Dxe/Gcd/Gcd.c b/MdeModulePkg/Core/Dxe/Gcd/Gcd.c index 77586a9ac8f3..c2769622581d 100644 --- a/MdeModulePkg/Core/Dxe/Gcd/Gcd.c +++ b/MdeModulePkg/Core/Dxe/Gcd/Gcd.c @@ -2003,6 +2003,30 @@ CoreConvertResourceDescriptorHobAttributesToCapabilities ( return Capabilities; } +/** + Calculate total memory bin size neeeded. + + @return The total memory bin size neeeded. + +**/ +UINT64 +CalculateTotalMemoryBinSizeNeeded ( + VOID + ) +{ + UINTN Index; + UINT64 TotalSize; + + // + // Loop through each memory type in the order specified by the gMemoryTypeInformation[] array + // + TotalSize = 0; + for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) { + TotalSize += LShiftU64 (gMemoryTypeInformation[Index].NumberOfPages, EFI_PAGE_SHIFT); + } + + return TotalSize; +} /** External function. Initializes memory services based on the memory @@ -2044,7 +2068,8 @@ CoreInitializeMemoryServices ( UINT64 TestedMemoryLength; EFI_PHYSICAL_ADDRESS HighAddress; EFI_HOB_GUID_TYPE *GuidHob; - UINT32 ReservedCodePageNumber; + UINT32 ReservedCodePageNumber; + UINT64 MinimalMemorySizeNeeded; // // Point at the first HOB. This must be the PHIT HOB. @@ -2097,10 +2122,14 @@ CoreInitializeMemoryServices ( } } + // + // Include the total memory bin size needed to make sure memory bin could be allocated successfully. + // + MinimalMemorySizeNeeded = MINIMUM_INITIAL_MEMORY_SIZE + CalculateTotalMemoryBinSizeNeeded (); + // // Find the Resource Descriptor HOB that contains PHIT range EfiFreeMemoryBottom..EfiFreeMemoryTop // - Length = 0; Found = FALSE; for (Hob.Raw = *HobStart; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) { // @@ -2138,19 +2167,19 @@ CoreInitializeMemoryServices ( Found = TRUE; // - // Compute range between PHIT EfiFreeMemoryTop and the end of the Resource Descriptor HOB + // Compute range between PHIT EfiMemoryTop and the end of the Resource Descriptor HOB // Attributes = PhitResourceHob->ResourceAttribute; BaseAddress = PageAlignAddress (PhitHob->EfiMemoryTop); Length = PageAlignLength (ResourceHob->PhysicalStart + ResourceHob->ResourceLength - BaseAddress); - if (Length < MINIMUM_INITIAL_MEMORY_SIZE) { + if (Length < MinimalMemorySizeNeeded) { // // If that range is not large enough to intialize the DXE Core, then // Compute range between PHIT EfiFreeMemoryBottom and PHIT EfiFreeMemoryTop // BaseAddress = PageAlignAddress (PhitHob->EfiFreeMemoryBottom); Length = PageAlignLength (PhitHob->EfiFreeMemoryTop - BaseAddress); - if (Length < MINIMUM_INITIAL_MEMORY_SIZE) { + if (Length < MinimalMemorySizeNeeded) { // // If that range is not large enough to intialize the DXE Core, then // Compute range between the start of the Resource Descriptor HOB and the start of the HOB List @@ -2168,81 +2197,79 @@ CoreInitializeMemoryServices ( ASSERT (Found); // - // Search all the resource descriptor HOBs from the highest possible addresses down for a memory - // region that is big enough to initialize the DXE core. Always skip the PHIT Resource HOB. - // The max address must be within the physically addressible range for the processor. + // Take the range in the resource descriptor HOB for the memory region described + // by the PHIT as higher priority if it is big enough. It can make the memory bin + // allocated to be at the same memory region with PHIT that has more better compatibility + // to avoid memory fragmentation for some code practices assume and allocate <4G ACPI memory. // - HighAddress = MAX_ADDRESS; - for (Hob.Raw = *HobStart; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) { - // - // Skip the Resource Descriptor HOB that contains the PHIT - // - if (Hob.ResourceDescriptor == PhitResourceHob) { - continue; - } + if (Length < MinimalMemorySizeNeeded) { // - // Skip all HOBs except Resource Descriptor HOBs + // Search all the resource descriptor HOBs from the highest possible addresses down for a memory + // region that is big enough to initialize the DXE core. Always skip the PHIT Resource HOB. + // The max address must be within the physically addressible range for the processor. // - if (GET_HOB_TYPE (Hob) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) { - continue; - } + HighAddress = MAX_ADDRESS; + for (Hob.Raw = *HobStart; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) { + // + // Skip the Resource Descriptor HOB that contains the PHIT + // + if (Hob.ResourceDescriptor == PhitResourceHob) { + continue; + } + // + // Skip all HOBs except Resource Descriptor HOBs + // + if (GET_HOB_TYPE (Hob) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) { + continue; + } - // - // Skip Resource Descriptor HOBs that do not describe tested system memory below MAX_ADDRESS - // - ResourceHob = Hob.ResourceDescriptor; - if (ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY) { - continue; - } - if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) != TESTED_MEMORY_ATTRIBUTES) { - continue; - } - if ((ResourceHob->PhysicalStart + ResourceHob->ResourceLength) > (EFI_PHYSICAL_ADDRESS)MAX_ADDRESS) { - continue; - } - - // - // Skip Resource Descriptor HOBs that are below a previously found Resource Descriptor HOB - // - if (HighAddress != (EFI_PHYSICAL_ADDRESS)MAX_ADDRESS && ResourceHob->PhysicalStart <= HighAddress) { - continue; - } + // + // Skip Resource Descriptor HOBs that do not describe tested system memory below MAX_ADDRESS + // + ResourceHob = Hob.ResourceDescriptor; + if (ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY) { + continue; + } + if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) != TESTED_MEMORY_ATTRIBUTES) { + continue; + } + if ((ResourceHob->PhysicalStart + ResourceHob->ResourceLength) > (EFI_PHYSICAL_ADDRESS)MAX_ADDRESS) { + continue; + } - // - // Skip Resource Descriptor HOBs that are not large enough to initilize the DXE Core - // - TestedMemoryBaseAddress = PageAlignAddress (ResourceHob->PhysicalStart); - TestedMemoryLength = PageAlignLength (ResourceHob->PhysicalStart + ResourceHob->ResourceLength - TestedMemoryBaseAddress); - if (TestedMemoryLength < MINIMUM_INITIAL_MEMORY_SIZE) { - continue; + // + // Skip Resource Descriptor HOBs that are below a previously found Resource Descriptor HOB + // + if (HighAddress != (EFI_PHYSICAL_ADDRESS)MAX_ADDRESS && ResourceHob->PhysicalStart <= HighAddress) { + continue; + } + + // + // Skip Resource Descriptor HOBs that are not large enough to initilize the DXE Core + // + TestedMemoryBaseAddress = PageAlignAddress (ResourceHob->PhysicalStart); + TestedMemoryLength = PageAlignLength (ResourceHob->PhysicalStart + ResourceHob->ResourceLength - TestedMemoryBaseAddress); + if (TestedMemoryLength < MinimalMemorySizeNeeded) { + continue; + } + + // + // Save the range described by the Resource Descriptor that is large enough to initilize the DXE Core + // + BaseAddress = TestedMemoryBaseAddress; + Length = TestedMemoryLength; + Attributes = ResourceHob->ResourceAttribute; + HighAddress = ResourceHob->PhysicalStart; } - - // - // Save the Resource Descriptor HOB context that is large enough to initilize the DXE Core - // - MaxMemoryBaseAddress = TestedMemoryBaseAddress; - MaxMemoryLength = TestedMemoryLength; - MaxMemoryAttributes = ResourceHob->ResourceAttribute; - HighAddress = ResourceHob->PhysicalStart; } - // - // If Length is not large enough to initialize the DXE Core or a Resource - // Descriptor HOB was found above the PHIT HOB that is large enough to initialize - // the DXE Core, then use the range described by the Resource Descriptor - // HOB that was found above the PHIT HOB. - // - if ((Length < MINIMUM_INITIAL_MEMORY_SIZE) || - (MaxMemoryBaseAddress > BaseAddress && MaxMemoryLength >= MINIMUM_INITIAL_MEMORY_SIZE)) { - BaseAddress = MaxMemoryBaseAddress; - Length = MaxMemoryLength; - Attributes = MaxMemoryAttributes; - } + DEBUG ((EFI_D_INFO, "CoreInitializeMemoryServices:\n")); + DEBUG ((EFI_D_INFO, " BaseAddress - 0x%lx Length - 0x%lx MinimalMemorySizeNeeded - 0x%lx\n", BaseAddress, Length, MinimalMemorySizeNeeded)); // // If no memory regions are found that are big enough to initialize the DXE core, then ASSERT(). // - ASSERT (Length >= MINIMUM_INITIAL_MEMORY_SIZE); + ASSERT (Length >= MinimalMemorySizeNeeded); // // Convert the Resource HOB Attributes to an EFI Memory Capabilities mask From 4b291a290e9c99a4306a73df1d9260e0025fcbe1 Mon Sep 17 00:00:00 2001 From: Samer El-Haj-Mahmoud Date: Fri, 18 Sep 2015 03:03:38 +0000 Subject: [PATCH 057/525] ShellPkg: Added SMBIOS 3.0 support in dmem. Added SMBIOS 3.0 support in dmdem Shell command since SMBIOS 3.0 uses a different GUID in the System Configuration Table. (Sync patch r18506 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Samer El-Haj-Mahmoud Reviewed-by: Jaben Carsey git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18509 6f19259b-4bc3-4df7-8a09-765794883524 --- ShellPkg/Library/UefiShellDebug1CommandsLib/Dmem.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/Dmem.c b/ShellPkg/Library/UefiShellDebug1CommandsLib/Dmem.c index 05dc0d56d599..7693835b8865 100644 --- a/ShellPkg/Library/UefiShellDebug1CommandsLib/Dmem.c +++ b/ShellPkg/Library/UefiShellDebug1CommandsLib/Dmem.c @@ -1,8 +1,9 @@ /** @file Main file for Dmem shell Debug1 function. - (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.
+ (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
+ (C) Copyright 2015 Hewlett Packard Enterprise Development LP
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -193,6 +194,10 @@ ShellCommandRunDmem ( SmbiosTableAddress = (UINT64)(UINTN)gST->ConfigurationTable[TableWalker].VendorTable; continue; } + if (CompareGuid (&gST->ConfigurationTable[TableWalker].VendorGuid, &gEfiSmbios3TableGuid)) { + SmbiosTableAddress = (UINT64) (UINTN) gST->ConfigurationTable[TableWalker].VendorTable; + continue; + } if (CompareGuid(&gST->ConfigurationTable[TableWalker].VendorGuid, &gEfiMpsTableGuid)) { MpsTableAddress = (UINT64)(UINTN)gST->ConfigurationTable[TableWalker].VendorTable; continue; From 1ee59ed17339e3cda0141e3080792fc12f147056 Mon Sep 17 00:00:00 2001 From: Samer El-Haj-Mahmoud Date: Fri, 18 Sep 2015 03:04:04 +0000 Subject: [PATCH 058/525] ShellPkg: Added SMBIOS 2.8 Type 17 changes to smbiosview Updated smbiosview to decode SMBIOS Type 17 MinimumVoltage, MaximumVoltage, and ConfiguredVoltage (Sync patch r18507 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Samer El-Haj-Mahmoud Reviewed-by: Jaben Carsey git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18510 6f19259b-4bc3-4df7-8a09-765794883524 --- .../UefiShellDebug1CommandsLib/SmbiosView/PrintInfo.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/PrintInfo.c b/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/PrintInfo.c index 1494c47e3709..e348c6f25c3a 100644 --- a/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/PrintInfo.c +++ b/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/PrintInfo.c @@ -2,7 +2,8 @@ Module for clarifying the content of the smbios structure element information. Copyright (c) 2005 - 2015, Intel Corporation. All rights reserved.
- (C) Copyright 2014 Hewlett-Packard Development Company, L.P.
+ (C) Copyright 2014 Hewlett-Packard Development Company, L.P.
+ (C) Copyright 2015 Hewlett Packard Enterprise Development LP
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -721,6 +722,11 @@ SmbiosPrintStructure ( PRINT_STRUCT_VALUE (Struct, Type17, ExtendedSize); PRINT_STRUCT_VALUE (Struct, Type17, ConfiguredMemoryClockSpeed); } + if (AE_SMBIOS_VERSION (0x2, 0x8) && (Struct->Hdr->Length > 0x22)) { + PRINT_STRUCT_VALUE (Struct, Type17, MinimumVoltage); + PRINT_STRUCT_VALUE (Struct, Type17, MaximumVoltage); + PRINT_STRUCT_VALUE (Struct, Type17, ConfiguredVoltage); + } break; // From 8df1f5edda8abc91c33ffb12d649ecf449ba2523 Mon Sep 17 00:00:00 2001 From: Qiu Shumin Date: Fri, 18 Sep 2015 06:25:27 +0000 Subject: [PATCH 059/525] ShellBinPkg: Ia32/X64 Shell binary update. The binaries of ShellBinPkg are generated with ShellPkg project 18507. The binaries are built with no debug information by building with "RELEASE" target. (Sync patch r18511 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Qiu Shumin git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18512 6f19259b-4bc3-4df7-8a09-765794883524 --- ShellBinPkg/MinUefiShell/Ia32/Shell.efi | Bin 339136 -> 338944 bytes ShellBinPkg/MinUefiShell/X64/Shell.efi | Bin 382336 -> 382528 bytes ShellBinPkg/ReadMe.txt | 2 +- ShellBinPkg/UefiShell/Ia32/Shell.efi | Bin 801984 -> 801824 bytes ShellBinPkg/UefiShell/X64/Shell.efi | Bin 895232 -> 896800 bytes 5 files changed, 1 insertion(+), 1 deletion(-) diff --git a/ShellBinPkg/MinUefiShell/Ia32/Shell.efi b/ShellBinPkg/MinUefiShell/Ia32/Shell.efi index ed01d4626cd73a38868ec7238d02f79d3daf4e27..154171811e70c20ebee9af11b471120829c32054 100644 GIT binary patch delta 121400 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

SFblR8Z(+aao+P3Z41ME3=vVFw9 zVgF^v$?~$QY$7`WRL0BMaq z?`(GVJ13lLPKNW`iBhqutP-k@YN@)ZA!?M`sg5GA87i+E@0N9yThDFgCb|RM;mGJx zcbj|AJ?Dmb?;@XVyx!ht-U{y=p!=!!A_!EOVS!zE$V*C-%A_`FNu~gjekWn{eW1=D zI-E|R{zAGLuyd520p#e+Vl|NAiEJeR<}a2-%cBv^(mH8_wOQIqZ4V%%hTc%m5oP7Im{raC%1S}p(ya>iaywpDmc8Y9nc%E( z&O6zascNgnzG|!b;e1gz*>X3D~?CJoQc6O?L3b}t`2Zu~iSzOkTZDc>>K1IHf*_>QX35Pp9oRP@%bZ3?` z&spRwb5=QPo%PNpCl;ywUQPAg2rrjc%qtVjS4?;y9S@v%qV*c3yfJN=XnqzmX;x`AGzKU0%^$eOb5tUnvU#<9t4I{Sic0SujBXW2!-(C;ju zMFN6iwfD65wF=rG?Q=Bg*J#cMn%_`ws!!2Z>8JH~__5ypi{f}K#wv@x=H}aCq>*!7^ z$9MKQSDiP`051?99!SICCXoB&50V3zQiBeon|*qR7Gq_Y$6DY7eb^8-8`CYB9b#A6 zPb`ClYdN)I0L_`e#+TZ=dVRe;V0sQNIKZo5Bz+3JNaCCMDU6^9v7`nl{O_6mEwecFza#bi_26`i{V89M6> zQ=h5H>I;>uwyH($3U`gW-#zZ0a=-GndON&VUVwxL=Hf)*;6vpIBPLlwRuY|Bv?5!; zcCp#oF72q6rrpwB0l*7j=t{l1eog;Pf2L318!$b8;AedPl)vW6=xK~ICKZHy+ioNK$jRt|E%IkM+!^oe3{^lAw0VCuT+LP~sjS_67VFRTFdkv#GH#SLT76WOiF)+}qG zwHfo_6nY`jE^3#utJto6$<8J#$VqaZ+yowZOkS6_*>w&R(n6aO0~v|Y%q zXxFg)I(Cx1%-&{y4+N+ptI7Iuvh%h2L4~`y-OBD!jMqDEDU8=fI2+nb~=8~ zOqtaw;|z7ueCLMq)OqN>cJWh_!ULIjXv*5L`53`_k-Ippv}SA7f!MRPt=chg!d3ca z{iyy@kKmMBybE8#H}bPQo&Uk}86O%Sfpl*-zBR5I&kYaU`eXBknPEl>S9~BkiIL)s z$OhJ2&+3c;w-hMor&?F6Y<5TFd6K;n6YWR)uKlN75R$10B+@>46ddM`jB@fi6&%lL zszIBc{MOA5KtD2xH{nb>pQf*V;sdFk_MY=I=ZMU(z%H4n-|Ixkg=JqOi zrq|Bv>dp67dZ(c`r(e3R{cfWIgabLRe9`|Yh37dQE zz0uxU?;ylDFfb)N5Og5JNg+ZZuM^1t$jtSS(BFe0T_tzP1M(D&RTOb!bO4D}6U6mBl|q zHGjsJ^VK|=KjYD$;&0n+GN{%$gP66@V7(E)73PaEa2z0igpXShFiyNi0Dnhc)sOkxPQA*fT9wf?$yH#*^TI( z!3=p68F6y74l>JY@s`Os*eh)7)mAU!d{ z&7zPiHp;FIVzn0{}Rzt}Odk4mb=~RO77 zUCv3&+Y0It?#yy?BpdmW3qL&G0}9qMMaW#pDW- z@(FY%Edo=fDQlp$M(3Q=egq7?((>p<^a^?$NLw$+im4!+I{~%tLr*HJnbiu!^HW@2 zP*H4!rZ@p5dCz)oz4EQRb~(E;#AHo$K!1?Y)%Gz6iqf*N{8$c=69Fq5ou#1_Iv_JAp~lSM`Wt_f< z%WCJQ^Vo@2`BgcH{OYQi>gD6S5ZYY?7eu_q$ne(yCq)udUa| z8|qE*=6cD{_vyiYkBJCGg(fE_&B-7r`wh^G>EtoV1Gm%$vu&!i(<0&Z&DUS+Rk#TY zuLf_=yYc>fB%jFV0H%Vl?ym#)|Ay~{8oACN^B25Hh|UzZxi`}L4w1MEVHpt!{t?0e$p%w8mc+rhT19q%Mf?cm908$O2Us_N zPC?^dfLgvwAJQlE6{V~L6sLcfod#BA2U0bJAJ<*mqFvYSX#yzUSs#vBn67u_6F{-r z8UsMAnCXDcHG{42j~NCHFczF4i^Z)))-LObRm{E$$a!tok_}`R46*&t!3CZ79Mc&H zzh}O4#<}cdI+{|dh1#VKs;erGj~T`RKsDV??r&}`udg@Eo8=uvFW-m2j0gl@fgwqC zOsbJ&0$GML-5~#vO0*vx0d=#D#&TsJtJd05poTysJq@8E@UmItPyT$`!w|NLe`5jRVE>5!8Ee?p|aK_%V60JTM zNE<__b;!CAs{B`0l%2gx}m(ZVyCl8zcwjVAY5~@OIhkq!Jj?ATpC|B-vqI?xiQ- zsz1Y6i)S@4%4QeA3Wi@k{wV|3in*-1=SlwgsF}kAQ#BhSVQa& z*@&6)PZ{Tw0{!lSD0~5Ez3V)5asx^#D5=^2Ij5*)YBkJ?gP000)H`k|S9dMfMP)Sv zzx)K9GuvGVkL|Jh0wb=3*8sRO$n!^gGvH?&@y>gXy+A@l$fL;(iCu!Yq#nd|64`?V zO?yb{e)J%CP%TyoONRN{CYaRMF!y5Nm!F2Gk&{!?m=<52a~{c z{x;v3B}Fx`!OgT|kDUOz*l^{ZU(9z&PrC52$uVw5wyT_ie+#t#yYrZx? z+ko>@csPypuKEalCN=@z=|AiD;SWUeT)Z;ZVW*7eQvj-e^6bX@Mg^k|ES;6cm&QTE zGV5W@F%VA5A~V_C2J-U8%qobmeH6(@VhZ*g!7{lGV=WR!bSKb-BUT*5$2v5RK+`13 z_41004q3?kAi$C#z#hXdZmv40K5A%aR$f*&;1ibwjXCDl@EXG1ALvblxql`&FZxD= zyv2f~40_`LiG(k52I|u9tqst|VmN*QE^{p8*x%H8U>7nEl4`GhQU3*I5y6c3nxBKk zmebG-3mq^7CtGA}Mh`rL58U4DV*X&JnH@z}xWE&{hp6yQRyWveH>`MjIPia`eH6MW zyNtmS&cSi|f!eH-JLNuKekX6pNAfB1T+JEejKHY^Dyzx?jy6|$aJEJO?bo_zAR{BZ zeAryXc@pZVuQ%9R?Ck=x|08(1F%f|bJmdwZZ$#EY6P<=@oSzm(YD>X2{Q$ee)+pe4 zG(WtNcsL_t*(A`{OU%E{-q&1Ue^YEPc4JL;N;|Jb>kD8iXXsD#EW9ZHfH#1koXA&T z<8_o@z)~VRkiY{H)HC`SLy_Svm<)S>1u<~T-UG+4Ykq{K#DI_i`302!Mf0Bd1O{FO zplVm}!0py~D+aUjeLI^k^I=#tk#po$gd+`c=mf)bu{x;=xh>%C2fH<=SI8UXO#-`n z>IIS_0>Rsgn_$`4iwuULk_1QSYci15V0EFAC&MS$7-BjZS`NLmZs>jBmtN6-(ns*I zJdIyOalYhhjlHmUufQkumD$+rfCb8CbC-D%&d*IuwmhOR@QaK7Vwji{>egR?U%9N3 zm~{2v`JS^1VadkffX{+1-ihgc23S8=TJQ(Pp)_?&xaDZlmPp^v?i2S2N-!g+_*X^* zg7-%Ti?A{I29qyy~*LnVwAV#OdmTCpB%I2!|zu^x?BNmE)A zEh%KxZ2(|rYH@lgZ1k$@v$3X2!CLMSAUi)yY>T(z9r$!U57g!cNKLrW5Y9+X!-uWC zC8Q{R18`Ty-qHWmoB}zq4;>jVDnd*o!YayvnKuyC`xQ19cddf(^lZ$yPwge}iFU!| z&Lazf!%UDzlhIKa&mK=2j_?~{SWPReX&2~U>u2-_ zdJZ_*4zGDMoa7g1|i=EQ0LN|VJ<<4xc+)6;DA?sq((OLGF z4-YI6r4XP?jD3uI4DG0rnpqLSEStSiBj|Bc~aBvXP+sTOn(HP?yv#mEo%_ zZcaB}hygZmJ7Zrv!=2-P0psz6d)5tjxxK>h#wpCR1gL;c-ZZeo`B>H-z{q~)z3~ER zZy8Sv(cp*&n`#(Y0R%jbJ>N4DP4m(!;J!oYDEcMc1Rwk<9OAO9D*FWY63oPs!r#w+ z!4@|jdp-ktHc?vwV{NbYllBKFU!QM7HhFaOJ__ov9oWhb=10IMsCyo!Zy1+BC-v41AMFh zpx+AJD-q6f@cg_uz=v@U1)0Fx@sD{QJ_2nyoiFBJKtlvo*7tzm8~h%;p^`==!|~x= zkHs+EU>w5c^0x65d+ivr9Ktu#+zE^59TD96)B!*EM(h=@MFSLSPb?i~So^I%Eeeye zIpk*&e6zO&8o-D(Fk-(8t(|K-?ZKO8I}70)Y-~0|G4?Ql3q2hHVD-q^z>YBV~8XE=>3AQ!57Jl2n1i!m_+^X_1?upn8Hz-(LxnVa}(LAj&HZ3DU_XupmZmcC%c@unnDv)~z z)c95S`sEO~_PjHn%@<-3^#nJSRD^r`fzbf&{#+EMm94yZXR(%MRf#S9T1V& z=`v9jT|E}-$s6Jwuu9!>th!bkFsc65I7DoV^))Pvz19IR?qe`uu3E+Is30#!L``_K!7eQPX)Kx@KKveKV@c{7v0bO)ayfN?F%F+}(@_+)=^=(T#oa|6b zEj6zWMKKjK6-B`-(=4^J8d}YxLOl2Xedc{ps^5PjlrS*id8DjzT`_p8|-eWR^=+CNn@diUtW&UIxG`LkUT%qS14~-4% zqNc%+eNZtNtopMO6;IUc(R#+jsnfBTcQ4}f+q2n`v-8eJ|t_SVz9fqMoq*c z?`UQ%SN~{-OSwA%S+!JrDhvj@Gq^dB626QD4SU|j%vwMg1N;Q_EaA8aM@<}KcPiD1 zSYBafeP9d$hAXW*VLU4_lxrIl0}7HiQHz$o=zjERPu8+{BkH?ab?*v_`_M$TU9E7q zx(-DiwC095)Iz)ZO@dk?-usO(EjvItRXviTo)xu-a%_h`(Qak{XqzTU+HU}(pfhNR zTd3l2H3^f%JaZd5)FU940%HA80xDSrm(YHSdR!bK>S|&-`r!bl)Q`F#nLeNT(FW~4 zkCga8Vku!-U*ZVSW%)wui{6#s^*|)n(HgN%t^M??Y^@-jWT+O4r!+DbKhBaedGN8M z(-mq1nP_zWN#H}Bz$l$SphnYxPI||Mkb|^(W}{zeC=xD#Noh0#h{t@8?%x zKvlYFg}t=GWmT!WEX%3y&JI0j%$*$)wMUZnXreu~YACC<$1*%by+6^e%d!q6g)h=s z$QY==b6XZ1r-DDVv^T+jqjYSC_JAK&M&W;B{E`ks@Wi7(9%y^J_V^T!%wFi!l8>ZN zj0ARBo~k-H5NeZ@UDY52{IW4Pe0sUboMrz-8=jlGE)*g!{@i5z_b`U&cz^16ZxbF* zHT@f};;KfkT*sRZJTSTvjEO1E|De}8s^j0)@e_XG3+A)>yx|>FlPpxi)XY#sdMFrD zE%hG*dT9W|V?aj$#KUZ(VXy2SdK+nX*>=T39%`X_LbOIZP?u5wAek$86m)@^5~~0Q z<^3QO?V-l((HHG;UGtHjS-*u{P4e}ILTA|QYLT#3NZdC+QuxI?ruu`f-9bL5$#mcn z4gd9(?D7y|w?y1&qsg&3SZScKVh1nFewMtn)p+Say!0Sm4B&+f0yUT6@099rY zk+_31s|#-`RByUN#iK_=t&a)C!>drdDPG|5_e`lFA5yzYEFKQk5+-vg5e`?fA1ch; zX)^FF_e{ajpY1alTzzUKM;9hp^N;2n_1K+B;UVfN;h$HEAh1~3FvY*3cX|&%& znz4*Oyk~0b^9L#-H*_iQbl()=b4bfJUCO82H#PEJuVo+c*Y2BQv(^wRY4LXTm}fv# z^mTO3x+KG!#h)P6rDs)+XMxj`gi}Vv(DWH|3)7lR7EW*DJ0Ep2#B#F%< zVxQ{7E}>Ao)Iytt+M0BZsC3h*mBJf6G6k5{ zC_MI&DY(z2mJliwI0A)%)CwuHSdv1`Ds!Ws6h1648KCgRImI3*i>C8uu;`8?RMpZH zggg+1gzf!UJci5Y5c6DHYUG3wSu-z!OWEoSEqj#c?@3adveNNYDfH@vF0auW2956 zLqL-DXGN0rJ1B-ki1l0|Elok?Y$V-(^c`jnO~*i;{47bnR8)sd;N)7DOa|ks(gxkx z;Fnob)XI}&R3#XYgnTTA7w7a%$UTChX?MwLpH~$ViU{5j@Qk+5(huGRmoCf8&?CD# zC(7my)6@*MJObn@Z*l-fRPm%a3hg82amd zo(drV?GVZjXG3tX#;TG}*v<_nkwxo1lv9;s?~u5iF_4KTZH_4Rm2FQT{?+pt+4ek7 zRz|ozuRNm>>a38+DN$m*?5DDb@=kQ$IUU`%beHTL&F}}^nJDt4O~)D$DI2mh*9&Wi zsn@}PvsHZ!9{3nONP}yPbsdMb4y|X*%)&b8rQup-`$_;F{7Ka}#Lh!NGYR;!a40wz|s0TZir zCYnnoqAWQYLPmg?E9Z)32G!mOlZ6JTVQ6b7l8ZGt7*C#NW}UJ!LCNk+4Y0fD-(Wwx zGuclh)k2GKBXYOU@L&r@NK{BjK(ISU28c$LNODMBO5*=Qy5}z`WlRQ@=KljBNnFq| zdIF>V|G*Htbc7~A@cv&2ocC5(Cr5E>V$$*o7O8@IaA(A4=fHfPM>?yAwZdss7(j(@ zQ6V&zqmrsv@o>13!qcELjW@%4JE5?afh$OVEqn2>t0~ysCWWV?{NV^w%P}%@=7VJ9+lt|(CT%{08j!PkL}`g6{3C;U$sRl1dsbKA zD8K>Hg{>3=uU?G>X5ILdd_Gklzx ziaqD+sL`WF9)zn3c5LlIP4451Jbq-?d~z&r1KH&MSVw5_Uxe8}FuNCJ=@`xbg;68N zG6WdjW#gm=E}LokUz~Qp@hj{01SjmjI5mM2QWp3Gr)CwLPQ))7`yGZMzO0<&ruE5G z1&MG5TMJqp0uqhg))fjL=FOTJck!3JS>3EWz{{LZ>aK@YRh5SYb<=_4T{eM`T$VS1 zkgyA*jp6=Ql%FNN#O(5;@yAk^+f~vk6&udLc_xclCmDl^-O?{Wa4Nx|B`auag0FJ@ zEya*yDc=T73H4zCS$`r0Uj$nw*cuAMgrPySdoTj(ev8z-?6lnLy(8g+BT%*s4pX)6Z;$?s**Q z?F6;Zxgg%|TyQhziqV<}$sE};U2dn+< zv`IUv4uGj9AAMjK8agE$)pp1Cuo^te1|o=HC|90B74OXYC^MoA;~ozlqO=W~H+I5y zPjRLS;l2wzIdIZLcZ7#vFAKk~2wT~TI7$1!GKG89V9m{E$$qx4!J3Wp?}id*vK_jc zF&}p0tw=P107hFH7r@vgXH2TAry0#wU}*u*N5v0aiCPg=6CJP#!vHk*lbk(9DF6!W zavy4EZw=NkOZl1TmCqf4Hh!@}kVnO7IAc)7C~`biC5rln@k5)6CoRCOh!U!z7E^rS z$WI1RaWHW+*_8m>SR%UgrBXR;8&OIQVXR#pe3ShBC^WqtHX4k5is^-Ek~ITuioC{D z$F>SZX!s`Fc+czP(z%BMC5d4M6<#2 zRul5?Fp`#;Kp0e$h1Cv21NNK>ccl-q_>za5;!yQeyuR*6p9^tAdQq|u?iLBOMGl%PE(7+2)={Yo(GaRnz z(A5%gmEW?m7D@9pZsOeChLzrH$IM138V9mR3%{z&;*G(A&@u7iBMubNp8uv?>!sBZ(Tgu>8 z5YVYV&|UPEM#qd{lsX3!Pa^$ZK99J=NfxEZq+%C_O<;-mN@lK7=D66wTh?Lm1MVU= zwJw-;LxmZ%n}{c+5Af1R?KuKryIMU!Ias!<-w2;$fM7}yYAZqw)KQlas`?Gk_`W*u z07_(62Zc|!yI`Chu6Pp})9em3x`aiFzDeS|87}?x7Vt70;Sr=Lrz#v!*+CK)CJz3{ zXVNjj>a>#*M4(8ENnpjwn+upDc7FJDYwq(h`DOT$EQsBjI|kWFIdNl?TvI|aJKJ6J zOuH_70LrVD*^)HAp=A17BxNkP%|VnU#kR=!8UM#wa}hc>BrLt*X7M|Wv>9t4r>Qh4 z)c>SV^gmJWf7W4afR~yb6UF&FQYazDv_e4^Zi9D*X)}7VXG$CPtx}Z5ig6h(5wc*JHM< z3}lFU9So~OJ!o%nP*Wu=u}3DrQ0``RD*vuklZ9iF+*Lvc8Y# zsn>r@y~DSBWdLiEHEEoYtXwrj^R;dji_f9h=n39qBtGh#8Hd&sYHb5anr6@|)P0w2 zgD$^iQdNq?d{o6{Altj?rdy$>3?fzqJx z7<*3P1G}q6FIcgc8HUB_2#==;9#4y9jCkguY&uhMr5oJ}Lbu4G{=jp5UVYXQp_^L{ z^#G(0lN^nR?NNB5&IK{zohT{R7!s=#IjWK0{s&ce+1?GH@h=jekdA;s^Q0ta3=v6D zFN;fP!>(q=Xv|xeypK9$6lZ)zb!%wGcscEaoXJ`7S_^6kjTILhbH=@lmS<;Xj7X3* z2BSNvF^|o7QUH-3Nfqb7UoRGkFyoL*W~|GO#ZtMsigq_o-nzg^R!?cZa4IbN?wVjn z+<>s{`)k5_&@Y?9XP7P}B7o*><=pX=6Bx_si10DA4^9}JFpBoV$B!S6A860H7J}DL z?(W3GdfLT-pRSP2OZCV>9|f{h!t3JcN;i>l%tRC=(X?ALjNW!@(s_Grpd?@Nco1RQ zg&lX!*CE3Xa%%(Dux6VBR8f~!Umn+hbu<3VUu?jd^=uPF(#K0Q5)VueHmZnExHn>Q z2chUlwGcxH!W@OfLCwm2k;tRGr_kYQpGc$eA^)ub3+{8a0l3|*fZG)H91Uq4O$@cB z=niy;>IEp42rbeP1{vxH@mYTMF1hXQZa=03u2A4W`Uqwi3*y6s8Bbf z7SuEZ%*~^=5Gx;^{sgvIhxGzX3LyO;?Q6V;>hcw%E|P0dEUMqrL_CQyDH7-_Cf=q( zm}g9rqZvM8$LSc5&S{J>^khT>)9#ED!5T7#rVSbsLrAdDS!o`x%YA6ExceQC3}y-b zxA$oVtBYY0Uhe9AJ@&jh_OTjEO>jgT+ z;j-Kt4|AG_2_Y)>5{a&{S=!jmg$w9TaKw)HlTPzE4ZWDqUnTUTgpT0vLW(aW!U?6p zkujHyr{U3&z@H~C^6~o#Gh9>{qb;PxSB5vh^hF=%VlxqwO(c|9Jg`Z*y+GkB8?uo0 zi$OV~o_+jfcM`w{7ARO$pN&9lYG8=F6w*V8xI_&3g;X;`Nl|}r2a7@cdP5f3bZcwy z*8~=wTBuEEH6&VQwUoFYQmo0}lX^YPyEI~xvd&>LU`r|XkpO|-%#PK4W2CH`8Ay5( z1*79o4`J09*BoGNlN3Q{wdy|3)4pOL*&LVUsy{?@%Ns0I|C0J&ECM4Wxj7W|Z@m(m z8Widlptbhmb?Ornu&7z335a+Azq>SJjHfg+3pE$KjU7(E5Ed3<#Ss!PrMbD9;drw< zH3e7drm&Ur+iV=UlqoN1@^Ba$LYJ8 z7^jzgFir+6jxktjmr9RFlqvSH~hN)Z^0Nisj(al%~&MM33sGy0!BvM%m=%b_Ss6#y6%P4m816= ztq5q)A9c#)@}R;Pjf@hz`1)`bY23+6!&zwhR8WzJ9y({%fq^Bmf?o5Cm0leE++tv>W!?wORY`|au`Lrg? z=Jh2Nd&}Y`bx^D=hdW8EmCIfk8Tv}A{yjh1gmvo}HycL8)#{ipj0QQpDPXD~6lzS~ z`qdodmP>NO4J4t|B7R^Kvki*@njz~OW#OowmgCr_kUM?e? z6jnnv(HlWb#E@!Kh>rYzQx-K~IjsS%K2c%`5-I8(J9?3VVTBsKXm`CC?hXD4b^()+ z-b86`*acc2%fBG$6lUP8O83SY9d<{NT3U|q1CxV5V znilYu5v+9+6ZlD??RbgYS=HWdFkn|eg7rAq&CD-}g-bjuf;BXL&R0dSwIf#}A_a>p zmz2_^CG!zPl##-<^+?wX=OX@Vd$$_l6haLR*`nrW7(kb@4X}cbbV0ui7)kbUQh1aR zyXFBPYR3T&p4Obz$?9E&RFA5pc6=&H4Ixq+byAW4B4yM_#r!WGZ_%2d^H}Cpg~t&Z z;fH_~Y;K@aJ_%q|Cbz>TaYu7(n%}NMXIWJ`Orx`o=xo!;%>Ead(IA7qV&CvzA$G4q zxKmZan=mjCVjm*>StWxF|3$ebG5ClW{MGiPqnDH_9qq5txeZvs4xPb6fK~11UW;Tf z;D0gbszNxgD&dN4lEIZkcvmHZQ~yPIDk$^qEx=&=Ds);_rL$V26Hj#Z=nRrpR%Nh( z#-R8AV(=op7S)INjJZnBduoJ#1FT?QL!EK~fK@3UgPF9e2C0Tqa;lJ;SC!NsTV-Eg zBT@%+O5;F@W&>hC9TtKLlzK8f{xQh3RELNbpsS-=;()_{Y{}}huT}+W{eNoyT>DAQ zpJ7b3n)|Cj^8x)|ZN6ItM}1s#b`|L8|EK1_Dmc-VHM_Q{0!oyp&>*y?FK32nL2jiWsSk;k)8tCnm)v8?1S-RXA(c^^fN<46anuVdZC}4C1-J zu)w%1CDmzkz9Aa(^vbksmug@!S%+0iTGDkh>cNI3#dKYZlr^spOtM(@h?aV5-fCo0 zxbD$WAoojAeMi;XCp?D!KW9O}bRsl5bXv0D+eFCsXkzaR=Krgmo zLG{7_a=4UY9~#Kg1QkcnO2iNK_?9+!3G4GuZdM^%7EA$PSF3WPqOA?og)+YiavLrE zpCe6Feuu%7oBDzYU{rYC1~b@I#e>%yD570eY0?weeI2$3Fi6J?A`q!(s?y6~eN!o) z3YyNYckm$Zz0ZE?dZ|dn6JZeV0XWBcroYi(-Dx`k6zk4cEpQ>2|w&b?9ER3Z*r|`~gStH}K{HeCg9#pUi?Qbe!T(l{Miym59GU&Ar#I9!^#NMnO7cACVDCFZnZl#CnKJEK;8+`z*}`>;q9%oSJ6Dxs?o7- zaJ=x&tZbsJd>ap(;y{SeR&5@PLtaPLxLedcGo(@|Hb8u!oPumYy54q>Y+G4R)kEip zhd40gsO*|AZPFz4h5y=-g$579roo}w#!31TrJsfpK`7y!SbWw4n74vwb-L4}b`OqH zdm|!yz+`tqlP=0l1md6M+IljEC8<4-9)Rs$srY;ibptzlOr##(;=z4VI%)V1pk=(| zm>UbW{O_9SRS*UNE@JLl*_|eU6)Z3syre8Ecv&abC@Vf!N^jWDX2{Hr9T~&$enKL3 z+7bSx-1~&$w1+_C?Iu8K2p6g;*1Uo)a;iWMwxW#5Ubg3cqO4zfk z0u6%**MW3BgmyLn<)T8pSQZ!1Q1U}HR?YOlw>uesn5bBcJnT6G=532`Jm^_dx9Ul;5_)DGH zP8K;9MmCNOH_qfM;;@~}$Tc*OIOx7T)eBbhd`gpR*ZV6LscE>pQw6yN%BT< zoe%2DLVaeUkQhD47j|WhLgr}|tD{;xO3LEsl!?ohq+{jsy&&HtM#J*P8kPJpioFT- z4(+^Lwjdp~3s<^9Ucd7;-B_c@W4hdbUoCr!;MGI2+DlXgc{O!ED&_-49OJWrZhV<@ zJbY&8wO;1?yRks8(S$LMUnYz|?&-$DeQY|0jkoO10;`z_3Bk54@V+?M{!M}`uh z`)p9bSjHxoQi$+@+m}c#N!~zO1j@UBN=iQGU*zgnl5^SC6SZ_n&FIH{ARnKxdM$q* zl>q7XC5&4~W=FuL;Z6Ie*(W`L;WE~KVaI`V^@ zy>eVvQmr7Z)>)q1gN67E)N7sL&-Vb`c*6LczuE(IpXFPD5qS^undm-4npTCb?-RP0 zfg*bIJE#?4S|O$E1zBvr7(MEo09TRe^Pxv?jE zyPfBG>6hn*NI4|uLpB*O&qd-_y`Y*VAhd0Z#-R|hdp%iClczeb-HSz=j#cOOUaXC2 zWpzHc7mG4Z=9_x4=gmu|!wv@75$(A66Yp+ku`yGoq7TmGZD=4fh@6E#F(58W*-hBT znV31E*BjJHLclb>3`K+0|9qgrx7(Sm`r?69Xn7O)QacV3d@&95Z`v^_t8;4#tMB6t zaumJx<84z|8*@CBPe@_WW*GCgohR^f?RP9>W}x%Ey;*~-w^0ZNoKybIz#HTL$$(X3VEP|m;45OF zWZ7c|5>2Xp2bKD!TV z*C0Pl%66MQ=c|YmXFor2xUcNM>NJIa-G_AuYIK?M714#sx#bxt7=~?=oXP06vS@(9 zZ4TCijY6WU0|)sRO{rwxgK)lTEAL0NNj`o=UU+GwFB2G-2gnrM_>iav9|tJ9P#stU zq@DD>M)?X5xPNG<*t3jWJT-Y}^ii#B6%mNFM`d{7|M*O1S0AOsJcK*hN9cdIW;3BC7(hFp%~=wa_ba@n2SXQnRGnAhAV&< z`WRJYl@A@DPp23#l8B2A#!GHX$!OSuOZ`~=fETpVC@O`U4=>PVag9Q$HI4N&GCm}Y zbxX*&s}X)%t?WVu-O*nED~%()zt>-ai9Qk$Z^Xn8{SX3Eks^U^;NPUNE?Gy=RZbD0YT$(?{P47ay5wgdQOv|JL7!OG)RONPxoOBq7!D(Qo@klyt zvx}sGZRvSH68b=E&+_*Nuz+Uo61AN=wT47ZRaR>RDnK9|=qE>DG`}Cff*LO?1G07v z@3^=Kvz)5-3IG;llp0SWx>3#>3}p46F+hR3n5}vHqz09UAU(fT=BY0iaq1T0piOBr zqFSo6FauO+^B#yA^8MjSQ4LzDMWN)xy+Y`xb@W8OY9I^ADgmsLkA&SQGl)**AcR1I ze!})Ki;V!sGC|%0N<}V+)2Yv5@gh>u7r{^FWi)V1Yk-6=zFw^Hv`ab(H)+s9!5$6k z-{e{6@vehd^#;o!HoS!p!^joEtt(`ql5~#I&BqO5F}^#o*P zAi6B)hE>tWxiV72QOjLO^^+G-5Or!VQ>G7ieC;=^xHSmg3UEYGdXYs)6TKjPn%9_t zVuX}a30}-c4q-0iQ#^kNYdGMIWLnrQ^YOrSsz(X?;DeBb+6Ah!hhS}?*Ufau0vlF@ zDrsuW?Er3vYxR=!dU}n_gV-cD8_L2>%j@#gq452@-sW@gG+yK%0&MKfj|^pN?4 zvW5-%B+16x7XMRvn&`&gvMG`P=EN zxv_vBOlK{PE`BqeB_-I&r;Z)DJ;UZulec5yMW3c)7kh7#@ZA#<$`6?`=zVkz(1sNL z?mlF62Yx(75}pUxju@cJ zwvM>>eu@PLCK5T-(o#~T!FSoF52Bz%vDUjmPqF5vk~Td1Db~UEc>=YKLs+C;Q5gQ8 zfXa_O#o8Df@q16P7qk9~ujGybbCxD3*UgpGIqQb&MW=g`Dm4h_MRqm(Y6LkxYCsp`Td{NSE`u1|4sdzijt-S0<{-J&4(a@m)J>UT)WfEnNmZ(O3DBwYb7Nd;y)r* z7htMk-lCu~-07}o&Bq#AEbi3cZAP)qHQK-wrqD6KyO>{@qhM*-Q#8^Pd-A0PiGr0C zm&o{9V(}=zQfd&*7D)HuBASD4{7uD>%3VOoPSlDoKWxlg4~P0U2pEf?`wXxWf6%bb z=vbKkN-vbVFQKqNC$V!uAB{$BqG8RGi>gamgB8w=9fNJOj#n)UXb>e%qd=7Xhe%OY zM;)9rZ!W_o05|2MN3&StRlagG>kxiAo%-bnkMS%M#COiu5jf*^SUCW=;oxCqH=g|V zXqFN@Os-JH4(D@G;`%(&p@Wa(yKQ;;7}nl@1He^}O6}tBk6{hi_Be&_8N(ubETK)L|?MgOok)47f!?Pkk>XfL*?pl_#!Ms)3K~!-B-Sc z$d5`_wM4x3A}wsC;v#=)EDI0VG#G@j;LEev-wdNxEM7y=i4|j6yAZ!p8G@y8$(xG? z5Z?u);EGP`E*E3*HY0-jjAKoMQ^`A4ld)iuNodiTcuYMH9z%A66UR6f&?TefF}<=m zlHO843Lfh8MxqT=y%bB5=B@_ zuu`^{nW4}Pvi;P+>?aLen=Sj0_Z=E&p*JuFjgox-;?D6bG3$Zk_jhcN#=$b;2r1;7 zCavoQnlV@`ao5HVcWtK0-JYcj%J7N`7AaxrNij-_v`9RIg&Y;@X@yjhq?e?jMBWev@kSF_Owfruf|ZJ=rMuxP zd~zvI#}dUVK64`L>7S1ctb2-G{l?u5svg=&;m0Pj1~u*gi~%G!zdgS-k=dd@ln|@* z=WmJ_5Q1~OfzBeU--x^_g+esY3K#KHjqt&isF#?}3bWbFhfiWb>1EQpBEQ9&TPQj1 z7a%rdVq~S)s$Vj66P7a(n%yr%EY(Uw9#7~KT4@N*%EM@WWmjv70$w_aC3KidW*}#L z0C?9#S6xWUkTX7nKv5*I>Y}HHh127(sk1O$2ol%qFIb7gNCbK4CpOa(bOa!`q z;AbCNbmK)sH5{Fz#b^;Poy>x32mK`RFi3@P`aoYSMKQUTq~MM)E4Ms$%K zmn>LwX*@)8K5z-vry|7tHDwanMu+}M1SS!R7ZF^dGS+-B&gMt)Jni% zSr0j?MWT#F%yFv`&9TzC# z(qw9yrdbWB`tUHEd?2MVpAufuds}AV2%u^F-l@yE^YSk=5n(zhJ(+<+IFMefJG2C>FsU?mxv` zr^C>;@;wcfPq7)B9Nk^UX0J#TPM4@4jGLgH*1{QgVzcIMfG_jB`YhYnIr3$cV*q2M zfY6@`bOilbc@q8E>W%&^o<c6;37{Nstc!4p?uDtWeS>_Q*>I?@gl9_?e2s`Qi_X9&JNm0+m-gM5 zH*Y0{PZ#F-ge-UBa1L&YlYGH*EV1jdqljV7BWxgQhx*mN0b-;Sna0NBjg6gvw6W2z zqE6rspJT1Vo}NLh_r%=8AdLvOr{ol3GgB-+#Wb`Nu_&JUJd0^`8N7*ZM1$tC+zqLH zL!d6lsGtd7_dJ_Eb_8|6WjO&WUQiz%jo34lsN9#qc|&F$mpw*AkYk|BAWg1GgJ>V0 zinkk-%k#|XqxbZjNWywrwcF=;<}?;zyv$ckW5d0M9zn}JxMvy*@~@AEs(Jwzfn0X7pbsZAKd-<|_W+F;S{ss)|+!{sAf^%5&C@Qmqf9IMq*;TNW}Mh$XFb>YH! zlk(1%nd_7}ftzc!Utn=YoHT!db@VAdM8u0JME?R7?5Fs)7g*iMkI@<04C12`nT;H= znAY+XWe`LI2`R;p&|#9$pZt#(Sb*Jho_ab0clbeRxfBabPqEmf9So;2A1K|j^0^9L zhPxNQ6vwwK7wxc0N~;XDI4=xyc;6YUtu^u=(Ea??8Ei`RRWzcm)SDu5#Y|SG#fVuj za`E<@d4Af(o2fMIU6#F2se-1}!PzHMh;$!6QO>*1Wc9KJpaRvGYr=W)8?smvwqWS6 z13qB3J5&9{uQXs1=R8fN1|m;lS@Yz5Y-+rs2Ta*`Y07Z%6)d@*vgc&!JbVkWfQJa; zA(nWkD|r}<+fcpuH{d$!6RA)oB9RJYL*G{3aujRz4oU_qM2yDZ8?w(gP=?`vOA8(* zfd>-q%kR*(d<5(^Vo77{>U?aZaG#aFGN3f1Td|?ooMOp=tK|nxXWdO5a2&^O-wl_F ze%bc819Yzp9lwGh)6stDMs6%TwWRP65IWaP;qPa#Amc$^kinw+^qP#uVTkBO^6X}4 z1g=B~`eGZ0dNBPIX;n+*2SRYBoRDdYjPf2Rcjza5Q8x~BV=`Hoe_asK>)}uxkodEi zEHx{NXsf4ShIa0SRP|H)+HFl#_eU|xPD9jk>g$L4>8lRqO=VI3m;Wppi=vBK(U<=! z>WQL4t>}VYRIl=yKns+u*UElH8Sgub^=;n;t&3?``JyjkRGz~$qf054LqNa@d@me{ zhgwizWCR5nN8tX@xk!F;7Ni)&ug_wE7ULNj!t*qWA8}r1Hk;x#0*#2*_{+0djL@@5{NZfq z{$HoaywJ)-9~~$X*>u)l=B>GdNtvC>#&E^phR4u#4HD>(HMa{29In|Rsj*En8W8R8 z#>>!a&qtjzd{b0>PzcjB)!7uMcQTriTU&r~;L%LpM#;GI8I1}4VFYqGOw`lOXm5?v zE*NiG@<)NK6eljn$m=i-#fyB;9M-%mgSjin();@iqGQq^3cuS@u2D7`?LQ zrBW0PZRPN=xva_94wyU+XJb^1ds304Or;b`^akU)UJt{^9j9xaqdY*A z1~E9C6XV7GQg9nPF)i~6OLnkbutlf*`B;>zc*Ua~6ry_K2es{qEs9OL>}RPI-?HdcUR_9ta(2gG@SK1?7<`r=dH?oPix*@ z9p@z-c5kAF^Fn1l*_yXf#~C?D2UfJU=3&zz8At()ZX!U29x(-O1>I8B{lmFZi7ek0 zLW;kW6pKb{mFiF>?LCMOZ;9_+cKUfD#k6rs0C#>*&>EcXisNH3mun!!*PaF>5uPtP)qg}SAThW44tiN1K z3ZEiAUrtpW;Zw?1$gV4|29wDruZY6L{MUu7Nl+iSyg1%9=pRL}l=oXgw#~9waBORE z05>{(DTS8R;_{Q>#wA`NK=M`U_7R<8USy?RA5_CXvY{BwWaFJig zVx8*_#=Sv(Ez?)M`z_E~WHt-6okPm{=D{jUV2vP!kIrV(jbr)AY}VEo%}p<{ITK1c z;iQp;R!&?+jg^aPwVm^wt9-|0zner5Fovf@?ZH7TPKmElR1V zCD^ZcmPtKvbu9;de(5FFoh1e;Jmh88FKi{G4&gsjfUaz{K=|pyB-IP`X<}Qxs;}_n zFS9n*H8L;1wy6-6(wA|NbZkeY+%L0;-g}Y4*E)99#Hip0|KdDint00!xHvyax-c}> z*J(v}SysVp6_ikOucXW7EFcefd4R%4<}gRh>JBvWC1R+oYR$E4eO)83&03uDCY!BC zB*jh+>X9CN2nMx(%wcuI#!570oP6NZqWD}LlB6N=P=j|#4P+?2buRPE>Mffp@}x!3 zHYpx4nfU)eI{pXJ@;{KU|3Cu%1F88Rh?xPz3v*d$?JQjNbI^5ny4Q~Q7@~LluUt07 z+&3DjzIg}&-l?nbsd+3YA-+9SD(S!yr4tg-h4RX$-(b6X4Yxkg11>Zi&!i3 zBPw0Bh=rRkQR?s_*0ttf=#y(80%Mk$NOAwgESlA^Dfzt?vx!FkFKW|h+g#uS7%OTk zeD4z0zj_Y>tCmFM1Dq_Ti8sP{D38QL%pU+wa^|ILF8?U4#EJ*cbh4f;-^aBmyP60q zkm!wr1=xS%Ti7n!^Ux4F6oNkFNDRx=S_=Qo$(sB2lE%(51rHvyl&$hzwNtjXACLS) zOA*}leeq)nnYRNFpH~R7^$Q8=oZnHH<(4Jo74R<9kE{ zT*2uPzV20)Zhi%T6|b>4-){gy_qtI@&(~O6UmuN_i2yIZ#uoZ+&@kqH3V`o2HpF+D z1_&U))Mcz-?A&HpjOB_xMk`9$j+r%!R%qUvte{c^i~I%QH zoCW$$`#^SSI#sOmI_qKDl+V*&XLHO`fXL6j&f1%!C{^PP=#8fdQeEF*ui+kqthQwf zc<;%;+x=c}Kk%iIVHM@dzHof~ECZ*6Q9!@!GJF~dZ?J+pqQ2ak9zt^v;;H!z>WA=59hJ$u$e|7(`W+ z3b;O09XqVA{NTId)7_~+q)UT{{k81-{)iK+z@uzFfh&n74(3+JhA=%=a{4z#UFSk(`}1Zwf(? z@om<`_t-{RG!PHo_H8!Bcc=!qvH^f~Z?l(KJEri+mFzT|Xj1s2m28l?XG7E;@(z2> ze+Q0DQxp(uX^F@78Zghk!|Z`cxR2qHi`ASq5M&2rA+5gkP_5&;Y(ns1I-9Ge_~9d( zFjBi@PDW-<)CEfZyKKIBBF2h$dXL>U*CSY~_gOdg_aifZ{(UyO)*FvV?gv1E=K4e% z5H7#Z+C;6ycTvr$YEg#o6Q!Y@aXa9rU}LGq$EV;-l4lHJB1$l*bz8-rF~^`5-@J-V zXI&oR3puOV$R^)EKm)GiM)FVqF2Y6u|0H0f3G&jYQt-gcKUmG;+YPOcg|7PV9?#)q zZcL6o?Vg+zGni*!>lxeyMRaC?K4F@sO^_Gx;I-GV(dMQBXm!>ame!yLQr5h_UT~`7 zJee)Zl8{P@v9%zCAJ?$nEr0k>j?p7L3Vy>B5bt#+H6OW}h|}WQa;-!lJU;XTwxLnV zTj((Rfi@$py8xHAOPbTGEF^I@{E+Q2?;&1(_z-%xmLz!hLpE>V{B;sLa}Wh_A=~rs z!UT7Ul|XtkD1k=^7^VZ8>%gr9wCF&a4tyU#eq=39L!RelYuStD1$9h@{K@OsXU4!I zwaA2=5m|}U8EmzZFT?x!6i^=h5!MtZrG|gRcKQD84*|WY{DB8=_%Z8gZuu(6PWhN! z2~Bg+Kq)CS=@7k$z+ZR3ouO0)Hyj}dacdQSdIQ_X+Wu+g%{Q{Jx?j9wHuQ0syV>vH zu%LRZhpSGAsCb``+sKl9JHH~Ocz-d7f4Y&i4yvyKz5<{C_q^~uuC`#+Whtu(M(%H9 z?R@8f8~_hiqDssr*1zUuI<=>kL2@U&fy6hlK7NY;BcBZJwQUALZ*O9|efQp^s<0FXa&D_+#s>H;P7J%+D? zNul-h0p_Z0EXvUXsRHOYxy`QL9?|pz7-Vc>d-~-ZL-axU=}ltggzquw0*m2V{qG?; zx_Ha(i{+$cF3T~JW#D#p)%@!lSg1{(vZsyaL(4G~(>`PU8a00%!}cSFjdmrLNIY}q zP0{XPcR~^W;WJjx+=WsVpRw)c4ODUS=j?)c^fFL$eu2ZZzT4zcGus-Rk>X$PV69qA zehuzT8r}k0GLaJJn-FbAKD>4@d+k7po0{fuQB1+cs9@|aHo>~~XCfkj%kCKs z`Db@AKV$H!G^Jbh4o1O34qE-VANfsz6+9JKw@HUbF{NW z(m6-8Dlb3>=WeJAwU;e2hfwP3UiMDd>zMl*Lu5`S3*=)?{km zWxJXCnEGIX=+rL&%>Sf%zc_htAqz_BMfF^kn;=+#XuUza+Ca`a1i9qJ_v2!{Qw~bg z95W4{4qOIcSz|aS(bv&hb(Ha!3)ur>XP$L{bqpFVn=cV-L5x14h>Z9?b$~5~ zY7P5}^@_QInrPmMN5NoPx0=;|(mX!-a$Iyd$s=Z zXTg~k1dU8`^)$+88e(}qyvq?5X*qa{Vxl)OgZrN|^BG5QBXc5u`v_ZTe)%Rk5m>~= zMNC~NJK@5k0N$lR^r?++fF3kT2Q*(RoQ?-ySHyCC3l~W2AMxPPN7?%k8#F*H9tGc# z_kG9zN%iqsVGvCGHL<4LE zAb)2u^JXpf&Bv{s`(_%9;GIaPw5Y%l&^cuSpcGaC=zDAWa}NH*!bhH;COUoB-L%@I`jS}9v$ zJ`Aq;qLVDvypmD}PqLxrb90euc#1t6kWYP5N1Tjs``dHwDzmZKRn`*T2d7w&IUjiW z2Trk*Mzb5XMsk=B4tFr$KQZv=`(HBvp8hQx+TrL-33wfVf^+2f8_-3(sijxhrJ_MK zh=3iIuF(w*a|%^`@GV;&`DX?!>R?>Mv&5nwq6=!UW}2I9>*kjM7SNxusPNBwCv; zuzQimHNf9^2!!V$oFn!-=Mh4Yyv)){zr}-}_>T4U?W*;qgaA!1vOzWXA>|r~Z>3p? z5?^wWwPfoG%{>1i>r#I`K=Ooifr0eynd=nMQu?8|#`i3~Z_;4dj|IRg*i4+x!-TKo zw3^n9F;uvP3gww8^^rTm{*s5jg*$_U<)dMBrncYto(=N-T{daC2tN7U@3HatK?7_h zK+_-C4BvPS(3Svee*i|b1~3!g6`Y{lD{Xit1hTt>^P{Pxo-E&(2QT&7Kx28bZQ=F8Z|hG_ss zfK!*j&C_TE-25~hfZLbZQ@-IS0$>LbW0rt2={I+ka$h{C1($N)9$Z59pYmSly7*#ETD1-&4-MBQ2O z6ASNgjV>N;JmEen z7EG5+RTYdG2nDkU{8%t;2{fNTn~5jt+pk3C+*Q`jTu7-JzhEbPo}}XVg{}3g4@*+X zljT`JJ-;xUxjii`0l%_Ha~nz}|H{G#H$$r6jATN7{n-(BONxOo3N8>FlDR8ER|)hT zfj%J{L?f0$peqD=yOOa-0P%glvQFkRl)C#Xg!LoD!V`aEYo2;Yb_P)x{3*LGsK0L{ zvUnYH=}*ks*hcbQU?9=#3dNv;L$YABw=9XEl5Tp*CsYD9=nvj~oC^9~1^gTXwK-L= z4!$1EqQy|tn*|P-f3E@lCUM*lEZO%J4X~a7-OB*T)c}JD@LCySXs>C25CVK%#v*-( zYk+Id08mlJTKZ1a06PfK=65uE6}XrRA;@#}q zhHVJ|?X54rRfn4=^0nv=xEjr<;SSfBqrqiVC!B4!$h=8}y+AlgRNuSC>{d1FPZL9U14rbK{lRv${&6!7E#e)$9#ra)AbnhI z$FRdqFJzS=fT2z^YH-U97RqjKG4oS5*c7%Hi7q!0Pe>+ut8cPC?A&HEzkZYT@@x4C zC}Bqug{mQiaA=Zlv39Kopt*#l=i`^+=ql4d-S`0F-n<-1=4coU%IpRAMb0u69@5&+Nt z$$FbtptTsf2?s#2JM9H)7<7#>lAtU}R_l z5HiMts`pVJmoHFj8qmw%F99i(gNi>Z}# ziDEkl#;ADwlj3YDCJhCuS+AY+q3MUJfJJ3GvyF#IrS*z8q%F@7dge zLt6597p~T$8qcd>q2?Zx+El@sbuL94@Efnt!d zegK^ZntLinY%xZOCeUy6F&bB28lVPoP~-hdl@3neo--6^Luzf8D?WCbs!`oAC_TwP_QA@npBkiq8T4x zQyS7*i%*=QKA>NT9;i=*4q|%d_x8ena*k4YSyPl9KkiU_<9wHtek?)hi$mP+5euBy zjhMiVir?YlM0?abnBYmRNvMNKC81KMP(a_s%X#FDulC^Rs;p2fb^}hxZAgnEbmVms z8Go_Bqag=raQZuwb@Gk9iwQu8@FH?DhJ)#Lto#7_ zVA(|oa)R0>jsdA{9#*eIO%QcwL!!wvr~c}sO}zw9p`3b{%(k0kFd(Ov^j$@lZ3|Vs z@4=1s#VB~|IdjYS{YaE8{F}z1(tI8#(6bVRv616)ia_ZA0jIZ8iFlESTrf}ceH{rf z>5HM~DMoXMIST;(oYCCLoJ*+qkxQFqs?2&OwU0-vv&boBlM% z9nir|Lzk_D67@+Wlprn1r9?F(#v{S~nYoF%I??aU%q<#6gAnPt*hC<;}n#X zy$vW|<94#yTh^XJj7N$5%6~>M>0={OrecgTKgG-e)v8Iv5={efX1>@g zE$bPxxwCmKHSVu~jbo%wofUI~QQgsX3i9v2>G4d;S?K2lUrly-92_NgO#=Dj#JJ1W z8+ox3SZ;r)M^EZsr*;4>0w{Z7EmFWvK!L6W&?Io#LaDXS6?3FHoLal0n7f&OB5eut zGDp?jiWIqpU&*hQ(kC_INk~(?fZvbs-|{jy$@*>>S{Mlw@DcHtH3N3WlC=npH8BWS zoq(mW76D@4L;(~IkacI@<~Xun-*XhLW#Fu)tsSW2tPf@gSa8#4LQd+u{PhQ^^bmY$ zyHuQoxwrG!YGzy50Gd|-9oC9*h^kb4M8!B`8^=rEqpLw(G3 z%?AMBaX#jdMDq9C0lN%-GTyfuxk-5yndBkV2DbcwcCmQxnj8rlUL{G=QWR>?WxE6) zov-pSw>DoLjnqjWb6o#JNXeHx-lzr*j~|Y!SMuxPh=Sti=(h&Xen7ZV$u8urb%oeKTWY68O*S%5Pf<9Eibxkk zB0R*(z1ikcQG`@FYeeZMQucqp&-w16{=Ht=^Zk52=W{;ib8esWIiGV*l{`+y=oMg@ zhve*OU%SWv=9#K)$f3ylMNVp6=$^WRgf8cL8v(1r#)l7nSvj@U1oQn+%)%Fzd zs8RUO|0b`Mx%_szLC3HsckYq+=)Zkbe`bMmjvTiA3fyvkMbRof3q;BXn8J22Sm91_ zl!GaX)XB_+UANHb*6^Q`HM}a|x<}_=voR4-&IrHb%#uQSv=u}J$D$w+BMUwN!HE+H z2#HL{%*G@yaHELDm-C|=Xji(sI~eHsz9d8SG%Nf=-^2NxSo*E; zUH-8bx6|T5CZ+wBr`|agIM4 z;l}~~;I#xB`Gdyq3jSczo{Jxe9$VT^Z8yi#x|c;vwoz-A#qL1kcN@-4rb@^6Qz>hz(+o|xZ82%pqO2y1{czyATR z8Hr};S9I&m_y6Ra+Qgq8=PXdgyRj{is|SOHSk@EMW=j4{;J1;i;FZkbzIjw0eO7zEMHtS+;2I5ay|+Sb}u# zESloFJ$!vA)BQ!?iLJE(hZu8+Y;!9U{`q=0kZG(Bh<#D`?0nFQlo5umVwDxswz_D$Xf`4(_zTQCN-XYFVq1|!O z{hxUKXBd%^qMCjOnbOVOdCieSfXN|_Ip8K2AGPZX5M)IAJa9O-6YhyC;m`2{PT=~K zp(HQ8KQbE!<}0acR2Id8BU+Cq`o;Y{#)P>z7nhi3>}dtZrFR5MpTU0saztCuU!Ru}ziesUfJ2&w))5k|i`t0raV8lru_ z=fKP}qz`nqhMncoF%p_x&@)60>(e3V_(Qxv=Fhxu0oPaWQEYhvI zpeVj~dct7}WiMAxldpn>;r*5DzXlxbjF*Pzs{yDA>qGBU#<6PH7;dLMpwN zQLX7v=827W9p%mTo~MFYisExdHFS{hFT13*+9%Y%0pWJX6Ry0iucD(6e%VfM`9aG4a@`ho$M| z9lGk-gPO2$CetA_9Bxb zxo_gRm{Djx*R>bT147T>o=CDDztmN5p#!=$SiJ&Pah@T)fO~D~h-mUo?A?TgGF(K)YSo^I7Le{J+`XDNOWL+^Ly%T0A@Jz-Z)1+Sd z3`Sc5a%IcUGT64n-k|EI0SmPzW{nGp?d`sxBH3bfkiCB`+hC^xY==)DswPCc}<7u@#1Hw_P z4aNZ+11nVdn95%_U&t|mqFuWlr%Uqw1u8_lcw|1CI^$zFr<~F>sCEr?P4TQQJ3HhBXi~t4A69v-sl;hf@z% zBYo6B)bVS6Ql3C;FRt?l4Hg3v?_i~a%3X&)-U}ql-^;@Jt9tt=T^DX<`Xokooe>13 z{9uSvNqmvSZ-cndhMT9U?*e%!ShVf402Vi%x+$#C+tbfaeaYE@FZ&*2Rkc;CG(M|@&-<=Z3MVqUt2cJ(oN*7&eHXT&U)m+t^%V`|NVoz;bbVM7?=%!WeLs`e8j3oB zn_!Vc?wT~rdvH6ryO;9Xf363@hK)o}ji(L8d00>;(6oYA4rnBt&E5owi3-3SoHlh( z$N%FEC7Vj6uvOa22#@qcAA$D_Gx7k7G(Kx`+O#Qm#v(5L(kwmB`plu6&W3;5Fiv7^T3}sRqv!fr z4G<%H@mWpLfRCp2?m%WYRPG^aX-)3^VFz%MrubtdCn!0%MXLek@* zJLix3>vSrD933b1Z#01~wV2(T)-Nk8>pdEX+>ycO6a4vPbbNDyH)+?Ef^uGIG0C=kvQ!3E08e zY`z%lgRhO|>$3S;Yrc+|uh-3&GGEKh*B$fqlKJvsOUSY>HeZ~N@U_5v1>>t=A>v5p zH5HZ8!wB@)k7M8lNh9<1gZTX>%m0j zOUuhxO2ocD%~p$>D^4MKi$%WZ^SX)g_|a5D@|7lW?8hHW5yf*?(L(ey@rr-~Eos7n_R))rSL4!_JfZckhgBp%M z@W*?SQm1UCD15FL>!Yk*t{ytodYwu${!)v51fCGL{Q|+@)BuCvHp8hQIqB)!UvskW zo-X9TRw6lUiYA7;5(ybP;c{ouAS+6q1s49xvkPHP+hakU(@F%^Xl7Wa3Rlsn6d&cQi-smvV_qg^m4$iQV2m7Z z5c8VGIPz5rP|;|fce}XMV+M<<&uTMo8f-A`cEMdG z`feAuoDnV>y8h8qb;p83?2zuhu=@D0UN72XrrJF@yPY8b-!mEm#!N_th90}FPq68rSB=Y(uB5{KIQ{6f9RRpNZHuco~ z@}&sTa^UYIEP2DhNBO;nZ*GQTfoG4J%8JEa>AjR8p_)CyP9_ z41W`|+Laz6 zXf;QmV)nXCXbp&6E4hJXHCqR6V1X0zpuS^e7Yu7F%!YS|-ezk%RhUE{35L-#DhJI@ zA9BWOH%|p^lLOkrDD8^a6n;Mnd%xhG?j9^cQw!WfF9Yl;`qSB)e^4TS2x>>I=n~z; zTNUuGQTX4w8{vO(;q@_I^xRH2`8>7b-4fwZV?JsFzV)-6>0R({XTJJO_s?^>fj?9P z+EX_u)N>@Ge}fNH>J^T1uV=BHC!i*F$w_PxkjORxPqpGZ5h?ULwZl>wWVNC^*U#|W z<*45=08WU@=sGM-^u~MY&;$`-zVqES65dCRi}P_vP*mqNDA~Bq4w6 zAevX$ImzUIN``b4J*#((#V1~^>4uhC4I!@TJ2|(b2nY+F0DIXf{U_U zo|c$Ea#j7^a$iSLuW^SDSQvPqwSQFmK^Jhe^f((AkwFfwsQ;^@2x2y_NHps+C(Y)hx7r_iC^ii*k)O7UYLPY56Mf({whBzRcX!cbLCZVlh zt0k+P>a$C3jui1VBBOLoJRSpCUx%z}=z58m=Xc|VuI&^vp}?`Dx2)DvM>q`a@$r}sk7+W_7)nAc_we(4oYj zt1d`~_xbQDhBY^(?~oatMRemuNT>VtCUgzt_%sAXj_zpW*s(nFnY~Va-&s7GK7Ad< z>l@6MX>f~DZ%@nkME7CUgt=w)2xiq%;@c1v>HlQibYuFT)>0fC20L}#<^C#Z;g4yR zD2RF<`Yz<{@^k;P;VC4H9$G$9ViA8(k1i1WFC4%=E$eg<4XULAh|Eh0 zvs?D=B0_x6%BfvMXwXNT{q!T$t5FKYXiJ!B=@{Y0juCQO7ty}PvA6!Ej!N6*pIt;l z+s)BJ){DV7v;hS`IsS=6IkvJKg>QnZHK+Q6FOZjs+(u*`k#5HebhBgPu7x`TrY&YP zojVTOSU7Cva{J;sBDXV1Q=HZ|Sb@pnb#nQfTo!9C&Ss#I=VQcx_-X8I*5l@O<^4#1 zLDjrQZ?pc&R~z)-9JQ3QwHw~qJ1P_kK#4zPPg^LbbrrEyBQ^Gn`qMQ_*pY%g1(vB2ZPo00vE^fEx?&x zz|k>R9mmK~FbJJNy$Zr@zJ-2m<#Vy3uFUKvT2_tZxZ*a#oKp{NlG)uT%$gEmY84A( z$p>MouumFcVnvhK<6oB*2DWR7Fkh=Jz)_f{+TMmR7(gvyw2_NPxYo!gV?}(UC}42F zAnKX0)No^*s}US+DI3h^bGVA}RIG^hy&xTNBEbJ1r#RxE<(q1mY#%44rdM1IARIFO z3!b$mmpiW)Lnaa8arXT~kCt>yCabGfG5f|xZU~u=o}3!TdOFBNIBW;A!be@vE%*)# z(Ur)JK%%D{?8vD)hs~a3v?RLtz91WQ7wwyWu!>#c4xXTD;-AU5a#lkenSzO_TnylO zYRqamzdPJ{HQ?RtE*hn0aQ?#lQ@D}|zJHBsMKD48p6V<7rW%Uxjy}w9PvsuHqw{9g z(l1sYCF!YO)RPz*3I?LKDbZERUgGTGwY2%_G+;DPO7EKGmQjk!Jy~|?A?kJ;Le{oy z_LRsp0ZN!qjxCRw&IF6Z{u+O~d*c)cHfXSFw(j>F0J5o%3Av(&Xj#3}O=#KUSk)HY zX>mnpagjXJLnQRbMr-3!!8g?>_=R&y?sFJk{WG8DaSl!qqxr+_Se3#~ZGWvjLIf92 zX5SqU3*YiGe9On;MMRgw*XVr8Rxwi7#zlN0KNyj?B9-}V0UQjv7Bkq-CrH7e134Ux z7s2U|8xAI3_rgleW}aa)f^2fgCeg6D-p-N(918FobFhhhpm1S&*IzmRMvm5|j-xE^ z`G$8x!`qL%b1VAP!GpR$K*n`tn7@JFGCe^AcloGL7tn|oVptpo45i$N-6wB8#anJT z3@*cA06Cmb5RLmjT$aP(6}o^E42NFiaEcr{fJ2fySKEHHrPP`QMMZHLe;1_&XA~9j zGAa8jLxk+zQ-n2aib}=pBy71|(89I-o}DVNwGm8M;7a*QPtnHa1pSeoVwvsv!9qUT zO9XWu4gWO^D(f6~9B%I5L5qpH2j{4f`tRYw1_VCLk78e80^Hrb#PseHN__QtS}QWU zZ(*%bh-JLur`B>7E-_>hTBG|cxGcM8iFe+-W4ug`bBSiv51NE0S|Q;!CiKd;Tq432 z2Z>L+M7xOxf92qCOl^X;jJeDw|D$p5s{L;jPtP!xU?Putx=T&NG zsQG9FSPN``8Hdi3q*micAs+sAzO6@|eARD-oZMTqwY7zM*7X+6YYY!#V|TpN5@Ow; zSaV;I7ki6X+x9_1HtZvo)ZN(v6xPap_Cp|Bg5zDRt>yA?AJMGOg64p|X~BjsqwxOf zef&-Iw6~o99cM7uVLA!dT7>OEK*#@W?n~jCuzWRRnT+f!!s}L}0SAXab^x##3!DPW zMQ8WOdii``QQvo+T-#TS_dO#YN)!`B`vz!o(-K8+GgmVDh9?0pvtY#5r|-K0Vx7K^ z%eZe(>jrH#N*1!HzX+%S9HJI>C3QCkh!;Zv^2bCGYRm7hDQb<;Tcpi?EYlU%yrdg) z3}Db%{bndnD(|JK{Blvz(Q;fs6nud(1Z91lhPB6W58CzaAV~p|7HrWY&F$1`pa|xM zL}ro*Zrq;U-UkG44u~Z*$?WsC; zq^t&>0Hl=Bpnj(8@~wVgUndC8(t~zY)G(Ibnc^4Z3m+mFzy^#@vn>{*HR+FDh4C0qx$D2M366tGm(YP_%t; z19~WT`EK2H|6!5g>(^rOu8cwAN#DjFqQ9`K{PF^Lplh~7SKN+N=A1Gy zCuOxEBH#Cp{C)`Ri*qt)sF>6+x{>DpC7Osg07kz0JQKZzgIyz3$dq0}ZX7CtZGG_L z_)u6(kAG99kzT;qiS{)QFvvK9Jc7w1F;iAa5e;lV^b|58Mbx)_jvoV3M11ug*EQ)O zv?p&Dl5Usprif0qwjlUEMbzkaAz1kAVLw!-F+!J_)Z4NMuOmafv~{F4;6`4KS_}yO zPRN?uzh%MF>EQGPYv$d&fH!OqO0xKDG%5ii}`@;_^22% zcnwem2T>}JjpA=wOZeTAzc-oRg84lTzYCv3!Z}DNzkgIT z9`wgKtx@bZ`gl8mO7(ai71$RvV*n~_j~{XT!Kg4F{$NyCK9cLGus8XGQDNixgHd7a z$vNdQ(V)k+I1Do!$(;T13#dtBu<7M-d^AXJB&eV07s;|O0TMdaJN^^Unmq8V;m!%L z!85Sl$3)nqA%M0!uA=+<`VyUo!WDZOt%W^CfA=l5eVN$Z6j;m|A8BG!{| z{#2(y%R0ne#!$F(TP*eNc#VHNnZ{+0Qvo=^EiVrj4SloZw@9i}@aC(IeX@7mImI`i&6L-S>W_t8X&<4z7}dAN4s@ zUktSU8ta;sHH|+wtM%d!R@See)|IsaKV8Q@>%6&4)?V}oNfiSY&Q3`VwbmnAYc0?wgBpZ$rHCrA4s&JW$skw^F zk9W^sN-do2!{Q(!?wneqQ^P8eqeqGGDy!(1kQSFh`Q|9mG;Cxs^&J(WsdH4I$rEdI zxZN%4HS+o>QMYDLG4(lh1yd!f{##jZv}jl5+h|bpG#DjpC5Mehu+@jXOBDMIsA;@C z`I2;x7Hv9B201AYY1gV=I)y=9xfNLR*&LmEmL{&Gv&vJpm*lO{qEVeWmN>acE zyAW`f+hT;OD(A|Wn2E4o2lUC7;}#I0+%9v+lB#s(Uw3#7LTEC$4#_D1w=j*1y48;%$CQMlD&)V(>&M-r*wNZBOS~-IH(}~6xn8?XdQgGhi=96WEk-syE=gEZL85#l<5;itxdrTAmS*SGMM5)6K?!PiB41-uUD%u{W8$p1|g5$U)+ zj-v5$`;_fer5?xzfd4m|_?WtzN-!Mfd2CA|U~>r=b)-8B0VD0Ea?{pAqshSEf?Mc8 zP^H?a@me=eYJ9#LtN-GLU3bDs+-ZFol_WRdhW#qjuuS)^w~BvI9+@QSH~iZw-sb7L z_?(OiXq%Z# z_8MSTvc{+qD)Y=V7R50PNuZT3zG;KJ8$qQu$%~JRUa>`p};HL;X#?uw3?jIU=J!u5;U{cAP# zDQYlnBHv8OI2ho{i0J{m5B3s0L3OutrUD)0t4`uLL)@8^X+MEtR#^(1zWG`;cuLNB zQpBe}PgC3D_@ydj=}B1@LwOS{KkeL_8ktKZ_DFrylUlR(H)= zVpEf8qGs8r5RPV6!NFX3+y_3?(=&uGkXLXOcr(O&D@6aW~7(*Ngd|D3&wz>b%dF`7HyH=Pr(3vO1?Bj z1hm~v*4RVzUs#T9E8}QD+8cO|(ev-*hr&(rKr8t~oxF3ulH|1OtmN((dL-ZlLpB5adkyxbVZ#wPkE7|(CLbrQ`J9{LyUH1 zBcf0<;$Q&r)O4r{n*!f}^@5gI;7t>?<+N#{{Nt&R-;|^u%-u32$w#||P*p3VB;T^bKKmbmpAkV*A=sbg}u7n%~<@KTi zarWwxtTJ7+O`lYWPw|?I?Ax=y@Mc2}=YKw-*X??XFq#OuzKOU9gv&i|Qt>unS0Z~_ z$j^wx9vWjsl8ESKA>Pxe?9Jd!Ny_S)`zfLh4_i%kq_D*Jnb_ahR2Gz!TE< zX#@y;-dxB!Ph-y7+RfLekGt~ss_P`JSOhb`oU44!ui%cZ0t~lU31JY{M0Fk{5(Q^U zi9$PDM1M@wVHfI}x=9h0FmMHk!5P$9?76m9&X zXG%F!#KFJv%}i0x_G5^Uf6f%GJ0FF;S@4W*e0rpD=~HkfXf7kBW+(=jwAN^??hsmU zJfF$}43B~VhuF&2>6HK|1VNtat*1PUY3J1Mux&7XA>549YZscd#SiO-Yx_1&?KOtL z5$wH3kOj7U^3+46EVe$t;;yzx_1nBAG^nDwszK@cH7G;~@CzKq8@3;V?RH397((DS zJ;!Ou9(o3c zFJgFp4o*8(t6fbZog*Xk1pFtMOGEcH5_09U2)K7+QjwoME9#`&Z%9q*@J6oGM*>l@ zc$yWMh%h}YtnDdu^0~jpvK(H2^B6)!%&O&G8Qu8CAPV}0wsk>`4KsZ1m2KyU7U_=} zqw7cZmll}Z)Rj??2(RygpPDcgGeFN$<@7VeyGY!g#5+mswtoT<|NRt0S1`G#ML(m4 zfDbZ-vvY9Bgl6?`L;GfJcR^m`;-TTc-;`&NSsAtUn7Ly z|04u1CTng9@izG2vtFqX?Tdw2I#)DuaM!xcyOiFc2n zHuIGLld_R>E~eq*iN*F{C@;?wLFw<38y9stdd=-9 zglh?A-Ua=q!*~3HCWsZ)S8B1=p!2wf;Q>Gf&tL{TofZT8=mS7~^wZLJ1@fgIpZWeV z9PBeW1_a#PbGN zJd?>YV@`mNMtxxes*Z)~K$NG$MR?w=lKVey1lVN$vgfVUKTDKZ0mL}5MB{2`z<;&* zs;-T5g{8`TO{XtbX805G<@qqQil{-4W4ZXbSeq4@vO&R>>Iq3#fn_ zNa80*Jb=WyOq`l?46pV?KS^|3qTTj(dSi(rF&6CB7}pQ*dVxa5J};bso3y{}jM@vU z2>jRRPd(fuJuas|FOvOQOqBthfMd$7 z3krbS6~LZSMV*p?3q;+7PdJdcfyfxeX{RreaE5-1;Eb_h0OhMD#xQ%OB%tznjcp8M zj!MIC`PN8Vtssvh0V`ddH<~0v6mT5S(T1@06Xk~sM1zr)`0=4Jw#t`;<9i%DZK-b4 z^5GKboO+9e=F4MC?(;{Ex{8ia*l14xC$atP0Vvo3aQD(%hQ)kVN>x>Tf^3woz&bDD74X7Z3flKLCVgCYo;y4Ti<#>dTvj~JQ}mfD%W)MSh>CREztYfSjP=X1 zAHxS?0T^Spkk69O!VfQ5K`)8^@i-ZfKmqmXaxB_;v|Q$7h$!C^(w>RXk$K3vY-gd- z&0SdZ1~r_WnHngHIfp`_6hx%}8Iz%4(5f^KQ2IT6%VPsqS4e8WofIvB(5sRf5 zwc@{&3k>CB|Dt^IzmzGYO!wHo!WdqbX&g!2_Ahkt21lSM>DXU{8xjw-Vo*d8w6FM= zO=Xsy!-r`3?gIw;{J&ALyI8TgfWuIaC=7EQsDMhrfAiTg%CpHQLe;2GV;$O6SKaw@ zRL3Xe?u8;c-AMs5LZ`q*#=pb$Uyt)4Iu1OJUB8vcz^ceskB-x8k7j7sXp*DG zGxHp^O?Rz)wPq~8^=4=rO^9`*$FaYeFCt5CQvT2@_rP1Pg7FC3(~Csiw(+{1(>0|B zz_0#6$^5X4OLF83BBI5f_sh_?H1xTEc^g{vYc2Zrlce_r z5nA6tp&9bZ*}w-Mcwr(VpM#WtQ`mX`ynr`NHtW93+SCP$VU^)oWu1Rj&CjMEjVLKt zk12BKVmMSjm9rL$Mgwm{Ro;G9g7*hf;F?|8*dcfId(1z3Huo+Ty;nx~yASKaz7Ci^ z!A~tt(P?v)??ichv8Y`|ndKFm2w!Qgo+bKRQi4gP<`nS599dnpJ#Qw~t)a zXT037MD%QWRkshV5{`|Jn8EC%hUyjoOEzC!kk#D6+4SK9C}S3G{(=Gl&r>_mqzVye z=D1v)S%2-ydakOvDG?9auJc-e)MK=eJdWiWt>=kQSYB`^;s}Ab zb4HCCA-!%99((j>-R4tpaL_v#Yk4&!nF_a;tAVWa3&z~ZF-vy)?>aHQxzmHaf-BX9 zZ1$pP=_}=s7e({tHEA@K#AA*yok9)Ke{)oK8d`3>%XU_N@Snj+F^O;U;bP{OL>IB2r!z;qBsPYI;8$UTxQy%@g}=ExSpIsP6#!Ce{y}Z> zEBY6ZHhUS-I;RTo>(!UVitws9xrp*-Auh?Ai9ui0PDJ*WyS9cwP9_p(!*GOO4qYmS z^uXcbxO_l1 zTPA9RcQGl`nDQu7+B92pCr3AfOd;|ZkyquD%S250NdO>A1;T$IT=prI<%~gI!=Uf| zk;rG|StN=WXW(xT&UJ=rp%a;$CK}{?BL60`N*@{jiiiyV8xUmGfe5^X;iC@rF4a|$ zK?V?sCpmoZP~@gpkkwKHKaMfpimWU)G z@?51^RW!)PMD`={Bf0ifQNLeZ?ybW4I*I*g6l=8}SG>E?ces<5jAaXs0CJlG{p~u| z=~xnc%~d;`n3E2GkxreAmXeHwvhs4#sKydx0!|qS`|}QCUe#POZn^NZ90Q0xql3^V zJfb)~S!5mjs-sOj5;v$e>Ye34smWvqQ<1%uEhzPH$6FPd|0LO#mc(!M0(P|iE zOCk>u>6LPYXcMsw0B|fo5T5ru;WNu5`q&^(5UJ13J=#;=Ss~)ub~A`sMBHVnhsvbt zZjg@=`4^D|2{10Z{etJZ*Iu`k55EQkvJ54@5sm4OfiLbEHw>~ok&TI5Dfg}v2@%W+ zi9SLkkGCt~-E<<;Gv*lNaw5AC*(gCqND)$L-*Fp`ICD6^Ek{Z*E^()c1p4(FD94g= zZanigY<3&uDI&)aIg&`v*hE~M2$X2h5Ug5%Ui@~7gJx6Xiam>o};c^BUOe6xZunv&xUl%dGRsjI{IR1Ij zi=ewQiB=or4k9rI;3@(j@wgi`dP(CFLxNG*@Yb^FYSAG)(9jPiJ)EbAe~B%Xpn*X~ z5($SroORN@T8tjNX1|u;umb!i!UrNzyW6;CR2_#&q1PmL)B>3DN8>|+)4AYt=M;R( zPHUB|4_KlM8RW2!9ID02xHa&$?)AmvB5Op=0fV&BgIhsvsw9{sy>U*nC^rowuYHN; z$K}2YhMpbwTNK(=s3FJQ9;&{!VE*Ae_l%x)uv|R`JK?7_qVJIRV2CGSVzG8{tnC}i zhQ9Y|8RKYbS8W{mFV~VLW6JkF3j0c31YD0ch+EHv3l!0C1LUGNFri|*BMIO*Q zJx-O8fp?FE=oKR?y(J=icgikri2&bKa`0PN4c1`VdKO7u7o^38w%(Ui7id(VhlfGg zc>eA22DQe;7V0ZFaR zTe>`59&>&6v#np$hVb$PR%ua)BRJx*B=^3<1Yjj}5;g=9#}%C=izr>Y$Jj33mJQYl zXT?ZJ<+k6))`aZ3R@Cmi?V6tt-g!;?Dan@IBV*rTev8zA{_f1fyYUlKL&F@ZIVoF3 zUSsD-I0@MMufUvm8T^|3@r8x01T0odmsLk?03~JPWpcdmiYwk$g7%BGA_(CwYORRv z5sY<(`WVw&A>Vv#1moT19vA?>PKi$?wJn(E`vre=VH4&F3Z>|#|wTFQo zA~uUcXVc>xW}F{@Z1FY*>4qBV_?&=8-xiH(|ABK-pst3Xkz(p)M7~PuJsRnFbSVIz zllnzN{m7D1>L^m*BlQ47U5kL`>qVo45JSCeRVj7B6&nI^(5a8$Lc}m%HT;{RqTL>j z3#fp){NwlgQ{fQU?K9R+2}~u}Yj(07gcCevkV6@LLVC8PElSRvXYA{07x@f)*Rl zZw54jpfm&e#ei;opAOg<10!RkBm>pofc`e1-UM}dfLTX^niOdsagF&bTDhfASuiS|1en!iHjiP?5?i+xD zj|X*#8;32EqZ-z5!2~3CL@))zdHKo_hbT?(}fg}v|o+MS2b#Rx%c`o3t@=I>MrIvl+| zO(7J8mg*D?CloY}MUFn08VuNQ3)ZTGT=+f$>DI~3?~8W9%P^-i19D}J2P^+KITj~e zW=w+mL>9d-oDqSqV@)_@ESmrXQmxuD%Y;aH0~Th_>J#N}4vcSS#klQ9|FFsU4@6_z zI{bLz15t0nL?CuMQ3(a>VN+rRJf>XTNSg#-BLu&roS5%$636=gLi@R`drif?`EGm=F}ue<4rb(+{Q6+Avo>N^7l3 z#}R<@;7}ZOujb1En?(ES=~Ns}r9+Ge@~YQP%1xqqgY|5pJP6;2)}g_blY3p zvdPPvM3374!}M4%?LJSrxS|q{(Mw}L^}9`W-Yn|1`dBYhl5la_G)Tm9PJxY}PDFqo zrufkoa2SER?k2dGB>(9f(;oHnS)V zQBC$ok#^5a6d&e^=8;Fo1*`d_Y_mngH|Va`_g~ z!gr6%-XdzHzrBXpqRJ2#k`SRXkQrp2)d8~!-gHG@7>x2HMbO1L6QlqO`2bia8>YFy z3v(O0Mc5kW-5p_Ac5u^z5xvJgh9j~({MUYM&yxsdPM%r~qZ8LrVk4bPDfrDk6w&=h zJj+Zv^!f&wSl+1B3(6Q=Ra$8wwgTpDfM&wkeu0MZiMhe3U59(F4d>|QLLa?flD`Gm z0~!y9BjkK)!X9{GP$K)JvtW++9+>y~fULd$uQvIS&0Zt@_$q26M{PmV)$7E9j%eH{ z^jfSI^nk$pZnZ>>1esRP=Co-s^zHYu-ZP^8^bCpHTEZOxFvKe+vDzZ1It(->K<;F&kE*cKpdXV_t+0FSJH!f0z$hGR8-s zI8a8Goc|GajeEd`J^;e`eCz;vW|L}+8k>XJ7M^`HyWg7W_Vfw>o`C~cyAzw^NK&68 zS`V|EfViI_W+OdlsK)`~#T2PqUnkHrMteTKU7qD3i}hbe%50m@LyP&o=by6kcG14w zU$ClOSv=lpwYuN1aDs=Ib&dMRQ9f*7uopkRf?Ca0NilNWc2T>+sD(%f!FI^cwu`{@ zO;kFj)aLP?bj*%1TMMadBXzeS|QB8f61mnko=XmrqPkr0Oh`B_j z?-WVthvqZi9Cd+Ga|%pk=f#0dRs-ONis6jA0K6*tF5#Pt;eiG|-=be$3>OAoljA+; z=N7}M3h)_Z=+o7>V#JpQ5o<9@EQaqh@DL2ZWYoSGzQMrTKX2fH#qbvmd=k17>4kx( z%|fOZ<`~$`rn<0c<6P-@Zvz@6;ROpwyXcSwJ7&SU0JhZ1Xom&kp2qS|Oxm>;j7zj@ zP&E0yXke)^sIFKntGV_q?wWd{z`8ZERzBKbzV0xIux+h_&~M9;yU^M^KilMUyRgQZ z_!n;X*ttt|s_`Q%SdI(XrjS8I6oEF%a}v2?oq|8!2|%il5F853hiQRqTzQzhGOwqG z<1WgO30c1CF(4u8vAakKxpcQ^(CRa0Xng*yJT4yG+lmDr z1ZHPqTPq`WsJyUSH1dB48c*^hgdhWdX5iQ(!f|nF%pMVBtM#Kz4&Ngh)>-fp4oUCh zcw4483$bw_sj-l>up<&*L}DmBk)ttmehDjmQ$TAtM8Xqg zl+{gs?nS`&?^8-AlTUJyJth-AO3-{p@no_#n5wYH0pR@^OwWSXI`M*8a({f`=!kOE`o4zv?94TIt0ahMj$Z+ad~+-Y}Y!{0@%#`98WI+fTo zd0#*vG|Q6NWy|-LP1BU4BQmRm<%k*G`6d&@ygw7!qSm#T1CVXOKV~3s=>CgGbr+PF zG^a_+_-7U=6to-wKgzT?^3L@(p1xRB+M^%`+nZ&*gtL`W06KS&^JM50PAUhfump2|6~E+;8j5l!y3>+n=%>QJ zUo1#qxdxzczoBq!G?9CFTPjNvQTVuZNkAP#7Rkk8q^CcO5_|RIhPWt}8Fwnp=xn$n*wm^_k3IX?zZB}Wzj5gSeby&4ypwP=Zi#k&z5OR_ zG2S%62-Q4Qs22iotEB^s*wZy3OJ%J(`691UmTB5vH55#=RKLVU$m~d4nAzIz)Q;f-bJg-jWAtO z?>#PfdiOQG?Iic?$Z%<%QgWskC?s2qW_N|e9!3(8LCtnSM z+R+5kW`M&r=$jl`f&)H(GM}_u;63W>qnw&^S|V_#EmA)N!b_{ptrqA8Q=5Y=I1+M9 z`3FgPK!l{faYSpq*d*C#t>Vj=>5Uf`_pqZ7T`hi2i_yDSjMS%88bH`Q-i+*;TiK2I zS9S{mnabSpRcJ%_KQe$8M)m}~K74OF(c%|ChAM`Ik*E42O}o>cK7NHw(E8EU%twfN zsFZnQmZeFcoS!XfHcq_2IG0I6_@$24)g_$E8p1RhfZ742?xvCPk#j>vrFJ6x5Bbq&qE^^JEv78 zIG5k?^zjrT+{W2NbHM>zdE+yj8t-%7CaZleYSpM#Pjki1kI-BjCj3}-{#o0` zSDbh0Y49W|vx>(b`_OM~a>pUj-%(+@wk2IzX_xWdK-I%|@TTrzq-%ayG!b_W;n$$U z2sXdOU-J%&hGIK^y$x6(hj-Hv{4>8|LGf-7W+Un_PyTRNG){jS6uiNY&Kw@;HEVtK zY5)_m(cp$5kMr_VCed7g6Wy2F!9)IIYQx?chx`~y@@OsY2YiWoExFllVs#8?wh39b z_$A|A+??nL8XnZ|bw4_7C;_1Wv^y>r9uakXzm;zt5e-`OvvT>RHZn)fNFRWTh+BeH zOuqWNIYojuEa9@+Ckv3ke~nYyQGSr{pQ$Kw?W4HiAnI%QbdHMph+QZjSE?Z6 zg}M;=U2LhfR70IHR@}!_Km5di`CXwyy$p&jeyQcU*i)grLXHiLpTUxN8qTuS`J5F2 ztHNFmzvPr-BCPNEFH06%@J+o6h()x3sg4Ko! zF1e!UW7+QuQK#bL16k;N)uFna{)KR+KMbL@e(`=hnsm%7qYeHcG&)y{BdKZn&^E$H zb5v79nmPt#mBtvdOVtcnzfv+Ei!2(#zKA7}UOnh#L$M*`X%z?|Az{1h%4H%cJku(@N#9qr0=?%6_p!D_$Wspm*Xa^$u#4x!Ia>%tOM8&q< z8#6C>)KwsjE-S9?p(6Zd!vK@YWtc>OiM((^#MC-~)e&~J-oqbWoDSKp6BnK6)hW7eiltFa8Fa#O-WT!jdAWim2vZ6jXdG5 zIQ137uVU3*@8#hhMO$F5O&-V>bwunX%9D>9`A$mTlOnX`_7g@OTq$0?2>%;yi7&kw zeqqsUCq08`nK|fx51$nMYD6N1rDZ011c~IwVAY{!1EZN_^(*H&OEZ|m_&!Ooa?Zo9 zr23h(=sP5JoDwZ+ttHg$$kIk<<$J*85!dgOaQO|XFISxsebPU#$k9=6BIv2>A!Nen zM2@a_+^1KC0xy+Gt~1M; zChE_Ua;0i;ak(zC_nLBPk!eNY`kfk<8M2o8fn)JK z{nxQ*Xa$THixCB*Qst*#if~)zF`K;cCC0XzBQVO~-uP@BYJd%HxhSqa%^5aNeSx-G zum<5CUc_1Y6b^y}2iNMlRGl8Ds-1T})}Qf9E-yCOs`>`ef`xSF#xA+3DjUfAdOXZs za!%cwq^F-c-umfai$YI?6fExnj2Z>JDm!jJGG+QW#7KSrgjPUm1rFB*VVqk%&eZKj zj&0zD&z(E;CoOm0o2y>aS@4l}&!S#nfxiV9@0I!YT6hY-GS6F^LmuaIhL3vG zBBaM0?4Pp0JuI+3{eo9LKQcnJl)b+eEnBQdUAUq@OKXKTe*>l#hK`DOa7a5-&bV=9 zM~Q+*%e7yN_!cjM2n0A@(Hu#2Ej&Q>_cZ8(YhE=$`kxgI(#IHetF9BNLH~uf{j_)k zEpSr{de0a5=QAARSVy6`d}7K>wm@DpGavGIcnmGf^W;M)zW+kblWaaM(Trfe zsS_*lH##&9R^&6Y(LV$5L*;N<^f)Txx3&AX0zDE|QetA%#DFxM|4gsy!>4u~1+XvC zsnjW?C_Le^yX}h)+2p`;qEljBVa&Xq7}>BA<|5M5VfLfYrT?y64zh0hL8PX%RK8o+ z0Af|ZSCa9OWVY)e3_qWuP*S`_{nj~1Nx8l_+s>Pdh zlgD8rJe6r7Ys%5z;@L5E-#!aKoM$NGR0Q%=?*gp)BLAHqu}1uai3F_~lo zARzzhLkw+^D4Kdk!}WHZ3y2fn!{Mj5>pG9-ZH#$rWe~XX2Q~!jl)r!o@%YbdGW-G> z>((b(xIFbLrm;BB3>$P2w4W7^d@_dWeA+Xgc;<5&k50hyMIO$V(V*2;u%}}Iv_lPT zdD145b|YvDvN2Za1Q@1rp(dyo3Ao4uO6 zc|p{4WFoEJrA~Vs=Yy+#C+ZGMFw`((EYd?51`Apv!#y>TKTPt2??HSt1M;r@Z|aqx zK0u#S!99$zC{WN#Y&SSMmyLkT7rqmXNBnjFKHS1Xu%^n>(FPT9g*mVHPSd+MiB+gL z#)JE3E;20cYQy)K8ca12KGnc~((pVLW8i7w*!n#s%U=|sjkY?_XK`TCd1NFTQ=Vd` zOuO(E$OgJ4vj0UT_WU=i6&95;?9x{Ywzo)%@5d^++elgH=#;LE#=VJjL_lV?ta0uNci z@iv52b4-2t4>@Yfj;Hj7j{w-?_yj%2%UcK3Ahb#5JPyg*9gp`+Z)z#0-_1Dq8r*+!UM`eK)Ox#d0lJ zQY*!Zy17@E3EQR?w_r5|%yjoEgh6ee2u=3(4CO^oML09T8+qd} zI@wzxVM)fN%l3_Wv7e`wpaYgHZ07L;;~?(enSDj1R2zv7?in%!H4}s}M@_pcuUrvL zJBRMVQwAez)F z(i2Y($o&_Z>rU)1?zPGEA8>B(q}=m^2(9|c9GI>+Kw3ixE4JgW z%9{cxy1D*uKFfvsZU>*#<0#@(a@5YArnop8lytJl`76W)L2N0(a{0d>af0b-S^Fo^ zu-b0o^=(vx?-V&d*khBue-a^L(+MmnrvD_u{5w@($vD$FQwe0T%UpqL^G`FXnAlky{aGdw3}nE$MFqXlUIR8HNA}p+xBp( z%z75|mm%>nyme9JoVgo>h~%oscJ2i=2L7mY6jqR_6c^Lg#Kk<_lNFtiG94oBMxUuqSiwMh}U_ji>q&ja4se zX`e?6_VTQy%KwAS?7Y57YcJci$1#pbT-U{WK;QaVB-fp8;C_VT$~!zt%tRPCM#%~a zhp~Tu!&rgXt=(z*fgUqx(a~(Q);&8$Qmj0+s$B7gLnCag@D|o*eYqma)t0JK@Cd-w zM+3abs5}_;)fX0m`asKysgaj(qU1z$9BPa7QOgX5_t)pCo3|)k62^Bc0__q3h(N>W zj2JY!J8=sA1Z;ut6rMaDL%BG|FpU~yzGhV;r(Wj6fARJEl>I9T`vc6SQekI9^n%t! z#M&ET9kb^-h-O)f2y*!Z>pRwH4h~h7YGUySB+Az;9oITzdEuRhRG?Eg=s9*f&Jl*d zSHifAMhzybGr+-?=9V(PQ&bJRJWwE-HM@fe*a*Z0$PtK#{PFN7H8=-01jKMa48+}4 z`vr5w*mb&+PhhF(UBk+(`}=)tI!_E}m)$!`gy>c>($Ks|nm0&u`#0vHV+Nms{iyPg zh9ir%A}qwCMC>d^VDW{zO(@?xD#6EpVK&M_g&r9WcfLOC>7TWQFxZtzkO!zg)u6lRS2*XFtCm0-y=5>g%}G0g4?E|o)Zb*=LfFb% z<&Z+rrun@88AeG^2#p^WG11f0ub?psgna8HntXk4$&U(gqf4ko|LM(Q=BahbJe472 zKBZy|zf&y6t0k0W#h3?ZyWJ(F(7qPbkqb2TnKgnIGSFk1Xus>zR>!NO8{A0R*%)-JuS9P*JK!nG> zZ^+o|qVXeH%`}C7CXe0Wm5~q?4wn3ZK0}-M<{nLu)=VR-Q zR{S-v_WpUDFP~f3^h?2yvLA# zQv`Qvwn7h%9L+fAKE2t@9o$9$h=G8-quSU%U8TY zru-&)r9aZCsAxYZ=VOB)=`~$M9TBpuTk*2F+%K?*adRaA-ep?4d^HC!HDVERviyK! z3^`SOwm{R*BK>lUzOUwy0GBeu7#xQ>TRZMGeETxIwN836TVw)C6ut=)0)t#Fvs70S ze3S=X{r^IjmJMcM@tQQOcF#y#!T*pSWPKtId225ctbk7;PXUh_BJhM}Oj-gfAWt2K zRfe@RhpNuCnBZMYSPv3FlCGO=GWT~;r`hkzO@c*85Whr$#bRk7sWj}|c?h^zoRF-( zmj1V}7~3LS-V${~y2E~h;gn()-&k2}=|bWp><3|WaXhuD3iwk#aSN-+TeQm=Wy0ht}tuv{`A4m$)D3B&aU-i%6#v2x_+VQ1U zN3o#(3vrqSBMr7G^VED~N#Q&LZLTQDc0F2G0cdoGfSCLrX$fZi)%Z zO;Ji$T%KC)!k}1NKKnm$BylYl!RT6e?AAOxoj|=rdivGFD(N0NsZo>1{w{K1Me>_H z_D>{y&}2=MFWwe`O;19N#{G}2k{%Tbv?1qleuuy+j50?PZbGX?>Wa+2E$TGv0^-F9 zzthr1{Pjq@4R&51*ji(#@#;{8KSi@fzoRgV6K*{~1_!3|VT)|U&vMY8BGh-2eD+UV zXAt#{O@8pFNa$Cg4fP$gfDIoVJPb*CM(Odu1lH{NL3i;-0rO^S-R7uPKN7~vv-RB_ zD-Xk=y%@(uVWh;|5n<_@;O;RFQA-nl!TPtXJ~pfpPw3PAjjw+Q+CjmWXx?6|J8*9} z+Cu~cc@pD_`aD7R-8yx>alG*`F9c^c#h8jSa z;u?7da#-uoQXzhY2c{s!Vzd{3eGn5q+OUE{NSE3E{(9`R--R*ni^0iaQC#mEJs7XB zg<)#_4weCK%f&hutUW!-7u?cJbeTraMVZdUYbz9eF3Qsv?~mBWf(4CPi^mS|U?!zP zwgo5uPm+F@U*8qYL#F|cpuq?n^$nx(%yhx(7YsxC(n5?XXVf?u`j==H@%f7n$jf%= zPYFxvU>Q4OoKtl-lzx?|ABG<1yrL=ybGh(|kR;MLd+F6P6x0ZY;&t#%t5i#m+% zp-K2YS5+&gVfA~3OA^p8N?=dxH$H|E9!Kz5P>fmAJ=C!%e1h|vs90W1_RB~${@jJa zYh!&)gK7YZ^Wg{YV&VH^VBlx&di3_l9E4vt?t1hvPuXeaA$1;Ig5HAdtr_m~M*K}E z{GUE=OuGT?jsg$;kYg5d^mqz6j<*56YPuRjSN-J(S#|ac4WM(ps16H`n_p7p{7fiU z{T#~0`kZ<@(Gi@Db}KT%z&k~T8JUR;w}mfmV%-N@o>kI;tz#RU^q&Uqt(Z1KfTQ5d zQFn5Zn9qy9v#{~^AiZ%f{urT$>d!%-=1ml6hC%?z=Q*UQD&l<(6jC=CcMZ;o!@^N5 zf7p%naNEqEcVpe$7V$USSYN;I*J)*;{z&{;vE9sXxv`+W*I_ba--3%{s$r*gE3NSa zm83OsG^iq~O!_d7YWa?ja%bJ!y$1rMKGSYw9EVgR|8MYw`CT{G7FXwNb7vhWH0I7a z`Ii8T+&H3*7O`XXHZ%Xto%#9PhILcbQ-yzWKQo(@IPx>um}g1bDMnc?{#9$s87onC z=2n26$JpVLg5$x&3Va{{f-z0&2nWWOvF@oAw zL972BpYswA*4bw&a?YK9X;_WizA%P=?ZLuY2LtGHY}y^{zM9+X!x|sq#RD1ZWrl z4@5D@#E2PKhF}BPyMR6fKQGeI=IRmDSVyoGB1B#q|5j0}9G2!%?>~S8ntcH66LTe& z3~UOuELx)wPf;KoLxK(aK*U9%U`{z7+?2I(>&eGAWkEJ?z-pR8NAl54^o}X?5M|7Z zZH@Kj3pH_T7-H{-rItf%bvinwC?6ynG6d7G@mKN$+b2$h}fMp2jypGMpWilI$* z4x2|p-NlS+)&1q%h5fY2%I+X6>T7~62jiZ8S~2cn z?%RyDZ8lrKj^X{9v5{fj8Zbt$3{6xhe}G0hqx^ECnQv~!LVJyY39NYpNY9c|fc=NC z@gHIi_c@jrny7dK``En;2>ziN>(lN5IAD#~^Cej{6#SC+ZqA~n&45}YAYu{sF~Tk>;y&-{QxcvrcZU`L*V3e7Dw@ zQ5N9=1l!mMOv4;WD?t!hdZ)QLT%i^$vUQga(fOQKtseP~Z*0N(*}lCb13IJc%IMsA zahcxp7GQJnH}Hbw?qxgJ>X`nN)!`kDUt$Jw&^GpDx!q7yQ(PW497omV?!T9asG;vr z$f{CgOYFl&&%oE6VS?X+tBh}pP6NGz;LjajZsM_C%+J4wrh-U+9_cmRk=mS6S8!WD z*3NA?U+cw^I~^ynIK0QYtNZyL%EbkZnAdzFhnqB7^jN_a06kEGvGmHcsU3_902K3g4X zo6?!cg%?d>E3z}4wKx-iTfU?5K7DFC$SHqamLOj0!OT4f}hlFTcg#Nv#^NOXa7}}f5r#Y%!~Ca z3W@Yy2UDWH68Y(3wlNI|&x0+OtLl?s3Ot5k&w1Rcdv^c507OO&1)dvb;eA8Ab= zeHU@&xadLYem3wUu`hLQsqlx;Uu$qo;Jo@@&Y&krpior`*3ZVQJ0UL!$IC$C5RhnpFVQh06j%G*AC+KV!h8F&q|Uv7 z7G12qsqN|A>G=NOulROf)@Aq@bioAsAmZ`0^PptSN(w{=%w025ec`-=G%eC;UIEol zu;b(5Sk?PTEW{iCup_=Y(7F{2g{_+s)FWUDeWeD<*U{=ok?Y4}fmnIJ^_$VBzDFQz ze?k%zDWri;$_sf|9TTUDAzxB1YIR0GY%ztTE8t}QUn4eZ5HD}VI=cP9t6H((Zgnu? z!W|mZ5V@ZUg{|?#yZD*(9%gto@6wv}>m!XMUdNpy@JDn;WHM=Mo*86?)mcV7OYJ%j zH%ct}lG|Fd$)lz(2T0%c(`ycT<`=TJTo7~L2M&EXbr~|1eW??YkbrF^d8@w0zbm-P zsZATUuw@mxL)ou7%RBtJHmt8L9GyCzBH^+2cdNIdyTM$1Ek<1>;%>oEeJwR$rA+W% z3n#T~8K?zE#JVP=A>K;}rq`V0s$u+3Vv$V3dQ<$9ST*y>#>KXBMwE@~5uv6Zh!VIa zGKSs+7yjJBrI4|HtgS6NkoFT$NGyhkjGh>hLErmnN4*$di^-&l$WQnXvW$2i=>g8^ z8!6qN(qA^x!(|}4^D6`Ua%y#i!;ZxkoFAjpcsI6VfSv_C!i@1^?NPweu6O zkXBli!P)M3g#Y4y#dos;ENrpuIXOBeJpxloE$M=WkxTV5Sra?5LM=UMHZcSk673KF zL{oVHDsk5f5ph9ulBjWgKAzRp==w>x!~*ve{j{c{&VI=bUxNZjUsE&+>bsWWaOjh{ zTS;efu35kVJDa^0BjOZV$+tPidx%-QLtECb^DfLRBCc8UX4nxGEX1=p68_@0Jv$A`RRYP&5I79DwGsfPn!8!?CKU!j8{t@m>DR zflssd31I&13$9=Qz)~w>nis@&ywtDL;A)8g7MC>57vwsIKb20MLIvht2yk-s**kKC zH~?7LOAt3PdzpmEy=u3hN|*PU)M>X^UK_x=*k;00{BHsGRtwRp|8rLOR9|A|MX?w2 z2MV|sp%SR+mUgJ{kgl-iZAkM4O2A1^3@dv(kbS-={=%RLCyoN{^Cp;Y0yj*bd9I?hg(kr7QDva=PO^aaXdYrKiG~1Pdm#UE(Tg3W(EtpeV*`9LJU zCV~(=JdC=U`ndOLxQY#NZ`))4t^IvaTE)GSRopvSJPv+S6WXB%fw&ZEBonn5ip2A+ zz+&271|G$KCXZzDXaDpF*z9k{w~c~W>&ZJYG~u)IYgUArGJ@rJgky2!0g&5O2@#4E zj15qSFJzwBQ;UGjC#MOFA1UoDnbjH~M&(h!(ECZSYf}&l9kJd|syoPPa!Ts@K>)Cw z6CRUy=o2toPXbKcy@m807ldZgCiyg|VYe4Clf4Yed5c}xCfsy^Ti!l zpUxjX1sLK!VbEK75MAHxkwDlXqCOw;(;Zln?Pu7!BsdM!ug3sS84L`FhLuNCj1k%! zQC@jMo)Ua10ju<>By3D_`CqexGgupC%jxPpi@R`RLZ#m_~(}8>gDZ%5EOp`FIIIRfAvZ; zpA^F0G(UtNzMYt5(lwZpYTU01`HT*aEt>~2aFYKMQn__8)&z$&D%9=fRbY7x*0TNO zHQ!EN^L9w=%^0gMYKH$B<4K!=NmMal?Y}Fqx2qHD>^6^Y?ZkSH`=*TefZLYVoF+SY za{&l;c;NFkY{d!?W!Ja=51>5aH6t_DgpiTS=*$y<*1I$7)iMgD>UZa!;A1*7$Atae zNm?}R!th%^?Yfto5}4FikIP{WGftW_o)>$K_kQVg=kj%!X+*()g(3QhHle2QPFmQ4&(}IGTqzFn2fDC!?w;@Q!4%(Z69u+q*~ z5;0A@o^MUnc!xn#%XR@SmX=D!1c=l0L!TtZrB%N!v49r=_;mDb;2wVBQCaQ_Jj(V` zxt_AzXw2=bR;&H=nySIr{+~`&6aY7>c$u>9qpWp&awuD1Zk>tyxk6c+&>irQu*DMh zh)=Rgg||=kCAo!&)^ggD{xLtZ|)l~7|z`)0TX)qCYzrFfD2=JM+A@tSkfC#Mik(UmXg z#)8@>2EuX_ff^F`RDG|~Py%k|d%LlTk==lZFiNIe6({gYo*-7|>uT6Z8Yt?0ze;jA z9bgnK0P9w`4zi9=pVQ3XA?rwQG!Mb4#LDEAIy-EG4%3^(Ya+zu-@ zOXFIF&<7w_`p}vEQ+fPE>BP>CB(d{iHN0uHi=`Mn3WCUJfl4RoN-ID}^+xJy4okKV znuZcr;WTI`D1q{(sJu3@1DPp9SO8Gtva_XFm|+LgK^6Hwup-KR>9c938oqI3niD}S zL6G`37q<5i7lG+$bR~}X+e@4mU zp2&=LQ-jf=*ySZ=zPktW!;XzNdazl&mq>3+P8T0T^7o)L;{Ceh6jE#$n(hv(pCgm* zm>YnCu|1jpoPuC-px9w)RFba3pkS`uA_UEapCc#VxcyN4gO;P{?Q#(jd zok*Y)d~;A8Rfd{+*VlAxv8u`12Q^i9CJW=ReB-6czfb%{_9&FL)D!ENhW#Am!j+SK zTS#?BKb(w@S7H|`&T6*rg?=2XDWXV7vslMd&8n{uYH-*e^~h!bhio-{A?N`03vXHG z;j7X&z~Cpm{qf zgAlJk!|9-9vOItOpJMo0#l$qicnXE!wm}Z!H7eih9c)yK&GQAV#F2kfa~i$35|V~YzhlHV?}4bJESe-R02NgqlWOp+ zuE_Eu42~F%85;UGjX5Q%P#u_B7DI*pJxq;L`D5$v((6c!gJSxryYxItr^B6D*_Q=k zm*wWZY(QlB9mxZqJZZP1arp_5$r=VVm1NDL8pt;hGi42|B^doLin`s)!~3ze=C{$d zgnq1jKq&lnwMgZYg9VPdnt4!)zZRPL%6=?(;v+CUYRk+JB9p4Av$TW%bvyz;iCdV; zvX|lNkYd2$l*hr9MeIdoVauQss)3>t7yVf5@Dheo~JoCIkrl7b8Y z%rPaF<{N)Xh_uzUV0z!X?n-`dVLZi0D{FboEi6YpAI`jNpDZw}wy_kCfG6g7Nz-7p z|IbqVV46yyg7%mqR4<~X_#_Z4Z*Cb#oP^MGy`}g9%cda(GQ8og=B|mLsd|)JHO+>4 zQ{EZgHsFIf#e1UtkL>c;Qz4Q8l}SGFe~A%5h16L{%`Ugv|3Hxhf_DQv_7p}1fYZ%M zE&f8L%aA#tY_6&|CrIc(UC|9R9C`00RlkJSD6xdML}Rt(@WLFrVcomb2MDU^#zyq(WHIX)82K_l3HCAJu_r?C z3*H*%1K1ez#>a3~=>Rrr#8-&Qh)4gCvuP}-B*CuX)GhfRa{7;GQ>|DEL^P%$W)Qykb+9HFuL)|K{yp#y#OqWC(Q-@jOzz*0rGy_P4bqM>}*JTreFlKH#+%3DXW?p>dBEiuBi zghiJaW{0s-_l$w$S}{*fN=QEVydDPVdie+ujMk8R5DJ$Ayx7NIj${Eor)Z5z^JDuX zN-lw360O=qcosARA5LndAUNthhy|L*A>W4OxbJEBAm-_F0!A$MO=W8;aZB>lL2OPZ z(`YH2W%oijb4fUB_hV3`+qMviVFN(_XM;^!emp&xwex9);wX&8HyY?~^TNR_)2)PeiDD7haxp!MCEETSE~|VFeYcFZyNDfo zNmlB^4;9p-adkE&wx&cI65%V*Y8~b#=i?o*Zn5@XME>tmzRQ{(r+z};8KaLBxBNju zGl$D>0igj8BJ{oHoU>;dY3Y_EJ;4^|oQ_GHyu4$Dyv=J918o8&HD^tqnb~X`Ob^zeSFyv7BMmu?`Vc0|JP@0 zA0wi?Q7ihO?>ZK_S6?O7c38fJH76;&%WH8Y;jI>r_P8jF_fH1{JJRm<5#thj9B9`&DZ$3p={W=->(A+x)6@M zSq5QGG2BDtbsX9y2di;_LAWhoMa$?GI1!ky>?7u2aPGXn{ap`P-|*yNthe8V1nT!r zM*_b~HS_huSlglZp{J2O9RZim@qoGd2VjG#iTF!akUj+!$Qki!R4gwWlPVP13!^3f zW*BQf;MrfGR`{NXIUe8Ua0Ag9lc6p*;i#Z5f|h9_5%(t5f28Tl2hF_iaMo$SahU_& zFLKqbr)%-7(KAyrumQL-ZryFM)C{_Yo?Yx;V~$^ktuvL_I{5T(IKyL+0Es_|<+MsM zMCDpK5dOeLj6&c%TZdItJ#8RwVK2u0hD*G=qVvbvzp5^UbmYe3O0mtII6#94EuZ>W zVS>dofT@86u~m^tZw|{RWR+*z=`fF&j7cN4wFy;PgUynbQc49$QIrDBtO8@zTK9E{^*Nb<0o#MI=OW^NzJI+@Sl$B~h&bH{$3nDOkP z?qX+jg$KkMgJB8#7cE|k5s$0|rv9UW709nAgP7Gs%n%TX0Ssq8u4Q`LW0LWil0)e1 zb?J#fGaR@F#jp;|i<=TF*{T^BHDch#C*y}bhIKK&jUO+^U|T>Wzkr8%9p0;BSbO(7 zO?Z=7*3tax{bn8(3;X&Uek8@RZeGjaH)CA}d|p(-ZLw^4(y*V1QIU}oK^wYU7${!$ zs}m!yZP;Tvz4(5H^zg%Yvr(*@EfyoRT+*Q68@a0b5JA_g z7$guNgL>k~dt%-kFp~yikPFummj(wd8+IiEk8^@+{`oH8JyLu-4MgR+rFX|jwVZdp^Y9fqf7tk{GH5Y`OW zHJ0)ZN3%8~p2g@&oL5&1I5otKhUn7*80asOd#roAN+#E>G8;2r^a(n!ktaIKb8Q? z)1eKyzZs9j6O?d!$Qr`_|bVRn`*`|$(M~~)7(20@JnOaCqe#u zq|kO}sRMDQ^f|aqBh`v<(-0 zm;(Lq9*$q4`~{Ns2f|C1!*^-!YI}utF_3HCy`e6j4ZK$(i)j7APtxu` zgm_KaSaezO4NpsC!EVR+bBQ2g3(PeUG2N-bbEq#n5iwQ0I}tI8AVz~Dd2J%=+4i#B z22t+wTxWPZy1~uY^YA3*7g9wX%YM}f!$pD^7*6v!Ni4!LO=HMY=O*NI&cTb5Sht53 z!}2GbB)1%YSwwIKIvng1eWm20m_o?_raHBvqpGuBY(D>ohJR^-WYAE{BPW1{Yzhj4 zmAN0IBHfBN`Kk$^VRsW(8s<6Eu$q!V!xSePCQuD9a({iTRA+>Gcj7~DXBs;4CKFk= zR^^E0f(9F0aLI!^eE38*zH0$YD%3w3kFqC7lE?{of7Dh6Mip1n&(^uaw&n#9i1^eNO|Ql*}v^cc6+rNyqOEZviy%70K}3 z9{mdg(o^^zE^7QF7B#NFMK${5+>2N*U>^cTgo#WIkCpJqZ!{c?5i^lw5PwV&{|upu zmqpSaH;CVDuO}Y2Oje2w_PaK)O;eqVpb&VS$q*N*=|}1Re4}Irr_Re-uW~gA#8!y= zC^sz{*NTlhso>36pG{|~ClYn=s>vg2nkbjJRm1733@B;C-Skh~L`d`$e{mA?ZQq3& zgNE4ul5Nj^RW+hC22w1age}gM>*^`bCCX0GJ8k_yHU5}#fo@z`>+tUKjXQm48C1zT z@^63wBxU?Sp&mqv$$Hj~g!Po)r`d^Lq7yL5otYQKQmI5_X45;&U6YARLH((&DeLa? zsgqgfPTPQOG0xMQphZFovKkCRX-~*0o@nKhS-3|J`gMLX3-pb`#8$iqrXxKYmGK*s zSx>iayyFz+Kj{~0Kh0q1FAIeI{XLndq$`OnD$2qD6L&JCqi_Yl_n>2l!?%R8zyUZ2 z6+R~VOj~Pb2JWr?3#;420%|hpO}R2tbcb!K(K|G=el-#f9s~0tk=j8Y=JBw8fI%!3H+v{0XwaB9v`SlM38I58S-jG#2XdD*^<(|1|WxD>767 zCVcw`QJj&EeCG|=MF~sydN2M6Mfa;cB%dv>8tEks=@d0I7Dl!k>CZK!BS2}YK7;>& ze~pp;_#ZaOCaQp@#nt;%hDAn(2@MFEP`@2=sCy!rzj6=j;yboEwBpmXQY$thH~--t*x(^FP&X2MBCY?KA-zUDpe1^5 zqaM&|aeWWKt|#gNU8sy5=LWEE95hrg36C2n`Z zz2O+sB57dmO0V7%^h(hmCQYQU?0k~Vokl_#EzdzF(2=Es&Q%v zAA2tg9##y8NREw()t)sUVN()_3jxB$Bi1i83vwk9vD&YuIWq0O@UHx-V4gIE~CsIn!qV zI78+7Gm6qE*GAV|h?THG$VH!b9Gc>}_~{yNt7CK>|IdBwDVzdda6b!k`<}meKkMEl zk%$IMuCFG>s_VsR*viIWL^_Yg@UQP@?QIVzK=-SZ|B69+21~GiN&A}F2$k;dl8(S0 zZY{b-w}N4R;stTVaknn!bvJ9?m@t|z?|{3mQ{F-f=5)wJ)4D0osUR&PEVvB(td%dD z!N%LNKbG@v%#_97Pf@R6+W9>?D~#YxI3-o=XNfCYTkvOP``@9rp+V zBAQh;8r+{JL}Rdt9mY{K$38oR0;1IQfDZNomBwZQ`S4!JUz*8A*uIIZM?;vyp@W|T zq&DY~SXQEq2A#JsOgP4RRxhV!e|JvGPcBDx|44F4@^_Ww(r`e)rRO5RrP-9-3)};` zvmhJ0Hdmt#3I!lOpfu_xMhdyXdosKTY<7ijlUQF=EWs+lO%4!xD#lxif2PupV!TB5}Y+txdB3rAjR# z)Q;iTAzjpfjoa9Bt_x2DQcq_xM!S-Mu5bAf{E}p}R|q?dF!SNF5TANwq?tcBi*=iw zhaAwO&aw(>PC15%adyAojhcLNX!92mW+5lO4dZ4VYV}O-N0-jgcPQ?K0z&GBBJ4qF zQiO(~B!E|=9d%2kL`o{-8$M}$LE8ZBu-5?&j$ z0JoGIT2Sg`6dc7*rLwu^n&F6SJ%||CS^S_1dz`r3P+?OV!x~q(@<%xD_Mc+yXLze1 z){YmTux(YPyGaI?5jGUH%cK$o4nSFiko!T2z9S_{T`rXduOwV=us$5ahfQ~Onm$VN2cW+padX9ygA_B2CB#yqrCa>C;Rg2_|*f*F^ARD1%cD8(`x73hfq zZ>j<`D)m<-E(3z>dy&1YKX8lPfTPuu(VqHN4}y3HF~IPSFdqR(Kx^Bb4EwvRw

IneYLNCG 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�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ËzDh0`O^h}I8O-(|+r(^z~)Fcne54Gh7N|*AY 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 z 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�TwhZzO>Cf4P+u_Jry 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

#a1UYQvD4IBg)mP> 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%0DWwy;YnNdH-;@ZfSCh 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

PnLq%@}<^r23GVE}Ajrpi!u3#ype8(w)hVrBh1H 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 delta 279055 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%0Aa2xomF3C)?1Kd?~O*&j(-tdGAxyG_GM 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�@1PkL96>O$MbjU_Pkk#U+A;~s=}sxM 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 From e8a7f76f9c99c8329cc0c05a5eb8648c413a1183 Mon Sep 17 00:00:00 2001 From: Laszlo Ersek Date: Mon, 21 Sep 2015 01:03:56 +0000 Subject: [PATCH 060/525] MdeModulePkg/Core/Dxe/Gcd: remove set but not used variables These trip up compilation with gcc. (Sync patch r18515 from main trunk.) Cc: Liming Gao Cc: Jiewen Yao Cc: Star Zeng Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Laszlo Ersek Reviewed-by: Ard Biesheuvel Reviewed-by: Star Zeng git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18516 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Core/Dxe/Gcd/Gcd.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/MdeModulePkg/Core/Dxe/Gcd/Gcd.c b/MdeModulePkg/Core/Dxe/Gcd/Gcd.c index c2769622581d..bd7c6c649350 100644 --- a/MdeModulePkg/Core/Dxe/Gcd/Gcd.c +++ b/MdeModulePkg/Core/Dxe/Gcd/Gcd.c @@ -2061,9 +2061,6 @@ CoreInitializeMemoryServices ( UINT64 Length; UINT64 Attributes; UINT64 Capabilities; - EFI_PHYSICAL_ADDRESS MaxMemoryBaseAddress; - UINT64 MaxMemoryLength; - UINT64 MaxMemoryAttributes; EFI_PHYSICAL_ADDRESS TestedMemoryBaseAddress; UINT64 TestedMemoryLength; EFI_PHYSICAL_ADDRESS HighAddress; @@ -2091,9 +2088,6 @@ CoreInitializeMemoryServices ( BaseAddress = 0; Length = 0; Attributes = 0; - MaxMemoryBaseAddress = 0; - MaxMemoryLength = 0; - MaxMemoryAttributes = 0; // // Cache the PHIT HOB for later use From 3a263f4c8203ce57f1bcc4be59511bcf5f15ce43 Mon Sep 17 00:00:00 2001 From: Samer El-Haj-Mahmoud Date: Mon, 21 Sep 2015 08:00:09 +0000 Subject: [PATCH 061/525] MdePkg: Http.h - Add HttpMethodMax to EFI_HTTP_METHOD. Add HttpMethodMax enum value to EFI_HTTP_METHOD to make it easier to iterate through the HTTP methods using a loop. (Sync patch r18520 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Samer El-Haj-Mahmoud Reviewed-by: Fu Siyuan git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18522 6f19259b-4bc3-4df7-8a09-765794883524 --- MdePkg/Include/Protocol/Http.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/MdePkg/Include/Protocol/Http.h b/MdePkg/Include/Protocol/Http.h index b1f8c51341d5..64b31213a46e 100644 --- a/MdePkg/Include/Protocol/Http.h +++ b/MdePkg/Include/Protocol/Http.h @@ -5,6 +5,7 @@ HTTP Protocol (HTTP) Copyright (c) 2015, Intel Corporation. All rights reserved.
+ (C) Copyright 2015 Hewlett Packard Enterprise Development LP
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -54,7 +55,8 @@ typedef enum { HttpMethodHead, HttpMethodPut, HttpMethodDelete, - HttpMethodTrace + HttpMethodTrace, + HttpMethodMax } EFI_HTTP_METHOD; /// From c6a0621e25b422a25d596a49c8d8d3dfa6afcd85 Mon Sep 17 00:00:00 2001 From: Samer El-Haj-Mahmoud Date: Mon, 21 Sep 2015 08:00:42 +0000 Subject: [PATCH 062/525] NetworkPkg: Fix typos in some EFI_HTTP_STATUS_CODE definitions Fix spelling typos in EFI_HTTP_STATUS_CODE definitions for error 415 and 501. (Sync patch r18521 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Samer El-Haj-Mahmoud Reviewed-by: Fu Siyuan git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18523 6f19259b-4bc3-4df7-8a09-765794883524 --- MdePkg/Include/Protocol/Http.h | 4 ++-- NetworkPkg/HttpDxe/HttpProto.c | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/MdePkg/Include/Protocol/Http.h b/MdePkg/Include/Protocol/Http.h index 64b31213a46e..839e378effe3 100644 --- a/MdePkg/Include/Protocol/Http.h +++ b/MdePkg/Include/Protocol/Http.h @@ -95,11 +95,11 @@ typedef enum { HTTP_STATUS_412_PRECONDITION_FAILED, HTTP_STATUS_413_REQUEST_ENTITY_TOO_LARGE, HTTP_STATUS_414_REQUEST_URI_TOO_LARGE, - HTTP_STATUS_415_UNSUPPORETD_MEDIA_TYPE, + HTTP_STATUS_415_UNSUPPORTED_MEDIA_TYPE, HTTP_STATUS_416_REQUESTED_RANGE_NOT_SATISFIED, HTTP_STATUS_417_EXPECTATION_FAILED, HTTP_STATUS_500_INTERNAL_SERVER_ERROR, - HTTP_STATUS_501_NOT_IMIPLEMENTED, + HTTP_STATUS_501_NOT_IMPLEMENTED, HTTP_STATUS_502_BAD_GATEWAY, HTTP_STATUS_503_SERVICE_UNAVAILABLE, HTTP_STATUS_504_GATEWAY_TIME_OUT, diff --git a/NetworkPkg/HttpDxe/HttpProto.c b/NetworkPkg/HttpDxe/HttpProto.c index 8fbd45411064..13d5748378e3 100644 --- a/NetworkPkg/HttpDxe/HttpProto.c +++ b/NetworkPkg/HttpDxe/HttpProto.c @@ -2,6 +2,7 @@ Miscellaneous routines for HttpDxe driver. Copyright (c) 2015, Intel Corporation. All rights reserved.
+(C) Copyright 2015 Hewlett Packard Enterprise Development LP
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -893,7 +894,7 @@ HttpMappingToStatusCode ( case 414: return HTTP_STATUS_414_REQUEST_URI_TOO_LARGE; case 415: - return HTTP_STATUS_415_UNSUPPORETD_MEDIA_TYPE; + return HTTP_STATUS_415_UNSUPPORTED_MEDIA_TYPE; case 416: return HTTP_STATUS_416_REQUESTED_RANGE_NOT_SATISFIED; case 417: @@ -901,7 +902,7 @@ HttpMappingToStatusCode ( case 500: return HTTP_STATUS_500_INTERNAL_SERVER_ERROR; case 501: - return HTTP_STATUS_501_NOT_IMIPLEMENTED; + return HTTP_STATUS_501_NOT_IMPLEMENTED; case 502: return HTTP_STATUS_502_BAD_GATEWAY; case 503: From d0b29b5ef6f903698d011510722233e37bcc7914 Mon Sep 17 00:00:00 2001 From: Ruiyu Ni Date: Thu, 24 Sep 2015 03:22:55 +0000 Subject: [PATCH 063/525] SourceLevelDebugPkg: Change the debug message to "v1.5" from "v1.4" (Sync patch r18534 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ruiyu Ni Reviewed-by: Jeff Fan git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18536 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Library/DebugAgent/DebugAgentCommon/DebugAgent.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugAgent.c b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugAgent.c index 6c3258630331..6a82cd354b3c 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugAgent.c +++ b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugAgent.c @@ -19,7 +19,7 @@ #include "Ia32/DebugException.h" GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 mErrorMsgVersionAlert[] = "\rThe SourceLevelDebugPkg you are using requires a newer version of the Intel(R) UDK Debugger Tool.\r\n"; -GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 mErrorMsgSendInitPacket[] = "\rSend INIT break packet and try to connect the HOST (Intel(R) UDK Debugger Tool v1.4) ...\r\n"; +GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 mErrorMsgSendInitPacket[] = "\rSend INIT break packet and try to connect the HOST (Intel(R) UDK Debugger Tool v1.5) ...\r\n"; GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 mErrorMsgConnectOK[] = "HOST connection is successful!\r\n"; GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 mErrorMsgConnectFail[] = "HOST connection is failed!\r\n"; GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 mWarningMsgIngoreBreakpoint[] = "Ignore break point in SMM for SMI issued during DXE debugging!\r\n"; From d81a37c69082331f98be995247fae41a65850e60 Mon Sep 17 00:00:00 2001 From: Ruiyu Ni Date: Thu, 24 Sep 2015 03:23:20 +0000 Subject: [PATCH 064/525] SourceLevelDebugPkg: Change revision to 4 to compress packet (Sync patch r18535 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ruiyu Ni Reviewed-by: Jeff Fan git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18537 6f19259b-4bc3-4df7-8a09-765794883524 --- SourceLevelDebugPkg/Include/TransferProtocol.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SourceLevelDebugPkg/Include/TransferProtocol.h b/SourceLevelDebugPkg/Include/TransferProtocol.h index 45d82c299599..ef7c891c39c8 100644 --- a/SourceLevelDebugPkg/Include/TransferProtocol.h +++ b/SourceLevelDebugPkg/Include/TransferProtocol.h @@ -24,7 +24,7 @@ // #define DEBUG_AGENT_REVISION_03 ((0 << 16) | 03) #define DEBUG_AGENT_REVISION_04 ((0 << 16) | 04) -#define DEBUG_AGENT_REVISION DEBUG_AGENT_REVISION_03 +#define DEBUG_AGENT_REVISION DEBUG_AGENT_REVISION_04 #define DEBUG_AGENT_CAPABILITIES 0 // From 182b7390e295ac469bde0e6606bef0c58d6521b5 Mon Sep 17 00:00:00 2001 From: Jaben Carsey Date: Fri, 25 Sep 2015 06:06:59 +0000 Subject: [PATCH 065/525] ShellPkg: Update tftp to build with current tip (Sync patch r18543 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jaben Carsey Signed-off-by: Tapan Shah Signed-off-by: Jiaxin Wu Reviewed-by: Qiu Shumin git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18547 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Library/UefiShellTftpCommandLib/Tftp.c | 26 +++++++++++------- .../UefiShellTftpCommandLib.h | 9 +++--- .../UefiShellTftpCommandLib.uni | Bin 8748 -> 8856 bytes 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/ShellPkg/Library/UefiShellTftpCommandLib/Tftp.c b/ShellPkg/Library/UefiShellTftpCommandLib/Tftp.c index d2f7046de037..2dc9287020d7 100644 --- a/ShellPkg/Library/UefiShellTftpCommandLib/Tftp.c +++ b/ShellPkg/Library/UefiShellTftpCommandLib/Tftp.c @@ -2,6 +2,8 @@ The implementation for the 'tftp' Shell command. Copyright (c) 2015, ARM Ltd. All rights reserved.
+ Copyright (c) 2015, Intel Corporation. All rights reserved.
+ (C) Copyright 2015 Hewlett Packard Enterprise Development LP
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License @@ -14,6 +16,8 @@ #include "UefiShellTftpCommandLib.h" +#define IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH 32 + /* Constant strings and definitions related to the message indicating the amount of progress in the dowloading of a TFTP file. @@ -59,7 +63,8 @@ StringToUint16 ( @param[in] NicNumber The network physical device number. @param[out] NicName Address where to store the NIC name. The memory area has to be at least - IP4_NIC_NAME_LENGTH bytes wide. + IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH + double byte wide. @return EFI_SUCCESS The name of the NIC was returned. @return Others The creation of the child for the Managed @@ -258,7 +263,7 @@ ShellCommandRunTftp ( EFI_HANDLE *Handles; UINTN HandleCount; UINTN NicNumber; - CHAR16 NicName[IP4_NIC_NAME_LENGTH]; + CHAR16 NicName[IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH]; EFI_HANDLE ControllerHandle; EFI_HANDLE Mtftp4ChildHandle; EFI_MTFTP4_PROTOCOL *Mtftp4; @@ -271,6 +276,7 @@ ShellCommandRunTftp ( NicFound = FALSE; AsciiRemoteFilePath = NULL; Handles = NULL; + FileSize = 0; // // Initialize the Shell library (we must be in non-auto-init...) @@ -571,7 +577,7 @@ StringToUint16 ( return FALSE; } - *Value = Val; + *Value = (UINT16)Val; return TRUE; } @@ -582,7 +588,8 @@ StringToUint16 ( @param[in] NicNumber The network physical device number. @param[out] NicName Address where to store the NIC name. The memory area has to be at least - IP4_NIC_NAME_LENGTH bytes wide. + IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH + double byte wide. @return EFI_SUCCESS The name of the NIC was returned. @return Others The creation of the child for the Managed @@ -623,7 +630,7 @@ GetNicName ( UnicodeSPrint ( NicName, - IP4_NIC_NAME_LENGTH, + IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH, SnpMode.IfType == NET_IFTYPE_ETHERNET ? L"eth%d" : L"unk%d" , @@ -942,7 +949,7 @@ CheckPacket ( { DOWNLOAD_CONTEXT *Context; CHAR16 Progress[TFTP_PROGRESS_MESSAGE_SIZE]; - UINT64 NbOfKb; + UINTN NbOfKb; UINTN Index; UINTN LastStep; UINTN Step; @@ -966,10 +973,9 @@ CheckPacket ( NbOfKb = Context->DownloadedNbOfBytes / 1024; Progress[0] = L'\0'; - LastStep = (Context->LastReportedNbOfBytes * TFTP_PROGRESS_SLIDER_STEPS) / - Context->FileSize; - Step = (Context->DownloadedNbOfBytes * TFTP_PROGRESS_SLIDER_STEPS) / - Context->FileSize; + LastStep = (Context->LastReportedNbOfBytes * TFTP_PROGRESS_SLIDER_STEPS) / Context->FileSize; + Step = (Context->DownloadedNbOfBytes * TFTP_PROGRESS_SLIDER_STEPS) / Context->FileSize; + if (Step <= LastStep) { return EFI_SUCCESS; } diff --git a/ShellPkg/Library/UefiShellTftpCommandLib/UefiShellTftpCommandLib.h b/ShellPkg/Library/UefiShellTftpCommandLib/UefiShellTftpCommandLib.h index a73b86c85b12..bef1e1d9f74d 100644 --- a/ShellPkg/Library/UefiShellTftpCommandLib/UefiShellTftpCommandLib.h +++ b/ShellPkg/Library/UefiShellTftpCommandLib/UefiShellTftpCommandLib.h @@ -1,7 +1,7 @@ /** @file header file for NULL named library for 'tftp' Shell command functions. - Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.
+ Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.
Copyright (c) 2015, ARM Ltd. All rights reserved.
This program and the accompanying materials @@ -21,7 +21,6 @@ #include #include -#include #include #include @@ -42,9 +41,9 @@ extern EFI_HANDLE gShellTftpHiiHandle; typedef struct { - UINT64 FileSize; - UINT64 DownloadedNbOfBytes; - UINT64 LastReportedNbOfBytes; + UINTN FileSize; + UINTN DownloadedNbOfBytes; + UINTN LastReportedNbOfBytes; } DOWNLOAD_CONTEXT; /** diff --git a/ShellPkg/Library/UefiShellTftpCommandLib/UefiShellTftpCommandLib.uni b/ShellPkg/Library/UefiShellTftpCommandLib/UefiShellTftpCommandLib.uni index 607a3602d2a3aad30619c0844162e7399c0aba9a..43b8cc5e7cd8726138c600b96b4ebbb1c960824c 100644 GIT binary patch delta 329 zcmZ4EGQ)L(lesB_0)q!bDnmI#4v;JXLIs8ZhD3&BhHM~N#E=5yyE5bf#Z!U20wB(0 zC}v2Vm@Ccf!w|4>p)ZSQ2tyiBx`4r%A)g@^2or(IQzrAWc8Z5ExG{tPjZ**`ha|W8 zAZxWSw;zK)P|}qln89kYqKGi30)rug9#Cn>$vQd-iPA)g_ap#Uh5$56?j!=S+6 z!=MLLrnhmrFN?e%Ln=cFLpe}Q5m1v614MN$Sak|R@#LQ@o!Uk~^#(wFc_?ZX7z}}8 z$zapr>Nn41trlihUnQCxI#jcgmg0z(Q=9mr}0h9rhcuzDT2l*u#X lx+XVpiA+8uDl|Djz5>MNEC#9p`8yS)YLY_U<~9W(CII6DN&o-= From 048e530ad73bed4d85ed50a5f727a6f4febc4dce Mon Sep 17 00:00:00 2001 From: Ye Ting Date: Fri, 25 Sep 2015 06:07:27 +0000 Subject: [PATCH 066/525] NetworkPkg:Fix iSCSI driver issue to work with iSCSI LIO target The patch fixes iSCSI driver can't reinstate itself when configured in AutoConfigure mode and IPv6 stack is actually used. The issue occurs when iSCSI driver communicates with iSCSI LIO target in IPv6 path and the target sends back TCP FIN packets randomly. (Sync patch r18546 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ye Ting Reviewed-by: Fu siyuan Reviewed-by: Wu jiaxin git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18548 6f19259b-4bc3-4df7-8a09-765794883524 --- NetworkPkg/IScsiDxe/IScsiConfig.h | 4 ++-- NetworkPkg/IScsiDxe/IScsiDriver.c | 4 ++-- NetworkPkg/IScsiDxe/IScsiDriver.h | 3 +-- NetworkPkg/IScsiDxe/IScsiMisc.c | 3 ++- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/NetworkPkg/IScsiDxe/IScsiConfig.h b/NetworkPkg/IScsiDxe/IScsiConfig.h index 7fd18a0ae2f2..daa0d343828a 100644 --- a/NetworkPkg/IScsiDxe/IScsiConfig.h +++ b/NetworkPkg/IScsiDxe/IScsiConfig.h @@ -2,7 +2,7 @@ The header file of functions for configuring or getting the parameters relating to iSCSI. -Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.
+Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -78,7 +78,7 @@ struct _ISCSI_ATTEMPT_CONFIG_NVDATA { union { ISCSI_CHAP_AUTH_CONFIG_NVDATA CHAP; } AuthConfigData; - + BOOLEAN AutoConfigureSuccess; }; /// diff --git a/NetworkPkg/IScsiDxe/IScsiDriver.c b/NetworkPkg/IScsiDxe/IScsiDriver.c index 5e5d700e4787..363daadc8f70 100644 --- a/NetworkPkg/IScsiDxe/IScsiDriver.c +++ b/NetworkPkg/IScsiDxe/IScsiDriver.c @@ -477,7 +477,7 @@ IScsiStart ( // Don't process the autoconfigure path if it is already established. // if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG && - AttemptConfigData->AutoConfigureMode == IP_MODE_AUTOCONFIG_SUCCESS) { + AttemptConfigData->AutoConfigureSuccess) { continue; } @@ -576,7 +576,7 @@ IScsiStart ( // IScsi session success. Update the attempt state to NVR. // if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG) { - AttemptConfigData->AutoConfigureMode = IP_MODE_AUTOCONFIG_SUCCESS; + AttemptConfigData->AutoConfigureSuccess = TRUE; } gRT->SetVariable ( diff --git a/NetworkPkg/IScsiDxe/IScsiDriver.h b/NetworkPkg/IScsiDxe/IScsiDriver.h index 825394a1d29a..338e3dcf188b 100644 --- a/NetworkPkg/IScsiDxe/IScsiDriver.h +++ b/NetworkPkg/IScsiDxe/IScsiDriver.h @@ -1,7 +1,7 @@ /** @file The header file of IScsiDriver.c. -Copyright (c) 2004 - 2013, Intel Corporation. All rights reserved.
+Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -29,7 +29,6 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #define IP_MODE_AUTOCONFIG_IP4 3 #define IP_MODE_AUTOCONFIG_IP6 4 -#define IP_MODE_AUTOCONFIG_SUCCESS 5 extern EFI_COMPONENT_NAME2_PROTOCOL gIScsiComponentName2; extern EFI_COMPONENT_NAME_PROTOCOL gIScsiComponentName; diff --git a/NetworkPkg/IScsiDxe/IScsiMisc.c b/NetworkPkg/IScsiDxe/IScsiMisc.c index f5c54e70188e..e7198d5ab04c 100644 --- a/NetworkPkg/IScsiDxe/IScsiMisc.c +++ b/NetworkPkg/IScsiDxe/IScsiMisc.c @@ -1054,7 +1054,7 @@ IScsiGetConfigData ( // Check the autoconfig path to see whether it should be retried. // if (AttemptTmp->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG && - AttemptTmp->AutoConfigureMode != IP_MODE_AUTOCONFIG_SUCCESS) { + !AttemptTmp->AutoConfigureSuccess) { if (mPrivate->Ipv6Flag && AttemptTmp->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP6) { // @@ -1197,6 +1197,7 @@ IScsiGetConfigData ( AttemptConfigData->AutoConfigureMode = (UINT8) (mPrivate->Ipv6Flag ? IP_MODE_AUTOCONFIG_IP6 : IP_MODE_AUTOCONFIG_IP4); + AttemptConfigData->AutoConfigureSuccess = FALSE; } // From 9228f69e2222ad78a5ba4e1f68446df8df6ee96e Mon Sep 17 00:00:00 2001 From: Jeff Fan Date: Fri, 25 Sep 2015 07:11:53 +0000 Subject: [PATCH 067/525] UefiCpuPkg/CpuMpPei: Add check on Processors number found (Sync patch r18549 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan Reviewed-by: Star Zeng git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18551 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/CpuMpPei/CpuMpPei.c | 1 + 1 file changed, 1 insertion(+) diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.c b/UefiCpuPkg/CpuMpPei/CpuMpPei.c index d5aee86d11e2..81d5b19fca0d 100644 --- a/UefiCpuPkg/CpuMpPei/CpuMpPei.c +++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.c @@ -368,6 +368,7 @@ CountProcessorNumber ( MicroSecondDelay (PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds)); PeiCpuMpData->InitFlag = 0; PeiCpuMpData->CpuCount += (UINT32) PeiCpuMpData->MpCpuExchangeInfo->NumApsExecuting; + ASSERT (PeiCpuMpData->CpuCount <= PcdGet32(PcdCpuMaxLogicalProcessorNumber)); // // Sort BSP/Aps by CPU APIC ID in ascending order // From 59fd15c5a2174a6a6fc4133964e6d5b520b58663 Mon Sep 17 00:00:00 2001 From: Jeff Fan Date: Fri, 25 Sep 2015 07:12:21 +0000 Subject: [PATCH 068/525] UefiCpuPkg/CpuMpPei: Fix wrong CpuData pointer CpuData buffer should be located in allocated buffer instead of at end of WakeupBuffer. (Sync patch r18550 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan Reviewed-by: Star Zeng git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18552 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/CpuMpPei/CpuMpPei.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.c b/UefiCpuPkg/CpuMpPei/CpuMpPei.c index 81d5b19fca0d..d5bc0c9b806a 100644 --- a/UefiCpuPkg/CpuMpPei/CpuMpPei.c +++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.c @@ -428,7 +428,8 @@ PrepareAPStartupVector ( PeiCpuMpData->CpuCount = 1; PeiCpuMpData->BspNumber = 0; - PeiCpuMpData->CpuData = (PEI_CPU_DATA *) (PeiCpuMpData->MpCpuExchangeInfo + 1); + PeiCpuMpData->CpuData = (PEI_CPU_DATA *) (PeiCpuMpData->BackupBuffer + + PeiCpuMpData->BackupBufferSize); PeiCpuMpData->CpuData[0].ApicId = GetInitialApicId (); PeiCpuMpData->CpuData[0].Health.Uint32 = 0; PeiCpuMpData->EndOfPeiFlag = FALSE; From af7fca3649779f0e55220a7acda9bd11bc660fc3 Mon Sep 17 00:00:00 2001 From: Jeff Fan Date: Mon, 16 Nov 2015 05:29:49 +0000 Subject: [PATCH 069/525] Update BaseTools from main trunk r18767. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18784 6f19259b-4bc3-4df7-8a09-765794883524 --- BaseTools/Bin/externals.txt | 2 +- BaseTools/BuildEnv | 66 ++++++-- BaseTools/Conf/tools_def.template | 22 ++- BaseTools/Scripts/SetVisualStudio.bat | 2 +- BaseTools/Scripts/ShowEnvironment.bat | 2 + BaseTools/Source/C/Common/PeCoffLoaderEx.c | 2 +- BaseTools/Source/C/GenFw/Elf32Convert.c | 42 +++-- BaseTools/Source/C/GenFw/Elf64Convert.c | 42 +++-- BaseTools/Source/C/GenFw/GenFw.c | 82 ++++++---- BaseTools/Source/C/Split/Split.c | 25 +-- BaseTools/Source/C/VfrCompile/VfrSyntax.g | 12 +- BaseTools/Source/Python/AutoGen/AutoGen.py | 16 +- BaseTools/Source/Python/AutoGen/GenC.py | 27 ++-- BaseTools/Source/Python/AutoGen/GenMake.py | 4 +- .../Source/Python/Common/EdkIIWorkspace.py | 3 +- .../Source/Python/Common/FdfParserLite.py | 6 +- .../Python/Common/LongFilePathOsPath.py | 2 + BaseTools/Source/Python/Common/Misc.py | 7 +- BaseTools/Source/Python/Common/String.py | 8 +- BaseTools/Source/Python/Ecc/Check.py | 18 +-- BaseTools/Source/Python/Ecc/Ecc.py | 8 +- BaseTools/Source/Python/Ecc/MetaDataParser.py | 5 +- BaseTools/Source/Python/Ecc/c.py | 16 +- .../Source/Python/GenFds/FfsInfStatement.py | 7 +- BaseTools/Source/Python/GenFds/GenFds.py | 13 +- .../Python/GenFds/GenFdsGlobalVariable.py | 4 +- BaseTools/Source/Python/GenFds/Region.py | 3 +- BaseTools/Source/Python/Makefile | 1 + .../UPT/Core/DistributionPackageClass.py | 26 +-- .../Source/Python/UPT/Core/PackageFile.py | 8 +- .../Source/Python/UPT/Library/GlobalData.py | 3 +- BaseTools/Source/Python/UPT/Library/Misc.py | 7 +- .../Python/UPT/Library/ParserValidate.py | 3 +- .../Source/Python/UPT/Library/Parsing.py | 32 ++-- BaseTools/Source/Python/UPT/MkPkg.py | 7 +- .../Python/UPT/PomAdapter/InfPomAlignment.py | 5 +- BaseTools/Source/Python/UPT/UPT.py | 3 +- .../Source/Python/Workspace/MetaFileParser.py | 11 +- .../Python/Workspace/WorkspaceDatabase.py | 31 +++- BaseTools/toolsetup.bat | 150 +++++++++++------- 40 files changed, 453 insertions(+), 280 deletions(-) diff --git a/BaseTools/Bin/externals.txt b/BaseTools/Bin/externals.txt index f47774936432..c2c4ab729732 100644 --- a/BaseTools/Bin/externals.txt +++ b/BaseTools/Bin/externals.txt @@ -1 +1 @@ -Win32 -r92 https://svn.code.sf.net/p/edk2-toolbinaries/code/trunk/Win32 +Win32 https://svn.code.sf.net/p/edk2-toolbinaries/code/trunk/Win32 diff --git a/BaseTools/BuildEnv b/BaseTools/BuildEnv index 6a1281b96b2a..7c77454bf88b 100755 --- a/BaseTools/BuildEnv +++ b/BaseTools/BuildEnv @@ -2,7 +2,7 @@ # Setup the environment for unix-like systems running a bash-like shell. # This file must be "sourced" not merely executed. For example: ". edksetup.sh" # -# Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.
+# Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
# This program and the accompanying materials # are licensed and made available under the terms and conditions of the BSD License # which accompanies this distribution. The full text of the license may be found at @@ -35,11 +35,28 @@ RestorePreviousConfiguration() { # # Restore previous configuration # - PREVIOUS_CONF_FILE=Conf/BuildEnv.sh + if [ -z "$CONF_PATH" ] + then + export CONF_PATH=$WORKSPACE/Conf + if [ ! -d $WORKSPACE/Conf ] && [ -n "$PACKAGES_PATH" ] + then + PACKAGES_PATH=${PACKAGES_PATH//:/ } + for DIR in $PACKAGES_PATH + do + if [ -d $DIR/Conf ] + then + export CONF_PATH=$DIR/Conf + break + fi + done + fi + fi + + PREVIOUS_CONF_FILE=$CONF_PATH/BuildEnv.sh if [ -e $PREVIOUS_CONF_FILE ] then - echo Loading previous configuration from \$WORKSPACE/$PREVIOUS_CONF_FILE - . $WORKSPACE/$PREVIOUS_CONF_FILE + echo Loading previous configuration from $PREVIOUS_CONF_FILE + . $PREVIOUS_CONF_FILE fi } @@ -70,9 +87,8 @@ StoreCurrentConfiguration() { # Write configuration to a shell script to allow for configuration to be # easily reloaded. # - OUTPUT_FILE=Conf/BuildEnv.sh - #echo Storing current configuration into \$WORKSPACE/$OUTPUT_FILE - OUTPUT_FILE=$WORKSPACE/$OUTPUT_FILE + OUTPUT_FILE=$CONF_PATH/BuildEnv.sh + #echo Storing current configuration into $OUTPUT_FILE echo "# Auto-generated by ${BASH_SOURCE[0]}" > $OUTPUT_FILE GenerateShellCodeToSetVariable WORKSPACE $OUTPUT_FILE GenerateShellCodeToSetVariable EDK_TOOLS_PATH $OUTPUT_FILE @@ -90,20 +106,20 @@ SetEdkToolsPath() { fi # - # Try $WORKSPACE/Conf/EdkTools + # Try $CONF_PATH/EdkTools # - if [ -e $WORKSPACE/Conf/EdkTools ] + if [ -e $CONF_PATH/EdkTools ] then - export EDK_TOOLS_PATH=$WORKSPACE/Conf/EdkTools + export EDK_TOOLS_PATH=$CONF_PATH/EdkTools return 0 fi # - # Try $WORKSPACE/Conf/BaseToolsSource + # Try $CONF_PATH/BaseToolsSource # - if [ -e $WORKSPACE/Conf/BaseToolsSource ] + if [ -e $CONF_PATH/BaseToolsSource ] then - export EDK_TOOLS_PATH=$WORKSPACE/Conf/BaseToolsSource + export EDK_TOOLS_PATH=$CONF_PATH/BaseToolsSource return 0 fi @@ -116,6 +132,22 @@ SetEdkToolsPath() { return 0 fi + # + # Try $PACKAGES_PATH + # + if [ -n "$PACKAGES_PATH"] + then + PACKAGES_PATH=${PACKAGES_PATH//:/ } + for DIR in $PACKAGES_PATH + do + if [ -d $DIR/BaseTools ] + then + export EDK_TOOLS_PATH=$DIR/BaseTools + return 0 + fi + done + fi + echo "Unable to determine EDK_TOOLS_PATH" echo echo "You may need to download the 'BaseTools' from buildtools.tianocore.org." @@ -179,17 +211,16 @@ AddEdkToolsToPath() { CopySingleTemplateFile() { SRC_FILENAME=Conf/$1.template - DST_FILENAME=Conf/$1.txt + DST_FILENAME=$CONF_PATH/$1.txt - if [ -e $WORKSPACE/$DST_FILENAME ] + if [ -e $DST_FILENAME ] then return fi echo "Copying \$EDK_TOOLS_PATH/$SRC_FILENAME" - echo " to \$WORKSPACE/$DST_FILENAME" + echo " to $DST_FILENAME" SRC_FILENAME=$EDK_TOOLS_PATH/$SRC_FILENAME - DST_FILENAME=$WORKSPACE/$DST_FILENAME cp $SRC_FILENAME $DST_FILENAME } @@ -230,6 +261,7 @@ ScriptMain() { echo WORKSPACE: $WORKSPACE echo EDK_TOOLS_PATH: $EDK_TOOLS_PATH + echo CONF_PATH: $CONF_PATH CopyTemplateFiles diff --git a/BaseTools/Conf/tools_def.template b/BaseTools/Conf/tools_def.template index aa2b6b1488c4..db08e252d2b9 100644 --- a/BaseTools/Conf/tools_def.template +++ b/BaseTools/Conf/tools_def.template @@ -3812,12 +3812,12 @@ DEFINE GCC_IA32_CC_FLAGS = DEF(GCC_ALL_CC_FLAGS) -m32 -malign-double - DEFINE GCC_X64_CC_FLAGS = DEF(GCC_ALL_CC_FLAGS) -mno-red-zone -Wno-address -mno-stack-arg-probe DEFINE GCC_IPF_CC_FLAGS = DEF(GCC_ALL_CC_FLAGS) -minline-int-divide-min-latency DEFINE GCC_ARM_CC_FLAGS = DEF(GCC_ALL_CC_FLAGS) -mword-relocations -mlittle-endian -mabi=aapcs -mapcs -fno-short-enums -save-temps -fsigned-char -ffunction-sections -fdata-sections -fomit-frame-pointer -Wno-address -mthumb -mfloat-abi=soft -DEFINE GCC_AARCH64_CC_FLAGS = DEF(GCC_ALL_CC_FLAGS) -mcmodel=tiny -mlittle-endian -fno-short-enums -save-temps -fverbose-asm -fsigned-char -ffunction-sections -fdata-sections -fomit-frame-pointer -fno-builtin -Wno-address -fno-asynchronous-unwind-tables +DEFINE GCC_AARCH64_CC_FLAGS = DEF(GCC_ALL_CC_FLAGS) -mlittle-endian -fno-short-enums -save-temps -fverbose-asm -fsigned-char -ffunction-sections -fdata-sections -fomit-frame-pointer -fno-builtin -Wno-address -fno-asynchronous-unwind-tables DEFINE GCC_DLINK_FLAGS_COMMON = -nostdlib --pie DEFINE GCC_DLINK2_FLAGS_COMMON = --script=$(EDK_TOOLS_PATH)/Scripts/GccBase.lds DEFINE GCC_IA32_X64_DLINK_COMMON = DEF(GCC_DLINK_FLAGS_COMMON) --gc-sections DEFINE GCC_ARM_AARCH64_DLINK_COMMON= --emit-relocs -nostdlib --gc-sections -u $(IMAGE_ENTRY_POINT) -e $(IMAGE_ENTRY_POINT) -Map $(DEST_DIR_DEBUG)/$(BASE_NAME).map -DEFINE GCC_ARM_DLINK_FLAGS = DEF(GCC_ARM_AARCH64_DLINK_COMMON) -Ttext=0x0 +DEFINE GCC_ARM_DLINK_FLAGS = DEF(GCC_ARM_AARCH64_DLINK_COMMON) -z common-page-size=0x20 DEFINE GCC_AARCH64_DLINK_FLAGS = DEF(GCC_ARM_AARCH64_DLINK_COMMON) -z common-page-size=0x20 DEFINE GCC_IA32_X64_ASLDLINK_FLAGS = DEF(GCC_IA32_X64_DLINK_COMMON) --entry _ReferenceAcpiTable -u $(IMAGE_ENTRY_POINT) DEFINE GCC_ARM_ASLDLINK_FLAGS = DEF(GCC_ARM_DLINK_FLAGS) --entry ReferenceAcpiTable -u $(IMAGE_ENTRY_POINT) @@ -3844,9 +3844,9 @@ DEFINE GCC44_X64_CC_FLAGS = DEF(GCC44_ALL_CC_FLAGS) -m64 -fno-stack-p DEFINE GCC44_IA32_X64_DLINK_COMMON = -nostdlib -n -q --gc-sections -z common-page-size=0x20 DEFINE GCC44_IA32_X64_ASLDLINK_FLAGS = DEF(GCC44_IA32_X64_DLINK_COMMON) --entry ReferenceAcpiTable -u ReferenceAcpiTable DEFINE GCC44_IA32_X64_DLINK_FLAGS = DEF(GCC44_IA32_X64_DLINK_COMMON) --entry $(IMAGE_ENTRY_POINT) -u $(IMAGE_ENTRY_POINT) -Map $(DEST_DIR_DEBUG)/$(BASE_NAME).map -DEFINE GCC44_IA32_DLINK2_FLAGS = DEF(GCC_DLINK2_FLAGS_COMMON) --defsym=PECOFF_HEADER_SIZE=0x220 +DEFINE GCC44_IA32_DLINK2_FLAGS = --defsym=PECOFF_HEADER_SIZE=0x220 DEF(GCC_DLINK2_FLAGS_COMMON) DEFINE GCC44_X64_DLINK_FLAGS = DEF(GCC44_IA32_X64_DLINK_FLAGS) -melf_x86_64 --oformat=elf64-x86-64 -DEFINE GCC44_X64_DLINK2_FLAGS = DEF(GCC_DLINK2_FLAGS_COMMON) --defsym=PECOFF_HEADER_SIZE=0x228 +DEFINE GCC44_X64_DLINK2_FLAGS = --defsym=PECOFF_HEADER_SIZE=0x228 DEF(GCC_DLINK2_FLAGS_COMMON) DEFINE GCC44_ASM_FLAGS = DEF(GCC_ASM_FLAGS) DEFINE GCC45_IA32_CC_FLAGS = DEF(GCC44_IA32_CC_FLAGS) @@ -3871,6 +3871,7 @@ DEFINE GCC46_ASM_FLAGS = DEF(GCC45_ASM_FLAGS) DEFINE GCC46_ARM_ASM_FLAGS = $(ARCHASM_FLAGS) $(PLATFORM_FLAGS) DEF(GCC_ASM_FLAGS) -mlittle-endian DEFINE GCC46_ARM_CC_FLAGS = $(ARCHCC_FLAGS) $(PLATFORM_FLAGS) DEF(GCC44_ALL_CC_FLAGS) DEF(GCC_ARM_CC_FLAGS) -fstack-protector DEFINE GCC46_ARM_DLINK_FLAGS = DEF(GCC_ARM_DLINK_FLAGS) --oformat=elf32-littlearm +DEFINE GCC46_ARM_DLINK2_FLAGS = DEF(GCC_DLINK2_FLAGS_COMMON) --defsym=PECOFF_HEADER_SIZE=0x220 DEFINE GCC46_ARM_ASLDLINK_FLAGS = DEF(GCC_ARM_ASLDLINK_FLAGS) --oformat=elf32-littlearm DEFINE GCC47_IA32_CC_FLAGS = DEF(GCC46_IA32_CC_FLAGS) @@ -3885,8 +3886,9 @@ DEFINE GCC47_ASM_FLAGS = DEF(GCC46_ASM_FLAGS) DEFINE GCC47_ARM_ASM_FLAGS = DEF(GCC46_ARM_ASM_FLAGS) DEFINE GCC47_AARCH64_ASM_FLAGS = $(ARCHASM_FLAGS) $(PLATFORM_FLAGS) DEF(GCC_ASM_FLAGS) -mlittle-endian DEFINE GCC47_ARM_CC_FLAGS = DEF(GCC46_ARM_CC_FLAGS) -mno-unaligned-access -DEFINE GCC47_AARCH64_CC_FLAGS = $(ARCHCC_FLAGS) $(PLATFORM_FLAGS) DEF(GCC44_ALL_CC_FLAGS) DEF(GCC_AARCH64_CC_FLAGS) +DEFINE GCC47_AARCH64_CC_FLAGS = $(ARCHCC_FLAGS) $(PLATFORM_FLAGS) DEF(GCC44_ALL_CC_FLAGS) -mcmodel=large DEF(GCC_AARCH64_CC_FLAGS) DEFINE GCC47_ARM_DLINK_FLAGS = DEF(GCC46_ARM_DLINK_FLAGS) +DEFINE GCC47_ARM_DLINK2_FLAGS = DEF(GCC46_ARM_DLINK2_FLAGS) DEFINE GCC47_AARCH64_DLINK_FLAGS = DEF(GCC_AARCH64_DLINK_FLAGS) DEFINE GCC47_AARCH64_DLINK2_FLAGS = DEF(GCC_DLINK2_FLAGS_COMMON) --defsym=PECOFF_HEADER_SIZE=0x228 DEFINE GCC47_ARM_ASLDLINK_FLAGS = DEF(GCC46_ARM_ASLDLINK_FLAGS) @@ -3906,6 +3908,7 @@ DEFINE GCC48_AARCH64_ASM_FLAGS = DEF(GCC47_AARCH64_ASM_FLAGS) DEFINE GCC48_ARM_CC_FLAGS = DEF(GCC47_ARM_CC_FLAGS) DEFINE GCC48_AARCH64_CC_FLAGS = DEF(GCC47_AARCH64_CC_FLAGS) DEFINE GCC48_ARM_DLINK_FLAGS = DEF(GCC47_ARM_DLINK_FLAGS) +DEFINE GCC48_ARM_DLINK2_FLAGS = DEF(GCC47_ARM_DLINK2_FLAGS) DEFINE GCC48_AARCH64_DLINK_FLAGS = DEF(GCC47_AARCH64_DLINK_FLAGS) DEFINE GCC48_AARCH64_DLINK2_FLAGS = DEF(GCC47_AARCH64_DLINK2_FLAGS) DEFINE GCC48_ARM_ASLDLINK_FLAGS = DEF(GCC47_ARM_ASLDLINK_FLAGS) @@ -3923,8 +3926,9 @@ DEFINE GCC49_ASM_FLAGS = DEF(GCC48_ASM_FLAGS) DEFINE GCC49_ARM_ASM_FLAGS = DEF(GCC48_ARM_ASM_FLAGS) DEFINE GCC49_AARCH64_ASM_FLAGS = DEF(GCC48_AARCH64_ASM_FLAGS) DEFINE GCC49_ARM_CC_FLAGS = DEF(GCC48_ARM_CC_FLAGS) -DEFINE GCC49_AARCH64_CC_FLAGS = DEF(GCC48_AARCH64_CC_FLAGS) +DEFINE GCC49_AARCH64_CC_FLAGS = $(ARCHCC_FLAGS) $(PLATFORM_FLAGS) DEF(GCC44_ALL_CC_FLAGS) -mcmodel=tiny DEF(GCC_AARCH64_CC_FLAGS) DEFINE GCC49_ARM_DLINK_FLAGS = DEF(GCC48_ARM_DLINK_FLAGS) +DEFINE GCC49_ARM_DLINK2_FLAGS = DEF(GCC48_ARM_DLINK2_FLAGS) DEFINE GCC49_AARCH64_DLINK_FLAGS = DEF(GCC48_AARCH64_DLINK_FLAGS) DEFINE GCC49_AARCH64_DLINK2_FLAGS = DEF(GCC48_AARCH64_DLINK2_FLAGS) DEFINE GCC49_ARM_ASLDLINK_FLAGS = DEF(GCC48_ARM_ASLDLINK_FLAGS) @@ -4250,6 +4254,7 @@ DEFINE GCC49_AARCH64_ASLDLINK_FLAGS = DEF(GCC48_AARCH64_ASLDLINK_FLAGS) *_GCC46_ARM_ASLDLINK_FLAGS = DEF(GCC46_ARM_ASLDLINK_FLAGS) *_GCC46_ARM_ASM_FLAGS = DEF(GCC46_ARM_ASM_FLAGS) *_GCC46_ARM_DLINK_FLAGS = DEF(GCC46_ARM_DLINK_FLAGS) +*_GCC46_ARM_DLINK2_FLAGS = DEF(GCC46_ARM_DLINK2_FLAGS) *_GCC46_ARM_PLATFORM_FLAGS = -march=armv7-a *_GCC46_ARM_PP_FLAGS = $(ARCHCC_FLAGS) $(PLATFORM_FLAGS) DEF(GCC_PP_FLAGS) *_GCC46_ARM_RC_FLAGS = DEF(GCC_ARM_RC_FLAGS) @@ -4349,6 +4354,7 @@ RELEASE_GCC46_ARM_CC_FLAGS = DEF(GCC46_ARM_CC_FLAGS) -D__ARM_FEATURE_UNALI *_GCC47_ARM_ASLDLINK_FLAGS = DEF(GCC47_ARM_ASLDLINK_FLAGS) *_GCC47_ARM_ASM_FLAGS = DEF(GCC47_ARM_ASM_FLAGS) *_GCC47_ARM_DLINK_FLAGS = DEF(GCC47_ARM_DLINK_FLAGS) +*_GCC47_ARM_DLINK2_FLAGS = DEF(GCC47_ARM_DLINK2_FLAGS) *_GCC47_ARM_PLATFORM_FLAGS = -march=armv7-a *_GCC47_ARM_PP_FLAGS = $(ARCHCC_FLAGS) $(PLATFORM_FLAGS) DEF(GCC_PP_FLAGS) *_GCC47_ARM_RC_FLAGS = DEF(GCC_ARM_RC_FLAGS) @@ -4475,6 +4481,7 @@ RELEASE_GCC47_AARCH64_CC_FLAGS = DEF(GCC47_AARCH64_CC_FLAGS) -Wno-unused-but-s *_GCC48_ARM_ASLDLINK_FLAGS = DEF(GCC48_ARM_ASLDLINK_FLAGS) *_GCC48_ARM_ASM_FLAGS = DEF(GCC48_ARM_ASM_FLAGS) *_GCC48_ARM_DLINK_FLAGS = DEF(GCC48_ARM_DLINK_FLAGS) +*_GCC48_ARM_DLINK2_FLAGS = DEF(GCC48_ARM_DLINK2_FLAGS) *_GCC48_ARM_PLATFORM_FLAGS = -march=armv7-a *_GCC48_ARM_PP_FLAGS = $(ARCHCC_FLAGS) $(PLATFORM_FLAGS) DEF(GCC_PP_FLAGS) *_GCC48_ARM_RC_FLAGS = DEF(GCC_ARM_RC_FLAGS) @@ -4601,6 +4608,7 @@ RELEASE_GCC48_AARCH64_CC_FLAGS = DEF(GCC48_AARCH64_CC_FLAGS) -Wno-unused-but-s *_GCC49_ARM_ASLDLINK_FLAGS = DEF(GCC49_ARM_ASLDLINK_FLAGS) *_GCC49_ARM_ASM_FLAGS = DEF(GCC49_ARM_ASM_FLAGS) *_GCC49_ARM_DLINK_FLAGS = DEF(GCC49_ARM_DLINK_FLAGS) +*_GCC49_ARM_DLINK2_FLAGS = DEF(GCC49_ARM_DLINK2_FLAGS) *_GCC49_ARM_PLATFORM_FLAGS = -march=armv7-a *_GCC49_ARM_PP_FLAGS = $(ARCHCC_FLAGS) $(PLATFORM_FLAGS) DEF(GCC_PP_FLAGS) *_GCC49_ARM_RC_FLAGS = DEF(GCC_ARM_RC_FLAGS) @@ -6609,7 +6617,7 @@ RELEASE_XCODE5_X64_CC_FLAGS = -target x86_64-pc-win32-macho -c -Os -W DEFINE RVCT_ALL_ASM_FLAGS = --diag_suppress=1786 --diag_error=warning --apcs /interwork DEFINE RVCT_ALL_CC_FLAGS = --c90 -c --no_autoinline --asm --gnu --apcs /interwork --signed_chars --no_unaligned_access --split_sections --enum_is_int --preinclude AutoGen.h --diag_suppress=186 --diag_warning 167 --diag_error=warning --diag_style=ide --protect_stack -DEFINE RVCT_ALL_DLINK_FLAGS = --ro-base 0 --no_scanlib --reloc --no_exceptions --datacompressor off --strict --symbols --diag_style=ide +DEFINE RVCT_ALL_DLINK_FLAGS = --ro-base 0 --no_scanlib --reloc --no_exceptions --datacompressor off --strict --symbols --diag_style=ide --no_legacyalign #################################################################################### # diff --git a/BaseTools/Scripts/SetVisualStudio.bat b/BaseTools/Scripts/SetVisualStudio.bat index a302a835969f..d379cd73dff4 100755 --- a/BaseTools/Scripts/SetVisualStudio.bat +++ b/BaseTools/Scripts/SetVisualStudio.bat @@ -68,7 +68,7 @@ if not exist "%COMMONTOOLSx64%\vcvarsx86_amd64.bat" ( @goto End :RebuildTools -@call python "%WORKSPACE%\BaseTools\Scripts\UpdateBuildVersions.py" +@call python "%BASE_TOOLS_PATH%\Scripts\UpdateBuildVersions.py" @set "BIN_DIR=%EDK_TOOLS_PATH%\Bin\Win32" if not exist "%BIN_DIR%" @mkdir "%BIN_DIR%" @echo Removing temporary and binary files diff --git a/BaseTools/Scripts/ShowEnvironment.bat b/BaseTools/Scripts/ShowEnvironment.bat index c4613e11708f..2b320fbc2152 100755 --- a/BaseTools/Scripts/ShowEnvironment.bat +++ b/BaseTools/Scripts/ShowEnvironment.bat @@ -47,9 +47,11 @@ if defined SRC_CONF @goto SetEnv @echo ############################################################################# @if defined WORKSPACE @echo WORKSPACE = %WORKSPACE% @if not defined WORKSPACE @echo WORKSPACE = Not Set +@if defined PACKAGES_PATH @echo PACKAGES_PATH = %PACKAGES_PATH% @if defined EDK_TOOLS_PATH @echo EDK_TOOLS_PATH = %EDK_TOOLS_PATH% @if not defined EDK_TOOLS_PATH @echo EDK_TOOLS_PATH = Not Set @if defined BASE_TOOLS_PATH @echo BASE_TOOLS_PATH = %BASE_TOOLS_PATH% +@if defined EDK_TOOLS_BIN @echo EDK_TOOLS_BIN = %EDK_TOOLS_BIN% @if defined PYTHON_FREEZER_PATH @echo PYTHON_FREEZER_PATH = %PYTHON_FREEZER_PATH% @if "%NT32PKG%"=="TRUE" ( @echo. diff --git a/BaseTools/Source/C/Common/PeCoffLoaderEx.c b/BaseTools/Source/C/Common/PeCoffLoaderEx.c index 382138a8937e..d04fa7d5ba2d 100644 --- a/BaseTools/Source/C/Common/PeCoffLoaderEx.c +++ b/BaseTools/Source/C/Common/PeCoffLoaderEx.c @@ -402,8 +402,8 @@ PeCoffLoaderRelocateArmImage ( if (*FixupData != NULL) { *FixupData = ALIGN_POINTER(*FixupData, sizeof(UINT64)); - *(UINT64 *)(*FixupData) = *Fixup16; CopyMem (*FixupData, Fixup16, sizeof (UINT64)); + *FixupData = *FixupData + sizeof(UINT64); } break; diff --git a/BaseTools/Source/C/GenFw/Elf32Convert.c b/BaseTools/Source/C/GenFw/Elf32Convert.c index e1b92ebd713e..a7b077873b40 100644 --- a/BaseTools/Source/C/GenFw/Elf32Convert.c +++ b/BaseTools/Source/C/GenFw/Elf32Convert.c @@ -218,6 +218,15 @@ CoffAlign ( return (Offset + mCoffAlignment - 1) & ~(mCoffAlignment - 1); } +STATIC +UINT32 +DebugRvaAlign ( + UINT32 Offset + ) +{ + return (Offset + 3) & ~3; +} + // // filter functions // @@ -331,12 +340,8 @@ ScanSections32 ( if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) { // if the section address is aligned we must align PE/COFF mCoffOffset = (mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1); - } else if ((shdr->sh_addr % shdr->sh_addralign) != (mCoffOffset % shdr->sh_addralign)) { - // ARM RVCT tools have behavior outside of the ELF specification to try - // and make images smaller. If sh_addr is not aligned to sh_addralign - // then the section needs to preserve sh_addr MOD sh_addralign. - // Normally doing nothing here works great. - Error (NULL, 0, 3000, "Invalid", "Unsupported section alignment."); + } else { + Error (NULL, 0, 3000, "Invalid", "Section address not aligned to its own alignment."); } } @@ -365,11 +370,8 @@ ScanSections32 ( assert (FALSE); } - mDebugOffset = mCoffOffset; - - if (mEhdr->e_machine != EM_ARM) { - mCoffOffset = CoffAlign(mCoffOffset); - } + mDebugOffset = DebugRvaAlign(mCoffOffset); + mCoffOffset = CoffAlign(mCoffOffset); if (SectionCount > 1 && mOutImageType == FW_EFI_IMAGE) { Warning (NULL, 0, 0, NULL, "Mulitple sections in %s are merged into 1 text section. Source level debug might not work correctly.", mInImageName); @@ -389,12 +391,8 @@ ScanSections32 ( if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) { // if the section address is aligned we must align PE/COFF mCoffOffset = (mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1); - } else if ((shdr->sh_addr % shdr->sh_addralign) != (mCoffOffset % shdr->sh_addralign)) { - // ARM RVCT tools have behavior outside of the ELF specification to try - // and make images smaller. If sh_addr is not aligned to sh_addralign - // then the section needs to preserve sh_addr MOD sh_addralign. - // Normally doing nothing here works great. - Error (NULL, 0, 3000, "Invalid", "Unsupported section alignment."); + } else { + Error (NULL, 0, 3000, "Invalid", "Section address not aligned to its own alignment."); } } @@ -423,7 +421,7 @@ ScanSections32 ( // section alignment. // if (SectionCount > 0) { - mDebugOffset = mCoffOffset; + mDebugOffset = DebugRvaAlign(mCoffOffset); } mCoffOffset = mDebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY) + sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY) + @@ -446,12 +444,8 @@ ScanSections32 ( if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) { // if the section address is aligned we must align PE/COFF mCoffOffset = (mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1); - } else if ((shdr->sh_addr % shdr->sh_addralign) != (mCoffOffset % shdr->sh_addralign)) { - // ARM RVCT tools have behavior outside of the ELF specification to try - // and make images smaller. If sh_addr is not aligned to sh_addralign - // then the section needs to preserve sh_addr MOD sh_addralign. - // Normally doing nothing here works great. - Error (NULL, 0, 3000, "Invalid", "Unsupported section alignment."); + } else { + Error (NULL, 0, 3000, "Invalid", "Section address not aligned to its own alignment."); } } if (shdr->sh_size != 0) { diff --git a/BaseTools/Source/C/GenFw/Elf64Convert.c b/BaseTools/Source/C/GenFw/Elf64Convert.c index c758ed9d64a6..90d80a22daf2 100644 --- a/BaseTools/Source/C/GenFw/Elf64Convert.c +++ b/BaseTools/Source/C/GenFw/Elf64Convert.c @@ -211,6 +211,15 @@ CoffAlign ( return (Offset + mCoffAlignment - 1) & ~(mCoffAlignment - 1); } +STATIC +UINT32 +DebugRvaAlign ( + UINT32 Offset + ) +{ + return (Offset + 3) & ~3; +} + // // filter functions // @@ -325,12 +334,8 @@ ScanSections64 ( if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) { // if the section address is aligned we must align PE/COFF mCoffOffset = (UINT32) ((mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1)); - } else if ((shdr->sh_addr % shdr->sh_addralign) != (mCoffOffset % shdr->sh_addralign)) { - // ARM RVCT tools have behavior outside of the ELF specification to try - // and make images smaller. If sh_addr is not aligned to sh_addralign - // then the section needs to preserve sh_addr MOD sh_addralign. - // Normally doing nothing here works great. - Error (NULL, 0, 3000, "Invalid", "Unsupported section alignment."); + } else { + Error (NULL, 0, 3000, "Invalid", "Section address not aligned to its own alignment."); } } @@ -359,11 +364,8 @@ ScanSections64 ( assert (FALSE); } - mDebugOffset = mCoffOffset; - - if (mEhdr->e_machine != EM_ARM) { - mCoffOffset = CoffAlign(mCoffOffset); - } + mDebugOffset = DebugRvaAlign(mCoffOffset); + mCoffOffset = CoffAlign(mCoffOffset); if (SectionCount > 1 && mOutImageType == FW_EFI_IMAGE) { Warning (NULL, 0, 0, NULL, "Mulitple sections in %s are merged into 1 text section. Source level debug might not work correctly.", mInImageName); @@ -383,12 +385,8 @@ ScanSections64 ( if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) { // if the section address is aligned we must align PE/COFF mCoffOffset = (UINT32) ((mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1)); - } else if ((shdr->sh_addr % shdr->sh_addralign) != (mCoffOffset % shdr->sh_addralign)) { - // ARM RVCT tools have behavior outside of the ELF specification to try - // and make images smaller. If sh_addr is not aligned to sh_addralign - // then the section needs to preserve sh_addr MOD sh_addralign. - // Normally doing nothing here works great. - Error (NULL, 0, 3000, "Invalid", "Unsupported section alignment."); + } else { + Error (NULL, 0, 3000, "Invalid", "Section address not aligned to its own alignment."); } } @@ -412,7 +410,7 @@ ScanSections64 ( // section alignment. // if (SectionCount > 0) { - mDebugOffset = mCoffOffset; + mDebugOffset = DebugRvaAlign(mCoffOffset); } mCoffOffset = mDebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY) + sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY) + @@ -439,12 +437,8 @@ ScanSections64 ( if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) { // if the section address is aligned we must align PE/COFF mCoffOffset = (UINT32) ((mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1)); - } else if ((shdr->sh_addr % shdr->sh_addralign) != (mCoffOffset % shdr->sh_addralign)) { - // ARM RVCT tools have behavior outside of the ELF specification to try - // and make images smaller. If sh_addr is not aligned to sh_addralign - // then the section needs to preserve sh_addr MOD sh_addralign. - // Normally doing nothing here works great. - Error (NULL, 0, 3000, "Invalid", "Unsupported section alignment."); + } else { + Error (NULL, 0, 3000, "Invalid", "Section address not aligned to its own alignment."); } } if (shdr->sh_size != 0) { diff --git a/BaseTools/Source/C/GenFw/GenFw.c b/BaseTools/Source/C/GenFw/GenFw.c index 4756c5276261..9ddd18e294a0 100644 --- a/BaseTools/Source/C/GenFw/GenFw.c +++ b/BaseTools/Source/C/GenFw/GenFw.c @@ -1,7 +1,7 @@ /** @file Converts a pe32+ image to an FW, Te image type, or other specific image. -Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.
+Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -168,7 +168,7 @@ Routine Description: // // Copyright declaration // - fprintf (stdout, "Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.\n\n"); + fprintf (stdout, "Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.\n\n"); // // Details Option @@ -184,9 +184,9 @@ Routine Description: PIC_PEIM, RELOCATABLE_PEIM, BS_DRIVER, RT_DRIVER,\n\ APPLICATION, SAL_RT_DRIVER to support all module types\n\ It can only be used together with --keepexceptiontable,\n\ - --keepzeropending, -r, -o option.It is a action option.\n\ - If it is combined with other action options, the later\n\ - input action option will override the previous one.\n"); + --keepzeropending, --keepoptionalheader, -r, -o option.\n\ + It is a action option. If it is combined with other action options,\n\ + the later input action option will override the previous one.\n"); fprintf (stdout, " -c, --acpi Create Acpi table.\n\ It can't be combined with other action options\n\ except for -o, -r option. It is a action option.\n\ @@ -194,9 +194,9 @@ Routine Description: input action option will override the previous one.\n"); fprintf (stdout, " -t, --terse Create Te Image.\n\ It can only be used together with --keepexceptiontable,\n\ - --keepzeropending, -r, -o option.It is a action option.\n\ - If it is combined with other action options, the later\n\ - input action option will override the previous one.\n"); + --keepzeropending, --keepoptionalheader, -r, -o option.\n\ + It is a action option. If it is combined with other action options,\n\ + the later input action option will override the previous one.\n"); fprintf (stdout, " -u, --dump Dump TeImage Header.\n\ It can't be combined with other action options\n\ except for -o, -r option. It is a action option.\n\ @@ -246,6 +246,9 @@ Routine Description: fprintf (stdout, " --keepexceptiontable Don't clear exception table.\n\ This option can be used together with -e or -t.\n\ It doesn't work for other options.\n"); + fprintf (stdout, " --keepoptionalheader Don't zero PE/COFF optional header fields.\n\ + This option can be used together with -e or -t.\n\ + It doesn't work for other options.\n"); fprintf (stdout, " --keepzeropending Don't strip zero pending of .reloc.\n\ This option can be used together with -e or -t.\n\ It doesn't work for other options.\n"); @@ -1079,6 +1082,7 @@ Routine Description: STATUS Status; BOOLEAN ReplaceFlag; BOOLEAN KeepExceptionTableFlag; + BOOLEAN KeepOptionalHeaderFlag; BOOLEAN KeepZeroPendingFlag; UINT64 LogLevel; EFI_TE_IMAGE_HEADER TEImageHeader; @@ -1141,6 +1145,7 @@ Routine Description: Optional32 = NULL; Optional64 = NULL; KeepExceptionTableFlag = FALSE; + KeepOptionalHeaderFlag = FALSE; KeepZeroPendingFlag = FALSE; NumberOfFormPacakge = 0; HiiPackageListBuffer = NULL; @@ -1269,6 +1274,13 @@ Routine Description: continue; } + if (stricmp(argv[0], "--keepoptionalheader") == 0) { + KeepOptionalHeaderFlag = TRUE; + argc--; + argv++; + continue; + } + if (stricmp (argv[0], "--keepzeropending") == 0) { KeepZeroPendingFlag = TRUE; argc --; @@ -2303,19 +2315,20 @@ Routine Description: if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { Optional32 = (EFI_IMAGE_OPTIONAL_HEADER32 *)&PeHdr->Pe32.OptionalHeader; - Optional32->MajorOperatingSystemVersion = 0; - Optional32->MinorOperatingSystemVersion = 0; - Optional32->MajorImageVersion = 0; - Optional32->MinorImageVersion = 0; - Optional32->MajorSubsystemVersion = 0; - Optional32->MinorSubsystemVersion = 0; - Optional32->Win32VersionValue = 0; - Optional32->CheckSum = 0; - Optional32->SizeOfStackReserve = 0; - Optional32->SizeOfStackCommit = 0; - Optional32->SizeOfHeapReserve = 0; - Optional32->SizeOfHeapCommit = 0; - + if (!KeepOptionalHeaderFlag) { + Optional32->MajorOperatingSystemVersion = 0; + Optional32->MinorOperatingSystemVersion = 0; + Optional32->MajorImageVersion = 0; + Optional32->MinorImageVersion = 0; + Optional32->MajorSubsystemVersion = 0; + Optional32->MinorSubsystemVersion = 0; + Optional32->Win32VersionValue = 0; + Optional32->CheckSum = 0; + Optional32->SizeOfStackReserve = 0; + Optional32->SizeOfStackCommit = 0; + Optional32->SizeOfHeapReserve = 0; + Optional32->SizeOfHeapCommit = 0; + } TEImageHeader.AddressOfEntryPoint = Optional32->AddressOfEntryPoint; TEImageHeader.BaseOfCode = Optional32->BaseOfCode; TEImageHeader.ImageBase = (UINT64) (Optional32->ImageBase); @@ -2395,19 +2408,20 @@ Routine Description: } } else if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) { Optional64 = (EFI_IMAGE_OPTIONAL_HEADER64 *)&PeHdr->Pe32.OptionalHeader; - Optional64->MajorOperatingSystemVersion = 0; - Optional64->MinorOperatingSystemVersion = 0; - Optional64->MajorImageVersion = 0; - Optional64->MinorImageVersion = 0; - Optional64->MajorSubsystemVersion = 0; - Optional64->MinorSubsystemVersion = 0; - Optional64->Win32VersionValue = 0; - Optional64->CheckSum = 0; - Optional64->SizeOfStackReserve = 0; - Optional64->SizeOfStackCommit = 0; - Optional64->SizeOfHeapReserve = 0; - Optional64->SizeOfHeapCommit = 0; - + if (!KeepOptionalHeaderFlag) { + Optional64->MajorOperatingSystemVersion = 0; + Optional64->MinorOperatingSystemVersion = 0; + Optional64->MajorImageVersion = 0; + Optional64->MinorImageVersion = 0; + Optional64->MajorSubsystemVersion = 0; + Optional64->MinorSubsystemVersion = 0; + Optional64->Win32VersionValue = 0; + Optional64->CheckSum = 0; + Optional64->SizeOfStackReserve = 0; + Optional64->SizeOfStackCommit = 0; + Optional64->SizeOfHeapReserve = 0; + Optional64->SizeOfHeapCommit = 0; + } TEImageHeader.AddressOfEntryPoint = Optional64->AddressOfEntryPoint; TEImageHeader.BaseOfCode = Optional64->BaseOfCode; TEImageHeader.ImageBase = (UINT64) (Optional64->ImageBase); diff --git a/BaseTools/Source/C/Split/Split.c b/BaseTools/Source/C/Split/Split.c index b63aef78f9a2..44a09681d36a 100644 --- a/BaseTools/Source/C/Split/Split.c +++ b/BaseTools/Source/C/Split/Split.c @@ -2,7 +2,7 @@ Split a file into two pieces at the request offset. -Copyright (c) 1999 - 2014, Intel Corporation. All rights reserved.
+Copyright (c) 1999 - 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -58,7 +58,7 @@ Routine Description: --*/ { printf ("%s Version %d.%d %s\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION, __BUILD_VERSION); - printf ("Copyright (c) 1999-2014 Intel Corporation. All rights reserved.\n"); + printf ("Copyright (c) 1999-2015 Intel Corporation. All rights reserved.\n"); printf ("\n SplitFile creates two Binary files either in the same directory as the current working\n"); printf (" directory or in the specified directory.\n"); } @@ -176,20 +176,25 @@ CreateDir ( { CHAR8* temp = *FullFileName; CHAR8* start = temp; + CHAR8 tempchar; UINT64 index = 0; for (;index < strlen(temp); ++index) { if (temp[index] == '\\' || temp[index] == '/') { - temp[index] = 0; - if (chdir(start)) { - if (mkdir(start, S_IRWXU | S_IRWXG | S_IRWXO) != 0) { - return EFI_ABORTED; + if (temp[index + 1] != '\0') { + tempchar = temp[index + 1]; + temp[index + 1] = 0; + if (chdir(start)) { + if (mkdir(start, S_IRWXU | S_IRWXG | S_IRWXO) != 0) { + return EFI_ABORTED; + } + chdir(start); } - chdir(start); + start = temp + index + 1; + temp[index] = '/'; + temp[index + 1] = tempchar; + } } - start = temp + index + 1; - temp[index] = '/'; - } } return EFI_SUCCESS; diff --git a/BaseTools/Source/C/VfrCompile/VfrSyntax.g b/BaseTools/Source/C/VfrCompile/VfrSyntax.g index ad839b2ab66e..d74fec8815c1 100644 --- a/BaseTools/Source/C/VfrCompile/VfrSyntax.g +++ b/BaseTools/Source/C/VfrCompile/VfrSyntax.g @@ -3258,7 +3258,7 @@ vfrStatementInconsistentIf : Prompt "=" "STRING_TOKEN" "\(" S:Number "\)" "," << IIObj.SetError (_STOSID(S->getText(), S->getLine())); >> { FLAGS "=" flagsField ( "\|" flagsField )* "," } vfrStatementExpression[0] - E:EndIf << CRT_END_OP (E); >> + E:EndIf {";"} << CRT_END_OP (E); >> ; vfrStatementNoSubmitIf : @@ -3267,7 +3267,7 @@ vfrStatementNoSubmitIf : Prompt "=" "STRING_TOKEN" "\(" S:Number "\)" "," << NSIObj.SetError (_STOSID(S->getText(), S->getLine())); >> { FLAGS "=" flagsField ( "\|" flagsField )* "," } vfrStatementExpression[0] - E:EndIf << CRT_END_OP (E); >> + E:EndIf {";"} << CRT_END_OP (E); >> ; vfrStatementWarningIf : @@ -3276,7 +3276,7 @@ vfrStatementWarningIf : Prompt "=" "STRING_TOKEN" "\(" S:Number "\)" "," << WIObj.SetWarning (_STOSID(S->getText(), S->getLine())); >> {Timeout "=" T:Number "," << WIObj.SetTimeOut (_STOU8(T->getText(), T->getLine())); >>} vfrStatementExpression[0] - E:EndIf << CRT_END_OP (E); >> + E:EndIf {";"} << CRT_END_OP (E); >> ; vfrStatementDisableIfQuest : @@ -3286,7 +3286,7 @@ vfrStatementDisableIfQuest : L:DisableIf << DIObj.SetLineNo(L->getLine()); >> vfrStatementExpression[0] ";" vfrStatementQuestionOptionList - E:EndIf << CRT_END_OP (E); >> + E:EndIf {";"} << CRT_END_OP (E); >> ; vfrStatementRefresh : @@ -3316,7 +3316,7 @@ vfrStatementSuppressIfQuest : { FLAGS "=" flagsField ( "\|" flagsField )* "," } vfrStatementExpression[0] ";" vfrStatementQuestionOptionList - E:EndIf << CRT_END_OP (E); >> + E:EndIf {";"} << CRT_END_OP (E); >> ; vfrStatementGrayOutIfQuest : @@ -3325,7 +3325,7 @@ vfrStatementGrayOutIfQuest : { FLAGS "=" flagsField ( "\|" flagsField )* "," } vfrStatementExpression[0] ";" vfrStatementQuestionOptionList - E:EndIf << CRT_END_OP (E); >> + E:EndIf {";"} << CRT_END_OP (E); >> ; vfrStatementOptions : diff --git a/BaseTools/Source/Python/AutoGen/AutoGen.py b/BaseTools/Source/Python/AutoGen/AutoGen.py index 259abc519b00..fe565743576b 100644 --- a/BaseTools/Source/Python/AutoGen/AutoGen.py +++ b/BaseTools/Source/Python/AutoGen/AutoGen.py @@ -40,7 +40,7 @@ import Common.VpdInfoFile as VpdInfoFile from GenPcdDb import CreatePcdDatabaseCode from Workspace.MetaFileCommentParser import UsageList - +from Common.MultipleWorkspace import MultipleWorkspace as mws import InfSectionParser ## Regular expression for splitting Dependency Expression string into tokens @@ -953,7 +953,7 @@ def CollectPlatformDynamicPcds(self): self._GuidValue = {} FdfModuleList = [] for InfName in self._AsBuildInfList: - InfName = os.path.join(self.WorkspaceDir, InfName) + InfName = mws.join(self.WorkspaceDir, InfName) FdfModuleList.append(os.path.normpath(InfName)) for F in self.Platform.Modules.keys(): M = ModuleAutoGen(self.Workspace, F, self.BuildTarget, self.ToolChain, self.Arch, self.MetaFile) @@ -1288,7 +1288,7 @@ def _GetVersion(self): def _GetFdfFile(self): if self._FdfFile == None: if self.Workspace.FdfFile != "": - self._FdfFile= path.join(self.WorkspaceDir, self.Workspace.FdfFile) + self._FdfFile= mws.join(self.WorkspaceDir, self.Workspace.FdfFile) else: self._FdfFile = '' return self._FdfFile @@ -2115,8 +2115,11 @@ def ApplyBuildOption(self, Module): BuildOptions[Tool][Attr] = "" # check if override is indicated if Value.startswith('='): - BuildOptions[Tool][Attr] = Value[1:] + ToolPath = Value[1:] + ToolPath = mws.handleWsMacro(ToolPath) + BuildOptions[Tool][Attr] = ToolPath else: + Value = mws.handleWsMacro(Value) BuildOptions[Tool][Attr] += " " + Value if Module.AutoGenVersion < 0x00010005 and self.Workspace.UniFlag != None: # @@ -2193,8 +2196,7 @@ def _Init(self, Workspace, ModuleFile, Target, Toolchain, Arch, PlatformFile): return False self.SourceDir = self.MetaFile.SubDir - if self.SourceDir.upper().find(self.WorkspaceDir.upper()) == 0: - self.SourceDir = self.SourceDir[len(self.WorkspaceDir) + 1:] + self.SourceDir = mws.relpath(self.SourceDir, self.WorkspaceDir) self.SourceOverrideDir = None # use overrided path defined in DSC file @@ -3042,7 +3044,7 @@ def _GetIncludePathList(self): self._IncludePathList.append(self.DebugDir) for Package in self.Module.Packages: - PackageDir = path.join(self.WorkspaceDir, Package.MetaFile.Dir) + PackageDir = mws.join(self.WorkspaceDir, Package.MetaFile.Dir) if PackageDir not in self._IncludePathList: self._IncludePathList.append(PackageDir) for Inc in Package.Includes: diff --git a/BaseTools/Source/Python/AutoGen/GenC.py b/BaseTools/Source/Python/AutoGen/GenC.py index 77de1657f0bb..45fb9899f2c2 100644 --- a/BaseTools/Source/Python/AutoGen/GenC.py +++ b/BaseTools/Source/Python/AutoGen/GenC.py @@ -1384,22 +1384,21 @@ def CreateModuleUnloadImageCode(Info, AutoGenC, AutoGenH): # @param AutoGenH The TemplateString object for header file # def CreateGuidDefinitionCode(Info, AutoGenC, AutoGenH): - if Info.IsLibrary: - return - if Info.ModuleType in ["USER_DEFINED", "BASE"]: GuidType = "GUID" else: GuidType = "EFI_GUID" if Info.GuidList: - AutoGenC.Append("\n// Guids\n") + if not Info.IsLibrary: + AutoGenC.Append("\n// Guids\n") AutoGenH.Append("\n// Guids\n") # # GUIDs # for Key in Info.GuidList: - AutoGenC.Append('GLOBAL_REMOVE_IF_UNREFERENCED %s %s = %s;\n' % (GuidType, Key, Info.GuidList[Key])) + if not Info.IsLibrary: + AutoGenC.Append('GLOBAL_REMOVE_IF_UNREFERENCED %s %s = %s;\n' % (GuidType, Key, Info.GuidList[Key])) AutoGenH.Append('extern %s %s;\n' % (GuidType, Key)) ## Create code for protocol @@ -1409,22 +1408,21 @@ def CreateGuidDefinitionCode(Info, AutoGenC, AutoGenH): # @param AutoGenH The TemplateString object for header file # def CreateProtocolDefinitionCode(Info, AutoGenC, AutoGenH): - if Info.IsLibrary: - return - if Info.ModuleType in ["USER_DEFINED", "BASE"]: GuidType = "GUID" else: GuidType = "EFI_GUID" if Info.ProtocolList: - AutoGenC.Append("\n// Protocols\n") + if not Info.IsLibrary: + AutoGenC.Append("\n// Protocols\n") AutoGenH.Append("\n// Protocols\n") # # Protocol GUIDs # for Key in Info.ProtocolList: - AutoGenC.Append('GLOBAL_REMOVE_IF_UNREFERENCED %s %s = %s;\n' % (GuidType, Key, Info.ProtocolList[Key])) + if not Info.IsLibrary: + AutoGenC.Append('GLOBAL_REMOVE_IF_UNREFERENCED %s %s = %s;\n' % (GuidType, Key, Info.ProtocolList[Key])) AutoGenH.Append('extern %s %s;\n' % (GuidType, Key)) ## Create code for PPI @@ -1434,22 +1432,21 @@ def CreateProtocolDefinitionCode(Info, AutoGenC, AutoGenH): # @param AutoGenH The TemplateString object for header file # def CreatePpiDefinitionCode(Info, AutoGenC, AutoGenH): - if Info.IsLibrary: - return - if Info.ModuleType in ["USER_DEFINED", "BASE"]: GuidType = "GUID" else: GuidType = "EFI_GUID" if Info.PpiList: - AutoGenC.Append("\n// PPIs\n") + if not Info.IsLibrary: + AutoGenC.Append("\n// PPIs\n") AutoGenH.Append("\n// PPIs\n") # # PPI GUIDs # for Key in Info.PpiList: - AutoGenC.Append('GLOBAL_REMOVE_IF_UNREFERENCED %s %s = %s;\n' % (GuidType, Key, Info.PpiList[Key])) + if not Info.IsLibrary: + AutoGenC.Append('GLOBAL_REMOVE_IF_UNREFERENCED %s %s = %s;\n' % (GuidType, Key, Info.PpiList[Key])) AutoGenH.Append('extern %s %s;\n' % (GuidType, Key)) ## Create code for PCD diff --git a/BaseTools/Source/Python/AutoGen/GenMake.py b/BaseTools/Source/Python/AutoGen/GenMake.py index 0342709a3a63..d9b219e1c75f 100644 --- a/BaseTools/Source/Python/AutoGen/GenMake.py +++ b/BaseTools/Source/Python/AutoGen/GenMake.py @@ -19,7 +19,7 @@ import re import os.path as path from Common.LongFilePathSupport import OpenLongFilePath as open - +from Common.MultipleWorkspace import MultipleWorkspace as mws from Common.BuildToolError import * from Common.Misc import * from Common.String import * @@ -559,7 +559,7 @@ def _CreateTemplateDict(self): found = False while not found and os.sep in package_rel_dir: index = package_rel_dir.index(os.sep) - current_dir = os.path.join(current_dir, package_rel_dir[:index]) + current_dir = mws.join(current_dir, package_rel_dir[:index]) for fl in os.listdir(current_dir): if fl.endswith('.dec'): found = True diff --git a/BaseTools/Source/Python/Common/EdkIIWorkspace.py b/BaseTools/Source/Python/Common/EdkIIWorkspace.py index 84d89b6c2ef8..401efeef3c94 100644 --- a/BaseTools/Source/Python/Common/EdkIIWorkspace.py +++ b/BaseTools/Source/Python/Common/EdkIIWorkspace.py @@ -17,6 +17,7 @@ import Common.LongFilePathOs as os, sys, time from DataType import * from Common.LongFilePathSupport import OpenLongFilePath as open +from Common.MultipleWorkspace import MultipleWorkspace as mws ## EdkIIWorkspace # @@ -112,7 +113,7 @@ def WorkspaceRelativePath(self, FileName): # @retval string The full path filename # def WorkspaceFile(self, FileName): - return os.path.realpath(os.path.join(self.WorkspaceDir,FileName)) + return os.path.realpath(mws.join(self.WorkspaceDir,FileName)) ## Convert to a real path filename # diff --git a/BaseTools/Source/Python/Common/FdfParserLite.py b/BaseTools/Source/Python/Common/FdfParserLite.py index 54a60a7e8f81..a0ee249748e1 100644 --- a/BaseTools/Source/Python/Common/FdfParserLite.py +++ b/BaseTools/Source/Python/Common/FdfParserLite.py @@ -20,6 +20,7 @@ import CommonDataClass.FdfClass from Common.LongFilePathSupport import OpenLongFilePath as open +from Common.MultipleWorkspace import MultipleWorkspace as mws ##define T_CHAR_SPACE ' ' ##define T_CHAR_NULL '\0' @@ -485,7 +486,8 @@ def PreprocessIncludeFile(self): IncFileName = self.__Token if not os.path.isabs(IncFileName): if IncFileName.startswith('$(WORKSPACE)'): - Str = IncFileName.replace('$(WORKSPACE)', os.environ.get('WORKSPACE')) + Str = mws.handleWsMacro(IncFileName) + Str = Str.replace('$(WORKSPACE)', os.environ.get('WORKSPACE')) if os.path.exists(Str): if not os.path.isabs(Str): Str = os.path.abspath(Str) @@ -494,7 +496,7 @@ def PreprocessIncludeFile(self): # file is in the same dir with FDF file FullFdf = self.FileName if not os.path.isabs(self.FileName): - FullFdf = os.path.join(os.environ.get('WORKSPACE'), self.FileName) + FullFdf = mws.join(os.environ.get('WORKSPACE'), self.FileName) IncFileName = os.path.join(os.path.dirname(FullFdf), IncFileName) diff --git a/BaseTools/Source/Python/Common/LongFilePathOsPath.py b/BaseTools/Source/Python/Common/LongFilePathOsPath.py index cb89b1b81384..0bba4464195d 100644 --- a/BaseTools/Source/Python/Common/LongFilePathOsPath.py +++ b/BaseTools/Source/Python/Common/LongFilePathOsPath.py @@ -49,3 +49,5 @@ def getctime(filename): islink = os.path.islink isabs = os.path.isabs realpath = os.path.realpath +relpath = os.path.relpath +pardir = os.path.pardir diff --git a/BaseTools/Source/Python/Common/Misc.py b/BaseTools/Source/Python/Common/Misc.py index 8ba5819cc1e3..0eedddc86125 100644 --- a/BaseTools/Source/Python/Common/Misc.py +++ b/BaseTools/Source/Python/Common/Misc.py @@ -35,6 +35,7 @@ from CommonDataClass.DataClass import * from Parsing import GetSplitValueList from Common.LongFilePathSupport import OpenLongFilePath as open +from Common.MultipleWorkspace import MultipleWorkspace as mws ## Regular expression used to find out place holders in string template gPlaceholderPattern = re.compile("\$\{([^$()\s]+)\}", re.MULTILINE|re.UNICODE) @@ -1728,6 +1729,7 @@ def __init__(self, File='', Root='', AlterRoot='', Type='', IsBinary=False, # Remove any '.' and '..' in path if self.Root: + self.Root = mws.getWs(self.Root, self.File) self.Path = os.path.normpath(os.path.join(self.Root, self.File)) self.Root = os.path.normpath(CommonPath([self.Root, self.Path])) # eliminate the side-effect of 'C:' @@ -1838,7 +1840,10 @@ def Validate(self, Type='', CaseSensitive=True): RealFile = os.path.join(self.AlterRoot, self.File) elif self.Root: RealFile = os.path.join(self.Root, self.File) - return FILE_NOT_FOUND, os.path.join(self.AlterRoot, RealFile) + if len (mws.getPkgPath()) == 0: + return FILE_NOT_FOUND, os.path.join(self.AlterRoot, RealFile) + else: + return FILE_NOT_FOUND, "%s is not found in packages path:\n\t%s" % (self.File, '\n\t'.join(mws.getPkgPath())) ErrorCode = 0 ErrorInfo = '' diff --git a/BaseTools/Source/Python/Common/String.py b/BaseTools/Source/Python/Common/String.py index 6c9671d51422..5c8d1e0ded5b 100644 --- a/BaseTools/Source/Python/Common/String.py +++ b/BaseTools/Source/Python/Common/String.py @@ -24,6 +24,7 @@ from BuildToolError import * from CommonDataClass.Exceptions import * from Common.LongFilePathSupport import OpenLongFilePath as open +from Common.MultipleWorkspace import MultipleWorkspace as mws gHexVerPatt = re.compile('0x[a-f0-9]{4}[a-f0-9]{4}$', re.IGNORECASE) gHumanReadableVerPatt = re.compile(r'([1-9][0-9]*|0)\.[0-9]{1,2}$') @@ -305,6 +306,11 @@ def NormPath(Path, Defines={}): # To local path format # Path = os.path.normpath(Path) + if Path.startswith(GlobalData.gWorkspace) and not os.path.exists(Path): + Path = Path[len (GlobalData.gWorkspace):] + if Path[0] == os.path.sep: + Path = Path[1:] + Path = mws.join(GlobalData.gWorkspace, Path) if IsRelativePath and Path[0] != '.': Path = os.path.join('.', Path) @@ -702,7 +708,7 @@ def RaiseParserError(Line, Section, File, Format='', LineNo= -1): # @retval string A full path # def WorkspaceFile(WorkspaceDir, Filename): - return os.path.join(NormPath(WorkspaceDir), NormPath(Filename)) + return mws.join(NormPath(WorkspaceDir), NormPath(Filename)) ## Split string # diff --git a/BaseTools/Source/Python/Ecc/Check.py b/BaseTools/Source/Python/Ecc/Check.py index 7932fb3394a9..5e5c8e72e400 100644 --- a/BaseTools/Source/Python/Ecc/Check.py +++ b/BaseTools/Source/Python/Ecc/Check.py @@ -19,6 +19,7 @@ import EccGlobalData import c from Common.LongFilePathSupport import OpenLongFilePath as open +from Common.MultipleWorkspace import MultipleWorkspace as mws ## Check # @@ -380,9 +381,7 @@ def IncludeFileCheckSameName(self): for Key in RecordDict: if len(RecordDict[Key]) > 1: for Item in RecordDict[Key]: - Path = Item[1].replace(EccGlobalData.gWorkspace, '') - if Path.startswith('\\') or Path.startswith('/'): - Path = Path[1:] + Path = mws.relpath(Item[1], EccGlobalData.gWorkspace) if not EccGlobalData.gException.IsException(ERROR_INCLUDE_FILE_CHECK_NAME, Path): EccGlobalData.gDb.TblReport.Insert(ERROR_INCLUDE_FILE_CHECK_NAME, OtherMsg="The file name for [%s] is duplicate" % Path, BelongsToTable='File', BelongsToItem=Item[0]) @@ -653,7 +652,7 @@ def MetaDataFileCheckLibraryInstanceDependent(self): if LibraryClass[1].upper() == 'NULL' or LibraryClass[1].startswith('!ifdef') or LibraryClass[1].startswith('!ifndef') or LibraryClass[1].endswith('!endif'): continue else: - LibraryIns = os.path.normpath(os.path.join(EccGlobalData.gWorkspace, LibraryClass[2])) + LibraryIns = os.path.normpath(mws.join(EccGlobalData.gWorkspace, LibraryClass[2])) SqlCommand = """select Value3 from Inf where BelongsToFile = (select ID from File where lower(FullPath) = lower('%s')) and Value2 = '%s'""" % (LibraryIns, 'LIBRARY_CLASS') @@ -729,7 +728,7 @@ def MetaDataFileCheckBinaryInfInFdf(self): for Record in RecordSet: FdfID = Record[0] FilePath = Record[1] - FilePath = os.path.normpath(os.path.join(EccGlobalData.gWorkspace, FilePath)) + FilePath = os.path.normpath(mws.join(EccGlobalData.gWorkspace, FilePath)) SqlCommand = """select ID from Inf where Model = %s and BelongsToFile = (select ID from File where FullPath like '%s') """ % (MODEL_EFI_SOURCE_FILE, FilePath) NewRecordSet = EccGlobalData.gDb.TblFile.Exec(SqlCommand) @@ -913,9 +912,7 @@ def GetInfFilePathFromID(self, FileID): RecordSet = Table.Exec(SqlCommand) Path = "" for Record in RecordSet: - Path = Record[0].replace(EccGlobalData.gWorkspace, '') - if Path.startswith('\\') or Path.startswith('/'): - Path = Path[1:] + Path = mws.relpath(Record[0], EccGlobalData.gWorkspace) return Path # Check whether two module INFs under one workspace has the same FILE_GUID value @@ -1223,7 +1220,10 @@ def NamingConventionCheckVariableName(self, FileTable): SqlCommand = """select ID, Name from %s where Model = %s""" % (FileTable, MODEL_IDENTIFIER_VARIABLE) RecordSet = EccGlobalData.gDb.TblFile.Exec(SqlCommand) for Record in RecordSet: - if not Pattern.match(Record[1]): + Var = Record[1] + if Var.startswith('CONST'): + Var = Var[5:].lstrip() + if not Pattern.match(Var): if not EccGlobalData.gException.IsException(ERROR_NAMING_CONVENTION_CHECK_VARIABLE_NAME, Record[1]): EccGlobalData.gDb.TblReport.Insert(ERROR_NAMING_CONVENTION_CHECK_VARIABLE_NAME, OtherMsg="The variable name [%s] does not follow the rules" % (Record[1]), BelongsToTable=FileTable, BelongsToItem=Record[0]) diff --git a/BaseTools/Source/Python/Ecc/Ecc.py b/BaseTools/Source/Python/Ecc/Ecc.py index ec8f6c22cfa4..c2ad4faff446 100644 --- a/BaseTools/Source/Python/Ecc/Ecc.py +++ b/BaseTools/Source/Python/Ecc/Ecc.py @@ -38,6 +38,7 @@ import re, string from Exception import * from Common.LongFilePathSupport import OpenLongFilePath as open +from Common.MultipleWorkspace import MultipleWorkspace as mws ## Ecc # @@ -70,8 +71,13 @@ def __init__(self): # WorkspaceDir = os.path.normcase(os.path.normpath(os.environ["WORKSPACE"])) os.environ["WORKSPACE"] = WorkspaceDir + + # set multiple workspace + PackagesPath = os.getenv("PACKAGES_PATH") + mws.setWs(WorkspaceDir, PackagesPath) + if "ECP_SOURCE" not in os.environ: - os.environ["ECP_SOURCE"] = os.path.join(WorkspaceDir, GlobalData.gEdkCompatibilityPkg) + os.environ["ECP_SOURCE"] = mws.join(WorkspaceDir, GlobalData.gEdkCompatibilityPkg) if "EFI_SOURCE" not in os.environ: os.environ["EFI_SOURCE"] = os.environ["ECP_SOURCE"] if "EDK_SOURCE" not in os.environ: diff --git a/BaseTools/Source/Python/Ecc/MetaDataParser.py b/BaseTools/Source/Python/Ecc/MetaDataParser.py index d80a5cff5d68..82ede3eb330c 100644 --- a/BaseTools/Source/Python/Ecc/MetaDataParser.py +++ b/BaseTools/Source/Python/Ecc/MetaDataParser.py @@ -14,6 +14,7 @@ import Common.LongFilePathOs as os from CommonDataClass.DataClass import * from EccToolError import * +from Common.MultipleWorkspace import MultipleWorkspace as mws import EccGlobalData import re ## Get the inlcude path list for a source file @@ -33,8 +34,8 @@ def GetIncludeListOfFile(WorkSpace, Filepath, Db): % (MODEL_META_DATA_PACKAGE, MODEL_EFI_SOURCE_FILE, '\\', Filepath) RecordSet = Db.TblFile.Exec(SqlCommand) for Record in RecordSet: - DecFullPath = os.path.normpath(os.path.join(WorkSpace, Record[0])) - InfFullPath = os.path.normpath(os.path.join(WorkSpace, Record[1])) + DecFullPath = os.path.normpath(mws.join(WorkSpace, Record[0])) + InfFullPath = os.path.normpath(mws.join(WorkSpace, Record[1])) (DecPath, DecName) = os.path.split(DecFullPath) (InfPath, InfName) = os.path.split(InfFullPath) SqlCommand = """select Value1 from Dec where BelongsToFile = diff --git a/BaseTools/Source/Python/Ecc/c.py b/BaseTools/Source/Python/Ecc/c.py index dcb37e5632fb..256b9e021c26 100644 --- a/BaseTools/Source/Python/Ecc/c.py +++ b/BaseTools/Source/Python/Ecc/c.py @@ -1271,7 +1271,10 @@ def CheckFuncLayoutReturnType(FullFileName): FuncName = Result[5] if EccGlobalData.gException.IsException(ERROR_C_FUNCTION_LAYOUT_CHECK_RETURN_TYPE, FuncName): continue - Index = Result[0].find(TypeStart) + Result0 = Result[0] + if Result0.upper().startswith('STATIC'): + Result0 = Result0[6:].strip() + Index = Result0.find(TypeStart) if Index != 0 or Result[3] != 0: PrintErrorMsg(ERROR_C_FUNCTION_LAYOUT_CHECK_RETURN_TYPE, '[%s] Return Type should appear at the start of line' % FuncName, FileTable, Result[1]) @@ -1313,9 +1316,10 @@ def CheckFuncLayoutModifier(FullFileName): for Result in ResultSet: ReturnType = GetDataTypeFromModifier(Result[0]) TypeStart = ReturnType.split()[0] -# if len(ReturnType) == 0: -# continue - Index = Result[0].find(TypeStart) + Result0 = Result[0] + if Result0.upper().startswith('STATIC'): + Result0 = Result0[6:].strip() + Index = Result0.find(TypeStart) if Index != 0: PrintErrorMsg(ERROR_C_FUNCTION_LAYOUT_CHECK_OPTIONAL_FUNCTIONAL_MODIFIER, '', FileTable, Result[1]) @@ -1327,8 +1331,6 @@ def CheckFuncLayoutModifier(FullFileName): for Result in ResultSet: ReturnType = GetDataTypeFromModifier(Result[0]) TypeStart = ReturnType.split()[0] -# if len(ReturnType) == 0: -# continue Result0 = Result[0] if Result0.upper().startswith('STATIC'): Result0 = Result0[6:].strip() @@ -1631,6 +1633,8 @@ def CheckMemberVariableFormat(Name, Value, FileTable, TdId, ModelId): Field = Field.strip() if Field == '': continue + if Field.startswith("#"): + continue # Enum could directly assign value to variable Field = Field.split('=')[0].strip() TokenList = Field.split() diff --git a/BaseTools/Source/Python/GenFds/FfsInfStatement.py b/BaseTools/Source/Python/GenFds/FfsInfStatement.py index 29dc75f433f4..ed767d3fa698 100644 --- a/BaseTools/Source/Python/GenFds/FfsInfStatement.py +++ b/BaseTools/Source/Python/GenFds/FfsInfStatement.py @@ -28,6 +28,7 @@ import RuleSimpleFile import RuleComplexFile from CommonDataClass.FdfClass import FfsInfStatementClassObject +from Common.MultipleWorkspace import MultipleWorkspace as mws from Common.String import * from Common.Misc import PathClass from Common.Misc import GuidStructureByteArrayToGuidString @@ -365,7 +366,7 @@ def GenFfs(self, Dict = {}, FvChildAddr = [], FvParentAddr=None): # self.__InfParse__(Dict) - SrcFile = os.path.join( GenFdsGlobalVariable.WorkSpaceDir , self.InfFileName); + SrcFile = mws.join( GenFdsGlobalVariable.WorkSpaceDir , self.InfFileName); DestFile = os.path.join( self.OutputPath, self.ModuleGuid + '.ffs') SrcFileDir = "." @@ -511,7 +512,7 @@ def __GetRule__ (self) : # def __GetPlatformArchList__(self): - InfFileKey = os.path.normpath(os.path.join(GenFdsGlobalVariable.WorkSpaceDir, self.InfFileName)) + InfFileKey = os.path.normpath(mws.join(GenFdsGlobalVariable.WorkSpaceDir, self.InfFileName)) DscArchList = [] PlatformDataBase = GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, 'IA32', GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag] if PlatformDataBase != None: @@ -878,7 +879,7 @@ def __GenComplexFileSection__(self, Rule, FvChildAddr, FvParentAddr): if not HasGneratedFlag: UniVfrOffsetFileSection = "" - ModuleFileName = os.path.join(GenFdsGlobalVariable.WorkSpaceDir, self.InfFileName) + ModuleFileName = mws.join(GenFdsGlobalVariable.WorkSpaceDir, self.InfFileName) InfData = GenFdsGlobalVariable.WorkSpace.BuildObject[PathClass(ModuleFileName), self.CurrentArch] # # Search the source list in InfData to find if there are .vfr file exist. diff --git a/BaseTools/Source/Python/GenFds/GenFds.py b/BaseTools/Source/Python/GenFds/GenFds.py index c2ad4e0e2a7c..a0beff039132 100644 --- a/BaseTools/Source/Python/GenFds/GenFds.py +++ b/BaseTools/Source/Python/GenFds/GenFds.py @@ -39,6 +39,7 @@ from Common.Misc import ClearDuplicatedInf from Common.Misc import GuidStructureStringToGuidString from Common.BuildVersion import gBUILD_VERSION +from Common.MultipleWorkspace import MultipleWorkspace as mws ## Version and Copyright versionNumber = "1.0" + ' ' + gBUILD_VERSION @@ -94,6 +95,10 @@ def main(): if (Options.debug): GenFdsGlobalVariable.VerboseLogger( "Using Workspace:" + Workspace) os.chdir(GenFdsGlobalVariable.WorkSpaceDir) + + # set multiple workspace + PackagesPath = os.getenv("PACKAGES_PATH") + mws.setWs(GenFdsGlobalVariable.WorkSpaceDir, PackagesPath) if (Options.filename): FdfFilename = Options.filename @@ -102,7 +107,7 @@ def main(): if FdfFilename[0:2] == '..': FdfFilename = os.path.realpath(FdfFilename) if not os.path.isabs (FdfFilename): - FdfFilename = os.path.join(GenFdsGlobalVariable.WorkSpaceDir, FdfFilename) + FdfFilename = mws.join(GenFdsGlobalVariable.WorkSpaceDir, FdfFilename) if not os.path.exists(FdfFilename): EdkLogger.error("GenFds", FILE_NOT_FOUND, ExtraData=FdfFilename) @@ -129,13 +134,13 @@ def main(): ActivePlatform = os.path.realpath(ActivePlatform) if not os.path.isabs (ActivePlatform): - ActivePlatform = os.path.join(GenFdsGlobalVariable.WorkSpaceDir, ActivePlatform) + ActivePlatform = mws.join(GenFdsGlobalVariable.WorkSpaceDir, ActivePlatform) if not os.path.exists(ActivePlatform) : EdkLogger.error("GenFds", FILE_NOT_FOUND, "ActivePlatform doesn't exist!") if os.path.normcase (ActivePlatform).find(Workspace) == 0: - ActivePlatform = ActivePlatform[len(Workspace):] + ActivePlatform = mws.relpath(ActivePlatform, Workspace) if len(ActivePlatform) > 0 : if ActivePlatform[0] == '\\' or ActivePlatform[0] == '/': ActivePlatform = ActivePlatform[1:] @@ -159,7 +164,7 @@ def main(): ConfDirectoryPath = os.path.join(GenFdsGlobalVariable.WorkSpaceDir, ConfDirectoryPath) else: # Get standard WORKSPACE/Conf, use the absolute path to the WORKSPACE/Conf - ConfDirectoryPath = os.path.join(GenFdsGlobalVariable.WorkSpaceDir, 'Conf') + ConfDirectoryPath = mws.join(GenFdsGlobalVariable.WorkSpaceDir, 'Conf') GenFdsGlobalVariable.ConfDir = ConfDirectoryPath BuildConfigurationFile = os.path.normpath(os.path.join(ConfDirectoryPath, "target.txt")) if os.path.isfile(BuildConfigurationFile) == True: diff --git a/BaseTools/Source/Python/GenFds/GenFdsGlobalVariable.py b/BaseTools/Source/Python/GenFds/GenFdsGlobalVariable.py index 04bbc300ceda..5bdc1b8288a8 100644 --- a/BaseTools/Source/Python/GenFds/GenFdsGlobalVariable.py +++ b/BaseTools/Source/Python/GenFds/GenFdsGlobalVariable.py @@ -31,6 +31,7 @@ import Common.DataType as DataType from Common.Misc import PathClass from Common.LongFilePathSupport import OpenLongFilePath as open +from Common.MultipleWorkspace import MultipleWorkspace as mws ## Global variables # @@ -322,12 +323,13 @@ def SetDir (OutputDir, FdfParser, WorkSpace, ArchList): # @param String String that may contain macro # def ReplaceWorkspaceMacro(String): + String = mws.handleWsMacro(String) Str = String.replace('$(WORKSPACE)', GenFdsGlobalVariable.WorkSpaceDir) if os.path.exists(Str): if not os.path.isabs(Str): Str = os.path.abspath(Str) else: - Str = os.path.join(GenFdsGlobalVariable.WorkSpaceDir, String) + Str = mws.join(GenFdsGlobalVariable.WorkSpaceDir, String) return os.path.normpath(Str) ## Check if the input files are newer than output files diff --git a/BaseTools/Source/Python/GenFds/Region.py b/BaseTools/Source/Python/GenFds/Region.py index 15b2ecba906a..feb56cb60f27 100644 --- a/BaseTools/Source/Python/GenFds/Region.py +++ b/BaseTools/Source/Python/GenFds/Region.py @@ -24,6 +24,7 @@ from Common import EdkLogger from Common.BuildToolError import * from Common.LongFilePathSupport import OpenLongFilePath as open +from Common.MultipleWorkspace import MultipleWorkspace as mws ## generate Region # @@ -205,7 +206,7 @@ def AddToBuffer(self, Buffer, BaseAddress, BlockSizeList, ErasePolarity, ImageBi for RegionData in self.RegionDataList: RegionData = GenFdsGlobalVariable.MacroExtend(RegionData, MacroDict) if RegionData[1] != ':' : - RegionData = os.path.join (GenFdsGlobalVariable.WorkSpaceDir, RegionData) + RegionData = mws.join (GenFdsGlobalVariable.WorkSpaceDir, RegionData) if not os.path.exists(RegionData): EdkLogger.error("GenFds", FILE_NOT_FOUND, ExtraData=RegionData) # diff --git a/BaseTools/Source/Python/Makefile b/BaseTools/Source/Python/Makefile index 4044fcefeb9f..d3f1baa83109 100644 --- a/BaseTools/Source/Python/Makefile +++ b/BaseTools/Source/Python/Makefile @@ -59,6 +59,7 @@ COMMON_PYTHON=$(BASE_TOOLS_PATH)\Source\Python\Common\BuildToolError.py \ $(BASE_TOOLS_PATH)\Source\Python\Common\ToolDefClassObject.py \ $(BASE_TOOLS_PATH)\Source\Python\Common\VpdInfoFile.py \ $(BASE_TOOLS_PATH)\Source\Python\Common\BuildVersion.py \ + $(BASE_TOOLS_PATH)\Source\Python\Common\MultipleWorkspace.py \ $(BASE_TOOLS_PATH)\Source\Python\CommonDataClass\CommonClass.py \ $(BASE_TOOLS_PATH)\Source\Python\CommonDataClass\DataClass.py \ $(BASE_TOOLS_PATH)\Source\Python\CommonDataClass\Exceptions.py \ diff --git a/BaseTools/Source/Python/UPT/Core/DistributionPackageClass.py b/BaseTools/Source/Python/UPT/Core/DistributionPackageClass.py index bfe6dcc70fea..9c55e0ea88a7 100644 --- a/BaseTools/Source/Python/UPT/Core/DistributionPackageClass.py +++ b/BaseTools/Source/Python/UPT/Core/DistributionPackageClass.py @@ -32,6 +32,7 @@ from Object.POM.CommonObject import IdentificationObject from Object.POM.CommonObject import CommonHeaderObject from Object.POM.CommonObject import MiscFileObject +from Common.MultipleWorkspace import MultipleWorkspace as mws ## DistributionPackageHeaderClass # @@ -110,14 +111,17 @@ def __init__(self): # @param ModuleList: A list of all modules # def GetDistributionPackage(self, WorkspaceDir, PackageList, ModuleList): + # Backup WorkspaceDir + Root = WorkspaceDir + # # Get Packages # if PackageList: for PackageFile in PackageList: - PackageFileFullPath = \ - os.path.normpath(os.path.join(WorkspaceDir, PackageFile)) - DecObj = DecPomAlignment(PackageFileFullPath, WorkspaceDir, CheckMulDec = True) + PackageFileFullPath = mws.join(Root, PackageFile) + WorkspaceDir = mws.getWs(Root, PackageFile) + DecObj = DecPomAlignment(PackageFileFullPath, WorkspaceDir, CheckMulDec=True) PackageObj = DecObj # # Parser inf file one bye one @@ -140,8 +144,7 @@ def GetDistributionPackage(self, WorkspaceDir, PackageList, ModuleList): # Inf class in InfPomAlignment. # try: - ModuleObj = InfPomAlignment(Filename, WorkspaceDir, \ - PackageObj.GetPackagePath()) + ModuleObj = InfPomAlignment(Filename, WorkspaceDir, PackageObj.GetPackagePath()) # # Add module to package @@ -168,11 +171,11 @@ def GetDistributionPackage(self, WorkspaceDir, PackageList, ModuleList): # if ModuleList: for ModuleFile in ModuleList: - ModuleFileFullPath = \ - os.path.normpath(os.path.join(WorkspaceDir, ModuleFile)) + ModuleFileFullPath = mws.join(Root, ModuleFile) + WorkspaceDir = mws.getWs(Root, ModuleFile) + try: - ModuleObj = InfPomAlignment(ModuleFileFullPath, - WorkspaceDir) + ModuleObj = InfPomAlignment(ModuleFileFullPath, WorkspaceDir) ModuleKey = (ModuleObj.GetGuid(), ModuleObj.GetVersion(), ModuleObj.GetName(), @@ -185,7 +188,10 @@ def GetDistributionPackage(self, WorkspaceDir, PackageList, ModuleList): ST.WRN_EDK1_INF_FOUND%ModuleFileFullPath, ExtraData=ST.ERR_NOT_SUPPORTED_SA_MODULE) else: - raise + raise + + # Recover WorkspaceDir + WorkspaceDir = Root ## Get all files included for a distribution package, except tool/misc of # distribution level diff --git a/BaseTools/Source/Python/UPT/Core/PackageFile.py b/BaseTools/Source/Python/UPT/Core/PackageFile.py index 47ea0bc0a932..5fafd85bffbf 100644 --- a/BaseTools/Source/Python/UPT/Core/PackageFile.py +++ b/BaseTools/Source/Python/UPT/Core/PackageFile.py @@ -37,6 +37,7 @@ from Library.Misc import CreateDirectory from Library.Misc import RemoveDirectory from Core.FileHook import __FileHookOpen__ +from Common.MultipleWorkspace import MultipleWorkspace as mws class PackageFile: @@ -203,8 +204,11 @@ def Pack(self, Top, BaseDir): # @param Files: the files to pack # def PackFiles(self, Files): - for File1 in Files: - self.PackFile(File1) + for File in Files: + Cwd = os.getcwd() + os.chdir(mws.getWs(mws.WORKSPACE, File)) + self.PackFile(File) + os.chdir(Cwd) ## Pack the file # diff --git a/BaseTools/Source/Python/UPT/Library/GlobalData.py b/BaseTools/Source/Python/UPT/Library/GlobalData.py index d478983c23db..8f446d48883d 100644 --- a/BaseTools/Source/Python/UPT/Library/GlobalData.py +++ b/BaseTools/Source/Python/UPT/Library/GlobalData.py @@ -19,6 +19,7 @@ # The workspace directory # gWORKSPACE = '.' +gPACKAGE_PATH = None # # INF module directory @@ -107,4 +108,4 @@ # Used by Library instance parser # {FilePath: FileObj} # -gLIBINSTANCEDICT = {} \ No newline at end of file +gLIBINSTANCEDICT = {} diff --git a/BaseTools/Source/Python/UPT/Library/Misc.py b/BaseTools/Source/Python/UPT/Library/Misc.py index bc9e0e172bf7..0d92cb3767c6 100644 --- a/BaseTools/Source/Python/UPT/Library/Misc.py +++ b/BaseTools/Source/Python/UPT/Library/Misc.py @@ -50,6 +50,7 @@ from Library.ParserValidate import IsValidPath from Object.POM.CommonObject import TextObject from Core.FileHook import __FileHookOpen__ +from Common.MultipleWorkspace import MultipleWorkspace as mws ## Convert GUID string in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx style to C # structure style @@ -592,7 +593,11 @@ def GetWorkspace(): if WorkspaceDir[-1] == ':': WorkspaceDir += os.sep - return WorkspaceDir + + PackagesPath = os.environ.get("PACKAGES_PATH") + mws.setWs(WorkspaceDir, PackagesPath) + + return WorkspaceDir, mws.PACKAGES_PATH ## Get relative path # diff --git a/BaseTools/Source/Python/UPT/Library/ParserValidate.py b/BaseTools/Source/Python/UPT/Library/ParserValidate.py index e9732278981a..028cf9a54f84 100644 --- a/BaseTools/Source/Python/UPT/Library/ParserValidate.py +++ b/BaseTools/Source/Python/UPT/Library/ParserValidate.py @@ -27,6 +27,7 @@ from Library.String import GetSplitValueList from Library.ExpressionValidate import IsValidBareCString from Library.ExpressionValidate import IsValidFeatureFlagExp +from Common.MultipleWorkspace import MultipleWorkspace as mws ## __HexDigit() method # @@ -236,7 +237,7 @@ def IsValidPath(Path, Root): Path = os.path.normpath(Path).replace('\\', '/') Root = os.path.normpath(Root).replace('\\', '/') - FullPath = os.path.normpath(os.path.join(Root, Path)).replace('\\', '/') + FullPath = mws.join(Root, Path) if not os.path.exists(FullPath): return False diff --git a/BaseTools/Source/Python/UPT/Library/Parsing.py b/BaseTools/Source/Python/UPT/Library/Parsing.py index ace3e0d11841..c34e7751442a 100644 --- a/BaseTools/Source/Python/UPT/Library/Parsing.py +++ b/BaseTools/Source/Python/UPT/Library/Parsing.py @@ -827,21 +827,23 @@ def GetPkgInfoFromDec(Path): def GetWorkspacePackage(): DecFileList = [] WorkspaceDir = GlobalData.gWORKSPACE - for Root, Dirs, Files in os.walk(WorkspaceDir): - if 'CVS' in Dirs: - Dirs.remove('CVS') - if '.svn' in Dirs: - Dirs.remove('.svn') - for Dir in Dirs: - if Dir.startswith('.'): - Dirs.remove(Dir) - for FileSp in Files: - if FileSp.startswith('.'): - continue - Ext = os.path.splitext(FileSp)[1] - if Ext.lower() in ['.dec']: - DecFileList.append\ - (os.path.normpath(os.path.join(Root, FileSp))) + PackageDir = GlobalData.gPACKAGE_PATH + for PkgRoot in [WorkspaceDir] + PackageDir: + for Root, Dirs, Files in os.walk(PkgRoot): + if 'CVS' in Dirs: + Dirs.remove('CVS') + if '.svn' in Dirs: + Dirs.remove('.svn') + for Dir in Dirs: + if Dir.startswith('.'): + Dirs.remove(Dir) + for FileSp in Files: + if FileSp.startswith('.'): + continue + Ext = os.path.splitext(FileSp)[1] + if Ext.lower() in ['.dec']: + DecFileList.append\ + (os.path.normpath(os.path.join(Root, FileSp))) # # abstract package guid, version info from DecFile List # diff --git a/BaseTools/Source/Python/UPT/MkPkg.py b/BaseTools/Source/Python/UPT/MkPkg.py index 2eb84588bdc4..87c84f0cc25b 100644 --- a/BaseTools/Source/Python/UPT/MkPkg.py +++ b/BaseTools/Source/Python/UPT/MkPkg.py @@ -50,6 +50,7 @@ from Core.DistributionPackageClass import DistributionPackageClass from Core.PackageFile import PackageFile +from Common.MultipleWorkspace import MultipleWorkspace as mws ## CheckForExistingDp # @@ -136,7 +137,7 @@ def Main(Options = None): # write(). # FromFile = os.path.normpath(FileObject.GetURI()).encode('utf_8') - FileFullPath = os.path.normpath(os.path.join(WorkspaceDir, FromFile)) + FileFullPath = mws.join(WorkspaceDir, FromFile) if FileFullPath in RePkgDict: (DpGuid, DpVersion, DpName, Repackage) = RePkgDict[FileFullPath] if not Repackage: @@ -183,7 +184,7 @@ def Main(Options = None): DistPkg.Header.RePackage = True Cwd = getcwd() - chdir(WorkspaceDir) + chdir(WorkspaceDir) ContentFile.PackFiles(FileList) chdir(Cwd) @@ -264,7 +265,7 @@ def CheckFileList(QualifiedExt, FileList, ErrorStringExt, ErrorStringFullPath): ErrorStringExt % Item) Item = os.path.normpath(Item) - Path = os.path.normpath(os.path.join(WorkspaceDir, Item)) + Path = mws.join(WorkspaceDir, Item) if not os.path.exists(Path): Logger.Error("\nMkPkg", FILE_NOT_FOUND, ST.ERR_NOT_FOUND % Item) elif Item == Path: diff --git a/BaseTools/Source/Python/UPT/PomAdapter/InfPomAlignment.py b/BaseTools/Source/Python/UPT/PomAdapter/InfPomAlignment.py index 22e9ef5fc0a3..a15173285345 100644 --- a/BaseTools/Source/Python/UPT/PomAdapter/InfPomAlignment.py +++ b/BaseTools/Source/Python/UPT/PomAdapter/InfPomAlignment.py @@ -51,7 +51,7 @@ from PomAdapter.InfPomAlignmentMisc import GenBinaryData from Parser import InfParser from PomAdapter.DecPomAlignment import DecPomAlignment - +from Common.MultipleWorkspace import MultipleWorkspace as mws ## InfPomAlignment # @@ -534,8 +534,7 @@ def _GenPackages(self, Skip): PackageDependency.SetSupArchList(ConvertArchList(PackageItemObj.GetSupArchList())) PackageDependency.SetFeatureFlag(PackageItemObj.GetFeatureFlagExp()) - PkgInfo = GetPkgInfoFromDec(os.path.normpath(os.path.join(self.WorkSpace, - NormPath(PackageItemObj.GetPackageName())))) + PkgInfo = GetPkgInfoFromDec(mws.join(self.WorkSpace, NormPath(PackageItemObj.GetPackageName()))) if PkgInfo[1] and PkgInfo[2]: PackageDependency.SetGuid(PkgInfo[1]) PackageDependency.SetVersion(PkgInfo[2]) diff --git a/BaseTools/Source/Python/UPT/UPT.py b/BaseTools/Source/Python/UPT/UPT.py index e7b0a8f264b1..17decda5c3e6 100644 --- a/BaseTools/Source/Python/UPT/UPT.py +++ b/BaseTools/Source/Python/UPT/UPT.py @@ -39,6 +39,7 @@ from Logger.ToolError import OPTION_CONFLICT from Logger.ToolError import FatalError from Logger.ToolError import UPT_ALREADY_INSTALLED_ERROR +from Common.MultipleWorkspace import MultipleWorkspace as mws import MkPkg import InstallPkg @@ -164,7 +165,7 @@ def Main(): setattr(Opt, Var[0], Var[1]) try: - GlobalData.gWORKSPACE = GetWorkspace() + GlobalData.gWORKSPACE, GlobalData.gPACKAGE_PATH = GetWorkspace() except FatalError, XExcept: if Logger.GetLevel() <= Logger.DEBUG_9: Logger.Quiet(ST.MSG_PYTHON_ON % (python_version(), platform) + format_exc()) diff --git a/BaseTools/Source/Python/Workspace/MetaFileParser.py b/BaseTools/Source/Python/Workspace/MetaFileParser.py index fe1f7fd6f642..e7d6df659590 100644 --- a/BaseTools/Source/Python/Workspace/MetaFileParser.py +++ b/BaseTools/Source/Python/Workspace/MetaFileParser.py @@ -343,9 +343,14 @@ def _DefineParser(self): Name, Value = self._ValueList[1], self._ValueList[2] # Sometimes, we need to make differences between EDK and EDK2 modules if Name == 'INF_VERSION': - try: - self._Version = int(Value, 0) - except: + if re.match(r'0[xX][\da-f-A-F]{5,8}', Value): + self._Version = int(Value, 0) + elif re.match(r'\d+\.\d+', Value): + ValueList = Value.split('.') + Major = '%04o' % int(ValueList[0], 0) + Minor = '%04o' % int(ValueList[1], 0) + self._Version = int('0x' + Major + Minor, 0) + else: EdkLogger.error('Parser', FORMAT_INVALID, "Invalid version number", ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex + 1) diff --git a/BaseTools/Source/Python/Workspace/WorkspaceDatabase.py b/BaseTools/Source/Python/Workspace/WorkspaceDatabase.py index fd10c5dfb9a8..46eb5d3a8c2f 100644 --- a/BaseTools/Source/Python/Workspace/WorkspaceDatabase.py +++ b/BaseTools/Source/Python/Workspace/WorkspaceDatabase.py @@ -21,6 +21,7 @@ import Common.EdkLogger as EdkLogger import Common.GlobalData as GlobalData +from Common.MultipleWorkspace import MultipleWorkspace as mws from Common.String import * from Common.DataType import * @@ -166,7 +167,7 @@ def _HandleOverridePath(self): ModuleFile = PathClass(NormPath(Record[0]), GlobalData.gWorkspace, Arch=self._Arch) RecordList = self._RawData[MODEL_META_DATA_COMPONENT_SOURCE_OVERRIDE_PATH, self._Arch, None, ModuleId] if RecordList != []: - SourceOverridePath = os.path.join(GlobalData.gWorkspace, NormPath(RecordList[0][0])) + SourceOverridePath = mws.join(GlobalData.gWorkspace, NormPath(RecordList[0][0])) # Check if the source override path exists if not os.path.isdir(SourceOverridePath): @@ -1954,7 +1955,13 @@ def _GetInfVersion(self): RecordList = self._RawData[MODEL_META_DATA_HEADER, self._Arch, self._Platform] for Record in RecordList: if Record[1] == TAB_INF_DEFINES_INF_VERSION: - self._AutoGenVersion = int(Record[2], 0) + if '.' in Record[2]: + ValueList = Record[2].split('.') + Major = '%04o' % int(ValueList[0], 0) + Minor = '%04o' % int(ValueList[1], 0) + self._AutoGenVersion = int('0x' + Major + Minor, 0) + else: + self._AutoGenVersion = int(Record[2], 0) break if self._AutoGenVersion == None: self._AutoGenVersion = 0x00010000 @@ -2179,8 +2186,11 @@ def _GetSourceFiles(self): if self.AutoGenVersion < 0x00010005: Macros["EDK_SOURCE"] = GlobalData.gEcpSource Macros['PROCESSOR'] = self._Arch + SourceFile = NormPath(Record[0], Macros) + if SourceFile[0] == os.path.sep: + SourceFile = mws.join(GlobalData.gWorkspace, SourceFile[1:]) # old module source files (Edk) - File = PathClass(NormPath(Record[0], Macros), self._ModuleDir, self._SourceOverridePath, + File = PathClass(SourceFile, self._ModuleDir, self._SourceOverridePath, '', False, self._Arch, ToolChainFamily, '', TagName, ToolCode) # check the file validation ErrorCode, ErrorInfo = File.Validate(CaseSensitive=False) @@ -2343,10 +2353,21 @@ def _GetIncludes(self): if File[0] == '.': File = os.path.join(self._ModuleDir, File) else: - File = os.path.join(GlobalData.gWorkspace, File) + File = mws.join(GlobalData.gWorkspace, File) File = RealPath(os.path.normpath(File)) if File: self._Includes.append(File) + if not File and Record[0].find('EFI_SOURCE') > -1: + # tricky to regard WorkSpace as EFI_SOURCE + Macros['EFI_SOURCE'] = GlobalData.gWorkspace + File = NormPath(Record[0], Macros) + if File[0] == '.': + File = os.path.join(self._ModuleDir, File) + else: + File = os.path.join(GlobalData.gWorkspace, File) + File = RealPath(os.path.normpath(File)) + if File: + self._Includes.append(File) return self._Includes ## Retrieve packages this module depends on @@ -2797,7 +2818,7 @@ def __getitem__(self, Key): def __init__(self, DbPath, RenewDb=False): self._DbClosedFlag = False if not DbPath: - DbPath = os.path.normpath(os.path.join(GlobalData.gWorkspace, 'Conf', GlobalData.gDatabasePath)) + DbPath = os.path.normpath(mws.join(GlobalData.gWorkspace, 'Conf', GlobalData.gDatabasePath)) # don't create necessary path for db in memory if DbPath != ':memory:': diff --git a/BaseTools/toolsetup.bat b/BaseTools/toolsetup.bat index 2afa8103ec7c..59874c58392f 100755 --- a/BaseTools/toolsetup.bat +++ b/BaseTools/toolsetup.bat @@ -113,30 +113,43 @@ if /I "%1"=="/?" goto Usage :set_PATH if defined WORKSPACE_TOOLS_PATH goto check_PATH - set PATH=%EDK_TOOLS_PATH%\Bin;%EDK_TOOLS_PATH%\Bin\Win32;%PATH% + if not defined EDK_TOOLS_BIN ( + if exist %EDK_TOOLS_PATH%\Bin\Win32 ( + set EDK_TOOLS_BIN=%EDK_TOOLS_PATH%\Bin\Win32 + ) else ( + echo. + echo !!! ERROR !!! Cannot find BaseTools Bin Win32!!! + echo Please check the directory %EDK_TOOLS_PATH%\Bin\Win32 + echo Or configure EDK_TOOLS_BIN env to point Win32 directory. + echo. + goto end + ) + ) + set PATH=%EDK_TOOLS_BIN%;%PATH% set WORKSPACE_TOOLS_PATH=%EDK_TOOLS_PATH% goto PATH_ok :check_PATH if "%EDK_TOOLS_PATH%"=="%WORKSPACE_TOOLS_PATH%" goto PATH_ok - set PATH=%EDK_TOOLS_PATH%\Bin;%EDK_TOOLS_PATH%\Bin\Win32;%PATH% + if not defined EDK_TOOLS_BIN ( + if exist %EDK_TOOLS_PATH%\Bin\Win32 ( + set EDK_TOOLS_BIN=%EDK_TOOLS_PATH%\Bin\Win32 + ) else ( + echo. + echo !!! ERROR !!! Cannot find BaseTools Bin Win32!!! + echo Please check the directory %EDK_TOOLS_PATH%\Bin\Win32 + echo Or configure EDK_TOOLS_BIN env to point Win32 directory. + echo. + goto end + ) + ) + set PATH=%EDK_TOOLS_BIN%;%PATH% set WORKSPACE_TOOLS_PATH=%EDK_TOOLS_PATH% echo Resetting the PATH variable to include the EDK_TOOLS_PATH for this session. :PATH_ok - echo PATH = %PATH% - echo. - if defined WORKSPACE ( - echo WORKSPACE = %WORKSPACE% - ) - echo EDK_TOOLS_PATH = %EDK_TOOLS_PATH% - if defined BASE_TOOLS_PATH ( - echo BASE_TOOLS_PATH = %BASE_TOOLS_PATH% - ) - echo. - REM -REM copy *.template to %WORKSPACE%\Conf +REM copy *.template to %CONF_PATH% REM if not defined WORKSPACE ( if defined RECONFIG ( @@ -147,49 +160,80 @@ if not defined WORKSPACE ( goto skip_reconfig ) -if NOT exist %WORKSPACE%\Conf ( - mkdir %WORKSPACE%\Conf +set CONF_PATH=%WORKSPACE%\Conf +if NOT exist %CONF_PATH% ( + if defined PACKAGES_PATH ( + for %%i IN (%PACKAGES_PATH%) DO ( + if exist %%~fi\Conf ( + set CONF_PATH=%%i\Conf + goto CopyConf + ) + ) + ) +) + +:CopyConf +if NOT exist %CONF_PATH% ( + mkdir %CONF_PATH% ) else ( if defined RECONFIG ( echo. - echo Over-writing the files in the WORKSPACE\Conf directory + echo Over-writing the files in the CONF_PATH directory echo using the default template files echo. ) ) -if NOT exist %WORKSPACE%\Conf\target.txt ( - echo copying ... target.template to %WORKSPACE%\Conf\target.txt +if NOT exist %CONF_PATH%\target.txt ( + echo copying ... target.template to %CONF_PATH%\target.txt if NOT exist %EDK_TOOLS_PATH%\Conf\target.template ( echo Error: target.template is missing at folder %EDK_TOOLS_PATH%\Conf\ ) - copy %EDK_TOOLS_PATH%\Conf\target.template %WORKSPACE%\Conf\target.txt > nul + copy %EDK_TOOLS_PATH%\Conf\target.template %CONF_PATH%\target.txt > nul ) else ( - if defined RECONFIG echo over-write ... target.template to %WORKSPACE%\Conf\target.txt - if defined RECONFIG copy /Y %EDK_TOOLS_PATH%\Conf\target.template %WORKSPACE%\Conf\target.txt > nul + if defined RECONFIG echo over-write ... target.template to %CONF_PATH%\target.txt + if defined RECONFIG copy /Y %EDK_TOOLS_PATH%\Conf\target.template %CONF_PATH%\target.txt > nul ) -if NOT exist %WORKSPACE%\Conf\tools_def.txt ( - echo copying ... tools_def.template to %WORKSPACE%\Conf\tools_def.txt +if NOT exist %CONF_PATH%\tools_def.txt ( + echo copying ... tools_def.template to %CONF_PATH%\tools_def.txt if NOT exist %EDK_TOOLS_PATH%\Conf\tools_def.template ( echo Error: tools_def.template is missing at folder %EDK_TOOLS_PATH%\Conf\ ) - copy %EDK_TOOLS_PATH%\Conf\tools_def.template %WORKSPACE%\Conf\tools_def.txt > nul + copy %EDK_TOOLS_PATH%\Conf\tools_def.template %CONF_PATH%\tools_def.txt > nul ) else ( - if defined RECONFIG echo over-write ... tools_def.template to %WORKSPACE%\Conf\tools_def.txt - if defined RECONFIG copy /Y %EDK_TOOLS_PATH%\Conf\tools_def.template %WORKSPACE%\Conf\tools_def.txt > nul + if defined RECONFIG echo over-write ... tools_def.template to %CONF_PATH%\tools_def.txt + if defined RECONFIG copy /Y %EDK_TOOLS_PATH%\Conf\tools_def.template %CONF_PATH%\tools_def.txt > nul ) -if NOT exist %WORKSPACE%\Conf\build_rule.txt ( - echo copying ... build_rule.template to %WORKSPACE%\Conf\build_rule.txt +if NOT exist %CONF_PATH%\build_rule.txt ( + echo copying ... build_rule.template to %CONF_PATH%\build_rule.txt if NOT exist %EDK_TOOLS_PATH%\Conf\build_rule.template ( echo Error: build_rule.template is missing at folder %EDK_TOOLS_PATH%\Conf\ ) - copy %EDK_TOOLS_PATH%\Conf\build_rule.template %WORKSPACE%\Conf\build_rule.txt > nul + copy %EDK_TOOLS_PATH%\Conf\build_rule.template %CONF_PATH%\build_rule.txt > nul ) else ( - if defined RECONFIG echo over-write ... build_rule.template to %WORKSPACE%\Conf\build_rule.txt - if defined RECONFIG copy /Y %EDK_TOOLS_PATH%\Conf\build_rule.template %WORKSPACE%\Conf\build_rule.txt > nul + if defined RECONFIG echo over-write ... build_rule.template to %CONF_PATH%\build_rule.txt + if defined RECONFIG copy /Y %EDK_TOOLS_PATH%\Conf\build_rule.template %CONF_PATH%\build_rule.txt > nul +) + +echo PATH = %PATH% +echo. +if defined WORKSPACE ( + echo WORKSPACE = %WORKSPACE% +) +if defined PACKAGES_PATH ( + echo PACKAGES_PATH = %PACKAGES_PATH% +) +echo EDK_TOOLS_PATH = %EDK_TOOLS_PATH% +if defined BASE_TOOLS_PATH ( + echo BASE_TOOLS_PATH = %BASE_TOOLS_PATH% +) +if defined EDK_TOOLS_BIN ( + echo EDK_TOOLS_BIN = %EDK_TOOLS_BIN% ) +echo CONF_PATH = %CONF_PATH% +echo. :skip_reconfig @@ -198,28 +242,26 @@ if NOT exist %WORKSPACE%\Conf\build_rule.txt ( @REM if defined FORCE_REBUILD goto check_build_environment if defined REBUILD goto check_build_environment -if not exist "%EDK_TOOLS_PATH%\Bin" goto check_build_environment - -IF NOT EXIST "%EDK_TOOLS_PATH%\Bin\Win32\BootSectImage.exe" goto check_build_environment -IF NOT EXIST "%EDK_TOOLS_PATH%\Bin\Win32\build.exe" goto check_build_environment -IF NOT EXIST "%EDK_TOOLS_PATH%\Bin\Win32\EfiLdrImage.exe" goto check_build_environment -IF NOT EXIST "%EDK_TOOLS_PATH%\Bin\Win32\EfiRom.exe" goto check_build_environment -IF NOT EXIST "%EDK_TOOLS_PATH%\Bin\Win32\GenBootSector.exe" goto check_build_environment -IF NOT EXIST "%EDK_TOOLS_PATH%\Bin\Win32\GenFds.exe" goto check_build_environment -IF NOT EXIST "%EDK_TOOLS_PATH%\Bin\Win32\GenFfs.exe" goto check_build_environment -IF NOT EXIST "%EDK_TOOLS_PATH%\Bin\Win32\GenFv.exe" goto check_build_environment -IF NOT EXIST "%EDK_TOOLS_PATH%\Bin\Win32\GenFw.exe" goto check_build_environment -IF NOT EXIST "%EDK_TOOLS_PATH%\Bin\Win32\GenPage.exe" goto check_build_environment -IF NOT EXIST "%EDK_TOOLS_PATH%\Bin\Win32\GenSec.exe" goto check_build_environment -IF NOT EXIST "%EDK_TOOLS_PATH%\Bin\Win32\GenVtf.exe" goto check_build_environment -IF NOT EXIST "%EDK_TOOLS_PATH%\Bin\Win32\MigrationMsa2Inf.exe" goto check_build_environment -IF NOT EXIST "%EDK_TOOLS_PATH%\Bin\Win32\Split.exe" goto check_build_environment -IF NOT EXIST "%EDK_TOOLS_PATH%\Bin\Win32\TargetTool.exe" goto check_build_environment -IF NOT EXIST "%EDK_TOOLS_PATH%\Bin\Win32\TianoCompress.exe" goto check_build_environment -IF NOT EXIST "%EDK_TOOLS_PATH%\Bin\Win32\Trim.exe" goto check_build_environment -IF NOT EXIST "%EDK_TOOLS_PATH%\Bin\Win32\VfrCompile.exe" goto check_build_environment -IF NOT EXIST "%EDK_TOOLS_PATH%\Bin\Win32\Fpd2Dsc.exe" goto check_build_environment -IF NOT EXIST "%EDK_TOOLS_PATH%\Bin\Win32\VolInfo.exe" goto check_build_environment +if not exist "%EDK_TOOLS_PATH%" goto check_build_environment + +IF NOT EXIST "%EDK_TOOLS_BIN%\BootSectImage.exe" goto check_build_environment +IF NOT EXIST "%EDK_TOOLS_BIN%\build.exe" goto check_build_environment +IF NOT EXIST "%EDK_TOOLS_BIN%\EfiLdrImage.exe" goto check_build_environment +IF NOT EXIST "%EDK_TOOLS_BIN%\EfiRom.exe" goto check_build_environment +IF NOT EXIST "%EDK_TOOLS_BIN%\GenBootSector.exe" goto check_build_environment +IF NOT EXIST "%EDK_TOOLS_BIN%\GenFds.exe" goto check_build_environment +IF NOT EXIST "%EDK_TOOLS_BIN%\GenFfs.exe" goto check_build_environment +IF NOT EXIST "%EDK_TOOLS_BIN%\GenFv.exe" goto check_build_environment +IF NOT EXIST "%EDK_TOOLS_BIN%\GenFw.exe" goto check_build_environment +IF NOT EXIST "%EDK_TOOLS_BIN%\GenPage.exe" goto check_build_environment +IF NOT EXIST "%EDK_TOOLS_BIN%\GenSec.exe" goto check_build_environment +IF NOT EXIST "%EDK_TOOLS_BIN%\GenVtf.exe" goto check_build_environment +IF NOT EXIST "%EDK_TOOLS_BIN%\Split.exe" goto check_build_environment +IF NOT EXIST "%EDK_TOOLS_BIN%\TargetTool.exe" goto check_build_environment +IF NOT EXIST "%EDK_TOOLS_BIN%\TianoCompress.exe" goto check_build_environment +IF NOT EXIST "%EDK_TOOLS_BIN%\Trim.exe" goto check_build_environment +IF NOT EXIST "%EDK_TOOLS_BIN%\VfrCompile.exe" goto check_build_environment +IF NOT EXIST "%EDK_TOOLS_BIN%\VolInfo.exe" goto check_build_environment goto end From 01c307eacd05fc15cfc1d2d0444867f7f9e9da82 Mon Sep 17 00:00:00 2001 From: Qin Long Date: Mon, 16 Nov 2015 06:38:00 +0000 Subject: [PATCH 070/525] MdePkg: Add CPU RdRand access APIs for random number generation Add AsmRdRand16/32/64 APIs for RdRand instruction access to generate high-quality random number. (Sync patch r18518 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Qin Long Reviewed-by: Michael Kinney Reviewed-by: Liming Gao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18785 6f19259b-4bc3-4df7-8a09-765794883524 --- MdePkg/Include/Library/BaseLib.h | 51 ++++++++++++++ MdePkg/Library/BaseLib/BaseLib.inf | 6 ++ MdePkg/Library/BaseLib/Ia32/RdRand.S | 80 ++++++++++++++++++++++ MdePkg/Library/BaseLib/Ia32/RdRand.asm | 94 ++++++++++++++++++++++++++ MdePkg/Library/BaseLib/X64/RdRand.S | 72 ++++++++++++++++++++ MdePkg/Library/BaseLib/X64/RdRand.asm | 83 +++++++++++++++++++++++ 6 files changed, 386 insertions(+) create mode 100644 MdePkg/Library/BaseLib/Ia32/RdRand.S create mode 100644 MdePkg/Library/BaseLib/Ia32/RdRand.asm create mode 100644 MdePkg/Library/BaseLib/X64/RdRand.S create mode 100644 MdePkg/Library/BaseLib/X64/RdRand.asm diff --git a/MdePkg/Include/Library/BaseLib.h b/MdePkg/Include/Library/BaseLib.h index 7e10804082d1..c41fa783df2b 100644 --- a/MdePkg/Include/Library/BaseLib.h +++ b/MdePkg/Include/Library/BaseLib.h @@ -7647,6 +7647,57 @@ AsmPrepareAndThunk16 ( IN OUT THUNK_CONTEXT *ThunkContext ); +/** + Generates a 16-bit random number through RDRAND instruction. + + if Rand is NULL, then ASSERT(). + + @param[out] Rand Buffer pointer to store the random result. + + @retval TRUE RDRAND call was successful. + @retval FALSE Failed attempts to call RDRAND. + + **/ +BOOLEAN +EFIAPI +AsmRdRand16 ( + OUT UINT16 *Rand + ); + +/** + Generates a 32-bit random number through RDRAND instruction. + + if Rand is NULL, then ASSERT(). + + @param[out] Rand Buffer pointer to store the random result. + + @retval TRUE RDRAND call was successful. + @retval FALSE Failed attempts to call RDRAND. + +**/ +BOOLEAN +EFIAPI +AsmRdRand32 ( + OUT UINT32 *Rand + ); + +/** + Generates a 64-bit random number through RDRAND instruction. + + if Rand is NULL, then ASSERT(). + + @param[out] Rand Buffer pointer to store the random result. + + @retval TRUE RDRAND call was successful. + @retval FALSE Failed attempts to call RDRAND. + +**/ +BOOLEAN +EFIAPI +AsmRdRand64 ( + OUT UINT64 *Rand + ); + #endif #endif diff --git a/MdePkg/Library/BaseLib/BaseLib.inf b/MdePkg/Library/BaseLib/BaseLib.inf index 4a37e60fe38b..4cc86d7e5d2f 100644 --- a/MdePkg/Library/BaseLib/BaseLib.inf +++ b/MdePkg/Library/BaseLib/BaseLib.inf @@ -159,6 +159,7 @@ Ia32/EnablePaging64.asm | MSFT Ia32/EnableCache.c | MSFT Ia32/DisableCache.c | MSFT + Ia32/RdRand.asm | MSFT Ia32/Wbinvd.asm | INTEL Ia32/WriteMm7.asm | INTEL @@ -252,6 +253,7 @@ Ia32/EnablePaging64.asm | INTEL Ia32/EnableCache.asm | INTEL Ia32/DisableCache.asm | INTEL + Ia32/RdRand.asm | INTEL Ia32/GccInline.c | GCC Ia32/Thunk16.nasm | GCC @@ -279,6 +281,7 @@ Ia32/LShiftU64.S | GCC Ia32/EnableCache.S | GCC Ia32/DisableCache.S | GCC + Ia32/RdRand.S | GCC Ia32/DivS64x64Remainder.c Ia32/InternalSwitchStack.c | MSFT @@ -383,10 +386,12 @@ X64/CpuBreakpoint.c | MSFT X64/WriteMsr64.c | MSFT X64/ReadMsr64.c | MSFT + X64/RdRand.asm | MSFT X64/CpuBreakpoint.asm | INTEL X64/WriteMsr64.asm | INTEL X64/ReadMsr64.asm | INTEL + X64/RdRand.asm | INTEL X64/Non-existing.c Math64.c @@ -417,6 +422,7 @@ X64/CpuIdEx.S | GCC X64/EnableCache.S | GCC X64/DisableCache.S | GCC + X64/RdRand.S | GCC ChkStkGcc.c | GCC [Sources.IPF] diff --git a/MdePkg/Library/BaseLib/Ia32/RdRand.S b/MdePkg/Library/BaseLib/Ia32/RdRand.S new file mode 100644 index 000000000000..503f65a72107 --- /dev/null +++ b/MdePkg/Library/BaseLib/Ia32/RdRand.S @@ -0,0 +1,80 @@ +#------------------------------------------------------------------------------ ; +# Copyright (c) 2015, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# Module Name: +# +# RdRand.S +# +# Abstract: +# +# Generates random number through CPU RdRand instruction under 32-bit platform. +# +# Notes: +# +#------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Generates a 16 bit random number through RDRAND instruction. +// Return TRUE if Rand generated successfully, or FALSE if not. +// +// BOOLEAN EFIAPI AsmRdRand16 (UINT16 *Rand); +//------------------------------------------------------------------------------ +ASM_GLOBAL ASM_PFX(AsmRdRand16) +ASM_PFX(AsmRdRand16): + .byte 0x0f, 0xc7, 0xf0 // rdrand r16: "0f c7 /6 ModRM:r/m(w)" + jc rn16_ok // jmp if CF=1 + xor %eax, %eax // reg=0 if CF=0 + ret // return with failure status +rn16_ok: + mov 0x4(%esp), %edx + mov %ax, (%edx) + mov $0x1, %eax + ret + +//------------------------------------------------------------------------------ +// Generates a 32 bit random number through RDRAND instruction. +// Return TRUE if Rand generated successfully, or FALSE if not. +// +// BOOLEAN EFIAPI AsmRdRand32 (UINT32 *Rand); +//------------------------------------------------------------------------------ +ASM_GLOBAL ASM_PFX(AsmRdRand32) +ASM_PFX(AsmRdRand32): + .byte 0x0f, 0xc7, 0xf0 // rdrand r32: "0f c7 /6 ModRM:r/m(w)" + jc rn32_ok // jmp if CF=1 + xor %eax, %eax // reg=0 if CF=0 + ret // return with failure status +rn32_ok: + mov 0x4(%esp), %edx + mov %eax, (%edx) + mov $0x1, %eax + ret + +//------------------------------------------------------------------------------ +// Generates a 64 bit random number through RDRAND instruction. +// Return TRUE if Rand generated successfully, or FALSE if not. +// +// BOOLEAN EFIAPI AsmRdRand64 (UINT64 *Rand); +//------------------------------------------------------------------------------ +ASM_GLOBAL ASM_PFX(AsmRdRand64) +ASM_PFX(AsmRdRand64): + .byte 0x0f, 0xc7, 0xf0 // rdrand r32: "0f c7 /6 ModRM:r/m(w)" + jnc rn64_ret // jmp if CF=0 + mov 0x4(%esp), %edx + mov %eax, (%edx) + + .byte 0x0f, 0xc7, 0xf0 // generate another 32 bit RN + jnc rn64_ret // jmp if CF=0 + mov %eax, 0x4(%edx) + + mov $0x1, %eax + ret +rn64_ret: + xor %eax, %eax + ret // return with failure status diff --git a/MdePkg/Library/BaseLib/Ia32/RdRand.asm b/MdePkg/Library/BaseLib/Ia32/RdRand.asm new file mode 100644 index 000000000000..21349b0918d4 --- /dev/null +++ b/MdePkg/Library/BaseLib/Ia32/RdRand.asm @@ -0,0 +1,94 @@ +;------------------------------------------------------------------------------ +; +; Copyright (c) 2015, Intel Corporation. All rights reserved.
+; This program and the accompanying materials +; are licensed and made available under the terms and conditions of the BSD License +; which accompanies this distribution. The full text of the license may be found at +; http://opensource.org/licenses/bsd-license.php. +; +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +; +; Module Name: +; +; RdRand.asm +; +; Abstract: +; +; Generates random number through CPU RdRand instruction under 32-bit platform. +; +; Notes: +; +;------------------------------------------------------------------------------ + +.686P +.model flat, C + +.code + +;------------------------------------------------------------------------------ +; Generates a 16 bit random number through RDRAND instruction. +; Return TRUE if Rand generated successfully, or FALSE if not. +; +; BOOLEAN EFIAPI AsmRdRand16 (UINT16 *Rand); +;------------------------------------------------------------------------------ +AsmRdRand16 PROC + ; rdrand ax ; generate a 16 bit RN into ax + ; CF=1 if RN generated ok, otherwise CF=0 + db 0fh, 0c7h, 0f0h ; rdrand r16: "0f c7 /6 ModRM:r/m(w)" + jc rn16_ok ; jmp if CF=1 + xor eax, eax ; reg=0 if CF=0 + ret ; return with failure status +rn16_ok: + mov edx, dword ptr [esp + 4] + mov [edx], ax + mov eax, 1 + ret +AsmRdRand16 ENDP + +;------------------------------------------------------------------------------ +; Generates a 32 bit random number through RDRAND instruction. +; Return TRUE if Rand generated successfully, or FALSE if not. +; +; BOOLEAN EFIAPI AsmRdRand32 (UINT32 *Rand); +;------------------------------------------------------------------------------ +AsmRdRand32 PROC + ; rdrand eax ; generate a 32 bit RN into eax + ; CF=1 if RN generated ok, otherwise CF=0 + db 0fh, 0c7h, 0f0h ; rdrand r32: "0f c7 /6 ModRM:r/m(w)" + jc rn32_ok ; jmp if CF=1 + xor eax, eax ; reg=0 if CF=0 + ret ; return with failure status +rn32_ok: + mov edx, dword ptr [esp + 4] + mov [edx], eax + mov eax, 1 + ret +AsmRdRand32 ENDP + +;------------------------------------------------------------------------------ +; Generates a 64 bit random number through RDRAND instruction. +; Return TRUE if Rand generated successfully, or FALSE if not. +; +; BOOLEAN EFIAPI AsmRdRand64 (UINT64 *Rand); +;------------------------------------------------------------------------------ +AsmRdRand64 PROC + ; rdrand eax ; generate a 32 bit RN into eax + ; CF=1 if RN generated ok, otherwise CF=0 + db 0fh, 0c7h, 0f0h ; rdrand r32: "0f c7 /6 ModRM:r/m(w)" + jnc rn64_ret ; jmp if CF=0 + mov edx, dword ptr [esp + 4] + mov [edx], eax + + db 0fh, 0c7h, 0f0h ; generate another 32 bit RN + jnc rn64_ret ; jmp if CF=0 + mov [edx + 4], eax + + mov eax, 1 + ret +rn64_ret: + xor eax, eax + ret ; return with failure status +AsmRdRand64 ENDP + + END diff --git a/MdePkg/Library/BaseLib/X64/RdRand.S b/MdePkg/Library/BaseLib/X64/RdRand.S new file mode 100644 index 000000000000..49b50e69013d --- /dev/null +++ b/MdePkg/Library/BaseLib/X64/RdRand.S @@ -0,0 +1,72 @@ +#------------------------------------------------------------------------------ ; +# Copyright (c) 2015, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# Module Name: +# +# RdRand.S +# +# Abstract: +# +# Generates random number through CPU RdRand instruction under 64-bit platform. +# +# Notes: +# +#------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Generates a 16 bit random number through RDRAND instruction. +// Return TRUE if Rand generated successfully, or FALSE if not. +// +// BOOLEAN EFIAPI AsmRdRand16 (UINT16 *Rand); +//------------------------------------------------------------------------------ +ASM_GLOBAL ASM_PFX(AsmRdRand16) +ASM_PFX(AsmRdRand16): + .byte 0x0f, 0xc7, 0xf0 // rdrand r16: "0f c7 /6 ModRM:r/m(w)" + jc rn16_ok // jmp if CF=1 + xor %rax, %rax // reg=0 if CF=0 + ret // return with failure status +rn16_ok: + mov %ax, (%rcx) + mov $0x1, %rax + ret + +//------------------------------------------------------------------------------ +// Generates a 32 bit random number through RDRAND instruction. +// Return TRUE if Rand generated successfully, or FALSE if not. +// +// BOOLEAN EFIAPI AsmRdRand32 (UINT32 *Rand); +//------------------------------------------------------------------------------ +ASM_GLOBAL ASM_PFX(AsmRdRand32) +ASM_PFX(AsmRdRand32): + .byte 0x0f, 0xc7, 0xf0 // rdrand r32: "0f c7 /6 ModRM:r/m(w)" + jc rn32_ok // jmp if CF=1 + xor %rax, %rax // reg=0 if CF=0 + ret // return with failure status +rn32_ok: + mov %eax, (%rcx) + mov $0x1, %rax + ret + +//------------------------------------------------------------------------------ +// Generates a 64 bit random number through RDRAND instruction. +// Return TRUE if Rand generated successfully, or FALSE if not. +// +// BOOLEAN EFIAPI AsmRdRand64 (UINT64 *Rand); +//------------------------------------------------------------------------------ +ASM_GLOBAL ASM_PFX(AsmRdRand64) +ASM_PFX(AsmRdRand64): + .byte 0x48, 0x0f, 0xc7, 0xf0 // rdrand r64: "REX.W + 0f c7 /6 ModRM:r/m(w)" + jc rn64_ok // jmp if CF=1 + xor %rax, %rax // reg=0 if CF=0 + ret // return with failure status +rn64_ok: + mov %rax, (%rcx) + mov $0x1, %rax + ret diff --git a/MdePkg/Library/BaseLib/X64/RdRand.asm b/MdePkg/Library/BaseLib/X64/RdRand.asm new file mode 100644 index 000000000000..370cdb607a70 --- /dev/null +++ b/MdePkg/Library/BaseLib/X64/RdRand.asm @@ -0,0 +1,83 @@ +;------------------------------------------------------------------------------ +; +; Copyright (c) 2015, Intel Corporation. All rights reserved.
+; This program and the accompanying materials +; are licensed and made available under the terms and conditions of the BSD License +; which accompanies this distribution. The full text of the license may be found at +; http://opensource.org/licenses/bsd-license.php. +; +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +; +; Module Name: +; +; RdRand.asm +; +; Abstract: +; +; Generates random number through CPU RdRand instruction under 64-bit platform. +; +; Notes: +; +;------------------------------------------------------------------------------ + + .code + +;------------------------------------------------------------------------------ +; Generates a 16 bit random number through RDRAND instruction. +; Return TRUE if Rand generated successfully, or FALSE if not. +; +; BOOLEAN EFIAPI AsmRdRand16 (UINT16 *Rand); +;------------------------------------------------------------------------------ +AsmRdRand16 PROC + ; rdrand ax ; generate a 16 bit RN into eax, + ; CF=1 if RN generated ok, otherwise CF=0 + db 0fh, 0c7h, 0f0h ; rdrand r16: "0f c7 /6 ModRM:r/m(w)" + jc rn16_ok ; jmp if CF=1 + xor rax, rax ; reg=0 if CF=0 + ret ; return with failure status +rn16_ok: + mov [rcx], ax + mov rax, 1 + ret +AsmRdRand16 ENDP + +;------------------------------------------------------------------------------ +; Generates a 32 bit random number through RDRAND instruction. +; Return TRUE if Rand generated successfully, or FALSE if not. +; +; BOOLEAN EFIAPI AsmRdRand32 (UINT32 *Rand); +;------------------------------------------------------------------------------ +AsmRdRand32 PROC + ; rdrand eax ; generate a 32 bit RN into eax, + ; CF=1 if RN generated ok, otherwise CF=0 + db 0fh, 0c7h, 0f0h ; rdrand r32: "0f c7 /6 ModRM:r/m(w)" + jc rn32_ok ; jmp if CF=1 + xor rax, rax ; reg=0 if CF=0 + ret ; return with failure status +rn32_ok: + mov [rcx], eax + mov rax, 1 + ret +AsmRdRand32 ENDP + +;------------------------------------------------------------------------------ +; Generates a 64 bit random number through one RDRAND instruction. +; Return TRUE if Rand generated successfully, or FALSE if not. +; +; BOOLEAN EFIAPI AsmRdRand64 (UINT64 *Random); +;------------------------------------------------------------------------------ +AsmRdRand64 PROC + ; rdrand rax ; generate a 64 bit RN into rax, + ; CF=1 if RN generated ok, otherwise CF=0 + db 048h, 0fh, 0c7h, 0f0h ; rdrand r64: "REX.W + 0f c7 /6 ModRM:r/m(w)" + jc rn64_ok ; jmp if CF=1 + xor rax, rax ; reg=0 if CF=0 + ret ; return with failure status +rn64_ok: + mov [rcx], rax + mov rax, 1 + ret +AsmRdRand64 ENDP + + END From 8b5a1bf12b775a84278b6d7a4e1970a6729b8b77 Mon Sep 17 00:00:00 2001 From: Qin Long Date: Mon, 16 Nov 2015 06:38:54 +0000 Subject: [PATCH 071/525] MdePkg: Add RngLib into MdePkg Add one library class (RngLib.h) with three GetRandomNumber16/32/64 APIs to provide random number generator services, and one library instance (BaseRngLib), based on Intel RdRand instruction access, to provide high-quality random numbers generator. (Sync patch r18519 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Qin Long Reviewed-by: Michael Kinney Reviewed-by: Liming Gao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18786 6f19259b-4bc3-4df7-8a09-765794883524 --- MdePkg/Include/Library/RngLib.h | 69 ++++++++++ MdePkg/Library/BaseRngLib/BaseRng.c | 157 +++++++++++++++++++++++ MdePkg/Library/BaseRngLib/BaseRngLib.inf | 41 ++++++ MdePkg/Library/BaseRngLib/BaseRngLib.uni | Bin 0 -> 1878 bytes MdePkg/MdePkg.dec | 4 + MdePkg/MdePkg.dsc | 1 + 6 files changed, 272 insertions(+) create mode 100644 MdePkg/Include/Library/RngLib.h create mode 100644 MdePkg/Library/BaseRngLib/BaseRng.c create mode 100644 MdePkg/Library/BaseRngLib/BaseRngLib.inf create mode 100644 MdePkg/Library/BaseRngLib/BaseRngLib.uni diff --git a/MdePkg/Include/Library/RngLib.h b/MdePkg/Include/Library/RngLib.h new file mode 100644 index 000000000000..157a93139c24 --- /dev/null +++ b/MdePkg/Include/Library/RngLib.h @@ -0,0 +1,69 @@ +/** @file + Provides random number generator services. + +Copyright (c) 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __RNG_LIB_H__ +#define __RNG_LIB_H__ + +/** + Generates a 16-bit random number. + + if Rand is NULL, then ASSERT(). + + @param[out] Rand Buffer pointer to store the 16-bit random value. + + @retval TRUE Random number generated successfully. + @retval FALSE Failed to generate the random number. + +**/ +BOOLEAN +EFIAPI +GetRandomNumber16 ( + OUT UINT16 *Rand + ); + +/** + Generates a 32-bit random number. + + if Rand is NULL, then ASSERT(). + + @param[out] Rand Buffer pointer to store the 32-bit random value. + + @retval TRUE Random number generated successfully. + @retval FALSE Failed to generate the random number. + +**/ +BOOLEAN +EFIAPI +GetRandomNumber32 ( + OUT UINT32 *Rand + ); + +/** + Generates a 64-bit random number. + + if Rand is NULL, then ASSERT(). + + @param[out] Rand Buffer pointer to store the 64-bit random value. + + @retval TRUE Random number generated successfully. + @retval FALSE Failed to generate the random number. + +**/ +BOOLEAN +EFIAPI +GetRandomNumber64 ( + OUT UINT64 *Rand + ); + +#endif // __RNG_LIB_H__ diff --git a/MdePkg/Library/BaseRngLib/BaseRng.c b/MdePkg/Library/BaseRngLib/BaseRng.c new file mode 100644 index 000000000000..279df3013c9f --- /dev/null +++ b/MdePkg/Library/BaseRngLib/BaseRng.c @@ -0,0 +1,157 @@ +/** @file + Random number generator services that uses RdRand instruction access + to provide high-quality random numbers. + +Copyright (c) 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include + +// +// Bit mask used to determine if RdRand instruction is supported. +// +#define RDRAND_MASK BIT30 + +// +// Limited retry number when valid random data is returned. +// Uses the recommended value defined in Section 7.3.17 of "Intel 64 and IA-32 +// Architectures Software Developer's Mannual". +// +#define RDRAND_RETRY_LIMIT 10 + +/** + The constructor function checks whether or not RDRAND instruction is supported + by the host hardware. + + The constructor function checks whether or not RDRAND instruction is supported. + It will ASSERT() if RDRAND instruction is not supported. + It will always return RETURN_SUCCESS. + + @retval RETURN_SUCCESS The constructor always returns EFI_SUCCESS. + +**/ +RETURN_STATUS +EFIAPI +BaseRngLibConstructor ( + VOID + ) +{ + UINT32 RegEcx; + + // + // Determine RDRAND support by examining bit 30 of the ECX register returned by + // CPUID. A value of 1 indicates that processor support RDRAND instruction. + // + AsmCpuid (1, 0, 0, &RegEcx, 0); + ASSERT ((RegEcx & RDRAND_MASK) == RDRAND_MASK); + + return RETURN_SUCCESS; +} + +/** + Generates a 16-bit random number. + + if Rand is NULL, then ASSERT(). + + @param[out] Rand Buffer pointer to store the 16-bit random value. + + @retval TRUE Random number generated successfully. + @retval FALSE Failed to generate the random number. + +**/ +BOOLEAN +EFIAPI +GetRandomNumber16 ( + OUT UINT16 *Rand + ) +{ + UINT32 Index; + + ASSERT (Rand != NULL); + + // + // A loop to fetch a 16 bit random value with a retry count limit. + // + for (Index = 0; Index < RDRAND_RETRY_LIMIT; Index++) { + if (AsmRdRand16 (Rand)) { + return TRUE; + } + } + + return FALSE; +} + +/** + Generates a 32-bit random number. + + if Rand is NULL, then ASSERT(). + + @param[out] Rand Buffer pointer to store the 32-bit random value. + + @retval TRUE Random number generated successfully. + @retval FALSE Failed to generate the random number. + +**/ +BOOLEAN +EFIAPI +GetRandomNumber32 ( + OUT UINT32 *Rand + ) +{ + UINT32 Index; + + ASSERT (Rand != NULL); + + // + // A loop to fetch a 32 bit random value with a retry count limit. + // + for (Index = 0; Index < RDRAND_RETRY_LIMIT; Index++) { + if (AsmRdRand32 (Rand)) { + return TRUE; + } + } + + return FALSE; +} + +/** + Generates a 64-bit random number. + + if Rand is NULL, then ASSERT(). + + @param[out] Rand Buffer pointer to store the 64-bit random value. + + @retval TRUE Random number generated successfully. + @retval FALSE Failed to generate the random number. + +**/ +BOOLEAN +EFIAPI +GetRandomNumber64 ( + OUT UINT64 *Rand + ) +{ + UINT32 Index; + + ASSERT (Rand != NULL); + + // + // A loop to fetch a 64 bit random value with a retry count limit. + // + for (Index = 0; Index < RDRAND_RETRY_LIMIT; Index++) { + if (AsmRdRand64 (Rand)) { + return TRUE; + } + } + + return FALSE; +} diff --git a/MdePkg/Library/BaseRngLib/BaseRngLib.inf b/MdePkg/Library/BaseRngLib/BaseRngLib.inf new file mode 100644 index 000000000000..05a5b77dc351 --- /dev/null +++ b/MdePkg/Library/BaseRngLib/BaseRngLib.inf @@ -0,0 +1,41 @@ +## @file +# Instance of RNG (Random Number Generator) Library. +# +# BaseRng Library that uses CPU RdRand instruction access to provide +# high-quality random numbers. +# +# Copyright (c) 2015, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = BaseRngLib + MODULE_UNI_FILE = BaseRngLib.uni + FILE_GUID = 626440D8-1971-41D9-9AB2-FB25F4AE79BC + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = RngLib + CONSTRUCTOR = BaseRngLibConstructor + +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources.Ia32, Sources.X64] + BaseRng.c + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + BaseLib + DebugLib diff --git a/MdePkg/Library/BaseRngLib/BaseRngLib.uni b/MdePkg/Library/BaseRngLib/BaseRngLib.uni new file mode 100644 index 0000000000000000000000000000000000000000..3d6e905d79a40b0c90329a576bcdb193cee6cf06 GIT binary patch literal 1878 zcmd6nU2hUW6o${WiT`0kZ>niQO}sJ2Sjt+7TF3&aUNs9?*n|S^QYwF5ecl;%2W+n=XS<= z$WFR3@@vlLcEdWvGUs&0I(Pe&7z<>NkiI9&kbTO#v3iv)WNo4=@JsNX-0_HrHN|3u z=Em6->`tv~1J(pAC8mf>9)FJI2#*XDbF5NMs;A&lyanGScow$CW{f7FnIf5x@z}l) zC5533j}0EGA=EzKslB+ju2bSK@yxdoRly-R#L6>!Vo&Y49kCbdD=^I1%O}T6U)Ag@ zsG~VSFN+XOwdAfU@xNv_2FFWl!pN(tqEK0%sxrrbuYKZjsE@ub&$PPk`BIOUPPf6& z_vYH6QofAcjA$XgIxKH7CbrcJVG8l(Ew&|D^J@N5rbAPx?uuPMOX|5~;w1-%YAsQY zU`Lkfi|0pLKdGf((|XoIs_6?@0@ho{#fb0SYBO^BIVt&4F5L@NJp^Z&SA7wyLVAVV zcSxAOV)HYmeO@A}O5I%P{>Xo^Wk85lJG@Rgt?0xHcS|)>o?F@HuDZILmkIj)90igg z$j40czNSu;DQ~!ss^qQ3An7tc9d2{N%zfb8hRX;xwf2#=nXm!7*fBidFVJG2U{gj2 z?6;Zd7>k~Z++n9l*0;v0xQbe1ZMw5gM?1A&pjXt6%NW@OR*6G)j=W7&#pt-~2`6Ef zOga15%0^ke)f;S;{S)guG(xT$7;m%qDq{Os#R<{daM5L+l(V(NTbL>RR~rtyWO@&( zsqweR^LI(44lxEqi|rCb;!Dh)z*ZkTzj_YnqHe*2&Zm4eH=2cGVhL#tbiepq0P kajio8cSzOe9vC$P-HO}$(Eb_e|M1t3++X0||Mr2mAF7cjiU0rr literal 0 HcmV?d00001 diff --git a/MdePkg/MdePkg.dec b/MdePkg/MdePkg.dec index 60549afaaafc..337059a6a602 100644 --- a/MdePkg/MdePkg.dec +++ b/MdePkg/MdePkg.dec @@ -249,6 +249,10 @@ # SmmPeriodicSmiLib|Include/Library/SmmPeriodicSmiLib.h + ## @libraryclass Provides services to generate random number. + # + RngLib|Include/Library/RngLib.h + [LibraryClasses.IPF] ## @libraryclass The SAL Library provides a service to make a SAL CALL. SalLib|Include/Library/SalLib.h diff --git a/MdePkg/MdePkg.dsc b/MdePkg/MdePkg.dsc index 89fc6304c4a3..e8a3ea76332e 100644 --- a/MdePkg/MdePkg.dsc +++ b/MdePkg/MdePkg.dsc @@ -151,6 +151,7 @@ MdePkg/Library/BaseS3SmbusLib/BaseS3SmbusLib.inf MdePkg/Library/BaseS3StallLib/BaseS3StallLib.inf MdePkg/Library/SmmMemLib/SmmMemLib.inf + MdePkg/Library/BaseRngLib/BaseRngLib.inf [Components.IPF] MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf From afcd7b24c523edfa9f562c07a47f3f3c62cc0752 Mon Sep 17 00:00:00 2001 From: Samer El-Haj-Mahmoud Date: Mon, 16 Nov 2015 06:48:33 +0000 Subject: [PATCH 072/525] MdeModulePkg: Add SMBIOS 3.0 support in NetLibGetSystemGuid. NetLibGetSystemGuid gets the UUID from SMBIOS table to use as the System GUID (in DHCP and other network use cases). This change adds support to get the UUID from either SMBIOS 2.x or 3.0, since SMBIOS 3.0 uses a different GUID in the System Configuration Table. (Sync patch r18559 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Samer El-Haj-Mahmoud Reviewed-by: Fu Siyuan git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18787 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Library/DxeNetLib/DxeNetLib.c | 30 ++++++++++++-------- MdeModulePkg/Library/DxeNetLib/DxeNetLib.inf | 2 ++ 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/MdeModulePkg/Library/DxeNetLib/DxeNetLib.c b/MdeModulePkg/Library/DxeNetLib/DxeNetLib.c index 57e8f9f27b0d..e112d45ef21c 100644 --- a/MdeModulePkg/Library/DxeNetLib/DxeNetLib.c +++ b/MdeModulePkg/Library/DxeNetLib/DxeNetLib.c @@ -2,6 +2,7 @@ Network library. Copyright (c) 2005 - 2015, Intel Corporation. All rights reserved.
+(C) Copyright 2015 Hewlett Packard Enterprise Development LP
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -3254,22 +3255,27 @@ NetLibGetSystemGuid ( OUT EFI_GUID *SystemGuid ) { - EFI_STATUS Status; - SMBIOS_TABLE_ENTRY_POINT *SmbiosTable; - SMBIOS_STRUCTURE_POINTER Smbios; - SMBIOS_STRUCTURE_POINTER SmbiosEnd; - CHAR8 *String; + EFI_STATUS Status; + SMBIOS_TABLE_ENTRY_POINT *SmbiosTable; + SMBIOS_TABLE_3_0_ENTRY_POINT *Smbios30Table; + SMBIOS_STRUCTURE_POINTER Smbios; + SMBIOS_STRUCTURE_POINTER SmbiosEnd; + CHAR8 *String; SmbiosTable = NULL; - Status = EfiGetSystemConfigurationTable (&gEfiSmbiosTableGuid, (VOID **) &SmbiosTable); - - if (EFI_ERROR (Status) || SmbiosTable == NULL) { - return EFI_NOT_FOUND; + Status = EfiGetSystemConfigurationTable (&gEfiSmbios3TableGuid, (VOID **) &Smbios30Table); + if (!(EFI_ERROR (Status) || Smbios30Table == NULL)) { + Smbios.Hdr = (SMBIOS_STRUCTURE *) (UINTN) Smbios30Table->TableAddress; + SmbiosEnd.Raw = (UINT8 *) (UINTN) (Smbios30Table->TableAddress + Smbios30Table->TableMaximumSize); + } else { + Status = EfiGetSystemConfigurationTable (&gEfiSmbiosTableGuid, (VOID **) &SmbiosTable); + if (EFI_ERROR (Status) || SmbiosTable == NULL) { + return EFI_NOT_FOUND; + } + Smbios.Hdr = (SMBIOS_STRUCTURE *) (UINTN) SmbiosTable->TableAddress; + SmbiosEnd.Raw = (UINT8 *) (UINTN) (SmbiosTable->TableAddress + SmbiosTable->TableLength); } - Smbios.Hdr = (SMBIOS_STRUCTURE *) (UINTN) SmbiosTable->TableAddress; - SmbiosEnd.Raw = (UINT8 *) (UINTN) (SmbiosTable->TableAddress + SmbiosTable->TableLength); - do { if (Smbios.Hdr->Type == 1) { if (Smbios.Hdr->Length < 0x19) { diff --git a/MdeModulePkg/Library/DxeNetLib/DxeNetLib.inf b/MdeModulePkg/Library/DxeNetLib/DxeNetLib.inf index 50fbcc24b503..1ff3a4fe556a 100644 --- a/MdeModulePkg/Library/DxeNetLib/DxeNetLib.inf +++ b/MdeModulePkg/Library/DxeNetLib/DxeNetLib.inf @@ -2,6 +2,7 @@ # This library instance provides the basic network services. # # Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.
+# (C) Copyright 2015 Hewlett Packard Enterprise Development LP
# This program and the accompanying materials # are licensed and made available under the terms and conditions of the BSD License # which accompanies this distribution. The full text of the license may be found at @@ -52,6 +53,7 @@ [Guids] gEfiSmbiosTableGuid ## SOMETIMES_CONSUMES ## SystemTable + gEfiSmbios3TableGuid ## SOMETIMES_CONSUMES ## SystemTable [Protocols] From faf34685caed686109e68f2d7b55a3e3852852a6 Mon Sep 17 00:00:00 2001 From: Samer El-Haj-Mahmoud Date: Mon, 16 Nov 2015 06:49:28 +0000 Subject: [PATCH 073/525] MdeModulePkg Ip4Dxe: Ip4Config2 to request DHCP Option6 DNS server IP Ip4Config2 protocol implementation must request for DNS server info when the policy is set to DHCP. And when a DHCP server responds to it with a list of DNS server addresses, it must parse it and set it for the instance. Without this, nobody can do a Ip4Config->GetData for DNS server IPs before calling Dns->Configure(). This will mean a DHCP is initiated when calling Dns->Configure(), thus causing serious performance issues. This patch attempts to address this issue. (Sync patch r18560 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Samer El-Haj-Mahmoud Reviewed-by: Ye Ting Reviewed-by: Samer El-Haj-Mahmoud Reviewed-by: Fu Siyuan git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18788 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Universal/Network/Ip4Dxe/Ip4Config2Impl.c | 258 +++++++++++------- .../Universal/Network/Ip4Dxe/Ip4Config2Impl.h | 4 +- 2 files changed, 168 insertions(+), 94 deletions(-) diff --git a/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Config2Impl.c b/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Config2Impl.c index 637d7cd65993..edbddba02118 100644 --- a/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Config2Impl.c +++ b/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Config2Impl.c @@ -2,6 +2,7 @@ The implementation of EFI IPv4 Configuration II Protocol. Copyright (c) 2015, Intel Corporation. All rights reserved.
+ (C) Copyright 2015 Hewlett Packard Enterprise Development LP
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License @@ -677,6 +678,126 @@ Ip4Config2CleanDhcp4 ( } } +/** + This worker function sets the DNS server list for the EFI IPv4 network + stack running on the communication device that this EFI_IP4_CONFIG2_PROTOCOL + manages. The DNS server addresses must be unicast IPv4 addresses. + + @param[in] Instance The pointer to the IP4 config2 instance data. + @param[in] DataSize The size of the buffer pointed to by Data in bytes. + @param[in] Data The data buffer to set, points to an array of + EFI_IPv4_ADDRESS instances. + + @retval EFI_BAD_BUFFER_SIZE The DataSize does not match the size of the type. + @retval EFI_INVALID_PARAMETER One or more fields in Data is invalid. + @retval EFI_OUT_OF_RESOURCES Failed to allocate resources to complete the operation. + @retval EFI_ABORTED The DNS server addresses to be set equal the current + configuration. + @retval EFI_SUCCESS The specified configuration data for the EFI IPv4 + network stack was set. + +**/ +EFI_STATUS +Ip4Config2SetDnsServerWorker ( + IN IP4_CONFIG2_INSTANCE *Instance, + IN UINTN DataSize, + IN VOID *Data + ) +{ + UINTN OldIndex; + UINTN NewIndex; + UINTN Index1; + EFI_IPv4_ADDRESS *OldDns; + EFI_IPv4_ADDRESS *NewDns; + UINTN OldDnsCount; + UINTN NewDnsCount; + IP4_CONFIG2_DATA_ITEM *Item; + BOOLEAN OneAdded; + VOID *Tmp; + IP4_ADDR DnsAddress; + + if ((DataSize % sizeof (EFI_IPv4_ADDRESS) != 0) || (DataSize == 0)) { + return EFI_BAD_BUFFER_SIZE; + } + + Item = &Instance->DataItem[Ip4Config2DataTypeDnsServer]; + NewDns = (EFI_IPv4_ADDRESS *) Data; + OldDns = Item->Data.DnsServers; + NewDnsCount = DataSize / sizeof (EFI_IPv4_ADDRESS); + OldDnsCount = Item->DataSize / sizeof (EFI_IPv4_ADDRESS); + OneAdded = FALSE; + + if (NewDnsCount != OldDnsCount) { + Tmp = AllocatePool (DataSize); + if (Tmp == NULL) { + return EFI_OUT_OF_RESOURCES; + } + } else { + Tmp = NULL; + } + + for (NewIndex = 0; NewIndex < NewDnsCount; NewIndex++) { + CopyMem (&DnsAddress, NewDns + NewIndex, sizeof (IP4_ADDR)); + + if (!NetIp4IsUnicast (NTOHL (DnsAddress), 0)) { + // + // The dns server address must be unicast. + // + FreePool (Tmp); + return EFI_INVALID_PARAMETER; + } + + for (Index1 = NewIndex + 1; Index1 < NewDnsCount; Index1++) { + if (EFI_IP4_EQUAL (NewDns + NewIndex, NewDns + Index1)) { + FreePool (Tmp); + return EFI_INVALID_PARAMETER; + } + } + + if (OneAdded) { + // + // If any address in the new setting is not in the old settings, skip the + // comparision below. + // + continue; + } + + for (OldIndex = 0; OldIndex < OldDnsCount; OldIndex++) { + if (EFI_IP4_EQUAL (NewDns + NewIndex, OldDns + OldIndex)) { + // + // If found break out. + // + break; + } + } + + if (OldIndex == OldDnsCount) { + OneAdded = TRUE; + } + } + + if (!OneAdded && (DataSize == Item->DataSize)) { + // + // No new item is added and the size is the same. + // + Item->Status = EFI_SUCCESS; + return EFI_ABORTED; + } else { + if (Tmp != NULL) { + if (Item->Data.Ptr != NULL) { + FreePool (Item->Data.Ptr); + } + Item->Data.Ptr = Tmp; + } + + CopyMem (Item->Data.Ptr, Data, DataSize); + Item->DataSize = DataSize; + Item->Status = EFI_SUCCESS; + return EFI_SUCCESS; + } +} + + /** Callback function when DHCP process finished. It will save the @@ -701,6 +822,9 @@ Ip4Config2OnDhcp4Complete ( IP4_ADDR StationAddress; IP4_ADDR SubnetMask; IP4_ADDR GatewayAddress; + UINT32 Index; + UINT32 OptionCount; + EFI_DHCP4_PACKET_OPTION **OptionList; Instance = (IP4_CONFIG2_INSTANCE *) Context; ASSERT (Instance->Dhcp4 != NULL); @@ -724,6 +848,44 @@ Ip4Config2OnDhcp4Complete ( goto Exit; } + // + // Parse the ACK to get required DNS server information. + // + OptionCount = 0; + OptionList = NULL; + + Status = Instance->Dhcp4->Parse (Instance->Dhcp4, Dhcp4Mode.ReplyPacket, &OptionCount, OptionList); + if (Status != EFI_BUFFER_TOO_SMALL) { + goto Exit; + } + + OptionList = AllocateZeroPool (OptionCount * sizeof (EFI_DHCP4_PACKET_OPTION *)); + if (OptionList == NULL) { + goto Exit; + } + + Status = Instance->Dhcp4->Parse (Instance->Dhcp4, Dhcp4Mode.ReplyPacket, &OptionCount, OptionList); + if (EFI_ERROR (Status)) { + FreePool (OptionList); + goto Exit; + } + + for (Index = 0; Index < OptionCount; Index++) { + // + // Look for DNS Server opcode (6). + // + if (OptionList[Index]->OpCode == DHCP_TAG_DNS_SERVER) { + if (((OptionList[Index]->Length & 0x3) != 0) || (OptionList[Index]->Length == 0)) { + break; + } + + Ip4Config2SetDnsServerWorker (Instance, OptionList[Index]->Length, &OptionList[Index]->Data[0]); + break; + } + } + + FreePool (OptionList); + Instance->DhcpSuccess = TRUE; } @@ -831,9 +993,10 @@ Ip4StartAutoConfig ( // yields the control of this DHCP service to us. // ParaList.Head.OpCode = DHCP_TAG_PARA_LIST; - ParaList.Head.Length = 2; + ParaList.Head.Length = 3; ParaList.Head.Data[0] = DHCP_TAG_NETMASK; ParaList.Route = DHCP_TAG_ROUTER; + ParaList.Dns = DHCP_TAG_DNS_SERVER; OptionList[0] = &ParaList.Head; Dhcp4Mode.ConfigData.OptionCount = 1; Dhcp4Mode.ConfigData.OptionList = OptionList; @@ -1293,102 +1456,11 @@ Ip4Config2SetDnsServer ( IN VOID *Data ) { - UINTN OldIndex; - UINTN NewIndex; - UINTN Index1; - EFI_IPv4_ADDRESS *OldDns; - EFI_IPv4_ADDRESS *NewDns; - UINTN OldDnsCount; - UINTN NewDnsCount; - IP4_CONFIG2_DATA_ITEM *Item; - BOOLEAN OneAdded; - VOID *Tmp; - IP4_ADDR DnsAddress; - - if ((DataSize % sizeof (EFI_IPv4_ADDRESS) != 0) || (DataSize == 0)) { - return EFI_BAD_BUFFER_SIZE; - } - if (Instance->Policy != Ip4Config2PolicyStatic) { return EFI_WRITE_PROTECTED; } - Item = &Instance->DataItem[Ip4Config2DataTypeDnsServer]; - NewDns = (EFI_IPv4_ADDRESS *) Data; - OldDns = Item->Data.DnsServers; - NewDnsCount = DataSize / sizeof (EFI_IPv4_ADDRESS); - OldDnsCount = Item->DataSize / sizeof (EFI_IPv4_ADDRESS); - OneAdded = FALSE; - - if (NewDnsCount != OldDnsCount) { - Tmp = AllocatePool (DataSize); - if (Tmp == NULL) { - return EFI_OUT_OF_RESOURCES; - } - } else { - Tmp = NULL; - } - - for (NewIndex = 0; NewIndex < NewDnsCount; NewIndex++) { - CopyMem (&DnsAddress, NewDns + NewIndex, sizeof (IP4_ADDR)); - - if (!NetIp4IsUnicast (NTOHL (DnsAddress), 0)) { - // - // The dns server address must be unicast. - // - FreePool (Tmp); - return EFI_INVALID_PARAMETER; - } - - for (Index1 = NewIndex + 1; Index1 < NewDnsCount; Index1++) { - if (EFI_IP4_EQUAL (NewDns + NewIndex, NewDns + Index1)) { - FreePool (Tmp); - return EFI_INVALID_PARAMETER; - } - } - - if (OneAdded) { - // - // If any address in the new setting is not in the old settings, skip the - // comparision below. - // - continue; - } - - for (OldIndex = 0; OldIndex < OldDnsCount; OldIndex++) { - if (EFI_IP4_EQUAL (NewDns + NewIndex, OldDns + OldIndex)) { - // - // If found break out. - // - break; - } - } - - if (OldIndex == OldDnsCount) { - OneAdded = TRUE; - } - } - - if (!OneAdded && (DataSize == Item->DataSize)) { - // - // No new item is added and the size is the same. - // - Item->Status = EFI_SUCCESS; - return EFI_ABORTED; - } else { - if (Tmp != NULL) { - if (Item->Data.Ptr != NULL) { - FreePool (Item->Data.Ptr); - } - Item->Data.Ptr = Tmp; - } - - CopyMem (Item->Data.Ptr, Data, DataSize); - Item->DataSize = DataSize; - Item->Status = EFI_SUCCESS; - return EFI_SUCCESS; - } - + return Ip4Config2SetDnsServerWorker (Instance, DataSize, Data); } /** diff --git a/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Config2Impl.h b/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Config2Impl.h index e74b9ae40744..ab7252564677 100644 --- a/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Config2Impl.h +++ b/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Config2Impl.h @@ -2,6 +2,7 @@ Definitions for EFI IPv4 Configuration II Protocol implementation. Copyright (c) 2015, Intel Corporation. All rights reserved.
+ (C) Copyright 2015 Hewlett Packard Enterprise Development LP
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License @@ -27,7 +28,7 @@ #define DHCP_TAG_PARA_LIST 55 #define DHCP_TAG_NETMASK 1 #define DHCP_TAG_ROUTER 3 - +#define DHCP_TAG_DNS_SERVER 6 #define DATA_ATTRIB_SET(Attrib, Bits) (BOOLEAN)((Attrib) & (Bits)) #define SET_DATA_ATTRIB(Attrib, Bits) ((Attrib) |= (Bits)) @@ -207,6 +208,7 @@ struct _IP4_CONFIG2_INSTANCE { typedef struct { EFI_DHCP4_PACKET_OPTION Head; UINT8 Route; + UINT8 Dns; } IP4_CONFIG2_DHCP4_OPTION; #pragma pack() From 17cc5459660dc1d49a85a2105ad34274f5df1895 Mon Sep 17 00:00:00 2001 From: Star Zeng Date: Mon, 16 Nov 2015 06:50:12 +0000 Subject: [PATCH 074/525] MdeModulePkg UefiBootManagerLib: Do not assume perf entry count has no change Current implementation assumes the performance entry count has no change from multiple GetPerformanceMeasurement() while loops, it may cause the allocated buffer for PerfEntriesAsDxeHandle at the first loop to be overflowed if the following loop has the count changed. This patch is also to sync the change at commit R17851 "IntelFrameworkModulePkg GenericBdsLib: Resolve array size mismatch". (Sync patch r18561 from main trunk.) Cc: Ruiyu Ni Cc: Liming Gao Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Star Zeng Reviewed-by: Ruiyu Ni git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18789 6f19259b-4bc3-4df7-8a09-765794883524 --- .../UefiBootManagerLib/BmPerformance.c | 120 +++++------------- 1 file changed, 35 insertions(+), 85 deletions(-) diff --git a/MdeModulePkg/Library/UefiBootManagerLib/BmPerformance.c b/MdeModulePkg/Library/UefiBootManagerLib/BmPerformance.c index e45c0bd23a5b..0abd0194409c 100644 --- a/MdeModulePkg/Library/UefiBootManagerLib/BmPerformance.c +++ b/MdeModulePkg/Library/UefiBootManagerLib/BmPerformance.c @@ -62,7 +62,7 @@ BmGetShortPdbFileName ( for (Index = StartIndex; Index < EndIndex; Index++) { GaugeString[Index1] = PdbFileName[Index]; Index1++; - if (Index1 == PERF_TOKEN_LENGTH - 1) { + if (Index1 == StringSize - 1) { break; } } @@ -157,7 +157,7 @@ BmWriteBootToOsPerformanceData ( UINT32 LimitCount; EFI_HANDLE *Handles; UINTN NoHandles; - CHAR8 GaugeString[PERF_TOKEN_LENGTH]; + CHAR8 GaugeString[PERF_TOKEN_SIZE]; UINT8 *Ptr; UINT32 Index; UINT64 Ticker; @@ -172,24 +172,14 @@ BmWriteBootToOsPerformanceData ( UINT64 StartValue; UINT64 EndValue; BOOLEAN CountUp; - UINTN EntryIndex; - UINTN NumPerfEntries; - // - // List of flags indicating PerfEntry contains DXE handle - // - BOOLEAN *PerfEntriesAsDxeHandle; UINTN VarSize; + BOOLEAN Found; // // Record the performance data for End of BDS // PERF_END(NULL, "BDS", NULL, 0); - // - // Reset the entry count - // - mBmPerfHeader.Count = 0; - // // Retrieve time stamp count as early as possible // @@ -212,6 +202,11 @@ BmWriteBootToOsPerformanceData ( CountUp = FALSE; } + // + // Reset the entry count + // + mBmPerfHeader.Count = 0; + if (mBmAcpiLowMemoryBase == 0x0FFFFFFFF) { VarSize = sizeof (EFI_PHYSICAL_ADDRESS); Status = gRT->GetVariable ( @@ -247,73 +242,10 @@ BmWriteBootToOsPerformanceData ( Ptr = (UINT8 *) ((UINT32) mBmAcpiLowMemoryBase + sizeof (PERF_HEADER)); LimitCount = (UINT32) (PERF_DATA_MAX_LENGTH - sizeof (PERF_HEADER)) / sizeof (PERF_DATA); - NumPerfEntries = 0; - LogEntryKey = 0; - while ((LogEntryKey = GetPerformanceMeasurement ( - LogEntryKey, - &Handle, - &Token, - &Module, - &StartTicker, - &EndTicker)) != 0) { - NumPerfEntries++; - } - PerfEntriesAsDxeHandle = AllocateZeroPool (NumPerfEntries * sizeof (BOOLEAN)); - ASSERT (PerfEntriesAsDxeHandle != NULL); - // - // Get DXE drivers performance - // - for (Index = 0; Index < NoHandles; Index++) { - Ticker = 0; - LogEntryKey = 0; - EntryIndex = 0; - while ((LogEntryKey = GetPerformanceMeasurement ( - LogEntryKey, - &Handle, - &Token, - &Module, - &StartTicker, - &EndTicker)) != 0) { - if (Handle == Handles[Index] && !PerfEntriesAsDxeHandle[EntryIndex]) { - PerfEntriesAsDxeHandle[EntryIndex] = TRUE; - } - EntryIndex++; - if ((Handle == Handles[Index]) && (EndTicker != 0)) { - if (StartTicker == 1) { - StartTicker = StartValue; - } - if (EndTicker == 1) { - EndTicker = StartValue; - } - Ticker += CountUp ? (EndTicker - StartTicker) : (StartTicker - EndTicker); - } - } - - Duration = (UINT32) DivU64x32 (Ticker, (UINT32) Freq); - - if (Duration > 0) { - - BmGetNameFromHandle (Handles[Index], GaugeString, PERF_TOKEN_LENGTH); - - AsciiStrCpyS (mBmPerfData.Token, PERF_TOKEN_SIZE, GaugeString); - mBmPerfData.Duration = Duration; - - CopyMem (Ptr, &mBmPerfData, sizeof (PERF_DATA)); - Ptr += sizeof (PERF_DATA); - - mBmPerfHeader.Count++; - if (mBmPerfHeader.Count == LimitCount) { - goto Done; - } - } - } - - // - // Get inserted performance data + // Get performance data // LogEntryKey = 0; - EntryIndex = 0; while ((LogEntryKey = GetPerformanceMeasurement ( LogEntryKey, &Handle, @@ -321,11 +253,7 @@ BmWriteBootToOsPerformanceData ( &Module, &StartTicker, &EndTicker)) != 0) { - if (!PerfEntriesAsDxeHandle[EntryIndex] && EndTicker != 0) { - - ZeroMem (&mBmPerfData, sizeof (PERF_DATA)); - - AsciiStrnCpyS (mBmPerfData.Token, PERF_TOKEN_SIZE, Token, PERF_TOKEN_LENGTH); + if (EndTicker != 0) { if (StartTicker == 1) { StartTicker = StartValue; } @@ -334,7 +262,31 @@ BmWriteBootToOsPerformanceData ( } Ticker = CountUp ? (EndTicker - StartTicker) : (StartTicker - EndTicker); - mBmPerfData.Duration = (UINT32) DivU64x32 (Ticker, (UINT32) Freq); + Duration = (UINT32) DivU64x32 (Ticker, (UINT32) Freq); + if (Duration == 0) { + continue; + } + + ZeroMem (&mBmPerfData, sizeof (PERF_DATA)); + + mBmPerfData.Duration = Duration; + + // + // See if the Handle is in the handle buffer + // + Found = FALSE; + for (Index = 0; Index < NoHandles; Index++) { + if (Handle == Handles[Index]) { + BmGetNameFromHandle (Handles[Index], GaugeString, PERF_TOKEN_SIZE); + AsciiStrCpyS (mBmPerfData.Token, PERF_TOKEN_SIZE, GaugeString); + Found = TRUE; + break; + } + } + + if (!Found) { + AsciiStrnCpyS (mBmPerfData.Token, PERF_TOKEN_SIZE, Token, PERF_TOKEN_LENGTH); + } CopyMem (Ptr, &mBmPerfData, sizeof (PERF_DATA)); Ptr += sizeof (PERF_DATA); @@ -344,13 +296,11 @@ BmWriteBootToOsPerformanceData ( goto Done; } } - EntryIndex++; } Done: FreePool (Handles); - FreePool (PerfEntriesAsDxeHandle); mBmPerfHeader.Signiture = PERFORMANCE_SIGNATURE; From 9a7067a328dfc9fbcc00260de363a756accb0f24 Mon Sep 17 00:00:00 2001 From: Star Zeng Date: Mon, 16 Nov 2015 06:51:08 +0000 Subject: [PATCH 075/525] IntelFrameworkModulePkg GenericBdsLib: Do not assume perf entry count has no change Current implementation assumes the performance entry count has no change from multiple GetPerformanceMeasurement() while loops, it may cause the allocated buffer for PerfEntriesAsDxeHandle at the first loop to be overflowed if the following loop has the count changed. This patch is also to sync the change at commit R18417 "MdeModulePkg: Fix a performance data buffer overrun issue". (Sync patch r18562 from main trunk.) Cc: Ruiyu Ni Cc: Liming Gao Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Star Zeng Reviewed-by: Ruiyu Ni git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18790 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Library/GenericBdsLib/Performance.c | 111 ++++++------------ 1 file changed, 33 insertions(+), 78 deletions(-) diff --git a/IntelFrameworkModulePkg/Library/GenericBdsLib/Performance.c b/IntelFrameworkModulePkg/Library/GenericBdsLib/Performance.c index 78039e79a578..e50345a59732 100644 --- a/IntelFrameworkModulePkg/Library/GenericBdsLib/Performance.c +++ b/IntelFrameworkModulePkg/Library/GenericBdsLib/Performance.c @@ -168,13 +168,8 @@ WriteBootToOsPerformanceData ( UINT64 StartValue; UINT64 EndValue; BOOLEAN CountUp; - UINTN EntryIndex; - UINTN NumPerfEntries; - // - // List of flags indicating PerfEntry contains DXE handle - // - BOOLEAN *PerfEntriesAsDxeHandle; UINTN VarSize; + BOOLEAN Found; // // Record the performance data for End of BDS @@ -203,6 +198,11 @@ WriteBootToOsPerformanceData ( CountUp = FALSE; } + // + // Reset the entry count + // + mPerfHeader.Count = 0; + if (mAcpiLowMemoryBase == 0x0FFFFFFFF) { VarSize = sizeof (EFI_PHYSICAL_ADDRESS); Status = gRT->GetVariable ( @@ -238,73 +238,10 @@ WriteBootToOsPerformanceData ( Ptr = (UINT8 *) ((UINT32) mAcpiLowMemoryBase + sizeof (PERF_HEADER)); LimitCount = (UINT32) (PERF_DATA_MAX_LENGTH - sizeof (PERF_HEADER)) / sizeof (PERF_DATA); - NumPerfEntries = 0; - LogEntryKey = 0; - while ((LogEntryKey = GetPerformanceMeasurement ( - LogEntryKey, - &Handle, - &Token, - &Module, - &StartTicker, - &EndTicker)) != 0) { - NumPerfEntries++; - } - PerfEntriesAsDxeHandle = AllocateZeroPool (NumPerfEntries * sizeof (BOOLEAN)); - ASSERT (PerfEntriesAsDxeHandle != NULL); - - // - // Get DXE drivers performance - // - for (Index = 0; Index < NoHandles; Index++) { - Ticker = 0; - LogEntryKey = 0; - EntryIndex = 0; - while ((LogEntryKey = GetPerformanceMeasurement ( - LogEntryKey, - &Handle, - &Token, - &Module, - &StartTicker, - &EndTicker)) != 0) { - if (Handle == Handles[Index] && !PerfEntriesAsDxeHandle[EntryIndex]) { - PerfEntriesAsDxeHandle[EntryIndex] = TRUE; - } - EntryIndex++; - if ((Handle == Handles[Index]) && (EndTicker != 0)) { - if (StartTicker == 1) { - StartTicker = StartValue; - } - if (EndTicker == 1) { - EndTicker = StartValue; - } - Ticker += CountUp ? (EndTicker - StartTicker) : (StartTicker - EndTicker); - } - } - - Duration = (UINT32) DivU64x32 (Ticker, (UINT32) Freq); - - if (Duration > 0) { - - GetNameFromHandle (Handles[Index], GaugeString); - - AsciiStrCpyS (mPerfData.Token, PERF_TOKEN_SIZE, GaugeString); - mPerfData.Duration = Duration; - - CopyMem (Ptr, &mPerfData, sizeof (PERF_DATA)); - Ptr += sizeof (PERF_DATA); - - mPerfHeader.Count++; - if (mPerfHeader.Count == LimitCount) { - goto Done; - } - } - } - // - // Get inserted performance data + // Get performance data // LogEntryKey = 0; - EntryIndex = 0; while ((LogEntryKey = GetPerformanceMeasurement ( LogEntryKey, &Handle, @@ -312,11 +249,7 @@ WriteBootToOsPerformanceData ( &Module, &StartTicker, &EndTicker)) != 0) { - if (!PerfEntriesAsDxeHandle[EntryIndex] && EndTicker != 0) { - - ZeroMem (&mPerfData, sizeof (PERF_DATA)); - - AsciiStrnCpyS (mPerfData.Token, PERF_TOKEN_SIZE, Token, PERF_TOKEN_LENGTH); + if (EndTicker != 0) { if (StartTicker == 1) { StartTicker = StartValue; } @@ -325,7 +258,31 @@ WriteBootToOsPerformanceData ( } Ticker = CountUp ? (EndTicker - StartTicker) : (StartTicker - EndTicker); - mPerfData.Duration = (UINT32) DivU64x32 (Ticker, (UINT32) Freq); + Duration = (UINT32) DivU64x32 (Ticker, (UINT32) Freq); + if (Duration == 0) { + continue; + } + + ZeroMem (&mPerfData, sizeof (PERF_DATA)); + + mPerfData.Duration = Duration; + + // + // See if the Handle is in the handle buffer + // + Found = FALSE; + for (Index = 0; Index < NoHandles; Index++) { + if (Handle == Handles[Index]) { + GetNameFromHandle (Handles[Index], GaugeString); + AsciiStrCpyS (mPerfData.Token, PERF_TOKEN_SIZE, GaugeString); + Found = TRUE; + break; + } + } + + if (!Found) { + AsciiStrnCpyS (mPerfData.Token, PERF_TOKEN_SIZE, Token, PERF_TOKEN_LENGTH); + } CopyMem (Ptr, &mPerfData, sizeof (PERF_DATA)); Ptr += sizeof (PERF_DATA); @@ -335,13 +292,11 @@ WriteBootToOsPerformanceData ( goto Done; } } - EntryIndex++; } Done: FreePool (Handles); - FreePool (PerfEntriesAsDxeHandle); mPerfHeader.Signiture = PERFORMANCE_SIGNATURE; From 472fdf0e4c2da40120ec489f9899e3bb3934328b Mon Sep 17 00:00:00 2001 From: Thomas Palmer Date: Mon, 16 Nov 2015 06:52:09 +0000 Subject: [PATCH 076/525] MdePkg: Create GetRandomNumber128 in RngLib Declare GetRandomNumber128 in RngLib.h. Create GetRandomNumber128 in BaseRngLib, which is simply calling GetRandomNumber64 twice. A GetRandomNumber128 function allows platforms with 128bit HWRNGs to save on IO overhead that comes from having to prime the HWRNG device before each read operation. Using the HWRNG installed on the HP ProLiant m400 moonshot cartridge, this will save about 50ms per RAW Entropy operation as compared with calling GetRandomNumber64 twice. (Sync patch r18590 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Thomas Palmer Reviewed-by: Samer El-Haj-Mahmoud Reviewed-by: Michael Kinney Reviewed-by: Chao Zhang Reviewed-by: Qin Long git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18791 6f19259b-4bc3-4df7-8a09-765794883524 --- MdePkg/Include/Library/RngLib.h | 17 +++++++++++++++ MdePkg/Library/BaseRngLib/BaseRng.c | 32 +++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/MdePkg/Include/Library/RngLib.h b/MdePkg/Include/Library/RngLib.h index 157a93139c24..ece43941688f 100644 --- a/MdePkg/Include/Library/RngLib.h +++ b/MdePkg/Include/Library/RngLib.h @@ -66,4 +66,21 @@ GetRandomNumber64 ( OUT UINT64 *Rand ); +/** + Generates a 128-bit random number. + + if Rand is NULL, then ASSERT(). + + @param[out] Rand Buffer pointer to store the 128-bit random value. + + @retval TRUE Random number generated successfully. + @retval FALSE Failed to generate the random number. + +**/ +BOOLEAN +EFIAPI +GetRandomNumber128 ( + OUT UINT64 *Rand + ); + #endif // __RNG_LIB_H__ diff --git a/MdePkg/Library/BaseRngLib/BaseRng.c b/MdePkg/Library/BaseRngLib/BaseRng.c index 279df3013c9f..2c8df5628611 100644 --- a/MdePkg/Library/BaseRngLib/BaseRng.c +++ b/MdePkg/Library/BaseRngLib/BaseRng.c @@ -155,3 +155,35 @@ GetRandomNumber64 ( return FALSE; } + +/** + Generates a 128-bit random number. + + if Rand is NULL, then ASSERT(). + + @param[out] Rand Buffer pointer to store the 128-bit random value. + + @retval TRUE Random number generated successfully. + @retval FALSE Failed to generate the random number. + +**/ +BOOLEAN +EFIAPI +GetRandomNumber128 ( + OUT UINT64 *Rand + ) +{ + ASSERT (Rand != NULL); + + // + // Read first 64 bits + // + if (!GetRandomNumber64 (Rand)) { + return FALSE; + } + + // + // Read second 64 bits + // + return GetRandomNumber64 (++Rand); +} From 99806531f4d6b0e35b29d96ed97fe83e39556b3a Mon Sep 17 00:00:00 2001 From: Thomas Palmer Date: Mon, 16 Nov 2015 06:53:01 +0000 Subject: [PATCH 077/525] SecurityPkg: Integrate new RngLib into RngDxe Use the new RngLib to provide the IA32/X64 random data for RngDxe. Remove x86 specific functions from RdRand files. Simplify RngDxe by using WriteUnaligned64 for all platforms. Use GetRandomNumber128 in RngDxe to leverage 128 bit support provided by some HW RNG devices. (Sync patch r18591 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Thomas Palmer Reviewed-by: Samer El-Haj-Mahmoud Reviewed-by: Michael Kinney Reviewed-by: Chao Zhang Reviewed-by: Qin Long git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18792 6f19259b-4bc3-4df7-8a09-765794883524 --- .../RandomNumberGenerator/RngDxe/RdRand.c | 256 ++---------------- .../RandomNumberGenerator/RngDxe/RdRand.h | 151 +---------- .../RandomNumberGenerator/RngDxe/RngDxe.c | 13 +- .../RandomNumberGenerator/RngDxe/RngDxe.inf | 14 +- SecurityPkg/SecurityPkg.dsc | 3 + 5 files changed, 28 insertions(+), 409 deletions(-) diff --git a/SecurityPkg/RandomNumberGenerator/RngDxe/RdRand.c b/SecurityPkg/RandomNumberGenerator/RngDxe/RdRand.c index 7e618dc91f23..395b8867c836 100644 --- a/SecurityPkg/RandomNumberGenerator/RngDxe/RdRand.c +++ b/SecurityPkg/RandomNumberGenerator/RngDxe/RdRand.c @@ -2,6 +2,7 @@ Support routines for RDRAND instruction access. Copyright (c) 2013, Intel Corporation. All rights reserved.
+(C) Copyright 2015 Hewlett Packard Enterprise Development LP
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -11,177 +12,11 @@ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ +#include #include "RdRand.h" #include "AesCore.h" -// -// Bit mask used to determine if RdRand instruction is supported. -// -#define RDRAND_MASK 0x40000000 - -/** - Determines whether or not RDRAND instruction is supported by the host hardware. - - @retval EFI_SUCCESS RDRAND instruction supported. - @retval EFI_UNSUPPORTED RDRAND instruction not supported. - -**/ -EFI_STATUS -EFIAPI -IsRdRandSupported ( - VOID - ) -{ - EFI_STATUS Status; - UINT32 RegEax; - UINT32 RegEbx; - UINT32 RegEcx; - UINT32 RegEdx; - BOOLEAN IsIntelCpu; - - Status = EFI_UNSUPPORTED; - IsIntelCpu = FALSE; - - // - // Checks whether the current processor is an Intel product by CPUID. - // - AsmCpuid (0, &RegEax, &RegEbx, &RegEcx, &RegEdx); - if ((CompareMem ((CHAR8 *)(&RegEbx), "Genu", 4) == 0) && - (CompareMem ((CHAR8 *)(&RegEdx), "ineI", 4) == 0) && - (CompareMem ((CHAR8 *)(&RegEcx), "ntel", 4) == 0)) { - IsIntelCpu = TRUE; - } - - if (IsIntelCpu) { - // - // Determine RDRAND support by examining bit 30 of the ECX register returned by CPUID. - // A value of 1 indicates that processor supports RDRAND instruction. - // - AsmCpuid (1, 0, 0, &RegEcx, 0); - - if ((RegEcx & RDRAND_MASK) == RDRAND_MASK) { - Status = EFI_SUCCESS; - } - } - - return Status; -} - -/** - Calls RDRAND to obtain a 16-bit random number. - - @param[out] Rand Buffer pointer to store the random result. - @param[in] NeedRetry Determine whether or not to loop retry. - - @retval EFI_SUCCESS RDRAND call was successful. - @retval EFI_NOT_READY Failed attempts to call RDRAND. - -**/ -EFI_STATUS -EFIAPI -RdRand16 ( - OUT UINT16 *Rand, - IN BOOLEAN NeedRetry - ) -{ - UINT32 Index; - UINT32 RetryCount; - - if (NeedRetry) { - RetryCount = RETRY_LIMIT; - } else { - RetryCount = 1; - } - - // - // Perform a single call to RDRAND, or enter a loop call until RDRAND succeeds. - // - for (Index = 0; Index < RetryCount; Index++) { - if (RdRand16Step (Rand)) { - return EFI_SUCCESS; - } - } - - return EFI_NOT_READY; -} - -/** - Calls RDRAND to obtain a 32-bit random number. - - @param[out] Rand Buffer pointer to store the random result. - @param[in] NeedRetry Determine whether or not to loop retry. - - @retval EFI_SUCCESS RDRAND call was successful. - @retval EFI_NOT_READY Failed attempts to call RDRAND. - -**/ -EFI_STATUS -EFIAPI -RdRand32 ( - OUT UINT32 *Rand, - IN BOOLEAN NeedRetry - ) -{ - UINT32 Index; - UINT32 RetryCount; - - if (NeedRetry) { - RetryCount = RETRY_LIMIT; - } else { - RetryCount = 1; - } - - // - // Perform a single call to RDRAND, or enter a loop call until RDRAND succeeds. - // - for (Index = 0; Index < RetryCount; Index++) { - if (RdRand32Step (Rand)) { - return EFI_SUCCESS; - } - } - - return EFI_NOT_READY; -} - -/** - Calls RDRAND to obtain a 64-bit random number. - - @param[out] Rand Buffer pointer to store the random result. - @param[in] NeedRetry Determine whether or not to loop retry. - - @retval EFI_SUCCESS RDRAND call was successful. - @retval EFI_NOT_READY Failed attempts to call RDRAND. - -**/ -EFI_STATUS -EFIAPI -RdRand64 ( - OUT UINT64 *Rand, - IN BOOLEAN NeedRetry - ) -{ - UINT32 Index; - UINT32 RetryCount; - - if (NeedRetry) { - RetryCount = RETRY_LIMIT; - } else { - RetryCount = 1; - } - - // - // Perform a single call to RDRAND, or enter a loop call until RDRAND succeeds. - // - for (Index = 0; Index < RetryCount; Index++) { - if (RdRand64Step (Rand)) { - return EFI_SUCCESS; - } - } - - return EFI_NOT_READY; -} - /** Calls RDRAND to fill a buffer of arbitrary size with random bytes. @@ -199,80 +34,23 @@ RdRandGetBytes ( OUT UINT8 *RandBuffer ) { - EFI_STATUS Status; - UINT8 *Start; - UINT8 *ResidualStart; - UINTN *BlockStart; - UINTN TempRand; - UINTN Count; - UINTN Residual; - UINTN StartLen; - UINTN BlockNum; - UINTN Index; - - ResidualStart = NULL; - TempRand = 0; + BOOLEAN IsRandom; + UINT64 TempRand[2]; - // - // Compute the address of the first word aligned (32/64-bit) block in the - // destination buffer, depending on whether we are in 32- or 64-bit mode. - // - Start = RandBuffer; - if (((UINT32)(UINTN)Start % (UINT32)sizeof(UINTN)) == 0) { - BlockStart = (UINTN *)Start; - Count = Length; - StartLen = 0; - } else { - BlockStart = (UINTN *)(((UINTN)Start & ~(UINTN)(sizeof(UINTN) - 1)) + (UINTN)sizeof(UINTN)); - Count = Length - (sizeof (UINTN) - (UINT32)((UINTN)Start % sizeof (UINTN))); - StartLen = (UINT32)((UINTN)BlockStart - (UINTN)Start); - } - - // - // Compute the number of word blocks and the remaining number of bytes. - // - Residual = Count % sizeof (UINTN); - BlockNum = Count / sizeof (UINTN); - if (Residual != 0) { - ResidualStart = (UINT8 *) (BlockStart + BlockNum); - } - - // - // Obtain a temporary random number for use in the residuals. Failout if retry fails. - // - if (StartLen > 0) { - Status = RdRandWord ((UINTN *) &TempRand, TRUE); - if (EFI_ERROR (Status)) { - return Status; - } - } - - // - // Populate the starting mis-aligned block. - // - for (Index = 0; Index < StartLen; Index++) { - Start[Index] = (UINT8)(TempRand & 0xff); - TempRand = TempRand >> 8; - } - - // - // Populate the central aligned block. Fail out if retry fails. - // - Status = RdRandGetWords (BlockNum, (UINTN *)(BlockStart)); - if (EFI_ERROR (Status)) { - return Status; - } - // - // Populate the final mis-aligned block. - // - if (Residual > 0) { - Status = RdRandWord ((UINTN *)&TempRand, TRUE); - if (EFI_ERROR (Status)) { - return Status; + while (Length > 0) { + IsRandom = GetRandomNumber128 (TempRand); + if (!IsRandom) { + return EFI_NOT_READY; } - for (Index = 0; Index < Residual; Index++) { - ResidualStart[Index] = (UINT8)(TempRand & 0xff); - TempRand = TempRand >> 8; + if (Length >= sizeof (TempRand)) { + WriteUnaligned64 ((UINT64*)RandBuffer, TempRand[0]); + RandBuffer += sizeof (UINT64); + WriteUnaligned64 ((UINT64*)RandBuffer, TempRand[1]); + RandBuffer += sizeof (UINT64); + Length -= sizeof (TempRand); + } else { + CopyMem (RandBuffer, TempRand, Length); + Length = 0; } } diff --git a/SecurityPkg/RandomNumberGenerator/RngDxe/RdRand.h b/SecurityPkg/RandomNumberGenerator/RngDxe/RdRand.h index 20fd9fbd3ffa..d6378778cf15 100644 --- a/SecurityPkg/RandomNumberGenerator/RngDxe/RdRand.h +++ b/SecurityPkg/RandomNumberGenerator/RngDxe/RdRand.h @@ -9,6 +9,7 @@ Secure Key technology. Copyright (c) 2013, Intel Corporation. All rights reserved.
+(C) Copyright 2015 Hewlett Packard Enterprise Development LP
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -28,154 +29,6 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include -// -// The maximun number of retries to obtain one available random number. -// -#define RETRY_LIMIT 10 - -/** - Determines whether or not RDRAND instruction is supported by the host hardware. - - @retval EFI_SUCCESS RDRAND instruction supported. - @retval EFI_UNSUPPORTED RDRAND instruction not supported. - -**/ -EFI_STATUS -EFIAPI -IsRdRandSupported ( - VOID - ); - -/** - Generates a 16-bit random number through RDRAND instruction. - - @param[out] Rand Buffer pointer to store the random result. - - @retval TRUE RDRAND call was successful. - @retval FALSE Failed attempts to call RDRAND. - -**/ -BOOLEAN -EFIAPI -RdRand16Step ( - OUT UINT16 *Rand - ); - -/** - Generates a 32-bit random number through RDRAND instruction. - - @param[out] Rand Buffer pointer to store the random result. - - @retval TRUE RDRAND call was successful. - @retval FALSE Failed attempts to call RDRAND. - -**/ -BOOLEAN -EFIAPI -RdRand32Step ( - OUT UINT32 *Rand - ); - -/** - Generates a 64-bit random number through RDRAND instruction. - - @param[out] Rand Buffer pointer to store the random result. - - @retval TRUE RDRAND call was successful. - @retval FALSE Failed attempts to call RDRAND. - -**/ -BOOLEAN -EFIAPI -RdRand64Step ( - OUT UINT64 *Rand - ); - -/** - Calls RDRAND to obtain a 16-bit random number. - - @param[out] Rand Buffer pointer to store the random result. - @param[in] NeedRetry Determine whether or not to loop retry. - - @retval EFI_SUCCESS RDRAND call was successful. - @retval EFI_NOT_READY Failed attempts to call RDRAND. - -**/ -EFI_STATUS -EFIAPI -RdRand16 ( - OUT UINT16 *Rand, - IN BOOLEAN NeedRetry - ); - -/** - Calls RDRAND to obtain a 32-bit random number. - - @param[out] Rand Buffer pointer to store the random result. - @param[in] NeedRetry Determine whether or not to loop retry. - - @retval EFI_SUCCESS RDRAND call was successful. - @retval EFI_NOT_READY Failed attempts to call RDRAND. - -**/ -EFI_STATUS -EFIAPI -RdRand32 ( - OUT UINT32 *Rand, - IN BOOLEAN NeedRetry - ); - -/** - Calls RDRAND to obtain a 64-bit random number. - - @param[out] Rand Buffer pointer to store the random result. - @param[in] NeedRetry Determine whether or not to loop retry. - - @retval EFI_SUCCESS RDRAND call was successful. - @retval EFI_NOT_READY Failed attempts to call RDRAND. - -**/ -EFI_STATUS -EFIAPI -RdRand64 ( - OUT UINT64 *Rand, - IN BOOLEAN NeedRetry - ); - -/** - Calls RDRAND to request a word-length random number. - - @param[out] Rand Buffer pointer to store the random number. - @param[in] NeedRetry Determine whether or not to loop retry. - - @retval EFI_SUCCESS Random word generation succeeded. - @retval EFI_NOT_READY Failed to request random word. - -**/ -EFI_STATUS -EFIAPI -RdRandWord ( - OUT UINTN *Rand, - IN BOOLEAN NeedRetry - ); - -/** - Calls RDRAND to request multiple word-length random numbers. - - @param[in] Length Size of the buffer, in words, to fill with. - @param[out] RandBuffer Pointer to the buffer to store the random result. - - @retval EFI_SUCCESS Random words generation succeeded. - @retval EFI_NOT_READY Failed to request random words. - -**/ -EFI_STATUS -EFIAPI -RdRandGetWords ( - IN UINTN Length, - OUT UINTN *RandBuffer - ); - /** Calls RDRAND to fill a buffer of arbitrary size with random bytes. @@ -210,4 +63,4 @@ RdRandGenerateEntropy ( OUT UINT8 *Entropy ); -#endif // __RD_RAND_H__ \ No newline at end of file +#endif // __RD_RAND_H__ diff --git a/SecurityPkg/RandomNumberGenerator/RngDxe/RngDxe.c b/SecurityPkg/RandomNumberGenerator/RngDxe/RngDxe.c index 98ef3b357fa5..32c46ab45f12 100644 --- a/SecurityPkg/RandomNumberGenerator/RngDxe/RngDxe.c +++ b/SecurityPkg/RandomNumberGenerator/RngDxe/RngDxe.c @@ -15,6 +15,7 @@ - EFI_RNG_ALGORITHM_X9_31_AES_GUID - Unsupported Copyright (c) 2013, Intel Corporation. All rights reserved.
+(C) Copyright 2015 Hewlett Packard Enterprise Development LP
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -156,7 +157,7 @@ RngGetRNG ( if (RNGValueLength < 32) { return EFI_INVALID_PARAMETER; } - + Status = RdRandGenerateEntropy (RNGValueLength, RNGValue); return Status; } @@ -196,14 +197,6 @@ RngDriverEntry ( EFI_STATUS Status; EFI_HANDLE Handle; - // - // Verify RdRand support on Platform. - // - Status = IsRdRandSupported (); - if (EFI_ERROR (Status)) { - return Status; - } - // // Install UEFI RNG (Random Number Generator) Protocol // @@ -214,6 +207,6 @@ RngDriverEntry ( &mRngRdRand, NULL ); - + return Status; } diff --git a/SecurityPkg/RandomNumberGenerator/RngDxe/RngDxe.inf b/SecurityPkg/RandomNumberGenerator/RngDxe/RngDxe.inf index d57c2d8c6f34..4d668a170ae1 100644 --- a/SecurityPkg/RandomNumberGenerator/RngDxe/RngDxe.inf +++ b/SecurityPkg/RandomNumberGenerator/RngDxe/RngDxe.inf @@ -9,6 +9,7 @@ # Secure Key technology. # # Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.
+# (C) Copyright 2015 Hewlett Packard Enterprise Development LP
# This program and the accompanying materials # are licensed and made available under the terms and conditions of the BSD License # which accompanies this distribution. The full text of the license may be found at @@ -41,16 +42,6 @@ AesCore.c AesCore.h -[Sources.IA32] - IA32/RdRandWord.c - IA32/AsmRdRand.asm - IA32/GccRdRand.c | GCC - -[Sources.X64] - X64/RdRandWord.c - X64/AsmRdRand.asm - X64/GccRdRand.c | GCC - [Packages] MdePkg/MdePkg.dec SecurityPkg/SecurityPkg.dec @@ -62,6 +53,7 @@ DebugLib UefiDriverEntryPoint TimerLib + RngLib [Guids] gEfiRngAlgorithmSp80090Ctr256Guid ## SOMETIMES_PRODUCES ## GUID # Unique ID of the algorithm for RNG @@ -77,4 +69,4 @@ XCODE:*_*_*_CC_FLAGS = -mmmx -msse [UserExtensions.TianoCore."ExtraFiles"] - RngDxeExtra.uni \ No newline at end of file + RngDxeExtra.uni diff --git a/SecurityPkg/SecurityPkg.dsc b/SecurityPkg/SecurityPkg.dsc index 6e2ca5c0b724..0908b26a7c24 100644 --- a/SecurityPkg/SecurityPkg.dsc +++ b/SecurityPkg/SecurityPkg.dsc @@ -2,6 +2,7 @@ # Security Module Package for All Architectures. # # Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.
+# (C) Copyright 2015 Hewlett Packard Enterprise Development LP
# This program and the accompanying materials # are licensed and made available under the terms and conditions of the BSD License # which accompanies this distribution. The full text of the license may be found at @@ -61,6 +62,7 @@ TcgPpVendorLib|SecurityPkg/Library/TcgPpVendorLibNull/TcgPpVendorLibNull.inf Tcg2PpVendorLib|SecurityPkg/Library/Tcg2PpVendorLibNull/Tcg2PpVendorLibNull.inf TrEEPpVendorLib|SecurityPkg/Library/TrEEPpVendorLibNull/TrEEPpVendorLibNull.inf + RngLib|MdePkg/Library/BaseRngLib/BaseRngLib.inf [LibraryClasses.common.PEIM] PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf @@ -74,6 +76,7 @@ Tpm12DeviceLib|SecurityPkg/Library/Tpm12DeviceLibDTpm/Tpm12DeviceLibDTpm.inf Tpm2DeviceLib|SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.inf Tcg2PhysicalPresenceLib|SecurityPkg/Library/PeiTcg2PhysicalPresenceLib/PeiTcg2PhysicalPresenceLib.inf + RngLib|MdePkg/Library/BaseRngLib/BaseRngLib.inf [LibraryClasses.common.DXE_DRIVER] HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf From 89d58323cf55ce28357107edb4036c5d5eac0e55 Mon Sep 17 00:00:00 2001 From: Thomas Palmer Date: Mon, 16 Nov 2015 06:53:53 +0000 Subject: [PATCH 078/525] SecurityPkg: Clean up unused files in RngDxe Clean up files in RngDxe/IA32 and RngDxe/X64 that are subsumed by files in BaseRngLib. (Sync patch r18592 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Thomas Palmer Reviewed-by: Samer El-Haj-Mahmoud Reviewed-by: Michael Kinney Reviewed-by: Chao Zhang Reviewed-by: Qin Long git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18793 6f19259b-4bc3-4df7-8a09-765794883524 --- .../RngDxe/IA32/AsmRdRand.asm | 67 ----------- .../RngDxe/IA32/GccRdRand.c | 69 ------------ .../RngDxe/IA32/RdRandWord.c | 104 ------------------ .../RngDxe/X64/AsmRdRand.asm | 83 -------------- .../RngDxe/X64/GccRdRand.c | 95 ---------------- .../RngDxe/X64/RdRandWord.c | 70 ------------ 6 files changed, 488 deletions(-) delete mode 100644 SecurityPkg/RandomNumberGenerator/RngDxe/IA32/AsmRdRand.asm delete mode 100644 SecurityPkg/RandomNumberGenerator/RngDxe/IA32/GccRdRand.c delete mode 100644 SecurityPkg/RandomNumberGenerator/RngDxe/IA32/RdRandWord.c delete mode 100644 SecurityPkg/RandomNumberGenerator/RngDxe/X64/AsmRdRand.asm delete mode 100644 SecurityPkg/RandomNumberGenerator/RngDxe/X64/GccRdRand.c delete mode 100644 SecurityPkg/RandomNumberGenerator/RngDxe/X64/RdRandWord.c diff --git a/SecurityPkg/RandomNumberGenerator/RngDxe/IA32/AsmRdRand.asm b/SecurityPkg/RandomNumberGenerator/RngDxe/IA32/AsmRdRand.asm deleted file mode 100644 index 37b38307e2ee..000000000000 --- a/SecurityPkg/RandomNumberGenerator/RngDxe/IA32/AsmRdRand.asm +++ /dev/null @@ -1,67 +0,0 @@ -;------------------------------------------------------------------------------ -; -; Copyright (c) 2013, Intel Corporation. All rights reserved.
-; This program and the accompanying materials -; are licensed and made available under the terms and conditions of the BSD License -; which accompanies this distribution. The full text of the license may be found at -; http://opensource.org/licenses/bsd-license.php. -; -; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -; -; Module Name: -; -; AsmRdRand.Asm -; -; Abstract: -; -; Implementation for 16-, and 32- invocations of RDRAND instruction under 32bit platform. -; -; Notes: -; -; Visual Studio coding practices do not use inline asm since multiple compilers and -; architectures are supported assembler not recognizing rdrand instruction so using DB's. -; -;------------------------------------------------------------------------------ - - .586P - .model flat, C - .code - -;------------------------------------------------------------------------------ -; Generate a 16 bit random number -; Return TRUE if Rand generated successfully, or FALSE if not -; -; BOOLEAN EFIAPI RdRand16Step (UINT16 *Rand); ECX -;------------------------------------------------------------------------------ -RdRand16Step PROC - ; rdrand ax ; generate a 16 bit RN into ax, CF=1 if RN generated ok, otherwise CF=0 - db 0fh, 0c7h, 0f0h ; rdrand r16: "0f c7 /6 ModRM:r/m(w)" - jb rn16_ok ; jmp if CF=1 - xor eax, eax ; reg=0 if CF=0 - ret ; return with failure status -rn16_ok: - mov [ecx], ax - mov eax, 1 - ret -RdRand16Step ENDP - -;------------------------------------------------------------------------------ -; Generate a 32 bit random number -; Return TRUE if Rand generated successfully, or FALSE if not -; -; BOOLEAN EFIAPI RdRand32Step (UINT32 *Rand); ECX -;------------------------------------------------------------------------------ -RdRand32Step PROC - ; rdrand eax ; generate a 32 bit RN into eax, CF=1 if RN generated ok, otherwise CF=0 - db 0fh, 0c7h, 0f0h ; rdrand r32: "0f c7 /6 ModRM:r/m(w)" - jb rn32_ok ; jmp if CF=1 - xor eax, eax ; reg=0 if CF=0 - ret ; return with failure status -rn32_ok: - mov [ecx], eax - mov eax, 1 - ret -RdRand32Step ENDP - - END diff --git a/SecurityPkg/RandomNumberGenerator/RngDxe/IA32/GccRdRand.c b/SecurityPkg/RandomNumberGenerator/RngDxe/IA32/GccRdRand.c deleted file mode 100644 index f42302afe35c..000000000000 --- a/SecurityPkg/RandomNumberGenerator/RngDxe/IA32/GccRdRand.c +++ /dev/null @@ -1,69 +0,0 @@ -/** @file - RDRAND Support Routines for GCC environment. - -Copyright (c) 2013, Intel Corporation. All rights reserved.
-This program and the accompanying materials -are licensed and made available under the terms and conditions of the BSD License -which accompanies this distribution. The full text of the license may be found at -http://opensource.org/licenses/bsd-license.php - -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -/** - Generates a 16-bit random number through RDRAND instruction. - - @param[out] Rand Buffer pointer to store the random result. - - @retval TRUE RDRAND call was successful. - @retval FALSE Failed attempts to call RDRAND. - -**/ -BOOLEAN -EFIAPI -RdRand16Step ( - OUT UINT16 *Rand - ) -{ - UINT8 Carry; - - // - // Uses byte code for RDRAND instruction, - // in case that GCC version has no direct support on RDRAND assembly. - // - __asm__ __volatile__ ( - ".byte 0x66; .byte 0x0f; .byte 0xc7; .byte 0xf0; setc %1" - :"=a" (*Rand), - "=qm" (Carry) - ); - - return (BOOLEAN) Carry; -} - -/** - Generates a 32-bit random number through RDRAND instruction. - - @param[out] Rand Buffer pointer to store the random result. - - @retval TRUE RDRAND call was successful. - @retval FALSE Failed attempts to call RDRAND. - -**/ -BOOLEAN -EFIAPI -RdRand32Step ( - OUT UINT32 *Rand - ) -{ - UINT8 Carry; - - __asm__ __volatile__ ( - ".byte 0x0f; .byte 0xc7; .byte 0xf0; setc %1" - :"=a" (*Rand), - "=qm" (Carry) - ); - - return (BOOLEAN) Carry; -} \ No newline at end of file diff --git a/SecurityPkg/RandomNumberGenerator/RngDxe/IA32/RdRandWord.c b/SecurityPkg/RandomNumberGenerator/RngDxe/IA32/RdRandWord.c deleted file mode 100644 index 125c53b3d3ad..000000000000 --- a/SecurityPkg/RandomNumberGenerator/RngDxe/IA32/RdRandWord.c +++ /dev/null @@ -1,104 +0,0 @@ -/** @file - RDRAND Support Routines. - -Copyright (c) 2013, Intel Corporation. All rights reserved.
-This program and the accompanying materials -are licensed and made available under the terms and conditions of the BSD License -which accompanies this distribution. The full text of the license may be found at -http://opensource.org/licenses/bsd-license.php - -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -#include "RdRand.h" - -/** - Generates a 64-bit random number through RDRAND instruction. - - @param[out] Rand Buffer pointer to store the random result. - - @retval TRUE RDRAND call was successful. - @retval FALSE Failed attempts to call RDRAND. - -**/ -BOOLEAN -EFIAPI -RdRand64Step ( - OUT UINT64 *Rand - ) -{ - UINT32 RandLow; - UINT32 RandHigh; - - // - // Generating a 64-bit rand on a 32-bit system by - // mapping two 32-bit RDRAND instructions. - // - if (!RdRand32Step (&RandLow)) { - return FALSE; - } - if (!RdRand32Step (&RandHigh)) { - return FALSE; - } - - *Rand = (UINT64) RandLow | LShiftU64 ((UINT64)RandHigh, 32); - - return TRUE; -} - -/** - Calls RDRAND to request a word-length random number. - - @param[out] Rand Buffer pointer to store the random number. - @param[in] NeedRetry Determine whether or not to loop retry. - - @retval EFI_SUCCESS Random word generation succeeded. - @retval EFI_NOT_READY Failed to request random word. - -**/ -EFI_STATUS -EFIAPI -RdRandWord ( - OUT UINTN *Rand, - IN BOOLEAN NeedRetry - ) -{ - return RdRand32 (Rand, NeedRetry); -} - -/** - Calls RDRAND to request multiple word-length random numbers. - - @param[in] Length Size of the buffer, in words, to fill with. - @param[out] RandBuffer Pointer to the buffer to store the random result. - - @retval EFI_SUCCESS Random words generation succeeded. - @retval EFI_NOT_READY Failed to request random words. - -**/ -EFI_STATUS -EFIAPI -RdRandGetWords ( - IN UINTN Length, - OUT UINTN *RandBuffer - ) -{ - EFI_STATUS Status; - UINT32 Index; - - for (Index = 0; Index < Length; Index++) { - // - // Obtain one word-length (32-bit) Random Number with possible retry-loop. - // - Status = RdRand32 (RandBuffer, TRUE); - if (EFI_ERROR (Status)) { - return Status; - } - - RandBuffer++; - } - - return EFI_SUCCESS; -} diff --git a/SecurityPkg/RandomNumberGenerator/RngDxe/X64/AsmRdRand.asm b/SecurityPkg/RandomNumberGenerator/RngDxe/X64/AsmRdRand.asm deleted file mode 100644 index 8a4fe65d053a..000000000000 --- a/SecurityPkg/RandomNumberGenerator/RngDxe/X64/AsmRdRand.asm +++ /dev/null @@ -1,83 +0,0 @@ -;------------------------------------------------------------------------------ -; -; Copyright (c) 2013, Intel Corporation. All rights reserved.
-; This program and the accompanying materials -; are licensed and made available under the terms and conditions of the BSD License -; which accompanies this distribution. The full text of the license may be found at -; http://opensource.org/licenses/bsd-license.php. -; -; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -; -; Module Name: -; -; AsmRdRand.Asm -; -; Abstract: -; -; Implementation for 16-, 32-, and 64-bit invocations of RDRAND instruction under 64bit platform. -; -; Notes: -; -; Visual Studio coding practices do not use inline asm since multiple compilers and -; architectures are supported assembler not recognizing rdrand instruction so using DB's. -; -;------------------------------------------------------------------------------ - - .code - -;------------------------------------------------------------------------------ -; Generate a 16 bit random number -; Return TRUE if Rand generated successfully, or FALSE if not -; -; BOOLEAN EFIAPI RdRand16Step (UINT16 *Rand); RCX -;------------------------------------------------------------------------------ -RdRand16Step PROC - ; rdrand ax ; generate a 16 bit RN into ax, CF=1 if RN generated ok, otherwise CF=0 - db 0fh, 0c7h, 0f0h ; rdrand r16: "0f c7 /6 ModRM:r/m(w)" - jb rn16_ok ; jmp if CF=1 - xor rax, rax ; reg=0 if CF=0 - ret ; return with failure status -rn16_ok: - mov [rcx], ax - mov rax, 1 - ret -RdRand16Step ENDP - -;------------------------------------------------------------------------------ -; Generate a 32 bit random number -; Return TRUE if Rand generated successfully, or FALSE if not -; -; BOOLEAN EFIAPI RdRand32Step (UINT32 *Rand); RCX -;------------------------------------------------------------------------------ -RdRand32Step PROC - ; rdrand eax ; generate a 32 bit RN into eax, CF=1 if RN generated ok, otherwise CF=0 - db 0fh, 0c7h, 0f0h ; rdrand r32: "0f c7 /6 ModRM:r/m(w)" - jb rn32_ok ; jmp if CF=1 - xor rax, rax ; reg=0 if CF=0 - ret ; return with failure status -rn32_ok: - mov [rcx], eax - mov rax, 1 - ret -RdRand32Step ENDP - -;------------------------------------------------------------------------------ -; Generate a 64 bit random number -; Return TRUE if RN generated successfully, or FALSE if not -; -; BOOLEAN EFIAPI RdRand64Step (UINT64 *Random); RCX -;------------------------------------------------------------------------------ -RdRand64Step PROC - ; rdrand rax ; generate a 64 bit RN into rax, CF=1 if RN generated ok, otherwise CF=0 - db 048h, 0fh, 0c7h, 0f0h ; rdrand r64: "REX.W + 0F C7 /6 ModRM:r/m(w)" - jb rn64_ok ; jmp if CF=1 - xor rax, rax ; reg=0 if CF=0 - ret ; return with failure status -rn64_ok: - mov [rcx], rax - mov rax, 1 - ret -RdRand64Step ENDP - - END diff --git a/SecurityPkg/RandomNumberGenerator/RngDxe/X64/GccRdRand.c b/SecurityPkg/RandomNumberGenerator/RngDxe/X64/GccRdRand.c deleted file mode 100644 index d28336de4843..000000000000 --- a/SecurityPkg/RandomNumberGenerator/RngDxe/X64/GccRdRand.c +++ /dev/null @@ -1,95 +0,0 @@ -/** @file - RDRAND Support Routines for GCC environment. - -Copyright (c) 2013, Intel Corporation. All rights reserved.
-This program and the accompanying materials -are licensed and made available under the terms and conditions of the BSD License -which accompanies this distribution. The full text of the license may be found at -http://opensource.org/licenses/bsd-license.php - -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -/** - Generates a 16-bit random number through RDRAND instruction. - - @param[out] Rand Buffer pointer to store the random result. - - @retval TRUE RDRAND call was successful. - @retval FALSE Failed attempts to call RDRAND. - -**/ -BOOLEAN -EFIAPI -RdRand16Step ( - OUT UINT16 *Rand - ) -{ - UINT8 Carry; - - // - // Uses byte code for RDRAND instruction, - // in case that GCC version has no direct support on RDRAND assembly. - // - __asm__ __volatile__ ( - ".byte 0x66; .byte 0x0f; .byte 0xc7; .byte 0xf0; setc %1" - :"=a" (*Rand), - "=qm" (Carry) - ); - - return (BOOLEAN) Carry; -} - -/** - Generates a 32-bit random number through RDRAND instruction. - - @param[out] Rand Buffer pointer to store the random result. - - @retval TRUE RDRAND call was successful. - @retval FALSE Failed attempts to call RDRAND. - -**/ -BOOLEAN -EFIAPI -RdRand32Step ( - OUT UINT32 *Rand - ) -{ - UINT8 Carry; - - __asm__ __volatile__ ( - ".byte 0x0f; .byte 0xc7; .byte 0xf0; setc %1" - :"=a" (*Rand), - "=qm" (Carry) - ); - - return (BOOLEAN) Carry; -} - -/** - Generates a 64-bit random number through RDRAND instruction. - - @param[out] Rand Buffer pointer to store the random result. - - @retval TRUE RDRAND call was successful. - @retval FALSE Failed attempts to call RDRAND. - -**/ -BOOLEAN -EFIAPI -RdRand64Step ( - OUT UINT64 *Rand - ) -{ - UINT8 Carry; - - __asm__ __volatile__ ( - ".byte 0x48; .byte 0x0f; .byte 0xc7; .byte 0xf0; setc %1" - :"=a" (*Rand), - "=qm" (Carry) - ); - - return (BOOLEAN) Carry; -} diff --git a/SecurityPkg/RandomNumberGenerator/RngDxe/X64/RdRandWord.c b/SecurityPkg/RandomNumberGenerator/RngDxe/X64/RdRandWord.c deleted file mode 100644 index 946e5babaa85..000000000000 --- a/SecurityPkg/RandomNumberGenerator/RngDxe/X64/RdRandWord.c +++ /dev/null @@ -1,70 +0,0 @@ -/** @file - RDRAND Support Routines. - -Copyright (c) 2013, Intel Corporation. All rights reserved.
-This program and the accompanying materials -are licensed and made available under the terms and conditions of the BSD License -which accompanies this distribution. The full text of the license may be found at -http://opensource.org/licenses/bsd-license.php - -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -#include "RdRand.h" - -/** - Calls RDRAND to request a word-length random number. - - @param[out] Rand Buffer pointer to store the random number. - @param[in] NeedRetry Determine whether or not to loop retry. - - @retval EFI_SUCCESS Random word generation succeeded. - @retval EFI_NOT_READY Failed to request random word. - -**/ -EFI_STATUS -EFIAPI -RdRandWord ( - OUT UINTN *Rand, - IN BOOLEAN NeedRetry - ) -{ - return RdRand64 (Rand, NeedRetry); -} - -/** - Calls RDRAND to request multiple word-length random numbers. - - @param[in] Length Size of the buffer, in words, to fill with. - @param[out] RandBuffer Pointer to the buffer to store the random result. - - @retval EFI_SUCCESS Random words generation succeeded. - @retval EFI_NOT_READY Failed to request random words. - -**/ -EFI_STATUS -EFIAPI -RdRandGetWords ( - IN UINTN Length, - OUT UINTN *RandBuffer - ) -{ - EFI_STATUS Status; - UINT32 Index; - - for (Index = 0; Index < Length; Index++) { - // - // Obtain one word-length (64-bit) Random Number with possible retry-loop. - // - Status = RdRand64 (RandBuffer, TRUE); - if (EFI_ERROR (Status)) { - return Status; - } - - RandBuffer++; - } - - return EFI_SUCCESS; -} \ No newline at end of file From ff113502bd44fe0bc5ec5397e3526bf4e9efb2fd Mon Sep 17 00:00:00 2001 From: Eric Dong Date: Mon, 16 Nov 2015 06:54:44 +0000 Subject: [PATCH 079/525] Update register hot key logic, return EFI_ALREADY_START status if same hot key already existed. In current case, if one key was requested to register twice, browser will override old hot key with new one. This behavior is not user friendly. Now update the logic, return EFI_ALREADY_STARTED for this case. If user still want to override it, he must unregistered it first. (Sync patch r18604 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Eric Dong Reviewed-by: Liming Gao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18794 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Universal/SetupBrowserDxe/Setup.c | 24 +++++++++---------- .../Universal/SetupBrowserDxe/Setup.h | 1 + 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c b/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c index 579396293edf..43cfc87eeb3d 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c @@ -5890,6 +5890,7 @@ SetScope ( @retval EFI_INVALID_PARAMETER KeyData is NULL or HelpString is NULL on register. @retval EFI_NOT_FOUND KeyData is not found to be unregistered. @retval EFI_UNSUPPORTED Key represents a printable character. It is conflicted with Browser. + @retval EFI_ALREADY_STARTED Key already been registered for one hot key. **/ EFI_STATUS EFIAPI @@ -5935,20 +5936,19 @@ RegisterHotKey ( return EFI_NOT_FOUND; } } - + + if (HotKey != NULL) { + return EFI_ALREADY_STARTED; + } + // - // Register HotKey into List. + // Create new Key, and add it into List. // - if (HotKey == NULL) { - // - // Create new Key, and add it into List. - // - HotKey = AllocateZeroPool (sizeof (BROWSER_HOT_KEY)); - ASSERT (HotKey != NULL); - HotKey->Signature = BROWSER_HOT_KEY_SIGNATURE; - HotKey->KeyData = AllocateCopyPool (sizeof (EFI_INPUT_KEY), KeyData); - InsertTailList (&gBrowserHotKeyList, &HotKey->Link); - } + HotKey = AllocateZeroPool (sizeof (BROWSER_HOT_KEY)); + ASSERT (HotKey != NULL); + HotKey->Signature = BROWSER_HOT_KEY_SIGNATURE; + HotKey->KeyData = AllocateCopyPool (sizeof (EFI_INPUT_KEY), KeyData); + InsertTailList (&gBrowserHotKeyList, &HotKey->Link); // // Fill HotKey information. diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Setup.h b/MdeModulePkg/Universal/SetupBrowserDxe/Setup.h index 12381975355e..61e706a0b4c9 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/Setup.h +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Setup.h @@ -1308,6 +1308,7 @@ SetScope ( @retval EFI_INVALID_PARAMETER KeyData is NULL. @retval EFI_NOT_FOUND KeyData is not found to be unregistered. @retval EFI_UNSUPPORTED Key represents a printable character. It is conflicted with Browser. + @retval EFI_ALREADY_STARTED Key already been registered for one hot key. **/ EFI_STATUS EFIAPI From fe25f37f5c000eb72fb325173dd9bb733689cb56 Mon Sep 17 00:00:00 2001 From: Fu Siyuan Date: Mon, 16 Nov 2015 06:55:32 +0000 Subject: [PATCH 080/525] NetworkPkg: remove unnecessary timeout event when setting IPv6 address. Use Ip6Cfg->SetData() to set IP6 manual address is asynchronous process and the registered data notify event will be singled when process is done. So it's not necessary to create another timeout event for the address setting. (Sync patch r18610 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Fu Siyuan Reviewed-by: Ye Ting Reviewed-by: Jiaxin Wu git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18795 6f19259b-4bc3-4df7-8a09-765794883524 --- NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c | 97 ++++++++++++++-------------- 1 file changed, 50 insertions(+), 47 deletions(-) diff --git a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c index 35bdc57479ca..6ad5f5f1ac9f 100644 --- a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c +++ b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c @@ -1376,16 +1376,15 @@ PxeBcRegisterIp6Address ( EFI_IP6_CONFIG_MANUAL_ADDRESS CfgAddr; EFI_IPv6_ADDRESS GatewayAddr; UINTN DataSize; - EFI_EVENT TimeOutEvt; EFI_EVENT MappedEvt; EFI_STATUS Status; - UINT64 DadTriggerTime; - EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS DadXmits; BOOLEAN NoGateway; + EFI_IPv6_ADDRESS *Ip6Addr; + UINTN Index; Status = EFI_SUCCESS; - TimeOutEvt = NULL; MappedEvt = NULL; + Ip6Addr = NULL; DataSize = sizeof (EFI_IP6_CONFIG_POLICY); Ip6Cfg = Private->Ip6Cfg; Ip6 = Private->Ip6; @@ -1426,34 +1425,6 @@ PxeBcRegisterIp6Address ( goto ON_EXIT; } - // - // Get Duplicate Address Detection Transmits count. - // - DataSize = sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS); - Status = Ip6Cfg->GetData ( - Ip6Cfg, - Ip6ConfigDataTypeDupAddrDetectTransmits, - &DataSize, - &DadXmits - ); - if (EFI_ERROR (Status)) { - goto ON_EXIT; - } - - // - // Create a timer as setting address timeout event since DAD in IP6 driver. - // - Status = gBS->CreateEvent ( - EVT_TIMER, - TPL_CALLBACK, - NULL, - NULL, - &TimeOutEvt - ); - if (EFI_ERROR (Status)) { - goto ON_EXIT; - } - // // Create a notify event to set address flag when DAD if IP6 driver succeeded. // @@ -1468,6 +1439,7 @@ PxeBcRegisterIp6Address ( goto ON_EXIT; } + Private->IsAddressOk = FALSE; Status = Ip6Cfg->RegisterDataNotify ( Ip6Cfg, Ip6ConfigDataTypeManualAddress, @@ -1485,23 +1457,54 @@ PxeBcRegisterIp6Address ( ); if (EFI_ERROR(Status) && Status != EFI_NOT_READY) { goto ON_EXIT; - } + } else if (Status == EFI_NOT_READY) { + // + // Poll the network until the asynchronous process is finished. + // + while (!Private->IsAddressOk) { + Ip6->Poll (Ip6); + } + // + // Check whether the IP6 address setting is successed. + // + DataSize = 0; + Status = Ip6Cfg->GetData ( + Ip6Cfg, + Ip6ConfigDataTypeManualAddress, + &DataSize, + NULL + ); + if (Status != EFI_BUFFER_TOO_SMALL || DataSize == 0) { + Status = EFI_DEVICE_ERROR; + goto ON_EXIT; + } - // - // Start the 5 secondes timer to wait for setting address. - // - Status = EFI_NO_MAPPING; - DadTriggerTime = TICKS_PER_SECOND * DadXmits.DupAddrDetectTransmits + PXEBC_DAD_ADDITIONAL_DELAY; - gBS->SetTimer (TimeOutEvt, TimerRelative, DadTriggerTime); + Ip6Addr = AllocatePool (DataSize); + if (Ip6Addr == NULL) { + return EFI_OUT_OF_RESOURCES; + } + Status = Ip6Cfg->GetData ( + Ip6Cfg, + Ip6ConfigDataTypeManualAddress, + &DataSize, + (VOID*) Ip6Addr + ); + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + goto ON_EXIT; + } - while (EFI_ERROR (gBS->CheckEvent (TimeOutEvt))) { - Ip6->Poll (Ip6); - if (Private->IsAddressOk) { - Status = EFI_SUCCESS; - break; + for (Index = 0; Index < DataSize / sizeof (EFI_IPv6_ADDRESS); Index++) { + if (CompareMem (Ip6Addr + Index, Address, sizeof (EFI_IPv6_ADDRESS)) == 0) { + break; + } + } + if (Index == DataSize / sizeof (EFI_IPv6_ADDRESS)) { + Status = EFI_ABORTED; + goto ON_EXIT; } } - + // // Set the default gateway address back if needed. // @@ -1526,8 +1529,8 @@ PxeBcRegisterIp6Address ( ); gBS->CloseEvent (MappedEvt); } - if (TimeOutEvt != NULL) { - gBS->CloseEvent (TimeOutEvt); + if (Ip6Addr != NULL) { + FreePool (Ip6Addr); } return Status; } From dbe8eed088d1aac38ea0bd65da053798b1dc4d20 Mon Sep 17 00:00:00 2001 From: Star Zeng Date: Mon, 16 Nov 2015 06:56:27 +0000 Subject: [PATCH 081/525] MdeModulepkg VarCheckLib: Return NULL when no property set to variable with wildcard name. VarCheckLib has zeroed property for variable with wildcard name and is waiting for property set. The code should return NULL when no property set to variable with wildcard name, but not return the zeroed property that will impact the functionality of SetVariableCheck. The issue does not appear with VarCheckUefiLib linked as the library just has the expected property set. (Sync patch r18611 from main trunk.) Cc: Jiewen Yao Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Star Zeng Reviewed-by: Jiewen Yao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18796 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Library/VarCheckLib/VarCheckLib.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/MdeModulePkg/Library/VarCheckLib/VarCheckLib.c b/MdeModulePkg/Library/VarCheckLib/VarCheckLib.c index cf001547a509..3d1f8f6f4698 100644 --- a/MdeModulePkg/Library/VarCheckLib/VarCheckLib.c +++ b/MdeModulePkg/Library/VarCheckLib/VarCheckLib.c @@ -141,11 +141,19 @@ VariablePropertyGetWithWildcardName ( VarCheckInternalIsHexaDecimalDigitCharacter (VariableName[NameLength + 1]) && VarCheckInternalIsHexaDecimalDigitCharacter (VariableName[NameLength + 2]) && VarCheckInternalIsHexaDecimalDigitCharacter (VariableName[NameLength + 3])) { - return &mVarCheckVariableWithWildcardName[Index].VariableProperty; + if (mVarCheckVariableWithWildcardName[Index].VariableProperty.Revision != VAR_CHECK_VARIABLE_PROPERTY_REVISION) { + return NULL; + } else { + return &mVarCheckVariableWithWildcardName[Index].VariableProperty; + } } } if (StrCmp (mVarCheckVariableWithWildcardName[Index].Name, VariableName) == 0) { - return &mVarCheckVariableWithWildcardName[Index].VariableProperty; + if (mVarCheckVariableWithWildcardName[Index].VariableProperty.Revision != VAR_CHECK_VARIABLE_PROPERTY_REVISION) { + return NULL; + } else { + return &mVarCheckVariableWithWildcardName[Index].VariableProperty; + } } } } From 5c0f43e4483246ede8efa2c1b676d1a0c7eb3143 Mon Sep 17 00:00:00 2001 From: Star Zeng Date: Mon, 16 Nov 2015 06:57:24 +0000 Subject: [PATCH 082/525] MdeModulePkg VariableRuntimeDxe: Add the missing gEfiImageSecurityDatabaseGuid Otherwise there will be build failure if without VarCheckUefiLib linked. (Sync patch r18612 from main trunk.) Cc: Jiewen Yao Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Star Zeng Reviewed-by: Jiewen Yao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18797 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf index 74b35ece09ba..62c1568a50e0 100644 --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf @@ -101,6 +101,10 @@ gEdkiiFaultTolerantWriteGuid ## SOMETIMES_CONSUMES ## HOB gEdkiiVarErrorFlagGuid ## CONSUMES ## GUID + ## SOMETIMES_CONSUMES ## Variable:L"DB" + ## SOMETIMES_CONSUMES ## Variable:L"DBX" + gEfiImageSecurityDatabaseGuid + [Pcd] gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize ## CONSUMES gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase ## SOMETIMES_CONSUMES From 04bc6734f757245e970048d14aeeace549701b29 Mon Sep 17 00:00:00 2001 From: Star Zeng Date: Mon, 16 Nov 2015 06:58:15 +0000 Subject: [PATCH 083/525] SecurityPkg AuthVariableLib: Add the missing gEfiAuthenticatedVariableGuid There is no real build failure, as AuthVariableLib always links to variable driver. But for code integrity, we should add it. (Sync patch r18613 from main trunk.) Cc: Jiewen Yao Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Star Zeng Reviewed-by: Jiewen Yao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18798 6f19259b-4bc3-4df7-8a09-765794883524 --- SecurityPkg/Library/AuthVariableLib/AuthVariableLib.inf | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.inf b/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.inf index d0c0cc230550..3709f7baae0b 100644 --- a/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.inf +++ b/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.inf @@ -81,6 +81,10 @@ ## PRODUCES ## Variable:L"VendorKeysNv" gEfiVendorKeysNvGuid + ## CONSUMES ## Variable:L"AuthVarKeyDatabase" + ## PRODUCES ## Variable:L"AuthVarKeyDatabase" + gEfiAuthenticatedVariableGuid + gEfiCertTypeRsa2048Sha256Guid ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the certificate. gEfiCertPkcs7Guid ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the certificate. gEfiCertX509Guid ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the signature. From b5cf1b799efb64e59218333a5ae44b47a0f26876 Mon Sep 17 00:00:00 2001 From: Fu Siyuan Date: Mon, 16 Nov 2015 06:59:13 +0000 Subject: [PATCH 084/525] MdeModulePkg: reset DHCP child when leaving PXE LoadFile. The DHCP4 can have only one configured child instance so we need to reset the DHCP4 child when leaving PXE driver's LoadFile() function, otherwise the other programs which also need to use DHCP4 (like HTTP boot) will be impacted. (Sync patch r18615 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Fu Siyuan Reviewed-by: Sriram Subramanian Reviewed-by: Ye Ting git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18799 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Universal/Network/UefiPxeBcDxe/PxeBcImpl.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/MdeModulePkg/Universal/Network/UefiPxeBcDxe/PxeBcImpl.c b/MdeModulePkg/Universal/Network/UefiPxeBcDxe/PxeBcImpl.c index 72923f1b38a4..89977e6690b9 100644 --- a/MdeModulePkg/Universal/Network/UefiPxeBcDxe/PxeBcImpl.c +++ b/MdeModulePkg/Universal/Network/UefiPxeBcDxe/PxeBcImpl.c @@ -2902,9 +2902,14 @@ EfiPxeLoadFile ( // if (Status == EFI_SUCCESS) { // + // The DHCP4 can have only one configured child instance so we need to stop + // reset the DHCP4 child before we return. Otherwise the other programs which + // also need to use DHCP4 will be impacted. // The functionality of PXE Base Code protocol will not be stopped, // when downloading is successfully. // + Private->Dhcp4->Stop (Private->Dhcp4); + Private->Dhcp4->Configure (Private->Dhcp4, NULL); return EFI_SUCCESS; } else if (Status == EFI_BUFFER_TOO_SMALL) { From cea2d2433b50493cb05bac564987f851141d5aa3 Mon Sep 17 00:00:00 2001 From: Fu Siyuan Date: Mon, 16 Nov 2015 07:17:05 +0000 Subject: [PATCH 085/525] NetworkPkg: reset DHCP child when leaving PXE LoadFile. The DHCP4 can have only one configured child instance so we need to reset the DHCP4 child when leaving PXE driver's LoadFile() function, otherwise the other programs which also need to use DHCP4 (like HTTP boot) will be impacted. (Sync patch r18616 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Fu Siyuan Reviewed-by: Ye Ting Reviewed-by: Sriram Subramanian git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18800 6f19259b-4bc3-4df7-8a09-765794883524 --- NetworkPkg/UefiPxeBcDxe/PxeBcImpl.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/NetworkPkg/UefiPxeBcDxe/PxeBcImpl.c b/NetworkPkg/UefiPxeBcDxe/PxeBcImpl.c index 367a1356abcc..12e5566a7913 100644 --- a/NetworkPkg/UefiPxeBcDxe/PxeBcImpl.c +++ b/NetworkPkg/UefiPxeBcDxe/PxeBcImpl.c @@ -2392,6 +2392,16 @@ EfiPxeLoadFile ( // 3. unsupported. // PxeBc->Stop (PxeBc); + } else { + // + // The DHCP4 can have only one configured child instance so we need to stop + // reset the DHCP4 child before we return. Otherwise these programs which + // also need to use DHCP4 will be impacted. + // + if (!PxeBc->Mode->UsingIpv6) { + Private->Dhcp4->Stop (Private->Dhcp4); + Private->Dhcp4->Configure (Private->Dhcp4, NULL); + } } return Status; From 964f068d05422e6f7d33210ee7e80f02f883c694 Mon Sep 17 00:00:00 2001 From: "Cohen, Eugene" Date: Mon, 16 Nov 2015 07:17:53 +0000 Subject: [PATCH 086/525] SecurityPkg : Fix Rsa2048Sha256GuidedSectionExtractLib issue This issue causes section extraction overrun and possible hang due to bad output size calculation. (Sync patch r18625 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: "Cohen, Eugene" Reviewed-by: "Zhang, Chao B" git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18801 6f19259b-4bc3-4df7-8a09-765794883524 --- .../DxeRsa2048Sha256GuidedSectionExtractLib.c | 4 ++-- .../PeiRsa2048Sha256GuidedSectionExtractLib.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/SecurityPkg/Library/DxeRsa2048Sha256GuidedSectionExtractLib/DxeRsa2048Sha256GuidedSectionExtractLib.c b/SecurityPkg/Library/DxeRsa2048Sha256GuidedSectionExtractLib/DxeRsa2048Sha256GuidedSectionExtractLib.c index 1f7a29904f3a..5f5d242d6ee7 100644 --- a/SecurityPkg/Library/DxeRsa2048Sha256GuidedSectionExtractLib/DxeRsa2048Sha256GuidedSectionExtractLib.c +++ b/SecurityPkg/Library/DxeRsa2048Sha256GuidedSectionExtractLib/DxeRsa2048Sha256GuidedSectionExtractLib.c @@ -86,7 +86,7 @@ Rsa2048Sha256GuidedSectionGetInfo ( // *SectionAttribute = ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->Attributes; *ScratchBufferSize = 0; - *OutputBufferSize = SECTION2_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->DataOffset; + *OutputBufferSize = SECTION2_SIZE (InputSection) - sizeof(RSA_2048_SHA_256_SECTION2_HEADER); } else { // // Check whether the input guid section is recognized. @@ -101,7 +101,7 @@ Rsa2048Sha256GuidedSectionGetInfo ( // *SectionAttribute = ((EFI_GUID_DEFINED_SECTION *) InputSection)->Attributes; *ScratchBufferSize = 0; - *OutputBufferSize = SECTION_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION *) InputSection)->DataOffset; + *OutputBufferSize = SECTION_SIZE (InputSection) - sizeof(RSA_2048_SHA_256_SECTION_HEADER); } return EFI_SUCCESS; diff --git a/SecurityPkg/Library/PeiRsa2048Sha256GuidedSectionExtractLib/PeiRsa2048Sha256GuidedSectionExtractLib.c b/SecurityPkg/Library/PeiRsa2048Sha256GuidedSectionExtractLib/PeiRsa2048Sha256GuidedSectionExtractLib.c index e2a0fb670884..e448164a5a33 100644 --- a/SecurityPkg/Library/PeiRsa2048Sha256GuidedSectionExtractLib/PeiRsa2048Sha256GuidedSectionExtractLib.c +++ b/SecurityPkg/Library/PeiRsa2048Sha256GuidedSectionExtractLib/PeiRsa2048Sha256GuidedSectionExtractLib.c @@ -84,7 +84,7 @@ Rsa2048Sha256GuidedSectionGetInfo ( // *SectionAttribute = ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->Attributes; *ScratchBufferSize = 0; - *OutputBufferSize = SECTION2_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->DataOffset; + *OutputBufferSize = SECTION2_SIZE (InputSection) - sizeof(RSA_2048_SHA_256_SECTION2_HEADER); } else { // // Check whether the input guid section is recognized. @@ -99,7 +99,7 @@ Rsa2048Sha256GuidedSectionGetInfo ( // *SectionAttribute = ((EFI_GUID_DEFINED_SECTION *) InputSection)->Attributes; *ScratchBufferSize = 0; - *OutputBufferSize = SECTION_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION *) InputSection)->DataOffset; + *OutputBufferSize = SECTION_SIZE (InputSection) - sizeof(RSA_2048_SHA_256_SECTION_HEADER); } return EFI_SUCCESS; From 7e37880a7fe0f485d00c5ffd046d6b81fd18e144 Mon Sep 17 00:00:00 2001 From: Star Zeng Date: Mon, 16 Nov 2015 07:18:36 +0000 Subject: [PATCH 087/525] MdeModulePkg VarCheckLib: R18611 was thoughtless for property set R18611 only updated the logic to return correct property when no property set to variable with wildcard name. But VariablePropertySet needs the pointer of property data for set. So roll back the change in VariablePropertyGetWithWildcardName at R18611, and check the property revision first in VariablePropertyGet and SetVariableCheck before using the property data. (Sync patch r18626 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Star Zeng Reviewed-by: Jiewen Yao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18802 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Library/VarCheckLib/VarCheckLib.c | 29 +++++++++++-------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/MdeModulePkg/Library/VarCheckLib/VarCheckLib.c b/MdeModulePkg/Library/VarCheckLib/VarCheckLib.c index 3d1f8f6f4698..60c141a6b935 100644 --- a/MdeModulePkg/Library/VarCheckLib/VarCheckLib.c +++ b/MdeModulePkg/Library/VarCheckLib/VarCheckLib.c @@ -141,19 +141,11 @@ VariablePropertyGetWithWildcardName ( VarCheckInternalIsHexaDecimalDigitCharacter (VariableName[NameLength + 1]) && VarCheckInternalIsHexaDecimalDigitCharacter (VariableName[NameLength + 2]) && VarCheckInternalIsHexaDecimalDigitCharacter (VariableName[NameLength + 3])) { - if (mVarCheckVariableWithWildcardName[Index].VariableProperty.Revision != VAR_CHECK_VARIABLE_PROPERTY_REVISION) { - return NULL; - } else { - return &mVarCheckVariableWithWildcardName[Index].VariableProperty; - } + return &mVarCheckVariableWithWildcardName[Index].VariableProperty; } } if (StrCmp (mVarCheckVariableWithWildcardName[Index].Name, VariableName) == 0) { - if (mVarCheckVariableWithWildcardName[Index].VariableProperty.Revision != VAR_CHECK_VARIABLE_PROPERTY_REVISION) { - return NULL; - } else { - return &mVarCheckVariableWithWildcardName[Index].VariableProperty; - } + return &mVarCheckVariableWithWildcardName[Index].VariableProperty; } } } @@ -512,6 +504,9 @@ VarCheckLibVariablePropertySet ( Status = EFI_SUCCESS; + // + // Get the pointer of property data for set. + // Property = VariablePropertyGetFunction (Name, Guid, FALSE); if (Property != NULL) { CopyMem (Property, VariableProperty, sizeof (*VariableProperty)); @@ -571,7 +566,12 @@ VarCheckLibVariablePropertyGet ( } Property = VariablePropertyGetFunction (Name, Guid, TRUE); - if (Property != NULL) { + // + // Also check the property revision before using the property data. + // There is no property set to this variable(wildcard name) + // if the revision is not VAR_CHECK_VARIABLE_PROPERTY_REVISION. + // + if ((Property != NULL) && (Property->Revision == VAR_CHECK_VARIABLE_PROPERTY_REVISION)) { CopyMem (VariableProperty, Property, sizeof (*VariableProperty)); return EFI_SUCCESS; } @@ -619,7 +619,12 @@ VarCheckLibSetVariableCheck ( } Property = VariablePropertyGetFunction (VariableName, VendorGuid, TRUE); - if (Property != NULL) { + // + // Also check the property revision before using the property data. + // There is no property set to this variable(wildcard name) + // if the revision is not VAR_CHECK_VARIABLE_PROPERTY_REVISION. + // + if ((Property != NULL) && (Property->Revision == VAR_CHECK_VARIABLE_PROPERTY_REVISION)) { if ((RequestSource != VarCheckFromTrusted) && ((Property->Property & VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY) != 0)) { DEBUG ((EFI_D_INFO, "Variable Check ReadOnly variable fail %r - %g:%s\n", EFI_WRITE_PROTECTED, VendorGuid, VariableName)); return EFI_WRITE_PROTECTED; From b0a3a913c1b9ce7f14324e3d73308f0bbbe9d35f Mon Sep 17 00:00:00 2001 From: Eric Dong Date: Mon, 16 Nov 2015 08:02:03 +0000 Subject: [PATCH 088/525] MdeModulePkg SetupBrowserDxe: Save global variable values before nest function called. The SendForm function can be called nest in it. This function also uses some global variables. So we must save global variable values before it been called again. Old implementation miss to save some global variables, this patch fixed it. (Sync patch r18650 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Eric Dong Reviewed-by: Liming Gao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18803 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Universal/SetupBrowserDxe/Setup.c | 8 ++++++++ MdeModulePkg/Universal/SetupBrowserDxe/Setup.h | 8 +++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c b/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c index 43cfc87eeb3d..4a6758a5e489 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c @@ -5568,6 +5568,10 @@ SaveBrowserContext ( Context->HiiHandle = mCurrentHiiHandle; Context->FormId = mCurrentFormId; CopyGuid (&Context->FormSetGuid, &mCurrentFormSetGuid); + Context->SystemLevelFormSet = mSystemLevelFormSet; + Context->CurFakeQestId = mCurFakeQestId; + Context->HiiPackageListUpdated = mHiiPackageListUpdated; + Context->FinishRetrieveCall = mFinishRetrieveCall; // // Save the menu history data. @@ -5625,6 +5629,10 @@ RestoreBrowserContext ( mCurrentHiiHandle = Context->HiiHandle; mCurrentFormId = Context->FormId; CopyGuid (&mCurrentFormSetGuid, &Context->FormSetGuid); + mSystemLevelFormSet = Context->SystemLevelFormSet; + mCurFakeQestId = Context->CurFakeQestId; + mHiiPackageListUpdated = Context->HiiPackageListUpdated; + mFinishRetrieveCall = Context->FinishRetrieveCall; // // Restore the menu history data. diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Setup.h b/MdeModulePkg/Universal/SetupBrowserDxe/Setup.h index 61e706a0b4c9..81e2a62df198 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/Setup.h +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Setup.h @@ -538,7 +538,10 @@ typedef struct { EFI_GUID FormSetGuid; EFI_FORM_ID FormId; UI_MENU_SELECTION *Selection; - + FORM_BROWSER_FORMSET *SystemLevelFormSet; + EFI_QUESTION_ID CurFakeQestId; + BOOLEAN HiiPackageListUpdated; + BOOLEAN FinishRetrieveCall; LIST_ENTRY FormHistoryList; } BROWSER_CONTEXT; @@ -586,6 +589,9 @@ extern SETUP_DRIVER_PRIVATE_DATA mPrivateData; extern CHAR16 *gEmptyString; extern UI_MENU_SELECTION *gCurrentSelection; +extern BOOLEAN mHiiPackageListUpdated; +extern UINT16 mCurFakeQestId; +extern BOOLEAN mFinishRetrieveCall; // // Global Procedure Defines From 25c087fae6279a6856a901dd045c148c1ae9c6d1 Mon Sep 17 00:00:00 2001 From: Ruiyu Ni Date: Mon, 16 Nov 2015 08:02:59 +0000 Subject: [PATCH 089/525] MdeModulePkg: Update BootManagerMenuApp to not display itself (Sync patch r18656 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ruiyu Ni Reviewed-by: Jiewen Yao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18804 6f19259b-4bc3-4df7-8a09-765794883524 --- .../BootManagerMenuApp/BootManagerMenu.c | 17 +++++++++++++++-- .../BootManagerMenuApp/BootManagerMenuApp.inf | 1 + 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenu.c b/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenu.c index c5a35c070fe2..2f90883cbbfd 100644 --- a/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenu.c +++ b/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenu.c @@ -262,13 +262,18 @@ InitializeBootMenuData ( OUT BOOT_MENU_POPUP_DATA *BootMenuData ) { + EFI_STATUS Status; UINTN Index; UINTN StrIndex; + EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath; if (BootOption == NULL || BootMenuData == NULL) { return EFI_INVALID_PARAMETER; - } - + } + + Status = gBS->HandleProtocol (gImageHandle, &gEfiLoadedImageDevicePathProtocolGuid, (VOID **) &ImageDevicePath); + ASSERT_EFI_ERROR (Status); + BootMenuData->TitleToken[0] = STRING_TOKEN (STR_BOOT_POPUP_MENU_TITLE_STRING); BootMenuData->PtrTokens = AllocateZeroPool (BootOptionCount * sizeof (EFI_STRING_ID)); ASSERT (BootMenuData->PtrTokens != NULL); @@ -284,6 +289,14 @@ InitializeBootMenuData ( !IsBootManagerMenu (&BootOption[Index])) { continue; } + + // + // Don't display myself + // + if (CompareMem (BootOption[Index].FilePath, ImageDevicePath, GetDevicePathSize (ImageDevicePath)) == 0) { + continue; + } + ASSERT (BootOption[Index].Description != NULL); BootMenuData->PtrTokens[StrIndex++] = HiiSetString ( gStringPackHandle, diff --git a/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenuApp.inf b/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenuApp.inf index b4455054096d..dd60ef4cd882 100644 --- a/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenuApp.inf +++ b/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenuApp.inf @@ -52,6 +52,7 @@ [Protocols] gEfiBootLogoProtocolGuid ## CONSUMES + gEfiLoadedImageDevicePathProtocolGuid ## CONSUMES [Pcd] gEfiMdeModulePkgTokenSpaceGuid.PcdConOutRow ## PRODUCES From 4e6613aa75d2d4f7084bfb07a086677201369d4d Mon Sep 17 00:00:00 2001 From: Ruiyu Ni Date: Mon, 16 Nov 2015 08:03:52 +0000 Subject: [PATCH 090/525] MdeModulePkg: Update UiApp to not display itself (Sync patch r18657 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ruiyu Ni Reviewed-by: Jiewen Yao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18805 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Application/UiApp/BootMngr/BootManager.c | 12 ++++++++++++ MdeModulePkg/Application/UiApp/Ui.h | 1 + MdeModulePkg/Application/UiApp/UiApp.inf | 1 + 3 files changed, 14 insertions(+) diff --git a/MdeModulePkg/Application/UiApp/BootMngr/BootManager.c b/MdeModulePkg/Application/UiApp/BootMngr/BootManager.c index 986413c19b4a..4390deef2455 100644 --- a/MdeModulePkg/Application/UiApp/BootMngr/BootManager.c +++ b/MdeModulePkg/Application/UiApp/BootMngr/BootManager.c @@ -219,7 +219,9 @@ EnumerateBootOptions ( VOID ) { + EFI_STATUS Status; UINTN Index; + EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath; EFI_BOOT_MANAGER_LOAD_OPTION *BootOption; UINTN BootOptionCount; EFI_STRING_ID Token; @@ -240,6 +242,9 @@ EnumerateBootOptions ( DeviceType = (UINT16) -1; + Status = gBS->HandleProtocol (gImageHandle, &gEfiLoadedImageDevicePathProtocolGuid, (VOID **) &ImageDevicePath); + ASSERT_EFI_ERROR (Status); + // // for better user experience // 1. User changes HD configuration (e.g.: unplug HDD), here we have a chance to remove the HDD boot option @@ -289,6 +294,13 @@ EnumerateBootOptions ( continue; } + // + // Don't display myself + // + if (CompareMem (BootOption[Index].FilePath, ImageDevicePath, GetDevicePathSize (ImageDevicePath)) == 0) { + continue; + } + // // Group the legacy boot option in the sub title created dynamically // diff --git a/MdeModulePkg/Application/UiApp/Ui.h b/MdeModulePkg/Application/UiApp/Ui.h index 413266d815d4..815987800707 100644 --- a/MdeModulePkg/Application/UiApp/Ui.h +++ b/MdeModulePkg/Application/UiApp/Ui.h @@ -30,6 +30,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include +#include #include #include #include diff --git a/MdeModulePkg/Application/UiApp/UiApp.inf b/MdeModulePkg/Application/UiApp/UiApp.inf index 36d292e67634..9553c7bab569 100644 --- a/MdeModulePkg/Application/UiApp/UiApp.inf +++ b/MdeModulePkg/Application/UiApp/UiApp.inf @@ -123,6 +123,7 @@ gEfiPciIoProtocolGuid ## CONSUMES gEfiDevicePathToTextProtocolGuid ## CONSUMES gEfiBootLogoProtocolGuid ## CONSUMES + gEfiLoadedImageDevicePathProtocolGuid ## CONSUMES [FeaturePcd] From 4ad4fe2bd3bbfeab5ed100bd6363d654bcf33dd4 Mon Sep 17 00:00:00 2001 From: "Yao, Jiewen" Date: Mon, 16 Nov 2015 08:04:49 +0000 Subject: [PATCH 091/525] Move Smbios table MAX length definition to Mde header filer. So that other module can also refer to them. (Sync patch r18674 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: "Yao, Jiewen" Reviewed-by: "Zeng, Star" git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18806 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.h | 12 ------------ MdePkg/Include/IndustryStandard/SmBios.h | 12 ++++++++++++ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.h b/MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.h index f87c8de8ca07..10cff8dd59f6 100644 --- a/MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.h +++ b/MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.h @@ -31,18 +31,6 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include -// -// The length of the entire structure table (including all strings) must be reported -// in the Structure Table Length field of the SMBIOS Structure Table Entry Point, -// which is a WORD field limited to 65,535 bytes. -// -#define SMBIOS_TABLE_MAX_LENGTH 0xFFFF - -// -// For SMBIOS 3.0, Structure table maximum size in Entry Point structure is DWORD field limited to 0xFFFFFFFF bytes. -// -#define SMBIOS_3_0_TABLE_MAX_LENGTH 0xFFFFFFFF - #define SMBIOS_INSTANCE_SIGNATURE SIGNATURE_32 ('S', 'B', 'i', 's') typedef struct { UINT32 Signature; diff --git a/MdePkg/Include/IndustryStandard/SmBios.h b/MdePkg/Include/IndustryStandard/SmBios.h index 14b5208fc5e2..0959247f5432 100644 --- a/MdePkg/Include/IndustryStandard/SmBios.h +++ b/MdePkg/Include/IndustryStandard/SmBios.h @@ -38,6 +38,18 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. /// #define SMBIOS_STRING_MAX_LENGTH 64 +// +// The length of the entire structure table (including all strings) must be reported +// in the Structure Table Length field of the SMBIOS Structure Table Entry Point, +// which is a WORD field limited to 65,535 bytes. +// +#define SMBIOS_TABLE_MAX_LENGTH 0xFFFF + +// +// For SMBIOS 3.0, Structure table maximum size in Entry Point structure is DWORD field limited to 0xFFFFFFFF bytes. +// +#define SMBIOS_3_0_TABLE_MAX_LENGTH 0xFFFFFFFF + /// /// Inactive type is added from SMBIOS 2.2. Reference SMBIOS 2.6, chapter 3.3.43. /// Upper-level software that interprets the SMBIOS structure-table should bypass an From 93e9f9955051c56b8cb0f44e2fa48ef156663216 Mon Sep 17 00:00:00 2001 From: "Yao, Jiewen" Date: Mon, 16 Nov 2015 08:05:37 +0000 Subject: [PATCH 092/525] Add suppressif around TCG hash seleciton checkbox in TCG2 Previous TCG2 configuration UI always add all TCG defined hash algorithm to let user select which one need be used. This brings risk that user might select unsupported hash, and selection is rejected later. So we enhance to UI to hide unsupported hash algorithm. (Sync patch r18676 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: "Yao, Jiewen" Reviewed-by: "Zhang, Chao B" git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18807 6f19259b-4bc3-4df7-8a09-765794883524 --- SecurityPkg/Tcg/Tcg2Config/Tcg2Config.vfr | 16 +++++++ SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigImpl.c | 48 +++++++++++++++++++ SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigNvData.h | 12 ++++- 3 files changed, 75 insertions(+), 1 deletion(-) diff --git a/SecurityPkg/Tcg/Tcg2Config/Tcg2Config.vfr b/SecurityPkg/Tcg/Tcg2Config/Tcg2Config.vfr index fe0ef14c2f1b..b3504441d083 100644 --- a/SecurityPkg/Tcg/Tcg2Config/Tcg2Config.vfr +++ b/SecurityPkg/Tcg/Tcg2Config/Tcg2Config.vfr @@ -19,6 +19,12 @@ formset title = STRING_TOKEN(STR_TCG2_TITLE), help = STRING_TOKEN(STR_TCG2_HELP), classguid = EFI_HII_PLATFORM_SETUP_FORMSET_GUID, + + efivarstore TCG2_CONFIGURATION_INFO, + varid = TCG2_CONFIGURATION_INFO_VARSTORE_ID, + attribute = 0x02, // EFI variable attribures EFI_VARIABLE_BOOTSERVICE_ACCESS + name = TCG2_CONFIGURATION_INFO, + guid = TCG2_CONFIG_FORM_SET_GUID; efivarstore TCG2_CONFIGURATION, varid = TCG2_CONFIGURATION_VARSTORE_ID, @@ -120,6 +126,7 @@ formset subtitle text = STRING_TOKEN(STR_NULL); + suppressif ideqval TCG2_CONFIGURATION_INFO.Sha1Supported == 0; checkbox name = TCG2ActivatePCRBank0, questionid = KEY_TPM2_PCR_BANKS_REQUEST_0, prompt = STRING_TOKEN(STR_TCG2_PCR_BANK_SHA1), @@ -127,7 +134,9 @@ formset flags = INTERACTIVE, default = 1, endcheckbox; + endif; + suppressif ideqval TCG2_CONFIGURATION_INFO.Sha256Supported == 0; checkbox name = TCG2ActivatePCRBank1, questionid = KEY_TPM2_PCR_BANKS_REQUEST_1, prompt = STRING_TOKEN(STR_TCG2_PCR_BANK_SHA256), @@ -135,7 +144,9 @@ formset flags = INTERACTIVE, default = 0, endcheckbox; + endif; + suppressif ideqval TCG2_CONFIGURATION_INFO.Sha384Supported == 0; checkbox name = TCG2ActivatePCRBank2, questionid = KEY_TPM2_PCR_BANKS_REQUEST_2, prompt = STRING_TOKEN(STR_TCG2_PCR_BANK_SHA384), @@ -143,7 +154,9 @@ formset flags = INTERACTIVE, default = 0, endcheckbox; + endif; + suppressif ideqval TCG2_CONFIGURATION_INFO.Sha512Supported == 0; checkbox name = TCG2ActivatePCRBank3, questionid = KEY_TPM2_PCR_BANKS_REQUEST_3, prompt = STRING_TOKEN(STR_TCG2_PCR_BANK_SHA512), @@ -151,7 +164,9 @@ formset flags = INTERACTIVE, default = 0, endcheckbox; + endif; + suppressif ideqval TCG2_CONFIGURATION_INFO.Sm3Supported == 0; checkbox name = TCG2ActivatePCRBank4, questionid = KEY_TPM2_PCR_BANKS_REQUEST_4, prompt = STRING_TOKEN(STR_TCG2_PCR_BANK_SM3_256), @@ -159,6 +174,7 @@ formset flags = INTERACTIVE, default = 0, endcheckbox; + endif; endif; diff --git a/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigImpl.c b/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigImpl.c index 245376966ea3..0d2956074a40 100644 --- a/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigImpl.c +++ b/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigImpl.c @@ -386,6 +386,38 @@ FillBufferWithBootHashAlg ( } } +/** + Set ConfigInfo according to TpmAlgHash. + + @param[in,out] Tcg2ConfigInfo TCG2 config info. + @param[in] TpmAlgHash TpmAlgHash. + +**/ +VOID +SetConfigInfo ( + IN OUT TCG2_CONFIGURATION_INFO *Tcg2ConfigInfo, + IN UINT32 TpmAlgHash + ) +{ + switch (TpmAlgHash) { + case TPM_ALG_SHA1: + Tcg2ConfigInfo->Sha1Supported = TRUE; + break; + case TPM_ALG_SHA256: + Tcg2ConfigInfo->Sha256Supported = TRUE; + break; + case TPM_ALG_SHA384: + Tcg2ConfigInfo->Sha384Supported = TRUE; + break; + case TPM_ALG_SHA512: + Tcg2ConfigInfo->Sha512Supported = TRUE; + break; + case TPM_ALG_SM3_256: + Tcg2ConfigInfo->Sm3Supported = TRUE; + break; + } +} + /** Fill Buffer With TCG2EventLogFormat. @@ -471,6 +503,7 @@ InstallTcg2ConfigForm ( UINTN Index; TPML_PCR_SELECTION Pcrs; CHAR16 TempBuffer[1024]; + TCG2_CONFIGURATION_INFO Tcg2ConfigInfo; DriverHandle = NULL; ConfigAccess = &PrivateData->ConfigAccess; @@ -531,6 +564,7 @@ InstallTcg2ConfigForm ( break; } + ZeroMem (&Tcg2ConfigInfo, sizeof(Tcg2ConfigInfo)); Status = Tpm2GetCapabilityPcrs (&Pcrs); if (EFI_ERROR (Status)) { HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TPM2_ACTIVE_HASH_ALGO_CONTENT), L"[Unknown]", NULL); @@ -547,6 +581,7 @@ InstallTcg2ConfigForm ( TempBuffer[0] = 0; for (Index = 0; Index < Pcrs.count; Index++) { AppendBufferWithTpmAlgHash (TempBuffer, sizeof(TempBuffer), Pcrs.pcrSelections[Index].hash); + SetConfigInfo (&Tcg2ConfigInfo, Pcrs.pcrSelections[Index].hash); } HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TPM2_SUPPORTED_HASH_ALGO_CONTENT), TempBuffer, NULL); } @@ -569,6 +604,19 @@ InstallTcg2ConfigForm ( FillBufferWithBootHashAlg (TempBuffer, sizeof(TempBuffer), PrivateData->ProtocolCapability.ActivePcrBanks); HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TCG2_ACTIVE_PCR_BANKS_CONTENT), TempBuffer, NULL); + // + // Set ConfigInfo, to control the check box. + // + Status = gRT->SetVariable ( + TCG2_STORAGE_INFO_NAME, + &gTcg2ConfigFormSetGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS, + sizeof(Tcg2ConfigInfo), + &Tcg2ConfigInfo + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Tcg2ConfigDriver: Fail to set TCG2_STORAGE_INFO_NAME\n")); + } return EFI_SUCCESS; } diff --git a/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigNvData.h b/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigNvData.h index 65044c2bd5e9..c6b3d32f49a4 100644 --- a/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigNvData.h +++ b/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigNvData.h @@ -29,6 +29,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #define EFI_TCG2_EVENT_LOG_FORMAT_ALL (EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2 | EFI_TCG2_EVENT_LOG_FORMAT_TCG_2) #define TCG2_CONFIGURATION_VARSTORE_ID 0x0001 +#define TCG2_CONFIGURATION_INFO_VARSTORE_ID 0x0002 #define TCG2_CONFIGURATION_FORM_ID 0x0001 #define KEY_TPM_DEVICE 0x2000 @@ -57,6 +58,14 @@ typedef struct { UINT8 TpmDevice; } TCG2_CONFIGURATION; +typedef struct { + UINT8 Sha1Supported; + UINT8 Sha256Supported; + UINT8 Sha384Supported; + UINT8 Sha512Supported; + UINT8 Sm3Supported; +} TCG2_CONFIGURATION_INFO; + // // Variable saved for S3, TPM detected, only valid in S3 path. // This variable is ReadOnly. @@ -65,7 +74,8 @@ typedef struct { UINT8 TpmDeviceDetected; } TCG2_DEVICE_DETECTION; -#define TCG2_STORAGE_NAME L"TCG2_CONFIGURATION" +#define TCG2_STORAGE_NAME L"TCG2_CONFIGURATION" +#define TCG2_STORAGE_INFO_NAME L"TCG2_CONFIGURATION_INFO" #define TCG2_DEVICE_DETECTION_NAME L"TCG2_DEVICE_DETECTION" #define TPM_INSTANCE_ID_LIST { \ From 2f6dbfce6d8d261f4829cb921f4fb9923f24f9b6 Mon Sep 17 00:00:00 2001 From: "Yao, Jiewen" Date: Mon, 16 Nov 2015 08:06:55 +0000 Subject: [PATCH 093/525] Move Smbios measurement from TCG driver to Smbios driver. This is patch to remove smbios measurement in TCG driver. There will be other patch to add it in Smbios driver. The problem of current SMBIOS measurement is: 1) TCG drivers do not support SMBIOS3.0 table. 2) TCG drivers do not follow TCG platform spec on: "Platform configuration information that is automatically updated, such as clock registers, and system unique information, such as asset numbers or serial numbers, MUST NOT be measured into PCR [1], or any other PCR." So we decide to move Smbios measurement from TCG drivers to Smbios driver. (Sync patch r18677 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: "Yao, Jiewen" Reviewed-by: "Zhang, Chao B" git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18808 6f19259b-4bc3-4df7-8a09-765794883524 --- SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c | 33 +---------------------------- SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf | 4 ---- SecurityPkg/Tcg/TcgDxe/TcgDxe.c | 33 +---------------------------- SecurityPkg/Tcg/TcgDxe/TcgDxe.inf | 4 ---- SecurityPkg/Tcg/TrEEDxe/TrEEDxe.c | 33 +---------------------------- SecurityPkg/Tcg/TrEEDxe/TrEEDxe.inf | 4 ---- 6 files changed, 3 insertions(+), 108 deletions(-) diff --git a/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c b/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c index 9ad970a47be6..7076772f30a3 100644 --- a/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c +++ b/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c @@ -15,11 +15,9 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include #include -#include #include #include -#include #include #include #include @@ -1690,42 +1688,13 @@ MeasureHandoffTables ( ) { EFI_STATUS Status; - SMBIOS_TABLE_ENTRY_POINT *SmbiosTable; TCG_PCR_EVENT_HDR TcgEvent; EFI_HANDOFF_TABLE_POINTERS HandoffTables; UINTN ProcessorNum; EFI_CPU_PHYSICAL_LOCATION *ProcessorLocBuf; ProcessorLocBuf = NULL; - - // - // Measure SMBIOS with EV_EFI_HANDOFF_TABLES to PCR[1] - // - Status = EfiGetSystemConfigurationTable ( - &gEfiSmbiosTableGuid, - (VOID **) &SmbiosTable - ); - - if (!EFI_ERROR (Status) && SmbiosTable != NULL) { - TcgEvent.PCRIndex = 1; - TcgEvent.EventType = EV_EFI_HANDOFF_TABLES; - TcgEvent.EventSize = sizeof (HandoffTables); - - HandoffTables.NumberOfTables = 1; - HandoffTables.TableEntry[0].VendorGuid = gEfiSmbiosTableGuid; - HandoffTables.TableEntry[0].VendorTable = SmbiosTable; - - DEBUG ((DEBUG_INFO, "The Smbios Table starts at: 0x%x\n", SmbiosTable->TableAddress)); - DEBUG ((DEBUG_INFO, "The Smbios Table size: 0x%x\n", SmbiosTable->TableLength)); - - Status = TcgDxeHashLogExtendEvent ( - 0, - (UINT8*)(UINTN)SmbiosTable->TableAddress, - SmbiosTable->TableLength, - &TcgEvent, - (UINT8*)&HandoffTables - ); - } + Status = EFI_SUCCESS; if (PcdGet8 (PcdTpmPlatformClass) == TCG_PLATFORM_TYPE_SERVER) { // diff --git a/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf b/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf index d6ac07ea6eeb..ca6741b3ad4d 100644 --- a/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf +++ b/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf @@ -61,10 +61,6 @@ Tcg2PhysicalPresenceLib [Guids] - ## SOMETIMES_CONSUMES ## SystemTable # Smbios Table - ## SOMETIMES_CONSUMES ## GUID # Handoff Table for measurement. - gEfiSmbiosTableGuid - ## SOMETIMES_CONSUMES ## Variable:L"SecureBoot" ## SOMETIMES_CONSUMES ## Variable:L"PK" ## SOMETIMES_CONSUMES ## Variable:L"KEK" diff --git a/SecurityPkg/Tcg/TcgDxe/TcgDxe.c b/SecurityPkg/Tcg/TcgDxe/TcgDxe.c index 4b9afe34a44d..80919414ab44 100644 --- a/SecurityPkg/Tcg/TcgDxe/TcgDxe.c +++ b/SecurityPkg/Tcg/TcgDxe/TcgDxe.c @@ -23,11 +23,9 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include #include -#include #include #include -#include #include #include #include @@ -748,42 +746,13 @@ MeasureHandoffTables ( ) { EFI_STATUS Status; - SMBIOS_TABLE_ENTRY_POINT *SmbiosTable; TCG_PCR_EVENT_HDR TcgEvent; EFI_HANDOFF_TABLE_POINTERS HandoffTables; UINTN ProcessorNum; EFI_CPU_PHYSICAL_LOCATION *ProcessorLocBuf; ProcessorLocBuf = NULL; - - // - // Measure SMBIOS with EV_EFI_HANDOFF_TABLES to PCR[1] - // - Status = EfiGetSystemConfigurationTable ( - &gEfiSmbiosTableGuid, - (VOID **) &SmbiosTable - ); - - if (!EFI_ERROR (Status) && SmbiosTable != NULL) { - TcgEvent.PCRIndex = 1; - TcgEvent.EventType = EV_EFI_HANDOFF_TABLES; - TcgEvent.EventSize = sizeof (HandoffTables); - - HandoffTables.NumberOfTables = 1; - HandoffTables.TableEntry[0].VendorGuid = gEfiSmbiosTableGuid; - HandoffTables.TableEntry[0].VendorTable = SmbiosTable; - - DEBUG ((DEBUG_INFO, "The Smbios Table starts at: 0x%x\n", SmbiosTable->TableAddress)); - DEBUG ((DEBUG_INFO, "The Smbios Table size: 0x%x\n", SmbiosTable->TableLength)); - - Status = TcgDxeHashLogExtendEventI ( - &mTcgDxeData, - (UINT8*)(UINTN)SmbiosTable->TableAddress, - SmbiosTable->TableLength, - &TcgEvent, - (UINT8*)&HandoffTables - ); - } + Status = EFI_SUCCESS; if (PcdGet8 (PcdTpmPlatformClass) == TCG_PLATFORM_TYPE_SERVER) { // diff --git a/SecurityPkg/Tcg/TcgDxe/TcgDxe.inf b/SecurityPkg/Tcg/TcgDxe/TcgDxe.inf index 39aeb8b950e4..0976304883f2 100644 --- a/SecurityPkg/Tcg/TcgDxe/TcgDxe.inf +++ b/SecurityPkg/Tcg/TcgDxe/TcgDxe.inf @@ -54,10 +54,6 @@ ReportStatusCodeLib [Guids] - ## SOMETIMES_CONSUMES ## SystemTable # Smbios Table - ## SOMETIMES_CONSUMES ## GUID # Handoff Table for measurement. - gEfiSmbiosTableGuid - gEfiGlobalVariableGuid ## SOMETIMES_CONSUMES ## Variable:L"BootXXXX" gTcgEventEntryHobGuid ## SOMETIMES_CONSUMES ## HOB gTpmErrorHobGuid ## SOMETIMES_CONSUMES ## HOB diff --git a/SecurityPkg/Tcg/TrEEDxe/TrEEDxe.c b/SecurityPkg/Tcg/TrEEDxe/TrEEDxe.c index 582f09f99f39..41e7207eaffa 100644 --- a/SecurityPkg/Tcg/TrEEDxe/TrEEDxe.c +++ b/SecurityPkg/Tcg/TrEEDxe/TrEEDxe.c @@ -15,11 +15,9 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include #include -#include #include #include -#include #include #include #include @@ -1046,42 +1044,13 @@ MeasureHandoffTables ( ) { EFI_STATUS Status; - SMBIOS_TABLE_ENTRY_POINT *SmbiosTable; TCG_PCR_EVENT_HDR TcgEvent; EFI_HANDOFF_TABLE_POINTERS HandoffTables; UINTN ProcessorNum; EFI_CPU_PHYSICAL_LOCATION *ProcessorLocBuf; ProcessorLocBuf = NULL; - - // - // Measure SMBIOS with EV_EFI_HANDOFF_TABLES to PCR[1] - // - Status = EfiGetSystemConfigurationTable ( - &gEfiSmbiosTableGuid, - (VOID **) &SmbiosTable - ); - - if (!EFI_ERROR (Status) && SmbiosTable != NULL) { - TcgEvent.PCRIndex = 1; - TcgEvent.EventType = EV_EFI_HANDOFF_TABLES; - TcgEvent.EventSize = sizeof (HandoffTables); - - HandoffTables.NumberOfTables = 1; - HandoffTables.TableEntry[0].VendorGuid = gEfiSmbiosTableGuid; - HandoffTables.TableEntry[0].VendorTable = SmbiosTable; - - DEBUG ((DEBUG_INFO, "The Smbios Table starts at: 0x%x\n", SmbiosTable->TableAddress)); - DEBUG ((DEBUG_INFO, "The Smbios Table size: 0x%x\n", SmbiosTable->TableLength)); - - Status = TcgDxeHashLogExtendEvent ( - 0, - (UINT8*)(UINTN)SmbiosTable->TableAddress, - SmbiosTable->TableLength, - &TcgEvent, - (UINT8*)&HandoffTables - ); - } + Status = EFI_SUCCESS; if (PcdGet8 (PcdTpmPlatformClass) == TCG_PLATFORM_TYPE_SERVER) { // diff --git a/SecurityPkg/Tcg/TrEEDxe/TrEEDxe.inf b/SecurityPkg/Tcg/TrEEDxe/TrEEDxe.inf index e564c8f2a561..258ab46db94d 100644 --- a/SecurityPkg/Tcg/TrEEDxe/TrEEDxe.inf +++ b/SecurityPkg/Tcg/TrEEDxe/TrEEDxe.inf @@ -60,10 +60,6 @@ ReportStatusCodeLib [Guids] - ## SOMETIMES_CONSUMES ## SystemTable # Smbios Table - ## SOMETIMES_CONSUMES ## GUID # Handoff Table for measurement. - gEfiSmbiosTableGuid - ## SOMETIMES_CONSUMES ## Variable:L"SecureBoot" ## SOMETIMES_CONSUMES ## Variable:L"PK" ## SOMETIMES_CONSUMES ## Variable:L"KEK" From e78223628741b988c3a26baade6b684ac27492a7 Mon Sep 17 00:00:00 2001 From: "Yao, Jiewen" Date: Mon, 16 Nov 2015 08:07:58 +0000 Subject: [PATCH 094/525] Do not deadloop if Microcode not found in FspTempRamInit. We do not consider microcode not found as critical error, because Microcode might be applied later. (Sync patch r18678 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: "Yao, Jiewen" Reviewed-by: "Ma, Maurice" Reviewed-by: "Rangarajan, Ravi P" git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18809 6f19259b-4bc3-4df7-8a09-765794883524 --- .../SecPeiFspPlatformSecLibSample/Ia32/SecEntry.S | 10 ++++++++++ .../SecPeiFspPlatformSecLibSample/Ia32/SecEntry.asm | 12 +++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/IntelFspWrapperPkg/Library/SecPeiFspPlatformSecLibSample/Ia32/SecEntry.S b/IntelFspWrapperPkg/Library/SecPeiFspPlatformSecLibSample/Ia32/SecEntry.S index 24bc36b9c449..c0b84e075cac 100644 --- a/IntelFspWrapperPkg/Library/SecPeiFspPlatformSecLibSample/Ia32/SecEntry.S +++ b/IntelFspWrapperPkg/Library/SecPeiFspPlatformSecLibSample/Ia32/SecEntry.S @@ -210,12 +210,22 @@ FspHeaderFound: jmp *%eax TempRamInitDone: + cmp $0x8000000E, %eax #Check if EFI_NOT_FOUND returned. Error code for Microcode Update not found. + je CallSecFspInit #If microcode not found, don't hang, but continue. + cmp $0x0, %eax jnz FspApiFailed # ECX: start of range # EDX: end of range +CallSecFspInit: + xorl %eax, %eax movl %edx, %esp + + # Align the stack at DWORD + addl $3, %esp + andl $0xFFFFFFFC, %esp + pushl %edx pushl %ecx pushl %eax # zero - no hob list yet diff --git a/IntelFspWrapperPkg/Library/SecPeiFspPlatformSecLibSample/Ia32/SecEntry.asm b/IntelFspWrapperPkg/Library/SecPeiFspPlatformSecLibSample/Ia32/SecEntry.asm index 0e0c5c5883f7..3c2e43a89cde 100644 --- a/IntelFspWrapperPkg/Library/SecPeiFspPlatformSecLibSample/Ia32/SecEntry.asm +++ b/IntelFspWrapperPkg/Library/SecPeiFspPlatformSecLibSample/Ia32/SecEntry.asm @@ -220,12 +220,22 @@ FspHeaderFound: jmp eax TempRamInitDone: - cmp eax, 0 + cmp eax, 8000000Eh ;Check if EFI_NOT_FOUND returned. Error code for Microcode Update not found. + je CallSecFspInit ;If microcode not found, don't hang, but continue. + + cmp eax, 0 ;Check if EFI_SUCCESS retuned. jnz FspApiFailed ; ECX: start of range ; EDX: end of range +CallSecFspInit: + xor eax, eax mov esp, edx + + ; Align the stack at DWORD + add esp, 3 + and esp, 0FFFFFFFCh + push edx push ecx push eax ; zero - no hob list yet From 772941091a71af0e6b0bfbdd27b3bd958b82aa62 Mon Sep 17 00:00:00 2001 From: "Yao, Jiewen" Date: Mon, 16 Nov 2015 08:09:06 +0000 Subject: [PATCH 095/525] Fix issue that calling GetS3MemoryInfo() with wrong order. (Sync patch r18679 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: "Yao, Jiewen" Reviewed-by: "Ma, Maurice" Reviewed-by: "Rangarajan, Ravi P" git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18810 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Library/PeiFspHobProcessLibSample/FspHobProcessLibSample.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IntelFspWrapperPkg/Library/PeiFspHobProcessLibSample/FspHobProcessLibSample.c b/IntelFspWrapperPkg/Library/PeiFspHobProcessLibSample/FspHobProcessLibSample.c index 82af87fea7a7..099980e52556 100644 --- a/IntelFspWrapperPkg/Library/PeiFspHobProcessLibSample/FspHobProcessLibSample.c +++ b/IntelFspWrapperPkg/Library/PeiFspHobProcessLibSample/FspHobProcessLibSample.c @@ -246,7 +246,7 @@ FspHobProcessForMemoryResource ( S3PeiMemBase = 0; S3PeiMemSize = 0; - Status = GetS3MemoryInfo (&S3PeiMemBase, &S3PeiMemSize); + Status = GetS3MemoryInfo (&S3PeiMemSize, &S3PeiMemBase); ASSERT_EFI_ERROR (Status); DEBUG((DEBUG_INFO, "S3 memory %Xh - %Xh bytes\n", S3PeiMemBase, S3PeiMemSize)); From 4d38d07f9e8fe62d873fadc74d978a4db6a300b6 Mon Sep 17 00:00:00 2001 From: "Yao, Jiewen" Date: Mon, 16 Nov 2015 08:10:46 +0000 Subject: [PATCH 096/525] Move Smbios measurement from TCG driver to Smbios driver. This is patch to add smbios measurement. The problem of current SMBIOS measurement is: 1) TCG drivers do not support SMBIOS3.0 table. 2) TCG drivers do not follow TCG platform spec on: "Platform configuration information that is automatically updated, such as clock registers, and system unique information, such as asset numbers or serial numbers, MUST NOT be measured into PCR [1], or any other PCR." So we decide to move Smbios measurement from TCG drivers to Smbios driver. (Sync patch r18680 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: "Yao, Jiewen" Reviewed-by: "Zeng, Star" git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18811 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/MdeModulePkg.dsc | 1 + .../SmbiosMeasurementDxe.c | 617 ++++++++++++++++++ .../SmbiosMeasurementDxe.inf | 68 ++ .../SmbiosMeasurementDxe.uni | Bin 0 -> 1988 bytes .../SmbiosMeasurementDxeExtra.uni | Bin 0 -> 1358 bytes 5 files changed, 686 insertions(+) create mode 100644 MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.c create mode 100644 MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.inf create mode 100644 MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.uni create mode 100644 MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxeExtra.uni diff --git a/MdeModulePkg/MdeModulePkg.dsc b/MdeModulePkg/MdeModulePkg.dsc index 3e04477318b9..c43093260453 100644 --- a/MdeModulePkg/MdeModulePkg.dsc +++ b/MdeModulePkg/MdeModulePkg.dsc @@ -310,6 +310,7 @@ MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounterRuntimeDxe.inf MdeModulePkg/Universal/ResetSystemRuntimeDxe/ResetSystemRuntimeDxe.inf MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.inf + MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.inf MdeModulePkg/Universal/Network/ArpDxe/ArpDxe.inf MdeModulePkg/Universal/Network/Dhcp4Dxe/Dhcp4Dxe.inf diff --git a/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.c b/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.c new file mode 100644 index 000000000000..21528276c11b --- /dev/null +++ b/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.c @@ -0,0 +1,617 @@ +/** @file + This driver measures SMBIOS table to TPM. + +Copyright (c) 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define FIELD_SIZE_OF(TYPE, Field) ((UINTN)sizeof(((TYPE *)0)->Field)) + +typedef struct { + UINT8 Type; + UINTN Offset; + UINTN Size; + UINT32 Flags; +} SMBIOS_FILTER_TABLE; +#define SMBIOS_FILTER_TABLE_FLAG_IS_STRING BIT0 + +typedef struct { + UINT8 Type; + SMBIOS_FILTER_TABLE *Filter; // NULL means all fields + UINTN FilterCount; +} SMBIOS_FILTER_STRUCT; + +// +// Platform Specific Policy +// +SMBIOS_FILTER_TABLE mSmbiosFilterType1BlackList[] = { + {0x01, OFFSET_OF(SMBIOS_TABLE_TYPE1, SerialNumber), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE1, SerialNumber), SMBIOS_FILTER_TABLE_FLAG_IS_STRING}, + {0x01, OFFSET_OF(SMBIOS_TABLE_TYPE1, Uuid), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE1, Uuid), 0}, + {0x01, OFFSET_OF(SMBIOS_TABLE_TYPE1, WakeUpType), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE1, WakeUpType), 0}, +}; +SMBIOS_FILTER_TABLE mSmbiosFilterType2BlackList[] = { + {0x02, OFFSET_OF(SMBIOS_TABLE_TYPE2, SerialNumber), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE2, SerialNumber), SMBIOS_FILTER_TABLE_FLAG_IS_STRING}, + {0x02, OFFSET_OF(SMBIOS_TABLE_TYPE2, LocationInChassis), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE2, LocationInChassis), SMBIOS_FILTER_TABLE_FLAG_IS_STRING}, +}; +SMBIOS_FILTER_TABLE mSmbiosFilterType3BlackList[] = { + {0x03, OFFSET_OF(SMBIOS_TABLE_TYPE3, SerialNumber), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE3, SerialNumber), SMBIOS_FILTER_TABLE_FLAG_IS_STRING}, + {0x03, OFFSET_OF(SMBIOS_TABLE_TYPE3, AssetTag), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE3, AssetTag), SMBIOS_FILTER_TABLE_FLAG_IS_STRING}, +}; +SMBIOS_FILTER_TABLE mSmbiosFilterType4BlackList[] = { + {0x04, OFFSET_OF(SMBIOS_TABLE_TYPE4, SerialNumber), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE4, SerialNumber), SMBIOS_FILTER_TABLE_FLAG_IS_STRING}, + {0x04, OFFSET_OF(SMBIOS_TABLE_TYPE4, AssetTag), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE4, AssetTag), SMBIOS_FILTER_TABLE_FLAG_IS_STRING}, + {0x04, OFFSET_OF(SMBIOS_TABLE_TYPE4, PartNumber), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE4, PartNumber), SMBIOS_FILTER_TABLE_FLAG_IS_STRING}, + {0x04, OFFSET_OF(SMBIOS_TABLE_TYPE4, CoreCount), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE4, CoreCount), 0}, + {0x04, OFFSET_OF(SMBIOS_TABLE_TYPE4, EnabledCoreCount), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE4, EnabledCoreCount), 0}, + {0x04, OFFSET_OF(SMBIOS_TABLE_TYPE4, ThreadCount), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE4, ThreadCount), 0}, + {0x04, OFFSET_OF(SMBIOS_TABLE_TYPE4, CoreCount2), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE4, CoreCount2), 0}, + {0x04, OFFSET_OF(SMBIOS_TABLE_TYPE4, EnabledCoreCount2), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE4, EnabledCoreCount2), 0}, + {0x04, OFFSET_OF(SMBIOS_TABLE_TYPE4, ThreadCount2), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE4, ThreadCount2), 0}, +}; +SMBIOS_FILTER_TABLE mSmbiosFilterType17BlackList[] = { + {0x11, OFFSET_OF(SMBIOS_TABLE_TYPE17, SerialNumber), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE17, SerialNumber), SMBIOS_FILTER_TABLE_FLAG_IS_STRING}, + {0x11, OFFSET_OF(SMBIOS_TABLE_TYPE17, AssetTag), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE17, AssetTag), SMBIOS_FILTER_TABLE_FLAG_IS_STRING}, + {0x11, OFFSET_OF(SMBIOS_TABLE_TYPE17, PartNumber), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE17, PartNumber), SMBIOS_FILTER_TABLE_FLAG_IS_STRING}, +}; +SMBIOS_FILTER_TABLE mSmbiosFilterType22BlackList[] = { + {0x16, OFFSET_OF(SMBIOS_TABLE_TYPE22, SerialNumber), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE22, SerialNumber), SMBIOS_FILTER_TABLE_FLAG_IS_STRING}, + {0x16, OFFSET_OF(SMBIOS_TABLE_TYPE22, SBDSSerialNumber), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE22, SBDSSerialNumber), 0}, + {0x16, OFFSET_OF(SMBIOS_TABLE_TYPE22, SBDSManufactureDate), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE22, SBDSManufactureDate), 0}, +}; +SMBIOS_FILTER_TABLE mSmbiosFilterType23BlackList[] = { + {0x17, OFFSET_OF(SMBIOS_TABLE_TYPE23, ResetCount), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE23, ResetCount), 0}, +}; +SMBIOS_FILTER_TABLE mSmbiosFilterType39BlackList[] = { + {0x27, OFFSET_OF(SMBIOS_TABLE_TYPE39, SerialNumber), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE39, SerialNumber), SMBIOS_FILTER_TABLE_FLAG_IS_STRING}, + {0x27, OFFSET_OF(SMBIOS_TABLE_TYPE39, AssetTagNumber), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE39, AssetTagNumber), SMBIOS_FILTER_TABLE_FLAG_IS_STRING}, + {0x27, OFFSET_OF(SMBIOS_TABLE_TYPE39, ModelPartNumber), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE39, ModelPartNumber), SMBIOS_FILTER_TABLE_FLAG_IS_STRING}, +}; + +SMBIOS_FILTER_STRUCT mSmbiosFilterStandardTableBlackList[] = { + {0x01, mSmbiosFilterType1BlackList, sizeof(mSmbiosFilterType1BlackList)/sizeof(mSmbiosFilterType1BlackList[0])}, + {0x02, mSmbiosFilterType2BlackList, sizeof(mSmbiosFilterType2BlackList)/sizeof(mSmbiosFilterType2BlackList[0])}, + {0x03, mSmbiosFilterType3BlackList, sizeof(mSmbiosFilterType3BlackList)/sizeof(mSmbiosFilterType3BlackList[0])}, + {0x04, mSmbiosFilterType4BlackList, sizeof(mSmbiosFilterType4BlackList)/sizeof(mSmbiosFilterType4BlackList[0])}, + {0x0B, NULL, 0}, + {0x0F, NULL, 0}, + {0x11, mSmbiosFilterType17BlackList, sizeof(mSmbiosFilterType17BlackList)/sizeof(mSmbiosFilterType17BlackList[0])}, + {0x12, NULL, 0}, + {0x16, mSmbiosFilterType22BlackList, sizeof(mSmbiosFilterType22BlackList)/sizeof(mSmbiosFilterType22BlackList[0])}, + {0x17, mSmbiosFilterType23BlackList, sizeof(mSmbiosFilterType23BlackList)/sizeof(mSmbiosFilterType23BlackList[0])}, + {0x1F, NULL, 0}, + {0x21, NULL, 0}, + {0x27, mSmbiosFilterType39BlackList, sizeof(mSmbiosFilterType39BlackList)/sizeof(mSmbiosFilterType39BlackList[0])}, +}; + +EFI_SMBIOS_PROTOCOL *mSmbios; +UINTN mMaxLen; + +/** + + This function dump raw data. + + @param Data raw data + @param Size raw data size + +**/ +VOID +InternalDumpData ( + IN UINT8 *Data, + IN UINTN Size + ) +{ + UINTN Index; + for (Index = 0; Index < Size; Index++) { + DEBUG ((EFI_D_INFO, "%02x", (UINTN)Data[Index])); + } +} + +/** + + This function dump raw data with colume format. + + @param Data raw data + @param Size raw data size + +**/ +VOID +InternalDumpHex ( + IN UINT8 *Data, + IN UINTN Size + ) +{ + UINTN Index; + UINTN Count; + UINTN Left; + +#define COLUME_SIZE (16 * 2) + + Count = Size / COLUME_SIZE; + Left = Size % COLUME_SIZE; + for (Index = 0; Index < Count; Index++) { + DEBUG ((EFI_D_INFO, "%04x: ", Index * COLUME_SIZE)); + InternalDumpData (Data + Index * COLUME_SIZE, COLUME_SIZE); + DEBUG ((EFI_D_INFO, "\n")); + } + + if (Left != 0) { + DEBUG ((EFI_D_INFO, "%04x: ", Index * COLUME_SIZE)); + InternalDumpData (Data + Index * COLUME_SIZE, Left); + DEBUG ((EFI_D_INFO, "\n")); + } +} + + +/** + + This function get filter structure by SMBIOS type. + + @param Type SMBIOS type + +**/ +SMBIOS_FILTER_STRUCT * +GetFilterStructByType ( + IN UINT8 Type + ) +{ + UINTN Index; + for (Index = 0; Index < sizeof(mSmbiosFilterStandardTableBlackList)/sizeof(mSmbiosFilterStandardTableBlackList[0]); Index++) { + if (mSmbiosFilterStandardTableBlackList[Index].Type == Type) { + return &mSmbiosFilterStandardTableBlackList[Index]; + } + } + return NULL; +} + +/** + + This function get SMBIOS string in SMBIOS table. + + @param Head SMBIOS table head + @param StringId SMBIOS string ID + @param StringLen length of SMBIOS string + + @return SMBIOS string data +**/ +CHAR8 * +GetSmbiosStringById ( + IN EFI_SMBIOS_TABLE_HEADER *Head, + IN SMBIOS_TABLE_STRING StringId, + OUT UINTN *StringLen + ) +{ + UINTN Size; + UINTN StrLen; + CHAR8 *CharInStr; + UINTN StringsNumber; + CHAR8 *String; + + CharInStr = (CHAR8 *)Head + Head->Length; + Size = Head->Length; + StringsNumber = 0; + StrLen = 0; + // + // look for the two consecutive zeros, check the string limit by the way. + // + String = NULL; + while (*CharInStr != 0 || *(CharInStr+1) != 0) { + if (*CharInStr == 0) { + Size += 1; + CharInStr++; + } + String = CharInStr; + + for (StrLen = 0 ; StrLen < mMaxLen; StrLen++) { + if (*(CharInStr+StrLen) == 0) { + break; + } + } + *StringLen = StrLen; + + if (StrLen == mMaxLen) { + return NULL; + } + + // + // forward the pointer + // + CharInStr += StrLen; + Size += StrLen; + StringsNumber += 1; + if (StringsNumber == StringId) { + break; + } + } + + return String; +} + +/** + + This function update SMBIOS table based on policy. + + @param TableEntry SMBIOS table + @param TableEntrySize SMBIOS table size + +**/ +VOID +FilterSmbiosEntry ( + IN OUT VOID *TableEntry, + IN UINTN TableEntrySize + ) +{ + SMBIOS_FILTER_STRUCT *FilterStruct; + SMBIOS_FILTER_TABLE *Filter; + UINTN Index; + SMBIOS_TABLE_STRING StringId; + CHAR8 *String; + UINTN StringLen; + + DEBUG ((EFI_D_INFO, "Smbios Table (Type - %d):\n", ((SMBIOS_STRUCTURE *)TableEntry)->Type)); + InternalDumpHex (TableEntry, TableEntrySize); + + FilterStruct = GetFilterStructByType (((SMBIOS_STRUCTURE *)TableEntry)->Type); + if (FilterStruct != NULL) { + if (FilterStruct->Filter == NULL || FilterStruct->FilterCount == 0) { + // zero all table entries, except header + ZeroMem ((UINT8 *)TableEntry + sizeof(SMBIOS_STRUCTURE), TableEntrySize - sizeof(SMBIOS_STRUCTURE)); + } else { + Filter = FilterStruct->Filter; + for (Index = 0; Index < FilterStruct->FilterCount; Index++) { + if ((Filter[Index].Flags & SMBIOS_FILTER_TABLE_FLAG_IS_STRING) != 0) { + CopyMem (&StringId, (UINT8 *)TableEntry + Filter[Index].Offset, sizeof(StringId)); + if (StringId != 0) { + // set ' ' for string field + String = GetSmbiosStringById (TableEntry, StringId, &StringLen); + //DEBUG ((EFI_D_INFO,"StrId(0x%x)-%a(%d)\n", StringId, String, StringLen)); + SetMem (String, StringLen, ' '); + } + } + // zero non-string field + ZeroMem ((UINT8 *)TableEntry + Filter[Index].Offset, Filter[Index].Size); + } + } + } + + DEBUG ((EFI_D_INFO, "Filter Smbios Table (Type - %d):\n", ((SMBIOS_STRUCTURE *)TableEntry)->Type)); + InternalDumpHex (TableEntry, TableEntrySize); +} + +/** + + Get the full size of SMBIOS structure including optional strings that follow the formatted structure. + + @param Head Pointer to the beginning of SMBIOS structure. + @param NumberOfStrings The returned number of optional strings that follow the formatted structure. + + @return Size The returned size. +**/ +UINTN +GetSmbiosStructureSize ( + IN EFI_SMBIOS_TABLE_HEADER *Head, + OUT UINTN *NumberOfStrings + ) +{ + UINTN Size; + UINTN StrLen; + CHAR8 *CharInStr; + UINTN StringsNumber; + + CharInStr = (CHAR8 *)Head + Head->Length; + Size = Head->Length; + StringsNumber = 0; + StrLen = 0; + // + // look for the two consecutive zeros, check the string limit by the way. + // + while (*CharInStr != 0 || *(CharInStr+1) != 0) { + if (*CharInStr == 0) { + Size += 1; + CharInStr++; + } + + for (StrLen = 0 ; StrLen < mMaxLen; StrLen++) { + if (*(CharInStr+StrLen) == 0) { + break; + } + } + + if (StrLen == mMaxLen) { + return 0; + } + + // + // forward the pointer + // + CharInStr += StrLen; + Size += StrLen; + StringsNumber += 1; + } + + // + // count ending two zeros. + // + Size += 2; + + if (NumberOfStrings != NULL) { + *NumberOfStrings = StringsNumber; + } + return Size; +} + +/** + + This function returns full SMBIOS table length. + + @param TableAddress SMBIOS table based address + @param TableMaximumSize Maximum size of SMBIOS table + + @return SMBIOS table length + +**/ +UINTN +GetSmbiosTableLength ( + IN VOID *TableAddress, + IN UINTN TableMaximumSize + ) +{ + VOID *TableEntry; + VOID *TableAddressEnd; + UINTN TableEntryLength; + + TableAddressEnd = (VOID *)((UINTN)TableAddress + TableMaximumSize); + TableEntry = TableAddress; + while (TableEntry < TableAddressEnd) { + TableEntryLength = GetSmbiosStructureSize (TableEntry, NULL); + if (TableEntryLength == 0) { + break; + } + if (((SMBIOS_STRUCTURE *)TableEntry)->Type == 127) { + TableEntry = (VOID *)((UINTN)TableEntry + TableEntryLength); + break; + } + TableEntry = (VOID *)((UINTN)TableEntry + TableEntryLength); + } + + return ((UINTN)TableEntry - (UINTN)TableAddress); +} + +/** + + This function updatess full SMBIOS table length. + + @param TableAddress SMBIOS table based address + @param TableLength SMBIOS table length + +**/ +VOID +FilterSmbiosTable ( + IN OUT VOID *TableAddress, + IN UINTN TableLength + ) +{ + VOID *TableAddressEnd; + VOID *TableEntry; + UINTN TableEntryLength; + + TableEntry = TableAddress; + TableAddressEnd = (VOID *)((UINTN)TableAddress + TableLength); + while ((UINTN)TableEntry < (UINTN)TableAddressEnd) { + TableEntryLength = GetSmbiosStructureSize (TableEntry, NULL); + if (TableEntryLength == 0) { + break; + } + + FilterSmbiosEntry (TableEntry, TableEntryLength); + + TableEntry = (VOID *)((UINTN)TableEntry + TableEntryLength); + } +} + +/** + Measure SMBIOS with EV_EFI_HANDOFF_TABLES to PCR[1] +**/ +VOID +EFIAPI +MeasureSmbiosTable ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + EFI_HANDOFF_TABLE_POINTERS HandoffTables; + SMBIOS_TABLE_ENTRY_POINT *SmbiosTable; + SMBIOS_TABLE_3_0_ENTRY_POINT *Smbios3Table; + VOID *SmbiosTableAddress; + VOID *TableAddress; + UINTN TableLength; + + SmbiosTable = NULL; + Smbios3Table = NULL; + SmbiosTableAddress = NULL; + TableLength = 0; + + if (mSmbios->MajorVersion >= 3) { + Status = EfiGetSystemConfigurationTable ( + &gEfiSmbios3TableGuid, + (VOID **) &Smbios3Table + ); + if (!EFI_ERROR (Status)) { + DEBUG ((EFI_D_INFO, "Smbios3Table:\n")); + DEBUG ((EFI_D_INFO, " AnchorString - '%c%c%c%c%c'\n", + Smbios3Table->AnchorString[0], + Smbios3Table->AnchorString[1], + Smbios3Table->AnchorString[2], + Smbios3Table->AnchorString[3], + Smbios3Table->AnchorString[4] + )); + DEBUG ((EFI_D_INFO, " EntryPointStructureChecksum - 0x%02x\n", Smbios3Table->EntryPointStructureChecksum)); + DEBUG ((EFI_D_INFO, " EntryPointLength - 0x%02x\n", Smbios3Table->EntryPointLength)); + DEBUG ((EFI_D_INFO, " MajorVersion - 0x%02x\n", Smbios3Table->MajorVersion)); + DEBUG ((EFI_D_INFO, " MinorVersion - 0x%02x\n", Smbios3Table->MinorVersion)); + DEBUG ((EFI_D_INFO, " DocRev - 0x%02x\n", Smbios3Table->DocRev)); + DEBUG ((EFI_D_INFO, " EntryPointRevision - 0x%02x\n", Smbios3Table->EntryPointRevision)); + DEBUG ((EFI_D_INFO, " TableMaximumSize - 0x%08x\n", Smbios3Table->TableMaximumSize)); + DEBUG ((EFI_D_INFO, " TableAddress - 0x%016lx\n", Smbios3Table->TableAddress)); + } + } + Status = EfiGetSystemConfigurationTable ( + &gEfiSmbiosTableGuid, + (VOID **) &SmbiosTable + ); + if (!EFI_ERROR (Status)) { + DEBUG ((EFI_D_INFO, "SmbiosTable:\n")); + DEBUG ((EFI_D_INFO, " AnchorString - '%c%c%c%c'\n", + Smbios3Table->AnchorString[0], + Smbios3Table->AnchorString[1], + Smbios3Table->AnchorString[2], + Smbios3Table->AnchorString[3] + )); + DEBUG ((EFI_D_INFO, " EntryPointStructureChecksum - 0x%02x\n", SmbiosTable->EntryPointStructureChecksum)); + DEBUG ((EFI_D_INFO, " EntryPointLength - 0x%02x\n", SmbiosTable->EntryPointLength)); + DEBUG ((EFI_D_INFO, " MajorVersion - 0x%02x\n", SmbiosTable->MajorVersion)); + DEBUG ((EFI_D_INFO, " MinorVersion - 0x%02x\n", SmbiosTable->MinorVersion)); + DEBUG ((EFI_D_INFO, " MaxStructureSize - 0x%08x\n", SmbiosTable->MaxStructureSize)); + DEBUG ((EFI_D_INFO, " EntryPointRevision - 0x%02x\n", SmbiosTable->EntryPointRevision)); + DEBUG ((EFI_D_INFO, " FormattedArea - '%c%c%c%c%c'\n", + SmbiosTable->FormattedArea[0], + SmbiosTable->FormattedArea[1], + SmbiosTable->FormattedArea[2], + SmbiosTable->FormattedArea[3], + SmbiosTable->FormattedArea[4] + )); + DEBUG ((EFI_D_INFO, " IntermediateAnchorString - '%c%c%c%c%c'\n", + SmbiosTable->IntermediateAnchorString[0], + SmbiosTable->IntermediateAnchorString[1], + SmbiosTable->IntermediateAnchorString[2], + SmbiosTable->IntermediateAnchorString[3], + SmbiosTable->IntermediateAnchorString[4] + )); + DEBUG ((EFI_D_INFO, " IntermediateChecksum - 0x%02x\n", SmbiosTable->IntermediateChecksum)); + DEBUG ((EFI_D_INFO, " TableLength - 0x%04x\n", SmbiosTable->TableLength)); + DEBUG ((EFI_D_INFO, " TableAddress - 0x%08x\n", SmbiosTable->TableAddress)); + DEBUG ((EFI_D_INFO, " NumberOfSmbiosStructures - 0x%04x\n", SmbiosTable->NumberOfSmbiosStructures)); + DEBUG ((EFI_D_INFO, " SmbiosBcdRevision - 0x%02x\n", SmbiosTable->SmbiosBcdRevision)); + } + + if (Smbios3Table != NULL) { + SmbiosTableAddress = (VOID *)(UINTN)Smbios3Table->TableAddress; + TableLength = GetSmbiosTableLength (SmbiosTableAddress, Smbios3Table->TableMaximumSize); + } else if (SmbiosTable != NULL) { + SmbiosTableAddress = (VOID *)(UINTN)SmbiosTable->TableAddress; + TableLength = SmbiosTable->TableLength; + } + + if (SmbiosTableAddress != NULL) { + DEBUG ((DEBUG_INFO, "The Smbios Table starts at: 0x%x\n", SmbiosTableAddress)); + DEBUG ((DEBUG_INFO, "The Smbios Table size: 0x%x\n", TableLength)); + InternalDumpHex ((UINT8 *)(UINTN)SmbiosTableAddress, TableLength); + + TableAddress = AllocateCopyPool ((UINTN)TableLength, (VOID *)(UINTN)SmbiosTableAddress); + if (TableAddress == NULL) { + return ; + } + + FilterSmbiosTable (TableAddress, TableLength); + + DEBUG ((DEBUG_INFO, "The final Smbios Table starts at: 0x%x\n", TableAddress)); + DEBUG ((DEBUG_INFO, "The final Smbios Table size: 0x%x\n", TableLength)); + InternalDumpHex (TableAddress, TableLength); + + HandoffTables.NumberOfTables = 1; + HandoffTables.TableEntry[0].VendorGuid = gEfiSmbiosTableGuid; + HandoffTables.TableEntry[0].VendorTable = SmbiosTable; + Status = TpmMeasureAndLogData ( + 1, // PCRIndex + EV_EFI_HANDOFF_TABLES, // EventType + &HandoffTables, // EventLog + sizeof (HandoffTables), // LogLen + TableAddress, // HashData + TableLength // HashDataLen + ); + if (EFI_ERROR (Status)) { + return ; + } + } + + return ; +} + +/** + + Driver to produce Smbios measurement. + + @param ImageHandle Module's image handle + @param SystemTable Pointer of EFI_SYSTEM_TABLE + + @retval EFI_SUCCESS Smbios protocol installed + @retval Other No protocol installed, unload driver. + +**/ +EFI_STATUS +EFIAPI +SmbiosMeasurementDriverEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_EVENT Event; + + Status = gBS->LocateProtocol (&gEfiSmbiosProtocolGuid, NULL, &mSmbios); + ASSERT_EFI_ERROR (Status); + DEBUG ((DEBUG_INFO, "The Smbios Table Version: %x.%x\n", mSmbios->MajorVersion, mSmbios->MinorVersion)); + + if (mSmbios->MajorVersion < 2 || (mSmbios->MajorVersion == 2 && mSmbios->MinorVersion < 7)){ + mMaxLen = SMBIOS_STRING_MAX_LENGTH; + } else if (mSmbios->MajorVersion < 3) { + // + // Reference SMBIOS 2.7, chapter 6.1.3, it will have no limit on the length of each individual text string. + // However, the length of the entire structure table (including all strings) must be reported + // in the Structure Table Length field of the SMBIOS Structure Table Entry Point, + // which is a WORD field limited to 65,535 bytes. + // + mMaxLen = SMBIOS_TABLE_MAX_LENGTH; + } else { + // + // SMBIOS 3.0 defines the Structure table maximum size as DWORD field limited to 0xFFFFFFFF bytes. + // Locate the end of string as long as possible. + // + mMaxLen = SMBIOS_3_0_TABLE_MAX_LENGTH; + } + + // + // Measure Smbios tables + // + Status = EfiCreateEventReadyToBootEx ( + TPL_CALLBACK, + MeasureSmbiosTable, + NULL, + &Event + ); + + return Status; +} diff --git a/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.inf b/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.inf new file mode 100644 index 000000000000..6f894476e46d --- /dev/null +++ b/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.inf @@ -0,0 +1,68 @@ +## @file +# This driver measures SMBIOS table to TPM. +# +# This driver is a sample driver to follow TCG platform specification to +# filter some fields in SMBIOS table. +# - Platform configuration information that is automatically updated, +# such as clock registers, and system unique information, such as +# asset numbers or serial numbers, MUST NOT be measured into PCR [1], +# or any other PCR. +# +# A platform may use its own policy to filter some fields in SMBIOS table. +# +# Copyright (c) 2015, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = SmbiosMeasurementDxe + MODULE_UNI_FILE = SmbiosMeasurementDxe.uni + FILE_GUID = D27FED59-ABB4-4FED-BEAD-2A878C7E4A7E + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = SmbiosMeasurementDriverEntryPoint + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC ARM AARCH64 +# + +[Sources] + SmbiosMeasurementDxe.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + UefiBootServicesTableLib + MemoryAllocationLib + BaseMemoryLib + BaseLib + UefiLib + UefiDriverEntryPoint + DebugLib + TpmMeasurementLib + +[Protocols] + gEfiSmbiosProtocolGuid ## PRODUCES + +[Guids] + gEfiSmbiosTableGuid ## SOMETIMES_PRODUCES ## SystemTable + gEfiSmbios3TableGuid ## SOMETIMES_PRODUCES ## SystemTable + +[Depex] + gEfiSmbiosProtocolGuid + +[UserExtensions.TianoCore."ExtraFiles"] + SmbiosMeasurementDxeExtra.uni diff --git a/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.uni b/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.uni new file mode 100644 index 0000000000000000000000000000000000000000..98b0f52a6a3968b18b637d33b0f3cb2f24a18e55 GIT binary patch literal 1988 zcmds&U60aW5QXR3#Q#9p8#TM2Cf*oh1gYAnTLLAkR|d*wQa(~(b^pBjoGGP3Sl1Y@ z3~AqwnfJ^&GxL@o-|JSl3eO{c6?!J?=1WIv<5AmV-yI_XBejGWDYMO;aR$z41k(x;7rcj@8M7;d z4eJ&ADJl}XVb#Y+zImL~Rm3Ki6?_&RG4t~YIE9Ww<=UOPbqo4%$5W`c<>OQaUc+kz zCuMj7p13}M*F(mq_Sl}-GdpJob8F{R z;_I}kr=4pa^<~*nTTaNTPAr(HKQf|9Yr#^? z@9JKZT-7-nD)HQJuX-xiBmd0R)li>N&-zjB*X#^nKD3J?OAVAMPZ=e)cNV~=P4`6h zmUqMNOz1biMVEHb+F@*3k6GaP?b#(`z`in(Bb2!h>E{5Ct|Ldx)W>>P8M}-^tui)! zt=0K2oUX77HS&lRyTYsE%r4mvK@~>i(L1cfU3-cd<0~IU&Ar~>tLUE@-(wMT-M?TL zC07yHr#()I9+HbT-K3bUlixdiZR^fmIn{Hv@0kU)(YHhS`vOt~Mh~=rRRit0r9rl0 z{BHZ5`E3!_mY$t>*QgUNz!K9cr^}B0H{bQ@UeTYaQ7?4Sp+0Hv^M6Xw->dmw|3S)J F{{*hWIG+Fj literal 0 HcmV?d00001 diff --git a/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxeExtra.uni b/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxeExtra.uni new file mode 100644 index 0000000000000000000000000000000000000000..4e081c44b8ab12ffaa6b76a2b7976925d8720162 GIT binary patch literal 1358 zcmZvcTW`}q5QXO%iT|)lUjVfUAn}3_q9Fz%nu~H#%TwhfG_{mV<%H7k)JNf;U;DOVL7KI&&sye zvIkDVF7TOhzrgz!mYGLy@y+m?6BoE$x&0%)ij4?mwsH@q`#alt?A&hg4E7B4=j^ZT zrMch5i8}(I4wY{@KdacmUdH4D`zGJOMFGo ziVXLh)u)uss9S-KNLOJ8azrLE*V0*+C}JkhY_E@$Skw0^u1U{Zyk9)xQgQw1T1;90 ztu}*$5XB+trCb}{RrLg(hkcQ%Vt<1@c1WBb@Hyu6SeK~f4zEcOzb+IIqwRsNnw%}2 zcSOS|q)6=uhtmph!G@V1% zmhU61ZRTriBYdUr*t+Zq_JA!SRNA+h=LCu<)f_8>l41p{*C=BH)5{;Us7a=RU~$`$EncU zXwheyl(WVEvDB^HgMWP*ZkO$3KQH=f=nEw6t_yYhpbYjET!Y;Mbqs!jPZyRQPQlSm u=$s~hPPbE5&6@guhQIhJTa8l(4OOjd|Nq9Ri&u`@@=4YgBPUh} Date: Mon, 16 Nov 2015 08:11:47 +0000 Subject: [PATCH 097/525] MdeModulePkg SetupBrowserDxe: Save global variable values before nest function called. The SendForm function can be called nest in it. This function also uses some global variables. So we must save global variable values before it been called again. Checked in the missing change for gBrowserFormSetList. (Sync patch r18681 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Eric Dong Reviewed-by: Liming Gao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18812 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Universal/SetupBrowserDxe/Setup.c | 29 +++++++++++++++++-- .../Universal/SetupBrowserDxe/Setup.h | 3 +- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c b/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c index 4a6758a5e489..cc9896959b6a 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c @@ -5541,8 +5541,9 @@ SaveBrowserContext ( VOID ) { - BROWSER_CONTEXT *Context; - FORM_ENTRY_INFO *MenuList; + BROWSER_CONTEXT *Context; + FORM_ENTRY_INFO *MenuList; + FORM_BROWSER_FORMSET *FormSet; gBrowserContextCount++; if (gBrowserContextCount == 1) { @@ -5584,6 +5585,17 @@ SaveBrowserContext ( InsertTailList(&Context->FormHistoryList, &MenuList->Link); } + // + // Save formset list. + // + InitializeListHead(&Context->FormSetList); + while (!IsListEmpty (&gBrowserFormSetList)) { + FormSet = FORM_BROWSER_FORMSET_FROM_LINK (gBrowserFormSetList.ForwardLink); + RemoveEntryList (&FormSet->Link); + + InsertTailList(&Context->FormSetList, &FormSet->Link); + } + // // Insert to FormBrowser context list // @@ -5602,7 +5614,8 @@ RestoreBrowserContext ( { LIST_ENTRY *Link; BROWSER_CONTEXT *Context; - FORM_ENTRY_INFO *MenuList; + FORM_ENTRY_INFO *MenuList; + FORM_BROWSER_FORMSET *FormSet; ASSERT (gBrowserContextCount != 0); gBrowserContextCount--; @@ -5644,6 +5657,16 @@ RestoreBrowserContext ( InsertTailList(&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &MenuList->Link); } + // + // Restore the Formset data. + // + while (!IsListEmpty (&Context->FormSetList)) { + FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Context->FormSetList.ForwardLink); + RemoveEntryList (&FormSet->Link); + + InsertTailList(&gBrowserFormSetList, &FormSet->Link); + } + // // Remove from FormBrowser context list // diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Setup.h b/MdeModulePkg/Universal/SetupBrowserDxe/Setup.h index 81e2a62df198..0abb09cf87b5 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/Setup.h +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Setup.h @@ -542,7 +542,8 @@ typedef struct { EFI_QUESTION_ID CurFakeQestId; BOOLEAN HiiPackageListUpdated; BOOLEAN FinishRetrieveCall; - LIST_ENTRY FormHistoryList; + LIST_ENTRY FormHistoryList; + LIST_ENTRY FormSetList; } BROWSER_CONTEXT; #define BROWSER_CONTEXT_FROM_LINK(a) CR (a, BROWSER_CONTEXT, Link, BROWSER_CONTEXT_SIGNATURE) From e42c0d6cf83cf42c2a1a209162e48a8ab33999de Mon Sep 17 00:00:00 2001 From: "Yao, Jiewen" Date: Mon, 16 Nov 2015 08:12:48 +0000 Subject: [PATCH 098/525] Publish FspHob to PEI Hob by default. because most platforms use such logic. PcdDataBaseHobGuid GuidHob is excluded because PCD database in FSP is different with the one in PEI. (Sync patch r18687 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: "Yao, Jiewen" Reviewed-by: "Ma, Maurice" Reviewed-by: "Rangarajan, Ravi P" git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18813 6f19259b-4bc3-4df7-8a09-765794883524 --- .../FspHobProcessLibSample.c | 38 +++++++++++++++++++ .../PeiFspHobProcessLibSample.inf | 1 + 2 files changed, 39 insertions(+) diff --git a/IntelFspWrapperPkg/Library/PeiFspHobProcessLibSample/FspHobProcessLibSample.c b/IntelFspWrapperPkg/Library/PeiFspHobProcessLibSample/FspHobProcessLibSample.c index 099980e52556..a96c151df4cd 100644 --- a/IntelFspWrapperPkg/Library/PeiFspHobProcessLibSample/FspHobProcessLibSample.c +++ b/IntelFspWrapperPkg/Library/PeiFspHobProcessLibSample/FspHobProcessLibSample.c @@ -25,6 +25,7 @@ #include #include +#include #include // @@ -334,6 +335,41 @@ FspHobProcessForMemoryResource ( return EFI_SUCCESS; } +/** + Process FSP HOB list + + @param[in] FspHobList Pointer to the HOB data structure produced by FSP. + +**/ +VOID +ProcessFspHobList ( + IN VOID *FspHobList + ) +{ + EFI_PEI_HOB_POINTERS FspHob; + + FspHob.Raw = FspHobList; + + // + // Add all the HOBs from FSP binary to FSP wrapper + // + while (!END_OF_HOB_LIST (FspHob)) { + if (FspHob.Header->HobType == EFI_HOB_TYPE_GUID_EXTENSION) { + // + // Skip FSP binary creates PcdDataBaseHobGuid + // + if (!CompareGuid(&FspHob.Guid->Name, &gPcdDataBaseHobGuid)) { + BuildGuidDataHob ( + &FspHob.Guid->Name, + GET_GUID_HOB_DATA(FspHob), + GET_GUID_HOB_DATA_SIZE(FspHob) + ); + } + } + FspHob.Raw = GET_NEXT_HOB (FspHob); + } +} + /** BIOS process FspBobList for other data (not Memory Resource Descriptor). @@ -347,6 +383,8 @@ FspHobProcessForOtherData ( IN VOID *FspHobList ) { + ProcessFspHobList (FspHobList); + return EFI_SUCCESS; } diff --git a/IntelFspWrapperPkg/Library/PeiFspHobProcessLibSample/PeiFspHobProcessLibSample.inf b/IntelFspWrapperPkg/Library/PeiFspHobProcessLibSample/PeiFspHobProcessLibSample.inf index 12f922c0d965..c7f35f7bdfe8 100644 --- a/IntelFspWrapperPkg/Library/PeiFspHobProcessLibSample/PeiFspHobProcessLibSample.inf +++ b/IntelFspWrapperPkg/Library/PeiFspHobProcessLibSample/PeiFspHobProcessLibSample.inf @@ -70,6 +70,7 @@ [Guids] gFspReservedMemoryResourceHobGuid ## CONSUMES ## HOB gEfiMemoryTypeInformationGuid ## CONSUMES ## GUID + gPcdDataBaseHobGuid ## CONSUMES ## HOB [Ppis] gEfiPeiCapsulePpiGuid ## CONSUMES From 1d5c1ea1c495cb9a2faa64bca18a898902cb167f Mon Sep 17 00:00:00 2001 From: Star Zeng Date: Mon, 16 Nov 2015 08:13:36 +0000 Subject: [PATCH 099/525] MdeModulePkg SmbiosMeasurementDxe: Use SMBIOS table and GUID correctly 1. Smbios3Table used as SmbiosTable wrongly after SmbiosTable got from configuration table. 2. Use correct VendorGuid and VendorTable to measure. (Sync patch r18691 from main trunk.) Cc: Jiewen Yao Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Star Zeng Reviewed-by: Jiewen Yao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18814 6f19259b-4bc3-4df7-8a09-765794883524 --- .../SmbiosMeasurementDxe.c | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.c b/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.c index 21528276c11b..85963818dcdf 100644 --- a/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.c +++ b/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.c @@ -478,6 +478,8 @@ MeasureSmbiosTable ( DEBUG ((EFI_D_INFO, " TableAddress - 0x%016lx\n", Smbios3Table->TableAddress)); } } + + if (Smbios3Table == NULL) { Status = EfiGetSystemConfigurationTable ( &gEfiSmbiosTableGuid, (VOID **) &SmbiosTable @@ -485,10 +487,10 @@ MeasureSmbiosTable ( if (!EFI_ERROR (Status)) { DEBUG ((EFI_D_INFO, "SmbiosTable:\n")); DEBUG ((EFI_D_INFO, " AnchorString - '%c%c%c%c'\n", - Smbios3Table->AnchorString[0], - Smbios3Table->AnchorString[1], - Smbios3Table->AnchorString[2], - Smbios3Table->AnchorString[3] + SmbiosTable->AnchorString[0], + SmbiosTable->AnchorString[1], + SmbiosTable->AnchorString[2], + SmbiosTable->AnchorString[3] )); DEBUG ((EFI_D_INFO, " EntryPointStructureChecksum - 0x%02x\n", SmbiosTable->EntryPointStructureChecksum)); DEBUG ((EFI_D_INFO, " EntryPointLength - 0x%02x\n", SmbiosTable->EntryPointLength)); @@ -516,6 +518,7 @@ MeasureSmbiosTable ( DEBUG ((EFI_D_INFO, " NumberOfSmbiosStructures - 0x%04x\n", SmbiosTable->NumberOfSmbiosStructures)); DEBUG ((EFI_D_INFO, " SmbiosBcdRevision - 0x%02x\n", SmbiosTable->SmbiosBcdRevision)); } + } if (Smbios3Table != NULL) { SmbiosTableAddress = (VOID *)(UINTN)Smbios3Table->TableAddress; @@ -542,8 +545,13 @@ MeasureSmbiosTable ( InternalDumpHex (TableAddress, TableLength); HandoffTables.NumberOfTables = 1; - HandoffTables.TableEntry[0].VendorGuid = gEfiSmbiosTableGuid; - HandoffTables.TableEntry[0].VendorTable = SmbiosTable; + if (Smbios3Table != NULL) { + CopyGuid (&(HandoffTables.TableEntry[0].VendorGuid), &gEfiSmbios3TableGuid); + HandoffTables.TableEntry[0].VendorTable = Smbios3Table; + } else { + CopyGuid (&(HandoffTables.TableEntry[0].VendorGuid), &gEfiSmbiosTableGuid); + HandoffTables.TableEntry[0].VendorTable = SmbiosTable; + } Status = TpmMeasureAndLogData ( 1, // PCRIndex EV_EFI_HANDOFF_TABLES, // EventType From fe76c80e960833a476394f3a75830c9543b7b0f5 Mon Sep 17 00:00:00 2001 From: Star Zeng Date: Mon, 16 Nov 2015 08:14:30 +0000 Subject: [PATCH 100/525] MdeModulePkg SmbiosMeasurementDxe: Add (VOID **) typecast for GCC build failure (Sync patch r18692 from main trunk.) Cc: Jiewen Yao Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Star Zeng Reviewed-by: Jiewen Yao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18815 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.c b/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.c index 85963818dcdf..e82b028116b4 100644 --- a/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.c +++ b/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.c @@ -589,7 +589,7 @@ SmbiosMeasurementDriverEntryPoint ( EFI_STATUS Status; EFI_EVENT Event; - Status = gBS->LocateProtocol (&gEfiSmbiosProtocolGuid, NULL, &mSmbios); + Status = gBS->LocateProtocol (&gEfiSmbiosProtocolGuid, NULL, (VOID **) &mSmbios); ASSERT_EFI_ERROR (Status); DEBUG ((DEBUG_INFO, "The Smbios Table Version: %x.%x\n", mSmbios->MajorVersion, mSmbios->MinorVersion)); From 94780ec73fb2c6aad387c79e1b84ba5cbc303555 Mon Sep 17 00:00:00 2001 From: Star Zeng Date: Mon, 16 Nov 2015 08:15:24 +0000 Subject: [PATCH 101/525] MdeModulePkg SmbiosMeasurementDxe: Use EFI_D_VERBOSE for internal dump functions Use EFI_D_VERBOSE instead of EFI_D_INFO in InternalDumpData() and InternalDumpHex(). And also add DEBUG_CODE wrapper to InternalDumpHex() call. It is to avoid the bother from the internal verbose debug information. (Sync patch r18693 from main trunk.) Cc: Jiewen Yao Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Star Zeng Reviewed-by: Jiewen Yao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18816 6f19259b-4bc3-4df7-8a09-765794883524 --- .../SmbiosMeasurementDxe.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.c b/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.c index e82b028116b4..95a3aebefd74 100644 --- a/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.c +++ b/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.c @@ -125,7 +125,7 @@ InternalDumpData ( { UINTN Index; for (Index = 0; Index < Size; Index++) { - DEBUG ((EFI_D_INFO, "%02x", (UINTN)Data[Index])); + DEBUG ((EFI_D_VERBOSE, "%02x", (UINTN)Data[Index])); } } @@ -152,15 +152,15 @@ InternalDumpHex ( Count = Size / COLUME_SIZE; Left = Size % COLUME_SIZE; for (Index = 0; Index < Count; Index++) { - DEBUG ((EFI_D_INFO, "%04x: ", Index * COLUME_SIZE)); + DEBUG ((EFI_D_VERBOSE, "%04x: ", Index * COLUME_SIZE)); InternalDumpData (Data + Index * COLUME_SIZE, COLUME_SIZE); - DEBUG ((EFI_D_INFO, "\n")); + DEBUG ((EFI_D_VERBOSE, "\n")); } if (Left != 0) { - DEBUG ((EFI_D_INFO, "%04x: ", Index * COLUME_SIZE)); + DEBUG ((EFI_D_VERBOSE, "%04x: ", Index * COLUME_SIZE)); InternalDumpData (Data + Index * COLUME_SIZE, Left); - DEBUG ((EFI_D_INFO, "\n")); + DEBUG ((EFI_D_VERBOSE, "\n")); } } @@ -271,7 +271,7 @@ FilterSmbiosEntry ( UINTN StringLen; DEBUG ((EFI_D_INFO, "Smbios Table (Type - %d):\n", ((SMBIOS_STRUCTURE *)TableEntry)->Type)); - InternalDumpHex (TableEntry, TableEntrySize); + DEBUG_CODE (InternalDumpHex (TableEntry, TableEntrySize);); FilterStruct = GetFilterStructByType (((SMBIOS_STRUCTURE *)TableEntry)->Type); if (FilterStruct != NULL) { @@ -297,7 +297,7 @@ FilterSmbiosEntry ( } DEBUG ((EFI_D_INFO, "Filter Smbios Table (Type - %d):\n", ((SMBIOS_STRUCTURE *)TableEntry)->Type)); - InternalDumpHex (TableEntry, TableEntrySize); + DEBUG_CODE (InternalDumpHex (TableEntry, TableEntrySize);); } /** @@ -531,7 +531,7 @@ MeasureSmbiosTable ( if (SmbiosTableAddress != NULL) { DEBUG ((DEBUG_INFO, "The Smbios Table starts at: 0x%x\n", SmbiosTableAddress)); DEBUG ((DEBUG_INFO, "The Smbios Table size: 0x%x\n", TableLength)); - InternalDumpHex ((UINT8 *)(UINTN)SmbiosTableAddress, TableLength); + DEBUG_CODE (InternalDumpHex ((UINT8 *)(UINTN)SmbiosTableAddress, TableLength);); TableAddress = AllocateCopyPool ((UINTN)TableLength, (VOID *)(UINTN)SmbiosTableAddress); if (TableAddress == NULL) { @@ -542,7 +542,7 @@ MeasureSmbiosTable ( DEBUG ((DEBUG_INFO, "The final Smbios Table starts at: 0x%x\n", TableAddress)); DEBUG ((DEBUG_INFO, "The final Smbios Table size: 0x%x\n", TableLength)); - InternalDumpHex (TableAddress, TableLength); + DEBUG_CODE (InternalDumpHex (TableAddress, TableLength);); HandoffTables.NumberOfTables = 1; if (Smbios3Table != NULL) { From e9d4d6455347484ccf16ee772ee0cea29f0ed2ea Mon Sep 17 00:00:00 2001 From: Star Zeng Date: Mon, 16 Nov 2015 08:16:22 +0000 Subject: [PATCH 102/525] MdeModulePkg SmbiosMeasurementDxe: Remove the tailing whitespace (Sync patch r18694 from main trunk.) Cc: Jiewen Yao Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Star Zeng Reviewed-by: Jiewen Yao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18817 6f19259b-4bc3-4df7-8a09-765794883524 --- .../SmbiosMeasurementDxe.c | 26 +++++++++---------- .../SmbiosMeasurementDxe.inf | 2 +- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.c b/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.c index 95a3aebefd74..9a73f299b1f6 100644 --- a/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.c +++ b/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.c @@ -1,14 +1,14 @@ /** @file This driver measures SMBIOS table to TPM. - + Copyright (c) 2015, Intel Corporation. All rights reserved.
-This program and the accompanying materials -are licensed and made available under the terms and conditions of the BSD License -which accompanies this distribution. The full text of the license may be found at -http://opensource.org/licenses/bsd-license.php - -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ @@ -217,7 +217,7 @@ GetSmbiosStringById ( // look for the two consecutive zeros, check the string limit by the way. // String = NULL; - while (*CharInStr != 0 || *(CharInStr+1) != 0) { + while (*CharInStr != 0 || *(CharInStr+1) != 0) { if (*CharInStr == 0) { Size += 1; CharInStr++; @@ -306,7 +306,7 @@ FilterSmbiosEntry ( @param Head Pointer to the beginning of SMBIOS structure. @param NumberOfStrings The returned number of optional strings that follow the formatted structure. - + @return Size The returned size. **/ UINTN @@ -327,7 +327,7 @@ GetSmbiosStructureSize ( // // look for the two consecutive zeros, check the string limit by the way. // - while (*CharInStr != 0 || *(CharInStr+1) != 0) { + while (*CharInStr != 0 || *(CharInStr+1) != 0) { if (*CharInStr == 0) { Size += 1; CharInStr++; @@ -570,7 +570,7 @@ MeasureSmbiosTable ( /** - Driver to produce Smbios measurement. + Driver to produce Smbios measurement. @param ImageHandle Module's image handle @param SystemTable Pointer of EFI_SYSTEM_TABLE @@ -592,7 +592,7 @@ SmbiosMeasurementDriverEntryPoint ( Status = gBS->LocateProtocol (&gEfiSmbiosProtocolGuid, NULL, (VOID **) &mSmbios); ASSERT_EFI_ERROR (Status); DEBUG ((DEBUG_INFO, "The Smbios Table Version: %x.%x\n", mSmbios->MajorVersion, mSmbios->MinorVersion)); - + if (mSmbios->MajorVersion < 2 || (mSmbios->MajorVersion == 2 && mSmbios->MinorVersion < 7)){ mMaxLen = SMBIOS_STRING_MAX_LENGTH; } else if (mSmbios->MajorVersion < 3) { diff --git a/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.inf b/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.inf index 6f894476e46d..3193a6df6ea4 100644 --- a/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.inf +++ b/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.inf @@ -56,7 +56,7 @@ [Protocols] gEfiSmbiosProtocolGuid ## PRODUCES - + [Guids] gEfiSmbiosTableGuid ## SOMETIMES_PRODUCES ## SystemTable gEfiSmbios3TableGuid ## SOMETIMES_PRODUCES ## SystemTable From 62f3bd24e0e16203b568a7a637633e8cf6c1d40e Mon Sep 17 00:00:00 2001 From: Star Zeng Date: Mon, 16 Nov 2015 08:17:16 +0000 Subject: [PATCH 103/525] MdeModulePkg SmbiosMeasurementDxe: Correct the comments 1. Correct the return comments of entrypoint function. 2. Add parameters' comments for MeasureSmbiosTable(). 3. Correct the Protocols and Guids usage comments in SmbiosMeasurementDxe.inf. (Sync patch r18695 from main trunk.) Cc: Jiewen Yao Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Star Zeng Reviewed-by: Jiewen Yao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18818 6f19259b-4bc3-4df7-8a09-765794883524 --- .../SmbiosMeasurementDxe/SmbiosMeasurementDxe.c | 9 ++++++--- .../SmbiosMeasurementDxe/SmbiosMeasurementDxe.inf | 6 +++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.c b/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.c index 9a73f299b1f6..5aafabfcedaf 100644 --- a/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.c +++ b/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.c @@ -432,7 +432,11 @@ FilterSmbiosTable ( } /** - Measure SMBIOS with EV_EFI_HANDOFF_TABLES to PCR[1] + Measure SMBIOS with EV_EFI_HANDOFF_TABLES to PCR[1]. + + @param[in] Event Event whose notification function is being invoked. + @param[in] Context Pointer to the notification function's context. + **/ VOID EFIAPI @@ -575,8 +579,7 @@ MeasureSmbiosTable ( @param ImageHandle Module's image handle @param SystemTable Pointer of EFI_SYSTEM_TABLE - @retval EFI_SUCCESS Smbios protocol installed - @retval Other No protocol installed, unload driver. + @return Status returned from EfiCreateEventReadyToBootEx(). **/ EFI_STATUS diff --git a/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.inf b/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.inf index 3193a6df6ea4..c5a779cca7fe 100644 --- a/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.inf +++ b/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.inf @@ -55,11 +55,11 @@ TpmMeasurementLib [Protocols] - gEfiSmbiosProtocolGuid ## PRODUCES + gEfiSmbiosProtocolGuid ## CONSUMES [Guids] - gEfiSmbiosTableGuid ## SOMETIMES_PRODUCES ## SystemTable - gEfiSmbios3TableGuid ## SOMETIMES_PRODUCES ## SystemTable + gEfiSmbiosTableGuid ## SOMETIMES_CONSUMES ## SystemTable + gEfiSmbios3TableGuid ## SOMETIMES_CONSUMES ## SystemTable [Depex] gEfiSmbiosProtocolGuid From 69015f48a9651c3c9b44c3e8e3baab7d98db5333 Mon Sep 17 00:00:00 2001 From: Nagaraj Hegde Date: Mon, 16 Nov 2015 08:18:01 +0000 Subject: [PATCH 104/525] NetworkPkg: HttpDxe sometimes free a pointer twice In EfiHttpRequest, HostName was getting freed twice whenever HttpTransmitTcp4 failed. Moved FreePool (HostName) after HttpTransmitTcp4 call to avoid a double free. (Sync patch r18709 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Nagaraj Hegde Reviewed-by: Samer El-Haj-Mahmoud Reviewed-by: Ye Ting git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18819 6f19259b-4bc3-4df7-8a09-765794883524 --- NetworkPkg/HttpDxe/HttpImpl.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/NetworkPkg/HttpDxe/HttpImpl.c b/NetworkPkg/HttpDxe/HttpImpl.c index 50c061743665..09ee379150a9 100644 --- a/NetworkPkg/HttpDxe/HttpImpl.c +++ b/NetworkPkg/HttpDxe/HttpImpl.c @@ -486,10 +486,6 @@ EfiHttpRequest ( goto Error4; } - if (HostName != NULL) { - FreePool (HostName); - } - // // Transmit the request message. // @@ -505,6 +501,10 @@ EfiHttpRequest ( DispatchDpc (); + if (HostName != NULL) { + FreePool (HostName); + } + return EFI_SUCCESS; Error5: From e95c0ce475df9d9e2a6f9e9e53a72b88f3801ed5 Mon Sep 17 00:00:00 2001 From: Star Zeng Date: Mon, 16 Nov 2015 08:18:40 +0000 Subject: [PATCH 105/525] MdeModulePkg SmbiosMeasurementDxe: NULL check to String from GetSmbiosStringById When StringId is not 0, String returned from GetSmbiosStringById is expected to non-NULL. Add ASSERT (String != NULL); to ensure this. (Sync patch r18713 from main trunk.) Cc: Jiewen Yao Cc: Shumin Qiu Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Star Zeng Reviewed-by: Jiewen Yao Reviewed-by: Shumin Qiu git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18820 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.c | 1 + 1 file changed, 1 insertion(+) diff --git a/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.c b/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.c index 5aafabfcedaf..f9e0196677a9 100644 --- a/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.c +++ b/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.c @@ -286,6 +286,7 @@ FilterSmbiosEntry ( if (StringId != 0) { // set ' ' for string field String = GetSmbiosStringById (TableEntry, StringId, &StringLen); + ASSERT (String != NULL); //DEBUG ((EFI_D_INFO,"StrId(0x%x)-%a(%d)\n", StringId, String, StringLen)); SetMem (String, StringLen, ' '); } From 595df205dd889bf0a6bc3e92b50aa60d5e83f0c2 Mon Sep 17 00:00:00 2001 From: Ruiyu Ni Date: Mon, 16 Nov 2015 08:19:27 +0000 Subject: [PATCH 106/525] MdeModulePkg: Fix a PCI resource dumping bug in PciBusDxe driver The resource dumping logic contains a bug which cannot dump the resource for hot plug controller correctly. The patch fixes this bug. (Sync patch r18718 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ruiyu Ni Reviewed-by: Feng Tian git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18821 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Bus/Pci/PciBusDxe/PciEnumeratorSupport.c | 80 ++++++++- .../Bus/Pci/PciBusDxe/PciEnumeratorSupport.h | 15 +- MdeModulePkg/Bus/Pci/PciBusDxe/PciLib.c | 156 +++++++++--------- 3 files changed, 171 insertions(+), 80 deletions(-) diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c b/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c index f46025e2f61c..b070eb1b5f4b 100644 --- a/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c +++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c @@ -315,6 +315,81 @@ PciSearchDevice ( return EFI_SUCCESS; } +/** + Dump the PPB padding resource information. + + @param PciIoDevice PCI IO instance. + @param ResourceType The desired resource type to dump. + PciBarTypeUnknown means to dump all types of resources. +**/ +VOID +DumpPpbPaddingResource ( + IN PCI_IO_DEVICE *PciIoDevice, + IN PCI_BAR_TYPE ResourceType + ) +{ + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor; + PCI_BAR_TYPE Type; + + if (PciIoDevice->ResourcePaddingDescriptors == NULL) { + return; + } + + if (ResourceType == PciBarTypeIo16 || ResourceType == PciBarTypeIo32) { + ResourceType = PciBarTypeIo; + } + + for (Descriptor = PciIoDevice->ResourcePaddingDescriptors; Descriptor->Desc != ACPI_END_TAG_DESCRIPTOR; Descriptor++) { + + Type = PciBarTypeUnknown; + if (Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR && Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_IO) { + Type = PciBarTypeIo; + } else if (Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR && Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) { + + if (Descriptor->AddrSpaceGranularity == 32) { + // + // prefechable + // + if (Descriptor->SpecificFlag == EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE) { + Type = PciBarTypePMem32; + } + + // + // Non-prefechable + // + if (Descriptor->SpecificFlag == 0) { + Type = PciBarTypeMem32; + } + } + + if (Descriptor->AddrSpaceGranularity == 64) { + // + // prefechable + // + if (Descriptor->SpecificFlag == EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE) { + Type = PciBarTypePMem64; + } + + // + // Non-prefechable + // + if (Descriptor->SpecificFlag == 0) { + Type = PciBarTypeMem64; + } + } + } + + if ((Type != PciBarTypeUnknown) && ((ResourceType == PciBarTypeUnknown) || (ResourceType == Type))) { + DEBUG (( + EFI_D_INFO, + " Padding: Type = %s; Alignment = 0x%lx;\tLength = 0x%lx\n", + mBarTypeStr[Type], Descriptor->AddrRangeMax, Descriptor->AddrLen + )); + } + } + +} + /** Dump the PCI BAR information. @@ -577,7 +652,10 @@ GatherPpbInfo ( GetResourcePaddingPpb (PciIoDevice); - DEBUG_CODE (DumpPciBars (PciIoDevice);); + DEBUG_CODE ( + DumpPpbPaddingResource (PciIoDevice, PciBarTypeUnknown); + DumpPciBars (PciIoDevice); + ); return PciIoDevice; } diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.h b/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.h index a4489b895fc4..42306e9a47d9 100644 --- a/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.h +++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.h @@ -1,7 +1,7 @@ /** @file PCI emumeration support functions declaration for PCI Bus module. -Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
+Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -460,4 +460,17 @@ ResetAllPpbBusNumber ( IN UINT8 StartBusNumber ); +/** + Dump the PPB padding resource information. + + @param PciIoDevice PCI IO instance. + @param ResourceType The desired resource type to dump. + PciBarTypeUnknown means to dump all types of resources. +**/ +VOID +DumpPpbPaddingResource ( + IN PCI_IO_DEVICE *PciIoDevice, + IN PCI_BAR_TYPE ResourceType + ); + #endif diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciLib.c b/MdeModulePkg/Bus/Pci/PciBusDxe/PciLib.c index b3d91a8d3037..bfb7e5bee98a 100644 --- a/MdeModulePkg/Bus/Pci/PciBusDxe/PciLib.c +++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciLib.c @@ -1,7 +1,8 @@ /** @file Internal library implementation for PCI Bus module. -Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.
+Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
+(C) Copyright 2015 Hewlett Packard Enterprise Development LP
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -187,19 +188,21 @@ DumpBridgeResource ( BridgeResource->PciDev->PciBar[BridgeResource->Bar].BaseAddress, BridgeResource->Length, BridgeResource->Alignment )); - for ( Link = BridgeResource->ChildList.ForwardLink - ; Link != &BridgeResource->ChildList - ; Link = Link->ForwardLink + for ( Link = GetFirstNode (&BridgeResource->ChildList) + ; !IsNull (&BridgeResource->ChildList, Link) + ; Link = GetNextNode (&BridgeResource->ChildList, Link) ) { Resource = RESOURCE_NODE_FROM_LINK (Link); if (Resource->ResourceUsage == PciResUsageTypical) { Bar = Resource->Virtual ? Resource->PciDev->VfPciBar : Resource->PciDev->PciBar; DEBUG (( - EFI_D_INFO, " Base = 0x%lx;\tLength = 0x%lx;\tAlignment = 0x%lx;\tOwner = %s ", + EFI_D_INFO, " Base = 0x%lx;\tLength = 0x%lx;\tAlignment = 0x%lx;\tOwner = %s [%02x|%02x|%02x:", Bar[Resource->Bar].BaseAddress, Resource->Length, Resource->Alignment, IS_PCI_BRIDGE (&Resource->PciDev->Pci) ? L"PPB" : IS_CARDBUS_BRIDGE (&Resource->PciDev->Pci) ? L"P2C" : - L"PCI" + L"PCI", + Resource->PciDev->BusNumber, Resource->PciDev->DeviceNumber, + Resource->PciDev->FunctionNumber )); if ((!IS_PCI_BRIDGE (&Resource->PciDev->Pci) && !IS_CARDBUS_BRIDGE (&Resource->PciDev->Pci)) || @@ -209,24 +212,20 @@ DumpBridgeResource ( // // The resource requirement comes from the device itself. // - DEBUG (( - EFI_D_INFO, " [%02x|%02x|%02x:%02x]\n", - Resource->PciDev->BusNumber, Resource->PciDev->DeviceNumber, - Resource->PciDev->FunctionNumber, Bar[Resource->Bar].Offset - )); + DEBUG ((EFI_D_INFO, "%02x]", Bar[Resource->Bar].Offset)); } else { // // The resource requirement comes from the subordinate devices. // - DEBUG (( - EFI_D_INFO, " [%02x|%02x|%02x:**]\n", - Resource->PciDev->BusNumber, Resource->PciDev->DeviceNumber, - Resource->PciDev->FunctionNumber - )); + DEBUG ((EFI_D_INFO, "**]")); } } else { - DEBUG ((EFI_D_INFO, " Padding:Length = 0x%lx;\tAlignment = 0x%lx\n", Resource->Length, Resource->Alignment)); + DEBUG ((EFI_D_INFO, " Base = Padding;\tLength = 0x%lx;\tAlignment = 0x%lx", Resource->Length, Resource->Alignment)); } + if (BridgeResource->ResType != Resource->ResType) { + DEBUG ((EFI_D_INFO, "; Type = %s", mBarTypeStr[MIN (Resource->ResType, PciBarTypeMaxType)])); + } + DEBUG ((EFI_D_INFO, "\n")); } } } @@ -234,63 +233,61 @@ DumpBridgeResource ( /** Find the corresponding resource node for the Device in child list of BridgeResource. - @param[in] Device Pointer to PCI_IO_DEVICE. - @param[in] BridgeResource Pointer to PCI_RESOURCE_NODE. + @param[in] Device Pointer to PCI_IO_DEVICE. + @param[in] BridgeResource Pointer to PCI_RESOURCE_NODE. + @param[out] DeviceResources Pointer to a buffer to receive resources for the Device. - @return !NULL The corresponding resource node for the Device. - @return NULL No corresponding resource node for the Device. + @return Count of the resource descriptors returned. **/ -PCI_RESOURCE_NODE * +UINTN FindResourceNode ( - IN PCI_IO_DEVICE *Device, - IN PCI_RESOURCE_NODE *BridgeResource + IN PCI_IO_DEVICE *Device, + IN PCI_RESOURCE_NODE *BridgeResource, + OUT PCI_RESOURCE_NODE **DeviceResources OPTIONAL ) { LIST_ENTRY *Link; PCI_RESOURCE_NODE *Resource; + UINTN Count; + Count = 0; for ( Link = BridgeResource->ChildList.ForwardLink ; Link != &BridgeResource->ChildList ; Link = Link->ForwardLink ) { Resource = RESOURCE_NODE_FROM_LINK (Link); if (Resource->PciDev == Device) { - return Resource; + if (DeviceResources != NULL) { + DeviceResources[Count] = Resource; + } + Count++; } } - return NULL; + return Count; } /** Dump the resource map of all the devices under Bridge. - @param[in] Bridge Bridge device instance. - @param[in] IoNode IO resource descriptor for the bridge device. - @param[in] Mem32Node Mem32 resource descriptor for the bridge device. - @param[in] PMem32Node PMem32 resource descriptor for the bridge device. - @param[in] Mem64Node Mem64 resource descriptor for the bridge device. - @param[in] PMem64Node PMem64 resource descriptor for the bridge device. + @param[in] Bridge Bridge device instance. + @param[in] Resources Resource descriptors for the bridge device. + @param[in] ResourceCount Count of resource descriptors. **/ VOID DumpResourceMap ( IN PCI_IO_DEVICE *Bridge, - IN PCI_RESOURCE_NODE *IoNode, - IN PCI_RESOURCE_NODE *Mem32Node, - IN PCI_RESOURCE_NODE *PMem32Node, - IN PCI_RESOURCE_NODE *Mem64Node, - IN PCI_RESOURCE_NODE *PMem64Node + IN PCI_RESOURCE_NODE **Resources, + IN UINTN ResourceCount ) { - EFI_STATUS Status; - LIST_ENTRY *Link; - PCI_IO_DEVICE *Device; - PCI_RESOURCE_NODE *ChildIoNode; - PCI_RESOURCE_NODE *ChildMem32Node; - PCI_RESOURCE_NODE *ChildPMem32Node; - PCI_RESOURCE_NODE *ChildMem64Node; - PCI_RESOURCE_NODE *ChildPMem64Node; - CHAR16 *Str; + EFI_STATUS Status; + LIST_ENTRY *Link; + PCI_IO_DEVICE *Device; + UINTN Index; + CHAR16 *Str; + PCI_RESOURCE_NODE **ChildResources; + UINTN ChildResourceCount; DEBUG ((EFI_D_INFO, "PciBus: Resource Map for ")); @@ -319,11 +316,9 @@ DumpResourceMap ( } } - DumpBridgeResource (IoNode); - DumpBridgeResource (Mem32Node); - DumpBridgeResource (PMem32Node); - DumpBridgeResource (Mem64Node); - DumpBridgeResource (PMem64Node); + for (Index = 0; Index < ResourceCount; Index++) { + DumpBridgeResource (Resources[Index]); + } DEBUG ((EFI_D_INFO, "\n")); for ( Link = Bridge->ChildList.ForwardLink @@ -333,20 +328,19 @@ DumpResourceMap ( Device = PCI_IO_DEVICE_FROM_LINK (Link); if (IS_PCI_BRIDGE (&Device->Pci)) { - ChildIoNode = (IoNode == NULL ? NULL : FindResourceNode (Device, IoNode)); - ChildMem32Node = (Mem32Node == NULL ? NULL : FindResourceNode (Device, Mem32Node)); - ChildPMem32Node = (PMem32Node == NULL ? NULL : FindResourceNode (Device, PMem32Node)); - ChildMem64Node = (Mem64Node == NULL ? NULL : FindResourceNode (Device, Mem64Node)); - ChildPMem64Node = (PMem64Node == NULL ? NULL : FindResourceNode (Device, PMem64Node)); - - DumpResourceMap ( - Device, - ChildIoNode, - ChildMem32Node, - ChildPMem32Node, - ChildMem64Node, - ChildPMem64Node - ); + ChildResourceCount = 0; + for (Index = 0; Index < ResourceCount; Index++) { + ChildResourceCount += FindResourceNode (Device, Resources[Index], NULL); + } + ChildResources = AllocatePool (sizeof (PCI_RESOURCE_NODE *) * ChildResourceCount); + ASSERT (ChildResources != NULL); + ChildResourceCount = 0; + for (Index = 0; Index < ResourceCount; Index++) { + ChildResourceCount += FindResourceNode (Device, Resources[Index], &ChildResources[ChildResourceCount]); + } + + DumpResourceMap (Device, ChildResources, ChildResourceCount); + FreePool (ChildResources); } } } @@ -806,11 +800,11 @@ PciHostBridgeResourceAllocator ( // Create the entire system resource map from the information collected by // enumerator. Several resource tree was created // - IoBridge = FindResourceNode (RootBridgeDev, &IoPool); - Mem32Bridge = FindResourceNode (RootBridgeDev, &Mem32Pool); - PMem32Bridge = FindResourceNode (RootBridgeDev, &PMem32Pool); - Mem64Bridge = FindResourceNode (RootBridgeDev, &Mem64Pool); - PMem64Bridge = FindResourceNode (RootBridgeDev, &PMem64Pool); + FindResourceNode (RootBridgeDev, &IoPool, &IoBridge); + FindResourceNode (RootBridgeDev, &Mem32Pool, &Mem32Bridge); + FindResourceNode (RootBridgeDev, &PMem32Pool, &PMem32Bridge); + FindResourceNode (RootBridgeDev, &Mem64Pool, &Mem64Bridge); + FindResourceNode (RootBridgeDev, &PMem64Pool, &PMem64Bridge); ASSERT (IoBridge != NULL); ASSERT (Mem32Bridge != NULL); @@ -868,14 +862,13 @@ PciHostBridgeResourceAllocator ( // Dump the resource map for current root bridge // DEBUG_CODE ( - DumpResourceMap ( - RootBridgeDev, - IoBridge, - Mem32Bridge, - PMem32Bridge, - Mem64Bridge, - PMem64Bridge - ); + PCI_RESOURCE_NODE *Resources[5]; + Resources[0] = IoBridge; + Resources[1] = Mem32Bridge; + Resources[2] = PMem32Bridge; + Resources[3] = Mem64Bridge; + Resources[4] = PMem64Bridge; + DumpResourceMap (RootBridgeDev, Resources, sizeof (Resources) / sizeof (Resources[0])); ); FreePool (AcpiConfig); @@ -1022,6 +1015,13 @@ PciScanBus ( Func ); + if (EFI_ERROR (Status) && Func == 0) { + // + // go to next device if there is no Function 0 + // + break; + } + if (EFI_ERROR (Status)) { continue; } From aa498e38bf2f7e86b695587a3487bca830b9bbde Mon Sep 17 00:00:00 2001 From: Ruiyu Ni Date: Mon, 16 Nov 2015 08:20:17 +0000 Subject: [PATCH 107/525] MdeModulePkg: Fix a PciBusDxe hot plug bug For a hot plug bridge with device attached, PciBusDxe driver reserves the resources which equal to the total amount of padding resource returned from HotPlug->GetResourcePadding() and the actual occupied resource by the attached device. The behavior is incorrect. Correct behavior is to reserve the bigger one between the padding resource and the actual occupied resource. (Sync patch r18719 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ruiyu Ni Reviewed-by: Feng Tian git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18822 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Bus/Pci/PciBusDxe/PciLib.c | 13 ++-- .../Bus/Pci/PciBusDxe/PciResourceSupport.c | 60 ++++++++++++------- 2 files changed, 48 insertions(+), 25 deletions(-) diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciLib.c b/MdeModulePkg/Bus/Pci/PciBusDxe/PciLib.c index bfb7e5bee98a..12647be85fb3 100644 --- a/MdeModulePkg/Bus/Pci/PciBusDxe/PciLib.c +++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciLib.c @@ -976,7 +976,8 @@ PciScanBus ( UINT8 Device; UINT8 Func; UINT64 Address; - UINTN SecondBus; + UINT8 SecondBus; + UINT8 PaddedSubBus; UINT16 Register; UINTN HpIndex; PCI_IO_DEVICE *PciDevice; @@ -1210,7 +1211,7 @@ PciScanBus ( Status = PciScanBus ( PciDevice, - (UINT8) (SecondBus), + SecondBus, SubBusNumber, PaddedBusRange ); @@ -1226,12 +1227,16 @@ PciScanBus ( if ((Attributes == EfiPaddingPciRootBridge) && (State & EFI_HPC_STATE_ENABLED) != 0 && (State & EFI_HPC_STATE_INITIALIZED) != 0) { - *PaddedBusRange = (UINT8) ((UINT8) (BusRange) +*PaddedBusRange); + *PaddedBusRange = (UINT8) ((UINT8) (BusRange) + *PaddedBusRange); } else { - Status = PciAllocateBusNumber (PciDevice, *SubBusNumber, (UINT8) (BusRange), SubBusNumber); + // + // Reserve the larger one between the actual occupied bus number and padded bus number + // + Status = PciAllocateBusNumber (PciDevice, StartBusNumber, (UINT8) (BusRange), &PaddedSubBus); if (EFI_ERROR (Status)) { return Status; } + *SubBusNumber = MAX (PaddedSubBus, *SubBusNumber); } } diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciResourceSupport.c b/MdeModulePkg/Bus/Pci/PciBusDxe/PciResourceSupport.c index d8d988cbfc27..e12d59f1d01f 100644 --- a/MdeModulePkg/Bus/Pci/PciBusDxe/PciResourceSupport.c +++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciResourceSupport.c @@ -1,7 +1,7 @@ /** @file PCI resouces support functions implemntation for PCI Bus module. -Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.
+Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -196,6 +196,7 @@ CalculateApertureIo16 ( PCI_RESOURCE_NODE *Node; UINT64 Offset; EFI_PCI_PLATFORM_POLICY PciPolicy; + UINT64 PaddingAperture; if (!mPolicyDetermined) { // @@ -228,21 +229,27 @@ CalculateApertureIo16 ( mPolicyDetermined = TRUE; } - Aperture = 0; + Aperture = 0; + PaddingAperture = 0; if (Bridge == NULL) { return ; } - CurrentLink = Bridge->ChildList.ForwardLink; - // // Assume the bridge is aligned // - while (CurrentLink != &Bridge->ChildList) { + for ( CurrentLink = GetFirstNode (&Bridge->ChildList) + ; !IsNull (&Bridge->ChildList, CurrentLink) + ; CurrentLink = GetNextNode (&Bridge->ChildList, CurrentLink) + ) { Node = RESOURCE_NODE_FROM_LINK (CurrentLink); - + if (Node->ResourceUsage == PciResUsagePadding) { + ASSERT (PaddingAperture == 0); + PaddingAperture = Node->Length; + continue; + } // // Consider the aperture alignment // @@ -293,13 +300,10 @@ CalculateApertureIo16 ( // Increment aperture by the length of node // Aperture += Node->Length; - - CurrentLink = CurrentLink->ForwardLink; } // - // At last, adjust the aperture with the bridge's - // alignment + // Adjust the aperture with the bridge's alignment // Offset = Aperture & (Bridge->Alignment); @@ -319,6 +323,12 @@ CalculateApertureIo16 ( Bridge->Alignment = Node->Alignment; } } + + // + // Hotplug controller needs padding resources. + // Use the larger one between the padding resource and actual occupied resource. + // + Bridge->Length = MAX (Bridge->Length, PaddingAperture); } /** @@ -336,10 +346,11 @@ CalculateResourceAperture ( UINT64 Aperture; LIST_ENTRY *CurrentLink; PCI_RESOURCE_NODE *Node; - + UINT64 PaddingAperture; UINT64 Offset; - Aperture = 0; + Aperture = 0; + PaddingAperture = 0; if (Bridge == NULL) { return ; @@ -351,14 +362,20 @@ CalculateResourceAperture ( return ; } - CurrentLink = Bridge->ChildList.ForwardLink; - // // Assume the bridge is aligned // - while (CurrentLink != &Bridge->ChildList) { + for ( CurrentLink = GetFirstNode (&Bridge->ChildList) + ; !IsNull (&Bridge->ChildList, CurrentLink) + ; CurrentLink = GetNextNode (&Bridge->ChildList, CurrentLink) + ) { Node = RESOURCE_NODE_FROM_LINK (CurrentLink); + if (Node->ResourceUsage == PciResUsagePadding) { + ASSERT (PaddingAperture == 0); + PaddingAperture = Node->Length; + continue; + } // // Apply padding resource if available @@ -381,11 +398,6 @@ CalculateResourceAperture ( // Increment aperture by the length of node // Aperture += Node->Length; - - // - // Consider the aperture alignment - // - CurrentLink = CurrentLink->ForwardLink; } // @@ -407,7 +419,7 @@ CalculateResourceAperture ( } // - // At last, adjust the bridge's alignment to the first child's alignment + // Adjust the bridge's alignment to the first child's alignment // if the bridge has at least one child // CurrentLink = Bridge->ChildList.ForwardLink; @@ -417,6 +429,12 @@ CalculateResourceAperture ( Bridge->Alignment = Node->Alignment; } } + + // + // Hotplug controller needs padding resources. + // Use the larger one between the padding resource and actual occupied resource. + // + Bridge->Length = MAX (Bridge->Length, PaddingAperture); } /** From fd499fabd32969c702dde04b37fe782871c6ffce Mon Sep 17 00:00:00 2001 From: Michael Kinney Date: Tue, 17 Nov 2015 04:50:47 +0000 Subject: [PATCH 108/525] UefiCpuPkg: Update CPU MP drivers to support single CPU configuration Only perform AP detection if PcdCpuMaxLogicalProcessorNumber > 1 Only free AP related structures of they were allocated (Sync patch r18629 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Michael Kinney Reviewed-by: Jeff Fan git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18824 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/CpuDxe/CpuMp.c | 49 +++++++++++++++++++--------------- UefiCpuPkg/CpuMpPei/CpuMpPei.c | 34 +++++++++++++---------- 2 files changed, 48 insertions(+), 35 deletions(-) diff --git a/UefiCpuPkg/CpuDxe/CpuMp.c b/UefiCpuPkg/CpuDxe/CpuMp.c index 4ddcca208a36..da3686e2788e 100644 --- a/UefiCpuPkg/CpuDxe/CpuMp.c +++ b/UefiCpuPkg/CpuDxe/CpuMp.c @@ -1642,35 +1642,40 @@ InitializeMpSupport ( return; } - if (gMaxLogicalProcessorNumber == 1) { - return; - } - gApStackSize = (UINTN) PcdGet32 (PcdCpuApStackSize); - ASSERT ((gApStackSize & (SIZE_4KB - 1)) == 0); - mApStackStart = AllocatePages (EFI_SIZE_TO_PAGES (gMaxLogicalProcessorNumber * gApStackSize)); - ASSERT (mApStackStart != NULL); + InitMpSystemData (); // - // the first buffer of stack size used for common stack, when the amount of AP - // more than 1, we should never free the common stack which maybe used for AP reset. + // Only perform AP detection if PcdCpuMaxLogicalProcessorNumber is greater than 1 // - mCommonStack = mApStackStart; - mTopOfApCommonStack = (UINT8*) mApStackStart + gApStackSize; - mApStackStart = mTopOfApCommonStack; + if (gMaxLogicalProcessorNumber > 1) { - InitMpSystemData (); + gApStackSize = (UINTN) PcdGet32 (PcdCpuApStackSize); + ASSERT ((gApStackSize & (SIZE_4KB - 1)) == 0); + + mApStackStart = AllocatePages (EFI_SIZE_TO_PAGES (gMaxLogicalProcessorNumber * gApStackSize)); + ASSERT (mApStackStart != NULL); + + // + // the first buffer of stack size used for common stack, when the amount of AP + // more than 1, we should never free the common stack which maybe used for AP reset. + // + mCommonStack = mApStackStart; + mTopOfApCommonStack = (UINT8*) mApStackStart + gApStackSize; + mApStackStart = mTopOfApCommonStack; - PrepareAPStartupCode (); + PrepareAPStartupCode (); - StartApsStackless (); + StartApsStackless (); + } DEBUG ((DEBUG_INFO, "Detect CPU count: %d\n", mMpSystemData.NumberOfProcessors)); if (mMpSystemData.NumberOfProcessors == 1) { FreeApStartupCode (); - FreePages (mCommonStack, EFI_SIZE_TO_PAGES (gMaxLogicalProcessorNumber * gApStackSize)); - return; + if (mCommonStack != NULL) { + FreePages (mCommonStack, EFI_SIZE_TO_PAGES (gMaxLogicalProcessorNumber * gApStackSize)); + } } mMpSystemData.CpuDatas = ReallocatePool ( @@ -1692,10 +1697,12 @@ InitializeMpSupport ( ); ASSERT_EFI_ERROR (Status); - if (mMpSystemData.NumberOfProcessors < gMaxLogicalProcessorNumber) { - FreePages (mApStackStart, EFI_SIZE_TO_PAGES ( - (gMaxLogicalProcessorNumber - mMpSystemData.NumberOfProcessors) * - gApStackSize)); + if (mMpSystemData.NumberOfProcessors > 1 && mMpSystemData.NumberOfProcessors < gMaxLogicalProcessorNumber) { + if (mApStackStart != NULL) { + FreePages (mApStackStart, EFI_SIZE_TO_PAGES ( + (gMaxLogicalProcessorNumber - mMpSystemData.NumberOfProcessors) * + gApStackSize)); + } } Status = gBS->CreateEvent ( diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.c b/UefiCpuPkg/CpuMpPei/CpuMpPei.c index d5bc0c9b806a..8e35f288fe3c 100644 --- a/UefiCpuPkg/CpuMpPei/CpuMpPei.c +++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.c @@ -357,22 +357,28 @@ CountProcessorNumber ( // Store BSP's MTRR setting // MtrrGetAllMtrrs (&PeiCpuMpData->MtrrTable); + // - // Send broadcast IPI to APs to wakeup APs - // - PeiCpuMpData->InitFlag = 1; - WakeUpAP (PeiCpuMpData, TRUE, 0, NULL, NULL); - // - // Wait for AP task to complete and then exit. - // - MicroSecondDelay (PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds)); - PeiCpuMpData->InitFlag = 0; - PeiCpuMpData->CpuCount += (UINT32) PeiCpuMpData->MpCpuExchangeInfo->NumApsExecuting; - ASSERT (PeiCpuMpData->CpuCount <= PcdGet32(PcdCpuMaxLogicalProcessorNumber)); - // - // Sort BSP/Aps by CPU APIC ID in ascending order + // Only perform AP detection if PcdCpuMaxLogicalProcessorNumber is greater than 1 // - SortApicId (PeiCpuMpData); + if (PcdGet32 (PcdCpuMaxLogicalProcessorNumber) > 1) { + // + // Send broadcast IPI to APs to wakeup APs + // + PeiCpuMpData->InitFlag = 1; + WakeUpAP (PeiCpuMpData, TRUE, 0, NULL, NULL); + // + // Wait for AP task to complete and then exit. + // + MicroSecondDelay (PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds)); + PeiCpuMpData->InitFlag = 0; + PeiCpuMpData->CpuCount += (UINT32)PeiCpuMpData->MpCpuExchangeInfo->NumApsExecuting; + ASSERT (PeiCpuMpData->CpuCount <= PcdGet32 (PcdCpuMaxLogicalProcessorNumber)); + // + // Sort BSP/Aps by CPU APIC ID in ascending order + // + SortApicId (PeiCpuMpData); + } DEBUG ((EFI_D_INFO, "CpuMpPei: Find %d processors in system.\n", PeiCpuMpData->CpuCount)); return PeiCpuMpData->CpuCount; From 7fe220343c3cf6bf0c77134c9039f8df91122b50 Mon Sep 17 00:00:00 2001 From: Michael Kinney Date: Tue, 17 Nov 2015 04:51:37 +0000 Subject: [PATCH 109/525] UefiCpuPkg: CpuDxe: Use PCD for AP detection timeout Use PcdCpuApInitTimeOutInMicroSeconds instead of hardcoded 100ms for the time to wait for all APs to respond to first INIT SIPI SIPI wake request. (Sync patch r18630 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Michael Kinney Cc: Jeff Fan Cc: Laszlo Ersek Reviewed-by: Laszlo Ersek Reviewed-by: Jeff Fan git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18825 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/CpuDxe/ApStartup.c | 4 ++-- UefiCpuPkg/CpuDxe/CpuDxe.inf | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/UefiCpuPkg/CpuDxe/ApStartup.c b/UefiCpuPkg/CpuDxe/ApStartup.c index 38a9c0e6ea27..78fb26f9856a 100644 --- a/UefiCpuPkg/CpuDxe/ApStartup.c +++ b/UefiCpuPkg/CpuDxe/ApStartup.c @@ -452,9 +452,9 @@ StartApsStackless ( { SendInitSipiSipiAllExcludingSelf ((UINT32)(UINTN)(VOID*) StartupCode); // - // Wait 100 milliseconds for APs to arrive at the ApEntryPoint routine + // Wait for APs to arrive at the ApEntryPoint routine // - MicroSecondDelay (100 * 1000); + MicroSecondDelay (PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds)); return EFI_SUCCESS; } diff --git a/UefiCpuPkg/CpuDxe/CpuDxe.inf b/UefiCpuPkg/CpuDxe/CpuDxe.inf index a2519222268c..9db5303ae94a 100644 --- a/UefiCpuPkg/CpuDxe/CpuDxe.inf +++ b/UefiCpuPkg/CpuDxe/CpuDxe.inf @@ -84,8 +84,9 @@ gEfiSecPlatformInformationPpiGuid ## UNDEFINED # HOB [Pcd] - gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber ## CONSUMES - gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize ## CONSUMES + gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber ## CONSUMES + gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize ## CONSUMES + gUefiCpuPkgTokenSpaceGuid.PcdCpuApInitTimeOutInMicroSeconds ## CONSUMES [Depex] TRUE From dd13ef90993c02fc78f074d1ac6c71a27172f71c Mon Sep 17 00:00:00 2001 From: Michael Kinney Date: Tue, 17 Nov 2015 04:52:28 +0000 Subject: [PATCH 110/525] UefiCpuPkg: CpuDxe: Wait for APs to enter idle loop Address a race condition in first call to StartupAllAPs() with SingleThread set to TRUE in the MP initialization. If the APs have not entered their idle loop before StartupAllAPs() is called, then some of the APs will be in an unexpected state, and StartupAllAPs() will hang. This is the hang condition that is only seen when SingleThread parameter is set to TRUE and StartupAllAPs() is called very shortly after mAPsAlreadyInitFinished is set to TRUE that releases the APs to complete their initialization. An internal function has been added to check if all APs are in the sleeping state in their idle loop. On the first call to StartupAllAPs(), this internal function is used in a loop to make sure the APs are in a state that is compatible with the use of StartupAllAPs(). PcdCpuApInitTimeOutInMicroSeconds is used as the maximum wait time for the APs to enter their idle loop. If all APs have not entered their idle loop within the timeout, then an ASSERT() is generated. (Sync patch r18631 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Michael Kinney Cc: Jeff Fan Cc: Laszlo Ersek Reviewed-by: Laszlo Ersek Reviewed-by: Jeff Fan git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18826 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/CpuDxe/CpuMp.c | 60 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/UefiCpuPkg/CpuDxe/CpuMp.c b/UefiCpuPkg/CpuDxe/CpuMp.c index da3686e2788e..f3a5a24b0f66 100644 --- a/UefiCpuPkg/CpuDxe/CpuMp.c +++ b/UefiCpuPkg/CpuDxe/CpuMp.c @@ -312,6 +312,47 @@ CheckAndUpdateAllAPsToIdleState ( } } +/** + Check if all APs are in state CpuStateSleeping. + + Return TRUE if all APs are in the CpuStateSleeping state. Do not + check the state of the BSP or any disabled APs. + + @retval TRUE All APs are in CpuStateSleeping state. + @retval FALSE One or more APs are not in CpuStateSleeping state. + +**/ +BOOLEAN +CheckAllAPsSleeping ( + VOID + ) +{ + UINTN ProcessorNumber; + CPU_DATA_BLOCK *CpuData; + + for (ProcessorNumber = 0; ProcessorNumber < mMpSystemData.NumberOfProcessors; ProcessorNumber++) { + CpuData = &mMpSystemData.CpuDatas[ProcessorNumber]; + if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT)) { + // + // Skip BSP + // + continue; + } + + if (!TestCpuStatusFlag (CpuData, PROCESSOR_ENABLED_BIT)) { + // + // Skip Disabled processors + // + continue; + } + + if (GetApState (CpuData) != CpuStateSleeping) { + return FALSE; + } + } + return TRUE; +} + /** If the timeout expires before all APs returns from Procedure, we should forcibly terminate the executing AP and fill FailedList back @@ -1634,7 +1675,8 @@ InitializeMpSupport ( VOID ) { - EFI_STATUS Status; + EFI_STATUS Status; + UINTN Timeout; gMaxLogicalProcessorNumber = (UINTN) PcdGet32 (PcdCpuMaxLogicalProcessorNumber); if (gMaxLogicalProcessorNumber < 1) { @@ -1683,8 +1725,24 @@ InitializeMpSupport ( sizeof (CPU_DATA_BLOCK) * mMpSystemData.NumberOfProcessors, mMpSystemData.CpuDatas); + // + // Release all APs to complete initialization and enter idle loop + // mAPsAlreadyInitFinished = TRUE; + // + // Wait for all APs to enter idle loop. + // + Timeout = 0; + do { + if (CheckAllAPsSleeping ()) { + break; + } + gBS->Stall (gPollInterval); + Timeout += gPollInterval; + } while (Timeout <= PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds)); + ASSERT (Timeout <= PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds)); + // // Update CPU healthy information from Guided HOB // From 63f8a5c091216aef574da1029236d4f21dec410d Mon Sep 17 00:00:00 2001 From: Laszlo Ersek Date: Tue, 17 Nov 2015 04:53:12 +0000 Subject: [PATCH 111/525] UefiCpuPkg: CpuDxe: broadcast MTRR changes to APs The Quark_EDKII_v1.1.0/IA32FamilyCpuBasePkg/CpuArchDxe driver applies any MTRR changes to APs, if the EFI_MP_SERVICES_PROTOCOL is available. We should do the same. Additionally, the broadcast should occur at MP startup as well, not only when MTRR settings are changed. The inspiration is taken from Quark_EDKII_v1.1.0/IA32FamilyCpuBasePkg/CpuMpDxe/ (see the EarlyMpInit() function and its call sites in "ProcessorConfig.c"). (Sync patch r18632 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Laszlo Ersek Reviewed-by: Jeff Fan Reviewed-by: Michael Kinney git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18827 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/CpuDxe/CpuDxe.c | 26 ++++++++++++++++++++++++++ UefiCpuPkg/CpuDxe/CpuMp.c | 32 ++++++++++++++++++++++++++++++++ UefiCpuPkg/CpuDxe/CpuMp.h | 13 +++++++++++++ 3 files changed, 71 insertions(+) diff --git a/UefiCpuPkg/CpuDxe/CpuDxe.c b/UefiCpuPkg/CpuDxe/CpuDxe.c index c9df4e146ac3..daf97bd4a6cf 100644 --- a/UefiCpuPkg/CpuDxe/CpuDxe.c +++ b/UefiCpuPkg/CpuDxe/CpuDxe.c @@ -350,6 +350,9 @@ CpuSetMemoryAttributes ( { RETURN_STATUS Status; MTRR_MEMORY_CACHE_TYPE CacheType; + EFI_STATUS MpStatus; + EFI_MP_SERVICES_PROTOCOL *MpService; + MTRR_SETTINGS MtrrSettings; if (!IsMtrrSupported ()) { return EFI_UNSUPPORTED; @@ -405,6 +408,29 @@ CpuSetMemoryAttributes ( CacheType ); + if (!RETURN_ERROR (Status)) { + MpStatus = gBS->LocateProtocol ( + &gEfiMpServiceProtocolGuid, + NULL, + (VOID **)&MpService + ); + // + // Synchronize the update with all APs + // + if (!EFI_ERROR (MpStatus)) { + MtrrGetAllMtrrs (&MtrrSettings); + MpStatus = MpService->StartupAllAPs ( + MpService, // This + SetMtrrsFromBuffer, // Procedure + TRUE, // SingleThread + NULL, // WaitEvent + 0, // TimeoutInMicrosecsond + &MtrrSettings, // ProcedureArgument + NULL // FailedCpuList + ); + ASSERT (MpStatus == EFI_SUCCESS || MpStatus == EFI_NOT_STARTED); + } + } return (EFI_STATUS) Status; } diff --git a/UefiCpuPkg/CpuDxe/CpuMp.c b/UefiCpuPkg/CpuDxe/CpuMp.c index f3a5a24b0f66..04c2f1f0ac12 100644 --- a/UefiCpuPkg/CpuDxe/CpuMp.c +++ b/UefiCpuPkg/CpuDxe/CpuMp.c @@ -1666,6 +1666,22 @@ ExitBootServicesCallback ( SendInitIpiAllExcludingSelf (); } +/** + A minimal wrapper function that allows MtrrSetAllMtrrs() to be passed to + EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() as Procedure. + + @param[in] Buffer Pointer to an MTRR_SETTINGS object, to be passed to + MtrrSetAllMtrrs(). +**/ +VOID +EFIAPI +SetMtrrsFromBuffer ( + IN VOID *Buffer + ) +{ + MtrrSetAllMtrrs (Buffer); +} + /** Initialize Multi-processor support. @@ -1676,6 +1692,7 @@ InitializeMpSupport ( ) { EFI_STATUS Status; + MTRR_SETTINGS MtrrSettings; UINTN Timeout; gMaxLogicalProcessorNumber = (UINTN) PcdGet32 (PcdCpuMaxLogicalProcessorNumber); @@ -1748,6 +1765,21 @@ InitializeMpSupport ( // CollectBistDataFromHob (); + // + // Synchronize MTRR settings to APs. + // + MtrrGetAllMtrrs (&MtrrSettings); + Status = mMpServicesTemplate.StartupAllAPs ( + &mMpServicesTemplate, // This + SetMtrrsFromBuffer, // Procedure + TRUE, // SingleThread + NULL, // WaitEvent + 0, // TimeoutInMicrosecsond + &MtrrSettings, // ProcedureArgument + NULL // FailedCpuList + ); + ASSERT (Status == EFI_SUCCESS || Status == EFI_NOT_STARTED); + Status = gBS->InstallMultipleProtocolInterfaces ( &mMpServiceHandle, &gEfiMpServiceProtocolGuid, &mMpServicesTemplate, diff --git a/UefiCpuPkg/CpuDxe/CpuMp.h b/UefiCpuPkg/CpuDxe/CpuMp.h index d2866e463bc9..503f3ae944fe 100644 --- a/UefiCpuPkg/CpuDxe/CpuMp.h +++ b/UefiCpuPkg/CpuDxe/CpuMp.h @@ -643,5 +643,18 @@ ResetApStackless ( IN UINT32 ProcessorId ); +/** + A minimal wrapper function that allows MtrrSetAllMtrrs() to be passed to + EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() as Procedure. + + @param[in] Buffer Pointer to an MTRR_SETTINGS object, to be passed to + MtrrSetAllMtrrs(). +**/ +VOID +EFIAPI +SetMtrrsFromBuffer ( + IN VOID *Buffer + ); + #endif // _CPU_MP_H_ From 01020000ffbf32b788d9865887b81cab73017cea Mon Sep 17 00:00:00 2001 From: Michael Kinney Date: Tue, 17 Nov 2015 04:54:19 +0000 Subject: [PATCH 112/525] UefiCpuPkg: Add Cpuid.h include files for CPUID related defines Move CPUID related defines from LocalApic.h to Cpuid.h Update LocalApicLib instances to include Cpuid.h Update CpuMpPei module to include Cpuid.h (Sync patch r18633 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Michael Kinney Reviewed-by: Jeff Fan git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18828 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/CpuMpPei/CpuMpPei.h | 1 + UefiCpuPkg/Include/Register/Cpuid.h | 51 +++++++++++++++++++ UefiCpuPkg/Include/Register/LocalApic.h | 13 ----- .../Library/BaseXApicLib/BaseXApicLib.c | 1 + .../BaseXApicX2ApicLib/BaseXApicX2ApicLib.c | 1 + 5 files changed, 54 insertions(+), 13 deletions(-) create mode 100644 UefiCpuPkg/Include/Register/Cpuid.h diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.h b/UefiCpuPkg/CpuMpPei/CpuMpPei.h index 19e649eb82ca..9325a12d4ceb 100644 --- a/UefiCpuPkg/CpuMpPei/CpuMpPei.h +++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.h @@ -22,6 +22,7 @@ #include #include +#include #include #include diff --git a/UefiCpuPkg/Include/Register/Cpuid.h b/UefiCpuPkg/Include/Register/Cpuid.h new file mode 100644 index 000000000000..6730551ff8cd --- /dev/null +++ b/UefiCpuPkg/Include/Register/Cpuid.h @@ -0,0 +1,51 @@ +/** @file +CPUID Definitions. + +CPUID definitions based on contents of the Intel(R) 64 and IA-32 Architectures +Software Developer's Manual, Volume 2A, CPUID instruction. + +Copyright (c) 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __CPUID_H__ +#define __CPUID_H__ + +// +// Definitions for CPUID instruction +// +#define CPUID_SIGNATURE 0x0 + +#define CPUID_VERSION_INFO 0x1 + +#define CPUID_CACHE_INFO 0x2 + +#define CPUID_SERIAL_NUMBER 0x3 + +#define CPUID_CACHE_PARAMS 0x4 + +#define CPUID_EXTENDED_TOPOLOGY 0xB +#define CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_INVALID 0x0 +#define CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT 0x1 +#define CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_CORE 0x2 + +#define CPUID_EXTENDED_FUNCTION 0x80000000 + +#define CPUID_EXTENDED_CPU_SIG 0x80000001 + +#define CPUID_BRAND_STRING1 0x80000002 + +#define CPUID_BRAND_STRING2 0x80000003 + +#define CPUID_BRAND_STRING3 0x80000004 + +#define CPUID_VIR_PHY_ADDRESS_SIZE 0x80000008 + +#endif diff --git a/UefiCpuPkg/Include/Register/LocalApic.h b/UefiCpuPkg/Include/Register/LocalApic.h index cf335a69d95d..346cce675643 100644 --- a/UefiCpuPkg/Include/Register/LocalApic.h +++ b/UefiCpuPkg/Include/Register/LocalApic.h @@ -20,19 +20,6 @@ // #define MSR_IA32_APIC_BASE_ADDRESS 0x1B -// -// Definitions for CPUID instruction -// -#define CPUID_SIGNATURE 0x0 -#define CPUID_VERSION_INFO 0x1 -#define CPUID_CACHE_PARAMS 0x4 -#define CPUID_EXTENDED_TOPOLOGY 0xB -#define CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_INVALID 0x0 -#define CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT 0x1 -#define CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_CORE 0x2 -#define CPUID_EXTENDED_FUNCTION 0x80000000 -#define CPUID_VIR_PHY_ADDRESS_SIZE 0x80000008 - // // Definition for Local APIC registers and related values // diff --git a/UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.c b/UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.c index f219b07888c0..b73b1d3da930 100644 --- a/UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.c +++ b/UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.c @@ -14,6 +14,7 @@ **/ +#include #include #include diff --git a/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c b/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c index 8c6e8d741564..9bbaca45dc6b 100644 --- a/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c +++ b/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c @@ -15,6 +15,7 @@ **/ +#include #include #include From 2e216411fadf5d4600aa15d27bea37707066f883 Mon Sep 17 00:00:00 2001 From: Michael Kinney Date: Tue, 17 Nov 2015 04:55:07 +0000 Subject: [PATCH 113/525] UefiCpuPkg: Add SMM Communication PPI and Handler Modules Add modules that produce the SMM Communications PPI and install a SW SMI handler for SMM Communication requests (Sync patch r18634 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Michael Kinney Reviewed-by: Jeff Fan git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18829 6f19259b-4bc3-4df7-8a09-765794883524 --- .../PiSmmCommunicationPei.c | 425 ++++++++++++++++++ .../PiSmmCommunicationPei.inf | 70 +++ .../PiSmmCommunicationPei.uni | Bin 0 -> 2066 bytes .../PiSmmCommunicationPeiExtra.uni | Bin 0 -> 1370 bytes .../PiSmmCommunicationPrivate.h | 30 ++ .../PiSmmCommunicationSmm.c | 269 +++++++++++ .../PiSmmCommunicationSmm.inf | 82 ++++ .../PiSmmCommunicationSmm.uni | Bin 0 -> 3004 bytes .../PiSmmCommunicationSmmExtra.uni | Bin 0 -> 1392 bytes UefiCpuPkg/UefiCpuPkg.dsc | 5 + 10 files changed, 881 insertions(+) create mode 100644 UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationPei.c create mode 100644 UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationPei.inf create mode 100644 UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationPei.uni create mode 100644 UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationPeiExtra.uni create mode 100644 UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationPrivate.h create mode 100644 UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationSmm.c create mode 100644 UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationSmm.inf create mode 100644 UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationSmm.uni create mode 100644 UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationSmmExtra.uni diff --git a/UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationPei.c b/UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationPei.c new file mode 100644 index 000000000000..aaeaa0672939 --- /dev/null +++ b/UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationPei.c @@ -0,0 +1,425 @@ +/** @file +PiSmmCommunication PEI Driver. + +Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "PiSmmCommunicationPrivate.h" + +/** + the whole picture is below: + + +----------------------------------+ + | ACPI_VARIABLE_HOB | + | SmramDescriptor | <- DRAM + | CpuStart |--- + +----------------------------------+ | + | + +----------------------------------+<-- + | SMM_S3_RESUME_STATE | + | Signature | <- SMRAM + | Smst |--- + +----------------------------------+ | + | + +----------------------------------+<-- + | EFI_SMM_SYSTEM_TABLE2 | + | NumberOfTableEntries | <- SMRAM + | SmmConfigurationTable |--- + +----------------------------------+ | + | + +----------------------------------+<-- + | EFI_SMM_COMMUNICATION_CONTEXT | + | SwSmiNumber | <- SMRAM + | BufferPtrAddress |---------------- + +----------------------------------+ | + | + +----------------------------------+ | + | EFI_SMM_COMMUNICATION_ACPI_TABLE | | + | SwSmiNumber | <- AcpiTable | + | BufferPtrAddress |--- | + +----------------------------------+ | | + | | + +----------------------------------+<--------------- + | Communication Buffer Pointer | <- AcpiNvs + +----------------------------------+--- + | + +----------------------------------+<-- + | EFI_SMM_COMMUNICATE_HEADER | + | HeaderGuid | <- DRAM + | MessageLength | + +----------------------------------+ + +**/ + +#if defined (MDE_CPU_IA32) +typedef struct { + EFI_TABLE_HEADER Hdr; + UINT64 SmmFirmwareVendor; + UINT64 SmmFirmwareRevision; + UINT64 SmmInstallConfigurationTable; + UINT64 SmmIoMemRead; + UINT64 SmmIoMemWrite; + UINT64 SmmIoIoRead; + UINT64 SmmIoIoWrite; + UINT64 SmmAllocatePool; + UINT64 SmmFreePool; + UINT64 SmmAllocatePages; + UINT64 SmmFreePages; + UINT64 SmmStartupThisAp; + UINT64 CurrentlyExecutingCpu; + UINT64 NumberOfCpus; + UINT64 CpuSaveStateSize; + UINT64 CpuSaveState; + UINT64 NumberOfTableEntries; + UINT64 SmmConfigurationTable; +} EFI_SMM_SYSTEM_TABLE2_64; + +typedef struct { + EFI_GUID VendorGuid; + UINT64 VendorTable; +} EFI_CONFIGURATION_TABLE64; +#endif + +#if defined (MDE_CPU_X64) +typedef EFI_SMM_SYSTEM_TABLE2 EFI_SMM_SYSTEM_TABLE2_64; +typedef EFI_CONFIGURATION_TABLE EFI_CONFIGURATION_TABLE64; +#endif + +/** + Communicates with a registered handler. + + This function provides a service to send and receive messages from a registered UEFI service. + + @param[in] This The EFI_PEI_SMM_COMMUNICATION_PPI instance. + @param[in, out] CommBuffer A pointer to the buffer to convey into SMRAM. + @param[in, out] CommSize The size of the data buffer being passed in.On exit, the size of data + being returned. Zero if the handler does not wish to reply with any data. + + @retval EFI_SUCCESS The message was successfully posted. + @retval EFI_INVALID_PARAMETER The CommBuffer was NULL. + @retval EFI_NOT_STARTED The service is NOT started. +**/ +EFI_STATUS +EFIAPI +Communicate ( + IN CONST EFI_PEI_SMM_COMMUNICATION_PPI *This, + IN OUT VOID *CommBuffer, + IN OUT UINTN *CommSize + ); + +EFI_PEI_SMM_COMMUNICATION_PPI mSmmCommunicationPpi = { Communicate }; + +EFI_PEI_PPI_DESCRIPTOR mPpiList = { + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiPeiSmmCommunicationPpiGuid, + &mSmmCommunicationPpi +}; + +/** + Get SMM communication context. + + @return SMM communication context. +**/ +EFI_SMM_COMMUNICATION_CONTEXT * +GetCommunicationContext ( + VOID + ) +{ + EFI_HOB_GUID_TYPE *GuidHob; + EFI_SMM_COMMUNICATION_CONTEXT *SmmCommunicationContext; + + GuidHob = GetFirstGuidHob (&gEfiPeiSmmCommunicationPpiGuid); + ASSERT (GuidHob != NULL); + + SmmCommunicationContext = (EFI_SMM_COMMUNICATION_CONTEXT *)GET_GUID_HOB_DATA (GuidHob); + + return SmmCommunicationContext; +} + +/** + Set SMM communication context. + + @param SmmCommunicationContext SMM communication context. +**/ +VOID +SetCommunicationContext ( + IN EFI_SMM_COMMUNICATION_CONTEXT *SmmCommunicationContext + ) +{ + EFI_PEI_HOB_POINTERS Hob; + UINTN BufferSize; + + BufferSize = sizeof (*SmmCommunicationContext); + Hob.Raw = BuildGuidHob ( + &gEfiPeiSmmCommunicationPpiGuid, + BufferSize + ); + ASSERT (Hob.Raw); + + CopyMem ((VOID *)Hob.Raw, SmmCommunicationContext, sizeof(*SmmCommunicationContext)); +} + +/** + Get VendorTable by VendorGuid in Smst. + + @param Signature Signature of SMM_S3_RESUME_STATE + @param Smst SMM system table + @param VendorGuid vendor guid + + @return vendor table. +**/ +VOID * +InternalSmstGetVendorTableByGuid ( + IN UINT64 Signature, + IN EFI_SMM_SYSTEM_TABLE2 *Smst, + IN EFI_GUID *VendorGuid + ) +{ + EFI_CONFIGURATION_TABLE *SmmConfigurationTable; + UINTN NumberOfTableEntries; + UINTN Index; + EFI_SMM_SYSTEM_TABLE2_64 *Smst64; + EFI_CONFIGURATION_TABLE64 *SmmConfigurationTable64; + + if ((sizeof(UINTN) == sizeof(UINT32)) && (Signature == SMM_S3_RESUME_SMM_64)) { + // + // 32 PEI + 64 DXE + // + Smst64 = (EFI_SMM_SYSTEM_TABLE2_64 *)Smst; + DEBUG ((EFI_D_INFO, "InitCommunicationContext - SmmConfigurationTable: %x\n", Smst64->SmmConfigurationTable)); + DEBUG ((EFI_D_INFO, "InitCommunicationContext - NumberOfTableEntries: %x\n", Smst64->NumberOfTableEntries)); + SmmConfigurationTable64 = (EFI_CONFIGURATION_TABLE64 *)(UINTN)Smst64->SmmConfigurationTable; + NumberOfTableEntries = (UINTN)Smst64->NumberOfTableEntries; + for (Index = 0; Index < NumberOfTableEntries; Index++) { + if (CompareGuid (&SmmConfigurationTable64[Index].VendorGuid, VendorGuid)) { + return (VOID *)(UINTN)SmmConfigurationTable64[Index].VendorTable; + } + } + return NULL; + } else { + DEBUG ((EFI_D_INFO, "InitCommunicationContext - SmmConfigurationTable: %x\n", Smst->SmmConfigurationTable)); + DEBUG ((EFI_D_INFO, "InitCommunicationContext - NumberOfTableEntries: %x\n", Smst->NumberOfTableEntries)); + SmmConfigurationTable = Smst->SmmConfigurationTable; + NumberOfTableEntries = Smst->NumberOfTableEntries; + for (Index = 0; Index < NumberOfTableEntries; Index++) { + if (CompareGuid (&SmmConfigurationTable[Index].VendorGuid, VendorGuid)) { + return (VOID *)SmmConfigurationTable[Index].VendorTable; + } + } + return NULL; + } +} + +/** + Init SMM communication context. +**/ +VOID +InitCommunicationContext ( + VOID + ) +{ + EFI_SMRAM_DESCRIPTOR *SmramDescriptor; + SMM_S3_RESUME_STATE *SmmS3ResumeState; + VOID *GuidHob; + EFI_SMM_COMMUNICATION_CONTEXT *SmmCommunicationContext; + + GuidHob = GetFirstGuidHob (&gEfiAcpiVariableGuid); + ASSERT (GuidHob != NULL); + SmramDescriptor = (EFI_SMRAM_DESCRIPTOR *) GET_GUID_HOB_DATA (GuidHob); + SmmS3ResumeState = (SMM_S3_RESUME_STATE *)(UINTN)SmramDescriptor->CpuStart; + + DEBUG ((EFI_D_INFO, "InitCommunicationContext - SmmS3ResumeState: %x\n", SmmS3ResumeState)); + DEBUG ((EFI_D_INFO, "InitCommunicationContext - Smst: %x\n", SmmS3ResumeState->Smst)); + + SmmCommunicationContext = (EFI_SMM_COMMUNICATION_CONTEXT *)InternalSmstGetVendorTableByGuid ( + SmmS3ResumeState->Signature, + (EFI_SMM_SYSTEM_TABLE2 *)(UINTN)SmmS3ResumeState->Smst, + &gEfiPeiSmmCommunicationPpiGuid + ); + ASSERT (SmmCommunicationContext != NULL); + + SetCommunicationContext (SmmCommunicationContext); + + return ; +} + +/** + Communicates with a registered handler. + + This function provides a service to send and receive messages from a registered UEFI service. + + @param[in] This The EFI_PEI_SMM_COMMUNICATION_PPI instance. + @param[in, out] CommBuffer A pointer to the buffer to convey into SMRAM. + @param[in, out] CommSize The size of the data buffer being passed in.On exit, the size of data + being returned. Zero if the handler does not wish to reply with any data. + + @retval EFI_SUCCESS The message was successfully posted. + @retval EFI_INVALID_PARAMETER The CommBuffer was NULL. + @retval EFI_NOT_STARTED The service is NOT started. +**/ +EFI_STATUS +EFIAPI +Communicate ( + IN CONST EFI_PEI_SMM_COMMUNICATION_PPI *This, + IN OUT VOID *CommBuffer, + IN OUT UINTN *CommSize + ) +{ + EFI_STATUS Status; + PEI_SMM_CONTROL_PPI *SmmControl; + PEI_SMM_ACCESS_PPI *SmmAccess; + UINT8 SmiCommand; + UINTN Size; + EFI_SMM_COMMUNICATION_CONTEXT *SmmCommunicationContext; + + DEBUG ((EFI_D_INFO, "PiSmmCommunicationPei Communicate Enter\n")); + + if (CommBuffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Get needed resource + // + Status = PeiServicesLocatePpi ( + &gPeiSmmControlPpiGuid, + 0, + NULL, + (VOID **)&SmmControl + ); + if (EFI_ERROR (Status)) { + return EFI_NOT_STARTED; + } + + Status = PeiServicesLocatePpi ( + &gPeiSmmAccessPpiGuid, + 0, + NULL, + (VOID **)&SmmAccess + ); + if (EFI_ERROR (Status)) { + return EFI_NOT_STARTED; + } + + // + // Check SMRAM locked, it should be done after SMRAM lock. + // + if (!SmmAccess->LockState) { + DEBUG ((EFI_D_INFO, "PiSmmCommunicationPei LockState - %x\n", (UINTN)SmmAccess->LockState)); + return EFI_NOT_STARTED; + } + + SmmCommunicationContext = GetCommunicationContext (); + DEBUG ((EFI_D_INFO, "PiSmmCommunicationPei BufferPtrAddress - 0x%016lx, BufferPtr: 0x%016lx\n", SmmCommunicationContext->BufferPtrAddress, *(EFI_PHYSICAL_ADDRESS *)(UINTN)SmmCommunicationContext->BufferPtrAddress)); + + // + // No need to check if BufferPtr is 0, because it is in PEI phase. + // + *(EFI_PHYSICAL_ADDRESS *)(UINTN)SmmCommunicationContext->BufferPtrAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)CommBuffer; + DEBUG ((EFI_D_INFO, "PiSmmCommunicationPei CommBuffer - %x\n", (UINTN)CommBuffer)); + + // + // Send command + // + SmiCommand = (UINT8)SmmCommunicationContext->SwSmiNumber; + Size = sizeof(SmiCommand); + Status = SmmControl->Trigger ( + (EFI_PEI_SERVICES **)GetPeiServicesTablePointer (), + SmmControl, + (INT8 *)&SmiCommand, + &Size, + FALSE, + 0 + ); + ASSERT_EFI_ERROR (Status); + + // + // Setting BufferPtr to 0 means this transaction is done. + // + *(EFI_PHYSICAL_ADDRESS *)(UINTN)SmmCommunicationContext->BufferPtrAddress = 0; + + DEBUG ((EFI_D_INFO, "PiSmmCommunicationPei Communicate Exit\n")); + + return EFI_SUCCESS; +} + +/** + Entry Point for PI SMM communication PEIM. + + @param FileHandle Handle of the file being invoked. + @param PeiServices Pointer to PEI Services table. + + @retval EFI_SUCEESS + @return Others Some error occurs. +**/ +EFI_STATUS +EFIAPI +PiSmmCommunicationPeiEntryPoint ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + PEI_SMM_ACCESS_PPI *SmmAccess; + EFI_BOOT_MODE BootMode; + UINTN Index; + + BootMode = GetBootModeHob (); + if (BootMode != BOOT_ON_S3_RESUME) { + return EFI_UNSUPPORTED; + } + + Status = PeiServicesLocatePpi ( + &gPeiSmmAccessPpiGuid, + 0, + NULL, + (VOID **)&SmmAccess + ); + if (EFI_ERROR (Status)) { + return EFI_NOT_STARTED; + } + + // + // Check SMRAM locked, it should be done before SMRAM lock. + // + if (SmmAccess->LockState) { + DEBUG ((EFI_D_INFO, "PiSmmCommunicationPei LockState - %x\n", (UINTN)SmmAccess->LockState)); + return EFI_ACCESS_DENIED; + } + + // + // Open all SMRAM + // + for (Index = 0; !EFI_ERROR (Status); Index++) { + Status = SmmAccess->Open ((EFI_PEI_SERVICES **)GetPeiServicesTablePointer (), SmmAccess, Index); + } + + InitCommunicationContext (); + + PeiServicesInstallPpi (&mPpiList); + + return RETURN_SUCCESS; +} diff --git a/UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationPei.inf b/UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationPei.inf new file mode 100644 index 000000000000..5cb596c5644d --- /dev/null +++ b/UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationPei.inf @@ -0,0 +1,70 @@ +## @file +# PI SMM Communication PEIM which produces PEI SMM Communication PPI. +# +# This PEIM retrieves the SMM communication context and produces PEI SMM +# Communication PPIin the S3 boot mode. +# +# Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PiSmmCommunicationPei + MODULE_UNI_FILE = PiSmmCommunicationPei.uni + FILE_GUID = 1C8B7F78-1699-40e6-AF33-9B995D16B043 + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + ENTRY_POINT = PiSmmCommunicationPeiEntryPoint + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + PiSmmCommunicationPei.c + PiSmmCommunicationPrivate.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + PeimEntryPoint + PeiServicesTablePointerLib + PeiServicesLib + BaseLib + BaseMemoryLib + HobLib + DebugLib + +[Guids] + gEfiAcpiVariableGuid ## CONSUMES ## HOB + +[Ppis] + ## PRODUCES + ## UNDEFINED # HOB # SMM Configuration Table + gEfiPeiSmmCommunicationPpiGuid + gPeiSmmAccessPpiGuid ## CONSUMES + gPeiSmmControlPpiGuid ## CONSUMES + +# [BootMode] +# S3_RESUME ## CONSUMES + +[Depex] + gPeiSmmAccessPpiGuid AND + gPeiSmmControlPpiGuid AND + gEfiPeiMasterBootModePpiGuid + +[UserExtensions.TianoCore."ExtraFiles"] + PiSmmCommunicationPeiExtra.uni diff --git a/UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationPei.uni b/UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationPei.uni new file mode 100644 index 0000000000000000000000000000000000000000..08af34e11b69fd4856a2cb42332ca51e2545652f GIT binary patch literal 2066 zcmc(gTW`}q5QXO%iT_}wFM!$vC{G9>5^BH#>L?chPbl|T%B6BbA%7nD&Ti~&s*to# z$nsvtXU?3NUH|!AvzkS`Pk17GV`Ix~W+QuO4_MV+(-PXYeddYmtu1ZN^TQTc4y<{^30Pd=^yDO&rS4%#DSI7AXc=DU$VNILSUvIswu^X{h zL@+oIf%X<4jO-U}M05+7ACDohI;@Xk$(&Y!)j9Zm{4SlxIsFj-`yv+hm2F&n6QUBs zN2vOk{<%H1XS|V}m9rOi$~f6ZG-E7;91OJ~b5(ZgWL*~0&SOhi>AB*~oti^fy|RY2 z?DfHX_>51Sk2xrXibc#lI7{g{OtiOgnoO{qJ67_SF`D5!DBE*vB34y*Bfb+eWv9T` z*V0Za*SxCa9@?s&BUiE7%^4R=l<6F=inTxyGi5!)%2&2_mz<37U4v@6VE$=`OW=C5 z{%=RC+7zNVWNsv1E9Q#256{A{@)B8RTfbv=e2zkW?y}ld#;dsjq3_}!6N65zS8RPl zSyj@ST)cEAUNz>`m3{8CuJUb8UDR%=zhb2i_aRlc>%9ufl(*2N=oQZg?g`x%Elce^ zZQb1&37STzs=mW&LZx*X#ZKw2UDC&_2ZWG?gvySwXglPTkt$kkg}S8w$WTYdSB{v$hLu9K+S(MPW+ zV*6U+1a#e>P3lTMFZSL7x~Xf9yEHv1D`!D|bjwM*@1Uf7-vudVRwr)1Q%9)|cK>=# z$fHiegxvRNb#hbid!RX1(oR!ud_T3!ubiJ0XOy$p9nbMP3A)B5!d zaxd`|U*r8EwjeelE63m3%J%qEW{L}K%i7Y%vR-M!`p%BNcV#zZM)nl+XV_Qv!d}{I zX6Kdn#?F{01?HN$D&)5FvF6%jr42)6h*!WCvm7pazTEDdd(+-o$ALamLnE>XlxnJHP}E~P|9AJqFg+~EcO%D6+XB4~B z)246`qBsP-RBMl~Q_tX8*44d4CSAqhpbMO32Gk6nic!ALIZI+{G+To z>A+pQ_5RM71$C95yVgz4pL3(F2kP&M%;3JD>rSgTLAl{8H7Tvm^TlFV4d|o3eP(Q1 z7e7JM2vudrL=!q~!Yp>BC)UHp#A}5577{u;CS&BteP-%tjSZ}Dh1$S&+?RJ&af|F5 z>*Ce-it^i360;uh1XN-4z4{PO+!a&JFz^1GRl+G^`(EMH z=m}a3=quH{ux7=v)=%$J%j1eYsX9lmiQX1zcU7o60A*O6;0o+Ms1xvGa(b}rG7C8R suL$E7yYh}v7o3wl@{9(y%P+hldj0-?^>nK`Wkg;^SEyr`=&lNX0qm328~^|S literal 0 HcmV?d00001 diff --git a/UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationPrivate.h b/UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationPrivate.h new file mode 100644 index 000000000000..3dd5ac6e3801 --- /dev/null +++ b/UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationPrivate.h @@ -0,0 +1,30 @@ +/** @file +PiSmmCommunication private data structure + +Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _SMM_COMMUNICATION_PRIVATE_H_ +#define _SMM_COMMUNICATION_PRIVATE_H_ + +#pragma pack(push, 1) + +#define SMM_COMMUNICATION_SIGNATURE SIGNATURE_32 ('S','M','M','C') + +typedef struct { + UINT32 Signature; + UINT32 SwSmiNumber; + EFI_PHYSICAL_ADDRESS BufferPtrAddress; +} EFI_SMM_COMMUNICATION_CONTEXT; + +#pragma pack(pop) + +#endif diff --git a/UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationSmm.c b/UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationSmm.c new file mode 100644 index 000000000000..077eacce88d1 --- /dev/null +++ b/UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationSmm.c @@ -0,0 +1,269 @@ +/** @file +PiSmmCommunication SMM Driver. + +Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "PiSmmCommunicationPrivate.h" + +EFI_SMM_COMMUNICATION_CONTEXT mSmmCommunicationContext = { + SMM_COMMUNICATION_SIGNATURE +}; + +EFI_SMM_COMMUNICATION_ACPI_TABLE mSmmCommunicationAcpiTable = { + { + { + EFI_ACPI_4_0_UEFI_ACPI_DATA_TABLE_SIGNATURE, + sizeof (EFI_SMM_COMMUNICATION_ACPI_TABLE), + 0x1, // Revision + 0x0, // Checksum + {0x0}, // OemId[6] + 0x0, // OemTableId + 0x0, // OemRevision + 0x0, // CreatorId + 0x0 // CreatorRevision + }, + {0x0}, // Identifier + OFFSET_OF (EFI_SMM_COMMUNICATION_ACPI_TABLE, SwSmiNumber) // DataOffset + }, + 0x0, // SwSmiNumber + 0x0 // BufferPtrAddress +}; + +/** + Set SMM communication context. +**/ +VOID +SetCommunicationContext ( + VOID + ) +{ + EFI_STATUS Status; + + Status = gSmst->SmmInstallConfigurationTable ( + gSmst, + &gEfiPeiSmmCommunicationPpiGuid, + &mSmmCommunicationContext, + sizeof(mSmmCommunicationContext) + ); + ASSERT_EFI_ERROR (Status); +} + +/** + Dispatch function for a Software SMI handler. + + @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister(). + @param Context Points to an optional handler context which was specified when the + handler was registered. + @param CommBuffer A pointer to a collection of data in memory that will + be conveyed from a non-SMM environment into an SMM environment. + @param CommBufferSize The size of the CommBuffer. + + @retval EFI_SUCCESS Command is handled successfully. + +**/ +EFI_STATUS +EFIAPI +PiSmmCommunicationHandler ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *Context OPTIONAL, + IN OUT VOID *CommBuffer OPTIONAL, + IN OUT UINTN *CommBufferSize OPTIONAL + ) +{ + UINTN CommSize; + EFI_STATUS Status; + EFI_SMM_COMMUNICATE_HEADER *CommunicateHeader; + EFI_PHYSICAL_ADDRESS *BufferPtrAddress; + + DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler Enter\n")); + + BufferPtrAddress = (EFI_PHYSICAL_ADDRESS *)(UINTN)mSmmCommunicationContext.BufferPtrAddress; + CommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *)(UINTN)*BufferPtrAddress; + DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler CommunicateHeader - %x\n", CommunicateHeader)); + if (CommunicateHeader == NULL) { + DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler is NULL, needn't to call dispatch function\n")); + Status = EFI_SUCCESS; + } else { + if (!SmmIsBufferOutsideSmmValid ((UINTN)CommunicateHeader, OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data))) { + DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler CommunicateHeader invalid - 0x%x\n", CommunicateHeader)); + Status = EFI_SUCCESS; + goto Done; + } + + CommSize = (UINTN)CommunicateHeader->MessageLength; + if (!SmmIsBufferOutsideSmmValid ((UINTN)&CommunicateHeader->Data[0], CommSize)) { + DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler CommunicateData invalid - 0x%x\n", &CommunicateHeader->Data[0])); + Status = EFI_SUCCESS; + goto Done; + } + + // + // Call dispatch function + // + DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler Data - %x\n", &CommunicateHeader->Data[0])); + Status = gSmst->SmiManage ( + &CommunicateHeader->HeaderGuid, + NULL, + &CommunicateHeader->Data[0], + &CommSize + ); + } + +Done: + DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler %r\n", Status)); + DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler Exit\n")); + + return (Status == EFI_SUCCESS) ? EFI_SUCCESS : EFI_INTERRUPT_PENDING; +} + +/** + Allocate EfiACPIMemoryNVS below 4G memory address. + + This function allocates EfiACPIMemoryNVS below 4G memory address. + + @param Size Size of memory to allocate. + + @return Allocated address for output. + +**/ +VOID* +AllocateAcpiNvsMemoryBelow4G ( + IN UINTN Size + ) +{ + UINTN Pages; + EFI_PHYSICAL_ADDRESS Address; + EFI_STATUS Status; + VOID* Buffer; + + Pages = EFI_SIZE_TO_PAGES (Size); + Address = 0xffffffff; + + Status = gBS->AllocatePages ( + AllocateMaxAddress, + EfiACPIMemoryNVS, + Pages, + &Address + ); + ASSERT_EFI_ERROR (Status); + + Buffer = (VOID *) (UINTN) Address; + ZeroMem (Buffer, Size); + + return Buffer; +} + +/** + Entry Point for PI SMM communication SMM driver. + + @param[in] ImageHandle Image handle of this driver. + @param[in] SystemTable A Pointer to the EFI System Table. + + @retval EFI_SUCEESS + @return Others Some error occurs. +**/ +EFI_STATUS +EFIAPI +PiSmmCommunicationSmmEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_SMM_SW_DISPATCH2_PROTOCOL *SmmSwDispatch2; + EFI_SMM_SW_REGISTER_CONTEXT SmmSwDispatchContext; + EFI_HANDLE DispatchHandle; + EFI_ACPI_TABLE_PROTOCOL *AcpiTableProtocol; + UINTN TableKey; + UINT64 OemTableId; + EFI_PHYSICAL_ADDRESS *BufferPtrAddress; + + CopyMem ( + mSmmCommunicationAcpiTable.UefiAcpiDataTable.Header.OemId, + PcdGetPtr (PcdAcpiDefaultOemId), + sizeof (mSmmCommunicationAcpiTable.UefiAcpiDataTable.Header.OemId) + ); + OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId); + CopyMem (&mSmmCommunicationAcpiTable.UefiAcpiDataTable.Header.OemTableId, &OemTableId, sizeof (UINT64)); + mSmmCommunicationAcpiTable.UefiAcpiDataTable.Header.OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision); + mSmmCommunicationAcpiTable.UefiAcpiDataTable.Header.CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId); + mSmmCommunicationAcpiTable.UefiAcpiDataTable.Header.CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision); + + // + // Register software SMI handler + // + Status = gSmst->SmmLocateProtocol ( + &gEfiSmmSwDispatch2ProtocolGuid, + NULL, + (VOID **)&SmmSwDispatch2 + ); + ASSERT_EFI_ERROR (Status); + + SmmSwDispatchContext.SwSmiInputValue = (UINTN)-1; + Status = SmmSwDispatch2->Register ( + SmmSwDispatch2, + PiSmmCommunicationHandler, + &SmmSwDispatchContext, + &DispatchHandle + ); + ASSERT_EFI_ERROR (Status); + + DEBUG ((EFI_D_INFO, "SmmCommunication SwSmi: %x\n", (UINTN)SmmSwDispatchContext.SwSmiInputValue)); + + // + // Set ACPI table + // + Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTableProtocol); + ASSERT_EFI_ERROR (Status); + + mSmmCommunicationAcpiTable.SwSmiNumber = (UINT32)SmmSwDispatchContext.SwSmiInputValue; + BufferPtrAddress = AllocateAcpiNvsMemoryBelow4G (sizeof(EFI_PHYSICAL_ADDRESS)); + ASSERT (BufferPtrAddress != NULL); + DEBUG ((EFI_D_INFO, "SmmCommunication BufferPtrAddress: 0x%016lx, BufferPtr: 0x%016lx\n", (EFI_PHYSICAL_ADDRESS)(UINTN)BufferPtrAddress, *BufferPtrAddress)); + mSmmCommunicationAcpiTable.BufferPtrAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)BufferPtrAddress; + CopyMem (&mSmmCommunicationAcpiTable.UefiAcpiDataTable.Identifier, &gEfiSmmCommunicationProtocolGuid, sizeof(gEfiSmmCommunicationProtocolGuid)); + + Status = AcpiTableProtocol->InstallAcpiTable ( + AcpiTableProtocol, + &mSmmCommunicationAcpiTable, + sizeof(mSmmCommunicationAcpiTable), + &TableKey + ); + ASSERT_EFI_ERROR (Status); + + // + // Save context + // + mSmmCommunicationContext.SwSmiNumber = (UINT32)SmmSwDispatchContext.SwSmiInputValue; + mSmmCommunicationContext.BufferPtrAddress = mSmmCommunicationAcpiTable.BufferPtrAddress; + SetCommunicationContext (); + + return Status; +} diff --git a/UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationSmm.inf b/UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationSmm.inf new file mode 100644 index 000000000000..9b03837cf3f1 --- /dev/null +++ b/UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationSmm.inf @@ -0,0 +1,82 @@ +## @file +# PI SMM Communication SMM driver that installs the SMM Communication ACPI Table. +# +# This SMM driver installs the SMM Communication ACPI Table defined in the UEFI spec +# which provides a mechanism that can be used in the OS present environment by +# non-firmware agents for inter-mode communication with SMM agents. It also saves +# SMM communication context for use by SMM Communication PEIM in the S3 boot mode. +# +# Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PiSmmCommunicationSmm + MODULE_UNI_FILE = PiSmmCommunicationSmm.uni + FILE_GUID = E21F35A8-42FF-4050-82D6-93F7CDFA7073 + MODULE_TYPE = DXE_SMM_DRIVER + VERSION_STRING = 1.0 + PI_SPECIFICATION_VERSION = 0x0001000A + ENTRY_POINT = PiSmmCommunicationSmmEntryPoint + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + PiSmmCommunicationSmm.c + PiSmmCommunicationPrivate.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + SmmServicesTableLib + BaseLib + BaseMemoryLib + HobLib + DebugLib + SmmMemLib + PcdLib + +[Guids] + gEfiAcpi20TableGuid ## SOMETIMES_CONSUMES ## SystemTable + gEfiAcpi10TableGuid ## SOMETIMES_CONSUMES ## SystemTable + gEfiAcpiTableGuid ## SOMETIMES_CONSUMES ## SystemTable + +[Ppis] + gEfiPeiSmmCommunicationPpiGuid ## UNDEFINED # SMM Configuration Table + +[Protocols] + gEfiSmmSwDispatch2ProtocolGuid ## CONSUMES + gEfiSmmCommunicationProtocolGuid ## UNDEFINED # SMM Communication ACPI Table GUID + gEfiAcpiTableProtocolGuid ## CONSUMES + +[Pcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemId ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemTableId ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemRevision ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorId ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorRevision ## CONSUMES + +[Depex] + gEfiSmmSwDispatch2ProtocolGuid AND + gEfiAcpiTableProtocolGuid + +[UserExtensions.TianoCore."ExtraFiles"] + PiSmmCommunicationSmmExtra.uni diff --git a/UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationSmm.uni b/UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationSmm.uni new file mode 100644 index 0000000000000000000000000000000000000000..0ce635815c6b4b3257e5e107cc3cb846d570c1e7 GIT binary patch literal 3004 zcmd6pTW=FF5QXO%iT_}wFMvqG?Fk`7LQ{xSGx4H%12Ry-E*|E)RZbx?4?l7vkuC@6l_JJqZYg^fZ=c_G| z9NW;=v@3dr%*0a0&d`!Fy0#OS3XCl+qd&yLoWD4CR9bnR_6D{imOdIrjWws zZ|2%_%-eYWK8j!y_A1XUX(#MQf5q+w*0KZlVrHjEj5nx*ojckw-@sgoC(l?dee%zc zci}7KLwP)-U-qdYAX_7(0#V6me@Dl9eB7R@sVAW5H5YT>ibKP zI>%z_)`m8{)FrIP$SL01`_7n{x?5x~E?txuQmHtyKDqE)P zUop9dr|#1}u}AipH{iv*_skyh-@e?zoPTLZ(V=gViSk&(b1al}D@KZ&;-9+rCRVc- z*0i3z-1u=<9z|YG-G^=q{oGH`gAsM)<2I^o&qQyEpE1|P-RJ}D zbzSnTn6xGq&%J_+W6`^kPuj*eUJ(Gzx!$z~rZ$;fJyIzUz{KhwTrM#zZrsMVC-kKzDo3_sSpoMT|=Dh}hQML~)mIZuX1v^tRq3 z63^)|_;l+i-@?Spa<%%mcZw=F@-yY;J4Jwps>QeUE)ma+;uaFmwB2{zc&g~U`TsYG Hm=!+()}`rs literal 0 HcmV?d00001 diff --git a/UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationSmmExtra.uni b/UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationSmmExtra.uni new file mode 100644 index 0000000000000000000000000000000000000000..60a7d627dab28774284412ae1adc735204db53dd GIT binary patch literal 1392 zcmZXUTW`}q5QXO%iT_}Q7eH;o?Fk`7(ipI4F3Lr~QN3p@jsx^bN!uy5>@y|%ZE z&P(r|oiR>w%r#?G$ZY4|iff&jCJdD!UIAOoGPvw{GrM!{b^Bl~8`#HEjf&j}Ml0XX zj{FpqjGb*jDfV|DW8wY`)>3ZgbH`kZh=^FJ-ipy0v zZdY&+qBsP-RBMl~T~Faz)YZ8}CSAqA+dM_x?^91$C95xz=^|pK+p%N9ym1OyNGK>rSiJLAl{AG%2k1^VMQl_35LYec{`* z4t|2B5vt0Lh$eK}m{IIXkFAT1iB|~KDI|1uOvccWdyLf4`qr?*6>1IJa$nwA$t|+) z%!^mgE6Q(DNzA&$6HtZG^XdaUaaT+=M`S5SRYTTia<%d&_8T)|u0Ju(tAt&|_M^n9 z&=a)i(^sn5wtC62(ogqN!{drQD?3NGiS8C@ca^K#2W3$1;0o*>sAKSBa=NhWFbX*O zSA=nkU3$l;3(m Date: Tue, 17 Nov 2015 04:55:54 +0000 Subject: [PATCH 114/525] UefiCpuPkg: Add PlatformSecLib Add PlatformSecLib class and PlatformSecLibNull instance that is used by the SecCore. PlatformSecLibNull should not be used in a platform build. Instead, it should be used as a template for implementing a platform specific instance of the PlatformSecLib library class. (Sync patch r18635 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Michael Kinney Reviewed-by: Jeff Fan git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18830 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/Include/Library/PlatformSecLib.h | 70 ++++++++++++++ .../PlatformSecLibNull/PlatformSecLibNull.c | 90 ++++++++++++++++++ .../PlatformSecLibNull/PlatformSecLibNull.inf | 37 +++++++ .../PlatformSecLibNull/PlatformSecLibNull.uni | Bin 0 -> 1644 bytes 4 files changed, 197 insertions(+) create mode 100644 UefiCpuPkg/Include/Library/PlatformSecLib.h create mode 100644 UefiCpuPkg/Library/PlatformSecLibNull/PlatformSecLibNull.c create mode 100644 UefiCpuPkg/Library/PlatformSecLibNull/PlatformSecLibNull.inf create mode 100644 UefiCpuPkg/Library/PlatformSecLibNull/PlatformSecLibNull.uni diff --git a/UefiCpuPkg/Include/Library/PlatformSecLib.h b/UefiCpuPkg/Include/Library/PlatformSecLib.h new file mode 100644 index 000000000000..0af7781771b5 --- /dev/null +++ b/UefiCpuPkg/Include/Library/PlatformSecLib.h @@ -0,0 +1,70 @@ +/** @file +This library class defines interface for platform to perform platform +specific initialization in SEC phase. + +Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __PLATFORM_SEC_LIB_H__ +#define __PLATFORM_SEC_LIB_H__ + +/** + A developer supplied function to perform platform specific operations. + + It's a developer supplied function to perform any operations appropriate to a + given platform. It's invoked just before passing control to PEI core by SEC + core. Platform developer may modify the SecCoreData passed to PEI Core. + It returns a platform specific PPI list that platform wishes to pass to PEI core. + The Generic SEC core module will merge this list to join the final list passed to + PEI core. + + @param SecCoreData The same parameter as passing to PEI core. It + could be overridden by this function. + + @return The platform specific PPI list to be passed to PEI core or + NULL if there is no need of such platform specific PPI list. + +**/ +EFI_PEI_PPI_DESCRIPTOR * +EFIAPI +SecPlatformMain ( + IN OUT EFI_SEC_PEI_HAND_OFF *SecCoreData + ); + +/** + This interface conveys state information out of the Security (SEC) phase into PEI. + + @param PeiServices Pointer to the PEI Services Table. + @param StructureSize Pointer to the variable describing size of the input buffer. + @param PlatformInformationRecord Pointer to the EFI_SEC_PLATFORM_INFORMATION_RECORD. + + @retval EFI_SUCCESS The data was successfully returned. + @retval EFI_BUFFER_TOO_SMALL The buffer was too small. + +**/ +EFI_STATUS +EFIAPI +SecPlatformInformation ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN OUT UINT64 *StructureSize, + OUT EFI_SEC_PLATFORM_INFORMATION_RECORD *PlatformInformationRecord + ); + +/** + This interface disables temporary memory in SEC Phase. +**/ +VOID +EFIAPI +SecPlatformDisableTemporaryMemory ( + VOID + ); + +#endif diff --git a/UefiCpuPkg/Library/PlatformSecLibNull/PlatformSecLibNull.c b/UefiCpuPkg/Library/PlatformSecLibNull/PlatformSecLibNull.c new file mode 100644 index 000000000000..ad3e9090c63f --- /dev/null +++ b/UefiCpuPkg/Library/PlatformSecLibNull/PlatformSecLibNull.c @@ -0,0 +1,90 @@ +/** @file +Null instance of Platform Sec Lib. + +Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include + +#include + +/** + A developer supplied function to perform platform specific operations. + + It's a developer supplied function to perform any operations appropriate to a + given platform. It's invoked just before passing control to PEI core by SEC + core. Platform developer may modify the SecCoreData passed to PEI Core. + It returns a platform specific PPI list that platform wishes to pass to PEI core. + The Generic SEC core module will merge this list to join the final list passed to + PEI core. + + @param SecCoreData The same parameter as passing to PEI core. It + could be overridden by this function. + + @return The platform specific PPI list to be passed to PEI core or + NULL if there is no need of such platform specific PPI list. + +**/ +EFI_PEI_PPI_DESCRIPTOR * +EFIAPI +SecPlatformMain ( + IN OUT EFI_SEC_PEI_HAND_OFF *SecCoreData + ) +{ + return NULL; +} + +/** + This interface conveys state information out of the Security (SEC) phase into PEI. + + @param PeiServices Pointer to the PEI Services Table. + @param StructureSize Pointer to the variable describing size of the input buffer. + @param PlatformInformationRecord Pointer to the EFI_SEC_PLATFORM_INFORMATION_RECORD. + + @retval EFI_SUCCESS The data was successfully returned. + @retval EFI_BUFFER_TOO_SMALL The buffer was too small. + +**/ +EFI_STATUS +EFIAPI +SecPlatformInformation ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN OUT UINT64 *StructureSize, + OUT EFI_SEC_PLATFORM_INFORMATION_RECORD *PlatformInformationRecord + ) +{ + return EFI_SUCCESS; +} + +/** + This interface disables temporary memory in SEC Phase. +**/ +VOID +EFIAPI +SecPlatformDisableTemporaryMemory ( + VOID + ) +{ +} + +/** + This function provides dummy function so that SecCore can pass build + validation. All real platform library instances need to implement the real + entry point in assembly. +**/ +VOID +EFIAPI +_ModuleEntryPoint ( + VOID + ) +{ + return; +} diff --git a/UefiCpuPkg/Library/PlatformSecLibNull/PlatformSecLibNull.inf b/UefiCpuPkg/Library/PlatformSecLibNull/PlatformSecLibNull.inf new file mode 100644 index 000000000000..3f8868adee3e --- /dev/null +++ b/UefiCpuPkg/Library/PlatformSecLibNull/PlatformSecLibNull.inf @@ -0,0 +1,37 @@ +## @file +# Library functions for PlatformSecLib. +# +# Null instance of Platform Sec Lib. +# +# Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PlatformSecLibNull + MODULE_UNI_FILE = PlatformSecLibNull.uni + FILE_GUID = 6695974D-968C-420b-80B9-7870CD20118F + MODULE_TYPE = SEC + VERSION_STRING = 1.0 + LIBRARY_CLASS = PlatformSecLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + PlatformSecLibNull.c + +[Packages] + MdePkg/MdePkg.dec + UefiCpuPkg/UefiCpuPkg.dec diff --git a/UefiCpuPkg/Library/PlatformSecLibNull/PlatformSecLibNull.uni b/UefiCpuPkg/Library/PlatformSecLibNull/PlatformSecLibNull.uni new file mode 100644 index 0000000000000000000000000000000000000000..352ede7190b859c7332adf9717d285c0fea895d8 GIT binary patch literal 1644 zcmb`H-EPxB5QXO&iFa6~H-K6Pkhnnz;ZOq>kVK6m;0ifOlSXRl$}xq$Jn)@e|CBTc zA&_OScV_m?nKNVm_};g^IqnBs&R*Ek)^={EcGvD;mG2#vnU$7vU$bA@7rU^zRoDyO zw%%6YbvEW~j%SIdw2e(bn%4+Xi`iih!8+%1Uw6IUH6rkKjbT#HKuYKq*!MKET z3Hr*;KzDWz^!u!j?V&xgCw9ntO3sR$;-NDor}R`Mp~eVLTr=&^RC&p{Eq7^GJQo(( zGaJ~6J>OGp28XrR>yr2aPRg+XMO80YD~;kUh|CYJ^K_*9ja>0u%=Afl()nyJ+&cgg1tlNx{xy22@w;IJmO6gt!Ix_ zxI*o*4*Xub!UABXEaxUnP{vXorGbkg@PeDr9 z#nc@ Date: Tue, 17 Nov 2015 04:56:43 +0000 Subject: [PATCH 115/525] UefiCpuPkg: Add SecCore module Add SecCore module that uses the PlatformSecLib class for platform specific actions. The SecCore module also uses a new PCD to configure the size of the stack used in the SEC phase. If the stack size PCD is set to 0, the stack is configured to use half of the available temporary RAM. (Sync patch r18636 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Michael Kinney Reviewed-by: Jeff Fan git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18831 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/SecCore/FindPeiCore.c | 198 +++++++++++++++++ UefiCpuPkg/SecCore/Ia32/ResetVec.asm16 | 106 +++++++++ UefiCpuPkg/SecCore/Ia32/ResetVec.nasmb | 103 +++++++++ UefiCpuPkg/SecCore/SecCore.inf | 72 ++++++ UefiCpuPkg/SecCore/SecCore.uni | Bin 0 -> 2908 bytes UefiCpuPkg/SecCore/SecCoreExtra.uni | Bin 0 -> 1316 bytes UefiCpuPkg/SecCore/SecMain.c | 295 +++++++++++++++++++++++++ UefiCpuPkg/SecCore/SecMain.h | 109 +++++++++ 8 files changed, 883 insertions(+) create mode 100644 UefiCpuPkg/SecCore/FindPeiCore.c create mode 100644 UefiCpuPkg/SecCore/Ia32/ResetVec.asm16 create mode 100644 UefiCpuPkg/SecCore/Ia32/ResetVec.nasmb create mode 100644 UefiCpuPkg/SecCore/SecCore.inf create mode 100644 UefiCpuPkg/SecCore/SecCore.uni create mode 100644 UefiCpuPkg/SecCore/SecCoreExtra.uni create mode 100644 UefiCpuPkg/SecCore/SecMain.c create mode 100644 UefiCpuPkg/SecCore/SecMain.h diff --git a/UefiCpuPkg/SecCore/FindPeiCore.c b/UefiCpuPkg/SecCore/FindPeiCore.c new file mode 100644 index 000000000000..60ccaa9667c7 --- /dev/null +++ b/UefiCpuPkg/SecCore/FindPeiCore.c @@ -0,0 +1,198 @@ +/** @file + Locate the entry point for the PEI Core + + Copyright (c) 2008 - 2011, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include + +#include "SecMain.h" + +/** + Find core image base. + + @param BootFirmwareVolumePtr Point to the boot firmware volume. + @param SecCoreImageBase The base address of the SEC core image. + @param PeiCoreImageBase The base address of the PEI core image. + +**/ +EFI_STATUS +EFIAPI +FindImageBase ( + IN EFI_FIRMWARE_VOLUME_HEADER *BootFirmwareVolumePtr, + OUT EFI_PHYSICAL_ADDRESS *SecCoreImageBase, + OUT EFI_PHYSICAL_ADDRESS *PeiCoreImageBase + ) +{ + EFI_PHYSICAL_ADDRESS CurrentAddress; + EFI_PHYSICAL_ADDRESS EndOfFirmwareVolume; + EFI_FFS_FILE_HEADER *File; + UINT32 Size; + EFI_PHYSICAL_ADDRESS EndOfFile; + EFI_COMMON_SECTION_HEADER *Section; + EFI_PHYSICAL_ADDRESS EndOfSection; + + *SecCoreImageBase = 0; + *PeiCoreImageBase = 0; + + CurrentAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) BootFirmwareVolumePtr; + EndOfFirmwareVolume = CurrentAddress + BootFirmwareVolumePtr->FvLength; + + // + // Loop through the FFS files in the Boot Firmware Volume + // + for (EndOfFile = CurrentAddress + BootFirmwareVolumePtr->HeaderLength; ; ) { + + CurrentAddress = (EndOfFile + 7) & 0xfffffffffffffff8ULL; + if (CurrentAddress > EndOfFirmwareVolume) { + return EFI_NOT_FOUND; + } + + File = (EFI_FFS_FILE_HEADER*)(UINTN) CurrentAddress; + if (IS_FFS_FILE2 (File)) { + Size = FFS_FILE2_SIZE (File); + if (Size <= 0x00FFFFFF) { + return EFI_NOT_FOUND; + } + } else { + Size = FFS_FILE_SIZE (File); + if (Size < sizeof (EFI_FFS_FILE_HEADER)) { + return EFI_NOT_FOUND; + } + } + + EndOfFile = CurrentAddress + Size; + if (EndOfFile > EndOfFirmwareVolume) { + return EFI_NOT_FOUND; + } + + // + // Look for SEC Core / PEI Core files + // + if (File->Type != EFI_FV_FILETYPE_SECURITY_CORE && + File->Type != EFI_FV_FILETYPE_PEI_CORE) { + continue; + } + + // + // Loop through the FFS file sections within the FFS file + // + if (IS_FFS_FILE2 (File)) { + EndOfSection = (EFI_PHYSICAL_ADDRESS) (UINTN) ((UINT8 *) File + sizeof (EFI_FFS_FILE_HEADER2)); + } else { + EndOfSection = (EFI_PHYSICAL_ADDRESS) (UINTN) ((UINT8 *) File + sizeof (EFI_FFS_FILE_HEADER)); + } + for (;;) { + CurrentAddress = (EndOfSection + 3) & 0xfffffffffffffffcULL; + Section = (EFI_COMMON_SECTION_HEADER*)(UINTN) CurrentAddress; + + if (IS_SECTION2 (Section)) { + Size = SECTION2_SIZE (Section); + if (Size <= 0x00FFFFFF) { + return EFI_NOT_FOUND; + } + } else { + Size = SECTION_SIZE (Section); + if (Size < sizeof (EFI_COMMON_SECTION_HEADER)) { + return EFI_NOT_FOUND; + } + } + + EndOfSection = CurrentAddress + Size; + if (EndOfSection > EndOfFile) { + return EFI_NOT_FOUND; + } + + // + // Look for executable sections + // + if (Section->Type == EFI_SECTION_PE32 || Section->Type == EFI_SECTION_TE) { + if (File->Type == EFI_FV_FILETYPE_SECURITY_CORE) { + if (IS_SECTION2 (Section)) { + *SecCoreImageBase = (PHYSICAL_ADDRESS) (UINTN) ((UINT8 *) Section + sizeof (EFI_COMMON_SECTION_HEADER2)); + } else { + *SecCoreImageBase = (PHYSICAL_ADDRESS) (UINTN) ((UINT8 *) Section + sizeof (EFI_COMMON_SECTION_HEADER)); + } + } else { + if (IS_SECTION2 (Section)) { + *PeiCoreImageBase = (PHYSICAL_ADDRESS) (UINTN) ((UINT8 *) Section + sizeof (EFI_COMMON_SECTION_HEADER2)); + } else { + *PeiCoreImageBase = (PHYSICAL_ADDRESS) (UINTN) ((UINT8 *) Section + sizeof (EFI_COMMON_SECTION_HEADER)); + } + } + break; + } + } + + // + // Both SEC Core and PEI Core images found + // + if (*SecCoreImageBase != 0 && *PeiCoreImageBase != 0) { + return EFI_SUCCESS; + } + } +} + +/** + Find and return Pei Core entry point. + + It also find SEC and PEI Core file debug information. It will report them if + remote debug is enabled. + + @param BootFirmwareVolumePtr Point to the boot firmware volume. + @param PeiCoreEntryPoint The entry point of the PEI core. + +**/ +VOID +EFIAPI +FindAndReportEntryPoints ( + IN EFI_FIRMWARE_VOLUME_HEADER *BootFirmwareVolumePtr, + OUT EFI_PEI_CORE_ENTRY_POINT *PeiCoreEntryPoint + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS SecCoreImageBase; + EFI_PHYSICAL_ADDRESS PeiCoreImageBase; + PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + + // + // Find SEC Core and PEI Core image base + // + Status = FindImageBase (BootFirmwareVolumePtr, &SecCoreImageBase, &PeiCoreImageBase); + ASSERT_EFI_ERROR (Status); + + ZeroMem ((VOID *) &ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT)); + // + // Report SEC Core debug information when remote debug is enabled + // + ImageContext.ImageAddress = SecCoreImageBase; + ImageContext.PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageContext.ImageAddress); + PeCoffLoaderRelocateImageExtraAction (&ImageContext); + + // + // Report PEI Core debug information when remote debug is enabled + // + ImageContext.ImageAddress = PeiCoreImageBase; + ImageContext.PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageContext.ImageAddress); + PeCoffLoaderRelocateImageExtraAction (&ImageContext); + + // + // Find PEI Core entry point + // + Status = PeCoffLoaderGetEntryPoint ((VOID *) (UINTN) PeiCoreImageBase, (VOID**) PeiCoreEntryPoint); + if (EFI_ERROR (Status)) { + *PeiCoreEntryPoint = 0; + } + + return; +} diff --git a/UefiCpuPkg/SecCore/Ia32/ResetVec.asm16 b/UefiCpuPkg/SecCore/Ia32/ResetVec.asm16 new file mode 100644 index 000000000000..d90613c4d038 --- /dev/null +++ b/UefiCpuPkg/SecCore/Ia32/ResetVec.asm16 @@ -0,0 +1,106 @@ +;------------------------------------------------------------------------------ +; +; Copyright (c) 2014, Intel Corporation. All rights reserved.
+; This program and the accompanying materials +; are licensed and made available under the terms and conditions of the BSD License +; which accompanies this distribution. The full text of the license may be found at +; http://opensource.org/licenses/bsd-license.php. +; +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +; +; Module Name: +; +; ResetVec.asm +; +; Abstract: +; +; Reset Vector Data structure +; This structure is located at 0xFFFFFFC0 +; +;------------------------------------------------------------------------------ + + .model tiny + .686p + .stack 0h + .code + +; +; The layout of this file is fixed. The build tool makes assumption of the layout. +; + + ORG 0h +; +; Reserved +; +ReservedData DD 0eeeeeeeeh, 0eeeeeeeeh + + ORG 10h +; +; This is located at 0xFFFFFFD0h +; + mov di, "AP" + jmp ApStartup + + ORG 20h +; +; Pointer to the entry point of the PEI core +; It is located at 0xFFFFFFE0, and is fixed up by some build tool +; So if the value 8..1 appears in the final FD image, tool failure occurs. +; +PeiCoreEntryPoint DD 87654321h + +; +; This is the handler for all kinds of exceptions. Since it's for debugging +; purpose only, nothing except a dead loop would be done here. Developers could +; analyze the cause of the exception if a debugger had been attached. +; +InterruptHandler PROC + jmp $ + iret +InterruptHandler ENDP + + ORG 30h +; +; For IA32, the reset vector must be at 0xFFFFFFF0, i.e., 4G-16 byte +; Execution starts here upon power-on/platform-reset. +; +ResetHandler: + nop + nop +ApStartup: + ; + ; Jmp Rel16 instruction + ; Use machine code directly in case of the assembler optimization + ; SEC entry point relative address will be fixed up by some build tool. + ; + ; Typically, SEC entry point is the function _ModuleEntryPoint() defined in + ; SecEntry.asm + ; + DB 0e9h + DW -3 + + + ORG 38h +; +; Ap reset vector segment address is at 0xFFFFFFF8 +; This will be fixed up by some build tool, +; so if the value 1..8 appears in the final FD image, +; tool failure occurs +; +ApSegAddress dd 12345678h + + ORG 3ch +; +; BFV Base is at 0xFFFFFFFC +; This will be fixed up by some build tool, +; so if the value 1..8 appears in the final FD image, +; tool failure occurs. +; +BfvBase DD 12345678h + +; +; Nothing can go here, otherwise the layout of this file would change. +; + + END diff --git a/UefiCpuPkg/SecCore/Ia32/ResetVec.nasmb b/UefiCpuPkg/SecCore/Ia32/ResetVec.nasmb new file mode 100644 index 000000000000..2fcdc85e47aa --- /dev/null +++ b/UefiCpuPkg/SecCore/Ia32/ResetVec.nasmb @@ -0,0 +1,103 @@ +;------------------------------------------------------------------------------ +; +; Copyright (c) 2014, Intel Corporation. All rights reserved.
+; This program and the accompanying materials +; are licensed and made available under the terms and conditions of the BSD License +; which accompanies this distribution. The full text of the license may be found at +; http://opensource.org/licenses/bsd-license.php. +; +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +; +; Module Name: +; +; ResetVec.nasmb +; +; Abstract: +; +; Reset Vector Data structure +; This structure is located at 0xFFFFFFC0 +; +;------------------------------------------------------------------------------ + +; .stack 0x0 +; SECTION .text +USE16 + +; +; The layout of this file is fixed. The build tool makes assumption of the layout. +; + + ORG 0h +; +; Reserved +; +ReservedData: DD 0eeeeeeeeh, 0eeeeeeeeh + + TIMES 0x10-($-$$) DB 0 +; +; This is located at 0xFFFFFFD0h +; + mov di, "PA" + jmp ApStartup + + TIMES 0x20-($-$$) DB 0 +; +; Pointer to the entry point of the PEI core +; It is located at 0xFFFFFFE0, and is fixed up by some build tool +; So if the value 8..1 appears in the final FD image, tool failure occurs. +; +PeiCoreEntryPoint: DD 87654321h + +; +; This is the handler for all kinds of exceptions. Since it's for debugging +; purpose only, nothing except a dead loop would be done here. Developers could +; analyze the cause of the exception if a debugger had been attached. +; +global ASM_PFX(InterruptHandler) +ASM_PFX(InterruptHandler): + jmp $ + iret + + TIMES 0x30-($-$$) DB 0 +; +; For IA32, the reset vector must be at 0xFFFFFFF0, i.e., 4G-16 byte +; Execution starts here upon power-on/platform-reset. +; +ResetHandler: + nop + nop +ApStartup: + ; + ; Jmp Rel16 instruction + ; Use machine code directly in case of the assembler optimization + ; SEC entry point relative address will be fixed up by some build tool. + ; + ; Typically, SEC entry point is the function _ModuleEntryPoint() defined in + ; SecEntry.asm + ; + DB 0e9h + DW -3 + + + TIMES 0x38-($-$$) DB 0 +; +; Ap reset vector segment address is at 0xFFFFFFF8 +; This will be fixed up by some build tool, +; so if the value 1..8 appears in the final FD image, +; tool failure occurs +; +ApSegAddress: dd 12345678h + + TIMES 0x3c-($-$$) DB 0 +; +; BFV Base is at 0xFFFFFFFC +; This will be fixed up by some build tool, +; so if the value 1..8 appears in the final FD image, +; tool failure occurs. +; +BfvBase: DD 12345678h + +; +; Nothing can go here, otherwise the layout of this file would change. +; diff --git a/UefiCpuPkg/SecCore/SecCore.inf b/UefiCpuPkg/SecCore/SecCore.inf new file mode 100644 index 000000000000..bf08a4cc49a5 --- /dev/null +++ b/UefiCpuPkg/SecCore/SecCore.inf @@ -0,0 +1,72 @@ +## @file +# SecCore module that implements the SEC phase. +# +# This is the first module taking control of the platform upon power-on/reset. +# It implements the first phase of the security phase. The entry point function is +# _ModuleEntryPoint in PlatformSecLib. The entry point function will switch to +# protected mode, setup flat memory model, enable temporary memory and +# call into SecStartup(). +# +# Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = SecCore + MODULE_UNI_FILE = SecCore.uni + FILE_GUID = 1BA0062E-C779-4582-8566-336AE8F78F09 + MODULE_TYPE = SEC + VERSION_STRING = 1.0 + + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + SecMain.c + SecMain.h + FindPeiCore.c + +[Sources.IA32] + Ia32/ResetVec.asm16 | MSFT + Ia32/ResetVec.asm16 | INTEL + Ia32/ResetVec.nasmb | GCC + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + UefiCpuPkg/UefiCpuPkg.dec + +[LibraryClasses] + BaseMemoryLib + DebugLib + BaseLib + PlatformSecLib + PcdLib + DebugAgentLib + UefiCpuLib + PeCoffGetEntryPointLib + PeCoffExtraActionLib + CpuExceptionHandlerLib + ReportStatusCodeLib + +[Ppis] + gEfiSecPlatformInformationPpiGuid ## PRODUCES + gEfiTemporaryRamDonePpiGuid ## PRODUCES + +[Pcd] + gUefiCpuPkgTokenSpaceGuid.PcdPeiTemporaryRamStackSize ## CONSUMES + +[UserExtensions.TianoCore."ExtraFiles"] + SecCoreExtra.uni diff --git a/UefiCpuPkg/SecCore/SecCore.uni b/UefiCpuPkg/SecCore/SecCore.uni new file mode 100644 index 0000000000000000000000000000000000000000..dff756a3b322aea1a748929138498bb8d5e81e91 GIT binary patch literal 2908 zcmd6p?Q0W35XR@T;Qw%>Us`Ds74d_JnA%f=+Jq!U{Un!{rp3IJOKR;uul}Cd-0d~g zN(({>*}I*coq6V&*}47wt6>dG_&?&8*lRnsQ=8h@9@+z>TI(?z+8bL~&Rb$L-bQxr zT8XXf#4^T&eKR|A=?uL&vL#ZjYgf-wY$Rw%e~GMK`iQ>zte*P5Fc!OoDn~9qoBlKV z&g$GItPQ~?&pFR2^9Aul3_>TY$H;T+Bt&uMJA`Xt7of^*&m|4s#*TAUL7G_0G29$$ z6>W@n6OA|+f*=R|$}T|@b?eN;g_sLm=4*|G$0{C<**nL=3W=gt29_nKiG8zA$cs#+ zYhEs`gH(KloM~TYgO`x;k7x~u{Vqr@*gN$MEMZmg4T(mXSX2<65&Hs}c+faPBV>1M zyS$5`mFGy&hTKVG>{@}5LVxNz#8n1rRj|BCQ<=??7W&oQ8Tz9Nq9J+#cVK9NmB2<1 zYqAmWY}-zyDq{WWl$?<%<#a;C;&_|rc6dIu$NZl2wzr-=v1g9D<=GfJU*Vh;n2X#h z3(YmMXj|v2sM6ei5bX$5FKyqt_Nt63qKl_1Fh5~;215y>c!(z@1GCPO*wfl2@q`mL zV=i8WLR?iVPW*`XDQiRC=AJ>>E$nOe$aOOCX6PxaMZQ$eTFom+g0C5tqLpyUN9->6 z(dyN+zE9o`kgAF!mdM40cbZU@o6(+vq3B(q56PFhkD?w>k%eF7C7utR$WT2({S&QC zR9Bf%EoXkN2hNH5Qs6+buF4E1UP&u*@xptuYAmoT{oLcLvp1*a8XN2{kqp2-qUx@C zuVdwef5A!dR6OtL*6IsgYuh`P#QmAL^^mdYV~wZm%6g6GzRxw=EwLr`nRVf6yGPBNcoMQhyq*Iq&tseLK!MC&cM=ulVkd2nqP(6_YV*v08qSvlbZ^}y2g z?%Zbo5tdSBP2vtKO_=I~SbcTBN&-LIR${l5|1-8@@ak;DZf0k;u^cP13#^%?L}m69&)j47 zoMyJRh3(jF$otbni@s&L}_R^BZc zI?b_5CZX2KS(hkcrpT<)M@nqC>pHK)J)g6`IO0-sy>~5Uy#MVsgM$#oA?T%AJND{& z3eUgqB{JzM{@0v@I}+<3L_K76tV~ezK-9Fz-xL~%Q$1f1_wtYX%np2 zm7Z9SHO5~f)VGi@*)b6#NA6>3qV;aD3RkEN){gJBJE^!u_LXz->U%})+f)*>9{vPW zVf4NFke#^8rLanr{LcD?6EW96F)pfvE@Jyu;ne5}S`3&g)jYRm#j(~; z-=3EH<$F?1j=m=P{z$vaLfruWTzu=}7+z>kUP!Lo}LaP(gh#x3i@Cq`3nO7zGh X8s6_2HNsa!GudS>=02BKs4JX5;;_nz literal 0 HcmV?d00001 diff --git a/UefiCpuPkg/SecCore/SecMain.c b/UefiCpuPkg/SecCore/SecMain.c new file mode 100644 index 000000000000..ec252cf719f5 --- /dev/null +++ b/UefiCpuPkg/SecCore/SecMain.c @@ -0,0 +1,295 @@ +/** @file + C functions in SEC + + Copyright (c) 2008 - 2015, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "SecMain.h" + +EFI_PEI_TEMPORARY_RAM_DONE_PPI gSecTemporaryRamDonePpi = { + SecTemporaryRamDone +}; + +EFI_SEC_PLATFORM_INFORMATION_PPI mSecPlatformInformationPpi = { SecPlatformInformation }; + +EFI_PEI_PPI_DESCRIPTOR mPeiSecPlatformInformationPpi[] = { + { + EFI_PEI_PPI_DESCRIPTOR_PPI, + &gEfiTemporaryRamDonePpiGuid, + &gSecTemporaryRamDonePpi + }, + { + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiSecPlatformInformationPpiGuid, + &mSecPlatformInformationPpi + } +}; + +// +// These are IDT entries pointing to 10:FFFFFFE4h. +// +UINT64 mIdtEntryTemplate = 0xffff8e000010ffe4ULL; + +/** + Caller provided function to be invoked at the end of InitializeDebugAgent(). + + Entry point to the C language phase of SEC. After the SEC assembly + code has initialized some temporary memory and set up the stack, + the control is transferred to this function. + + @param[in] Context The first input parameter of InitializeDebugAgent(). + +**/ +VOID +EFIAPI +SecStartupPhase2( + IN VOID *Context + ); + +/** + + Entry point to the C language phase of SEC. After the SEC assembly + code has initialized some temporary memory and set up the stack, + the control is transferred to this function. + + + @param SizeOfRam Size of the temporary memory available for use. + @param TempRamBase Base address of temporary ram + @param BootFirmwareVolume Base address of the Boot Firmware Volume. +**/ +VOID +EFIAPI +SecStartup ( + IN UINT32 SizeOfRam, + IN UINT32 TempRamBase, + IN VOID *BootFirmwareVolume + ) +{ + EFI_SEC_PEI_HAND_OFF SecCoreData; + IA32_DESCRIPTOR IdtDescriptor; + SEC_IDT_TABLE IdtTableInStack; + UINT32 Index; + UINT32 PeiStackSize; + EFI_STATUS Status; + + // + // Report Status Code to indicate entering SEC core + // + REPORT_STATUS_CODE ( + EFI_PROGRESS_CODE, + EFI_SOFTWARE_SEC | EFI_SW_SEC_PC_ENTRY_POINT + ); + + PeiStackSize = PcdGet32 (PcdPeiTemporaryRamStackSize); + if (PeiStackSize == 0) { + PeiStackSize = (SizeOfRam >> 1); + } + + ASSERT (PeiStackSize < SizeOfRam); + + // + // Process all libraries constructor function linked to SecCore. + // + ProcessLibraryConstructorList (); + + // + // Initialize floating point operating environment + // to be compliant with UEFI spec. + // + InitializeFloatingPointUnits (); + + // |-------------------|----> + // |IDT Table | + // |-------------------| + // |PeiService Pointer | PeiStackSize + // |-------------------| + // | | + // | Stack | + // |-------------------|----> + // | | + // | | + // | Heap | PeiTemporayRamSize + // | | + // | | + // |-------------------|----> TempRamBase + + IdtTableInStack.PeiService = 0; + for (Index = 0; Index < SEC_IDT_ENTRY_COUNT; Index ++) { + CopyMem ((VOID*)&IdtTableInStack.IdtTable[Index], (VOID*)&mIdtEntryTemplate, sizeof (UINT64)); + } + + IdtDescriptor.Base = (UINTN) &IdtTableInStack.IdtTable; + IdtDescriptor.Limit = (UINT16)(sizeof (IdtTableInStack.IdtTable) - 1); + + AsmWriteIdtr (&IdtDescriptor); + + // + // Setup the default exception handlers + // + Status = InitializeCpuExceptionHandlers (NULL); + ASSERT_EFI_ERROR (Status); + + // + // Update the base address and length of Pei temporary memory + // + SecCoreData.DataSize = (UINT16) sizeof (EFI_SEC_PEI_HAND_OFF); + SecCoreData.BootFirmwareVolumeBase = BootFirmwareVolume; + SecCoreData.BootFirmwareVolumeSize = (UINTN)(0x100000000ULL - (UINTN) BootFirmwareVolume); + SecCoreData.TemporaryRamBase = (VOID*)(UINTN) TempRamBase; + SecCoreData.TemporaryRamSize = SizeOfRam; + SecCoreData.PeiTemporaryRamBase = SecCoreData.TemporaryRamBase; + SecCoreData.PeiTemporaryRamSize = SizeOfRam - PeiStackSize; + SecCoreData.StackBase = (VOID*)(UINTN)(TempRamBase + SecCoreData.PeiTemporaryRamSize); + SecCoreData.StackSize = PeiStackSize; + + // + // Initialize Debug Agent to support source level debug in SEC/PEI phases before memory ready. + // + InitializeDebugAgent (DEBUG_AGENT_INIT_PREMEM_SEC, &SecCoreData, SecStartupPhase2); +} + +/** + Caller provided function to be invoked at the end of InitializeDebugAgent(). + + Entry point to the C language phase of SEC. After the SEC assembly + code has initialized some temporary memory and set up the stack, + the control is transferred to this function. + + @param[in] Context The first input parameter of InitializeDebugAgent(). + +**/ +VOID +EFIAPI +SecStartupPhase2( + IN VOID *Context + ) +{ + EFI_SEC_PEI_HAND_OFF *SecCoreData; + EFI_PEI_PPI_DESCRIPTOR *PpiList; + UINT32 Index; + EFI_PEI_PPI_DESCRIPTOR *AllSecPpiList; + EFI_PEI_CORE_ENTRY_POINT PeiCoreEntryPoint; + + SecCoreData = (EFI_SEC_PEI_HAND_OFF *) Context; + AllSecPpiList = (EFI_PEI_PPI_DESCRIPTOR *) SecCoreData->PeiTemporaryRamBase; + // + // Find Pei Core entry point. It will report SEC and Pei Core debug information if remote debug + // is enabled. + // + FindAndReportEntryPoints ((EFI_FIRMWARE_VOLUME_HEADER *) SecCoreData->BootFirmwareVolumeBase, &PeiCoreEntryPoint); + if (PeiCoreEntryPoint == NULL) + { + CpuDeadLoop (); + } + + // + // Perform platform specific initialization before entering PeiCore. + // + PpiList = SecPlatformMain (SecCoreData); + if (PpiList != NULL) { + // + // Remove the terminal flag from the terminal PPI + // + CopyMem (AllSecPpiList, mPeiSecPlatformInformationPpi, sizeof (mPeiSecPlatformInformationPpi)); + Index = sizeof (mPeiSecPlatformInformationPpi) / sizeof (EFI_PEI_PPI_DESCRIPTOR) - 1; + AllSecPpiList[Index].Flags = AllSecPpiList[Index].Flags & (~EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST); + + // + // Append the platform additional PPI list + // + Index += 1; + while (((PpiList->Flags & EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) != EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST)) { + CopyMem (&AllSecPpiList[Index], PpiList, sizeof (EFI_PEI_PPI_DESCRIPTOR)); + Index++; + PpiList++; + } + + // + // Add the terminal PPI + // + CopyMem (&AllSecPpiList[Index ++], PpiList, sizeof (EFI_PEI_PPI_DESCRIPTOR)); + + // + // Set PpiList to the total PPI + // + PpiList = AllSecPpiList; + + // + // Adjust PEI TEMP RAM Range. + // + ASSERT (SecCoreData->PeiTemporaryRamSize > Index * sizeof (EFI_PEI_PPI_DESCRIPTOR)); + SecCoreData->PeiTemporaryRamBase = (VOID *)((UINTN) SecCoreData->PeiTemporaryRamBase + Index * sizeof (EFI_PEI_PPI_DESCRIPTOR)); + SecCoreData->PeiTemporaryRamSize = SecCoreData->PeiTemporaryRamSize - Index * sizeof (EFI_PEI_PPI_DESCRIPTOR); + } else { + // + // No addition PPI, PpiList directly point to the common PPI list. + // + PpiList = &mPeiSecPlatformInformationPpi[0]; + } + + // + // Report Status Code to indicate transferring to PEI core + // + REPORT_STATUS_CODE ( + EFI_PROGRESS_CODE, + EFI_SOFTWARE_SEC | EFI_SW_SEC_PC_HANDOFF_TO_NEXT + ); + + // + // Transfer the control to the PEI core + // + ASSERT (PeiCoreEntryPoint != NULL); + (*PeiCoreEntryPoint) (SecCoreData, PpiList); + + // + // Should not come here. + // + return; +} + +/** + TemporaryRamDone() disables the use of Temporary RAM. If present, this service is invoked + by the PEI Foundation after the EFI_PEI_PERMANANT_MEMORY_INSTALLED_PPI is installed. + + @retval EFI_SUCCESS Use of Temporary RAM was disabled. + @retval EFI_INVALID_PARAMETER Temporary RAM could not be disabled. + +**/ +EFI_STATUS +EFIAPI +SecTemporaryRamDone ( + VOID + ) +{ + BOOLEAN State; + + // + // Migrate DebugAgentContext. + // + InitializeDebugAgent (DEBUG_AGENT_INIT_POSTMEM_SEC, NULL, NULL); + + // + // Disable interrupts and save current interrupt state + // + State = SaveAndDisableInterrupts(); + + // + // Disable Temporary RAM after Stack and Heap have been migrated at this point. + // + SecPlatformDisableTemporaryMemory (); + + // + // Restore original interrupt state + // + SetInterruptState (State); + + return EFI_SUCCESS; +} diff --git a/UefiCpuPkg/SecCore/SecMain.h b/UefiCpuPkg/SecCore/SecMain.h new file mode 100644 index 000000000000..05175d299d6d --- /dev/null +++ b/UefiCpuPkg/SecCore/SecMain.h @@ -0,0 +1,109 @@ +/** @file + Master header file for SecCore. + + Copyright (c) 2008 - 2013, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _SEC_CORE_H_ +#define _SEC_CORE_H_ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define SEC_IDT_ENTRY_COUNT 34 + +typedef struct _SEC_IDT_TABLE { + // + // Reserved 8 bytes preceding IDT to store EFI_PEI_SERVICES**, since IDT base + // address should be 8-byte alignment. + // Note: For IA32, only the 4 bytes immediately preceding IDT is used to store + // EFI_PEI_SERVICES** + // + UINT64 PeiService; + UINT64 IdtTable[SEC_IDT_ENTRY_COUNT]; +} SEC_IDT_TABLE; + +/** + TemporaryRamDone() disables the use of Temporary RAM. If present, this service is invoked + by the PEI Foundation after the EFI_PEI_PERMANANT_MEMORY_INSTALLED_PPI is installed. + + @retval EFI_SUCCESS Use of Temporary RAM was disabled. + @retval EFI_INVALID_PARAMETER Temporary RAM could not be disabled. + +**/ +EFI_STATUS +EFIAPI +SecTemporaryRamDone ( + VOID + ); + +/** + Entry point to the C language phase of SEC. After the SEC assembly + code has initialized some temporary memory and set up the stack, + the control is transferred to this function. + + @param SizeOfRam Size of the temporary memory available for use. + @param TempRamBase Base address of temporary ram + @param BootFirmwareVolume Base address of the Boot Firmware Volume. +**/ +VOID +EFIAPI +SecStartup ( + IN UINT32 SizeOfRam, + IN UINT32 TempRamBase, + IN VOID *BootFirmwareVolume + ); + +/** + Find and return Pei Core entry point. + + It also find SEC and PEI Core file debug information. It will report them if + remote debug is enabled. + + @param BootFirmwareVolumePtr Point to the boot firmware volume. + @param PeiCoreEntryPoint Point to the PEI core entry point. + +**/ +VOID +EFIAPI +FindAndReportEntryPoints ( + IN EFI_FIRMWARE_VOLUME_HEADER *BootFirmwareVolumePtr, + OUT EFI_PEI_CORE_ENTRY_POINT *PeiCoreEntryPoint + ); + +/** + Auto-generated function that calls the library constructors for all of the module's + dependent libraries. This function must be called by the SEC Core once a stack has + been established. + +**/ +VOID +EFIAPI +ProcessLibraryConstructorList ( + VOID + ); + +#endif From 5c5d01ab3c2be157f090745b17014f31ab6bf637 Mon Sep 17 00:00:00 2001 From: Michael Kinney Date: Tue, 17 Nov 2015 04:57:35 +0000 Subject: [PATCH 116/525] UefiCpuPkg: Add SecCore module and supporting library class and PCD Add declaration of PlatformSecLib library class to DEC file Add declaration of PcdPeiTemporaryRamStackSize PCD to DEC/UNI file Add build of PlatformSecLibNull to DSC file Add build of SecCore to DSC file (Sync patch r18637 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Michael Kinney Reviewed-by: Jeff Fan git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18832 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/UefiCpuPkg.dec | 9 +++++++++ UefiCpuPkg/UefiCpuPkg.dsc | 8 +++++++- UefiCpuPkg/UefiCpuPkg.uni | Bin 6628 -> 7222 bytes 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec index 202e71990ffb..fe9b2a5f27cc 100644 --- a/UefiCpuPkg/UefiCpuPkg.dec +++ b/UefiCpuPkg/UefiCpuPkg.dec @@ -37,6 +37,11 @@ ## @libraryclass Provides functions to manage the Local APIC on IA32 and X64 CPUs. ## LocalApicLib|Include/Library/LocalApicLib.h + + ## @libraryclass Provides platform specific initialization functions in the SEC phase. + ## + PlatformSecLib|Include/Library/PlatformSecLib.h + [Guids] gUefiCpuPkgTokenSpaceGuid = { 0xac05bf33, 0x995a, 0x4ed4, { 0xaa, 0xb8, 0xef, 0x7a, 0xe8, 0xf, 0x5c, 0xb0 }} @@ -62,6 +67,10 @@ # @Prompt Configure stack size for Application Processor (AP) gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize|0x8000|UINT32|0x00000003 + ## Specifies stack size in the temporary RAM. 0 means half of TemporaryRamSize. + # @Prompt Stack size in the temporary RAM. + gUefiCpuPkgTokenSpaceGuid.PcdPeiTemporaryRamStackSize|0|UINT32|0x10001003 + [PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx] ## Specifies timeout value in microseconds for the BSP to detect all APs for the first time. # @Prompt Timeout for the BSP to detect all APs for the first time. diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc index a4117a2e85ad..68400e3cf8c8 100644 --- a/UefiCpuPkg/UefiCpuPkg.dsc +++ b/UefiCpuPkg/UefiCpuPkg.dsc @@ -54,8 +54,12 @@ CpuExceptionHandlerLib|MdeModulePkg/Library/CpuExceptionHandlerLibNull/CpuExceptionHandlerLibNull.inf SynchronizationLib|MdePkg/Library/BaseSynchronizationLib/BaseSynchronizationLib.inf SmmMemLib|MdePkg/Library/SmmMemLib/SmmMemLib.inf + PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf + PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf - +[LibraryClasses.common.SEC] + PlatformSecLib|UefiCpuPkg/Library/PlatformSecLibNull/PlatformSecLibNull.inf + [LibraryClasses.common.PEIM] MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf @@ -96,7 +100,9 @@ UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.inf + UefiCpuPkg/Library/PlatformSecLibNull/PlatformSecLibNull.inf UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationPei.inf UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationSmm.inf + UefiCpuPkg/SecCore/SecCore.inf UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume2Pei.inf diff --git a/UefiCpuPkg/UefiCpuPkg.uni b/UefiCpuPkg/UefiCpuPkg.uni index 2f2d20f7fd87879dde9f9b1cd59a0503399a4a7c..4fe2faf981581025adcbbfd9829512e2328c889b 100644 GIT binary patch delta 262 zcmaE2yv<_66UoVSVnMP245|kAS)kC;_wGUFwpf?Kz(`)N({UVTwn|U`N%cl delta 7 OcmdmH@x*w;6G;FMf&;Sv From a6e7e7a74187c2890e069bc2aeef7da2e8eea986 Mon Sep 17 00:00:00 2001 From: Michael Kinney Date: Tue, 17 Nov 2015 04:58:22 +0000 Subject: [PATCH 117/525] UefiCpuPkg: Add SmmCpuFeaturesLib Add SmmCpuFeaturesLib that provides CPU specific functions that are used to initialize SMM and process SMIs. A functional implementation of this library class is provided that is based on the Intel(R) 64 and IA-32 Architectures Software Developer's Manual (Sync patch r18638 from main trunk.) [jeff.fan@intel.com: Fix code style issues reported by ECC] Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Michael Kinney Reviewed-by: Jeff Fan git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18833 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Include/Library/SmmCpuFeaturesLib.h | 366 ++++++++++++ .../SmmCpuFeaturesLib/SmmCpuFeaturesLib.c | 562 ++++++++++++++++++ .../SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf | 39 ++ .../SmmCpuFeaturesLib/SmmCpuFeaturesLib.uni | Bin 0 -> 1672 bytes 4 files changed, 967 insertions(+) create mode 100644 UefiCpuPkg/Include/Library/SmmCpuFeaturesLib.h create mode 100644 UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.c create mode 100644 UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf create mode 100644 UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.uni diff --git a/UefiCpuPkg/Include/Library/SmmCpuFeaturesLib.h b/UefiCpuPkg/Include/Library/SmmCpuFeaturesLib.h new file mode 100644 index 000000000000..d1c7a8ac965c --- /dev/null +++ b/UefiCpuPkg/Include/Library/SmmCpuFeaturesLib.h @@ -0,0 +1,366 @@ +/** @file +Library that provides CPU specific functions to support the PiSmmCpuDxeSmm module. + +Copyright (c) 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __SMM_FEATURES_LIB_H__ +#define __SMM_FEATURES_LIB_H__ + +#include +#include +#include +#include + +/// +/// Enumeration of SMM registers that are accessed using the library functions +/// SmmCpuFeaturesIsSmmRegisterSupported (), SmmCpuFeaturesGetSmmRegister (), +/// and SmmCpuFeaturesSetSmmRegister (). +/// +typedef enum { + /// + /// Read-write register to provides access to MSR_SMM_FEATURE_CONTROL if the + /// CPU supports this MSR. + /// + SmmRegFeatureControl, + /// + /// Read-only register that returns a non-zero value if the CPU is able to + /// respond to SMIs. + /// + SmmRegSmmEnable, + /// + /// Read-only register that returns a non-zero value if the CPU is able to + /// respond to SMIs, but is busy with other actions that are causing a delay + /// in responding to an SMI. This register abstracts access to MSR_SMM_DELAYED + /// if the CPU supports this MSR. + /// + SmmRegSmmDelayed, + /// + /// Read-only register that returns a non-zero value if the CPU is able to + /// respond to SMIs, but is busy with other actions that are blocking its + /// ability to respond to an SMI. This register abstracts access to + /// MSR_SMM_BLOCKED if the CPU supports this MSR. + /// + SmmRegSmmBlocked +} SMM_REG_NAME; + +/** + Called during the very first SMI into System Management Mode to initialize + CPU features, including SMBASE, for the currently executing CPU. Since this + is the first SMI, the SMRAM Save State Map is at the default address of + SMM_DEFAULT_SMBASE + SMRAM_SAVE_STATE_MAP_OFFSET. The currently executing + CPU is specified by CpuIndex and CpuIndex can be used to access information + about the currently executing CPU in the ProcessorInfo array and the + HotPlugCpuData data structure. + + @param[in] CpuIndex The index of the CPU to initialize. The value + must be between 0 and the NumberOfCpus field in + the System Management System Table (SMST). + @param[in] IsMonarch TRUE if the CpuIndex is the index of the CPU that + was elected as monarch during System Management + Mode initialization. + FALSE if the CpuIndex is not the index of the CPU + that was elected as monarch during System + Management Mode initialization. + @param[in] ProcessorInfo Pointer to an array of EFI_PROCESSOR_INFORMATION + structures. ProcessorInfo[CpuIndex] contains the + information for the currently executing CPU. + @param[in] CpuHotPlugData Pointer to the CPU_HOT_PLUG_DATA structure that + contains the ApidId and SmBase arrays. +**/ +VOID +EFIAPI +SmmCpuFeaturesInitializeProcessor ( + IN UINTN CpuIndex, + IN BOOLEAN IsMonarch, + IN EFI_PROCESSOR_INFORMATION *ProcessorInfo, + IN CPU_HOT_PLUG_DATA *CpuHotPlugData + ); + +/** + This function updates the SMRAM save state on the currently executing CPU + to resume execution at a specific address after an RSM instruction. This + function must evaluate the SMRAM save state to determine the execution mode + the RSM instruction resumes and update the resume execution address with + either NewInstructionPointer32 or NewInstructionPoint. The auto HALT restart + flag in the SMRAM save state must always be cleared. This function returns + the value of the instruction pointer from the SMRAM save state that was + replaced. If this function returns 0, then the SMRAM save state was not + modified. + + This function is called during the very first SMI on each CPU after + SmmCpuFeaturesInitializeProcessor() to set a flag in normal execution mode + to signal that the SMBASE of each CPU has been updated before the default + SMBASE address is used for the first SMI to the next CPU. + + @param[in] CpuIndex The index of the CPU to hook. The value + must be between 0 and the NumberOfCpus + field in the System Management System Table + (SMST). + @param[in] CpuState Pointer to SMRAM Save State Map for the + currently executing CPU. + @param[in] NewInstructionPointer32 Instruction pointer to use if resuming to + 32-bit execution mode from 64-bit SMM. + @param[in] NewInstructionPointer Instruction pointer to use if resuming to + same execution mode as SMM. + + @retval 0 This function did modify the SMRAM save state. + @retval > 0 The original instruction pointer value from the SMRAM save state + before it was replaced. +**/ +UINT64 +EFIAPI +SmmCpuFeaturesHookReturnFromSmm ( + IN UINTN CpuIndex, + IN SMRAM_SAVE_STATE_MAP *CpuState, + IN UINT64 NewInstructionPointer32, + IN UINT64 NewInstructionPointer + ); + +/** + Hook point in normal execution mode that allows the one CPU that was elected + as monarch during System Management Mode initialization to perform additional + initialization actions immediately after all of the CPUs have processed their + first SMI and called SmmCpuFeaturesInitializeProcessor() relocating SMBASE + into a buffer in SMRAM and called SmmCpuFeaturesHookReturnFromSmm(). +**/ +VOID +EFIAPI +SmmCpuFeaturesSmmRelocationComplete ( + VOID + ); + +/** + Return the size, in bytes, of a custom SMI Handler in bytes. If 0 is + returned, then a custom SMI handler is not provided by this library, + and the default SMI handler must be used. + + @retval 0 Use the default SMI handler. + @retval > 0 Use the SMI handler installed by SmmCpuFeaturesInstallSmiHandler() + The caller is required to allocate enough SMRAM for each CPU to + support the size of the custom SMI handler. +**/ +UINTN +EFIAPI +SmmCpuFeaturesGetSmiHandlerSize ( + VOID + ); + +/** + Install a custom SMI handler for the CPU specified by CpuIndex. This function + is only called if SmmCpuFeaturesGetSmiHandlerSize() returns a size is greater + than zero and is called by the CPU that was elected as monarch during System + Management Mode initialization. + + @param[in] CpuIndex The index of the CPU to install the custom SMI handler. + The value must be between 0 and the NumberOfCpus field + in the System Management System Table (SMST). + @param[in] SmBase The SMBASE address for the CPU specified by CpuIndex. + @param[in] SmiStack The stack to use when an SMI is processed by the + the CPU specified by CpuIndex. + @param[in] StackSize The size, in bytes, if the stack used when an SMI is + processed by the CPU specified by CpuIndex. + @param[in] GdtBase The base address of the GDT to use when an SMI is + processed by the CPU specified by CpuIndex. + @param[in] GdtSize The size, in bytes, of the GDT used when an SMI is + processed by the CPU specified by CpuIndex. + @param[in] IdtBase The base address of the IDT to use when an SMI is + processed by the CPU specified by CpuIndex. + @param[in] IdtSize The size, in bytes, of the IDT used when an SMI is + processed by the CPU specified by CpuIndex. + @param[in] Cr3 The base address of the page tables to use when an SMI + is processed by the CPU specified by CpuIndex. +**/ +VOID +EFIAPI +SmmCpuFeaturesInstallSmiHandler ( + IN UINTN CpuIndex, + IN UINT32 SmBase, + IN VOID *SmiStack, + IN UINTN StackSize, + IN UINTN GdtBase, + IN UINTN GdtSize, + IN UINTN IdtBase, + IN UINTN IdtSize, + IN UINT32 Cr3 + ); + +/** + Determines if MTRR registers must be configured to set SMRAM cache-ability + when executing in System Management Mode. + + @retval TRUE MTRR registers must be configured to set SMRAM cache-ability. + @retval FALSE MTRR registers do not need to be configured to set SMRAM + cache-ability. +**/ +BOOLEAN +EFIAPI +SmmCpuFeaturesNeedConfigureMtrrs ( + VOID + ); + +/** + Disable SMRR register if SMRR is supported and SmmCpuFeaturesNeedConfigureMtrrs() + returns TRUE. +**/ +VOID +EFIAPI +SmmCpuFeaturesDisableSmrr ( + VOID + ); + +/** + Enable SMRR register if SMRR is supported and SmmCpuFeaturesNeedConfigureMtrrs() + returns TRUE. +**/ +VOID +EFIAPI +SmmCpuFeaturesReenableSmrr ( + VOID + ); + +/** + Processor specific hook point each time a CPU enters System Management Mode. + + @param[in] CpuIndex The index of the CPU that has entered SMM. The value + must be between 0 and the NumberOfCpus field in the + System Management System Table (SMST). +**/ +VOID +EFIAPI +SmmCpuFeaturesRendezvousEntry ( + IN UINTN CpuIndex + ); + +/** + Processor specific hook point each time a CPU exits System Management Mode. + + @param[in] CpuIndex The index of the CPU that is exiting SMM. The value must + be between 0 and the NumberOfCpus field in the System + Management System Table (SMST). +**/ +VOID +EFIAPI +SmmCpuFeaturesRendezvousExit ( + IN UINTN CpuIndex + ); + +/** + Check to see if an SMM register is supported by a specified CPU. + + @param[in] CpuIndex The index of the CPU to check for SMM register support. + The value must be between 0 and the NumberOfCpus field + in the System Management System Table (SMST). + @param[in] RegName Identifies the SMM register to check for support. + + @retval TRUE The SMM register specified by RegName is supported by the CPU + specified by CpuIndex. + @retval FALSE The SMM register specified by RegName is not supported by the + CPU specified by CpuIndex. +**/ +BOOLEAN +EFIAPI +SmmCpuFeaturesIsSmmRegisterSupported ( + IN UINTN CpuIndex, + IN SMM_REG_NAME RegName + ); + +/** + Returns the current value of the SMM register for the specified CPU. + If the SMM register is not supported, then 0 is returned. + + @param[in] CpuIndex The index of the CPU to read the SMM register. The + value must be between 0 and the NumberOfCpus field in + the System Management System Table (SMST). + @param[in] RegName Identifies the SMM register to read. + + @return The value of the SMM register specified by RegName from the CPU + specified by CpuIndex. +**/ +UINT64 +EFIAPI +SmmCpuFeaturesGetSmmRegister ( + IN UINTN CpuIndex, + IN SMM_REG_NAME RegName + ); + +/** + Sets the value of an SMM register on a specified CPU. + If the SMM register is not supported, then no action is performed. + + @param[in] CpuIndex The index of the CPU to write the SMM register. The + value must be between 0 and the NumberOfCpus field in + the System Management System Table (SMST). + @param[in] RegName Identifies the SMM register to write. + registers are read-only. + @param[in] Value The value to write to the SMM register. +**/ +VOID +EFIAPI +SmmCpuFeaturesSetSmmRegister ( + IN UINTN CpuIndex, + IN SMM_REG_NAME RegName, + IN UINT64 Value + ); + +/** + Read an SMM Save State register on the target processor. If this function + returns EFI_UNSUPPORTED, then the caller is responsible for reading the + SMM Save Sate register. + + @param[in] CpuIndex The index of the CPU to read the SMM Save State. The + value must be between 0 and the NumberOfCpus field in + the System Management System Table (SMST). + @param[in] Register The SMM Save State register to read. + @param[in] Width The number of bytes to read from the CPU save state. + @param[out] Buffer Upon return, this holds the CPU register value read + from the save state. + + @retval EFI_SUCCESS The register was read from Save State. + @retval EFI_INVALID_PARAMTER Buffer is NULL. + @retval EFI_UNSUPPORTED This function does not support reading Register. + +**/ +EFI_STATUS +EFIAPI +SmmCpuFeaturesReadSaveStateRegister ( + IN UINTN CpuIndex, + IN EFI_SMM_SAVE_STATE_REGISTER Register, + IN UINTN Width, + OUT VOID *Buffer + ); + +/** + Writes an SMM Save State register on the target processor. If this function + returns EFI_UNSUPPORTED, then the caller is responsible for writing the + SMM Save Sate register. + + @param[in] CpuIndex The index of the CPU to write the SMM Save State. The + value must be between 0 and the NumberOfCpus field in + the System Management System Table (SMST). + @param[in] Register The SMM Save State register to write. + @param[in] Width The number of bytes to write to the CPU save state. + @param[in] Buffer Upon entry, this holds the new CPU register value. + + @retval EFI_SUCCESS The register was written to Save State. + @retval EFI_INVALID_PARAMTER Buffer is NULL. + @retval EFI_UNSUPPORTED This function does not support writing Register. +**/ +EFI_STATUS +EFIAPI +SmmCpuFeaturesWriteSaveStateRegister ( + IN UINTN CpuIndex, + IN EFI_SMM_SAVE_STATE_REGISTER Register, + IN UINTN Width, + IN CONST VOID *Buffer + ); + +#endif diff --git a/UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.c b/UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.c new file mode 100644 index 000000000000..4f2f9b65fa37 --- /dev/null +++ b/UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.c @@ -0,0 +1,562 @@ +/** @file +The CPU specific programming for PiSmmCpuDxeSmm module. + +Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// +// Machine Specific Registers (MSRs) +// +#define SMM_FEATURES_LIB_IA32_MTRR_CAP 0x0FE +#define SMM_FEATURES_LIB_IA32_FEATURE_CONTROL 0x03A +#define SMM_FEATURES_LIB_IA32_SMRR_PHYSBASE 0x1F2 +#define SMM_FEATURES_LIB_IA32_SMRR_PHYSMASK 0x1F3 +#define SMM_FEATURES_LIB_IA32_CORE_SMRR_PHYSBASE 0x0A0 +#define SMM_FEATURES_LIB_IA32_CORE_SMRR_PHYSMASK 0x0A1 +#define EFI_MSR_SMRR_MASK 0xFFFFF000 +#define EFI_MSR_SMRR_PHYS_MASK_VALID BIT11 + +// +// Set default value to assume SMRR is not supported +// +BOOLEAN mSmrrSupported = FALSE; + +// +// Set default value to assume IA-32 Architectural MSRs are used +// +UINT32 mSmrrPhysBaseMsr = SMM_FEATURES_LIB_IA32_SMRR_PHYSBASE; +UINT32 mSmrrPhysMaskMsr = SMM_FEATURES_LIB_IA32_SMRR_PHYSMASK; + +// +// Set default value to assume MTRRs need to be configured on each SMI +// +BOOLEAN mNeedConfigureMtrrs = TRUE; + +// +// Array for state of SMRR enable on all CPUs +// +BOOLEAN *mSmrrEnabled; + +/** + The constructor function + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS. + +**/ +EFI_STATUS +EFIAPI +SmmCpuFeaturesLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + UINT32 RegEax; + UINT32 RegEdx; + UINTN FamilyId; + UINTN ModelId; + + // + // Retrieve CPU Family and Model + // + AsmCpuid (CPUID_VERSION_INFO, &RegEax, NULL, NULL, &RegEdx); + FamilyId = (RegEax >> 8) & 0xf; + ModelId = (RegEax >> 4) & 0xf; + if (FamilyId == 0x06 || FamilyId == 0x0f) { + ModelId = ModelId | ((RegEax >> 12) & 0xf0); + } + + // + // Check CPUID(CPUID_VERSION_INFO).EDX[12] for MTRR capability + // + if ((RegEdx & BIT12) != 0) { + // + // Check MTRR_CAP MSR bit 11 for SMRR support + // + if ((AsmReadMsr64 (SMM_FEATURES_LIB_IA32_MTRR_CAP) & BIT11) != 0) { + mSmrrSupported = TRUE; + } + } + + // + // Intel(R) 64 and IA-32 Architectures Software Developer's Manual + // Volume 3C, Section 35.3 MSRs in the Intel(R) Atom(TM) Processor Family + // + // If CPU Family/Model is 06_1CH, 06_26H, 06_27H, 06_35H or 06_36H, then + // SMRR Physical Base and SMM Physical Mask MSRs are not available. + // + if (FamilyId == 0x06) { + if (ModelId == 0x1C || ModelId == 0x26 || ModelId == 0x27 || ModelId == 0x35 || ModelId == 0x36) { + mSmrrSupported = FALSE; + } + } + + // + // Intel(R) 64 and IA-32 Architectures Software Developer's Manual + // Volume 3C, Section 35.2 MSRs in the Intel(R) Core(TM) 2 Processor Family + // + // If CPU Family/Model is 06_0F or 06_17, then use Intel(R) Core(TM) 2 + // Processor Family MSRs + // + if (FamilyId == 0x06) { + if (ModelId == 0x17 || ModelId == 0x0f) { + mSmrrPhysBaseMsr = SMM_FEATURES_LIB_IA32_CORE_SMRR_PHYSBASE; + mSmrrPhysMaskMsr = SMM_FEATURES_LIB_IA32_CORE_SMRR_PHYSMASK; + } + } + + // + // Intel(R) 64 and IA-32 Architectures Software Developer's Manual + // Volume 3C, Section 34.4.2 SMRAM Caching + // An IA-32 processor does not automatically write back and invalidate its + // caches before entering SMM or before exiting SMM. Because of this behavior, + // care must be taken in the placement of the SMRAM in system memory and in + // the caching of the SMRAM to prevent cache incoherence when switching back + // and forth between SMM and protected mode operation. + // + // An IA-32 processor is a processor that does not support the Intel 64 + // Architecture. Support for the Intel 64 Architecture can be detected from + // CPUID(CPUID_EXTENDED_CPU_SIG).EDX[29] + // + // If an IA-32 processor is detected, then set mNeedConfigureMtrrs to TRUE, + // so caches are flushed on SMI entry and SMI exit, the interrupted code + // MTRRs are saved/restored, and MTRRs for SMM are loaded. + // + AsmCpuid (CPUID_EXTENDED_FUNCTION, &RegEax, NULL, NULL, NULL); + if (RegEax >= CPUID_EXTENDED_CPU_SIG) { + AsmCpuid (CPUID_EXTENDED_CPU_SIG, NULL, NULL, NULL, &RegEdx); + if ((RegEdx & BIT29) != 0) { + mNeedConfigureMtrrs = FALSE; + } + } + + // + // Allocate array for state of SMRR enable on all CPUs + // + mSmrrEnabled = (BOOLEAN *)AllocatePool (sizeof (BOOLEAN) * PcdGet32 (PcdCpuMaxLogicalProcessorNumber)); + ASSERT (mSmrrEnabled != NULL); + + return EFI_SUCCESS; +} + +/** + Called during the very first SMI into System Management Mode to initialize + CPU features, including SMBASE, for the currently executing CPU. Since this + is the first SMI, the SMRAM Save State Map is at the default address of + SMM_DEFAULT_SMBASE + SMRAM_SAVE_STATE_MAP_OFFSET. The currently executing + CPU is specified by CpuIndex and CpuIndex can be used to access information + about the currently executing CPU in the ProcessorInfo array and the + HotPlugCpuData data structure. + + @param[in] CpuIndex The index of the CPU to initialize. The value + must be between 0 and the NumberOfCpus field in + the System Management System Table (SMST). + @param[in] IsMonarch TRUE if the CpuIndex is the index of the CPU that + was elected as monarch during System Management + Mode initialization. + FALSE if the CpuIndex is not the index of the CPU + that was elected as monarch during System + Management Mode initialization. + @param[in] ProcessorInfo Pointer to an array of EFI_PROCESSOR_INFORMATION + structures. ProcessorInfo[CpuIndex] contains the + information for the currently executing CPU. + @param[in] CpuHotPlugData Pointer to the CPU_HOT_PLUG_DATA structure that + contains the ApidId and SmBase arrays. +**/ +VOID +EFIAPI +SmmCpuFeaturesInitializeProcessor ( + IN UINTN CpuIndex, + IN BOOLEAN IsMonarch, + IN EFI_PROCESSOR_INFORMATION *ProcessorInfo, + IN CPU_HOT_PLUG_DATA *CpuHotPlugData + ) +{ + SMRAM_SAVE_STATE_MAP *CpuState; + UINT64 FeatureControl; + + // + // Configure SMBASE. + // + CpuState = (SMRAM_SAVE_STATE_MAP *)(UINTN)(SMM_DEFAULT_SMBASE + SMRAM_SAVE_STATE_MAP_OFFSET); + CpuState->x86.SMBASE = (UINT32)CpuHotPlugData->SmBase[CpuIndex]; + + // + // Intel(R) 64 and IA-32 Architectures Software Developer's Manual + // Volume 3C, Section 35.2 MSRs in the Intel(R) Core(TM) 2 Processor Family + // + // If Intel(R) Core(TM) Core(TM) 2 Processor Family MSRs are being used, then + // make sure SMRR Enable(BIT3) of MSR_FEATURE_CONTROL MSR(0x3A) is set before + // accessing SMRR base/mask MSRs. If Lock(BIT0) of MSR_FEATURE_CONTROL MSR(0x3A) + // is set, then the MSR is locked and can not be modified. + // + if (mSmrrSupported && mSmrrPhysBaseMsr == SMM_FEATURES_LIB_IA32_CORE_SMRR_PHYSBASE) { + FeatureControl = AsmReadMsr64 (SMM_FEATURES_LIB_IA32_FEATURE_CONTROL); + if ((FeatureControl & BIT3) == 0) { + if ((FeatureControl & BIT0) == 0) { + AsmWriteMsr64 (SMM_FEATURES_LIB_IA32_FEATURE_CONTROL, FeatureControl | BIT3); + } else { + mSmrrSupported = FALSE; + } + } + } + + // + // If SMRR is supported, then program SMRR base/mask MSRs. + // The EFI_MSR_SMRR_PHYS_MASK_VALID bit is not set until the first normal SMI. + // The code that initializes SMM environment is running in normal mode + // from SMRAM region. If SMRR is enabled here, then the SMRAM region + // is protected and the normal mode code execution will fail. + // + if (mSmrrSupported) { + AsmWriteMsr64 (mSmrrPhysBaseMsr, CpuHotPlugData->SmrrBase | MTRR_CACHE_WRITE_BACK); + AsmWriteMsr64 (mSmrrPhysMaskMsr, (~(CpuHotPlugData->SmrrSize - 1) & EFI_MSR_SMRR_MASK)); + mSmrrEnabled[CpuIndex] = FALSE; + } +} + +/** + This function updates the SMRAM save state on the currently executing CPU + to resume execution at a specific address after an RSM instruction. This + function must evaluate the SMRAM save state to determine the execution mode + the RSM instruction resumes and update the resume execution address with + either NewInstructionPointer32 or NewInstructionPoint. The auto HALT restart + flag in the SMRAM save state must always be cleared. This function returns + the value of the instruction pointer from the SMRAM save state that was + replaced. If this function returns 0, then the SMRAM save state was not + modified. + + This function is called during the very first SMI on each CPU after + SmmCpuFeaturesInitializeProcessor() to set a flag in normal execution mode + to signal that the SMBASE of each CPU has been updated before the default + SMBASE address is used for the first SMI to the next CPU. + + @param[in] CpuIndex The index of the CPU to hook. The value + must be between 0 and the NumberOfCpus + field in the System Management System Table + (SMST). + @param[in] CpuState Pointer to SMRAM Save State Map for the + currently executing CPU. + @param[in] NewInstructionPointer32 Instruction pointer to use if resuming to + 32-bit execution mode from 64-bit SMM. + @param[in] NewInstructionPointer Instruction pointer to use if resuming to + same execution mode as SMM. + + @retval 0 This function did modify the SMRAM save state. + @retval > 0 The original instruction pointer value from the SMRAM save state + before it was replaced. +**/ +UINT64 +EFIAPI +SmmCpuFeaturesHookReturnFromSmm ( + IN UINTN CpuIndex, + IN SMRAM_SAVE_STATE_MAP *CpuState, + IN UINT64 NewInstructionPointer32, + IN UINT64 NewInstructionPointer + ) +{ + return 0; +} + +/** + Hook point in normal execution mode that allows the one CPU that was elected + as monarch during System Management Mode initialization to perform additional + initialization actions immediately after all of the CPUs have processed their + first SMI and called SmmCpuFeaturesInitializeProcessor() relocating SMBASE + into a buffer in SMRAM and called SmmCpuFeaturesHookReturnFromSmm(). +**/ +VOID +EFIAPI +SmmCpuFeaturesSmmRelocationComplete ( + VOID + ) +{ +} + +/** + Return the size, in bytes, of a custom SMI Handler in bytes. If 0 is + returned, then a custom SMI handler is not provided by this library, + and the default SMI handler must be used. + + @retval 0 Use the default SMI handler. + @retval > 0 Use the SMI handler installed by SmmCpuFeaturesInstallSmiHandler() + The caller is required to allocate enough SMRAM for each CPU to + support the size of the custom SMI handler. +**/ +UINTN +EFIAPI +SmmCpuFeaturesGetSmiHandlerSize ( + VOID + ) +{ + return 0; +} + +/** + Install a custom SMI handler for the CPU specified by CpuIndex. This function + is only called if SmmCpuFeaturesGetSmiHandlerSize() returns a size is greater + than zero and is called by the CPU that was elected as monarch during System + Management Mode initialization. + + @param[in] CpuIndex The index of the CPU to install the custom SMI handler. + The value must be between 0 and the NumberOfCpus field + in the System Management System Table (SMST). + @param[in] SmBase The SMBASE address for the CPU specified by CpuIndex. + @param[in] SmiStack The stack to use when an SMI is processed by the + the CPU specified by CpuIndex. + @param[in] StackSize The size, in bytes, if the stack used when an SMI is + processed by the CPU specified by CpuIndex. + @param[in] GdtBase The base address of the GDT to use when an SMI is + processed by the CPU specified by CpuIndex. + @param[in] GdtSize The size, in bytes, of the GDT used when an SMI is + processed by the CPU specified by CpuIndex. + @param[in] IdtBase The base address of the IDT to use when an SMI is + processed by the CPU specified by CpuIndex. + @param[in] IdtSize The size, in bytes, of the IDT used when an SMI is + processed by the CPU specified by CpuIndex. + @param[in] Cr3 The base address of the page tables to use when an SMI + is processed by the CPU specified by CpuIndex. +**/ +VOID +EFIAPI +SmmCpuFeaturesInstallSmiHandler ( + IN UINTN CpuIndex, + IN UINT32 SmBase, + IN VOID *SmiStack, + IN UINTN StackSize, + IN UINTN GdtBase, + IN UINTN GdtSize, + IN UINTN IdtBase, + IN UINTN IdtSize, + IN UINT32 Cr3 + ) +{ +} + +/** + Determines if MTRR registers must be configured to set SMRAM cache-ability + when executing in System Management Mode. + + @retval TRUE MTRR registers must be configured to set SMRAM cache-ability. + @retval FALSE MTRR registers do not need to be configured to set SMRAM + cache-ability. +**/ +BOOLEAN +EFIAPI +SmmCpuFeaturesNeedConfigureMtrrs ( + VOID + ) +{ + return mNeedConfigureMtrrs; +} + +/** + Disable SMRR register if SMRR is supported and SmmCpuFeaturesNeedConfigureMtrrs() + returns TRUE. +**/ +VOID +EFIAPI +SmmCpuFeaturesDisableSmrr ( + VOID + ) +{ + if (mSmrrSupported && mNeedConfigureMtrrs) { + AsmWriteMsr64 (mSmrrPhysMaskMsr, AsmReadMsr64(mSmrrPhysMaskMsr) & ~EFI_MSR_SMRR_PHYS_MASK_VALID); + } +} + +/** + Enable SMRR register if SMRR is supported and SmmCpuFeaturesNeedConfigureMtrrs() + returns TRUE. +**/ +VOID +EFIAPI +SmmCpuFeaturesReenableSmrr ( + VOID + ) +{ + if (mSmrrSupported && mNeedConfigureMtrrs) { + AsmWriteMsr64 (mSmrrPhysMaskMsr, AsmReadMsr64(mSmrrPhysMaskMsr) | EFI_MSR_SMRR_PHYS_MASK_VALID); + } +} + +/** + Processor specific hook point each time a CPU enters System Management Mode. + + @param[in] CpuIndex The index of the CPU that has entered SMM. The value + must be between 0 and the NumberOfCpus field in the + System Management System Table (SMST). +**/ +VOID +EFIAPI +SmmCpuFeaturesRendezvousEntry ( + IN UINTN CpuIndex + ) +{ + // + // If SMRR is supported and this is the first normal SMI, then enable SMRR + // + if (mSmrrSupported && !mSmrrEnabled[CpuIndex]) { + AsmWriteMsr64 (mSmrrPhysMaskMsr, AsmReadMsr64 (mSmrrPhysMaskMsr) | EFI_MSR_SMRR_PHYS_MASK_VALID); + mSmrrEnabled[CpuIndex] = TRUE; + } +} + +/** + Processor specific hook point each time a CPU exits System Management Mode. + + @param[in] CpuIndex The index of the CPU that is exiting SMM. The value must + be between 0 and the NumberOfCpus field in the System + Management System Table (SMST). +**/ +VOID +EFIAPI +SmmCpuFeaturesRendezvousExit ( + IN UINTN CpuIndex + ) +{ +} + +/** + Check to see if an SMM register is supported by a specified CPU. + + @param[in] CpuIndex The index of the CPU to check for SMM register support. + The value must be between 0 and the NumberOfCpus field + in the System Management System Table (SMST). + @param[in] RegName Identifies the SMM register to check for support. + + @retval TRUE The SMM register specified by RegName is supported by the CPU + specified by CpuIndex. + @retval FALSE The SMM register specified by RegName is not supported by the + CPU specified by CpuIndex. +**/ +BOOLEAN +EFIAPI +SmmCpuFeaturesIsSmmRegisterSupported ( + IN UINTN CpuIndex, + IN SMM_REG_NAME RegName + ) +{ + return FALSE; +} + +/** + Returns the current value of the SMM register for the specified CPU. + If the SMM register is not supported, then 0 is returned. + + @param[in] CpuIndex The index of the CPU to read the SMM register. The + value must be between 0 and the NumberOfCpus field in + the System Management System Table (SMST). + @param[in] RegName Identifies the SMM register to read. + + @return The value of the SMM register specified by RegName from the CPU + specified by CpuIndex. +**/ +UINT64 +EFIAPI +SmmCpuFeaturesGetSmmRegister ( + IN UINTN CpuIndex, + IN SMM_REG_NAME RegName + ) +{ + return 0; +} + +/** + Sets the value of an SMM register on a specified CPU. + If the SMM register is not supported, then no action is performed. + + @param[in] CpuIndex The index of the CPU to write the SMM register. The + value must be between 0 and the NumberOfCpus field in + the System Management System Table (SMST). + @param[in] RegName Identifies the SMM register to write. + registers are read-only. + @param[in] Value The value to write to the SMM register. +**/ +VOID +EFIAPI +SmmCpuFeaturesSetSmmRegister ( + IN UINTN CpuIndex, + IN SMM_REG_NAME RegName, + IN UINT64 Value + ) +{ +} + +/** + Read an SMM Save State register on the target processor. If this function + returns EFI_UNSUPPORTED, then the caller is responsible for reading the + SMM Save Sate register. + + @param[in] CpuIndex The index of the CPU to read the SMM Save State. The + value must be between 0 and the NumberOfCpus field in + the System Management System Table (SMST). + @param[in] Register The SMM Save State register to read. + @param[in] Width The number of bytes to read from the CPU save state. + @param[out] Buffer Upon return, this holds the CPU register value read + from the save state. + + @retval EFI_SUCCESS The register was read from Save State. + @retval EFI_INVALID_PARAMTER Buffer is NULL. + @retval EFI_UNSUPPORTED This function does not support reading Register. + +**/ +EFI_STATUS +EFIAPI +SmmCpuFeaturesReadSaveStateRegister ( + IN UINTN CpuIndex, + IN EFI_SMM_SAVE_STATE_REGISTER Register, + IN UINTN Width, + OUT VOID *Buffer + ) +{ + return EFI_UNSUPPORTED; +} + +/** + Writes an SMM Save State register on the target processor. If this function + returns EFI_UNSUPPORTED, then the caller is responsible for writing the + SMM Save Sate register. + + @param[in] CpuIndex The index of the CPU to write the SMM Save State. The + value must be between 0 and the NumberOfCpus field in + the System Management System Table (SMST). + @param[in] Register The SMM Save State register to write. + @param[in] Width The number of bytes to write to the CPU save state. + @param[in] Buffer Upon entry, this holds the new CPU register value. + + @retval EFI_SUCCESS The register was written to Save State. + @retval EFI_INVALID_PARAMTER Buffer is NULL. + @retval EFI_UNSUPPORTED This function does not support writing Register. +**/ +EFI_STATUS +EFIAPI +SmmCpuFeaturesWriteSaveStateRegister ( + IN UINTN CpuIndex, + IN EFI_SMM_SAVE_STATE_REGISTER Register, + IN UINTN Width, + IN CONST VOID *Buffer + ) +{ + return EFI_UNSUPPORTED; +} diff --git a/UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf b/UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf new file mode 100644 index 000000000000..1735062b17e3 --- /dev/null +++ b/UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf @@ -0,0 +1,39 @@ +## @file +# The CPU specific programming for PiSmmCpuDxeSmm module. +# +# Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = SmmCpuFeaturesLib + MODULE_UNI_FILE = SmmCpuFeaturesLib.uni + FILE_GUID = FC3DC10D-D271-422a-AFF3-CBCF70344431 + MODULE_TYPE = DXE_SMM_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = SmmCpuFeaturesLib + CONSTRUCTOR = SmmCpuFeaturesLibConstructor + +[Sources] + SmmCpuFeaturesLib.c + +[Packages] + MdePkg/MdePkg.dec + UefiCpuPkg/UefiCpuPkg.dec + +[LibraryClasses] + BaseLib + PcdLib + MemoryAllocationLib + DebugLib + +[Pcd] + gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber ## SOMETIMES_CONSUMES diff --git a/UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.uni b/UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.uni new file mode 100644 index 0000000000000000000000000000000000000000..594062cd0bace29214e055fe8453f214cefff6bf GIT binary patch literal 1672 zcmd6n&2Q5{5XI+=#Q(5LFM!$vkT`%4A|D1UppKeEz^QVaw6WxT$Vs66=YikbZR{or z2QCO%-rbpq+*uQ?ZtYwb(36Hb4c4fI0HnoTL0I&9jHp6z-wZ4s**S5mWh*NBa zXJw@=?V2&QIZtj2EXV#5pW|F^1HaQHc56Mm0U>xC{-sUuDr>XKTj%exzp`79a!_Zs z0r3%eA2UCq~*+}5)YcFjb(l<*Mi9g3KVZ(ix6-6eNepX+dEJ?u|= zTxzaAycQXwaQCat$tgss5%f~7HMXiA!}I>V)LnPwJ41IQ);ElYtoD^rKc#5vz*PO} z!JvUSZSEp=ZAo-y1fblraTCMYxBohG|k^?a}h zK7INqvGRX8E?1+egM^0F&qct{|g)7ts zbI04VPAhKCzOXM|iO(pzO(ror#~*_#jKpWZz!G=)lygXwVw5#Ry(3m9zcGJgN6hsl zMt5046_I_daBB1zE&BA8a`uk?1@wPvdG6Bmr0SgT1qJOcK}k420x7af*hnj>+D54% wT>kW&_-{s7Te{@hcaFN@3@ov1aQa{V1si`^sd{8Ujq0C%buY)N{XZ-H4N)co@c;k- literal 0 HcmV?d00001 From afc8be03f21338f32a30a34c08959c0c58ee5641 Mon Sep 17 00:00:00 2001 From: Michael Kinney Date: Tue, 17 Nov 2015 04:59:32 +0000 Subject: [PATCH 118/525] UefiCpuPkg: Add SmmCpuPlatformHookLib Add SmmCpuPlatformHookLib that provides platform specific functions that are used to initialize SMM and process SMIs. A Null instance of this library is provided that should work for most platforms. (Sync patch r18639 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Michael Kinney Reviewed-by: Jeff Fan git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18834 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Include/Library/SmmCpuPlatformHookLib.h | 109 ++++++++++++++++++ .../SmmCpuPlatformHookLibNull.c | 108 +++++++++++++++++ .../SmmCpuPlatformHookLibNull.inf | 40 +++++++ .../SmmCpuPlatformHookLibNull.uni | Bin 0 -> 1604 bytes 4 files changed, 257 insertions(+) create mode 100644 UefiCpuPkg/Include/Library/SmmCpuPlatformHookLib.h create mode 100644 UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.c create mode 100644 UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.inf create mode 100644 UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.uni diff --git a/UefiCpuPkg/Include/Library/SmmCpuPlatformHookLib.h b/UefiCpuPkg/Include/Library/SmmCpuPlatformHookLib.h new file mode 100644 index 000000000000..e40084edf91a --- /dev/null +++ b/UefiCpuPkg/Include/Library/SmmCpuPlatformHookLib.h @@ -0,0 +1,109 @@ +/** @file + Public include file for the SMM CPU Platform Hook Library. + + Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __SMM_CPU_PLATFORM_HOOK_LIB_H__ +#define __SMM_CPU_PLATFORM_HOOK_LIB_H__ + +/// +/// SMM Page Size Type +/// +typedef enum { + SmmPageSize4K, + SmmPageSize2M, + SmmPageSize1G, + MaxSmmPageSizeType +} SMM_PAGE_SIZE_TYPE; + +/** + Checks if platform produces a valid SMI. + + This function checks if platform produces a valid SMI. This function is + called at SMM entry to detect if this is a spurious SMI. This function + must be implemented in an MP safe way because it is called by multiple CPU + threads. + + @retval TRUE There is a valid SMI + @retval FALSE There is no valid SMI + +**/ +BOOLEAN +EFIAPI +PlatformValidSmi ( + VOID + ); + +/** + Clears platform top level SMI status bit. + + This function clears platform top level SMI status bit. + + @retval TRUE The platform top level SMI status is cleared. + @retval FALSE The platform top level SMI status cannot be cleared. + +**/ +BOOLEAN +EFIAPI +ClearTopLevelSmiStatus ( + VOID + ); + +/** + Performs platform specific way of SMM BSP election. + + This function performs platform specific way of SMM BSP election. + + @param IsBsp Output parameter. TRUE: the CPU this function executes + on is elected to be the SMM BSP. FALSE: the CPU this + function executes on is to be SMM AP. + + @retval EFI_SUCCESS The function executes successfully. + @retval EFI_NOT_READY The function does not determine whether this CPU should be + BSP or AP. This may occur if hardware init sequence to + enable the determination is yet to be done, or the function + chooses not to do BSP election and will let SMM CPU driver to + use its default BSP election process. + @retval EFI_DEVICE_ERROR The function cannot determine whether this CPU should be + BSP or AP due to hardware error. + +**/ +EFI_STATUS +EFIAPI +PlatformSmmBspElection ( + OUT BOOLEAN *IsBsp + ); + +/** + Get platform page table attribute . + + This function gets page table attribute of platform. + + @param Address Input parameter. Obtain the page table entries attribute on this address. + @param PageSize Output parameter. The size of the page. + @param NumOfPages Output parameter. Number of page. + @param PageAttribute Output parameter. Paging Attributes (WB, UC, etc). + + @retval EFI_SUCCESS The platform page table attribute from the address is determined. + @retval EFI_UNSUPPORTED The platform does not support getting page table attribute for the address. + +**/ +EFI_STATUS +EFIAPI +GetPlatformPageTableAttribute ( + IN UINT64 Address, + OUT SMM_PAGE_SIZE_TYPE *PageSize, + OUT UINTN *NumOfPages, + OUT UINTN *PageAttribute + ); + +#endif diff --git a/UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.c b/UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.c new file mode 100644 index 000000000000..efb61fa6f8c2 --- /dev/null +++ b/UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.c @@ -0,0 +1,108 @@ +/** @file +SMM CPU Platform Hook NULL library instance. + +Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ +#include +#include + +/** + Checks if platform produces a valid SMI. + + This function checks if platform produces a valid SMI. This function is + called at SMM entry to detect if this is a spurious SMI. This function + must be implemented in an MP safe way because it is called by multiple CPU + threads. + + @retval TRUE There is a valid SMI + @retval FALSE There is no valid SMI + +**/ +BOOLEAN +EFIAPI +PlatformValidSmi ( + VOID + ) +{ + return TRUE; +} + +/** + Clears platform top level SMI status bit. + + This function clears platform top level SMI status bit. + + @retval TRUE The platform top level SMI status is cleared. + @retval FALSE The platform top level SMI status cannot be cleared. + +**/ +BOOLEAN +EFIAPI +ClearTopLevelSmiStatus ( + VOID + ) +{ + return TRUE; +} + +/** + Performs platform specific way of SMM BSP election. + + This function performs platform specific way of SMM BSP election. + + @param IsBsp Output parameter. TRUE: the CPU this function executes + on is elected to be the SMM BSP. FALSE: the CPU this + function executes on is to be SMM AP. + + @retval EFI_SUCCESS The function executes successfully. + @retval EFI_NOT_READY The function does not determine whether this CPU should be + BSP or AP. This may occur if hardware init sequence to + enable the determination is yet to be done, or the function + chooses not to do BSP election and will let SMM CPU driver to + use its default BSP election process. + @retval EFI_DEVICE_ERROR The function cannot determine whether this CPU should be + BSP or AP due to hardware error. + +**/ +EFI_STATUS +EFIAPI +PlatformSmmBspElection ( + OUT BOOLEAN *IsBsp + ) +{ + return EFI_NOT_READY; +} + +/** + Get platform page table attribute. + + This function gets page table attribute of platform. + + @param Address Input parameter. Obtain the page table entries attribute on this address. + @param PageSize Output parameter. The size of the page. + @param NumOfPages Output parameter. Number of page. + @param PageAttribute Output parameter. Paging Attributes (WB, UC, etc). + + @retval EFI_SUCCESS The platform page table attribute from the address is determined. + @retval EFI_UNSUPPORTED The platform does not support getting page table attribute for the address. + +**/ +EFI_STATUS +EFIAPI +GetPlatformPageTableAttribute ( + IN UINT64 Address, + IN OUT SMM_PAGE_SIZE_TYPE *PageSize, + IN OUT UINTN *NumOfPages, + IN OUT UINTN *PageAttribute + ) +{ + return EFI_UNSUPPORTED; +} diff --git a/UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.inf b/UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.inf new file mode 100644 index 000000000000..4dea5fb4e1e3 --- /dev/null +++ b/UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.inf @@ -0,0 +1,40 @@ +## @file +# SMM CPU Platform Hook NULL library instance. +# +# Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +################################################################################ +# +# Defines Section - statements that will be processed to create a Makefile. +# +################################################################################ +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = SmmCpuPlatformHookLibNull + MODULE_UNI_FILE = SmmCpuPlatformHookLibNull.uni + FILE_GUID = D6494E1B-E06F-4ab5-B64D-48B25AA9EB33 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = SmmCpuPlatformHookLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + SmmCpuPlatformHookLibNull.c + +[Packages] + MdePkg/MdePkg.dec + UefiCpuPkg/UefiCpuPkg.dec diff --git a/UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.uni b/UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.uni new file mode 100644 index 0000000000000000000000000000000000000000..9935934a35273bab9d569804e73a1f1326a1bee2 GIT binary patch literal 1604 zcmc(fOK;Oq5QS%r#DBO-H-Op%kYIrj!f6b(D7BS`fE98cO)b*6a@<1yJn)@s$8M^y zV1bb3`Deo=&%+|KyR?0jBzuQD;BOQZsg?EAX(k}3J_6YCC%+Kv9 z&r4QE_3oLyutU}nh$Vt2MEl1=!`$VsHFz0jmY4H;i*UUt8aX_GS;e zF^n?29ry*fOCLk|E2lYgiO0h4XRyxE=E~b{efCQ%m!6g4Wvo`9wb@H4-Ij7vNP3A= zi?7@BI>HTWRVqbg)yvtnXCdsCiF8qo#Cpq8%)~cq^pQ2Ep6$IpRUfcF-Qm)5{qD7x zF$#A#+l-h(lp2*@ily2s>nS|%*2S5075{TARgJ{@2VVDC?J85Lsot8__w!laj{)`4?X6F8LQ!w0BSa4JT8$&*{3|=v`1Qc(SmD7N>E zf&YFYG=b&RJ6*{f(sES5RW^>u(dX3&^{&1SmDe?@!MG vb<~%zr1mMJI#1nj1eREK82`opuJe}}sTW4%qCQC){r6?{zcT8gl`8Zb&D-?w literal 0 HcmV?d00001 From 90811cf59dad0d0b33c597a8987091ba327e4cce Mon Sep 17 00:00:00 2001 From: Michael Kinney Date: Tue, 17 Nov 2015 05:00:16 +0000 Subject: [PATCH 119/525] UefiCpuPkg: Add SMM CPU Service Protocol Add definition of the SMM CPU Service Protocol that is produced by the PiSmmCpuDxeSmm module. (Sync patch r18640 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Michael Kinney Reviewed-by: Jeff Fan git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18835 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/Include/Protocol/SmmCpuService.h | 209 ++++++++++++++++++++ 1 file changed, 209 insertions(+) create mode 100644 UefiCpuPkg/Include/Protocol/SmmCpuService.h diff --git a/UefiCpuPkg/Include/Protocol/SmmCpuService.h b/UefiCpuPkg/Include/Protocol/SmmCpuService.h new file mode 100644 index 000000000000..9aced54f4d6f --- /dev/null +++ b/UefiCpuPkg/Include/Protocol/SmmCpuService.h @@ -0,0 +1,209 @@ +/** @file +SMM CPU Service protocol definition. + +Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _SMM_CPU_SERVICE_PROTOCOL_H_ +#define _SMM_CPU_SERVICE_PROTOCOL_H_ + +// +// Share some definitions with MP Services and CPU Arch Protocol +// +#include +#include + +#define EFI_SMM_CPU_SERVICE_PROTOCOL_GUID \ + { \ + 0x1d202cab, 0xc8ab, 0x4d5c, { 0x94, 0xf7, 0x3c, 0xfc, 0xc0, 0xd3, 0xd3, 0x35 } \ + } + +typedef struct _EFI_SMM_CPU_SERVICE_PROTOCOL EFI_SMM_CPU_SERVICE_PROTOCOL; + +// +// Protocol functions +// + +/** + Gets processor information on the requested processor at the + instant this call is made. This service may only be called from the BSP. + + @param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL + instance. + @param[in] ProcessorNumber The handle number of processor. + @param[out] ProcessorInfoBuffer A pointer to the buffer where information for + the requested processor is deposited. + + @retval EFI_SUCCESS Processor information was returned. + @retval EFI_DEVICE_ERROR The calling processor is an AP. + @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL. + @retval EFI_NOT_FOUND The processor with the handle specified by + ProcessorNumber does not exist in the platform. +**/ +typedef +EFI_STATUS +(EFIAPI * EFI_SMM_GET_PROCESSOR_INFO) ( + IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This, + IN UINTN ProcessorNumber, + OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer + ); + +/** + This service switches the requested AP to be the BSP from that point onward. + This service changes the BSP for all purposes. This call can only be performed + by the current BSP. + + This service switches the requested AP to be the BSP from that point onward. + This service changes the BSP for all purposes. The new BSP can take over the + execution of the old BSP and continue seamlessly from where the old one left + off. + + If the BSP cannot be switched prior to the return from this service, then + EFI_UNSUPPORTED must be returned. + + @param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance. + @param[in] ProcessorNumber The handle number of AP that is to become the new + BSP. The range is from 0 to the total number of + logical processors minus 1. + + @retval EFI_SUCCESS BSP successfully switched. + @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to + this service returning. + @retval EFI_UNSUPPORTED Switching the BSP is not supported. + @retval EFI_SUCCESS The calling processor is an AP. + @retval EFI_NOT_FOUND The processor with the handle specified by + ProcessorNumber does not exist. + @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or + a disabled AP. + @retval EFI_NOT_READY The specified AP is busy. + +**/ +typedef +EFI_STATUS +(EFIAPI * EFI_SMM_SWITCH_BSP) ( + IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This, + IN UINTN ProcessorNumber + ); + +/** + Notify that a new processor has been added to the system. + + The SMM CPU driver should add the processor to the SMM CPU list. + + If the processor is disabled it won't participate any SMI handler during subsequent SMIs. + + @param This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance. + @param ProcessorId The hardware ID of the processor. + @param ProcessorNumber The handle number of processor. + @param ProcessorResource A pointer to EFI_SMM_PROCESSOR_RESOURCE which holds the assigned resources. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_ALREADY_STARTED Processor already present. + @retval EFI_NOT_READY Space for a new handle could not be allocated. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SMM_ADD_PROCESSOR) ( + IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This, + IN UINT64 ProcessorId, + OUT UINTN *ProcessorNumber + ); + +/** + Notify that a processor is hot-removed. + + Remove a processor from the CPU list of the SMM CPU driver. After this API is called, the removed processor + must not respond to SMIs in the coherence domain. + + @param This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance. + @param ProcessorId The hardware ID of the processor. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_NOT_FOUND Processor with the hardware ID specified by ProcessorId does not exist. + @retval EFI_NOT_READY Specified AP is busy. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SMM_REMOVE_PROCESSOR) ( + IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This, + IN UINTN ProcessorNumber + ); + +/** + This return the handle number for the calling processor. This service may be + called from the BSP and APs. + + This service returns the processor handle number for the calling processor. + The returned value is in the range from 0 to the total number of logical + processors minus 1. This service may be called from the BSP and APs. + If ProcessorNumber is NULL, then EFI_INVALID_PARAMETER + is returned. Otherwise, the current processors handle number is returned in + ProcessorNumber, and EFI_SUCCESS is returned. + + @param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance. + @param[in] ProcessorNumber The handle number of AP that is to become the new + BSP. The range is from 0 to the total number of + logical processors minus 1. + + @retval EFI_SUCCESS The current processor handle number was returned + in ProcessorNumber. + @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL. + +**/ +typedef +EFI_STATUS +(EFIAPI * EFI_SMM_WHOAMI) ( + IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This, + OUT UINTN *ProcessorNumber + ); + +/** + Register exception handler. + + @param This A pointer to the SMM_CPU_SERVICE_PROTOCOL instance. + @param ExceptionType Defines which interrupt or exception to hook. Type EFI_EXCEPTION_TYPE and + the valid values for this parameter are defined in EFI_DEBUG_SUPPORT_PROTOCOL + of the UEFI 2.0 specification. + @param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER + that is called when a processor interrupt occurs. + If this parameter is NULL, then the handler will be uninstalled. + + @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled. + @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was previously installed. + @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not previously installed. + @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SMM_REGISTER_EXCEPTION_HANDLER) ( + IN EFI_SMM_CPU_SERVICE_PROTOCOL *This, + IN EFI_EXCEPTION_TYPE ExceptionType, + IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler + ); + +// +// This protocol provides CPU services from SMM. +// +struct _EFI_SMM_CPU_SERVICE_PROTOCOL { + EFI_SMM_GET_PROCESSOR_INFO GetProcessorInfo; + EFI_SMM_SWITCH_BSP SwitchBsp; + EFI_SMM_ADD_PROCESSOR AddProcessor; + EFI_SMM_REMOVE_PROCESSOR RemoveProcessor; + EFI_SMM_WHOAMI WhoAmI; + EFI_SMM_REGISTER_EXCEPTION_HANDLER RegisterExceptionHandler; +}; + +extern EFI_GUID gEfiSmmCpuServiceProtocolGuid; + +#endif From 3f509e3056409219dbffa6a802d4c163ec40f2f9 Mon Sep 17 00:00:00 2001 From: Michael Kinney Date: Tue, 17 Nov 2015 05:00:55 +0000 Subject: [PATCH 120/525] UefiCpuPkg: Add SMRAM Save State include file Add SmramSaveStateMap.h file that defines the 32-bit and 64-bit CPU SMRAM Save State Map. (Sync patch r18641 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Michael Kinney Reviewed-by: Jeff Fan git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18836 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Include/Register/SmramSaveStateMap.h | 190 ++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 UefiCpuPkg/Include/Register/SmramSaveStateMap.h diff --git a/UefiCpuPkg/Include/Register/SmramSaveStateMap.h b/UefiCpuPkg/Include/Register/SmramSaveStateMap.h new file mode 100644 index 000000000000..a7c7562df8e8 --- /dev/null +++ b/UefiCpuPkg/Include/Register/SmramSaveStateMap.h @@ -0,0 +1,190 @@ +/** @file +SMRAM Save State Map Definitions. + +SMRAM Save State Map definitions based on contents of the +Intel(R) 64 and IA-32 Architectures Software Developer's Manual + Volume 3C, Section 34.4 SMRAM + Volume 3C, Section 34.5 SMI Handler Execution Environment + Volume 3C, Section 34.7 Managing Synchronous and Asynchronous SMIs + +Copyright (c) 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __SMRAM_SAVE_STATE_MAP_H__ +#define __SMRAM_SAVE_STATE_MAP_H__ + +/// +/// Default SMBASE address +/// +#define SMM_DEFAULT_SMBASE 0x30000 + +/// +/// Offset of SMM handler from SMBASE +/// +#define SMM_HANDLER_OFFSET 0x8000 + +/// +/// Offset of SMRAM Save State Map from SMBASE +/// +#define SMRAM_SAVE_STATE_MAP_OFFSET 0xfc00 + +#pragma pack (1) + +/// +/// 32-bit SMRAM Save State Map +/// +typedef struct { + UINT8 Reserved[0x200]; // 7c00h + // Padded an extra 0x200 bytes so 32-bit and 64-bit + // SMRAM Save State Maps are the same size + UINT8 Reserved1[0xf8]; // 7e00h + UINT32 SMBASE; // 7ef8h + UINT32 SMMRevId; // 7efch + UINT16 IORestart; // 7f00h + UINT16 AutoHALTRestart; // 7f02h + UINT8 Reserved2[0x9C]; // 7f08h + UINT32 IOMemAddr; // 7fa0h + UINT32 IOMisc; // 7fa4h + UINT32 _ES; // 7fa8h + UINT32 _CS; // 7fach + UINT32 _SS; // 7fb0h + UINT32 _DS; // 7fb4h + UINT32 _FS; // 7fb8h + UINT32 _GS; // 7fbch + UINT32 Reserved3; // 7fc0h + UINT32 _TR; // 7fc4h + UINT32 _DR7; // 7fc8h + UINT32 _DR6; // 7fcch + UINT32 _EAX; // 7fd0h + UINT32 _ECX; // 7fd4h + UINT32 _EDX; // 7fd8h + UINT32 _EBX; // 7fdch + UINT32 _ESP; // 7fe0h + UINT32 _EBP; // 7fe4h + UINT32 _ESI; // 7fe8h + UINT32 _EDI; // 7fech + UINT32 _EIP; // 7ff0h + UINT32 _EFLAGS; // 7ff4h + UINT32 _CR3; // 7ff8h + UINT32 _CR0; // 7ffch +} SMRAM_SAVE_STATE_MAP32; + +/// +/// 64-bit SMRAM Save State Map +/// +typedef struct { + UINT8 Reserved1[0x1d0]; // 7c00h + UINT32 GdtBaseHiDword; // 7dd0h + UINT32 LdtBaseHiDword; // 7dd4h + UINT32 IdtBaseHiDword; // 7dd8h + UINT8 Reserved2[0xc]; // 7ddch + UINT64 IO_EIP; // 7de8h + UINT8 Reserved3[0x50]; // 7df0h + UINT32 _CR4; // 7e40h + UINT8 Reserved4[0x48]; // 7e44h + UINT32 GdtBaseLoDword; // 7e8ch + UINT32 Reserved5; // 7e90h + UINT32 IdtBaseLoDword; // 7e94h + UINT32 Reserved6; // 7e98h + UINT32 LdtBaseLoDword; // 7e9ch + UINT8 Reserved7[0x38]; // 7ea0h + UINT64 EptVmxControl; // 7ed8h + UINT32 EnEptVmxControl; // 7ee0h + UINT8 Reserved8[0x14]; // 7ee4h + UINT32 SMBASE; // 7ef8h + UINT32 SMMRevId; // 7efch + UINT16 IORestart; // 7f00h + UINT16 AutoHALTRestart; // 7f02h + UINT8 Reserved9[0x18]; // 7f04h + UINT64 _R15; // 7f1ch + UINT64 _R14; + UINT64 _R13; + UINT64 _R12; + UINT64 _R11; + UINT64 _R10; + UINT64 _R9; + UINT64 _R8; + UINT64 _RAX; // 7f5ch + UINT64 _RCX; + UINT64 _RDX; + UINT64 _RBX; + UINT64 _RSP; + UINT64 _RBP; + UINT64 _RSI; + UINT64 _RDI; + UINT64 IOMemAddr; // 7f9ch + UINT32 IOMisc; // 7fa4h + UINT32 _ES; // 7fa8h + UINT32 _CS; + UINT32 _SS; + UINT32 _DS; + UINT32 _FS; + UINT32 _GS; + UINT32 _LDTR; // 7fc0h + UINT32 _TR; + UINT64 _DR7; // 7fc8h + UINT64 _DR6; + UINT64 _RIP; // 7fd8h + UINT64 IA32_EFER; // 7fe0h + UINT64 _RFLAGS; // 7fe8h + UINT64 _CR3; // 7ff0h + UINT64 _CR0; // 7ff8h +} SMRAM_SAVE_STATE_MAP64; + +/// +/// Union of 32-bit and 64-bit SMRAM Save State Maps +/// +typedef union { + SMRAM_SAVE_STATE_MAP32 x86; + SMRAM_SAVE_STATE_MAP64 x64; +} SMRAM_SAVE_STATE_MAP; + +/// +/// Minimum SMM Revision ID that supports IOMisc field in SMRAM Save State Map +/// +#define SMRAM_SAVE_STATE_MIN_REV_ID_IOMISC 0x30004 + +/// +/// SMRAM Save State Map IOMisc I/O Length Values +/// +#define SMM_IO_LENGTH_BYTE 0x01 +#define SMM_IO_LENGTH_WORD 0x02 +#define SMM_IO_LENGTH_DWORD 0x04 + +/// +/// SMRAM Save State Map IOMisc I/O Instruction Type Values +/// +#define SMM_IO_TYPE_IN_IMMEDIATE 0x9 +#define SMM_IO_TYPE_IN_DX 0x1 +#define SMM_IO_TYPE_OUT_IMMEDIATE 0x8 +#define SMM_IO_TYPE_OUT_DX 0x0 +#define SMM_IO_TYPE_INS 0x3 +#define SMM_IO_TYPE_OUTS 0x2 +#define SMM_IO_TYPE_REP_INS 0x7 +#define SMM_IO_TYPE_REP_OUTS 0x6 + +/// +/// SMRAM Save State Map IOMisc structure +/// +typedef union { + struct { + UINT32 SmiFlag:1; + UINT32 Length:3; + UINT32 Type:4; + UINT32 Reserved1:8; + UINT32 Port:16; + } Bits; + UINT32 Uint32; +} SMRAM_SAVE_STATE_IOMISC; + +#pragma pack () + +#endif From 2c32377264945f4e43d02987a1398be6b4231ce7 Mon Sep 17 00:00:00 2001 From: Michael Kinney Date: Tue, 17 Nov 2015 05:01:42 +0000 Subject: [PATCH 121/525] UefiCpuPkg: Add ACPI CPU Data include file Add AcpuCpuData.h that defines a data structure that is shared between modules and is required for ACPI S3 support. APState field removed between V1 and V2 patch. (Sync patch r18642 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Michael Kinney Cc: Laszlo Ersek Reviewed-by: Laszlo Ersek Reviewed-by: Jeff Fan git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18837 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/Include/AcpiCpuData.h | 71 ++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 UefiCpuPkg/Include/AcpiCpuData.h diff --git a/UefiCpuPkg/Include/AcpiCpuData.h b/UefiCpuPkg/Include/AcpiCpuData.h new file mode 100644 index 000000000000..a36725711cd8 --- /dev/null +++ b/UefiCpuPkg/Include/AcpiCpuData.h @@ -0,0 +1,71 @@ +/** @file +Definitions for CPU S3 data. + +Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _ACPI_CPU_DATA_H_ +#define _ACPI_CPU_DATA_H_ + +// +// Register types in register table +// +typedef enum _REGISTER_TYPE { + Msr, + ControlRegister, + MemoryMapped, + CacheControl +} REGISTER_TYPE; + +// +// Element of register table entry +// +typedef struct { + REGISTER_TYPE RegisterType; + UINT32 Index; + UINT8 ValidBitStart; + UINT8 ValidBitLength; + UINT64 Value; +} CPU_REGISTER_TABLE_ENTRY; + +// +// Register table definition, including current table length, +// allocated size of this table, and pointer to the list of table entries. +// +typedef struct { + UINT32 TableLength; + UINT32 NumberBeforeReset; + UINT32 AllocatedSize; + UINT32 InitialApicId; + CPU_REGISTER_TABLE_ENTRY *RegisterTableEntry; +} CPU_REGISTER_TABLE; + +typedef struct { + EFI_PHYSICAL_ADDRESS StartupVector; + EFI_PHYSICAL_ADDRESS GdtrProfile; + EFI_PHYSICAL_ADDRESS IdtrProfile; + EFI_PHYSICAL_ADDRESS StackAddress; + UINT32 StackSize; + UINT32 NumberOfCpus; + EFI_PHYSICAL_ADDRESS MtrrTable; + // + // Physical address of a CPU_REGISTER_TABLE structure + // + EFI_PHYSICAL_ADDRESS PreSmmInitRegisterTable; + // + // Physical address of a CPU_REGISTER_TABLE structure + // + EFI_PHYSICAL_ADDRESS RegisterTable; + EFI_PHYSICAL_ADDRESS ApMachineCheckHandlerBase; + UINT32 ApMachineCheckHandlerSize; +} ACPI_CPU_DATA; + +#endif From a5f9b8d642ca18a6f9a52cc90658c4dfb3d288e4 Mon Sep 17 00:00:00 2001 From: Michael Kinney Date: Tue, 17 Nov 2015 05:02:24 +0000 Subject: [PATCH 122/525] UefiCpuPkg: Add CPU Hot Plug Data include file Add CpuHotPlugData.h that defines a data structure that is shared between modules and is required for to support hot plug CPUs. (Sync patch r18643 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Michael Kinney Reviewed-by: Jeff Fan git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18838 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/Include/CpuHotPlugData.h | 33 +++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 UefiCpuPkg/Include/CpuHotPlugData.h diff --git a/UefiCpuPkg/Include/CpuHotPlugData.h b/UefiCpuPkg/Include/CpuHotPlugData.h new file mode 100644 index 000000000000..2a0d9fabd5b5 --- /dev/null +++ b/UefiCpuPkg/Include/CpuHotPlugData.h @@ -0,0 +1,33 @@ +/** @file +Definition for a structure sharing information for CPU hot plug. + +Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _CPU_HOT_PLUG_DATA_H_ +#define _CPU_HOT_PLUG_DATA_H_ + +#define CPU_HOT_PLUG_DATA_REVISION_1 0x00000001 + +typedef struct { + UINT32 Revision; // Used for version identification for this structure + UINT32 ArrayLength; // The entries number of the following ApicId array and SmBase array + // + // Data required for SMBASE relocation + // + UINT64 *ApicId; // Pointer to ApicId array + UINTN *SmBase; // Pointer to SmBase array + UINT32 Reserved; + UINT32 SmrrBase; + UINT32 SmrrSize; +} CPU_HOT_PLUG_DATA; + +#endif From fb0d7d0169376f20b98ded3a79e59f59015910ad Mon Sep 17 00:00:00 2001 From: Michael Kinney Date: Tue, 17 Nov 2015 05:03:17 +0000 Subject: [PATCH 123/525] UefiCpuPkg: Update DEC/DSC files for new includes and libraries Add SmmCpuPlatformHookLib library class declaration Add SmmCpuFeaturesLib library class declaration Add gEfiSmmCpuServiceProtocolGuid protocol declaration Build SmmCpuPlatformHookLibNull library instance Build SmmCpuFeaturesLib library instance Changes between [PATCH v1] and [PATCH v2]: 1) Use module type specific CpuExceptionHandlerLib in DSC file instead of Null library instance (Sync patch r18644 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Michael Kinney Cc: Laszlo Ersek Reviewed-by: Laszlo Ersek Reviewed-by: Jeff Fan git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18839 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/UefiCpuPkg.dec | 13 ++++++++++++- UefiCpuPkg/UefiCpuPkg.dsc | 10 ++++++++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec index fe9b2a5f27cc..4f7065fca604 100644 --- a/UefiCpuPkg/UefiCpuPkg.dec +++ b/UefiCpuPkg/UefiCpuPkg.dec @@ -41,11 +41,22 @@ ## @libraryclass Provides platform specific initialization functions in the SEC phase. ## PlatformSecLib|Include/Library/PlatformSecLib.h - + ## @libraryclass Public include file for the SMM CPU Platform Hook Library. + ## + SmmCpuPlatformHookLib|Include/Library/SmmCpuPlatformHookLib.h + + ## @libraryclass Provides the CPU specific programming for PiSmmCpuDxeSmm module. + ## + SmmCpuFeaturesLib|Include/Library/SmmCpuFeaturesLib.h + [Guids] gUefiCpuPkgTokenSpaceGuid = { 0xac05bf33, 0x995a, 0x4ed4, { 0xaa, 0xb8, 0xef, 0x7a, 0xe8, 0xf, 0x5c, 0xb0 }} +[Protocols] + ## Include/Protocol/SmmCpuService.h + gEfiSmmCpuServiceProtocolGuid = { 0x1d202cab, 0xc8ab, 0x4d5c, { 0x94, 0xf7, 0x3c, 0xfc, 0xc0, 0xd3, 0xd3, 0x35 }} + # # [Error.gUefiCpuPkgTokenSpaceGuid] # 0x80000001 | Invalid value provided. diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc index 68400e3cf8c8..961c970418d6 100644 --- a/UefiCpuPkg/UefiCpuPkg.dsc +++ b/UefiCpuPkg/UefiCpuPkg.dsc @@ -32,6 +32,7 @@ BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf CpuLib|MdePkg/Library/BaseCpuLib/BaseCpuLib.inf DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf + SerialPortLib|MdePkg/Library/BaseSerialPortLibNull/BaseSerialPortLibNull.inf DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf UefiCpuLib|UefiCpuPkg/Library/BaseUefiCpuLib/BaseUefiCpuLib.inf @@ -51,14 +52,16 @@ DebugAgentLib|MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf LocalApicLib|UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.inf ReportStatusCodeLib|MdePkg/Library/BaseReportStatusCodeLibNull/BaseReportStatusCodeLibNull.inf - CpuExceptionHandlerLib|MdeModulePkg/Library/CpuExceptionHandlerLibNull/CpuExceptionHandlerLibNull.inf SynchronizationLib|MdePkg/Library/BaseSynchronizationLib/BaseSynchronizationLib.inf SmmMemLib|MdePkg/Library/SmmMemLib/SmmMemLib.inf + SmmCpuPlatformHookLib|UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.inf + SmmCpuFeaturesLib|UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf [LibraryClasses.common.SEC] PlatformSecLib|UefiCpuPkg/Library/PlatformSecLibNull/PlatformSecLibNull.inf + CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf [LibraryClasses.common.PEIM] MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf @@ -74,11 +77,13 @@ [LibraryClasses.common.DXE_DRIVER] MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf + CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf [LibraryClasses.common.DXE_SMM_DRIVER] SmmServicesTableLib|MdePkg/Library/SmmServicesTableLib/SmmServicesTableLib.inf MemoryAllocationLib|MdePkg/Library/SmmMemoryAllocationLib/SmmMemoryAllocationLib.inf HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf + CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.inf # # Drivers/Libraries within this package @@ -101,8 +106,9 @@ UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.inf UefiCpuPkg/Library/PlatformSecLibNull/PlatformSecLibNull.inf + UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.inf + UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationPei.inf UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationSmm.inf UefiCpuPkg/SecCore/SecCore.inf UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume2Pei.inf - From b6d5be554045c818072df05636aa0e897c1b18b2 Mon Sep 17 00:00:00 2001 From: Michael Kinney Date: Tue, 17 Nov 2015 05:04:08 +0000 Subject: [PATCH 124/525] UefiCpuPkg: Add PiSmmCpuDxeSmm module no IA32/X64 files Add module that initializes a CPU for the SMM environment and installs the first level SMI handler. This module along with the SMM IPL and SMM Core provide the services required for DXE_SMM_DRIVERS to register hardware and software SMI handlers. CPU specific features are abstracted through the SmmCpuFeaturesLib Platform specific features are abstracted through the SmmCpuPlatformHookLib Several PCDs are added to enable/disable features and configure settings for the PiSmmCpuDxeSmm module Changes between [PATCH v1] and [PATCH v2]: 1) Swap PTE init order for QEMU compatibility. Current PTE initialization algorithm works on HW but breaks QEMU emulator. Update the PTE initialization order to be compatible with both. 2) Update comment block that describes 32KB SMBASE alignment requirement to match contents of Intel(R) 64 and IA-32 Architectures Software Developer's Manual 3) Remove BUGBUG comment and call to ClearSmi() that is not required. SMI should be cleared by root SMI handler. (Sync patch r18645 from main trunk.) [jeff.fan@intel.com: Fix code style issues reported by ECC] Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Michael Kinney Cc: Laszlo Ersek Cc: Paolo Bonzini [pbonzini@redhat.com: InitPaging: prepare PT before filling in PDE] Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Paolo Bonzini Acked-by: Laszlo Ersek Reviewed-by: Jeff Fan git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18840 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/PiSmmCpuDxeSmm/CpuS3.c | 491 ++++++ UefiCpuPkg/PiSmmCpuDxeSmm/CpuService.c | 486 ++++++ UefiCpuPkg/PiSmmCpuDxeSmm/CpuService.h | 181 ++ UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c | 1327 +++++++++++++++ UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c | 1489 +++++++++++++++++ UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h | 699 ++++++++ UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf | 163 ++ UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.uni | Bin 0 -> 1868 bytes .../PiSmmCpuDxeSmm/PiSmmCpuDxeSmmExtra.uni | Bin 0 -> 1378 bytes UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.c | 1443 ++++++++++++++++ UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.h | 134 ++ .../PiSmmCpuDxeSmm/SmmProfileInternal.h | 172 ++ UefiCpuPkg/PiSmmCpuDxeSmm/SmramSaveState.c | 700 ++++++++ UefiCpuPkg/PiSmmCpuDxeSmm/SyncTimer.c | 116 ++ UefiCpuPkg/UefiCpuPkg.dec | 108 +- UefiCpuPkg/UefiCpuPkg.uni | Bin 7222 -> 21898 bytes 16 files changed, 7503 insertions(+), 6 deletions(-) create mode 100644 UefiCpuPkg/PiSmmCpuDxeSmm/CpuS3.c create mode 100644 UefiCpuPkg/PiSmmCpuDxeSmm/CpuService.c create mode 100644 UefiCpuPkg/PiSmmCpuDxeSmm/CpuService.h create mode 100644 UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c create mode 100644 UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c create mode 100644 UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h create mode 100644 UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf create mode 100644 UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.uni create mode 100644 UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmmExtra.uni create mode 100644 UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.c create mode 100644 UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.h create mode 100644 UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfileInternal.h create mode 100644 UefiCpuPkg/PiSmmCpuDxeSmm/SmramSaveState.c create mode 100644 UefiCpuPkg/PiSmmCpuDxeSmm/SyncTimer.c diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/CpuS3.c b/UefiCpuPkg/PiSmmCpuDxeSmm/CpuS3.c new file mode 100644 index 000000000000..bbff6e18b437 --- /dev/null +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/CpuS3.c @@ -0,0 +1,491 @@ +/** @file +Code for Processor S3 restoration + +Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "PiSmmCpuDxeSmm.h" + +typedef struct { + UINTN Lock; + VOID *StackStart; + UINTN StackSize; + VOID *ApFunction; + IA32_DESCRIPTOR GdtrProfile; + IA32_DESCRIPTOR IdtrProfile; + UINT32 BufferStart; + UINT32 Cr3; +} MP_CPU_EXCHANGE_INFO; + +typedef struct { + UINT8 *RendezvousFunnelAddress; + UINTN PModeEntryOffset; + UINTN FlatJumpOffset; + UINTN Size; + UINTN LModeEntryOffset; + UINTN LongJumpOffset; +} MP_ASSEMBLY_ADDRESS_MAP; + +/** + Get starting address and size of the rendezvous entry for APs. + Information for fixing a jump instruction in the code is also returned. + + @param AddressMap Output buffer for address map information. +**/ +VOID * +EFIAPI +AsmGetAddressMap ( + MP_ASSEMBLY_ADDRESS_MAP *AddressMap + ); + +#define LEGACY_REGION_SIZE (2 * 0x1000) +#define LEGACY_REGION_BASE (0xA0000 - LEGACY_REGION_SIZE) +#define MSR_SPIN_LOCK_INIT_NUM 15 + +ACPI_CPU_DATA mAcpiCpuData; +UINT32 mNumberToFinish; +MP_CPU_EXCHANGE_INFO *mExchangeInfo; +BOOLEAN mRestoreSmmConfigurationInS3 = FALSE; +VOID *mGdtForAp = NULL; +VOID *mIdtForAp = NULL; +VOID *mMachineCheckHandlerForAp = NULL; +MP_MSR_LOCK *mMsrSpinLocks = NULL; +UINTN mMsrSpinLockCount = MSR_SPIN_LOCK_INIT_NUM; +UINTN mMsrCount = 0; + +/** + Get MSR spin lock by MSR index. + + @param MsrIndex MSR index value. + + @return Pointer to MSR spin lock. + +**/ +SPIN_LOCK * +GetMsrSpinLockByIndex ( + IN UINT32 MsrIndex + ) +{ + UINTN Index; + for (Index = 0; Index < mMsrCount; Index++) { + if (MsrIndex == mMsrSpinLocks[Index].MsrIndex) { + return &mMsrSpinLocks[Index].SpinLock; + } + } + return NULL; +} + +/** + Initialize MSR spin lock by MSR index. + + @param MsrIndex MSR index value. + +**/ +VOID +InitMsrSpinLockByIndex ( + IN UINT32 MsrIndex + ) +{ + UINTN NewMsrSpinLockCount; + + if (mMsrSpinLocks == NULL) { + mMsrSpinLocks = (MP_MSR_LOCK *) AllocatePool (sizeof (MP_MSR_LOCK) * mMsrSpinLockCount); + ASSERT (mMsrSpinLocks != NULL); + } + if (GetMsrSpinLockByIndex (MsrIndex) == NULL) { + // + // Initialize spin lock for MSR programming + // + mMsrSpinLocks[mMsrCount].MsrIndex = MsrIndex; + InitializeSpinLock (&mMsrSpinLocks[mMsrCount].SpinLock); + mMsrCount ++; + if (mMsrCount == mMsrSpinLockCount) { + // + // If MSR spin lock buffer is full, enlarge it + // + NewMsrSpinLockCount = mMsrSpinLockCount + MSR_SPIN_LOCK_INIT_NUM; + mMsrSpinLocks = ReallocatePool ( + sizeof (MP_MSR_LOCK) * mMsrSpinLockCount, + sizeof (MP_MSR_LOCK) * NewMsrSpinLockCount, + mMsrSpinLocks + ); + mMsrSpinLockCount = NewMsrSpinLockCount; + } + } +} + +/** + Sync up the MTRR values for all processors. + + @param MtrrTable Table holding fixed/variable MTRR values to be loaded. +**/ +VOID +EFIAPI +LoadMtrrData ( + EFI_PHYSICAL_ADDRESS MtrrTable + ) +/*++ + +Routine Description: + + Sync up the MTRR values for all processors. + +Arguments: + +Returns: + None + +--*/ +{ + MTRR_SETTINGS *MtrrSettings; + + MtrrSettings = (MTRR_SETTINGS *) (UINTN) MtrrTable; + MtrrSetAllMtrrs (MtrrSettings); +} + +/** + Programs registers for the calling processor. + + This function programs registers for the calling processor. + + @param RegisterTable Pointer to register table of the running processor. + +**/ +VOID +SetProcessorRegister ( + IN CPU_REGISTER_TABLE *RegisterTable + ) +{ + CPU_REGISTER_TABLE_ENTRY *RegisterTableEntry; + UINTN Index; + UINTN Value; + SPIN_LOCK *MsrSpinLock; + + // + // Traverse Register Table of this logical processor + // + RegisterTableEntry = (CPU_REGISTER_TABLE_ENTRY *) (UINTN) RegisterTable->RegisterTableEntry; + for (Index = 0; Index < RegisterTable->TableLength; Index++, RegisterTableEntry++) { + // + // Check the type of specified register + // + switch (RegisterTableEntry->RegisterType) { + // + // The specified register is Control Register + // + case ControlRegister: + switch (RegisterTableEntry->Index) { + case 0: + Value = AsmReadCr0 (); + Value = (UINTN) BitFieldWrite64 ( + Value, + RegisterTableEntry->ValidBitStart, + RegisterTableEntry->ValidBitStart + RegisterTableEntry->ValidBitLength - 1, + (UINTN) RegisterTableEntry->Value + ); + AsmWriteCr0 (Value); + break; + case 2: + Value = AsmReadCr2 (); + Value = (UINTN) BitFieldWrite64 ( + Value, + RegisterTableEntry->ValidBitStart, + RegisterTableEntry->ValidBitStart + RegisterTableEntry->ValidBitLength - 1, + (UINTN) RegisterTableEntry->Value + ); + AsmWriteCr2 (Value); + break; + case 3: + Value = AsmReadCr3 (); + Value = (UINTN) BitFieldWrite64 ( + Value, + RegisterTableEntry->ValidBitStart, + RegisterTableEntry->ValidBitStart + RegisterTableEntry->ValidBitLength - 1, + (UINTN) RegisterTableEntry->Value + ); + AsmWriteCr3 (Value); + break; + case 4: + Value = AsmReadCr4 (); + Value = (UINTN) BitFieldWrite64 ( + Value, + RegisterTableEntry->ValidBitStart, + RegisterTableEntry->ValidBitStart + RegisterTableEntry->ValidBitLength - 1, + (UINTN) RegisterTableEntry->Value + ); + AsmWriteCr4 (Value); + break; + default: + break; + } + break; + // + // The specified register is Model Specific Register + // + case Msr: + // + // If this function is called to restore register setting after INIT signal, + // there is no need to restore MSRs in register table. + // + if (RegisterTableEntry->ValidBitLength >= 64) { + // + // If length is not less than 64 bits, then directly write without reading + // + AsmWriteMsr64 ( + RegisterTableEntry->Index, + RegisterTableEntry->Value + ); + } else { + // + // Get lock to avoid Package/Core scope MSRs programming issue in parallel execution mode + // to make sure MSR read/write operation is atomic. + // + MsrSpinLock = GetMsrSpinLockByIndex (RegisterTableEntry->Index); + AcquireSpinLock (MsrSpinLock); + // + // Set the bit section according to bit start and length + // + AsmMsrBitFieldWrite64 ( + RegisterTableEntry->Index, + RegisterTableEntry->ValidBitStart, + RegisterTableEntry->ValidBitStart + RegisterTableEntry->ValidBitLength - 1, + RegisterTableEntry->Value + ); + ReleaseSpinLock (MsrSpinLock); + } + break; + // + // Enable or disable cache + // + case CacheControl: + // + // If value of the entry is 0, then disable cache. Otherwise, enable cache. + // + if (RegisterTableEntry->Value == 0) { + AsmDisableCache (); + } else { + AsmEnableCache (); + } + break; + + default: + break; + } + } +} + +/** + AP initialization before SMBASE relocation in the S3 boot path. +**/ +VOID +EarlyMPRendezvousProcedure ( + VOID + ) +{ + CPU_REGISTER_TABLE *RegisterTableList; + UINT32 InitApicId; + UINTN Index; + + LoadMtrrData (mAcpiCpuData.MtrrTable); + + // + // Find processor number for this CPU. + // + RegisterTableList = (CPU_REGISTER_TABLE *) (UINTN) mAcpiCpuData.PreSmmInitRegisterTable; + InitApicId = GetInitialApicId (); + for (Index = 0; Index < mAcpiCpuData.NumberOfCpus; Index++) { + if (RegisterTableList[Index].InitialApicId == InitApicId) { + SetProcessorRegister (&RegisterTableList[Index]); + break; + } + } + + // + // Count down the number with lock mechanism. + // + InterlockedDecrement (&mNumberToFinish); +} + +/** + AP initialization after SMBASE relocation in the S3 boot path. +**/ +VOID +MPRendezvousProcedure ( + VOID + ) +{ + CPU_REGISTER_TABLE *RegisterTableList; + UINT32 InitApicId; + UINTN Index; + + ProgramVirtualWireMode (); + DisableLvtInterrupts (); + + RegisterTableList = (CPU_REGISTER_TABLE *) (UINTN) mAcpiCpuData.RegisterTable; + InitApicId = GetInitialApicId (); + for (Index = 0; Index < mAcpiCpuData.NumberOfCpus; Index++) { + if (RegisterTableList[Index].InitialApicId == InitApicId) { + SetProcessorRegister (&RegisterTableList[Index]); + break; + } + } + + // + // Count down the number with lock mechanism. + // + InterlockedDecrement (&mNumberToFinish); +} + +/** + Prepares startup vector for APs. + + This function prepares startup vector for APs. + + @param WorkingBuffer The address of the work buffer. +**/ +VOID +PrepareApStartupVector ( + EFI_PHYSICAL_ADDRESS WorkingBuffer + ) +{ + EFI_PHYSICAL_ADDRESS StartupVector; + MP_ASSEMBLY_ADDRESS_MAP AddressMap; + + // + // Get the address map of startup code for AP, + // including code size, and offset of long jump instructions to redirect. + // + ZeroMem (&AddressMap, sizeof (AddressMap)); + AsmGetAddressMap (&AddressMap); + + StartupVector = WorkingBuffer; + + // + // Copy AP startup code to startup vector, and then redirect the long jump + // instructions for mode switching. + // + CopyMem ((VOID *) (UINTN) StartupVector, AddressMap.RendezvousFunnelAddress, AddressMap.Size); + *(UINT32 *) (UINTN) (StartupVector + AddressMap.FlatJumpOffset + 3) = (UINT32) (StartupVector + AddressMap.PModeEntryOffset); + if (AddressMap.LongJumpOffset != 0) { + *(UINT32 *) (UINTN) (StartupVector + AddressMap.LongJumpOffset + 2) = (UINT32) (StartupVector + AddressMap.LModeEntryOffset); + } + + // + // Get the start address of exchange data between BSP and AP. + // + mExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (StartupVector + AddressMap.Size); + ZeroMem ((VOID *) mExchangeInfo, sizeof (MP_CPU_EXCHANGE_INFO)); + + CopyMem ((VOID *) (UINTN) &mExchangeInfo->GdtrProfile, (VOID *) (UINTN) mAcpiCpuData.GdtrProfile, sizeof (IA32_DESCRIPTOR)); + CopyMem ((VOID *) (UINTN) &mExchangeInfo->IdtrProfile, (VOID *) (UINTN) mAcpiCpuData.IdtrProfile, sizeof (IA32_DESCRIPTOR)); + + // + // Copy AP's GDT, IDT and Machine Check handler from SMRAM to ACPI NVS memory + // + CopyMem ((VOID *) mExchangeInfo->GdtrProfile.Base, mGdtForAp, mExchangeInfo->GdtrProfile.Limit + 1); + CopyMem ((VOID *) mExchangeInfo->IdtrProfile.Base, mIdtForAp, mExchangeInfo->IdtrProfile.Limit + 1); + CopyMem ((VOID *)(UINTN) mAcpiCpuData.ApMachineCheckHandlerBase, mMachineCheckHandlerForAp, mAcpiCpuData.ApMachineCheckHandlerSize); + + mExchangeInfo->StackStart = (VOID *) (UINTN) mAcpiCpuData.StackAddress; + mExchangeInfo->StackSize = mAcpiCpuData.StackSize; + mExchangeInfo->BufferStart = (UINT32) StartupVector; + mExchangeInfo->Cr3 = (UINT32) (AsmReadCr3 ()); +} + +/** + The function is invoked before SMBASE relocation in S3 path to restores CPU status. + + The function is invoked before SMBASE relocation in S3 path. It does first time microcode load + and restores MTRRs for both BSP and APs. + +**/ +VOID +EarlyInitializeCpu ( + VOID + ) +{ + CPU_REGISTER_TABLE *RegisterTableList; + UINT32 InitApicId; + UINTN Index; + + LoadMtrrData (mAcpiCpuData.MtrrTable); + + // + // Find processor number for this CPU. + // + RegisterTableList = (CPU_REGISTER_TABLE *) (UINTN) mAcpiCpuData.PreSmmInitRegisterTable; + InitApicId = GetInitialApicId (); + for (Index = 0; Index < mAcpiCpuData.NumberOfCpus; Index++) { + if (RegisterTableList[Index].InitialApicId == InitApicId) { + SetProcessorRegister (&RegisterTableList[Index]); + break; + } + } + + ProgramVirtualWireMode (); + + PrepareApStartupVector (mAcpiCpuData.StartupVector); + + mNumberToFinish = mAcpiCpuData.NumberOfCpus - 1; + mExchangeInfo->ApFunction = (VOID *) (UINTN) EarlyMPRendezvousProcedure; + + // + // Send INIT IPI - SIPI to all APs + // + SendInitSipiSipiAllExcludingSelf ((UINT32)mAcpiCpuData.StartupVector); + + while (mNumberToFinish > 0) { + CpuPause (); + } +} + +/** + The function is invoked after SMBASE relocation in S3 path to restores CPU status. + + The function is invoked after SMBASE relocation in S3 path. It restores configuration according to + data saved by normal boot path for both BSP and APs. + +**/ +VOID +InitializeCpu ( + VOID + ) +{ + CPU_REGISTER_TABLE *RegisterTableList; + UINT32 InitApicId; + UINTN Index; + + RegisterTableList = (CPU_REGISTER_TABLE *) (UINTN) mAcpiCpuData.RegisterTable; + InitApicId = GetInitialApicId (); + for (Index = 0; Index < mAcpiCpuData.NumberOfCpus; Index++) { + if (RegisterTableList[Index].InitialApicId == InitApicId) { + SetProcessorRegister (&RegisterTableList[Index]); + break; + } + } + + mNumberToFinish = mAcpiCpuData.NumberOfCpus - 1; + // + // StackStart was updated when APs were waken up in EarlyInitializeCpu. + // Re-initialize StackAddress to original beginning address. + // + mExchangeInfo->StackStart = (VOID *) (UINTN) mAcpiCpuData.StackAddress; + mExchangeInfo->ApFunction = (VOID *) (UINTN) MPRendezvousProcedure; + + // + // Send INIT IPI - SIPI to all APs + // + SendInitSipiSipiAllExcludingSelf ((UINT32)mAcpiCpuData.StartupVector); + + while (mNumberToFinish > 0) { + CpuPause (); + } +} diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/CpuService.c b/UefiCpuPkg/PiSmmCpuDxeSmm/CpuService.c new file mode 100644 index 000000000000..40f2a1719d5b --- /dev/null +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/CpuService.c @@ -0,0 +1,486 @@ +/** @file +Implementation of SMM CPU Services Protocol. + +Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "PiSmmCpuDxeSmm.h" + +// +// SMM CPU Service Protocol instance +// +EFI_SMM_CPU_SERVICE_PROTOCOL mSmmCpuService = { + SmmGetProcessorInfo, + SmmSwitchBsp, + SmmAddProcessor, + SmmRemoveProcessor, + SmmWhoAmI, + SmmRegisterExceptionHandler +}; + +/** + Get Package ID/Core ID/Thread ID of a processor. + + APIC ID must be an initial APIC ID. + + The algorithm below assumes the target system has symmetry across physical package boundaries + with respect to the number of logical processors per package, number of cores per package. + + @param ApicId APIC ID of the target logical processor. + @param Location Returns the processor location information. +**/ +VOID +SmmGetProcessorLocation ( + IN UINT32 ApicId, + OUT EFI_CPU_PHYSICAL_LOCATION *Location + ) +{ + UINTN ThreadBits; + UINTN CoreBits; + UINT32 RegEax; + UINT32 RegEbx; + UINT32 RegEcx; + UINT32 RegEdx; + UINT32 MaxCpuIdIndex; + UINT32 SubIndex; + UINTN LevelType; + UINT32 MaxLogicProcessorsPerPackage; + UINT32 MaxCoresPerPackage; + BOOLEAN TopologyLeafSupported; + + ASSERT (Location != NULL); + + ThreadBits = 0; + CoreBits = 0; + TopologyLeafSupported = FALSE; + + // + // Check if the processor is capable of supporting more than one logical processor. + // + AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &RegEdx); + ASSERT ((RegEdx & BIT28) != 0); + + // + // Assume three-level mapping of APIC ID: Package:Core:SMT. + // + + // + // Get the max index of basic CPUID + // + AsmCpuid (CPUID_SIGNATURE, &MaxCpuIdIndex, NULL, NULL, NULL); + + // + // If the extended topology enumeration leaf is available, it + // is the preferred mechanism for enumerating topology. + // + if (MaxCpuIdIndex >= CPUID_EXTENDED_TOPOLOGY) { + AsmCpuidEx (CPUID_EXTENDED_TOPOLOGY, 0, &RegEax, &RegEbx, &RegEcx, NULL); + // + // If CPUID.(EAX=0BH, ECX=0H):EBX returns zero and maximum input value for + // basic CPUID information is greater than 0BH, then CPUID.0BH leaf is not + // supported on that processor. + // + if ((RegEbx & 0xffff) != 0) { + TopologyLeafSupported = TRUE; + + // + // Sub-leaf index 0 (ECX= 0 as input) provides enumeration parameters to extract + // the SMT sub-field of x2APIC ID. + // + LevelType = (RegEcx >> 8) & 0xff; + ASSERT (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT); + if ((RegEbx & 0xffff) > 1 ) { + ThreadBits = RegEax & 0x1f; + } else { + // + // HT is not supported + // + ThreadBits = 0; + } + + // + // Software must not assume any "level type" encoding + // value to be related to any sub-leaf index, except sub-leaf 0. + // + SubIndex = 1; + do { + AsmCpuidEx (CPUID_EXTENDED_TOPOLOGY, SubIndex, &RegEax, NULL, &RegEcx, NULL); + LevelType = (RegEcx >> 8) & 0xff; + if (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_CORE) { + CoreBits = (RegEax & 0x1f) - ThreadBits; + break; + } + SubIndex++; + } while (LevelType != CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_INVALID); + } + } + + if (!TopologyLeafSupported) { + AsmCpuid (CPUID_VERSION_INFO, NULL, &RegEbx, NULL, NULL); + MaxLogicProcessorsPerPackage = (RegEbx >> 16) & 0xff; + if (MaxCpuIdIndex >= CPUID_CACHE_PARAMS) { + AsmCpuidEx (CPUID_CACHE_PARAMS, 0, &RegEax, NULL, NULL, NULL); + MaxCoresPerPackage = (RegEax >> 26) + 1; + } else { + // + // Must be a single-core processor. + // + MaxCoresPerPackage = 1; + } + + ThreadBits = (UINTN) (HighBitSet32 (MaxLogicProcessorsPerPackage / MaxCoresPerPackage - 1) + 1); + CoreBits = (UINTN) (HighBitSet32 (MaxCoresPerPackage - 1) + 1); + } + + Location->Thread = ApicId & ~((-1) << ThreadBits); + Location->Core = (ApicId >> ThreadBits) & ~((-1) << CoreBits); + Location->Package = (ApicId >> (ThreadBits+ CoreBits)); +} + +/** + Gets processor information on the requested processor at the instant this call is made. + + @param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance. + @param[in] ProcessorNumber The handle number of processor. + @param[out] ProcessorInfoBuffer A pointer to the buffer where information for + the requested processor is deposited. + + @retval EFI_SUCCESS Processor information was returned. + @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL. + @retval EFI_INVALID_PARAMETER ProcessorNumber is invalid. + @retval EFI_NOT_FOUND The processor with the handle specified by + ProcessorNumber does not exist in the platform. + +**/ +EFI_STATUS +EFIAPI +SmmGetProcessorInfo ( + IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This, + IN UINTN ProcessorNumber, + OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer + ) +{ + // + // Check parameter + // + if (ProcessorNumber >= mMaxNumberOfCpus || ProcessorInfoBuffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (gSmmCpuPrivate->ProcessorInfo[ProcessorNumber].ProcessorId == INVALID_APIC_ID) { + return EFI_NOT_FOUND; + } + + // + // Fill in processor information + // + CopyMem (ProcessorInfoBuffer, &gSmmCpuPrivate->ProcessorInfo[ProcessorNumber], sizeof (EFI_PROCESSOR_INFORMATION)); + return EFI_SUCCESS; +} + +/** + This service switches the requested AP to be the BSP since the next SMI. + + @param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance. + @param[in] ProcessorNumber The handle number of AP that is to become the new BSP. + + @retval EFI_SUCCESS BSP will be switched in next SMI. + @retval EFI_UNSUPPORTED Switching the BSP or a processor to be hot-removed is not supported. + @retval EFI_NOT_FOUND The processor with the handle specified by ProcessorNumber does not exist. + @retval EFI_INVALID_PARAMETER ProcessorNumber is invalid. +**/ +EFI_STATUS +EFIAPI +SmmSwitchBsp ( + IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This, + IN UINTN ProcessorNumber + ) +{ + // + // Check parameter + // + if (ProcessorNumber >= mMaxNumberOfCpus) { + return EFI_INVALID_PARAMETER; + } + + if (gSmmCpuPrivate->ProcessorInfo[ProcessorNumber].ProcessorId == INVALID_APIC_ID) { + return EFI_NOT_FOUND; + } + + if (gSmmCpuPrivate->Operation[ProcessorNumber] != SmmCpuNone || + gSmst->CurrentlyExecutingCpu == ProcessorNumber) { + return EFI_UNSUPPORTED; + } + + // + // Setting of the BSP for next SMI is pending until all SMI handlers are finished + // + gSmmCpuPrivate->Operation[ProcessorNumber] = SmmCpuSwitchBsp; + return EFI_SUCCESS; +} + +/** + Notify that a processor was hot-added. + + @param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance. + @param[in] ProcessorId Local APIC ID of the hot-added processor. + @param[out] ProcessorNumber The handle number of the hot-added processor. + + @retval EFI_SUCCESS The hot-addition of the specified processors was successfully notified. + @retval EFI_UNSUPPORTED Hot addition of processor is not supported. + @retval EFI_NOT_FOUND The processor with the handle specified by ProcessorNumber does not exist. + @retval EFI_INVALID_PARAMETER ProcessorNumber is invalid. + @retval EFI_ALREADY_STARTED The processor is already online in the system. +**/ +EFI_STATUS +EFIAPI +SmmAddProcessor ( + IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This, + IN UINT64 ProcessorId, + OUT UINTN *ProcessorNumber + ) +{ + UINTN Index; + + if (!FeaturePcdGet (PcdCpuHotPlugSupport)) { + return EFI_UNSUPPORTED; + } + + // + // Check parameter + // + if (ProcessorNumber == NULL || ProcessorId == INVALID_APIC_ID) { + return EFI_INVALID_PARAMETER; + } + + // + // Check if the processor already exists + // + + for (Index = 0; Index < mMaxNumberOfCpus; Index++) { + if (gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId == ProcessorId) { + return EFI_ALREADY_STARTED; + } + } + + // + // Check CPU hot plug data. The CPU RAS handler should have created the mapping + // of the APIC ID to SMBASE. + // + for (Index = 0; Index < mMaxNumberOfCpus; Index++) { + if (mCpuHotPlugData.ApicId[Index] == ProcessorId && + gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId == INVALID_APIC_ID) { + gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId = ProcessorId; + gSmmCpuPrivate->ProcessorInfo[Index].StatusFlag = 0; + SmmGetProcessorLocation ((UINT32)ProcessorId, &gSmmCpuPrivate->ProcessorInfo[Index].Location); + + *ProcessorNumber = Index; + gSmmCpuPrivate->Operation[Index] = SmmCpuAdd; + return EFI_SUCCESS; + } + } + + return EFI_INVALID_PARAMETER; +} + +/** + Notify that a processor was hot-removed. + + @param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance. + @param[in] ProcessorNumber The handle number of the hot-added processor. + + @retval EFI_SUCCESS The hot-removal of the specified processors was successfully notified. + @retval EFI_UNSUPPORTED Hot removal of processor is not supported. + @retval EFI_UNSUPPORTED Hot removal of BSP is not supported. + @retval EFI_UNSUPPORTED Hot removal of a processor with pending hot-plug operation is not supported. + @retval EFI_INVALID_PARAMETER ProcessorNumber is invalid. +**/ +EFI_STATUS +EFIAPI +SmmRemoveProcessor ( + IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This, + IN UINTN ProcessorNumber + ) +{ + if (!FeaturePcdGet (PcdCpuHotPlugSupport)) { + return EFI_UNSUPPORTED; + } + + // + // Check parameter + // + if (ProcessorNumber >= mMaxNumberOfCpus || + gSmmCpuPrivate->ProcessorInfo[ProcessorNumber].ProcessorId == INVALID_APIC_ID) { + return EFI_INVALID_PARAMETER; + } + + // + // Can't remove BSP + // + if (ProcessorNumber == gSmmCpuPrivate->SmmCoreEntryContext.CurrentlyExecutingCpu) { + return EFI_UNSUPPORTED; + } + + if (gSmmCpuPrivate->Operation[ProcessorNumber] != SmmCpuNone) { + return EFI_UNSUPPORTED; + } + + gSmmCpuPrivate->ProcessorInfo[ProcessorNumber].ProcessorId = INVALID_APIC_ID; + mCpuHotPlugData.ApicId[ProcessorNumber] = INVALID_APIC_ID; + + // + // Removal of the processor from the CPU list is pending until all SMI handlers are finished + // + gSmmCpuPrivate->Operation[ProcessorNumber] = SmmCpuRemove; + return EFI_SUCCESS; +} + +/** + This return the handle number for the calling processor. + + @param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance. + @param[out] ProcessorNumber The handle number of currently executing processor. + + @retval EFI_SUCCESS The current processor handle number was returned + in ProcessorNumber. + @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL. + +**/ +EFI_STATUS +EFIAPI +SmmWhoAmI ( + IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This, + OUT UINTN *ProcessorNumber + ) +{ + UINTN Index; + UINT64 ApicId; + + // + // Check parameter + // + if (ProcessorNumber == NULL) { + return EFI_INVALID_PARAMETER; + } + + ApicId = GetApicId (); + + for (Index = 0; Index < mMaxNumberOfCpus; Index++) { + if (gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId == ApicId) { + *ProcessorNumber = Index; + return EFI_SUCCESS; + } + } + // + // This should not happen + // + ASSERT (FALSE); + return EFI_NOT_FOUND; +} + +/** + Update the SMM CPU list per the pending operation. + + This function is called after return from SMI handlers. +**/ +VOID +SmmCpuUpdate ( + VOID + ) +{ + UINTN Index; + + // + // Handle pending BSP switch operations + // + for (Index = 0; Index < mMaxNumberOfCpus; Index++) { + if (gSmmCpuPrivate->Operation[Index] == SmmCpuSwitchBsp) { + gSmmCpuPrivate->Operation[Index] = SmmCpuNone; + mSmmMpSyncData->SwitchBsp = TRUE; + mSmmMpSyncData->CandidateBsp[Index] = TRUE; + } + } + + // + // Handle pending hot-add operations + // + for (Index = 0; Index < mMaxNumberOfCpus; Index++) { + if (gSmmCpuPrivate->Operation[Index] == SmmCpuAdd) { + gSmmCpuPrivate->Operation[Index] = SmmCpuNone; + mNumberOfCpus++; + } + } + + // + // Handle pending hot-remove operations + // + for (Index = 0; Index < mMaxNumberOfCpus; Index++) { + if (gSmmCpuPrivate->Operation[Index] == SmmCpuRemove) { + gSmmCpuPrivate->Operation[Index] = SmmCpuNone; + mNumberOfCpus--; + } + } +} + +/** + Register exception handler. + + @param This A pointer to the SMM_CPU_SERVICE_PROTOCOL instance. + @param ExceptionType Defines which interrupt or exception to hook. Type EFI_EXCEPTION_TYPE and + the valid values for this parameter are defined in EFI_DEBUG_SUPPORT_PROTOCOL + of the UEFI 2.0 specification. + @param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER + that is called when a processor interrupt occurs. + If this parameter is NULL, then the handler will be uninstalled. + + @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled. + @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was previously installed. + @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not previously installed. + @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported. + +**/ +EFI_STATUS +EFIAPI +SmmRegisterExceptionHandler ( + IN EFI_SMM_CPU_SERVICE_PROTOCOL *This, + IN EFI_EXCEPTION_TYPE ExceptionType, + IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler + ) +{ + return RegisterCpuInterruptHandler (ExceptionType, InterruptHandler); +} + +/** + Initialize SMM CPU Services. + + It installs EFI SMM CPU Services Protocol. + + @param ImageHandle The firmware allocated handle for the EFI image. + + @retval EFI_SUCCESS EFI SMM CPU Services Protocol was installed successfully. +**/ +EFI_STATUS +InitializeSmmCpuServices ( + IN EFI_HANDLE Handle + ) +{ + EFI_STATUS Status; + + Status = gSmst->SmmInstallProtocolInterface ( + &Handle, + &gEfiSmmCpuServiceProtocolGuid, + EFI_NATIVE_INTERFACE, + &mSmmCpuService + ); + ASSERT_EFI_ERROR (Status); + return Status; +} + diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/CpuService.h b/UefiCpuPkg/PiSmmCpuDxeSmm/CpuService.h new file mode 100644 index 000000000000..9fe3f45b0266 --- /dev/null +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/CpuService.h @@ -0,0 +1,181 @@ +/** @file +Include file for SMM CPU Services protocol implementation. + +Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _CPU_SERVICE_H_ +#define _CPU_SERVICE_H_ + +typedef enum { + SmmCpuNone, + SmmCpuAdd, + SmmCpuRemove, + SmmCpuSwitchBsp +} SMM_CPU_OPERATION; + +// +// SMM CPU Service Protocol function prototypes. +// + +/** + Gets processor information on the requested processor at the instant this call is made. + + @param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance. + @param[in] ProcessorNumber The handle number of processor. + @param[out] ProcessorInfoBuffer A pointer to the buffer where information for + the requested processor is deposited. + + @retval EFI_SUCCESS Processor information was returned. + @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL. + @retval EFI_INVALID_PARAMETER ProcessorNumber is invalid. + @retval EFI_NOT_FOUND The processor with the handle specified by + ProcessorNumber does not exist in the platform. + +**/ +EFI_STATUS +EFIAPI +SmmGetProcessorInfo ( + IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This, + IN UINTN ProcessorNumber, + OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer + ); + +/** + This service switches the requested AP to be the BSP since the next SMI. + + @param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance. + @param[in] ProcessorNumber The handle number of AP that is to become the new BSP. + + @retval EFI_SUCCESS BSP will be switched in next SMI. + @retval EFI_UNSUPPORTED Switching the BSP or a processor to be hot-removed is not supported. + @retval EFI_NOT_FOUND The processor with the handle specified by ProcessorNumber does not exist. + @retval EFI_INVALID_PARAMETER ProcessorNumber is invalid. +**/ +EFI_STATUS +EFIAPI +SmmSwitchBsp ( + IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This, + IN UINTN ProcessorNumber + ); + +/** + Notify that a processor was hot-added. + + @param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance. + @param[in] ProcessorId Local APIC ID of the hot-added processor. + @param[out] ProcessorNumber The handle number of the hot-added processor. + + @retval EFI_SUCCESS The hot-addition of the specified processors was successfully notified. + @retval EFI_UNSUPPORTED Hot addition of processor is not supported. + @retval EFI_NOT_FOUND The processor with the handle specified by ProcessorNumber does not exist. + @retval EFI_INVALID_PARAMETER ProcessorNumber is invalid. + @retval EFI_ALREADY_STARTED The processor is already online in the system. +**/ +EFI_STATUS +EFIAPI +SmmAddProcessor ( + IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This, + IN UINT64 ProcessorId, + OUT UINTN *ProcessorNumber + ); + +/** + Notify that a processor was hot-removed. + + @param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance. + @param[in] ProcessorNumber The handle number of the hot-added processor. + + @retval EFI_SUCCESS The hot-removal of the specified processors was successfully notified. + @retval EFI_UNSUPPORTED Hot removal of processor is not supported. + @retval EFI_UNSUPPORTED Hot removal of BSP is not supported. + @retval EFI_UNSUPPORTED Hot removal of a processor with pending hot-plug operation is not supported. + @retval EFI_INVALID_PARAMETER ProcessorNumber is invalid. +**/ +EFI_STATUS +EFIAPI +SmmRemoveProcessor ( + IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This, + IN UINTN ProcessorNumber + ); + +/** + This return the handle number for the calling processor. + + @param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance. + @param[out] ProcessorNumber The handle number of currently executing processor. + + @retval EFI_SUCCESS The current processor handle number was returned + in ProcessorNumber. + @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL. + +**/ +EFI_STATUS +EFIAPI +SmmWhoAmI ( + IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This, + OUT UINTN *ProcessorNumber + ); + +/** + Register exception handler. + + @param This A pointer to the SMM_CPU_SERVICE_PROTOCOL instance. + @param ExceptionType Defines which interrupt or exception to hook. Type EFI_EXCEPTION_TYPE and + the valid values for this parameter are defined in EFI_DEBUG_SUPPORT_PROTOCOL + of the UEFI 2.0 specification. + @param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER + that is called when a processor interrupt occurs. + If this parameter is NULL, then the handler will be uninstalled. + + @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled. + @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was previously installed. + @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not previously installed. + @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported. + +**/ +EFI_STATUS +EFIAPI +SmmRegisterExceptionHandler ( + IN EFI_SMM_CPU_SERVICE_PROTOCOL *This, + IN EFI_EXCEPTION_TYPE ExceptionType, + IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler + ); + +// +// Internal function prototypes +// + +/** + Update the SMM CPU list per the pending operation. + + This function is called after return from SMI handlers. +**/ +VOID +SmmCpuUpdate ( + VOID + ); + +/** + Initialize SMM CPU Services. + + It installs EFI SMM CPU Services Protocol. + + @param ImageHandle The firmware allocated handle for the EFI image. + + @retval EFI_SUCCESS EFI SMM CPU Services Protocol was installed successfully. +**/ +EFI_STATUS +InitializeSmmCpuServices ( + IN EFI_HANDLE Handle + ); + +#endif diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c b/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c new file mode 100644 index 000000000000..730c32df0a25 --- /dev/null +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c @@ -0,0 +1,1327 @@ +/** @file +SMM MP service implementation + +Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "PiSmmCpuDxeSmm.h" + +// +// Slots for all MTRR( FIXED MTRR + VARIABLE MTRR + MTRR_LIB_IA32_MTRR_DEF_TYPE) +// +UINT64 gSmiMtrrs[MTRR_NUMBER_OF_FIXED_MTRR + 2 * MTRR_NUMBER_OF_VARIABLE_MTRR + 1]; +UINT64 gPhyMask; +SMM_DISPATCHER_MP_SYNC_DATA *mSmmMpSyncData = NULL; +UINTN mSmmMpSyncDataSize; + +/** + Performs an atomic compare exchange operation to get semaphore. + The compare exchange operation must be performed using + MP safe mechanisms. + + @param Sem IN: 32-bit unsigned integer + OUT: original integer - 1 + @return Original integer - 1 + +**/ +UINT32 +WaitForSemaphore ( + IN OUT volatile UINT32 *Sem + ) +{ + UINT32 Value; + + do { + Value = *Sem; + } while (Value == 0 || + InterlockedCompareExchange32 ( + (UINT32*)Sem, + Value, + Value - 1 + ) != Value); + return Value - 1; +} + + +/** + Performs an atomic compare exchange operation to release semaphore. + The compare exchange operation must be performed using + MP safe mechanisms. + + @param Sem IN: 32-bit unsigned integer + OUT: original integer + 1 + @return Original integer + 1 + +**/ +UINT32 +ReleaseSemaphore ( + IN OUT volatile UINT32 *Sem + ) +{ + UINT32 Value; + + do { + Value = *Sem; + } while (Value + 1 != 0 && + InterlockedCompareExchange32 ( + (UINT32*)Sem, + Value, + Value + 1 + ) != Value); + return Value + 1; +} + +/** + Performs an atomic compare exchange operation to lock semaphore. + The compare exchange operation must be performed using + MP safe mechanisms. + + @param Sem IN: 32-bit unsigned integer + OUT: -1 + @return Original integer + +**/ +UINT32 +LockdownSemaphore ( + IN OUT volatile UINT32 *Sem + ) +{ + UINT32 Value; + + do { + Value = *Sem; + } while (InterlockedCompareExchange32 ( + (UINT32*)Sem, + Value, (UINT32)-1 + ) != Value); + return Value; +} + +/** + Wait all APs to performs an atomic compare exchange operation to release semaphore. + + @param NumberOfAPs AP number + +**/ +VOID +WaitForAllAPs ( + IN UINTN NumberOfAPs + ) +{ + UINTN BspIndex; + + BspIndex = mSmmMpSyncData->BspIndex; + while (NumberOfAPs-- > 0) { + WaitForSemaphore (&mSmmMpSyncData->CpuData[BspIndex].Run); + } +} + +/** + Performs an atomic compare exchange operation to release semaphore + for each AP. + +**/ +VOID +ReleaseAllAPs ( + VOID + ) +{ + UINTN Index; + UINTN BspIndex; + + BspIndex = mSmmMpSyncData->BspIndex; + for (Index = mMaxNumberOfCpus; Index-- > 0;) { + if (Index != BspIndex && mSmmMpSyncData->CpuData[Index].Present) { + ReleaseSemaphore (&mSmmMpSyncData->CpuData[Index].Run); + } + } +} + +/** + Checks if all CPUs (with certain exceptions) have checked in for this SMI run + + @param Exceptions CPU Arrival exception flags. + + @retval TRUE if all CPUs the have checked in. + @retval FALSE if at least one Normal AP hasn't checked in. + +**/ +BOOLEAN +AllCpusInSmmWithExceptions ( + SMM_CPU_ARRIVAL_EXCEPTIONS Exceptions + ) +{ + UINTN Index; + SMM_CPU_DATA_BLOCK *CpuData; + EFI_PROCESSOR_INFORMATION *ProcessorInfo; + + ASSERT (mSmmMpSyncData->Counter <= mNumberOfCpus); + + if (mSmmMpSyncData->Counter == mNumberOfCpus) { + return TRUE; + } + + CpuData = mSmmMpSyncData->CpuData; + ProcessorInfo = gSmmCpuPrivate->ProcessorInfo; + for (Index = mMaxNumberOfCpus; Index-- > 0;) { + if (!CpuData[Index].Present && ProcessorInfo[Index].ProcessorId != INVALID_APIC_ID) { + if (((Exceptions & ARRIVAL_EXCEPTION_DELAYED) != 0) && SmmCpuFeaturesGetSmmRegister (Index, SmmRegSmmDelayed) != 0) { + continue; + } + if (((Exceptions & ARRIVAL_EXCEPTION_BLOCKED) != 0) && SmmCpuFeaturesGetSmmRegister (Index, SmmRegSmmBlocked) != 0) { + continue; + } + if (((Exceptions & ARRIVAL_EXCEPTION_SMI_DISABLED) != 0) && SmmCpuFeaturesGetSmmRegister (Index, SmmRegSmmEnable) != 0) { + continue; + } + return FALSE; + } + } + + + return TRUE; +} + + +/** + Given timeout constraint, wait for all APs to arrive, and insure when this function returns, no AP will execute normal mode code before + entering SMM, except SMI disabled APs. + +**/ +VOID +SmmWaitForApArrival ( + VOID + ) +{ + UINT64 Timer; + UINTN Index; + + ASSERT (mSmmMpSyncData->Counter <= mNumberOfCpus); + + // + // Platform implementor should choose a timeout value appropriately: + // - The timeout value should balance the SMM time constrains and the likelihood that delayed CPUs are excluded in the SMM run. Note + // the SMI Handlers must ALWAYS take into account the cases that not all APs are available in an SMI run. + // - The timeout value must, in the case of 2nd timeout, be at least long enough to give time for all APs to receive the SMI IPI + // and either enter SMM or buffer the SMI, to insure there is no CPU running normal mode code when SMI handling starts. This will + // be TRUE even if a blocked CPU is brought out of the blocked state by a normal mode CPU (before the normal mode CPU received the + // SMI IPI), because with a buffered SMI, and CPU will enter SMM immediately after it is brought out of the blocked state. + // - The timeout value must be longer than longest possible IO operation in the system + // + + // + // Sync with APs 1st timeout + // + for (Timer = StartSyncTimer (); + !IsSyncTimerTimeout (Timer) && + !AllCpusInSmmWithExceptions (ARRIVAL_EXCEPTION_BLOCKED | ARRIVAL_EXCEPTION_SMI_DISABLED ); + ) { + CpuPause (); + } + + // + // Not all APs have arrived, so we need 2nd round of timeout. IPIs should be sent to ALL none present APs, + // because: + // a) Delayed AP may have just come out of the delayed state. Blocked AP may have just been brought out of blocked state by some AP running + // normal mode code. These APs need to be guaranteed to have an SMI pending to insure that once they are out of delayed / blocked state, they + // enter SMI immediately without executing instructions in normal mode. Note traditional flow requires there are no APs doing normal mode + // work while SMI handling is on-going. + // b) As a consequence of SMI IPI sending, (spurious) SMI may occur after this SMM run. + // c) ** NOTE **: Use SMI disabling feature VERY CAREFULLY (if at all) for traditional flow, because a processor in SMI-disabled state + // will execute normal mode code, which breaks the traditional SMI handlers' assumption that no APs are doing normal + // mode work while SMI handling is on-going. + // d) We don't add code to check SMI disabling status to skip sending IPI to SMI disabled APs, because: + // - In traditional flow, SMI disabling is discouraged. + // - In relaxed flow, CheckApArrival() will check SMI disabling status before calling this function. + // In both cases, adding SMI-disabling checking code increases overhead. + // + if (mSmmMpSyncData->Counter < mNumberOfCpus) { + // + // Send SMI IPIs to bring outside processors in + // + for (Index = mMaxNumberOfCpus; Index-- > 0;) { + if (!mSmmMpSyncData->CpuData[Index].Present && gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId != INVALID_APIC_ID) { + SendSmiIpi ((UINT32)gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId); + } + } + + // + // Sync with APs 2nd timeout. + // + for (Timer = StartSyncTimer (); + !IsSyncTimerTimeout (Timer) && + !AllCpusInSmmWithExceptions (ARRIVAL_EXCEPTION_BLOCKED | ARRIVAL_EXCEPTION_SMI_DISABLED ); + ) { + CpuPause (); + } + } + + return; +} + + +/** + Replace OS MTRR's with SMI MTRR's. + + @param CpuIndex Processor Index + +**/ +VOID +ReplaceOSMtrrs ( + IN UINTN CpuIndex + ) +{ + PROCESSOR_SMM_DESCRIPTOR *Psd; + UINT64 *SmiMtrrs; + MTRR_SETTINGS *BiosMtrr; + + Psd = (PROCESSOR_SMM_DESCRIPTOR*)(mCpuHotPlugData.SmBase[CpuIndex] + SMM_PSD_OFFSET); + SmiMtrrs = (UINT64*)(UINTN)Psd->MtrrBaseMaskPtr; + + SmmCpuFeaturesDisableSmrr (); + + // + // Replace all MTRRs registers + // + BiosMtrr = (MTRR_SETTINGS*)SmiMtrrs; + MtrrSetAllMtrrs(BiosMtrr); +} + +/** + SMI handler for BSP. + + @param CpuIndex BSP processor Index + @param SyncMode SMM MP sync mode + +**/ +VOID +BSPHandler ( + IN UINTN CpuIndex, + IN SMM_CPU_SYNC_MODE SyncMode + ) +{ + UINTN Index; + MTRR_SETTINGS Mtrrs; + UINTN ApCount; + BOOLEAN ClearTopLevelSmiResult; + UINTN PresentCount; + + ASSERT (CpuIndex == mSmmMpSyncData->BspIndex); + ApCount = 0; + + // + // Flag BSP's presence + // + mSmmMpSyncData->InsideSmm = TRUE; + + // + // Initialize Debug Agent to start source level debug in BSP handler + // + InitializeDebugAgent (DEBUG_AGENT_INIT_ENTER_SMI, NULL, NULL); + + // + // Mark this processor's presence + // + mSmmMpSyncData->CpuData[CpuIndex].Present = TRUE; + + // + // Clear platform top level SMI status bit before calling SMI handlers. If + // we cleared it after SMI handlers are run, we would miss the SMI that + // occurs after SMI handlers are done and before SMI status bit is cleared. + // + ClearTopLevelSmiResult = ClearTopLevelSmiStatus(); + ASSERT (ClearTopLevelSmiResult == TRUE); + + // + // Set running processor index + // + gSmmCpuPrivate->SmmCoreEntryContext.CurrentlyExecutingCpu = CpuIndex; + + // + // If Traditional Sync Mode or need to configure MTRRs: gather all available APs. + // + if (SyncMode == SmmCpuSyncModeTradition || SmmCpuFeaturesNeedConfigureMtrrs()) { + + // + // Wait for APs to arrive + // + SmmWaitForApArrival(); + + // + // Lock the counter down and retrieve the number of APs + // + mSmmMpSyncData->AllCpusInSync = TRUE; + ApCount = LockdownSemaphore (&mSmmMpSyncData->Counter) - 1; + + // + // Wait for all APs to get ready for programming MTRRs + // + WaitForAllAPs (ApCount); + + if (SmmCpuFeaturesNeedConfigureMtrrs()) { + // + // Signal all APs it's time for backup MTRRs + // + ReleaseAllAPs (); + + // + // WaitForSemaphore() may wait for ever if an AP happens to enter SMM at + // exactly this point. Please make sure PcdCpuSmmMaxSyncLoops has been set + // to a large enough value to avoid this situation. + // Note: For HT capable CPUs, threads within a core share the same set of MTRRs. + // We do the backup first and then set MTRR to avoid race condition for threads + // in the same core. + // + MtrrGetAllMtrrs(&Mtrrs); + + // + // Wait for all APs to complete their MTRR saving + // + WaitForAllAPs (ApCount); + + // + // Let all processors program SMM MTRRs together + // + ReleaseAllAPs (); + + // + // WaitForSemaphore() may wait for ever if an AP happens to enter SMM at + // exactly this point. Please make sure PcdCpuSmmMaxSyncLoops has been set + // to a large enough value to avoid this situation. + // + ReplaceOSMtrrs (CpuIndex); + + // + // Wait for all APs to complete their MTRR programming + // + WaitForAllAPs (ApCount); + } + } + + // + // The BUSY lock is initialized to Acquired state + // + AcquireSpinLockOrFail (&mSmmMpSyncData->CpuData[CpuIndex].Busy); + + // + // Restore SMM Configuration in S3 boot path. + // + if (mRestoreSmmConfigurationInS3) { + // + // Configure SMM Code Access Check feature if available. + // + ConfigSmmCodeAccessCheck (); + mRestoreSmmConfigurationInS3 = FALSE; + } + + // + // Invoke SMM Foundation EntryPoint with the processor information context. + // + gSmmCpuPrivate->SmmCoreEntry (&gSmmCpuPrivate->SmmCoreEntryContext); + + // + // Make sure all APs have completed their pending none-block tasks + // + for (Index = mMaxNumberOfCpus; Index-- > 0;) { + if (Index != CpuIndex && mSmmMpSyncData->CpuData[Index].Present) { + AcquireSpinLock (&mSmmMpSyncData->CpuData[Index].Busy); + ReleaseSpinLock (&mSmmMpSyncData->CpuData[Index].Busy);; + } + } + + // + // Perform the remaining tasks + // + PerformRemainingTasks (); + + // + // If Relaxed-AP Sync Mode: gather all available APs after BSP SMM handlers are done, and + // make those APs to exit SMI synchronously. APs which arrive later will be excluded and + // will run through freely. + // + if (SyncMode != SmmCpuSyncModeTradition && !SmmCpuFeaturesNeedConfigureMtrrs()) { + + // + // Lock the counter down and retrieve the number of APs + // + mSmmMpSyncData->AllCpusInSync = TRUE; + ApCount = LockdownSemaphore (&mSmmMpSyncData->Counter) - 1; + // + // Make sure all APs have their Present flag set + // + while (TRUE) { + PresentCount = 0; + for (Index = mMaxNumberOfCpus; Index-- > 0;) { + if (mSmmMpSyncData->CpuData[Index].Present) { + PresentCount ++; + } + } + if (PresentCount > ApCount) { + break; + } + } + } + + // + // Notify all APs to exit + // + mSmmMpSyncData->InsideSmm = FALSE; + ReleaseAllAPs (); + + // + // Wait for all APs to complete their pending tasks + // + WaitForAllAPs (ApCount); + + if (SmmCpuFeaturesNeedConfigureMtrrs()) { + // + // Signal APs to restore MTRRs + // + ReleaseAllAPs (); + + // + // Restore OS MTRRs + // + SmmCpuFeaturesReenableSmrr (); + MtrrSetAllMtrrs(&Mtrrs); + + // + // Wait for all APs to complete MTRR programming + // + WaitForAllAPs (ApCount); + } + + // + // Stop source level debug in BSP handler, the code below will not be + // debugged. + // + InitializeDebugAgent (DEBUG_AGENT_INIT_EXIT_SMI, NULL, NULL); + + // + // Signal APs to Reset states/semaphore for this processor + // + ReleaseAllAPs (); + + // + // Perform pending operations for hot-plug + // + SmmCpuUpdate (); + + // + // Clear the Present flag of BSP + // + mSmmMpSyncData->CpuData[CpuIndex].Present = FALSE; + + // + // Gather APs to exit SMM synchronously. Note the Present flag is cleared by now but + // WaitForAllAps does not depend on the Present flag. + // + WaitForAllAPs (ApCount); + + // + // Reset BspIndex to -1, meaning BSP has not been elected. + // + if (FeaturePcdGet (PcdCpuSmmEnableBspElection)) { + mSmmMpSyncData->BspIndex = (UINT32)-1; + } + + // + // Allow APs to check in from this point on + // + mSmmMpSyncData->Counter = 0; + mSmmMpSyncData->AllCpusInSync = FALSE; +} + +/** + SMI handler for AP. + + @param CpuIndex AP processor Index. + @param ValidSmi Indicates that current SMI is a valid SMI or not. + @param SyncMode SMM MP sync mode. + +**/ +VOID +APHandler ( + IN UINTN CpuIndex, + IN BOOLEAN ValidSmi, + IN SMM_CPU_SYNC_MODE SyncMode + ) +{ + UINT64 Timer; + UINTN BspIndex; + MTRR_SETTINGS Mtrrs; + + // + // Timeout BSP + // + for (Timer = StartSyncTimer (); + !IsSyncTimerTimeout (Timer) && + !mSmmMpSyncData->InsideSmm; + ) { + CpuPause (); + } + + if (!mSmmMpSyncData->InsideSmm) { + // + // BSP timeout in the first round + // + if (mSmmMpSyncData->BspIndex != -1) { + // + // BSP Index is known + // + BspIndex = mSmmMpSyncData->BspIndex; + ASSERT (CpuIndex != BspIndex); + + // + // Send SMI IPI to bring BSP in + // + SendSmiIpi ((UINT32)gSmmCpuPrivate->ProcessorInfo[BspIndex].ProcessorId); + + // + // Now clock BSP for the 2nd time + // + for (Timer = StartSyncTimer (); + !IsSyncTimerTimeout (Timer) && + !mSmmMpSyncData->InsideSmm; + ) { + CpuPause (); + } + + if (!mSmmMpSyncData->InsideSmm) { + // + // Give up since BSP is unable to enter SMM + // and signal the completion of this AP + WaitForSemaphore (&mSmmMpSyncData->Counter); + return; + } + } else { + // + // Don't know BSP index. Give up without sending IPI to BSP. + // + WaitForSemaphore (&mSmmMpSyncData->Counter); + return; + } + } + + // + // BSP is available + // + BspIndex = mSmmMpSyncData->BspIndex; + ASSERT (CpuIndex != BspIndex); + + // + // Mark this processor's presence + // + mSmmMpSyncData->CpuData[CpuIndex].Present = TRUE; + + if (SyncMode == SmmCpuSyncModeTradition || SmmCpuFeaturesNeedConfigureMtrrs()) { + // + // Notify BSP of arrival at this point + // + ReleaseSemaphore (&mSmmMpSyncData->CpuData[BspIndex].Run); + } + + if (SmmCpuFeaturesNeedConfigureMtrrs()) { + // + // Wait for the signal from BSP to backup MTRRs + // + WaitForSemaphore (&mSmmMpSyncData->CpuData[CpuIndex].Run); + + // + // Backup OS MTRRs + // + MtrrGetAllMtrrs(&Mtrrs); + + // + // Signal BSP the completion of this AP + // + ReleaseSemaphore (&mSmmMpSyncData->CpuData[BspIndex].Run); + + // + // Wait for BSP's signal to program MTRRs + // + WaitForSemaphore (&mSmmMpSyncData->CpuData[CpuIndex].Run); + + // + // Replace OS MTRRs with SMI MTRRs + // + ReplaceOSMtrrs (CpuIndex); + + // + // Signal BSP the completion of this AP + // + ReleaseSemaphore (&mSmmMpSyncData->CpuData[BspIndex].Run); + } + + while (TRUE) { + // + // Wait for something to happen + // + WaitForSemaphore (&mSmmMpSyncData->CpuData[CpuIndex].Run); + + // + // Check if BSP wants to exit SMM + // + if (!mSmmMpSyncData->InsideSmm) { + break; + } + + // + // BUSY should be acquired by SmmStartupThisAp() + // + ASSERT ( + !AcquireSpinLockOrFail (&mSmmMpSyncData->CpuData[CpuIndex].Busy) + ); + + // + // Invoke the scheduled procedure + // + (*mSmmMpSyncData->CpuData[CpuIndex].Procedure) ( + (VOID*)mSmmMpSyncData->CpuData[CpuIndex].Parameter + ); + + // + // Release BUSY + // + ReleaseSpinLock (&mSmmMpSyncData->CpuData[CpuIndex].Busy); + } + + if (SmmCpuFeaturesNeedConfigureMtrrs()) { + // + // Notify BSP the readiness of this AP to program MTRRs + // + ReleaseSemaphore (&mSmmMpSyncData->CpuData[BspIndex].Run); + + // + // Wait for the signal from BSP to program MTRRs + // + WaitForSemaphore (&mSmmMpSyncData->CpuData[CpuIndex].Run); + + // + // Restore OS MTRRs + // + SmmCpuFeaturesReenableSmrr (); + MtrrSetAllMtrrs(&Mtrrs); + } + + // + // Notify BSP the readiness of this AP to Reset states/semaphore for this processor + // + ReleaseSemaphore (&mSmmMpSyncData->CpuData[BspIndex].Run); + + // + // Wait for the signal from BSP to Reset states/semaphore for this processor + // + WaitForSemaphore (&mSmmMpSyncData->CpuData[CpuIndex].Run); + + // + // Reset states/semaphore for this processor + // + mSmmMpSyncData->CpuData[CpuIndex].Present = FALSE; + + // + // Notify BSP the readiness of this AP to exit SMM + // + ReleaseSemaphore (&mSmmMpSyncData->CpuData[BspIndex].Run); + +} + +/** + Create 4G PageTable in SMRAM. + + @param ExtraPages Additional page numbers besides for 4G memory + @return PageTable Address + +**/ +UINT32 +Gen4GPageTable ( + IN UINTN ExtraPages + ) +{ + VOID *PageTable; + UINTN Index; + UINT64 *Pte; + UINTN PagesNeeded; + UINTN Low2MBoundary; + UINTN High2MBoundary; + UINTN Pages; + UINTN GuardPage; + UINT64 *Pdpte; + UINTN PageIndex; + UINTN PageAddress; + + Low2MBoundary = 0; + High2MBoundary = 0; + PagesNeeded = 0; + if (FeaturePcdGet (PcdCpuSmmStackGuard)) { + // + // Add one more page for known good stack, then find the lower 2MB aligned address. + // + Low2MBoundary = (mSmmStackArrayBase + EFI_PAGE_SIZE) & ~(SIZE_2MB-1); + // + // Add two more pages for known good stack and stack guard page, + // then find the lower 2MB aligned address. + // + High2MBoundary = (mSmmStackArrayEnd - mSmmStackSize + EFI_PAGE_SIZE * 2) & ~(SIZE_2MB-1); + PagesNeeded = ((High2MBoundary - Low2MBoundary) / SIZE_2MB) + 1; + } + // + // Allocate the page table + // + PageTable = AllocatePages (ExtraPages + 5 + PagesNeeded); + ASSERT (PageTable != NULL); + + PageTable = (VOID *)((UINTN)PageTable + EFI_PAGES_TO_SIZE (ExtraPages)); + Pte = (UINT64*)PageTable; + + // + // Zero out all page table entries first + // + ZeroMem (Pte, EFI_PAGES_TO_SIZE (1)); + + // + // Set Page Directory Pointers + // + for (Index = 0; Index < 4; Index++) { + Pte[Index] = (UINTN)PageTable + EFI_PAGE_SIZE * (Index + 1) + IA32_PG_P; + } + Pte += EFI_PAGE_SIZE / sizeof (*Pte); + + // + // Fill in Page Directory Entries + // + for (Index = 0; Index < EFI_PAGE_SIZE * 4 / sizeof (*Pte); Index++) { + Pte[Index] = (Index << 21) + IA32_PG_PS + IA32_PG_RW + IA32_PG_P; + } + + if (FeaturePcdGet (PcdCpuSmmStackGuard)) { + Pages = (UINTN)PageTable + EFI_PAGES_TO_SIZE (5); + GuardPage = mSmmStackArrayBase + EFI_PAGE_SIZE; + Pdpte = (UINT64*)PageTable; + for (PageIndex = Low2MBoundary; PageIndex <= High2MBoundary; PageIndex += SIZE_2MB) { + Pte = (UINT64*)(UINTN)(Pdpte[BitFieldRead32 ((UINT32)PageIndex, 30, 31)] & ~(EFI_PAGE_SIZE - 1)); + Pte[BitFieldRead32 ((UINT32)PageIndex, 21, 29)] = (UINT64)Pages + IA32_PG_RW + IA32_PG_P; + // + // Fill in Page Table Entries + // + Pte = (UINT64*)Pages; + PageAddress = PageIndex; + for (Index = 0; Index < EFI_PAGE_SIZE / sizeof (*Pte); Index++) { + if (PageAddress == GuardPage) { + // + // Mark the guard page as non-present + // + Pte[Index] = PageAddress; + GuardPage += mSmmStackSize; + if (GuardPage > mSmmStackArrayEnd) { + GuardPage = 0; + } + } else { + Pte[Index] = PageAddress + IA32_PG_RW + IA32_PG_P; + } + PageAddress+= EFI_PAGE_SIZE; + } + Pages += EFI_PAGE_SIZE; + } + } + + return (UINT32)(UINTN)PageTable; +} + +/** + Set memory cache ability. + + @param PageTable PageTable Address + @param Address Memory Address to change cache ability + @param Cacheability Cache ability to set + +**/ +VOID +SetCacheability ( + IN UINT64 *PageTable, + IN UINTN Address, + IN UINT8 Cacheability + ) +{ + UINTN PTIndex; + VOID *NewPageTableAddress; + UINT64 *NewPageTable; + UINTN Index; + + ASSERT ((Address & EFI_PAGE_MASK) == 0); + + if (sizeof (UINTN) == sizeof (UINT64)) { + PTIndex = (UINTN)RShiftU64 (Address, 39) & 0x1ff; + ASSERT (PageTable[PTIndex] & IA32_PG_P); + PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & gPhyMask); + } + + PTIndex = (UINTN)RShiftU64 (Address, 30) & 0x1ff; + ASSERT (PageTable[PTIndex] & IA32_PG_P); + PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & gPhyMask); + + // + // A perfect implementation should check the original cacheability with the + // one being set, and break a 2M page entry into pieces only when they + // disagreed. + // + PTIndex = (UINTN)RShiftU64 (Address, 21) & 0x1ff; + if ((PageTable[PTIndex] & IA32_PG_PS) != 0) { + // + // Allocate a page from SMRAM + // + NewPageTableAddress = AllocatePages (1); + ASSERT (NewPageTableAddress != NULL); + + NewPageTable = (UINT64 *)NewPageTableAddress; + + for (Index = 0; Index < 0x200; Index++) { + NewPageTable[Index] = PageTable[PTIndex]; + if ((NewPageTable[Index] & IA32_PG_PAT_2M) != 0) { + NewPageTable[Index] &= ~((UINT64)IA32_PG_PAT_2M); + NewPageTable[Index] |= (UINT64)IA32_PG_PAT_4K; + } + NewPageTable[Index] |= (UINT64)(Index << EFI_PAGE_SHIFT); + } + + PageTable[PTIndex] = ((UINTN)NewPageTableAddress & gPhyMask) | IA32_PG_P; + } + + ASSERT (PageTable[PTIndex] & IA32_PG_P); + PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & gPhyMask); + + PTIndex = (UINTN)RShiftU64 (Address, 12) & 0x1ff; + ASSERT (PageTable[PTIndex] & IA32_PG_P); + PageTable[PTIndex] &= ~((UINT64)((IA32_PG_PAT_4K | IA32_PG_CD | IA32_PG_WT))); + PageTable[PTIndex] |= (UINT64)Cacheability; +} + + +/** + Schedule a procedure to run on the specified CPU. + + @param Procedure The address of the procedure to run + @param CpuIndex Target CPU Index + @param ProcArguments The parameter to pass to the procedure + + @retval EFI_INVALID_PARAMETER CpuNumber not valid + @retval EFI_INVALID_PARAMETER CpuNumber specifying BSP + @retval EFI_INVALID_PARAMETER The AP specified by CpuNumber did not enter SMM + @retval EFI_INVALID_PARAMETER The AP specified by CpuNumber is busy + @retval EFI_SUCCESS The procedure has been successfully scheduled + +**/ +EFI_STATUS +EFIAPI +SmmStartupThisAp ( + IN EFI_AP_PROCEDURE Procedure, + IN UINTN CpuIndex, + IN OUT VOID *ProcArguments OPTIONAL + ) +{ + if (CpuIndex >= gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus || + CpuIndex == gSmmCpuPrivate->SmmCoreEntryContext.CurrentlyExecutingCpu || + !mSmmMpSyncData->CpuData[CpuIndex].Present || + gSmmCpuPrivate->Operation[CpuIndex] == SmmCpuRemove || + !AcquireSpinLockOrFail (&mSmmMpSyncData->CpuData[CpuIndex].Busy)) { + return EFI_INVALID_PARAMETER; + } + + mSmmMpSyncData->CpuData[CpuIndex].Procedure = Procedure; + mSmmMpSyncData->CpuData[CpuIndex].Parameter = ProcArguments; + ReleaseSemaphore (&mSmmMpSyncData->CpuData[CpuIndex].Run); + + if (FeaturePcdGet (PcdCpuSmmBlockStartupThisAp)) { + AcquireSpinLock (&mSmmMpSyncData->CpuData[CpuIndex].Busy); + ReleaseSpinLock (&mSmmMpSyncData->CpuData[CpuIndex].Busy); + } + return EFI_SUCCESS; +} + +/** + C function for SMI entry, each processor comes here upon SMI trigger. + + @param CpuIndex CPU Index + +**/ +VOID +EFIAPI +SmiRendezvous ( + IN UINTN CpuIndex + ) +{ + EFI_STATUS Status; + BOOLEAN ValidSmi; + BOOLEAN IsBsp; + BOOLEAN BspInProgress; + UINTN Index; + UINTN Cr2; + + // + // Save Cr2 because Page Fault exception in SMM may override its value + // + Cr2 = AsmReadCr2 (); + + // + // Perform CPU specific entry hooks + // + SmmCpuFeaturesRendezvousEntry (CpuIndex); + + // + // Determine if this is a valid SMI + // + ValidSmi = PlatformValidSmi(); + + // + // Determine if BSP has been already in progress. Note this must be checked after + // ValidSmi because BSP may clear a valid SMI source after checking in. + // + BspInProgress = mSmmMpSyncData->InsideSmm; + + if (!BspInProgress && !ValidSmi) { + // + // If we reach here, it means when we sampled the ValidSmi flag, SMI status had not + // been cleared by BSP in a new SMI run (so we have a truly invalid SMI), or SMI + // status had been cleared by BSP and an existing SMI run has almost ended. (Note + // we sampled ValidSmi flag BEFORE judging BSP-in-progress status.) In both cases, there + // is nothing we need to do. + // + goto Exit; + } else { + // + // Signal presence of this processor + // + if (ReleaseSemaphore (&mSmmMpSyncData->Counter) == 0) { + // + // BSP has already ended the synchronization, so QUIT!!! + // + + // + // Wait for BSP's signal to finish SMI + // + while (mSmmMpSyncData->AllCpusInSync) { + CpuPause (); + } + goto Exit; + } else { + + // + // The BUSY lock is initialized to Released state. + // This needs to be done early enough to be ready for BSP's SmmStartupThisAp() call. + // E.g., with Relaxed AP flow, SmmStartupThisAp() may be called immediately + // after AP's present flag is detected. + // + InitializeSpinLock (&mSmmMpSyncData->CpuData[CpuIndex].Busy); + } + + // + // Try to enable NX + // + if (mXdSupported) { + ActivateXd (); + } + + if (FeaturePcdGet (PcdCpuSmmProfileEnable)) { + ActivateSmmProfile (CpuIndex); + } + + if (BspInProgress) { + // + // BSP has been elected. Follow AP path, regardless of ValidSmi flag + // as BSP may have cleared the SMI status + // + APHandler (CpuIndex, ValidSmi, mSmmMpSyncData->EffectiveSyncMode); + } else { + // + // We have a valid SMI + // + + // + // Elect BSP + // + IsBsp = FALSE; + if (FeaturePcdGet (PcdCpuSmmEnableBspElection)) { + if (!mSmmMpSyncData->SwitchBsp || mSmmMpSyncData->CandidateBsp[CpuIndex]) { + // + // Call platform hook to do BSP election + // + Status = PlatformSmmBspElection (&IsBsp); + if (EFI_SUCCESS == Status) { + // + // Platform hook determines successfully + // + if (IsBsp) { + mSmmMpSyncData->BspIndex = (UINT32)CpuIndex; + } + } else { + // + // Platform hook fails to determine, use default BSP election method + // + InterlockedCompareExchange32 ( + (UINT32*)&mSmmMpSyncData->BspIndex, + (UINT32)-1, + (UINT32)CpuIndex + ); + } + } + } + + // + // "mSmmMpSyncData->BspIndex == CpuIndex" means this is the BSP + // + if (mSmmMpSyncData->BspIndex == CpuIndex) { + + // + // Clear last request for SwitchBsp. + // + if (mSmmMpSyncData->SwitchBsp) { + mSmmMpSyncData->SwitchBsp = FALSE; + for (Index = 0; Index < mMaxNumberOfCpus; Index++) { + mSmmMpSyncData->CandidateBsp[Index] = FALSE; + } + } + + if (FeaturePcdGet (PcdCpuSmmProfileEnable)) { + SmmProfileRecordSmiNum (); + } + + // + // BSP Handler is always called with a ValidSmi == TRUE + // + BSPHandler (CpuIndex, mSmmMpSyncData->EffectiveSyncMode); + + } else { + APHandler (CpuIndex, ValidSmi, mSmmMpSyncData->EffectiveSyncMode); + } + } + + ASSERT (mSmmMpSyncData->CpuData[CpuIndex].Run == 0); + + // + // Wait for BSP's signal to exit SMI + // + while (mSmmMpSyncData->AllCpusInSync) { + CpuPause (); + } + } + +Exit: + SmmCpuFeaturesRendezvousExit (CpuIndex); + // + // Restore Cr2 + // + AsmWriteCr2 (Cr2); +} + + +/** + Initialize un-cacheable data. + +**/ +VOID +EFIAPI +InitializeMpSyncData ( + VOID + ) +{ + if (mSmmMpSyncData != NULL) { + ZeroMem (mSmmMpSyncData, mSmmMpSyncDataSize); + mSmmMpSyncData->CpuData = (SMM_CPU_DATA_BLOCK *)((UINT8 *)mSmmMpSyncData + sizeof (SMM_DISPATCHER_MP_SYNC_DATA)); + mSmmMpSyncData->CandidateBsp = (BOOLEAN *)(mSmmMpSyncData->CpuData + gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus); + if (FeaturePcdGet (PcdCpuSmmEnableBspElection)) { + // + // Enable BSP election by setting BspIndex to -1 + // + mSmmMpSyncData->BspIndex = (UINT32)-1; + } + mSmmMpSyncData->EffectiveSyncMode = (SMM_CPU_SYNC_MODE) PcdGet8 (PcdCpuSmmSyncMode); + } +} + +/** + Initialize global data for MP synchronization. + + @param Stacks Base address of SMI stack buffer for all processors. + @param StackSize Stack size for each processor in SMM. + +**/ +UINT32 +InitializeMpServiceData ( + IN VOID *Stacks, + IN UINTN StackSize + ) +{ + UINT32 Cr3; + UINTN Index; + MTRR_SETTINGS *Mtrr; + PROCESSOR_SMM_DESCRIPTOR *Psd; + UINTN GdtTssTableSize; + UINT8 *GdtTssTables; + IA32_SEGMENT_DESCRIPTOR *GdtDescriptor; + UINTN TssBase; + UINTN GdtTableStepSize; + + // + // Initialize physical address mask + // NOTE: Physical memory above virtual address limit is not supported !!! + // + AsmCpuid (0x80000008, (UINT32*)&Index, NULL, NULL, NULL); + gPhyMask = LShiftU64 (1, (UINT8)Index) - 1; + gPhyMask &= (1ull << 48) - EFI_PAGE_SIZE; + + // + // Create page tables + // + Cr3 = SmmInitPageTable (); + + GdtTssTables = NULL; + GdtTssTableSize = 0; + GdtTableStepSize = 0; + // + // For X64 SMM, we allocate separate GDT/TSS for each CPUs to avoid TSS load contention + // on each SMI entry. + // + if (EFI_IMAGE_MACHINE_TYPE_SUPPORTED(EFI_IMAGE_MACHINE_X64)) { + GdtTssTableSize = (gcSmiGdtr.Limit + 1 + TSS_SIZE + 7) & ~7; // 8 bytes aligned + GdtTssTables = (UINT8*)AllocatePages (EFI_SIZE_TO_PAGES (GdtTssTableSize * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus)); + ASSERT (GdtTssTables != NULL); + GdtTableStepSize = GdtTssTableSize; + + for (Index = 0; Index < gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus; Index++) { + CopyMem (GdtTssTables + GdtTableStepSize * Index, (VOID*)(UINTN)gcSmiGdtr.Base, gcSmiGdtr.Limit + 1 + TSS_SIZE); + if (FeaturePcdGet (PcdCpuSmmStackGuard)) { + // + // Setup top of known good stack as IST1 for each processor. + // + *(UINTN *)(GdtTssTables + GdtTableStepSize * Index + gcSmiGdtr.Limit + 1 + TSS_X64_IST1_OFFSET) = (mSmmStackArrayBase + EFI_PAGE_SIZE + Index * mSmmStackSize); + } + } + } else if (FeaturePcdGet (PcdCpuSmmStackGuard)) { + + // + // For IA32 SMM, if SMM Stack Guard feature is enabled, we use 2 TSS. + // in this case, we allocate separate GDT/TSS for each CPUs to avoid TSS load contention + // on each SMI entry. + // + + // + // Enlarge GDT to contain 2 TSS descriptors + // + gcSmiGdtr.Limit += (UINT16)(2 * sizeof (IA32_SEGMENT_DESCRIPTOR)); + + GdtTssTableSize = (gcSmiGdtr.Limit + 1 + TSS_SIZE * 2 + 7) & ~7; // 8 bytes aligned + GdtTssTables = (UINT8*)AllocatePages (EFI_SIZE_TO_PAGES (GdtTssTableSize * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus)); + ASSERT (GdtTssTables != NULL); + GdtTableStepSize = GdtTssTableSize; + + for (Index = 0; Index < gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus; Index++) { + CopyMem (GdtTssTables + GdtTableStepSize * Index, (VOID*)(UINTN)gcSmiGdtr.Base, gcSmiGdtr.Limit + 1 + TSS_SIZE * 2); + // + // Fixup TSS descriptors + // + TssBase = (UINTN)(GdtTssTables + GdtTableStepSize * Index + gcSmiGdtr.Limit + 1); + GdtDescriptor = (IA32_SEGMENT_DESCRIPTOR *)(TssBase) - 2; + GdtDescriptor->Bits.BaseLow = (UINT16)TssBase; + GdtDescriptor->Bits.BaseMid = (UINT8)(TssBase >> 16); + GdtDescriptor->Bits.BaseHigh = (UINT8)(TssBase >> 24); + + TssBase += TSS_SIZE; + GdtDescriptor++; + GdtDescriptor->Bits.BaseLow = (UINT16)TssBase; + GdtDescriptor->Bits.BaseMid = (UINT8)(TssBase >> 16); + GdtDescriptor->Bits.BaseHigh = (UINT8)(TssBase >> 24); + // + // Fixup TSS segments + // + // ESP as known good stack + // + *(UINTN *)(TssBase + TSS_IA32_ESP_OFFSET) = mSmmStackArrayBase + EFI_PAGE_SIZE + Index * mSmmStackSize; + *(UINT32 *)(TssBase + TSS_IA32_CR3_OFFSET) = Cr3; + } + } + + // + // Initialize PROCESSOR_SMM_DESCRIPTOR for each CPU + // + for (Index = 0; Index < mMaxNumberOfCpus; Index++) { + Psd = (PROCESSOR_SMM_DESCRIPTOR *)(VOID *)(UINTN)(mCpuHotPlugData.SmBase[Index] + SMM_PSD_OFFSET); + CopyMem (Psd, &gcPsd, sizeof (gcPsd)); + if (EFI_IMAGE_MACHINE_TYPE_SUPPORTED (EFI_IMAGE_MACHINE_X64)) { + // + // For X64 SMM, set GDT to the copy allocated above. + // + Psd->SmmGdtPtr = (UINT64)(UINTN)(GdtTssTables + GdtTableStepSize * Index); + } else if (FeaturePcdGet (PcdCpuSmmStackGuard)) { + // + // For IA32 SMM, if SMM Stack Guard feature is enabled, set GDT to the copy allocated above. + // + Psd->SmmGdtPtr = (UINT64)(UINTN)(GdtTssTables + GdtTableStepSize * Index); + Psd->SmmGdtSize = gcSmiGdtr.Limit + 1; + } + + // + // Install SMI handler + // + InstallSmiHandler ( + Index, + (UINT32)mCpuHotPlugData.SmBase[Index], + (VOID*)((UINTN)Stacks + (StackSize * Index)), + StackSize, + (UINTN)Psd->SmmGdtPtr, + Psd->SmmGdtSize, + gcSmiIdtr.Base, + gcSmiIdtr.Limit + 1, + Cr3 + ); + } + + // + // Initialize mSmmMpSyncData + // + mSmmMpSyncDataSize = sizeof (SMM_DISPATCHER_MP_SYNC_DATA) + + (sizeof (SMM_CPU_DATA_BLOCK) + sizeof (BOOLEAN)) * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus; + mSmmMpSyncData = (SMM_DISPATCHER_MP_SYNC_DATA*) AllocatePages (EFI_SIZE_TO_PAGES (mSmmMpSyncDataSize)); + ASSERT (mSmmMpSyncData != NULL); + InitializeMpSyncData (); + + // + // Record current MTRR settings + // + ZeroMem(gSmiMtrrs, sizeof (gSmiMtrrs)); + Mtrr = (MTRR_SETTINGS*)gSmiMtrrs; + MtrrGetAllMtrrs (Mtrr); + + return Cr3; +} + +/** + + Register the SMM Foundation entry point. + + @param This Pointer to EFI_SMM_CONFIGURATION_PROTOCOL instance + @param SmmEntryPoint SMM Foundation EntryPoint + + @retval EFI_SUCCESS Successfully to register SMM foundation entry point + +**/ +EFI_STATUS +EFIAPI +RegisterSmmEntry ( + IN CONST EFI_SMM_CONFIGURATION_PROTOCOL *This, + IN EFI_SMM_ENTRY_POINT SmmEntryPoint + ) +{ + // + // Record SMM Foundation EntryPoint, later invoke it on SMI entry vector. + // + gSmmCpuPrivate->SmmCoreEntry = SmmEntryPoint; + return EFI_SUCCESS; +} diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c new file mode 100644 index 000000000000..0e39173cbbe8 --- /dev/null +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c @@ -0,0 +1,1489 @@ +/** @file +Agent Module to load other modules to deploy SMM Entry Vector for X86 CPU. + +Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "PiSmmCpuDxeSmm.h" + +// +// SMM CPU Private Data structure that contains SMM Configuration Protocol +// along its supporting fields. +// +SMM_CPU_PRIVATE_DATA mSmmCpuPrivateData = { + SMM_CPU_PRIVATE_DATA_SIGNATURE, // Signature + NULL, // SmmCpuHandle + NULL, // Pointer to ProcessorInfo array + NULL, // Pointer to Operation array + NULL, // Pointer to CpuSaveStateSize array + NULL, // Pointer to CpuSaveState array + { {0} }, // SmmReservedSmramRegion + { + SmmStartupThisAp, // SmmCoreEntryContext.SmmStartupThisAp + 0, // SmmCoreEntryContext.CurrentlyExecutingCpu + 0, // SmmCoreEntryContext.NumberOfCpus + NULL, // SmmCoreEntryContext.CpuSaveStateSize + NULL // SmmCoreEntryContext.CpuSaveState + }, + NULL, // SmmCoreEntry + { + mSmmCpuPrivateData.SmmReservedSmramRegion, // SmmConfiguration.SmramReservedRegions + RegisterSmmEntry // SmmConfiguration.RegisterSmmEntry + }, +}; + +CPU_HOT_PLUG_DATA mCpuHotPlugData = { + CPU_HOT_PLUG_DATA_REVISION_1, // Revision + 0, // Array Length of SmBase and APIC ID + NULL, // Pointer to APIC ID array + NULL, // Pointer to SMBASE array + 0, // Reserved + 0, // SmrrBase + 0 // SmrrSize +}; + +// +// Global pointer used to access mSmmCpuPrivateData from outside and inside SMM +// +SMM_CPU_PRIVATE_DATA *gSmmCpuPrivate = &mSmmCpuPrivateData; + +// +// SMM Relocation variables +// +volatile BOOLEAN *mRebased; +volatile BOOLEAN mIsBsp; + +/// +/// Handle for the SMM CPU Protocol +/// +EFI_HANDLE mSmmCpuHandle = NULL; + +/// +/// SMM CPU Protocol instance +/// +EFI_SMM_CPU_PROTOCOL mSmmCpu = { + SmmReadSaveState, + SmmWriteSaveState +}; + +EFI_CPU_INTERRUPT_HANDLER mExternalVectorTable[EXCEPTION_VECTOR_NUMBER]; + +/// +/// SMM CPU Save State Protocol instance +/// +EFI_SMM_CPU_SAVE_STATE_PROTOCOL mSmmCpuSaveState = { + NULL +}; + +// +// SMM stack information +// +UINTN mSmmStackArrayBase; +UINTN mSmmStackArrayEnd; +UINTN mSmmStackSize; + +// +// Pointer to structure used during S3 Resume +// +SMM_S3_RESUME_STATE *mSmmS3ResumeState = NULL; + +UINTN mMaxNumberOfCpus = 1; +UINTN mNumberOfCpus = 1; + +// +// SMM ready to lock flag +// +BOOLEAN mSmmReadyToLock = FALSE; + +// +// Global used to cache PCD for SMM Code Access Check enable +// +BOOLEAN mSmmCodeAccessCheckEnable = FALSE; + +// +// Spin lock used to serialize setting of SMM Code Access Check feature +// +SPIN_LOCK mConfigSmmCodeAccessCheckLock; + +/** + Initialize IDT to setup exception handlers for SMM. + +**/ +VOID +InitializeSmmIdt ( + VOID + ) +{ + EFI_STATUS Status; + BOOLEAN InterruptState; + IA32_DESCRIPTOR DxeIdtr; + // + // Disable Interrupt and save DXE IDT table + // + InterruptState = SaveAndDisableInterrupts (); + AsmReadIdtr (&DxeIdtr); + // + // Load SMM temporary IDT table + // + AsmWriteIdtr (&gcSmiIdtr); + // + // Setup SMM default exception handlers, SMM IDT table + // will be updated and saved in gcSmiIdtr + // + Status = InitializeCpuExceptionHandlers (NULL); + ASSERT_EFI_ERROR (Status); + // + // Restore DXE IDT table and CPU interrupt + // + AsmWriteIdtr ((IA32_DESCRIPTOR *) &DxeIdtr); + SetInterruptState (InterruptState); +} + +/** + Search module name by input IP address and output it. + + @param CallerIpAddress Caller instruction pointer. + +**/ +VOID +DumpModuleInfoByIp ( + IN UINTN CallerIpAddress + ) +{ + UINTN Pe32Data; + EFI_IMAGE_DOS_HEADER *DosHdr; + EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr; + VOID *PdbPointer; + UINT64 DumpIpAddress; + + // + // Find Image Base + // + Pe32Data = CallerIpAddress & ~(SIZE_4KB - 1); + while (Pe32Data != 0) { + DosHdr = (EFI_IMAGE_DOS_HEADER *) Pe32Data; + if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) { + // + // DOS image header is present, so read the PE header after the DOS image header. + // + Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)(Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff)); + // + // Make sure PE header address does not overflow and is less than the initial address. + // + if (((UINTN)Hdr.Pe32 > Pe32Data) && ((UINTN)Hdr.Pe32 < CallerIpAddress)) { + if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) { + // + // It's PE image. + // + break; + } + } + } + + // + // Not found the image base, check the previous aligned address + // + Pe32Data -= SIZE_4KB; + } + + DumpIpAddress = CallerIpAddress; + DEBUG ((EFI_D_ERROR, "It is invoked from the instruction before IP(0x%lx)", DumpIpAddress)); + + if (Pe32Data != 0) { + PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *) Pe32Data); + if (PdbPointer != NULL) { + DEBUG ((EFI_D_ERROR, " in module (%a)", PdbPointer)); + } + } +} + +/** + Read information from the CPU save state. + + @param This EFI_SMM_CPU_PROTOCOL instance + @param Width The number of bytes to read from the CPU save state. + @param Register Specifies the CPU register to read form the save state. + @param CpuIndex Specifies the zero-based index of the CPU save state. + @param Buffer Upon return, this holds the CPU register value read from the save state. + + @retval EFI_SUCCESS The register was read from Save State + @retval EFI_NOT_FOUND The register is not defined for the Save State of Processor + @retval EFI_INVALID_PARAMTER This or Buffer is NULL. + +**/ +EFI_STATUS +EFIAPI +SmmReadSaveState ( + IN CONST EFI_SMM_CPU_PROTOCOL *This, + IN UINTN Width, + IN EFI_SMM_SAVE_STATE_REGISTER Register, + IN UINTN CpuIndex, + OUT VOID *Buffer + ) +{ + EFI_STATUS Status; + + // + // Retrieve pointer to the specified CPU's SMM Save State buffer + // + if ((CpuIndex >= gSmst->NumberOfCpus) || (Buffer == NULL)) { + return EFI_INVALID_PARAMETER; + } + + // + // Check for special EFI_SMM_SAVE_STATE_REGISTER_PROCESSOR_ID + // + if (Register == EFI_SMM_SAVE_STATE_REGISTER_PROCESSOR_ID) { + // + // The pseudo-register only supports the 64-bit size specified by Width. + // + if (Width != sizeof (UINT64)) { + return EFI_INVALID_PARAMETER; + } + // + // If the processor is in SMM at the time the SMI occurred, + // the pseudo register value for EFI_SMM_SAVE_STATE_REGISTER_PROCESSOR_ID is returned in Buffer. + // Otherwise, EFI_NOT_FOUND is returned. + // + if (mSmmMpSyncData->CpuData[CpuIndex].Present) { + *(UINT64 *)Buffer = gSmmCpuPrivate->ProcessorInfo[CpuIndex].ProcessorId; + return EFI_SUCCESS; + } else { + return EFI_NOT_FOUND; + } + } + + if (!mSmmMpSyncData->CpuData[CpuIndex].Present) { + return EFI_INVALID_PARAMETER; + } + + Status = SmmCpuFeaturesReadSaveStateRegister (CpuIndex, Register, Width, Buffer); + if (Status == EFI_UNSUPPORTED) { + Status = ReadSaveStateRegister (CpuIndex, Register, Width, Buffer); + } + return Status; +} + +/** + Write data to the CPU save state. + + @param This EFI_SMM_CPU_PROTOCOL instance + @param Width The number of bytes to read from the CPU save state. + @param Register Specifies the CPU register to write to the save state. + @param CpuIndex Specifies the zero-based index of the CPU save state + @param Buffer Upon entry, this holds the new CPU register value. + + @retval EFI_SUCCESS The register was written from Save State + @retval EFI_NOT_FOUND The register is not defined for the Save State of Processor + @retval EFI_INVALID_PARAMTER ProcessorIndex or Width is not correct + +**/ +EFI_STATUS +EFIAPI +SmmWriteSaveState ( + IN CONST EFI_SMM_CPU_PROTOCOL *This, + IN UINTN Width, + IN EFI_SMM_SAVE_STATE_REGISTER Register, + IN UINTN CpuIndex, + IN CONST VOID *Buffer + ) +{ + EFI_STATUS Status; + + // + // Retrieve pointer to the specified CPU's SMM Save State buffer + // + if ((CpuIndex >= gSmst->NumberOfCpus) || (Buffer == NULL)) { + return EFI_INVALID_PARAMETER; + } + + // + // Writes to EFI_SMM_SAVE_STATE_REGISTER_PROCESSOR_ID are ignored + // + if (Register == EFI_SMM_SAVE_STATE_REGISTER_PROCESSOR_ID) { + return EFI_SUCCESS; + } + + if (!mSmmMpSyncData->CpuData[CpuIndex].Present) { + return EFI_INVALID_PARAMETER; + } + + Status = SmmCpuFeaturesWriteSaveStateRegister (CpuIndex, Register, Width, Buffer); + if (Status == EFI_UNSUPPORTED) { + Status = WriteSaveStateRegister (CpuIndex, Register, Width, Buffer); + } + return Status; +} + + +/** + C function for SMI handler. To change all processor's SMMBase Register. + +**/ +VOID +EFIAPI +SmmInitHandler ( + VOID + ) +{ + UINT32 ApicId; + UINTN Index; + + // + // Update SMM IDT entries' code segment and load IDT + // + AsmWriteIdtr (&gcSmiIdtr); + ApicId = GetApicId (); + + ASSERT (mNumberOfCpus <= PcdGet32 (PcdCpuMaxLogicalProcessorNumber)); + + for (Index = 0; Index < mNumberOfCpus; Index++) { + if (ApicId == (UINT32)gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId) { + // + // Initialize SMM specific features on the currently executing CPU + // + SmmCpuFeaturesInitializeProcessor ( + Index, + mIsBsp, + gSmmCpuPrivate->ProcessorInfo, + &mCpuHotPlugData + ); + + if (mIsBsp) { + // + // BSP rebase is already done above. + // Initialize private data during S3 resume + // + InitializeMpSyncData (); + } + + // + // Hook return after RSM to set SMM re-based flag + // + SemaphoreHook (Index, &mRebased[Index]); + + return; + } + } + ASSERT (FALSE); +} + +/** + Relocate SmmBases for each processor. + + Execute on first boot and all S3 resumes + +**/ +VOID +EFIAPI +SmmRelocateBases ( + VOID + ) +{ + UINT8 BakBuf[BACK_BUF_SIZE]; + SMRAM_SAVE_STATE_MAP BakBuf2; + SMRAM_SAVE_STATE_MAP *CpuStatePtr; + UINT8 *U8Ptr; + UINT32 ApicId; + UINTN Index; + UINTN BspIndex; + + // + // Make sure the reserved size is large enough for procedure SmmInitTemplate. + // + ASSERT (sizeof (BakBuf) >= gcSmmInitSize); + + // + // Patch ASM code template with current CR0, CR3, and CR4 values + // + gSmmCr0 = (UINT32)AsmReadCr0 (); + gSmmCr3 = (UINT32)AsmReadCr3 (); + gSmmCr4 = (UINT32)AsmReadCr4 (); + + // + // Patch GDTR for SMM base relocation + // + gcSmiInitGdtr.Base = gcSmiGdtr.Base; + gcSmiInitGdtr.Limit = gcSmiGdtr.Limit; + + U8Ptr = (UINT8*)(UINTN)(SMM_DEFAULT_SMBASE + SMM_HANDLER_OFFSET); + CpuStatePtr = (SMRAM_SAVE_STATE_MAP *)(UINTN)(SMM_DEFAULT_SMBASE + SMRAM_SAVE_STATE_MAP_OFFSET); + + // + // Backup original contents at address 0x38000 + // + CopyMem (BakBuf, U8Ptr, sizeof (BakBuf)); + CopyMem (&BakBuf2, CpuStatePtr, sizeof (BakBuf2)); + + // + // Load image for relocation + // + CopyMem (U8Ptr, gcSmmInitTemplate, gcSmmInitSize); + + // + // Retrieve the local APIC ID of current processor + // + ApicId = GetApicId (); + + // + // Relocate SM bases for all APs + // This is APs' 1st SMI - rebase will be done here, and APs' default SMI handler will be overridden by gcSmmInitTemplate + // + mIsBsp = FALSE; + BspIndex = (UINTN)-1; + for (Index = 0; Index < mNumberOfCpus; Index++) { + mRebased[Index] = FALSE; + if (ApicId != (UINT32)gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId) { + SendSmiIpi ((UINT32)gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId); + // + // Wait for this AP to finish its 1st SMI + // + while (!mRebased[Index]); + } else { + // + // BSP will be Relocated later + // + BspIndex = Index; + } + } + + // + // Relocate BSP's SMM base + // + ASSERT (BspIndex != (UINTN)-1); + mIsBsp = TRUE; + SendSmiIpi (ApicId); + // + // Wait for the BSP to finish its 1st SMI + // + while (!mRebased[BspIndex]); + + // + // Restore contents at address 0x38000 + // + CopyMem (CpuStatePtr, &BakBuf2, sizeof (BakBuf2)); + CopyMem (U8Ptr, BakBuf, sizeof (BakBuf)); +} + +/** + Perform SMM initialization for all processors in the S3 boot path. + + For a native platform, MP initialization in the S3 boot path is also performed in this function. +**/ +VOID +EFIAPI +SmmRestoreCpu ( + VOID + ) +{ + SMM_S3_RESUME_STATE *SmmS3ResumeState; + IA32_DESCRIPTOR Ia32Idtr; + IA32_DESCRIPTOR X64Idtr; + IA32_IDT_GATE_DESCRIPTOR IdtEntryTable[EXCEPTION_VECTOR_NUMBER]; + EFI_STATUS Status; + + DEBUG ((EFI_D_INFO, "SmmRestoreCpu()\n")); + + // + // See if there is enough context to resume PEI Phase + // + if (mSmmS3ResumeState == NULL) { + DEBUG ((EFI_D_ERROR, "No context to return to PEI Phase\n")); + CpuDeadLoop (); + } + + SmmS3ResumeState = mSmmS3ResumeState; + ASSERT (SmmS3ResumeState != NULL); + + if (SmmS3ResumeState->Signature == SMM_S3_RESUME_SMM_64) { + // + // Save the IA32 IDT Descriptor + // + AsmReadIdtr ((IA32_DESCRIPTOR *) &Ia32Idtr); + + // + // Setup X64 IDT table + // + ZeroMem (IdtEntryTable, sizeof (IA32_IDT_GATE_DESCRIPTOR) * 32); + X64Idtr.Base = (UINTN) IdtEntryTable; + X64Idtr.Limit = (UINT16) (sizeof (IA32_IDT_GATE_DESCRIPTOR) * 32 - 1); + AsmWriteIdtr ((IA32_DESCRIPTOR *) &X64Idtr); + + // + // Setup the default exception handler + // + Status = InitializeCpuExceptionHandlers (NULL); + ASSERT_EFI_ERROR (Status); + + // + // Initialize Debug Agent to support source level debug + // + InitializeDebugAgent (DEBUG_AGENT_INIT_THUNK_PEI_IA32TOX64, (VOID *)&Ia32Idtr, NULL); + } + + // + // Do below CPU things for native platform only + // + if (!FeaturePcdGet(PcdFrameworkCompatibilitySupport)) { + // + // Skip initialization if mAcpiCpuData is not valid + // + if (mAcpiCpuData.NumberOfCpus > 0) { + // + // First time microcode load and restore MTRRs + // + EarlyInitializeCpu (); + } + } + + // + // Restore SMBASE for BSP and all APs + // + SmmRelocateBases (); + + // + // Do below CPU things for native platform only + // + if (!FeaturePcdGet(PcdFrameworkCompatibilitySupport)) { + // + // Skip initialization if mAcpiCpuData is not valid + // + if (mAcpiCpuData.NumberOfCpus > 0) { + // + // Restore MSRs for BSP and all APs + // + InitializeCpu (); + } + } + + // + // Set a flag to restore SMM configuration in S3 path. + // + mRestoreSmmConfigurationInS3 = TRUE; + + DEBUG (( EFI_D_INFO, "SMM S3 Return CS = %x\n", SmmS3ResumeState->ReturnCs)); + DEBUG (( EFI_D_INFO, "SMM S3 Return Entry Point = %x\n", SmmS3ResumeState->ReturnEntryPoint)); + DEBUG (( EFI_D_INFO, "SMM S3 Return Context1 = %x\n", SmmS3ResumeState->ReturnContext1)); + DEBUG (( EFI_D_INFO, "SMM S3 Return Context2 = %x\n", SmmS3ResumeState->ReturnContext2)); + DEBUG (( EFI_D_INFO, "SMM S3 Return Stack Pointer = %x\n", SmmS3ResumeState->ReturnStackPointer)); + + // + // If SMM is in 32-bit mode, then use SwitchStack() to resume PEI Phase + // + if (SmmS3ResumeState->Signature == SMM_S3_RESUME_SMM_32) { + DEBUG ((EFI_D_INFO, "Call SwitchStack() to return to S3 Resume in PEI Phase\n")); + + SwitchStack ( + (SWITCH_STACK_ENTRY_POINT)(UINTN)SmmS3ResumeState->ReturnEntryPoint, + (VOID *)(UINTN)SmmS3ResumeState->ReturnContext1, + (VOID *)(UINTN)SmmS3ResumeState->ReturnContext2, + (VOID *)(UINTN)SmmS3ResumeState->ReturnStackPointer + ); + } + + // + // If SMM is in 64-bit mode, then use AsmDisablePaging64() to resume PEI Phase + // + if (SmmS3ResumeState->Signature == SMM_S3_RESUME_SMM_64) { + DEBUG ((EFI_D_INFO, "Call AsmDisablePaging64() to return to S3 Resume in PEI Phase\n")); + // + // Disable interrupt of Debug timer, since new IDT table is for IA32 and will not work in long mode. + // + SaveAndSetDebugTimerInterrupt (FALSE); + // + // Restore IA32 IDT table + // + AsmWriteIdtr ((IA32_DESCRIPTOR *) &Ia32Idtr); + AsmDisablePaging64 ( + SmmS3ResumeState->ReturnCs, + (UINT32)SmmS3ResumeState->ReturnEntryPoint, + (UINT32)SmmS3ResumeState->ReturnContext1, + (UINT32)SmmS3ResumeState->ReturnContext2, + (UINT32)SmmS3ResumeState->ReturnStackPointer + ); + } + + // + // Can not resume PEI Phase + // + DEBUG ((EFI_D_ERROR, "No context to return to PEI Phase\n")); + CpuDeadLoop (); +} + +/** + Copy register table from ACPI NVS memory into SMRAM. + + @param[in] DestinationRegisterTableList Points to destination register table. + @param[in] SourceRegisterTableList Points to source register table. + @param[in] NumberOfCpus Number of CPUs. + +**/ +VOID +CopyRegisterTable ( + IN CPU_REGISTER_TABLE *DestinationRegisterTableList, + IN CPU_REGISTER_TABLE *SourceRegisterTableList, + IN UINT32 NumberOfCpus + ) +{ + UINTN Index; + UINTN Index1; + CPU_REGISTER_TABLE_ENTRY *RegisterTableEntry; + + CopyMem (DestinationRegisterTableList, SourceRegisterTableList, NumberOfCpus * sizeof (CPU_REGISTER_TABLE)); + for (Index = 0; Index < NumberOfCpus; Index++) { + DestinationRegisterTableList[Index].RegisterTableEntry = AllocatePool (DestinationRegisterTableList[Index].AllocatedSize); + ASSERT (DestinationRegisterTableList[Index].RegisterTableEntry != NULL); + CopyMem (DestinationRegisterTableList[Index].RegisterTableEntry, SourceRegisterTableList[Index].RegisterTableEntry, DestinationRegisterTableList[Index].AllocatedSize); + // + // Go though all MSRs in register table to initialize MSR spin lock + // + RegisterTableEntry = DestinationRegisterTableList[Index].RegisterTableEntry; + for (Index1 = 0; Index1 < DestinationRegisterTableList[Index].TableLength; Index1++, RegisterTableEntry++) { + if ((RegisterTableEntry->RegisterType == Msr) && (RegisterTableEntry->ValidBitLength < 64)) { + // + // Initialize MSR spin lock only for those MSRs need bit field writing + // + InitMsrSpinLockByIndex (RegisterTableEntry->Index); + } + } + } +} + +/** + SMM Ready To Lock event notification handler. + + The CPU S3 data is copied to SMRAM for security and mSmmReadyToLock is set to + perform additional lock actions that must be performed from SMM on the next SMI. + + @param[in] Protocol Points to the protocol's unique identifier. + @param[in] Interface Points to the interface instance. + @param[in] Handle The handle on which the interface was installed. + + @retval EFI_SUCCESS Notification handler runs successfully. + **/ +EFI_STATUS +EFIAPI +SmmReadyToLockEventNotify ( + IN CONST EFI_GUID *Protocol, + IN VOID *Interface, + IN EFI_HANDLE Handle + ) +{ + ACPI_CPU_DATA *AcpiCpuData; + IA32_DESCRIPTOR *Gdtr; + IA32_DESCRIPTOR *Idtr; + + // + // Prevent use of mAcpiCpuData by initialize NumberOfCpus to 0 + // + mAcpiCpuData.NumberOfCpus = 0; + + // + // If FrameworkCompatibilitySspport is enabled, then do not copy CPU S3 Data into SMRAM + // + if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) { + goto Done; + } + + // + // If PcdCpuS3DataAddress was never set, then do not copy CPU S3 Data into SMRAM + // + AcpiCpuData = (ACPI_CPU_DATA *)(UINTN)PcdGet64 (PcdCpuS3DataAddress); + if (AcpiCpuData == 0) { + goto Done; + } + + // + // For a native platform, copy the CPU S3 data into SMRAM for use on CPU S3 Resume. + // + CopyMem (&mAcpiCpuData, AcpiCpuData, sizeof (mAcpiCpuData)); + + mAcpiCpuData.MtrrTable = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocatePool (sizeof (MTRR_SETTINGS)); + ASSERT (mAcpiCpuData.MtrrTable != 0); + + CopyMem ((VOID *)(UINTN)mAcpiCpuData.MtrrTable, (VOID *)(UINTN)AcpiCpuData->MtrrTable, sizeof (MTRR_SETTINGS)); + + mAcpiCpuData.GdtrProfile = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocatePool (sizeof (IA32_DESCRIPTOR)); + ASSERT (mAcpiCpuData.GdtrProfile != 0); + + CopyMem ((VOID *)(UINTN)mAcpiCpuData.GdtrProfile, (VOID *)(UINTN)AcpiCpuData->GdtrProfile, sizeof (IA32_DESCRIPTOR)); + + mAcpiCpuData.IdtrProfile = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocatePool (sizeof (IA32_DESCRIPTOR)); + ASSERT (mAcpiCpuData.IdtrProfile != 0); + + CopyMem ((VOID *)(UINTN)mAcpiCpuData.IdtrProfile, (VOID *)(UINTN)AcpiCpuData->IdtrProfile, sizeof (IA32_DESCRIPTOR)); + + mAcpiCpuData.PreSmmInitRegisterTable = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocatePool (mAcpiCpuData.NumberOfCpus * sizeof (CPU_REGISTER_TABLE)); + ASSERT (mAcpiCpuData.PreSmmInitRegisterTable != 0); + + CopyRegisterTable ( + (CPU_REGISTER_TABLE *)(UINTN)mAcpiCpuData.PreSmmInitRegisterTable, + (CPU_REGISTER_TABLE *)(UINTN)AcpiCpuData->PreSmmInitRegisterTable, + mAcpiCpuData.NumberOfCpus + ); + + mAcpiCpuData.RegisterTable = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocatePool (mAcpiCpuData.NumberOfCpus * sizeof (CPU_REGISTER_TABLE)); + ASSERT (mAcpiCpuData.RegisterTable != 0); + + CopyRegisterTable ( + (CPU_REGISTER_TABLE *)(UINTN)mAcpiCpuData.RegisterTable, + (CPU_REGISTER_TABLE *)(UINTN)AcpiCpuData->RegisterTable, + mAcpiCpuData.NumberOfCpus + ); + + // + // Copy AP's GDT, IDT and Machine Check handler into SMRAM. + // + Gdtr = (IA32_DESCRIPTOR *)(UINTN)mAcpiCpuData.GdtrProfile; + Idtr = (IA32_DESCRIPTOR *)(UINTN)mAcpiCpuData.IdtrProfile; + + mGdtForAp = AllocatePool ((Gdtr->Limit + 1) + (Idtr->Limit + 1) + mAcpiCpuData.ApMachineCheckHandlerSize); + ASSERT (mGdtForAp != NULL); + mIdtForAp = (VOID *) ((UINTN)mGdtForAp + (Gdtr->Limit + 1)); + mMachineCheckHandlerForAp = (VOID *) ((UINTN)mIdtForAp + (Idtr->Limit + 1)); + + CopyMem (mGdtForAp, (VOID *)Gdtr->Base, Gdtr->Limit + 1); + CopyMem (mIdtForAp, (VOID *)Idtr->Base, Idtr->Limit + 1); + CopyMem (mMachineCheckHandlerForAp, (VOID *)(UINTN)mAcpiCpuData.ApMachineCheckHandlerBase, mAcpiCpuData.ApMachineCheckHandlerSize); + +Done: + // + // Set SMM ready to lock flag and return + // + mSmmReadyToLock = TRUE; + return EFI_SUCCESS; +} + +/** + The module Entry Point of the CPU SMM driver. + + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + @retval Other Some error occurs when executing this entry point. + +**/ +EFI_STATUS +EFIAPI +PiCpuSmmEntry ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_MP_SERVICES_PROTOCOL *MpServices; + UINTN NumberOfEnabledProcessors; + UINTN Index; + VOID *Buffer; + UINTN TileSize; + VOID *GuidHob; + EFI_SMRAM_DESCRIPTOR *SmramDescriptor; + SMM_S3_RESUME_STATE *SmmS3ResumeState; + UINT8 *Stacks; + VOID *Registration; + UINT32 RegEax; + UINT32 RegEdx; + UINTN FamilyId; + UINTN ModelId; + UINT32 Cr3; + + // + // Initialize Debug Agent to support source level debug in SMM code + // + InitializeDebugAgent (DEBUG_AGENT_INIT_SMM, NULL, NULL); + + // + // Report the start of CPU SMM initialization. + // + REPORT_STATUS_CODE ( + EFI_PROGRESS_CODE, + EFI_COMPUTING_UNIT_HOST_PROCESSOR | EFI_CU_HP_PC_SMM_INIT + ); + + // + // Fix segment address of the long-mode-switch jump + // + if (sizeof (UINTN) == sizeof (UINT64)) { + gSmmJmpAddr.Segment = LONG_MODE_CODE_SEGMENT; + } + + // + // Find out SMRR Base and SMRR Size + // + FindSmramInfo (&mCpuHotPlugData.SmrrBase, &mCpuHotPlugData.SmrrSize); + + // + // Get MP Services Protocol + // + Status = SystemTable->BootServices->LocateProtocol (&gEfiMpServiceProtocolGuid, NULL, (VOID **)&MpServices); + ASSERT_EFI_ERROR (Status); + + // + // Use MP Services Protocol to retrieve the number of processors and number of enabled processors + // + Status = MpServices->GetNumberOfProcessors (MpServices, &mNumberOfCpus, &NumberOfEnabledProcessors); + ASSERT_EFI_ERROR (Status); + ASSERT (mNumberOfCpus <= PcdGet32 (PcdCpuMaxLogicalProcessorNumber)); + + // + // If support CPU hot plug, PcdCpuSmmEnableBspElection should be set to TRUE. + // A constant BSP index makes no sense because it may be hot removed. + // + DEBUG_CODE ( + if (FeaturePcdGet (PcdCpuHotPlugSupport)) { + + ASSERT (FeaturePcdGet (PcdCpuSmmEnableBspElection)); + } + ); + + // + // Save the PcdCpuSmmCodeAccessCheckEnable value into a global variable. + // + mSmmCodeAccessCheckEnable = PcdGetBool (PcdCpuSmmCodeAccessCheckEnable); + DEBUG ((EFI_D_INFO, "PcdCpuSmmCodeAccessCheckEnable = %d\n", mSmmCodeAccessCheckEnable)); + + // + // If support CPU hot plug, we need to allocate resources for possibly hot-added processors + // + if (FeaturePcdGet (PcdCpuHotPlugSupport)) { + mMaxNumberOfCpus = PcdGet32 (PcdCpuMaxLogicalProcessorNumber); + } else { + mMaxNumberOfCpus = mNumberOfCpus; + } + gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus = mMaxNumberOfCpus; + + // + // The CPU save state and code for the SMI entry point are tiled within an SMRAM + // allocated buffer. The minimum size of this buffer for a uniprocessor system + // is 32 KB, because the entry point is SMBASE + 32KB, and CPU save state area + // just below SMBASE + 64KB. If more than one CPU is present in the platform, + // then the SMI entry point and the CPU save state areas can be tiles to minimize + // the total amount SMRAM required for all the CPUs. The tile size can be computed + // by adding the // CPU save state size, any extra CPU specific context, and + // the size of code that must be placed at the SMI entry point to transfer + // control to a C function in the native SMM execution mode. This size is + // rounded up to the nearest power of 2 to give the tile size for a each CPU. + // The total amount of memory required is the maximum number of CPUs that + // platform supports times the tile size. The picture below shows the tiling, + // where m is the number of tiles that fit in 32KB. + // + // +-----------------------------+ <-- 2^n offset from Base of allocated buffer + // | CPU m+1 Save State | + // +-----------------------------+ + // | CPU m+1 Extra Data | + // +-----------------------------+ + // | Padding | + // +-----------------------------+ + // | CPU 2m SMI Entry | + // +#############################+ <-- Base of allocated buffer + 64 KB + // | CPU m-1 Save State | + // +-----------------------------+ + // | CPU m-1 Extra Data | + // +-----------------------------+ + // | Padding | + // +-----------------------------+ + // | CPU 2m-1 SMI Entry | + // +=============================+ <-- 2^n offset from Base of allocated buffer + // | . . . . . . . . . . . . | + // +=============================+ <-- 2^n offset from Base of allocated buffer + // | CPU 2 Save State | + // +-----------------------------+ + // | CPU 2 Extra Data | + // +-----------------------------+ + // | Padding | + // +-----------------------------+ + // | CPU m+1 SMI Entry | + // +=============================+ <-- Base of allocated buffer + 32 KB + // | CPU 1 Save State | + // +-----------------------------+ + // | CPU 1 Extra Data | + // +-----------------------------+ + // | Padding | + // +-----------------------------+ + // | CPU m SMI Entry | + // +#############################+ <-- Base of allocated buffer + 32 KB == CPU 0 SMBASE + 64 KB + // | CPU 0 Save State | + // +-----------------------------+ + // | CPU 0 Extra Data | + // +-----------------------------+ + // | Padding | + // +-----------------------------+ + // | CPU m-1 SMI Entry | + // +=============================+ <-- 2^n offset from Base of allocated buffer + // | . . . . . . . . . . . . | + // +=============================+ <-- 2^n offset from Base of allocated buffer + // | Padding | + // +-----------------------------+ + // | CPU 1 SMI Entry | + // +=============================+ <-- 2^n offset from Base of allocated buffer + // | Padding | + // +-----------------------------+ + // | CPU 0 SMI Entry | + // +#############################+ <-- Base of allocated buffer == CPU 0 SMBASE + 32 KB + // + + // + // Retrieve CPU Family + // + AsmCpuid (CPUID_VERSION_INFO, &RegEax, NULL, NULL, &RegEdx); + FamilyId = (RegEax >> 8) & 0xf; + ModelId = (RegEax >> 4) & 0xf; + if (FamilyId == 0x06 || FamilyId == 0x0f) { + ModelId = ModelId | ((RegEax >> 12) & 0xf0); + } + + // + // Determine the mode of the CPU at the time an SMI occurs + // Intel(R) 64 and IA-32 Architectures Software Developer's Manual + // Volume 3C, Section 34.4.1.1 + // + mSmmSaveStateRegisterLma = EFI_SMM_SAVE_STATE_REGISTER_LMA_32BIT; + if ((RegEdx & BIT29) != 0) { + mSmmSaveStateRegisterLma = EFI_SMM_SAVE_STATE_REGISTER_LMA_64BIT; + } + if (FamilyId == 0x06) { + if (ModelId == 0x17 || ModelId == 0x0f || ModelId == 0x1c) { + mSmmSaveStateRegisterLma = EFI_SMM_SAVE_STATE_REGISTER_LMA_64BIT; + } + } + + // + // Compute tile size of buffer required to hold the CPU SMRAM Save State Map, extra CPU + // specific context in a PROCESSOR_SMM_DESCRIPTOR, and the SMI entry point. This size + // is rounded up to nearest power of 2. + // + TileSize = sizeof (SMRAM_SAVE_STATE_MAP) + sizeof (PROCESSOR_SMM_DESCRIPTOR) + GetSmiHandlerSize () - 1; + TileSize = 2 * GetPowerOfTwo32 ((UINT32)TileSize); + DEBUG ((EFI_D_INFO, "SMRAM TileSize = %08x\n", TileSize)); + + // + // If the TileSize is larger than space available for the SMI Handler of CPU[i], + // the PROCESSOR_SMM_DESCRIPTOR of CPU[i+1] and the SMRAM Save State Map of CPU[i+1], + // the ASSERT(). If this ASSERT() is triggered, then the SMI Handler size must be + // reduced. + // + ASSERT (TileSize <= (SMRAM_SAVE_STATE_MAP_OFFSET + sizeof (SMRAM_SAVE_STATE_MAP) - SMM_HANDLER_OFFSET)); + + // + // Allocate buffer for all of the tiles. + // + // Intel(R) 64 and IA-32 Architectures Software Developer's Manual + // Volume 3C, Section 34.11 SMBASE Relocation + // For Pentium and Intel486 processors, the SMBASE values must be + // aligned on a 32-KByte boundary or the processor will enter shutdown + // state during the execution of a RSM instruction. + // + // Intel486 processors: FamilyId is 4 + // Pentium processors : FamilyId is 5 + // + if ((FamilyId == 4) || (FamilyId == 5)) { + Buffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES (SIZE_32KB + TileSize * (mMaxNumberOfCpus - 1)), SIZE_32KB); + } else { + Buffer = AllocatePages (EFI_SIZE_TO_PAGES (SIZE_32KB + TileSize * (mMaxNumberOfCpus - 1))); + } + ASSERT (Buffer != NULL); + + // + // Allocate buffer for pointers to array in SMM_CPU_PRIVATE_DATA. + // + gSmmCpuPrivate->ProcessorInfo = (EFI_PROCESSOR_INFORMATION *)AllocatePool (sizeof (EFI_PROCESSOR_INFORMATION) * mMaxNumberOfCpus); + ASSERT (gSmmCpuPrivate->ProcessorInfo != NULL); + + gSmmCpuPrivate->Operation = (SMM_CPU_OPERATION *)AllocatePool (sizeof (SMM_CPU_OPERATION) * mMaxNumberOfCpus); + ASSERT (gSmmCpuPrivate->Operation != NULL); + + gSmmCpuPrivate->CpuSaveStateSize = (UINTN *)AllocatePool (sizeof (UINTN) * mMaxNumberOfCpus); + ASSERT (gSmmCpuPrivate->CpuSaveStateSize != NULL); + + gSmmCpuPrivate->CpuSaveState = (VOID **)AllocatePool (sizeof (VOID *) * mMaxNumberOfCpus); + ASSERT (gSmmCpuPrivate->CpuSaveState != NULL); + + mSmmCpuPrivateData.SmmCoreEntryContext.CpuSaveStateSize = gSmmCpuPrivate->CpuSaveStateSize; + mSmmCpuPrivateData.SmmCoreEntryContext.CpuSaveState = gSmmCpuPrivate->CpuSaveState; + mSmmCpuSaveState.CpuSaveState = (EFI_SMM_CPU_STATE **)gSmmCpuPrivate->CpuSaveState; + + // + // Allocate buffer for pointers to array in CPU_HOT_PLUG_DATA. + // + mCpuHotPlugData.ApicId = (UINT64 *)AllocatePool (sizeof (UINT64) * mMaxNumberOfCpus); + ASSERT (mCpuHotPlugData.ApicId != NULL); + mCpuHotPlugData.SmBase = (UINTN *)AllocatePool (sizeof (UINTN) * mMaxNumberOfCpus); + ASSERT (mCpuHotPlugData.SmBase != NULL); + mCpuHotPlugData.ArrayLength = (UINT32)mMaxNumberOfCpus; + + // + // Retrieve APIC ID of each enabled processor from the MP Services protocol. + // Also compute the SMBASE address, CPU Save State address, and CPU Save state + // size for each CPU in the platform + // + for (Index = 0; Index < mMaxNumberOfCpus; Index++) { + mCpuHotPlugData.SmBase[Index] = (UINTN)Buffer + Index * TileSize - SMM_HANDLER_OFFSET; + gSmmCpuPrivate->CpuSaveStateSize[Index] = sizeof(SMRAM_SAVE_STATE_MAP); + gSmmCpuPrivate->CpuSaveState[Index] = (VOID *)(mCpuHotPlugData.SmBase[Index] + SMRAM_SAVE_STATE_MAP_OFFSET); + gSmmCpuPrivate->Operation[Index] = SmmCpuNone; + + if (Index < mNumberOfCpus) { + Status = MpServices->GetProcessorInfo (MpServices, Index, &gSmmCpuPrivate->ProcessorInfo[Index]); + ASSERT_EFI_ERROR (Status); + mCpuHotPlugData.ApicId[Index] = gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId; + + DEBUG ((EFI_D_INFO, "CPU[%03x] APIC ID=%04x SMBASE=%08x SaveState=%08x Size=%08x\n", + Index, + (UINT32)gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId, + mCpuHotPlugData.SmBase[Index], + gSmmCpuPrivate->CpuSaveState[Index], + gSmmCpuPrivate->CpuSaveStateSize[Index] + )); + } else { + gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId = INVALID_APIC_ID; + mCpuHotPlugData.ApicId[Index] = INVALID_APIC_ID; + } + } + + // + // Allocate SMI stacks for all processors. + // + if (FeaturePcdGet (PcdCpuSmmStackGuard)) { + // + // 2 more pages is allocated for each processor. + // one is guard page and the other is known good stack. + // + // +-------------------------------------------+-----+-------------------------------------------+ + // | Known Good Stack | Guard Page | SMM Stack | ... | Known Good Stack | Guard Page | SMM Stack | + // +-------------------------------------------+-----+-------------------------------------------+ + // | | | | + // |<-------------- Processor 0 -------------->| |<-------------- Processor n -------------->| + // + mSmmStackSize = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmStackSize)) + 2); + Stacks = (UINT8 *) AllocatePages (gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus * (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmStackSize)) + 2)); + ASSERT (Stacks != NULL); + mSmmStackArrayBase = (UINTN)Stacks; + mSmmStackArrayEnd = mSmmStackArrayBase + gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus * mSmmStackSize - 1; + } else { + mSmmStackSize = PcdGet32 (PcdCpuSmmStackSize); + Stacks = (UINT8 *) AllocatePages (EFI_SIZE_TO_PAGES (gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus * mSmmStackSize)); + ASSERT (Stacks != NULL); + } + + // + // Set SMI stack for SMM base relocation + // + gSmmInitStack = (UINTN) (Stacks + mSmmStackSize - sizeof (UINTN)); + + // + // Initialize IDT + // + InitializeSmmIdt (); + + // + // Relocate SMM Base addresses to the ones allocated from SMRAM + // + mRebased = (BOOLEAN *)AllocateZeroPool (sizeof (BOOLEAN) * mMaxNumberOfCpus); + ASSERT (mRebased != NULL); + SmmRelocateBases (); + + // + // Call hook for BSP to perform extra actions in normal mode after all + // SMM base addresses have been relocated on all CPUs + // + SmmCpuFeaturesSmmRelocationComplete (); + + // + // SMM Time initialization + // + InitializeSmmTimer (); + + // + // Initialize MP globals + // + Cr3 = InitializeMpServiceData (Stacks, mSmmStackSize); + + // + // Fill in SMM Reserved Regions + // + gSmmCpuPrivate->SmmReservedSmramRegion[0].SmramReservedStart = 0; + gSmmCpuPrivate->SmmReservedSmramRegion[0].SmramReservedSize = 0; + + // + // Install the SMM Configuration Protocol onto a new handle on the handle database. + // The entire SMM Configuration Protocol is allocated from SMRAM, so only a pointer + // to an SMRAM address will be present in the handle database + // + Status = SystemTable->BootServices->InstallMultipleProtocolInterfaces ( + &gSmmCpuPrivate->SmmCpuHandle, + &gEfiSmmConfigurationProtocolGuid, &gSmmCpuPrivate->SmmConfiguration, + NULL + ); + ASSERT_EFI_ERROR (Status); + + // + // Install the SMM CPU Protocol into SMM protocol database + // + Status = gSmst->SmmInstallProtocolInterface ( + &mSmmCpuHandle, + &gEfiSmmCpuProtocolGuid, + EFI_NATIVE_INTERFACE, + &mSmmCpu + ); + ASSERT_EFI_ERROR (Status); + + // + // Expose address of CPU Hot Plug Data structure if CPU hot plug is supported. + // + if (FeaturePcdGet (PcdCpuHotPlugSupport)) { + PcdSet64 (PcdCpuHotPlugDataAddress, (UINT64)(UINTN)&mCpuHotPlugData); + } + + // + // Initialize SMM CPU Services Support + // + Status = InitializeSmmCpuServices (mSmmCpuHandle); + ASSERT_EFI_ERROR (Status); + + if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) { + // + // Install Framework SMM Save State Protocol into UEFI protocol database for backward compatibility + // + Status = SystemTable->BootServices->InstallMultipleProtocolInterfaces ( + &gSmmCpuPrivate->SmmCpuHandle, + &gEfiSmmCpuSaveStateProtocolGuid, + &mSmmCpuSaveState, + NULL + ); + ASSERT_EFI_ERROR (Status); + // + // The SmmStartupThisAp service in Framework SMST should always be non-null. + // Update SmmStartupThisAp pointer in PI SMST here so that PI/Framework SMM thunk + // can have it ready when constructing Framework SMST. + // + gSmst->SmmStartupThisAp = SmmStartupThisAp; + } + + // + // register SMM Ready To Lock Protocol notification + // + Status = gSmst->SmmRegisterProtocolNotify ( + &gEfiSmmReadyToLockProtocolGuid, + SmmReadyToLockEventNotify, + &Registration + ); + ASSERT_EFI_ERROR (Status); + + GuidHob = GetFirstGuidHob (&gEfiAcpiVariableGuid); + if (GuidHob != NULL) { + SmramDescriptor = (EFI_SMRAM_DESCRIPTOR *) GET_GUID_HOB_DATA (GuidHob); + + DEBUG ((EFI_D_INFO, "SMM S3 SMRAM Structure = %x\n", SmramDescriptor)); + DEBUG ((EFI_D_INFO, "SMM S3 Structure = %x\n", SmramDescriptor->CpuStart)); + + SmmS3ResumeState = (SMM_S3_RESUME_STATE *)(UINTN)SmramDescriptor->CpuStart; + ZeroMem (SmmS3ResumeState, sizeof (SMM_S3_RESUME_STATE)); + + mSmmS3ResumeState = SmmS3ResumeState; + SmmS3ResumeState->Smst = (EFI_PHYSICAL_ADDRESS)(UINTN)gSmst; + + SmmS3ResumeState->SmmS3ResumeEntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)SmmRestoreCpu; + + SmmS3ResumeState->SmmS3StackSize = SIZE_32KB; + SmmS3ResumeState->SmmS3StackBase = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocatePages (EFI_SIZE_TO_PAGES ((UINTN)SmmS3ResumeState->SmmS3StackSize)); + if (SmmS3ResumeState->SmmS3StackBase == 0) { + SmmS3ResumeState->SmmS3StackSize = 0; + } + + SmmS3ResumeState->SmmS3Cr0 = gSmmCr0; + SmmS3ResumeState->SmmS3Cr3 = Cr3; + SmmS3ResumeState->SmmS3Cr4 = gSmmCr4; + + if (sizeof (UINTN) == sizeof (UINT64)) { + SmmS3ResumeState->Signature = SMM_S3_RESUME_SMM_64; + } + if (sizeof (UINTN) == sizeof (UINT32)) { + SmmS3ResumeState->Signature = SMM_S3_RESUME_SMM_32; + } + } + + // + // Check XD and BTS features + // + CheckProcessorFeature (); + + // + // Initialize SMM Profile feature + // + InitSmmProfile (Cr3); + + // + // Patch SmmS3ResumeState->SmmS3Cr3 + // + InitSmmS3Cr3 (); + + DEBUG ((EFI_D_INFO, "SMM CPU Module exit from SMRAM with EFI_SUCCESS\n")); + + return EFI_SUCCESS; +} + +/** + + Find out SMRAM information including SMRR base and SMRR size. + + @param SmrrBase SMRR base + @param SmrrSize SMRR size + +**/ +VOID +FindSmramInfo ( + OUT UINT32 *SmrrBase, + OUT UINT32 *SmrrSize + ) +{ + EFI_STATUS Status; + UINTN Size; + EFI_SMM_ACCESS2_PROTOCOL *SmmAccess; + EFI_SMRAM_DESCRIPTOR *CurrentSmramRange; + EFI_SMRAM_DESCRIPTOR *SmramRanges; + UINTN SmramRangeCount; + UINTN Index; + UINT64 MaxSize; + BOOLEAN Found; + + // + // Get SMM Access Protocol + // + Status = gBS->LocateProtocol (&gEfiSmmAccess2ProtocolGuid, NULL, (VOID **)&SmmAccess); + ASSERT_EFI_ERROR (Status); + + // + // Get SMRAM information + // + Size = 0; + Status = SmmAccess->GetCapabilities (SmmAccess, &Size, NULL); + ASSERT (Status == EFI_BUFFER_TOO_SMALL); + + SmramRanges = (EFI_SMRAM_DESCRIPTOR *)AllocatePool (Size); + ASSERT (SmramRanges != NULL); + + Status = SmmAccess->GetCapabilities (SmmAccess, &Size, SmramRanges); + ASSERT_EFI_ERROR (Status); + + SmramRangeCount = Size / sizeof (EFI_SMRAM_DESCRIPTOR); + + // + // Find the largest SMRAM range between 1MB and 4GB that is at least 256K - 4K in size + // + CurrentSmramRange = NULL; + for (Index = 0, MaxSize = SIZE_256KB - EFI_PAGE_SIZE; Index < SmramRangeCount; Index++) { + // + // Skip any SMRAM region that is already allocated, needs testing, or needs ECC initialization + // + if ((SmramRanges[Index].RegionState & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) { + continue; + } + + if (SmramRanges[Index].CpuStart >= BASE_1MB) { + if ((SmramRanges[Index].CpuStart + SmramRanges[Index].PhysicalSize) <= BASE_4GB) { + if (SmramRanges[Index].PhysicalSize >= MaxSize) { + MaxSize = SmramRanges[Index].PhysicalSize; + CurrentSmramRange = &SmramRanges[Index]; + } + } + } + } + + ASSERT (CurrentSmramRange != NULL); + + *SmrrBase = (UINT32)CurrentSmramRange->CpuStart; + *SmrrSize = (UINT32)CurrentSmramRange->PhysicalSize; + + do { + Found = FALSE; + for (Index = 0; Index < SmramRangeCount; Index++) { + if (SmramRanges[Index].CpuStart < *SmrrBase && *SmrrBase == (SmramRanges[Index].CpuStart + SmramRanges[Index].PhysicalSize)) { + *SmrrBase = (UINT32)SmramRanges[Index].CpuStart; + *SmrrSize = (UINT32)(*SmrrSize + SmramRanges[Index].PhysicalSize); + Found = TRUE; + } else if ((*SmrrBase + *SmrrSize) == SmramRanges[Index].CpuStart && SmramRanges[Index].PhysicalSize > 0) { + *SmrrSize = (UINT32)(*SmrrSize + SmramRanges[Index].PhysicalSize); + Found = TRUE; + } + } + } while (Found); + + DEBUG ((EFI_D_INFO, "SMRR Base: 0x%x, SMRR Size: 0x%x\n", *SmrrBase, *SmrrSize)); +} + +/** +Configure SMM Code Access Check feature on an AP. +SMM Feature Control MSR will be locked after configuration. + +@param[in,out] Buffer Pointer to private data buffer. +**/ +VOID +EFIAPI +ConfigSmmCodeAccessCheckOnCurrentProcessor ( + IN OUT VOID *Buffer + ) +{ + UINTN CpuIndex; + UINT64 SmmFeatureControlMsr; + UINT64 NewSmmFeatureControlMsr; + + // + // Retrieve the CPU Index from the context passed in + // + CpuIndex = *(UINTN *)Buffer; + + // + // Get the current SMM Feature Control MSR value + // + SmmFeatureControlMsr = SmmCpuFeaturesGetSmmRegister (CpuIndex, SmmRegFeatureControl); + + // + // Compute the new SMM Feature Control MSR value + // + NewSmmFeatureControlMsr = SmmFeatureControlMsr; + if (mSmmCodeAccessCheckEnable) { + NewSmmFeatureControlMsr |= SMM_CODE_CHK_EN_BIT; + } + if (FeaturePcdGet (PcdCpuSmmFeatureControlMsrLock)) { + NewSmmFeatureControlMsr |= SMM_FEATURE_CONTROL_LOCK_BIT; + } + + // + // Only set the SMM Feature Control MSR value if the new value is different than the current value + // + if (NewSmmFeatureControlMsr != SmmFeatureControlMsr) { + SmmCpuFeaturesSetSmmRegister (CpuIndex, SmmRegFeatureControl, NewSmmFeatureControlMsr); + } + + // + // Release the spin lock user to serialize the updates to the SMM Feature Control MSR + // + ReleaseSpinLock (&mConfigSmmCodeAccessCheckLock); +} + +/** +Configure SMM Code Access Check feature for all processors. +SMM Feature Control MSR will be locked after configuration. +**/ +VOID +ConfigSmmCodeAccessCheck ( + VOID + ) +{ + UINTN Index; + EFI_STATUS Status; + + // + // Check to see if the Feature Control MSR is supported on this CPU + // + Index = gSmst->CurrentlyExecutingCpu; + if (!SmmCpuFeaturesIsSmmRegisterSupported (Index, SmmRegFeatureControl)) { + mSmmCodeAccessCheckEnable = FALSE; + return; + } + + // + // Check to see if the CPU supports the SMM Code Access Check feature + // Do not access this MSR unless the CPU supports the SmmRegFeatureControl + // + if ((AsmReadMsr64 (EFI_MSR_SMM_MCA_CAP) & SMM_CODE_ACCESS_CHK_BIT) == 0) { + mSmmCodeAccessCheckEnable = FALSE; + } + + // + // If the SMM Code Access Check feature is disabled and the Feature Control MSR + // is not being locked, then no additional work is required + // + if (!mSmmCodeAccessCheckEnable && !FeaturePcdGet (PcdCpuSmmFeatureControlMsrLock)) { + return; + } + + // + // Initialize the lock used to serialize the MSR programming in BSP and all APs + // + InitializeSpinLock (&mConfigSmmCodeAccessCheckLock); + + // + // Acquire Config SMM Code Access Check spin lock. The BSP will release the + // spin lock when it is done executing ConfigSmmCodeAccessCheckOnCurrentProcessor(). + // + AcquireSpinLock (&mConfigSmmCodeAccessCheckLock); + + // + // Enable SMM Code Access Check feature on the BSP. + // + ConfigSmmCodeAccessCheckOnCurrentProcessor (&Index); + + // + // Enable SMM Code Access Check feature for the APs. + // + for (Index = 0; Index < gSmst->NumberOfCpus; Index++) { + if (Index != gSmst->CurrentlyExecutingCpu) { + + // + // Acquire Config SMM Code Access Check spin lock. The AP will release the + // spin lock when it is done executing ConfigSmmCodeAccessCheckOnCurrentProcessor(). + // + AcquireSpinLock (&mConfigSmmCodeAccessCheckLock); + + // + // Call SmmStartupThisAp() to enable SMM Code Access Check on an AP. + // + Status = gSmst->SmmStartupThisAp (ConfigSmmCodeAccessCheckOnCurrentProcessor, Index, &Index); + ASSERT_EFI_ERROR (Status); + + // + // Wait for the AP to release the Config SMM Code Access Check spin lock. + // + while (!AcquireSpinLockOrFail (&mConfigSmmCodeAccessCheckLock)) { + CpuPause (); + } + + // + // Release the Config SMM Code Access Check spin lock. + // + ReleaseSpinLock (&mConfigSmmCodeAccessCheckLock); + } + } +} + +/** + Perform the remaining tasks. + +**/ +VOID +PerformRemainingTasks ( + VOID + ) +{ + if (mSmmReadyToLock) { + // + // Start SMM Profile feature + // + if (FeaturePcdGet (PcdCpuSmmProfileEnable)) { + SmmProfileStart (); + } + // + // Create a mix of 2MB and 4KB page table. Update some memory ranges absent and execute-disable. + // + InitPaging (); + // + // Configure SMM Code Access Check feature if available. + // + ConfigSmmCodeAccessCheck (); + + // + // Clean SMM ready to lock flag + // + mSmmReadyToLock = FALSE; + } +} diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h new file mode 100644 index 000000000000..9ea11894cdd5 --- /dev/null +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h @@ -0,0 +1,699 @@ +/** @file +Agent Module to load other modules to deploy SMM Entry Vector for X86 CPU. + +Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _CPU_PISMMCPUDXESMM_H_ +#define _CPU_PISMMCPUDXESMM_H_ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "CpuService.h" +#include "SmmProfile.h" + +// +// MSRs required for configuration of SMM Code Access Check +// +#define EFI_MSR_SMM_MCA_CAP 0x17D +#define SMM_CODE_ACCESS_CHK_BIT BIT58 + +#define SMM_FEATURE_CONTROL_LOCK_BIT BIT0 +#define SMM_CODE_CHK_EN_BIT BIT2 + +/// +/// Page Table Entry +/// +#define IA32_PG_P BIT0 +#define IA32_PG_RW BIT1 +#define IA32_PG_WT BIT3 +#define IA32_PG_CD BIT4 +#define IA32_PG_A BIT5 +#define IA32_PG_PS BIT7 +#define IA32_PG_PAT_2M BIT12 +#define IA32_PG_PAT_4K IA32_PG_PS +#define IA32_PG_PMNT BIT62 +#define IA32_PG_NX BIT63 + +// +// Size of Task-State Segment defined in IA32 Manual +// +#define TSS_SIZE 104 +#define TSS_X64_IST1_OFFSET 36 +#define TSS_IA32_CR3_OFFSET 28 +#define TSS_IA32_ESP_OFFSET 56 + +// +// Code select value +// +#define PROTECT_MODE_CODE_SEGMENT 0x08 +#define LONG_MODE_CODE_SEGMENT 0x38 + +// +// The size 0x20 must be bigger than +// the size of template code of SmmInit. Currently, +// the size of SmmInit requires the 0x16 Bytes buffer +// at least. +// +#define BACK_BUF_SIZE 0x20 + +#define EXCEPTION_VECTOR_NUMBER 0x20 + +#define INVALID_APIC_ID 0xFFFFFFFFFFFFFFFFULL + +typedef UINT32 SMM_CPU_ARRIVAL_EXCEPTIONS; +#define ARRIVAL_EXCEPTION_BLOCKED 0x1 +#define ARRIVAL_EXCEPTION_DELAYED 0x2 +#define ARRIVAL_EXCEPTION_SMI_DISABLED 0x4 + +// +// Private structure for the SMM CPU module that is stored in DXE Runtime memory +// Contains the SMM Configuration Protocols that is produced. +// Contains a mix of DXE and SMM contents. All the fields must be used properly. +// +#define SMM_CPU_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('s', 'c', 'p', 'u') + +typedef struct { + UINTN Signature; + + EFI_HANDLE SmmCpuHandle; + + EFI_PROCESSOR_INFORMATION *ProcessorInfo; + SMM_CPU_OPERATION *Operation; + UINTN *CpuSaveStateSize; + VOID **CpuSaveState; + + EFI_SMM_RESERVED_SMRAM_REGION SmmReservedSmramRegion[1]; + EFI_SMM_ENTRY_CONTEXT SmmCoreEntryContext; + EFI_SMM_ENTRY_POINT SmmCoreEntry; + + EFI_SMM_CONFIGURATION_PROTOCOL SmmConfiguration; +} SMM_CPU_PRIVATE_DATA; + +extern SMM_CPU_PRIVATE_DATA *gSmmCpuPrivate; +extern CPU_HOT_PLUG_DATA mCpuHotPlugData; +extern UINTN mMaxNumberOfCpus; +extern UINTN mNumberOfCpus; +extern BOOLEAN mRestoreSmmConfigurationInS3; +extern EFI_SMM_CPU_PROTOCOL mSmmCpu; + +/// +/// The mode of the CPU at the time an SMI occurs +/// +extern UINT8 mSmmSaveStateRegisterLma; + + +// +// SMM CPU Protocol function prototypes. +// + +/** + Read information from the CPU save state. + + @param This EFI_SMM_CPU_PROTOCOL instance + @param Width The number of bytes to read from the CPU save state. + @param Register Specifies the CPU register to read form the save state. + @param CpuIndex Specifies the zero-based index of the CPU save state + @param Buffer Upon return, this holds the CPU register value read from the save state. + + @retval EFI_SUCCESS The register was read from Save State + @retval EFI_NOT_FOUND The register is not defined for the Save State of Processor + @retval EFI_INVALID_PARAMTER This or Buffer is NULL. + +**/ +EFI_STATUS +EFIAPI +SmmReadSaveState ( + IN CONST EFI_SMM_CPU_PROTOCOL *This, + IN UINTN Width, + IN EFI_SMM_SAVE_STATE_REGISTER Register, + IN UINTN CpuIndex, + OUT VOID *Buffer + ); + +/** + Write data to the CPU save state. + + @param This EFI_SMM_CPU_PROTOCOL instance + @param Width The number of bytes to read from the CPU save state. + @param Register Specifies the CPU register to write to the save state. + @param CpuIndex Specifies the zero-based index of the CPU save state + @param Buffer Upon entry, this holds the new CPU register value. + + @retval EFI_SUCCESS The register was written from Save State + @retval EFI_NOT_FOUND The register is not defined for the Save State of Processor + @retval EFI_INVALID_PARAMTER ProcessorIndex or Width is not correct + +**/ +EFI_STATUS +EFIAPI +SmmWriteSaveState ( + IN CONST EFI_SMM_CPU_PROTOCOL *This, + IN UINTN Width, + IN EFI_SMM_SAVE_STATE_REGISTER Register, + IN UINTN CpuIndex, + IN CONST VOID *Buffer + ); + +/** +Read a CPU Save State register on the target processor. + +This function abstracts the differences that whether the CPU Save State register is in the +IA32 CPU Save State Map or X64 CPU Save State Map. + +This function supports reading a CPU Save State register in SMBase relocation handler. + +@param[in] CpuIndex Specifies the zero-based index of the CPU save state. +@param[in] RegisterIndex Index into mSmmCpuWidthOffset[] look up table. +@param[in] Width The number of bytes to read from the CPU save state. +@param[out] Buffer Upon return, this holds the CPU register value read from the save state. + +@retval EFI_SUCCESS The register was read from Save State. +@retval EFI_NOT_FOUND The register is not defined for the Save State of Processor. +@retval EFI_INVALID_PARAMTER This or Buffer is NULL. + +**/ +EFI_STATUS +EFIAPI +ReadSaveStateRegister ( + IN UINTN CpuIndex, + IN EFI_SMM_SAVE_STATE_REGISTER Register, + IN UINTN Width, + OUT VOID *Buffer + ); + +/** +Write value to a CPU Save State register on the target processor. + +This function abstracts the differences that whether the CPU Save State register is in the +IA32 CPU Save State Map or X64 CPU Save State Map. + +This function supports writing a CPU Save State register in SMBase relocation handler. + +@param[in] CpuIndex Specifies the zero-based index of the CPU save state. +@param[in] RegisterIndex Index into mSmmCpuWidthOffset[] look up table. +@param[in] Width The number of bytes to read from the CPU save state. +@param[in] Buffer Upon entry, this holds the new CPU register value. + +@retval EFI_SUCCESS The register was written to Save State. +@retval EFI_NOT_FOUND The register is not defined for the Save State of Processor. +@retval EFI_INVALID_PARAMTER ProcessorIndex or Width is not correct. + +**/ +EFI_STATUS +EFIAPI +WriteSaveStateRegister ( + IN UINTN CpuIndex, + IN EFI_SMM_SAVE_STATE_REGISTER Register, + IN UINTN Width, + IN CONST VOID *Buffer + ); + +// +// +// +typedef struct { + UINT32 Offset; + UINT16 Segment; + UINT16 Reserved; +} IA32_FAR_ADDRESS; + +extern IA32_FAR_ADDRESS gSmmJmpAddr; + +extern CONST UINT8 gcSmmInitTemplate[]; +extern CONST UINT16 gcSmmInitSize; +extern UINT32 gSmmCr0; +extern UINT32 gSmmCr3; +extern UINT32 gSmmCr4; +extern UINTN gSmmInitStack; + +/** + Semaphore operation for all processor relocate SMMBase. +**/ +VOID +EFIAPI +SmmRelocationSemaphoreComplete ( + VOID + ); + +/// +/// The type of SMM CPU Information +/// +typedef struct { + SPIN_LOCK Busy; + volatile EFI_AP_PROCEDURE Procedure; + volatile VOID *Parameter; + volatile UINT32 Run; + volatile BOOLEAN Present; +} SMM_CPU_DATA_BLOCK; + +typedef enum { + SmmCpuSyncModeTradition, + SmmCpuSyncModeRelaxedAp, + SmmCpuSyncModeMax +} SMM_CPU_SYNC_MODE; + +typedef struct { + // + // Pointer to an array. The array should be located immediately after this structure + // so that UC cache-ability can be set together. + // + SMM_CPU_DATA_BLOCK *CpuData; + volatile UINT32 Counter; + volatile UINT32 BspIndex; + volatile BOOLEAN InsideSmm; + volatile BOOLEAN AllCpusInSync; + volatile SMM_CPU_SYNC_MODE EffectiveSyncMode; + volatile BOOLEAN SwitchBsp; + volatile BOOLEAN *CandidateBsp; +} SMM_DISPATCHER_MP_SYNC_DATA; + +typedef struct { + SPIN_LOCK SpinLock; + UINT32 MsrIndex; +} MP_MSR_LOCK; + +#define SMM_PSD_OFFSET 0xfb00 + +typedef struct { + UINT64 Signature; // Offset 0x00 + UINT16 Reserved1; // Offset 0x08 + UINT16 Reserved2; // Offset 0x0A + UINT16 Reserved3; // Offset 0x0C + UINT16 SmmCs; // Offset 0x0E + UINT16 SmmDs; // Offset 0x10 + UINT16 SmmSs; // Offset 0x12 + UINT16 SmmOtherSegment; // Offset 0x14 + UINT16 Reserved4; // Offset 0x16 + UINT64 Reserved5; // Offset 0x18 + UINT64 Reserved6; // Offset 0x20 + UINT64 Reserved7; // Offset 0x28 + UINT64 SmmGdtPtr; // Offset 0x30 + UINT32 SmmGdtSize; // Offset 0x38 + UINT32 Reserved8; // Offset 0x3C + UINT64 Reserved9; // Offset 0x40 + UINT64 Reserved10; // Offset 0x48 + UINT16 Reserved11; // Offset 0x50 + UINT16 Reserved12; // Offset 0x52 + UINT32 Reserved13; // Offset 0x54 + UINT64 MtrrBaseMaskPtr; // Offset 0x58 +} PROCESSOR_SMM_DESCRIPTOR; + +extern IA32_DESCRIPTOR gcSmiGdtr; +extern IA32_DESCRIPTOR gcSmiIdtr; +extern VOID *gcSmiIdtrPtr; +extern CONST PROCESSOR_SMM_DESCRIPTOR gcPsd; +extern UINT64 gPhyMask; +extern ACPI_CPU_DATA mAcpiCpuData; +extern SMM_DISPATCHER_MP_SYNC_DATA *mSmmMpSyncData; +extern VOID *mGdtForAp; +extern VOID *mIdtForAp; +extern VOID *mMachineCheckHandlerForAp; +extern UINTN mSmmStackArrayBase; +extern UINTN mSmmStackArrayEnd; +extern UINTN mSmmStackSize; +extern EFI_SMM_CPU_SERVICE_PROTOCOL mSmmCpuService; +extern IA32_DESCRIPTOR gcSmiInitGdtr; + +/** + Create 4G PageTable in SMRAM. + + @param ExtraPages Additional page numbers besides for 4G memory + @return PageTable Address + +**/ +UINT32 +Gen4GPageTable ( + IN UINTN ExtraPages + ); + + +/** + Initialize global data for MP synchronization. + + @param Stacks Base address of SMI stack buffer for all processors. + @param StackSize Stack size for each processor in SMM. + +**/ +UINT32 +InitializeMpServiceData ( + IN VOID *Stacks, + IN UINTN StackSize + ); + +/** + Initialize Timer for SMM AP Sync. + +**/ +VOID +InitializeSmmTimer ( + VOID + ); + +/** + Start Timer for SMM AP Sync. + +**/ +UINT64 +EFIAPI +StartSyncTimer ( + VOID + ); + +/** + Check if the SMM AP Sync timer is timeout. + + @param Timer The start timer from the begin. + +**/ +BOOLEAN +EFIAPI +IsSyncTimerTimeout ( + IN UINT64 Timer + ); + +/** + Initialize IDT for SMM Stack Guard. + +**/ +VOID +EFIAPI +InitializeIDTSmmStackGuard ( + VOID + ); + +/** + + Register the SMM Foundation entry point. + + @param This Pointer to EFI_SMM_CONFIGURATION_PROTOCOL instance + @param SmmEntryPoint SMM Foundation EntryPoint + + @retval EFI_SUCCESS Successfully to register SMM foundation entry point + +**/ +EFI_STATUS +EFIAPI +RegisterSmmEntry ( + IN CONST EFI_SMM_CONFIGURATION_PROTOCOL *This, + IN EFI_SMM_ENTRY_POINT SmmEntryPoint + ); + +/** + Create PageTable for SMM use. + + @return PageTable Address + +**/ +UINT32 +SmmInitPageTable ( + VOID + ); + +/** + Schedule a procedure to run on the specified CPU. + + @param Procedure The address of the procedure to run + @param CpuIndex Target CPU number + @param ProcArguments The parameter to pass to the procedure + + @retval EFI_INVALID_PARAMETER CpuNumber not valid + @retval EFI_INVALID_PARAMETER CpuNumber specifying BSP + @retval EFI_INVALID_PARAMETER The AP specified by CpuNumber did not enter SMM + @retval EFI_INVALID_PARAMETER The AP specified by CpuNumber is busy + @retval EFI_SUCCESS - The procedure has been successfully scheduled + +**/ +EFI_STATUS +EFIAPI +SmmStartupThisAp ( + IN EFI_AP_PROCEDURE Procedure, + IN UINTN CpuIndex, + IN OUT VOID *ProcArguments OPTIONAL + ); + +/** + Schedule a procedure to run on the specified CPU in a blocking fashion. + + @param Procedure The address of the procedure to run + @param CpuIndex Target CPU Index + @param ProcArguments The parameter to pass to the procedure + + @retval EFI_INVALID_PARAMETER CpuNumber not valid + @retval EFI_INVALID_PARAMETER CpuNumber specifying BSP + @retval EFI_INVALID_PARAMETER The AP specified by CpuNumber did not enter SMM + @retval EFI_INVALID_PARAMETER The AP specified by CpuNumber is busy + @retval EFI_SUCCESS The procedure has been successfully scheduled + +**/ +EFI_STATUS +EFIAPI +SmmBlockingStartupThisAp ( + IN EFI_AP_PROCEDURE Procedure, + IN UINTN CpuIndex, + IN OUT VOID *ProcArguments OPTIONAL + ); + +/** + Initialize MP synchronization data. + +**/ +VOID +EFIAPI +InitializeMpSyncData ( + VOID + ); + +/** + + Find out SMRAM information including SMRR base and SMRR size. + + @param SmrrBase SMRR base + @param SmrrSize SMRR size + +**/ +VOID +FindSmramInfo ( + OUT UINT32 *SmrrBase, + OUT UINT32 *SmrrSize + ); + +/** + The function is invoked before SMBASE relocation in S3 path to restores CPU status. + + The function is invoked before SMBASE relocation in S3 path. It does first time microcode load + and restores MTRRs for both BSP and APs. + +**/ +VOID +EarlyInitializeCpu ( + VOID + ); + +/** + The function is invoked after SMBASE relocation in S3 path to restores CPU status. + + The function is invoked after SMBASE relocation in S3 path. It restores configuration according to + data saved by normal boot path for both BSP and APs. + +**/ +VOID +InitializeCpu ( + VOID + ); + +/** + Page Fault handler for SMM use. + + @param InterruptType Defines the type of interrupt or exception that + occurred on the processor.This parameter is processor architecture specific. + @param SystemContext A pointer to the processor context when + the interrupt occurred on the processor. +**/ +VOID +EFIAPI +SmiPFHandler ( + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_SYSTEM_CONTEXT SystemContext + ); + +/** + Perform the remaining tasks. + +**/ +VOID +PerformRemainingTasks ( + VOID + ); + +/** + Initialize MSR spin lock by MSR index. + + @param MsrIndex MSR index value. + +**/ +VOID +InitMsrSpinLockByIndex ( + IN UINT32 MsrIndex + ); + +/** + Hook return address of SMM Save State so that semaphore code + can be executed immediately after AP exits SMM to indicate to + the BSP that an AP has exited SMM after SMBASE relocation. + + @param[in] CpuIndex The processor index. + @param[in] RebasedFlag A pointer to a flag that is set to TRUE + immediately after AP exits SMM. + +**/ +VOID +SemaphoreHook ( + IN UINTN CpuIndex, + IN volatile BOOLEAN *RebasedFlag + ); + +/** +Configure SMM Code Access Check feature for all processors. +SMM Feature Control MSR will be locked after configuration. +**/ +VOID +ConfigSmmCodeAccessCheck ( + VOID + ); + +/** + Hook the code executed immediately after an RSM instruction on the currently + executing CPU. The mode of code executed immediately after RSM must be + detected, and the appropriate hook must be selected. Always clear the auto + HALT restart flag if it is set. + + @param[in] CpuIndex The processor index for the currently + executing CPU. + @param[in] CpuState Pointer to SMRAM Save State Map for the + currently executing CPU. + @param[in] NewInstructionPointer32 Instruction pointer to use if resuming to + 32-bit mode from 64-bit SMM. + @param[in] NewInstructionPointer Instruction pointer to use if resuming to + same mode as SMM. + + @retval The value of the original instruction pointer before it was hooked. + +**/ +UINT64 +EFIAPI +HookReturnFromSmm ( + IN UINTN CpuIndex, + SMRAM_SAVE_STATE_MAP *CpuState, + UINT64 NewInstructionPointer32, + UINT64 NewInstructionPointer + ); + +/** + Get the size of the SMI Handler in bytes. + + @retval The size, in bytes, of the SMI Handler. + +**/ +UINTN +EFIAPI +GetSmiHandlerSize ( + VOID + ); + +/** + Install the SMI handler for the CPU specified by CpuIndex. This function + is called by the CPU that was elected as monarch during System Management + Mode initialization. + + @param[in] CpuIndex The index of the CPU to install the custom SMI handler. + The value must be between 0 and the NumberOfCpus field + in the System Management System Table (SMST). + @param[in] SmBase The SMBASE address for the CPU specified by CpuIndex. + @param[in] SmiStack The stack to use when an SMI is processed by the + the CPU specified by CpuIndex. + @param[in] StackSize The size, in bytes, if the stack used when an SMI is + processed by the CPU specified by CpuIndex. + @param[in] GdtBase The base address of the GDT to use when an SMI is + processed by the CPU specified by CpuIndex. + @param[in] GdtSize The size, in bytes, of the GDT used when an SMI is + processed by the CPU specified by CpuIndex. + @param[in] IdtBase The base address of the IDT to use when an SMI is + processed by the CPU specified by CpuIndex. + @param[in] IdtSize The size, in bytes, of the IDT used when an SMI is + processed by the CPU specified by CpuIndex. + @param[in] Cr3 The base address of the page tables to use when an SMI + is processed by the CPU specified by CpuIndex. +**/ +VOID +EFIAPI +InstallSmiHandler ( + IN UINTN CpuIndex, + IN UINT32 SmBase, + IN VOID *SmiStack, + IN UINTN StackSize, + IN UINTN GdtBase, + IN UINTN GdtSize, + IN UINTN IdtBase, + IN UINTN IdtSize, + IN UINT32 Cr3 + ); + +/** + Search module name by input IP address and output it. + + @param CallerIpAddress Caller instruction pointer. + +**/ +VOID +DumpModuleInfoByIp ( + IN UINTN CallerIpAddress + ); +#endif diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf new file mode 100644 index 000000000000..45ab16c07f2b --- /dev/null +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf @@ -0,0 +1,163 @@ +## @file +# CPU SMM driver. +# +# This SMM driver performs SMM initialization, deploy SMM Entry Vector, +# provides CPU specific services in SMM. +# +# Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PiSmmCpuDxeSmm + MODULE_UNI_FILE = PiSmmCpuDxeSmm.uni + FILE_GUID = A3FF0EF5-0C28-42f5-B544-8C7DE1E80014 + MODULE_TYPE = DXE_SMM_DRIVER + VERSION_STRING = 1.0 + PI_SPECIFICATION_VERSION = 0x0001000A + ENTRY_POINT = PiCpuSmmEntry + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + PiSmmCpuDxeSmm.c + PiSmmCpuDxeSmm.h + MpService.c + SyncTimer.c + CpuS3.c + CpuService.c + CpuService.h + SmmProfile.c + SmmProfile.h + SmmProfileInternal.h + SmramSaveState.c + +[Sources.Ia32] + Ia32/Semaphore.c + Ia32/PageTbl.c + Ia32/SmmProfileArch.c + Ia32/SmmProfileArch.h + Ia32/SmmInit.asm | MSFT + Ia32/SmiEntry.asm | MSFT + Ia32/SmiException.asm | MSFT + Ia32/MpFuncs.asm | MSFT + + Ia32/SmmInit.asm | INTEL + Ia32/SmiEntry.asm | INTEL + Ia32/SmiException.asm | INTEL + Ia32/MpFuncs.asm | INTEL + + Ia32/SmmInit.S | GCC + Ia32/SmiEntry.S | GCC + Ia32/SmiException.S | GCC + Ia32/MpFuncs.S | GCC + +[Sources.X64] + X64/Semaphore.c + X64/PageTbl.c + X64/SmmProfileArch.c + X64/SmmProfileArch.h + X64/SmmInit.asm | MSFT + X64/SmiEntry.asm | MSFT + X64/SmiException.asm | MSFT + X64/MpFuncs.asm | MSFT + + X64/SmmInit.asm | INTEL + X64/SmiEntry.asm | INTEL + X64/SmiException.asm | INTEL + X64/MpFuncs.asm | INTEL + + X64/SmmInit.S | GCC + X64/SmiEntry.S | GCC + X64/SmiException.S | GCC + X64/MpFuncs.S | GCC + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + UefiCpuPkg/UefiCpuPkg.dec + IntelFrameworkPkg/IntelFrameworkPkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + UefiRuntimeServicesTableLib + CacheMaintenanceLib + PcdLib + DebugLib + BaseLib + SynchronizationLib + BaseMemoryLib + MtrrLib + SmmLib + IoLib + TimerLib + SmmServicesTableLib + MemoryAllocationLib + DebugAgentLib + HobLib + PciLib + LocalApicLib + UefiCpuLib + SmmCpuPlatformHookLib + CpuExceptionHandlerLib + UefiLib + DxeServicesTableLib + CpuLib + ReportStatusCodeLib + SmmCpuFeaturesLib + PeCoffGetEntryPointLib + +[Protocols] + gEfiSmmAccess2ProtocolGuid ## CONSUMES + gEfiMpServiceProtocolGuid ## CONSUMES + gEfiSmmConfigurationProtocolGuid ## PRODUCES + gEfiSmmCpuProtocolGuid ## PRODUCES + gEfiSmmReadyToLockProtocolGuid ## NOTIFY + gEfiSmmCpuServiceProtocolGuid ## PRODUCES + gEfiSmmCpuSaveStateProtocolGuid ## SOMETIMES_PRODUCES + +[Guids] + gEfiAcpiVariableGuid ## SOMETIMES_CONSUMES ## HOB # it is used for S3 boot. + gEfiGlobalVariableGuid ## SOMETIMES_PRODUCES ## Variable:L"SmmProfileData" + gEfiAcpi20TableGuid ## SOMETIMES_CONSUMES ## SystemTable + gEfiAcpi10TableGuid ## SOMETIMES_CONSUMES ## SystemTable + +[FeaturePcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdFrameworkCompatibilitySupport ## CONSUMES + gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmDebug ## CONSUMES + gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmBlockStartupThisAp ## CONSUMES + gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmEnableBspElection ## CONSUMES + gUefiCpuPkgTokenSpaceGuid.PcdCpuHotPlugSupport ## CONSUMES + gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmStackGuard ## CONSUMES + gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmProfileEnable ## CONSUMES + gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmProfileRingBuffer ## CONSUMES + gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmFeatureControlMsrLock ## CONSUMES + +[Pcd] + gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber ## SOMETIMES_CONSUMES + gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmProfileSize ## SOMETIMES_CONSUMES + gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmStackSize ## CONSUMES + gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmApSyncTimeout ## CONSUMES + gUefiCpuPkgTokenSpaceGuid.PcdCpuS3DataAddress ## SOMETIMES_CONSUMES + gUefiCpuPkgTokenSpaceGuid.PcdCpuHotPlugDataAddress ## SOMETIMES_PRODUCES + gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmCodeAccessCheckEnable ## CONSUMES + gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmSyncMode ## CONSUMES + +[Depex] + gEfiMpServiceProtocolGuid + +[UserExtensions.TianoCore."ExtraFiles"] + PiSmmCpuDxeSmmExtra.uni diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.uni b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.uni new file mode 100644 index 0000000000000000000000000000000000000000..6a5b8c972fe8c4b881826cee4b4a1253706a8fbe GIT binary patch literal 1868 zcmchYTW`}q5QXO%iT_}wFMyf^kaz$gMA90tfF{a?!c&zvmqsc{6sLjm7Sydg*Q85NS%28!QgZy}y_qup zo$U-ZLX;Yze-$fZt*nRe%zIIFiA;Si{u3;rMq>RPuRmGsDihRHw+^@G7h4U)X z0)Nf5v={y+s>g!5@?W{uHSd@y_T3m6J43jS=(=4?4U|jnT$6lOKJP4sRhvF)*;~ej zzwZf}MyRT}$8JKW^?8b2>AsyY$LyB~Wfc-SJI15y$St1K(Hbkv!WC+Tx#?@IZojwZ z*u|^m5hFXttK-bh*iS$eM$4mjSc$v#6tjn~d=xc!y}?(}zc9bYBIf$8#M>w#i`YIF zI3;?57H#@UF;Dk?_w)s=yROposOX&V1_kXdKxuKl4^nIwu#r|$wSiJSxE#8UsH5J5 zDYYLks`JzhRj|aeQhd?&eWxpTsa`f@79o^cc-IE#EOVD32zOy&>*4|@X zRN-+#hG*lLNw*STtLH_9 z2W*|x#HM^z^}q^6bL^6dueC1f_)`!wS!tz@l*l;wdR?0{>@dGR<5F{cbXv^#irx8c zQ#c4w9K2qtwPUVbPvLobE`do`@xLSD&q%DF$oikvxiVhOBU#g8eO727PWux@)k%BK z;-l;649lyl{M>0Bvj3bDZNlJG{T-eu+~;)Nc_akop10Jb9JQbC7Qw1dA0_sUZ_B#O zV>As=RpSV6Os9>pBB%7&dW;eN8lgUgn9h#K7&_zxOC7CmgHgCbZ7{aoT(gUcTVOwl zi&x?*YTlxfnDy|-pb8^#)d$SPT|U(uk)<3}^;uuZ)yiLtKZuCA{=}%L;&&0*O@&jV z$7s=~uT-;RVa2i5Pd8E1`Q>|2b&hTm-7V7YwotbZ%Anf8E!YXDWAGz#da&$bc^v&K z!ZkF3BFcj0Twcul4Wkc+?T9*X8lIjQ?ZGyRN=pbgDPh(WoBRU6OMes{0R^ Ch}L=l literal 0 HcmV?d00001 diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.c b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.c new file mode 100644 index 000000000000..8ddde9acb55c --- /dev/null +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.c @@ -0,0 +1,1443 @@ +/** @file +Enable SMM profile. + +Copyright (c) 2012 - 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "PiSmmCpuDxeSmm.h" +#include "SmmProfileInternal.h" + +UINT32 mSmmProfileCr3; + +SMM_PROFILE_HEADER *mSmmProfileBase; +MSR_DS_AREA_STRUCT *mMsrDsAreaBase; +// +// The buffer to store SMM profile data. +// +UINTN mSmmProfileSize; + +// +// The buffer to enable branch trace store. +// +UINTN mMsrDsAreaSize = SMM_PROFILE_DTS_SIZE; + +// +// The flag indicates if execute-disable is supported by processor. +// +BOOLEAN mXdSupported = FALSE; + +// +// The flag indicates if execute-disable is enabled on processor. +// +BOOLEAN mXdEnabled = FALSE; + +// +// The flag indicates if BTS is supported by processor. +// +BOOLEAN mBtsSupported = FALSE; + +// +// The flag indicates if SMM profile starts to record data. +// +BOOLEAN mSmmProfileStart = FALSE; + +// +// Record the page fault exception count for one instruction execution. +// +UINTN *mPFEntryCount; + +UINT64 (*mLastPFEntryValue)[MAX_PF_ENTRY_COUNT]; +UINT64 *(*mLastPFEntryPointer)[MAX_PF_ENTRY_COUNT]; + +MSR_DS_AREA_STRUCT **mMsrDsArea; +BRANCH_TRACE_RECORD **mMsrBTSRecord; +UINTN mBTSRecordNumber; +PEBS_RECORD **mMsrPEBSRecord; + +// +// These memory ranges are always present, they does not generate the access type of page fault exception, +// but they possibly generate instruction fetch type of page fault exception. +// +MEMORY_PROTECTION_RANGE *mProtectionMemRange = NULL; +UINTN mProtectionMemRangeCount = 0; + +// +// Some predefined memory ranges. +// +MEMORY_PROTECTION_RANGE mProtectionMemRangeTemplate[] = { + // + // SMRAM range (to be fixed in runtime). + // It is always present and instruction fetches are allowed. + // + {{0x00000000, 0x00000000},TRUE,FALSE}, + + // + // SMM profile data range( to be fixed in runtime). + // It is always present and instruction fetches are not allowed. + // + {{0x00000000, 0x00000000},TRUE,TRUE}, + + // + // Future extended range could be added here. + // + + // + // PCI MMIO ranges (to be added in runtime). + // They are always present and instruction fetches are not allowed. + // +}; + +// +// These memory ranges are mapped by 4KB-page instead of 2MB-page. +// +MEMORY_RANGE *mSplitMemRange = NULL; +UINTN mSplitMemRangeCount = 0; + +// +// SMI command port. +// +UINT32 mSmiCommandPort; + +/** + Disable branch trace store. + +**/ +VOID +DisableBTS ( + VOID + ) +{ + AsmMsrAnd64 (MSR_DEBUG_CTL, ~((UINT64)(MSR_DEBUG_CTL_BTS | MSR_DEBUG_CTL_TR))); +} + +/** + Enable branch trace store. + +**/ +VOID +EnableBTS ( + VOID + ) +{ + AsmMsrOr64 (MSR_DEBUG_CTL, (MSR_DEBUG_CTL_BTS | MSR_DEBUG_CTL_TR)); +} + +/** + Get CPU Index from APIC ID. + +**/ +UINTN +GetCpuIndex ( + VOID + ) +{ + UINTN Index; + UINT32 ApicId; + + ApicId = GetApicId (); + + for (Index = 0; Index < PcdGet32 (PcdCpuMaxLogicalProcessorNumber); Index++) { + if (gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId == ApicId) { + return Index; + } + } + ASSERT (FALSE); + return 0; +} + +/** + Get the source of IP after execute-disable exception is triggered. + + @param CpuIndex The index of CPU. + @param DestinationIP The destination address. + +**/ +UINT64 +GetSourceFromDestinationOnBts ( + UINTN CpuIndex, + UINT64 DestinationIP + ) +{ + BRANCH_TRACE_RECORD *CurrentBTSRecord; + UINTN Index; + BOOLEAN FirstMatch; + + FirstMatch = FALSE; + + CurrentBTSRecord = (BRANCH_TRACE_RECORD *)mMsrDsArea[CpuIndex]->BTSIndex; + for (Index = 0; Index < mBTSRecordNumber; Index++) { + if ((UINTN)CurrentBTSRecord < (UINTN)mMsrBTSRecord[CpuIndex]) { + // + // Underflow + // + CurrentBTSRecord = (BRANCH_TRACE_RECORD *)((UINTN)mMsrDsArea[CpuIndex]->BTSAbsoluteMaximum - 1); + CurrentBTSRecord --; + } + if (CurrentBTSRecord->LastBranchTo == DestinationIP) { + // + // Good! find 1st one, then find 2nd one. + // + if (!FirstMatch) { + // + // The first one is DEBUG exception + // + FirstMatch = TRUE; + } else { + // + // Good find proper one. + // + return CurrentBTSRecord->LastBranchFrom; + } + } + CurrentBTSRecord--; + } + + return 0; +} + +/** + SMM profile specific INT 1 (single-step) exception handler. + + @param InterruptType Defines the type of interrupt or exception that + occurred on the processor.This parameter is processor architecture specific. + @param SystemContext A pointer to the processor context when + the interrupt occurred on the processor. +**/ +VOID +EFIAPI +DebugExceptionHandler ( + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ + UINTN CpuIndex; + UINTN PFEntry; + + if (!mSmmProfileStart) { + return; + } + CpuIndex = GetCpuIndex (); + + // + // Clear last PF entries + // + for (PFEntry = 0; PFEntry < mPFEntryCount[CpuIndex]; PFEntry++) { + *mLastPFEntryPointer[CpuIndex][PFEntry] = mLastPFEntryValue[CpuIndex][PFEntry]; + } + + // + // Reset page fault exception count for next page fault. + // + mPFEntryCount[CpuIndex] = 0; + + // + // Flush TLB + // + CpuFlushTlb (); + + // + // Clear TF in EFLAGS + // + ClearTrapFlag (SystemContext); +} + +/** + Check if the memory address will be mapped by 4KB-page. + + @param Address The address of Memory. + @param Nx The flag indicates if the memory is execute-disable. + +**/ +BOOLEAN +IsAddressValid ( + IN EFI_PHYSICAL_ADDRESS Address, + IN BOOLEAN *Nx + ) +{ + UINTN Index; + + *Nx = FALSE; + if (FeaturePcdGet (PcdCpuSmmProfileEnable)) { + // + // Check configuration + // + for (Index = 0; Index < mProtectionMemRangeCount; Index++) { + if ((Address >= mProtectionMemRange[Index].Range.Base) && (Address < mProtectionMemRange[Index].Range.Top)) { + *Nx = mProtectionMemRange[Index].Nx; + return mProtectionMemRange[Index].Present; + } + } + *Nx = TRUE; + return FALSE; + + } else { + if ((Address < mCpuHotPlugData.SmrrBase) || + (Address >= mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize)) { + *Nx = TRUE; + } + return TRUE; + } +} + +/** + Check if the memory address will be mapped by 4KB-page. + + @param Address The address of Memory. + +**/ +BOOLEAN +IsAddressSplit ( + IN EFI_PHYSICAL_ADDRESS Address + ) +{ + UINTN Index; + + if (FeaturePcdGet (PcdCpuSmmProfileEnable)) { + // + // Check configuration + // + for (Index = 0; Index < mSplitMemRangeCount; Index++) { + if ((Address >= mSplitMemRange[Index].Base) && (Address < mSplitMemRange[Index].Top)) { + return TRUE; + } + } + } else { + if (Address < mCpuHotPlugData.SmrrBase) { + if ((mCpuHotPlugData.SmrrBase - Address) < BASE_2MB) { + return TRUE; + } + } else if (Address > (mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize - BASE_2MB)) { + if ((Address - (mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize - BASE_2MB)) < BASE_2MB) { + return TRUE; + } + } + } + // + // Return default + // + return FALSE; +} + +/** + Initialize the protected memory ranges and the 4KB-page mapped memory ranges. + +**/ +VOID +InitProtectedMemRange ( + VOID + ) +{ + UINTN Index; + UINTN NumberOfDescriptors; + UINTN NumberOfMmioDescriptors; + UINTN NumberOfProtectRange; + UINTN NumberOfSpliteRange; + EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap; + UINTN TotalSize; + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS ProtectBaseAddress; + EFI_PHYSICAL_ADDRESS ProtectEndAddress; + EFI_PHYSICAL_ADDRESS Top2MBAlignedAddress; + EFI_PHYSICAL_ADDRESS Base2MBAlignedAddress; + UINT64 High4KBPageSize; + UINT64 Low4KBPageSize; + + NumberOfDescriptors = 0; + NumberOfMmioDescriptors = 0; + NumberOfSpliteRange = 0; + MemorySpaceMap = NULL; + + // + // Get MMIO ranges from GCD and add them into protected memory ranges. + // + Status = gDS->GetMemorySpaceMap ( + &NumberOfDescriptors, + &MemorySpaceMap + ); + for (Index = 0; Index < NumberOfDescriptors; Index++) { + if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) { + NumberOfMmioDescriptors++; + } + } + + if (NumberOfMmioDescriptors != 0) { + TotalSize = NumberOfMmioDescriptors * sizeof (MEMORY_PROTECTION_RANGE) + sizeof (mProtectionMemRangeTemplate); + mProtectionMemRange = (MEMORY_PROTECTION_RANGE *) AllocateZeroPool (TotalSize); + ASSERT (mProtectionMemRange != NULL); + mProtectionMemRangeCount = TotalSize / sizeof (MEMORY_PROTECTION_RANGE); + + // + // Copy existing ranges. + // + CopyMem (mProtectionMemRange, mProtectionMemRangeTemplate, sizeof (mProtectionMemRangeTemplate)); + + // + // Create split ranges which come from protected ranges. + // + TotalSize = (TotalSize / sizeof (MEMORY_PROTECTION_RANGE)) * sizeof (MEMORY_RANGE); + mSplitMemRange = (MEMORY_RANGE *) AllocateZeroPool (TotalSize); + ASSERT (mSplitMemRange != NULL); + + // + // Create MMIO ranges which are set to present and execution-disable. + // + NumberOfProtectRange = sizeof (mProtectionMemRangeTemplate) / sizeof (MEMORY_PROTECTION_RANGE); + for (Index = 0; Index < NumberOfDescriptors; Index++) { + if (MemorySpaceMap[Index].GcdMemoryType != EfiGcdMemoryTypeMemoryMappedIo) { + continue; + } + mProtectionMemRange[NumberOfProtectRange].Range.Base = MemorySpaceMap[Index].BaseAddress; + mProtectionMemRange[NumberOfProtectRange].Range.Top = MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length; + mProtectionMemRange[NumberOfProtectRange].Present = TRUE; + mProtectionMemRange[NumberOfProtectRange].Nx = TRUE; + NumberOfProtectRange++; + } + } + + // + // According to protected ranges, create the ranges which will be mapped by 2KB page. + // + NumberOfSpliteRange = 0; + NumberOfProtectRange = mProtectionMemRangeCount; + for (Index = 0; Index < NumberOfProtectRange; Index++) { + // + // If MMIO base address is not 2MB alignment, make 2MB alignment for create 4KB page in page table. + // + ProtectBaseAddress = mProtectionMemRange[Index].Range.Base; + ProtectEndAddress = mProtectionMemRange[Index].Range.Top; + if (((ProtectBaseAddress & (SIZE_2MB - 1)) != 0) || ((ProtectEndAddress & (SIZE_2MB - 1)) != 0)) { + // + // Check if it is possible to create 4KB-page for not 2MB-aligned range and to create 2MB-page for 2MB-aligned range. + // A mix of 4KB and 2MB page could save SMRAM space. + // + Top2MBAlignedAddress = ProtectEndAddress & ~(SIZE_2MB - 1); + Base2MBAlignedAddress = (ProtectBaseAddress + SIZE_2MB - 1) & ~(SIZE_2MB - 1); + if ((Top2MBAlignedAddress > Base2MBAlignedAddress) && + ((Top2MBAlignedAddress - Base2MBAlignedAddress) >= SIZE_2MB)) { + // + // There is an range which could be mapped by 2MB-page. + // + High4KBPageSize = ((ProtectEndAddress + SIZE_2MB - 1) & ~(SIZE_2MB - 1)) - (ProtectEndAddress & ~(SIZE_2MB - 1)); + Low4KBPageSize = ((ProtectBaseAddress + SIZE_2MB - 1) & ~(SIZE_2MB - 1)) - (ProtectBaseAddress & ~(SIZE_2MB - 1)); + if (High4KBPageSize != 0) { + // + // Add not 2MB-aligned range to be mapped by 4KB-page. + // + mSplitMemRange[NumberOfSpliteRange].Base = ProtectEndAddress & ~(SIZE_2MB - 1); + mSplitMemRange[NumberOfSpliteRange].Top = (ProtectEndAddress + SIZE_2MB - 1) & ~(SIZE_2MB - 1); + NumberOfSpliteRange++; + } + if (Low4KBPageSize != 0) { + // + // Add not 2MB-aligned range to be mapped by 4KB-page. + // + mSplitMemRange[NumberOfSpliteRange].Base = ProtectBaseAddress & ~(SIZE_2MB - 1); + mSplitMemRange[NumberOfSpliteRange].Top = (ProtectBaseAddress + SIZE_2MB - 1) & ~(SIZE_2MB - 1); + NumberOfSpliteRange++; + } + } else { + // + // The range could only be mapped by 4KB-page. + // + mSplitMemRange[NumberOfSpliteRange].Base = ProtectBaseAddress & ~(SIZE_2MB - 1); + mSplitMemRange[NumberOfSpliteRange].Top = (ProtectEndAddress + SIZE_2MB - 1) & ~(SIZE_2MB - 1); + NumberOfSpliteRange++; + } + } + } + + mSplitMemRangeCount = NumberOfSpliteRange; + + DEBUG ((EFI_D_INFO, "SMM Profile Memory Ranges:\n")); + for (Index = 0; Index < mProtectionMemRangeCount; Index++) { + DEBUG ((EFI_D_INFO, "mProtectionMemRange[%d].Base = %lx\n", Index, mProtectionMemRange[Index].Range.Base)); + DEBUG ((EFI_D_INFO, "mProtectionMemRange[%d].Top = %lx\n", Index, mProtectionMemRange[Index].Range.Top)); + } + for (Index = 0; Index < mSplitMemRangeCount; Index++) { + DEBUG ((EFI_D_INFO, "mSplitMemRange[%d].Base = %lx\n", Index, mSplitMemRange[Index].Base)); + DEBUG ((EFI_D_INFO, "mSplitMemRange[%d].Top = %lx\n", Index, mSplitMemRange[Index].Top)); + } +} + +/** + Update page table according to protected memory ranges and the 4KB-page mapped memory ranges. + +**/ +VOID +InitPaging ( + VOID + ) +{ + UINT64 *Pml4; + UINT64 *Pde; + UINT64 *Pte; + UINT64 *Pt; + UINTN Address; + UINTN Level1; + UINTN Level2; + UINTN Level3; + UINTN Level4; + UINTN NumberOfPdpEntries; + UINTN NumberOfPml4Entries; + UINTN SizeOfMemorySpace; + BOOLEAN Nx; + + if (sizeof (UINTN) == sizeof (UINT64)) { + Pml4 = (UINT64*)(UINTN)mSmmProfileCr3; + SizeOfMemorySpace = HighBitSet64 (gPhyMask) + 1; + // + // Calculate the table entries of PML4E and PDPTE. + // + if (SizeOfMemorySpace <= 39 ) { + NumberOfPml4Entries = 1; + NumberOfPdpEntries = (UINT32)LShiftU64 (1, (SizeOfMemorySpace - 30)); + } else { + NumberOfPml4Entries = (UINT32)LShiftU64 (1, (SizeOfMemorySpace - 39)); + NumberOfPdpEntries = 512; + } + } else { + NumberOfPml4Entries = 1; + NumberOfPdpEntries = 4; + } + + // + // Go through page table and change 2MB-page into 4KB-page. + // + for (Level1 = 0; Level1 < NumberOfPml4Entries; Level1++) { + if (sizeof (UINTN) == sizeof (UINT64)) { + if ((Pml4[Level1] & IA32_PG_P) == 0) { + // + // If Pml4 entry does not exist, skip it + // + continue; + } + Pde = (UINT64 *)(UINTN)(Pml4[Level1] & PHYSICAL_ADDRESS_MASK); + } else { + Pde = (UINT64*)(UINTN)mSmmProfileCr3; + } + for (Level2 = 0; Level2 < NumberOfPdpEntries; Level2++, Pde++) { + if ((*Pde & IA32_PG_P) == 0) { + // + // If PDE entry does not exist, skip it + // + continue; + } + Pte = (UINT64 *)(UINTN)(*Pde & PHYSICAL_ADDRESS_MASK); + if (Pte == 0) { + continue; + } + for (Level3 = 0; Level3 < SIZE_4KB / sizeof (*Pte); Level3++, Pte++) { + if ((*Pte & IA32_PG_P) == 0) { + // + // If PTE entry does not exist, skip it + // + continue; + } + Address = (((Level2 << 9) + Level3) << 21); + + // + // If it is 2M page, check IsAddressSplit() + // + if (((*Pte & IA32_PG_PS) != 0) && IsAddressSplit (Address)) { + // + // Based on current page table, create 4KB page table for split area. + // + ASSERT (Address == (*Pte & PHYSICAL_ADDRESS_MASK)); + + Pt = AllocatePages (1); + ASSERT (Pt != NULL); + + // Split it + for (Level4 = 0; Level4 < SIZE_4KB / sizeof(*Pt); Level4++) { + Pt[Level4] = Address + ((Level4 << 12) | IA32_PG_RW | IA32_PG_P); + } // end for PT + *Pte = (UINTN)Pt | IA32_PG_RW | IA32_PG_P; + } // end if IsAddressSplit + } // end for PTE + } // end for PDE + } + + // + // Go through page table and set several page table entries to absent or execute-disable. + // + DEBUG ((EFI_D_INFO, "Patch page table start ...\n")); + for (Level1 = 0; Level1 < NumberOfPml4Entries; Level1++) { + if (sizeof (UINTN) == sizeof (UINT64)) { + if ((Pml4[Level1] & IA32_PG_P) == 0) { + // + // If Pml4 entry does not exist, skip it + // + continue; + } + Pde = (UINT64 *)(UINTN)(Pml4[Level1] & PHYSICAL_ADDRESS_MASK); + } else { + Pde = (UINT64*)(UINTN)mSmmProfileCr3; + } + for (Level2 = 0; Level2 < NumberOfPdpEntries; Level2++, Pde++) { + if ((*Pde & IA32_PG_P) == 0) { + // + // If PDE entry does not exist, skip it + // + continue; + } + Pte = (UINT64 *)(UINTN)(*Pde & PHYSICAL_ADDRESS_MASK); + if (Pte == 0) { + continue; + } + for (Level3 = 0; Level3 < SIZE_4KB / sizeof (*Pte); Level3++, Pte++) { + if ((*Pte & IA32_PG_P) == 0) { + // + // If PTE entry does not exist, skip it + // + continue; + } + Address = (((Level2 << 9) + Level3) << 21); + + if ((*Pte & IA32_PG_PS) != 0) { + // 2MB page + + if (!IsAddressValid (Address, &Nx)) { + // + // Patch to remove Present flag and RW flag + // + *Pte = *Pte & (INTN)(INT32)(~(IA32_PG_RW | IA32_PG_P)); + } + if (Nx && mXdSupported) { + *Pte = *Pte | IA32_PG_NX; + } + } else { + // 4KB page + Pt = (UINT64 *)(UINTN)(*Pte & PHYSICAL_ADDRESS_MASK); + if (Pt == 0) { + continue; + } + for (Level4 = 0; Level4 < SIZE_4KB / sizeof(*Pt); Level4++, Pt++) { + if (!IsAddressValid (Address, &Nx)) { + *Pt = *Pt & (INTN)(INT32)(~(IA32_PG_RW | IA32_PG_P)); + } + if (Nx && mXdSupported) { + *Pt = *Pt | IA32_PG_NX; + } + Address += SIZE_4KB; + } // end for PT + } // end if PS + } // end for PTE + } // end for PDE + } + + // + // Flush TLB + // + CpuFlushTlb (); + DEBUG ((EFI_D_INFO, "Patch page table done!\n")); + // + // Set execute-disable flag + // + mXdEnabled = TRUE; + + return ; +} + +/** + To find FADT in ACPI tables. + + @param AcpiTableGuid The GUID used to find ACPI table in UEFI ConfigurationTable. + + @return FADT table pointer. +**/ +EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE * +FindAcpiFadtTableByAcpiGuid ( + IN EFI_GUID *AcpiTableGuid + ) +{ + EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp; + EFI_ACPI_DESCRIPTION_HEADER *Rsdt; + EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *Fadt; + UINTN Index; + UINT32 Data32; + Rsdp = NULL; + Rsdt = NULL; + Fadt = NULL; + // + // found ACPI table RSD_PTR from system table + // + for (Index = 0; Index < gST->NumberOfTableEntries; Index++) { + if (CompareGuid (&(gST->ConfigurationTable[Index].VendorGuid), AcpiTableGuid)) { + // + // A match was found. + // + Rsdp = gST->ConfigurationTable[Index].VendorTable; + break; + } + } + + if (Rsdp == NULL) { + return NULL; + } + + Rsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN) Rsdp->RsdtAddress; + if (Rsdt == NULL || Rsdt->Signature != EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) { + return NULL; + } + + for (Index = sizeof (EFI_ACPI_DESCRIPTION_HEADER); Index < Rsdt->Length; Index = Index + sizeof (UINT32)) { + + Data32 = *(UINT32 *) ((UINT8 *) Rsdt + Index); + Fadt = (EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *) (UINT32 *) (UINTN) Data32; + if (Fadt->Header.Signature == EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE) { + break; + } + } + + if (Fadt == NULL || Fadt->Header.Signature != EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE) { + return NULL; + } + + return Fadt; +} + +/** + To find FADT in ACPI tables. + + @return FADT table pointer. +**/ +EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE * +FindAcpiFadtTable ( + VOID + ) +{ + EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *Fadt; + + Fadt = FindAcpiFadtTableByAcpiGuid (&gEfiAcpi20TableGuid); + if (Fadt != NULL) { + return Fadt; + } + + return FindAcpiFadtTableByAcpiGuid (&gEfiAcpi10TableGuid); +} + +/** + To get system port address of the SMI Command Port in FADT table. + +**/ +VOID +GetSmiCommandPort ( + VOID + ) +{ + EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *Fadt; + + Fadt = FindAcpiFadtTable (); + ASSERT (Fadt != NULL); + + mSmiCommandPort = Fadt->SmiCmd; + DEBUG ((EFI_D_INFO, "mSmiCommandPort = %x\n", mSmiCommandPort)); +} + +/** + Updates page table to make some memory ranges (like system memory) absent + and make some memory ranges (like MMIO) present and execute disable. It also + update 2MB-page to 4KB-page for some memory ranges. + +**/ +VOID +SmmProfileStart ( + VOID + ) +{ + // + // The flag indicates SMM profile starts to work. + // + mSmmProfileStart = TRUE; +} + +/** + Initialize SMM profile in SmmReadyToLock protocol callback function. + + @param Protocol Points to the protocol's unique identifier. + @param Interface Points to the interface instance. + @param Handle The handle on which the interface was installed. + + @retval EFI_SUCCESS SmmReadyToLock protocol callback runs successfully. +**/ +EFI_STATUS +EFIAPI +InitSmmProfileCallBack ( + IN CONST EFI_GUID *Protocol, + IN VOID *Interface, + IN EFI_HANDLE Handle + ) +{ + EFI_STATUS Status; + + // + // Save to variable so that SMM profile data can be found. + // + Status = gRT->SetVariable ( + SMM_PROFILE_NAME, + &gEfiCallerIdGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + sizeof(mSmmProfileBase), + &mSmmProfileBase + ); + + // + // Get Software SMI from FADT + // + GetSmiCommandPort (); + + // + // Initialize protected memory range for patching page table later. + // + InitProtectedMemRange (); + + return EFI_SUCCESS; +} + +/** + Initialize SMM profile data structures. + +**/ +VOID +InitSmmProfileInternal ( + VOID + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS Base; + VOID *Registration; + UINTN Index; + UINTN MsrDsAreaSizePerCpu; + UINTN TotalSize; + + mPFEntryCount = (UINTN *)AllocateZeroPool (sizeof (UINTN) * PcdGet32 (PcdCpuMaxLogicalProcessorNumber)); + ASSERT (mPFEntryCount != NULL); + mLastPFEntryValue = (UINT64 (*)[MAX_PF_ENTRY_COUNT])AllocateZeroPool ( + sizeof (mLastPFEntryValue[0]) * PcdGet32 (PcdCpuMaxLogicalProcessorNumber)); + ASSERT (mLastPFEntryValue != NULL); + mLastPFEntryPointer = (UINT64 *(*)[MAX_PF_ENTRY_COUNT])AllocateZeroPool ( + sizeof (mLastPFEntryPointer[0]) * PcdGet32 (PcdCpuMaxLogicalProcessorNumber)); + ASSERT (mLastPFEntryPointer != NULL); + + // + // Allocate memory for SmmProfile below 4GB. + // The base address + // + mSmmProfileSize = PcdGet32 (PcdCpuSmmProfileSize); + ASSERT ((mSmmProfileSize & 0xFFF) == 0); + + if (mBtsSupported) { + TotalSize = mSmmProfileSize + mMsrDsAreaSize; + } else { + TotalSize = mSmmProfileSize; + } + + Base = 0xFFFFFFFF; + Status = gBS->AllocatePages ( + AllocateMaxAddress, + EfiReservedMemoryType, + EFI_SIZE_TO_PAGES (TotalSize), + &Base + ); + ASSERT_EFI_ERROR (Status); + ZeroMem ((VOID *)(UINTN)Base, TotalSize); + mSmmProfileBase = (SMM_PROFILE_HEADER *)(UINTN)Base; + + // + // Initialize SMM profile data header. + // + mSmmProfileBase->HeaderSize = sizeof (SMM_PROFILE_HEADER); + mSmmProfileBase->MaxDataEntries = (UINT64)((mSmmProfileSize - sizeof(SMM_PROFILE_HEADER)) / sizeof (SMM_PROFILE_ENTRY)); + mSmmProfileBase->MaxDataSize = MultU64x64 (mSmmProfileBase->MaxDataEntries, sizeof(SMM_PROFILE_ENTRY)); + mSmmProfileBase->CurDataEntries = 0; + mSmmProfileBase->CurDataSize = 0; + mSmmProfileBase->TsegStart = mCpuHotPlugData.SmrrBase; + mSmmProfileBase->TsegSize = mCpuHotPlugData.SmrrSize; + mSmmProfileBase->NumSmis = 0; + mSmmProfileBase->NumCpus = gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus; + + if (mBtsSupported) { + mMsrDsArea = (MSR_DS_AREA_STRUCT **)AllocateZeroPool (sizeof (MSR_DS_AREA_STRUCT *) * PcdGet32 (PcdCpuMaxLogicalProcessorNumber)); + ASSERT (mMsrDsArea != NULL); + mMsrBTSRecord = (BRANCH_TRACE_RECORD **)AllocateZeroPool (sizeof (BRANCH_TRACE_RECORD *) * PcdGet32 (PcdCpuMaxLogicalProcessorNumber)); + ASSERT (mMsrBTSRecord != NULL); + mMsrPEBSRecord = (PEBS_RECORD **)AllocateZeroPool (sizeof (PEBS_RECORD *) * PcdGet32 (PcdCpuMaxLogicalProcessorNumber)); + ASSERT (mMsrPEBSRecord != NULL); + + mMsrDsAreaBase = (MSR_DS_AREA_STRUCT *)((UINTN)Base + mSmmProfileSize); + MsrDsAreaSizePerCpu = mMsrDsAreaSize / PcdGet32 (PcdCpuMaxLogicalProcessorNumber); + mBTSRecordNumber = (MsrDsAreaSizePerCpu - sizeof(PEBS_RECORD) * PEBS_RECORD_NUMBER - sizeof(MSR_DS_AREA_STRUCT)) / sizeof(BRANCH_TRACE_RECORD); + for (Index = 0; Index < PcdGet32 (PcdCpuMaxLogicalProcessorNumber); Index++) { + mMsrDsArea[Index] = (MSR_DS_AREA_STRUCT *)((UINTN)mMsrDsAreaBase + MsrDsAreaSizePerCpu * Index); + mMsrBTSRecord[Index] = (BRANCH_TRACE_RECORD *)((UINTN)mMsrDsArea[Index] + sizeof(MSR_DS_AREA_STRUCT)); + mMsrPEBSRecord[Index] = (PEBS_RECORD *)((UINTN)mMsrDsArea[Index] + MsrDsAreaSizePerCpu - sizeof(PEBS_RECORD) * PEBS_RECORD_NUMBER); + + mMsrDsArea[Index]->BTSBufferBase = (UINTN)mMsrBTSRecord[Index]; + mMsrDsArea[Index]->BTSIndex = mMsrDsArea[Index]->BTSBufferBase; + mMsrDsArea[Index]->BTSAbsoluteMaximum = mMsrDsArea[Index]->BTSBufferBase + mBTSRecordNumber * sizeof(BRANCH_TRACE_RECORD) + 1; + mMsrDsArea[Index]->BTSInterruptThreshold = mMsrDsArea[Index]->BTSAbsoluteMaximum + 1; + + mMsrDsArea[Index]->PEBSBufferBase = (UINTN)mMsrPEBSRecord[Index]; + mMsrDsArea[Index]->PEBSIndex = mMsrDsArea[Index]->PEBSBufferBase; + mMsrDsArea[Index]->PEBSAbsoluteMaximum = mMsrDsArea[Index]->PEBSBufferBase + PEBS_RECORD_NUMBER * sizeof(PEBS_RECORD) + 1; + mMsrDsArea[Index]->PEBSInterruptThreshold = mMsrDsArea[Index]->PEBSAbsoluteMaximum + 1; + } + } + + mProtectionMemRange = mProtectionMemRangeTemplate; + mProtectionMemRangeCount = sizeof (mProtectionMemRangeTemplate) / sizeof (MEMORY_PROTECTION_RANGE); + + // + // Update TSeg entry. + // + mProtectionMemRange[0].Range.Base = mCpuHotPlugData.SmrrBase; + mProtectionMemRange[0].Range.Top = mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize; + + // + // Update SMM profile entry. + // + mProtectionMemRange[1].Range.Base = (EFI_PHYSICAL_ADDRESS)(UINTN)mSmmProfileBase; + mProtectionMemRange[1].Range.Top = (EFI_PHYSICAL_ADDRESS)(UINTN)mSmmProfileBase + TotalSize; + + // + // Allocate memory reserved for creating 4KB pages. + // + InitPagesForPFHandler (); + + // + // Start SMM profile when SmmReadyToLock protocol is installed. + // + Status = gSmst->SmmRegisterProtocolNotify ( + &gEfiSmmReadyToLockProtocolGuid, + InitSmmProfileCallBack, + &Registration + ); + ASSERT_EFI_ERROR (Status); + + return ; +} + +/** + Check if XD feature is supported by a processor. + +**/ +VOID +CheckFeatureSupported ( + VOID + ) +{ + UINT32 RegEax; + UINT32 RegEdx; + + if (mXdSupported) { + AsmCpuid (CPUID_EXTENDED_FUNCTION, &RegEax, NULL, NULL, NULL); + if (RegEax <= CPUID_EXTENDED_FUNCTION) { + // + // Extended CPUID functions are not supported on this processor. + // + mXdSupported = FALSE; + } + + AsmCpuid (CPUID_EXTENDED_CPU_SIG, NULL, NULL, NULL, &RegEdx); + if ((RegEdx & CPUID1_EDX_XD_SUPPORT) == 0) { + // + // Execute Disable Bit feature is not supported on this processor. + // + mXdSupported = FALSE; + } + } + + if (mBtsSupported) { + AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &RegEdx); + if ((RegEdx & CPUID1_EDX_BTS_AVAILABLE) != 0) { + // + // Per IA32 manuals: + // When CPUID.1:EDX[21] is set, the following BTS facilities are available: + // 1. The BTS_UNAVAILABLE flag in the IA32_MISC_ENABLE MSR indicates the + // availability of the BTS facilities, including the ability to set the BTS and + // BTINT bits in the MSR_DEBUGCTLA MSR. + // 2. The IA32_DS_AREA MSR can be programmed to point to the DS save area. + // + if ((AsmMsrBitFieldRead64 (MSR_IA32_MISC_ENABLE, 11, 11) == 0) && + (AsmMsrBitFieldRead64 (MSR_IA32_MISC_ENABLE, 12, 12) == 0)) { + // + // BTS facilities is supported. + // + mBtsSupported = FALSE; + } + } + } +} + +/** + Check if XD and BTS features are supported by all processors. + +**/ +VOID +CheckProcessorFeature ( + VOID + ) +{ + EFI_STATUS Status; + EFI_MP_SERVICES_PROTOCOL *MpServices; + + Status = gBS->LocateProtocol (&gEfiMpServiceProtocolGuid, NULL, (VOID **)&MpServices); + ASSERT_EFI_ERROR (Status); + + // + // First detect if XD and BTS are supported + // + mXdSupported = TRUE; + mBtsSupported = TRUE; + + // + // Check if XD and BTS are supported on all processors. + // + CheckFeatureSupported (); + + // + //Check on other processors if BSP supports this + // + if (mXdSupported || mBtsSupported) { + MpServices->StartupAllAPs ( + MpServices, + (EFI_AP_PROCEDURE) CheckFeatureSupported, + TRUE, + NULL, + 0, + NULL, + NULL + ); + } +} + +/** + Enable XD feature. + +**/ +VOID +ActivateXd ( + VOID + ) +{ + UINT64 MsrRegisters; + + MsrRegisters = AsmReadMsr64 (MSR_EFER); + if ((MsrRegisters & MSR_EFER_XD) != 0) { + return ; + } + MsrRegisters |= MSR_EFER_XD; + AsmWriteMsr64 (MSR_EFER, MsrRegisters); +} + +/** + Enable single step. + +**/ +VOID +ActivateSingleStepDB ( + VOID + ) +{ + UINTN Dr6; + + Dr6 = AsmReadDr6 (); + if ((Dr6 & DR6_SINGLE_STEP) != 0) { + return; + } + Dr6 |= DR6_SINGLE_STEP; + AsmWriteDr6 (Dr6); +} + +/** + Enable last branch. + +**/ +VOID +ActivateLBR ( + VOID + ) +{ + UINT64 DebugCtl; + + DebugCtl = AsmReadMsr64 (MSR_DEBUG_CTL); + if ((DebugCtl & MSR_DEBUG_CTL_LBR) != 0) { + return ; + } + AsmWriteMsr64 (MSR_LER_FROM_LIP, 0); + AsmWriteMsr64 (MSR_LER_TO_LIP, 0); + DebugCtl |= MSR_DEBUG_CTL_LBR; + AsmWriteMsr64 (MSR_DEBUG_CTL, DebugCtl); +} + +/** + Enable branch trace store. + + @param CpuIndex The index of the processor. + +**/ +VOID +ActivateBTS ( + IN UINTN CpuIndex + ) +{ + UINT64 DebugCtl; + + DebugCtl = AsmReadMsr64 (MSR_DEBUG_CTL); + if ((DebugCtl & MSR_DEBUG_CTL_BTS) != 0) { + return ; + } + + AsmWriteMsr64 (MSR_DS_AREA, (UINT64)(UINTN)mMsrDsArea[CpuIndex]); + DebugCtl |= (UINT64)(MSR_DEBUG_CTL_BTS | MSR_DEBUG_CTL_TR); + DebugCtl &= ~((UINT64)MSR_DEBUG_CTL_BTINT); + AsmWriteMsr64 (MSR_DEBUG_CTL, DebugCtl); +} + +/** + Increase SMI number in each SMI entry. + +**/ +VOID +SmmProfileRecordSmiNum ( + VOID + ) +{ + if (mSmmProfileStart) { + mSmmProfileBase->NumSmis++; + } +} + +/** + Initialize processor environment for SMM profile. + + @param CpuIndex The index of the processor. + +**/ +VOID +ActivateSmmProfile ( + IN UINTN CpuIndex + ) +{ + // + // Enable Single Step DB# + // + ActivateSingleStepDB (); + + if (mBtsSupported) { + // + // We can not get useful information from LER, so we have to use BTS. + // + ActivateLBR (); + + // + // Enable BTS + // + ActivateBTS (CpuIndex); + } +} + +/** + Initialize SMM profile in SMM CPU entry point. + + @param[in] Cr3 The base address of the page tables to use in SMM. + +**/ +VOID +InitSmmProfile ( + UINT32 Cr3 + ) +{ + // + // Save Cr3 + // + mSmmProfileCr3 = Cr3; + + // + // Skip SMM profile initialization if feature is disabled + // + if (!FeaturePcdGet (PcdCpuSmmProfileEnable)) { + return; + } + + // + // Initialize SmmProfile here + // + InitSmmProfileInternal (); + + // + // Initialize profile IDT. + // + InitIdtr (); +} + +/** + Update page table to map the memory correctly in order to make the instruction + which caused page fault execute successfully. And it also save the original page + table to be restored in single-step exception. + + @param PageTable PageTable Address. + @param PFAddress The memory address which caused page fault exception. + @param CpuIndex The index of the processor. + @param ErrorCode The Error code of exception. + +**/ +VOID +RestorePageTableBelow4G ( + UINT64 *PageTable, + UINT64 PFAddress, + UINTN CpuIndex, + UINTN ErrorCode + ) +{ + UINTN PTIndex; + UINTN PFIndex; + + // + // PML4 + // + if (sizeof(UINT64) == sizeof(UINTN)) { + PTIndex = (UINTN)BitFieldRead64 (PFAddress, 39, 47); + ASSERT (PageTable[PTIndex] != 0); + PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & PHYSICAL_ADDRESS_MASK); + } + + // + // PDPTE + // + PTIndex = (UINTN)BitFieldRead64 (PFAddress, 30, 38); + ASSERT (PageTable[PTIndex] != 0); + PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & PHYSICAL_ADDRESS_MASK); + + // + // PD + // + PTIndex = (UINTN)BitFieldRead64 (PFAddress, 21, 29); + if ((PageTable[PTIndex] & IA32_PG_PS) != 0) { + // + // Large page + // + + // + // Record old entries with non-present status + // Old entries include the memory which instruction is at and the memory which instruction access. + // + // + ASSERT (mPFEntryCount[CpuIndex] < MAX_PF_ENTRY_COUNT); + if (mPFEntryCount[CpuIndex] < MAX_PF_ENTRY_COUNT) { + PFIndex = mPFEntryCount[CpuIndex]; + mLastPFEntryValue[CpuIndex][PFIndex] = PageTable[PTIndex]; + mLastPFEntryPointer[CpuIndex][PFIndex] = &PageTable[PTIndex]; + mPFEntryCount[CpuIndex]++; + } + + // + // Set new entry + // + PageTable[PTIndex] = (PFAddress & ~((1ull << 21) - 1)); + PageTable[PTIndex] |= (UINT64)IA32_PG_PS; + PageTable[PTIndex] |= (UINT64)(IA32_PG_RW | IA32_PG_P); + if ((ErrorCode & IA32_PF_EC_ID) != 0) { + PageTable[PTIndex] &= ~IA32_PG_NX; + } + } else { + // + // Small page + // + ASSERT (PageTable[PTIndex] != 0); + PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & PHYSICAL_ADDRESS_MASK); + + // + // 4K PTE + // + PTIndex = (UINTN)BitFieldRead64 (PFAddress, 12, 20); + + // + // Record old entries with non-present status + // Old entries include the memory which instruction is at and the memory which instruction access. + // + // + ASSERT (mPFEntryCount[CpuIndex] < MAX_PF_ENTRY_COUNT); + if (mPFEntryCount[CpuIndex] < MAX_PF_ENTRY_COUNT) { + PFIndex = mPFEntryCount[CpuIndex]; + mLastPFEntryValue[CpuIndex][PFIndex] = PageTable[PTIndex]; + mLastPFEntryPointer[CpuIndex][PFIndex] = &PageTable[PTIndex]; + mPFEntryCount[CpuIndex]++; + } + + // + // Set new entry + // + PageTable[PTIndex] = (PFAddress & ~((1ull << 12) - 1)); + PageTable[PTIndex] |= (UINT64)(IA32_PG_RW | IA32_PG_P); + if ((ErrorCode & IA32_PF_EC_ID) != 0) { + PageTable[PTIndex] &= ~IA32_PG_NX; + } + } +} + +/** + The Page fault handler to save SMM profile data. + + @param Rip The RIP when exception happens. + @param ErrorCode The Error code of exception. + +**/ +VOID +SmmProfilePFHandler ( + UINTN Rip, + UINTN ErrorCode + ) +{ + UINT64 *PageTable; + UINT64 PFAddress; + UINTN CpuIndex; + UINTN Index; + UINT64 InstructionAddress; + UINTN MaxEntryNumber; + UINTN CurrentEntryNumber; + BOOLEAN IsValidPFAddress; + SMM_PROFILE_ENTRY *SmmProfileEntry; + UINT64 SmiCommand; + EFI_STATUS Status; + UINTN SwSmiCpuIndex; + UINT8 SoftSmiValue; + EFI_SMM_SAVE_STATE_IO_INFO IoInfo; + + if (!mSmmProfileStart) { + // + // If SMM profile does not start, call original page fault handler. + // + SmiDefaultPFHandler (); + return; + } + + if (mBtsSupported) { + DisableBTS (); + } + + IsValidPFAddress = FALSE; + PageTable = (UINT64 *)AsmReadCr3 (); + PFAddress = AsmReadCr2 (); + CpuIndex = GetCpuIndex (); + + if (PFAddress <= 0xFFFFFFFF) { + RestorePageTableBelow4G (PageTable, PFAddress, CpuIndex, ErrorCode); + } else { + RestorePageTableAbove4G (PageTable, PFAddress, CpuIndex, ErrorCode, &IsValidPFAddress); + } + + if (!IsValidPFAddress) { + InstructionAddress = Rip; + if ((ErrorCode & IA32_PF_EC_ID) != 0 && (mBtsSupported)) { + // + // If it is instruction fetch failure, get the correct IP from BTS. + // + InstructionAddress = GetSourceFromDestinationOnBts (CpuIndex, Rip); + if (InstructionAddress == 0) { + // + // It indicates the instruction which caused page fault is not a jump instruction, + // set instruction address same as the page fault address. + // + InstructionAddress = PFAddress; + } + } + + // + // Try to find which CPU trigger SWSMI + // + SwSmiCpuIndex = 0; + // + // Indicate it is not software SMI + // + SmiCommand = 0xFFFFFFFFFFFFFFFFULL; + for (Index = 0; Index < gSmst->NumberOfCpus; Index++) { + Status = SmmReadSaveState(&mSmmCpu, sizeof(IoInfo), EFI_SMM_SAVE_STATE_REGISTER_IO, Index, &IoInfo); + if (EFI_ERROR (Status)) { + continue; + } + if (IoInfo.IoPort == mSmiCommandPort) { + // + // Great! Find it. + // + SwSmiCpuIndex = Index; + // + // A software SMI triggered by SMI command port has been found, get SmiCommand from SMI command port. + // + SoftSmiValue = IoRead8 (mSmiCommandPort); + SmiCommand = (UINT64)SoftSmiValue; + break; + } + } + + SmmProfileEntry = (SMM_PROFILE_ENTRY *)(UINTN)(mSmmProfileBase + 1); + // + // Check if there is already a same entry in profile data. + // + for (Index = 0; Index < (UINTN) mSmmProfileBase->CurDataEntries; Index++) { + if ((SmmProfileEntry[Index].ErrorCode == (UINT64)ErrorCode) && + (SmmProfileEntry[Index].Address == PFAddress) && + (SmmProfileEntry[Index].CpuNum == (UINT64)CpuIndex) && + (SmmProfileEntry[Index].Instruction == InstructionAddress) && + (SmmProfileEntry[Index].SmiCmd == SmiCommand)) { + // + // Same record exist, need not save again. + // + break; + } + } + if (Index == mSmmProfileBase->CurDataEntries) { + CurrentEntryNumber = (UINTN) mSmmProfileBase->CurDataEntries; + MaxEntryNumber = (UINTN) mSmmProfileBase->MaxDataEntries; + if (FeaturePcdGet (PcdCpuSmmProfileRingBuffer)) { + CurrentEntryNumber = CurrentEntryNumber % MaxEntryNumber; + } + if (CurrentEntryNumber < MaxEntryNumber) { + // + // Log the new entry + // + SmmProfileEntry[CurrentEntryNumber].SmiNum = mSmmProfileBase->NumSmis; + SmmProfileEntry[CurrentEntryNumber].ErrorCode = (UINT64)ErrorCode; + SmmProfileEntry[CurrentEntryNumber].ApicId = (UINT64)GetApicId (); + SmmProfileEntry[CurrentEntryNumber].CpuNum = (UINT64)CpuIndex; + SmmProfileEntry[CurrentEntryNumber].Address = PFAddress; + SmmProfileEntry[CurrentEntryNumber].Instruction = InstructionAddress; + SmmProfileEntry[CurrentEntryNumber].SmiCmd = SmiCommand; + // + // Update current entry index and data size in the header. + // + mSmmProfileBase->CurDataEntries++; + mSmmProfileBase->CurDataSize = MultU64x64 (mSmmProfileBase->CurDataEntries, sizeof (SMM_PROFILE_ENTRY)); + } + } + } + // + // Flush TLB + // + CpuFlushTlb (); + + if (mBtsSupported) { + EnableBTS (); + } +} + +/** + Replace INT1 exception handler to restore page table to absent/execute-disable state + in order to trigger page fault again to save SMM profile data.. + +**/ +VOID +InitIdtr ( + VOID + ) +{ + SmmRegisterExceptionHandler (&mSmmCpuService, EXCEPT_IA32_DEBUG, DebugExceptionHandler); +} diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.h b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.h new file mode 100644 index 000000000000..45484674589d --- /dev/null +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.h @@ -0,0 +1,134 @@ +/** @file +SMM profile header file. + +Copyright (c) 2012 - 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _SMM_PROFILE_H_ +#define _SMM_PROFILE_H_ + +#include "SmmProfileInternal.h" + +/// +/// MSR Register Index +/// +#define MSR_IA32_MISC_ENABLE 0x1A0 + +// +// External functions +// + +/** + Initialize processor environment for SMM profile. + + @param CpuIndex The index of the processor. + +**/ +VOID +ActivateSmmProfile ( + IN UINTN CpuIndex + ); + +/** + Initialize SMM profile in SMM CPU entry point. + + @param[in] Cr3 The base address of the page tables to use in SMM. + +**/ +VOID +InitSmmProfile ( + UINT32 Cr3 + ); + +/** + Increase SMI number in each SMI entry. + +**/ +VOID +SmmProfileRecordSmiNum ( + VOID + ); + +/** + The Page fault handler to save SMM profile data. + + @param Rip The RIP when exception happens. + @param ErrorCode The Error code of exception. + +**/ +VOID +SmmProfilePFHandler ( + UINTN Rip, + UINTN ErrorCode + ); + +/** + Updates page table to make some memory ranges (like system memory) absent + and make some memory ranges (like MMIO) present and execute disable. It also + update 2MB-page to 4KB-page for some memory ranges. + +**/ +VOID +SmmProfileStart ( + VOID + ); + +/** + Page fault IDT handler for SMM Profile. + +**/ +VOID +EFIAPI +PageFaultIdtHandlerSmmProfile ( + VOID + ); + + +/** + Check if XD feature is supported by a processor. + +**/ +VOID +CheckFeatureSupported ( + VOID + ); + +/** + Enable XD feature. + +**/ +VOID +ActivateXd ( + VOID + ); + +/** + Update page table according to protected memory ranges and the 4KB-page mapped memory ranges. + +**/ +VOID +InitPaging ( + VOID + ); + +/** + Check if XD and BTS features are supported by all processors. + +**/ +VOID +CheckProcessorFeature ( + VOID + ); + +extern BOOLEAN mXdSupported; +extern BOOLEAN mXdEnabled; + +#endif // _SMM_PROFILE_H_ diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfileInternal.h b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfileInternal.h new file mode 100644 index 000000000000..de6eb0aceb9c --- /dev/null +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfileInternal.h @@ -0,0 +1,172 @@ +/** @file +SMM profile internal header file. + +Copyright (c) 2012 - 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _SMM_PROFILE_INTERNAL_H_ +#define _SMM_PROFILE_INTERNAL_H_ + +#include +#include +#include +#include +#include +#include +#include + +#include "SmmProfileArch.h" + +// +// Configure the SMM_PROFILE DTS region size +// +#define SMM_PROFILE_DTS_SIZE (4 * 1024 * 1024) // 4M + +#define MAX_PF_PAGE_COUNT 0x2 + +#define PEBS_RECORD_NUMBER 0x2 + +#define MAX_PF_ENTRY_COUNT 10 + +// +// This MACRO just enable unit test for the profile +// Please disable it. +// + +#define IA32_PF_EC_P (1u << 0) +#define IA32_PF_EC_WR (1u << 1) +#define IA32_PF_EC_US (1u << 2) +#define IA32_PF_EC_RSVD (1u << 3) +#define IA32_PF_EC_ID (1u << 4) + +#define SMM_PROFILE_NAME L"SmmProfileData" + +// +// CPU generic definition +// +#define CPUID1_EDX_XD_SUPPORT 0x100000 +#define MSR_EFER 0xc0000080 +#define MSR_EFER_XD 0x800 + +#define CPUID1_EDX_BTS_AVAILABLE 0x200000 + +#define DR6_SINGLE_STEP 0x4000 +#define RFLAG_TF 0x100 + +#define MSR_DEBUG_CTL 0x1D9 +#define MSR_DEBUG_CTL_LBR 0x1 +#define MSR_DEBUG_CTL_TR 0x40 +#define MSR_DEBUG_CTL_BTS 0x80 +#define MSR_DEBUG_CTL_BTINT 0x100 +#define MSR_LASTBRANCH_TOS 0x1C9 +#define MSR_LER_FROM_LIP 0x1DD +#define MSR_LER_TO_LIP 0x1DE +#define MSR_DS_AREA 0x600 + +typedef struct { + EFI_PHYSICAL_ADDRESS Base; + EFI_PHYSICAL_ADDRESS Top; +} MEMORY_RANGE; + +typedef struct { + MEMORY_RANGE Range; + BOOLEAN Present; + BOOLEAN Nx; +} MEMORY_PROTECTION_RANGE; + +typedef struct { + UINT64 HeaderSize; + UINT64 MaxDataEntries; + UINT64 MaxDataSize; + UINT64 CurDataEntries; + UINT64 CurDataSize; + UINT64 TsegStart; + UINT64 TsegSize; + UINT64 NumSmis; + UINT64 NumCpus; +} SMM_PROFILE_HEADER; + +typedef struct { + UINT64 SmiNum; + UINT64 CpuNum; + UINT64 ApicId; + UINT64 ErrorCode; + UINT64 Instruction; + UINT64 Address; + UINT64 SmiCmd; +} SMM_PROFILE_ENTRY; + +extern SMM_S3_RESUME_STATE *mSmmS3ResumeState; +extern UINTN gSmiExceptionHandlers[]; +extern BOOLEAN mXdSupported; +extern UINTN *mPFEntryCount; +extern UINT64 (*mLastPFEntryValue)[MAX_PF_ENTRY_COUNT]; +extern UINT64 *(*mLastPFEntryPointer)[MAX_PF_ENTRY_COUNT]; + +// +// Internal functions +// + +/** + Update IDT table to replace page fault handler and INT 1 handler. + +**/ +VOID +InitIdtr ( + VOID + ); + +/** + Check if the memory address will be mapped by 4KB-page. + + @param Address The address of Memory. + +**/ +BOOLEAN +IsAddressSplit ( + IN EFI_PHYSICAL_ADDRESS Address + ); + +/** + Check if the memory address will be mapped by 4KB-page. + + @param Address The address of Memory. + @param Nx The flag indicates if the memory is execute-disable. + +**/ +BOOLEAN +IsAddressValid ( + IN EFI_PHYSICAL_ADDRESS Address, + IN BOOLEAN *Nx + ); + +/** + Page Fault handler for SMM use. + +**/ +VOID +SmiDefaultPFHandler ( + VOID + ); + +/** + Clear TF in FLAGS. + + @param SystemContext A pointer to the processor context when + the interrupt occurred on the processor. + +**/ +VOID +ClearTrapFlag ( + IN OUT EFI_SYSTEM_CONTEXT SystemContext + ); + +#endif // _SMM_PROFILE_H_ diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/SmramSaveState.c b/UefiCpuPkg/PiSmmCpuDxeSmm/SmramSaveState.c new file mode 100644 index 000000000000..539c0294cd6e --- /dev/null +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/SmramSaveState.c @@ -0,0 +1,700 @@ +/** @file +Provides services to access SMRAM Save State Map + +Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include + +#include + +#include +#include +#include +#include +#include +#include + +// +// EFER register LMA bit +// +#define LMA BIT10 + +/// +/// Macro used to simplify the lookup table entries of type CPU_SMM_SAVE_STATE_LOOKUP_ENTRY +/// +#define SMM_CPU_OFFSET(Field) OFFSET_OF (SMRAM_SAVE_STATE_MAP, Field) + +/// +/// Macro used to simplify the lookup table entries of type CPU_SMM_SAVE_STATE_REGISTER_RANGE +/// +#define SMM_REGISTER_RANGE(Start, End) { Start, End, End - Start + 1 } + +/// +/// Structure used to describe a range of registers +/// +typedef struct { + EFI_SMM_SAVE_STATE_REGISTER Start; + EFI_SMM_SAVE_STATE_REGISTER End; + UINTN Length; +} CPU_SMM_SAVE_STATE_REGISTER_RANGE; + +/// +/// Structure used to build a lookup table to retrieve the widths and offsets +/// associated with each supported EFI_SMM_SAVE_STATE_REGISTER value +/// + +#define SMM_SAVE_STATE_REGISTER_SMMREVID_INDEX 1 +#define SMM_SAVE_STATE_REGISTER_IOMISC_INDEX 2 +#define SMM_SAVE_STATE_REGISTER_IOMEMADDR_INDEX 3 +#define SMM_SAVE_STATE_REGISTER_MAX_INDEX 4 + +typedef struct { + UINT8 Width32; + UINT8 Width64; + UINT16 Offset32; + UINT16 Offset64Lo; + UINT16 Offset64Hi; + BOOLEAN Writeable; +} CPU_SMM_SAVE_STATE_LOOKUP_ENTRY; + +/// +/// Structure used to build a lookup table for the IOMisc width information +/// +typedef struct { + UINT8 Width; + EFI_SMM_SAVE_STATE_IO_WIDTH IoWidth; +} CPU_SMM_SAVE_STATE_IO_WIDTH; + +/// +/// Variables from SMI Handler +/// +extern UINT32 gSmbase; +extern volatile UINT32 gSmiStack; +extern UINT32 gSmiCr3; +extern volatile UINT8 gcSmiHandlerTemplate[]; +extern CONST UINT16 gcSmiHandlerSize; + +// +// Variables used by SMI Handler +// +IA32_DESCRIPTOR gSmiHandlerIdtr; + +/// +/// Table used by GetRegisterIndex() to convert an EFI_SMM_SAVE_STATE_REGISTER +/// value to an index into a table of type CPU_SMM_SAVE_STATE_LOOKUP_ENTRY +/// +CONST CPU_SMM_SAVE_STATE_REGISTER_RANGE mSmmCpuRegisterRanges[] = { + SMM_REGISTER_RANGE (EFI_SMM_SAVE_STATE_REGISTER_GDTBASE, EFI_SMM_SAVE_STATE_REGISTER_LDTINFO), + SMM_REGISTER_RANGE (EFI_SMM_SAVE_STATE_REGISTER_ES, EFI_SMM_SAVE_STATE_REGISTER_RIP), + SMM_REGISTER_RANGE (EFI_SMM_SAVE_STATE_REGISTER_RFLAGS, EFI_SMM_SAVE_STATE_REGISTER_CR4), + { (EFI_SMM_SAVE_STATE_REGISTER)0, (EFI_SMM_SAVE_STATE_REGISTER)0, 0 } +}; + +/// +/// Lookup table used to retrieve the widths and offsets associated with each +/// supported EFI_SMM_SAVE_STATE_REGISTER value +/// +CONST CPU_SMM_SAVE_STATE_LOOKUP_ENTRY mSmmCpuWidthOffset[] = { + {0, 0, 0, 0, 0, FALSE}, // Reserved + + // + // Internally defined CPU Save State Registers. Not defined in PI SMM CPU Protocol. + // + {4, 4, SMM_CPU_OFFSET (x86.SMMRevId) , SMM_CPU_OFFSET (x64.SMMRevId) , 0 , FALSE}, // SMM_SAVE_STATE_REGISTER_SMMREVID_INDEX = 1 + {4, 4, SMM_CPU_OFFSET (x86.IOMisc) , SMM_CPU_OFFSET (x64.IOMisc) , 0 , FALSE}, // SMM_SAVE_STATE_REGISTER_IOMISC_INDEX = 2 + {4, 8, SMM_CPU_OFFSET (x86.IOMemAddr) , SMM_CPU_OFFSET (x64.IOMemAddr) , SMM_CPU_OFFSET (x64.IOMemAddr) + 4, FALSE}, // SMM_SAVE_STATE_REGISTER_IOMEMADDR_INDEX = 3 + + // + // CPU Save State registers defined in PI SMM CPU Protocol. + // + {0, 8, 0 , SMM_CPU_OFFSET (x64.GdtBaseLoDword) , SMM_CPU_OFFSET (x64.GdtBaseHiDword), FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_GDTBASE = 4 + {0, 8, 0 , SMM_CPU_OFFSET (x64.IdtBaseLoDword) , SMM_CPU_OFFSET (x64.IdtBaseHiDword), FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_IDTBASE = 5 + {0, 8, 0 , SMM_CPU_OFFSET (x64.LdtBaseLoDword) , SMM_CPU_OFFSET (x64.LdtBaseHiDword), FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_LDTBASE = 6 + {0, 0, 0 , 0 , 0 , FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_GDTLIMIT = 7 + {0, 0, 0 , 0 , 0 , FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_IDTLIMIT = 8 + {0, 0, 0 , 0 , 0 , FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_LDTLIMIT = 9 + {0, 0, 0 , 0 , 0 , FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_LDTINFO = 10 + + {4, 4, SMM_CPU_OFFSET (x86._ES) , SMM_CPU_OFFSET (x64._ES) , 0 , FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_ES = 20 + {4, 4, SMM_CPU_OFFSET (x86._CS) , SMM_CPU_OFFSET (x64._CS) , 0 , FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_CS = 21 + {4, 4, SMM_CPU_OFFSET (x86._SS) , SMM_CPU_OFFSET (x64._SS) , 0 , FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_SS = 22 + {4, 4, SMM_CPU_OFFSET (x86._DS) , SMM_CPU_OFFSET (x64._DS) , 0 , FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_DS = 23 + {4, 4, SMM_CPU_OFFSET (x86._FS) , SMM_CPU_OFFSET (x64._FS) , 0 , FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_FS = 24 + {4, 4, SMM_CPU_OFFSET (x86._GS) , SMM_CPU_OFFSET (x64._GS) , 0 , FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_GS = 25 + {0, 4, 0 , SMM_CPU_OFFSET (x64._LDTR) , 0 , FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_LDTR_SEL = 26 + {4, 4, SMM_CPU_OFFSET (x86._TR) , SMM_CPU_OFFSET (x64._TR) , 0 , FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_TR_SEL = 27 + {4, 8, SMM_CPU_OFFSET (x86._DR7) , SMM_CPU_OFFSET (x64._DR7) , SMM_CPU_OFFSET (x64._DR7) + 4, FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_DR7 = 28 + {4, 8, SMM_CPU_OFFSET (x86._DR6) , SMM_CPU_OFFSET (x64._DR6) , SMM_CPU_OFFSET (x64._DR6) + 4, FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_DR6 = 29 + {0, 8, 0 , SMM_CPU_OFFSET (x64._R8) , SMM_CPU_OFFSET (x64._R8) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_R8 = 30 + {0, 8, 0 , SMM_CPU_OFFSET (x64._R9) , SMM_CPU_OFFSET (x64._R9) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_R9 = 31 + {0, 8, 0 , SMM_CPU_OFFSET (x64._R10) , SMM_CPU_OFFSET (x64._R10) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_R10 = 32 + {0, 8, 0 , SMM_CPU_OFFSET (x64._R11) , SMM_CPU_OFFSET (x64._R11) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_R11 = 33 + {0, 8, 0 , SMM_CPU_OFFSET (x64._R12) , SMM_CPU_OFFSET (x64._R12) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_R12 = 34 + {0, 8, 0 , SMM_CPU_OFFSET (x64._R13) , SMM_CPU_OFFSET (x64._R13) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_R13 = 35 + {0, 8, 0 , SMM_CPU_OFFSET (x64._R14) , SMM_CPU_OFFSET (x64._R14) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_R14 = 36 + {0, 8, 0 , SMM_CPU_OFFSET (x64._R15) , SMM_CPU_OFFSET (x64._R15) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_R15 = 37 + {4, 8, SMM_CPU_OFFSET (x86._EAX) , SMM_CPU_OFFSET (x64._RAX) , SMM_CPU_OFFSET (x64._RAX) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_RAX = 38 + {4, 8, SMM_CPU_OFFSET (x86._EBX) , SMM_CPU_OFFSET (x64._RBX) , SMM_CPU_OFFSET (x64._RBX) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_RBX = 39 + {4, 8, SMM_CPU_OFFSET (x86._ECX) , SMM_CPU_OFFSET (x64._RCX) , SMM_CPU_OFFSET (x64._RCX) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_RCX = 40 + {4, 8, SMM_CPU_OFFSET (x86._EDX) , SMM_CPU_OFFSET (x64._RDX) , SMM_CPU_OFFSET (x64._RDX) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_RDX = 41 + {4, 8, SMM_CPU_OFFSET (x86._ESP) , SMM_CPU_OFFSET (x64._RSP) , SMM_CPU_OFFSET (x64._RSP) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_RSP = 42 + {4, 8, SMM_CPU_OFFSET (x86._EBP) , SMM_CPU_OFFSET (x64._RBP) , SMM_CPU_OFFSET (x64._RBP) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_RBP = 43 + {4, 8, SMM_CPU_OFFSET (x86._ESI) , SMM_CPU_OFFSET (x64._RSI) , SMM_CPU_OFFSET (x64._RSI) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_RSI = 44 + {4, 8, SMM_CPU_OFFSET (x86._EDI) , SMM_CPU_OFFSET (x64._RDI) , SMM_CPU_OFFSET (x64._RDI) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_RDI = 45 + {4, 8, SMM_CPU_OFFSET (x86._EIP) , SMM_CPU_OFFSET (x64._RIP) , SMM_CPU_OFFSET (x64._RIP) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_RIP = 46 + + {4, 8, SMM_CPU_OFFSET (x86._EFLAGS) , SMM_CPU_OFFSET (x64._RFLAGS) , SMM_CPU_OFFSET (x64._RFLAGS) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_RFLAGS = 51 + {4, 8, SMM_CPU_OFFSET (x86._CR0) , SMM_CPU_OFFSET (x64._CR0) , SMM_CPU_OFFSET (x64._CR0) + 4, FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_CR0 = 52 + {4, 8, SMM_CPU_OFFSET (x86._CR3) , SMM_CPU_OFFSET (x64._CR3) , SMM_CPU_OFFSET (x64._CR3) + 4, FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_CR3 = 53 + {0, 4, 0 , SMM_CPU_OFFSET (x64._CR4) , 0 , FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_CR4 = 54 +}; + +/// +/// Lookup table for the IOMisc width information +/// +CONST CPU_SMM_SAVE_STATE_IO_WIDTH mSmmCpuIoWidth[] = { + { 0, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8 }, // Undefined = 0 + { 1, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8 }, // SMM_IO_LENGTH_BYTE = 1 + { 2, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT16 }, // SMM_IO_LENGTH_WORD = 2 + { 0, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8 }, // Undefined = 3 + { 4, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT32 }, // SMM_IO_LENGTH_DWORD = 4 + { 0, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8 }, // Undefined = 5 + { 0, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8 }, // Undefined = 6 + { 0, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8 } // Undefined = 7 +}; + +/// +/// Lookup table for the IOMisc type information +/// +CONST EFI_SMM_SAVE_STATE_IO_TYPE mSmmCpuIoType[] = { + EFI_SMM_SAVE_STATE_IO_TYPE_OUTPUT, // SMM_IO_TYPE_OUT_DX = 0 + EFI_SMM_SAVE_STATE_IO_TYPE_INPUT, // SMM_IO_TYPE_IN_DX = 1 + EFI_SMM_SAVE_STATE_IO_TYPE_STRING, // SMM_IO_TYPE_OUTS = 2 + EFI_SMM_SAVE_STATE_IO_TYPE_STRING, // SMM_IO_TYPE_INS = 3 + (EFI_SMM_SAVE_STATE_IO_TYPE)0, // Undefined = 4 + (EFI_SMM_SAVE_STATE_IO_TYPE)0, // Undefined = 5 + EFI_SMM_SAVE_STATE_IO_TYPE_REP_PREFIX, // SMM_IO_TYPE_REP_OUTS = 6 + EFI_SMM_SAVE_STATE_IO_TYPE_REP_PREFIX, // SMM_IO_TYPE_REP_INS = 7 + EFI_SMM_SAVE_STATE_IO_TYPE_OUTPUT, // SMM_IO_TYPE_OUT_IMMEDIATE = 8 + EFI_SMM_SAVE_STATE_IO_TYPE_INPUT, // SMM_IO_TYPE_OUT_IMMEDIATE = 9 + (EFI_SMM_SAVE_STATE_IO_TYPE)0, // Undefined = 10 + (EFI_SMM_SAVE_STATE_IO_TYPE)0, // Undefined = 11 + (EFI_SMM_SAVE_STATE_IO_TYPE)0, // Undefined = 12 + (EFI_SMM_SAVE_STATE_IO_TYPE)0, // Undefined = 13 + (EFI_SMM_SAVE_STATE_IO_TYPE)0, // Undefined = 14 + (EFI_SMM_SAVE_STATE_IO_TYPE)0 // Undefined = 15 +}; + +/// +/// The mode of the CPU at the time an SMI occurs +/// +UINT8 mSmmSaveStateRegisterLma; + +/** + Read information from the CPU save state. + + @param Register Specifies the CPU register to read form the save state. + + @retval 0 Register is not valid + @retval >0 Index into mSmmCpuWidthOffset[] associated with Register + +**/ +UINTN +GetRegisterIndex ( + IN EFI_SMM_SAVE_STATE_REGISTER Register + ) +{ + UINTN Index; + UINTN Offset; + + for (Index = 0, Offset = SMM_SAVE_STATE_REGISTER_MAX_INDEX; mSmmCpuRegisterRanges[Index].Length != 0; Index++) { + if (Register >= mSmmCpuRegisterRanges[Index].Start && Register <= mSmmCpuRegisterRanges[Index].End) { + return Register - mSmmCpuRegisterRanges[Index].Start + Offset; + } + Offset += mSmmCpuRegisterRanges[Index].Length; + } + return 0; +} + +/** + Read a CPU Save State register on the target processor. + + This function abstracts the differences that whether the CPU Save State register is in the + IA32 CPU Save State Map or X64 CPU Save State Map. + + This function supports reading a CPU Save State register in SMBase relocation handler. + + @param[in] CpuIndex Specifies the zero-based index of the CPU save state. + @param[in] RegisterIndex Index into mSmmCpuWidthOffset[] look up table. + @param[in] Width The number of bytes to read from the CPU save state. + @param[out] Buffer Upon return, this holds the CPU register value read from the save state. + + @retval EFI_SUCCESS The register was read from Save State. + @retval EFI_NOT_FOUND The register is not defined for the Save State of Processor. + @retval EFI_INVALID_PARAMTER This or Buffer is NULL. + +**/ +EFI_STATUS +ReadSaveStateRegisterByIndex ( + IN UINTN CpuIndex, + IN UINTN RegisterIndex, + IN UINTN Width, + OUT VOID *Buffer + ) +{ + SMRAM_SAVE_STATE_MAP *CpuSaveState; + + if (RegisterIndex == 0) { + return EFI_NOT_FOUND; + } + + CpuSaveState = gSmst->CpuSaveState[CpuIndex]; + + if (mSmmSaveStateRegisterLma == EFI_SMM_SAVE_STATE_REGISTER_LMA_32BIT) { + // + // If 32-bit mode width is zero, then the specified register can not be accessed + // + if (mSmmCpuWidthOffset[RegisterIndex].Width32 == 0) { + return EFI_NOT_FOUND; + } + + // + // If Width is bigger than the 32-bit mode width, then the specified register can not be accessed + // + if (Width > mSmmCpuWidthOffset[RegisterIndex].Width32) { + return EFI_INVALID_PARAMETER; + } + + // + // Write return buffer + // + ASSERT(CpuSaveState != NULL); + CopyMem(Buffer, (UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset32, Width); + } else { + // + // If 64-bit mode width is zero, then the specified register can not be accessed + // + if (mSmmCpuWidthOffset[RegisterIndex].Width64 == 0) { + return EFI_NOT_FOUND; + } + + // + // If Width is bigger than the 64-bit mode width, then the specified register can not be accessed + // + if (Width > mSmmCpuWidthOffset[RegisterIndex].Width64) { + return EFI_INVALID_PARAMETER; + } + + // + // Write lower 32-bits of return buffer + // + CopyMem(Buffer, (UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset64Lo, MIN(4, Width)); + if (Width >= 4) { + // + // Write upper 32-bits of return buffer + // + CopyMem((UINT8 *)Buffer + 4, (UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset64Hi, Width - 4); + } + } + return EFI_SUCCESS; +} + +/** + Read a CPU Save State register on the target processor. + + This function abstracts the differences that whether the CPU Save State register is in the + IA32 CPU Save State Map or X64 CPU Save State Map. + + This function supports reading a CPU Save State register in SMBase relocation handler. + + @param[in] CpuIndex Specifies the zero-based index of the CPU save state. + @param[in] RegisterIndex Index into mSmmCpuWidthOffset[] look up table. + @param[in] Width The number of bytes to read from the CPU save state. + @param[out] Buffer Upon return, this holds the CPU register value read from the save state. + + @retval EFI_SUCCESS The register was read from Save State. + @retval EFI_NOT_FOUND The register is not defined for the Save State of Processor. + @retval EFI_INVALID_PARAMTER This or Buffer is NULL. + +**/ +EFI_STATUS +EFIAPI +ReadSaveStateRegister ( + IN UINTN CpuIndex, + IN EFI_SMM_SAVE_STATE_REGISTER Register, + IN UINTN Width, + OUT VOID *Buffer + ) +{ + UINT32 SmmRevId; + SMRAM_SAVE_STATE_IOMISC IoMisc; + EFI_SMM_SAVE_STATE_IO_INFO *IoInfo; + VOID *IoMemAddr; + + // + // Check for special EFI_SMM_SAVE_STATE_REGISTER_LMA + // + if (Register == EFI_SMM_SAVE_STATE_REGISTER_LMA) { + // + // Only byte access is supported for this register + // + if (Width != 1) { + return EFI_INVALID_PARAMETER; + } + + *(UINT8 *)Buffer = mSmmSaveStateRegisterLma; + + return EFI_SUCCESS; + } + + // + // Check for special EFI_SMM_SAVE_STATE_REGISTER_IO + // + if (Register == EFI_SMM_SAVE_STATE_REGISTER_IO) { + // + // Get SMM Revision ID + // + ReadSaveStateRegisterByIndex (CpuIndex, SMM_SAVE_STATE_REGISTER_SMMREVID_INDEX, sizeof(SmmRevId), &SmmRevId); + + // + // See if the CPU supports the IOMisc register in the save state + // + if (SmmRevId < SMRAM_SAVE_STATE_MIN_REV_ID_IOMISC) { + return EFI_NOT_FOUND; + } + + // + // Get the IOMisc register value + // + ReadSaveStateRegisterByIndex (CpuIndex, SMM_SAVE_STATE_REGISTER_IOMISC_INDEX, sizeof(IoMisc.Uint32), &IoMisc.Uint32); + + // + // Check for the SMI_FLAG in IOMisc + // + if (IoMisc.Bits.SmiFlag == 0) { + return EFI_NOT_FOUND; + } + + // + // Compute index for the I/O Length and I/O Type lookup tables + // + if (mSmmCpuIoWidth[IoMisc.Bits.Length].Width == 0 || mSmmCpuIoType[IoMisc.Bits.Type] == 0) { + return EFI_NOT_FOUND; + } + + // + // Zero the IoInfo structure that will be returned in Buffer + // + IoInfo = (EFI_SMM_SAVE_STATE_IO_INFO *)Buffer; + ZeroMem (IoInfo, sizeof(EFI_SMM_SAVE_STATE_IO_INFO)); + + // + // Use lookup tables to help fill in all the fields of the IoInfo structure + // + IoInfo->IoPort = (UINT16)IoMisc.Bits.Port; + IoInfo->IoWidth = mSmmCpuIoWidth[IoMisc.Bits.Length].IoWidth; + IoInfo->IoType = mSmmCpuIoType[IoMisc.Bits.Type]; + if (IoInfo->IoType == EFI_SMM_SAVE_STATE_IO_TYPE_INPUT || IoInfo->IoType == EFI_SMM_SAVE_STATE_IO_TYPE_OUTPUT) { + ReadSaveStateRegister (CpuIndex, EFI_SMM_SAVE_STATE_REGISTER_RAX, mSmmCpuIoWidth[IoMisc.Bits.Length].Width, &IoInfo->IoData); + } + else { + ReadSaveStateRegisterByIndex(CpuIndex, SMM_SAVE_STATE_REGISTER_IOMEMADDR_INDEX, sizeof(IoMemAddr), &IoMemAddr); + CopyMem(&IoInfo->IoData, IoMemAddr, mSmmCpuIoWidth[IoMisc.Bits.Length].Width); + } + return EFI_SUCCESS; + } + + // + // Convert Register to a register lookup table index + // + return ReadSaveStateRegisterByIndex (CpuIndex, GetRegisterIndex (Register), Width, Buffer); +} + +/** + Write value to a CPU Save State register on the target processor. + + This function abstracts the differences that whether the CPU Save State register is in the + IA32 CPU Save State Map or X64 CPU Save State Map. + + This function supports writing a CPU Save State register in SMBase relocation handler. + + @param[in] CpuIndex Specifies the zero-based index of the CPU save state. + @param[in] RegisterIndex Index into mSmmCpuWidthOffset[] look up table. + @param[in] Width The number of bytes to read from the CPU save state. + @param[in] Buffer Upon entry, this holds the new CPU register value. + + @retval EFI_SUCCESS The register was written to Save State. + @retval EFI_NOT_FOUND The register is not defined for the Save State of Processor. + @retval EFI_INVALID_PARAMTER ProcessorIndex or Width is not correct. + +**/ +EFI_STATUS +EFIAPI +WriteSaveStateRegister ( + IN UINTN CpuIndex, + IN EFI_SMM_SAVE_STATE_REGISTER Register, + IN UINTN Width, + IN CONST VOID *Buffer + ) +{ + UINTN RegisterIndex; + SMRAM_SAVE_STATE_MAP *CpuSaveState; + + // + // Writes to EFI_SMM_SAVE_STATE_REGISTER_LMA are ignored + // + if (Register == EFI_SMM_SAVE_STATE_REGISTER_LMA) { + return EFI_SUCCESS; + } + + // + // Writes to EFI_SMM_SAVE_STATE_REGISTER_IO are not supported + // + if (Register == EFI_SMM_SAVE_STATE_REGISTER_IO) { + return EFI_NOT_FOUND; + } + + // + // Convert Register to a register lookup table index + // + RegisterIndex = GetRegisterIndex (Register); + if (RegisterIndex == 0) { + return EFI_NOT_FOUND; + } + + CpuSaveState = gSmst->CpuSaveState[CpuIndex]; + + // + // Do not write non-writable SaveState, because it will cause exception. + // + if (!mSmmCpuWidthOffset[RegisterIndex].Writeable) { + return EFI_UNSUPPORTED; + } + + // + // Check CPU mode + // + if (mSmmSaveStateRegisterLma == EFI_SMM_SAVE_STATE_REGISTER_LMA_32BIT) { + // + // If 32-bit mode width is zero, then the specified register can not be accessed + // + if (mSmmCpuWidthOffset[RegisterIndex].Width32 == 0) { + return EFI_NOT_FOUND; + } + + // + // If Width is bigger than the 32-bit mode width, then the specified register can not be accessed + // + if (Width > mSmmCpuWidthOffset[RegisterIndex].Width32) { + return EFI_INVALID_PARAMETER; + } + // + // Write SMM State register + // + ASSERT (CpuSaveState != NULL); + CopyMem((UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset32, Buffer, Width); + } else { + // + // If 64-bit mode width is zero, then the specified register can not be accessed + // + if (mSmmCpuWidthOffset[RegisterIndex].Width64 == 0) { + return EFI_NOT_FOUND; + } + + // + // If Width is bigger than the 64-bit mode width, then the specified register can not be accessed + // + if (Width > mSmmCpuWidthOffset[RegisterIndex].Width64) { + return EFI_INVALID_PARAMETER; + } + + // + // Write lower 32-bits of SMM State register + // + CopyMem((UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset64Lo, Buffer, MIN (4, Width)); + if (Width >= 4) { + // + // Write upper 32-bits of SMM State register + // + CopyMem((UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset64Hi, (UINT8 *)Buffer + 4, Width - 4); + } + } + return EFI_SUCCESS; +} + +/** + Hook the code executed immediately after an RSM instruction on the currently + executing CPU. The mode of code executed immediately after RSM must be + detected, and the appropriate hook must be selected. Always clear the auto + HALT restart flag if it is set. + + @param[in] CpuIndex The processor index for the currently + executing CPU. + @param[in] CpuState Pointer to SMRAM Save State Map for the + currently executing CPU. + @param[in] NewInstructionPointer32 Instruction pointer to use if resuming to + 32-bit mode from 64-bit SMM. + @param[in] NewInstructionPointer Instruction pointer to use if resuming to + same mode as SMM. + + @retval The value of the original instruction pointer before it was hooked. + +**/ +UINT64 +EFIAPI +HookReturnFromSmm ( + IN UINTN CpuIndex, + SMRAM_SAVE_STATE_MAP *CpuState, + UINT64 NewInstructionPointer32, + UINT64 NewInstructionPointer + ) +{ + UINT64 OriginalInstructionPointer; + + OriginalInstructionPointer = SmmCpuFeaturesHookReturnFromSmm ( + CpuIndex, + CpuState, + NewInstructionPointer32, + NewInstructionPointer + ); + if (OriginalInstructionPointer != 0) { + return OriginalInstructionPointer; + } + + if (mSmmSaveStateRegisterLma == EFI_SMM_SAVE_STATE_REGISTER_LMA_32BIT) { + OriginalInstructionPointer = (UINT64)CpuState->x86._EIP; + CpuState->x86._EIP = (UINT32)NewInstructionPointer; + // + // Clear the auto HALT restart flag so the RSM instruction returns + // program control to the instruction following the HLT instruction. + // + if ((CpuState->x86.AutoHALTRestart & BIT0) != 0) { + CpuState->x86.AutoHALTRestart &= ~BIT0; + } + } else { + OriginalInstructionPointer = CpuState->x64._RIP; + if ((CpuState->x64.IA32_EFER & LMA) == 0) { + CpuState->x64._RIP = (UINT32)NewInstructionPointer32; + } else { + CpuState->x64._RIP = (UINT32)NewInstructionPointer; + } + // + // Clear the auto HALT restart flag so the RSM instruction returns + // program control to the instruction following the HLT instruction. + // + if ((CpuState->x64.AutoHALTRestart & BIT0) != 0) { + CpuState->x64.AutoHALTRestart &= ~BIT0; + } + } + return OriginalInstructionPointer; +} + +/** + Get the size of the SMI Handler in bytes. + + @retval The size, in bytes, of the SMI Handler. + +**/ +UINTN +EFIAPI +GetSmiHandlerSize ( + VOID + ) +{ + UINTN Size; + + Size = SmmCpuFeaturesGetSmiHandlerSize (); + if (Size != 0) { + return Size; + } + return gcSmiHandlerSize; +} + +/** + Install the SMI handler for the CPU specified by CpuIndex. This function + is called by the CPU that was elected as monarch during System Management + Mode initialization. + + @param[in] CpuIndex The index of the CPU to install the custom SMI handler. + The value must be between 0 and the NumberOfCpus field + in the System Management System Table (SMST). + @param[in] SmBase The SMBASE address for the CPU specified by CpuIndex. + @param[in] SmiStack The stack to use when an SMI is processed by the + the CPU specified by CpuIndex. + @param[in] StackSize The size, in bytes, if the stack used when an SMI is + processed by the CPU specified by CpuIndex. + @param[in] GdtBase The base address of the GDT to use when an SMI is + processed by the CPU specified by CpuIndex. + @param[in] GdtSize The size, in bytes, of the GDT used when an SMI is + processed by the CPU specified by CpuIndex. + @param[in] IdtBase The base address of the IDT to use when an SMI is + processed by the CPU specified by CpuIndex. + @param[in] IdtSize The size, in bytes, of the IDT used when an SMI is + processed by the CPU specified by CpuIndex. + @param[in] Cr3 The base address of the page tables to use when an SMI + is processed by the CPU specified by CpuIndex. +**/ +VOID +EFIAPI +InstallSmiHandler ( + IN UINTN CpuIndex, + IN UINT32 SmBase, + IN VOID *SmiStack, + IN UINTN StackSize, + IN UINTN GdtBase, + IN UINTN GdtSize, + IN UINTN IdtBase, + IN UINTN IdtSize, + IN UINT32 Cr3 + ) +{ + if (SmmCpuFeaturesGetSmiHandlerSize () != 0) { + // + // Install SMI handler provided by library + // + SmmCpuFeaturesInstallSmiHandler ( + CpuIndex, + SmBase, + SmiStack, + StackSize, + GdtBase, + GdtSize, + IdtBase, + IdtSize, + Cr3 + ); + return; + } + + // + // Initialize values in template before copy + // + gSmiStack = (UINT32)((UINTN)SmiStack + StackSize - sizeof (UINTN)); + gSmiCr3 = Cr3; + gSmbase = SmBase; + gSmiHandlerIdtr.Base = IdtBase; + gSmiHandlerIdtr.Limit = (UINT16)(IdtSize - 1); + + // + // Set the value at the top of the CPU stack to the CPU Index + // + *(UINTN*)(UINTN)gSmiStack = CpuIndex; + + // + // Copy template to CPU specific SMI handler location + // + CopyMem ( + (VOID*)(UINTN)(SmBase + SMM_HANDLER_OFFSET), + (VOID*)gcSmiHandlerTemplate, + gcSmiHandlerSize + ); +} diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/SyncTimer.c b/UefiCpuPkg/PiSmmCpuDxeSmm/SyncTimer.c new file mode 100644 index 000000000000..5a632eaa2487 --- /dev/null +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/SyncTimer.c @@ -0,0 +1,116 @@ +/** @file +SMM Timer feature support + +Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "PiSmmCpuDxeSmm.h" + +UINT64 mTimeoutTicker = 0; +// +// Number of counts in a roll-over cycle of the performance counter. +// +UINT64 mCycle = 0; +// +// Flag to indicate the performance counter is count-up or count-down. +// +BOOLEAN mCountDown; + +/** + Initialize Timer for SMM AP Sync. + +**/ +VOID +InitializeSmmTimer ( + VOID + ) +{ + UINT64 TimerFrequency; + UINT64 Start; + UINT64 End; + + TimerFrequency = GetPerformanceCounterProperties (&Start, &End); + mTimeoutTicker = DivU64x32 ( + MultU64x64(TimerFrequency, PcdGet64 (PcdCpuSmmApSyncTimeout)), + 1000 * 1000 + ); + if (End < Start) { + mCountDown = TRUE; + mCycle = Start - End; + } else { + mCountDown = FALSE; + mCycle = End - Start; + } +} + +/** + Start Timer for SMM AP Sync. + +**/ +UINT64 +EFIAPI +StartSyncTimer ( + VOID + ) +{ + return GetPerformanceCounter (); +} + + +/** + Check if the SMM AP Sync timer is timeout. + + @param Timer The start timer from the begin. + +**/ +BOOLEAN +EFIAPI +IsSyncTimerTimeout ( + IN UINT64 Timer + ) +{ + UINT64 CurrentTimer; + UINT64 Delta; + + CurrentTimer = GetPerformanceCounter (); + // + // We need to consider the case that CurrentTimer is equal to Timer + // when some timer runs too slow and CPU runs fast. We think roll over + // condition does not happen on this case. + // + if (mCountDown) { + // + // The performance counter counts down. Check for roll over condition. + // + if (CurrentTimer <= Timer) { + Delta = Timer - CurrentTimer; + } else { + // + // Handle one roll-over. + // + Delta = mCycle - (CurrentTimer - Timer) + 1; + } + } else { + // + // The performance counter counts up. Check for roll over condition. + // + if (CurrentTimer >= Timer) { + Delta = CurrentTimer - Timer; + } else { + // + // Handle one roll-over. + // + Delta = mCycle - (Timer - CurrentTimer) + 1; + } + } + + return (BOOLEAN) (Delta >= mTimeoutTicker); +} diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec index 4f7065fca604..e783a7b53616 100644 --- a/UefiCpuPkg/UefiCpuPkg.dec +++ b/UefiCpuPkg/UefiCpuPkg.dec @@ -41,11 +41,11 @@ ## @libraryclass Provides platform specific initialization functions in the SEC phase. ## PlatformSecLib|Include/Library/PlatformSecLib.h - + ## @libraryclass Public include file for the SMM CPU Platform Hook Library. ## SmmCpuPlatformHookLib|Include/Library/SmmCpuPlatformHookLib.h - + ## @libraryclass Provides the CPU specific programming for PiSmmCpuDxeSmm module. ## SmmCpuFeaturesLib|Include/Library/SmmCpuFeaturesLib.h @@ -56,23 +56,82 @@ [Protocols] ## Include/Protocol/SmmCpuService.h gEfiSmmCpuServiceProtocolGuid = { 0x1d202cab, 0xc8ab, 0x4d5c, { 0x94, 0xf7, 0x3c, 0xfc, 0xc0, 0xd3, 0xd3, 0x35 }} - + # # [Error.gUefiCpuPkgTokenSpaceGuid] # 0x80000001 | Invalid value provided. # +[PcdsFeatureFlag] + ## Indicates if SMM Profile will be enabled. + # If enabled, instruction executions in and data accesses to memory outside of SMRAM will be logged. + # This PCD is only for validation purpose. It should be set to false in production.

+ # TRUE - SMM Profile will be enabled.
+ # FALSE - SMM Profile will be disabled.
+ # @Prompt Enable SMM Profile. + gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmProfileEnable|FALSE|BOOLEAN|0x32132109 + + ## Indicates if the SMM profile log buffer is a ring buffer. + # If disabled, no additional log can be done when the buffer is full.

+ # TRUE - the SMM profile log buffer is a ring buffer.
+ # FALSE - the SMM profile log buffer is a normal buffer.
+ # @Prompt The SMM profile log buffer is a ring buffer. + gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmProfileRingBuffer|FALSE|BOOLEAN|0x3213210a + + ## Indicates if SMM Startup AP in a blocking fashion. + # TRUE - SMM Startup AP in a blocking fashion.
+ # FALSE - SMM Startup AP in a non-blocking fashion.
+ # @Prompt SMM Startup AP in a blocking fashion. + gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmBlockStartupThisAp|FALSE|BOOLEAN|0x32132108 + + ## Indicates if SMM Stack Guard will be enabled. + # If enabled, stack overflow in SMM can be caught which eases debugging.

+ # TRUE - SMM Stack Guard will be enabled.
+ # FALSE - SMM Stack Guard will be disabled.
+ # @Prompt Enable SMM Stack Guard. + gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmStackGuard|FALSE|BOOLEAN|0x1000001C + + ## Indicates if BSP election in SMM will be enabled. + # If enabled, a BSP will be dynamically elected among all processors in each SMI. + # Otherwise, processor 0 is always as BSP in each SMI.

+ # TRUE - BSP election in SMM will be enabled.
+ # FALSE - BSP election in SMM will be disabled.
+ # @Prompt Enable BSP election in SMM. + gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmEnableBspElection|TRUE|BOOLEAN|0x32132106 + + ## Indicates if CPU SMM hot-plug will be enabled.

+ # TRUE - SMM CPU hot-plug will be enabled.
+ # FALSE - SMM CPU hot-plug will be disabled.
+ # @Prompt SMM CPU hot-plug. + gUefiCpuPkgTokenSpaceGuid.PcdCpuHotPlugSupport|FALSE|BOOLEAN|0x3213210C + + ## Indicates if SMM Debug will be enabled. + # If enabled, hardware breakpoints in SMRAM can be set outside of SMM mode and take effect in SMM.

+ # TRUE - SMM Debug will be enabled.
+ # FALSE - SMM Debug will be disabled.
+ # @Prompt Enable SMM Debug. + gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmDebug|FALSE|BOOLEAN|0x1000001B + + ## Indicates if lock SMM Feature Control MSR.

+ # TRUE - SMM Feature Control MSR will be locked.
+ # FALSE - SMM Feature Control MSR will not be locked.
+ # @Prompt Lock SMM Feature Control MSR. + gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmFeatureControlMsrLock|TRUE|BOOLEAN|0x3213210B + [PcdsFixedAtBuild, PcdsPatchableInModule] - ## This value is the CPU Local Apic base address, which aligns the address on a 4-KByte boundary. - # @Prompt Configure base address of CPU Local Apic + ## This value is the CPU Local APIC base address, which aligns the address on a 4-KByte boundary. + # @Prompt Configure base address of CPU Local APIC # @Expression 0x80000001 | (gUefiCpuPkgTokenSpaceGuid.PcdCpuLocalApicBaseAddress & 0xfff) == 0 gUefiCpuPkgTokenSpaceGuid.PcdCpuLocalApicBaseAddress|0xfee00000|UINT32|0x00000001 + ## Specifies delay value in microseconds after sending out an INIT IPI. # @Prompt Configure delay value after send an INIT IPI gUefiCpuPkgTokenSpaceGuid.PcdCpuInitIpiDelayInMicroSeconds|10000|UINT32|0x30000002 + ## Specifies max supported number of Logical Processors. - # @Prompt Configure max supported number of Logical Processorss + # @Prompt Configure max supported number of Logical Processors gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber|64|UINT32|0x00000002 + ## This value specifies the Application Processor (AP) stack size, used for Mp Service, which must ## aligns the address on a 4-KByte boundary. # @Prompt Configure stack size for Application Processor (AP) @@ -82,6 +141,32 @@ # @Prompt Stack size in the temporary RAM. gUefiCpuPkgTokenSpaceGuid.PcdPeiTemporaryRamStackSize|0|UINT32|0x10001003 + ## Specifies buffer size in bytes to save SMM profile data. The value should be a multiple of 4KB. + # @Prompt SMM profile data buffer size. + gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmProfileSize|0x200000|UINT32|0x32132107 + + ## Specifies stack size in bytes for each processor in SMM. + # @Prompt Processor stack size in SMM. + gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmStackSize|0x2000|UINT32|0x32132105 + + ## Specifies timeout value in microseconds for the BSP in SMM to wait for all APs to come into SMM. + # @Prompt AP synchronization timeout value in SMM. + gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmApSyncTimeout|1000000|UINT64|0x32132104 + + ## Indicates if SMM Code Access Check is enabled. + # If enabled, the SMM handler cannot execute the code outside SMM regions. + # This PCD is suggested to TRUE in production image.

+ # TRUE - SMM Code Access Check will be enabled.
+ # FALSE - SMM Code Access Check will be disabled.
+ # @Prompt SMM Code Access Check. + gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmCodeAccessCheckEnable|TRUE|BOOLEAN|0x60000013 + + ## Indicates the CPU synchronization method used when processing an SMI. + # 0x00 - Traditional CPU synchronization method.
+ # 0x01 - Relaxed CPU synchronization method.
+ # @Prompt SMM CPU Synchronization Method. + gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmSyncMode|0x00|UINT8|0x60000014 + [PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx] ## Specifies timeout value in microseconds for the BSP to detect all APs for the first time. # @Prompt Timeout for the BSP to detect all APs for the first time. @@ -93,5 +178,16 @@ # @Prompt Microcode Region size. gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchRegionSize|0x0|UINT64|0x00000006 +[PcdsDynamic, PcdsDynamicEx] + ## Contains the pointer to a CPU S3 data buffer of structure ACPI_CPU_DATA. + # @Prompt The pointer to a CPU S3 data buffer. + # @ValidList 0x80000001 | 0 + gUefiCpuPkgTokenSpaceGuid.PcdCpuS3DataAddress|0x0|UINT64|0x60000010 + + ## Contains the pointer to a CPU Hot Plug Data structure if CPU hot-plug is supported. + # @Prompt The pointer to CPU Hot Plug Data. + # @ValidList 0x80000001 | 0 + gUefiCpuPkgTokenSpaceGuid.PcdCpuHotPlugDataAddress|0x0|UINT64|0x60000011 + [UserExtensions.TianoCore."ExtraFiles"] UefiCpuPkgExtra.uni diff --git a/UefiCpuPkg/UefiCpuPkg.uni b/UefiCpuPkg/UefiCpuPkg.uni index 4fe2faf981581025adcbbfd9829512e2328c889b..f7ab84c5a246356d85cba9e5c88b15bd7c5e80fe 100644 GIT binary patch literal 21898 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
mBcf8ky7& z>mIZ;J=G;;K9YPKX%t0zr$b!+Y_d__-)PEz*8GpE-*&V)AMuDlBsn+U!nDW>RS}>q zuj&R>{`Bc!j;l4=-Y%6<>72-Txdj8l^YhYvd22wVkp0s~K^EOA>?LEm4 z(v9w}OLO{|5}niO$7a-A#YnbmD9;v6@>j5yPIvyEbgFbN`g3R^YS*nk8k~{Y_E?K= zS3QPolC+`q@x8vRl6i08NEU#)@N!l7EWAuSSubAjFEsGtP`Kc~Rd}n3cYNmKK^+qH zgWhk#6F-(ml>fWZEZXB}u+~j^8uJd!F0;aQezd|5IvO5ZcwVZf(o3Y Date: Tue, 17 Nov 2015 05:05:10 +0000 Subject: [PATCH 125/525] UefiCpuPkg: Add PiSmmCpuDxeSmm module IA32 files Add module that initializes a CPU for the SMM environment and installs the first level SMI handler. This module along with the SMM IPL and SMM Core provide the services required for DXE_SMM_DRIVERS to register hardware and software SMI handlers. CPU specific features are abstracted through the SmmCpuFeaturesLib Platform specific features are abstracted through the SmmCpuPlatformHookLib Several PCDs are added to enable/disable features and configure settings for the PiSmmCpuDxeSmm module (Sync patch r18646 from main trunk.) [jeff.fan@intel.com: Fix code style issues reported by ECC] Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Michael Kinney Reviewed-by: Jeff Fan git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18841 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/MpFuncs.S | 165 ++++ UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/MpFuncs.asm | 168 ++++ UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/PageTbl.c | 132 +++ UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/Semaphore.c | 48 + UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.S | 191 ++++ UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.asm | 193 ++++ UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.S | 911 ++++++++++++++++++ .../PiSmmCpuDxeSmm/Ia32/SmiException.asm | 738 ++++++++++++++ UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmmInit.S | 84 ++ UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmmInit.asm | 94 ++ .../PiSmmCpuDxeSmm/Ia32/SmmProfileArch.c | 80 ++ .../PiSmmCpuDxeSmm/Ia32/SmmProfileArch.h | 97 ++ 12 files changed, 2901 insertions(+) create mode 100644 UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/MpFuncs.S create mode 100644 UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/MpFuncs.asm create mode 100644 UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/PageTbl.c create mode 100644 UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/Semaphore.c create mode 100644 UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.S create mode 100644 UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.asm create mode 100644 UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.S create mode 100644 UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.asm create mode 100644 UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmmInit.S create mode 100644 UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmmInit.asm create mode 100644 UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmmProfileArch.c create mode 100644 UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmmProfileArch.h diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/MpFuncs.S b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/MpFuncs.S new file mode 100644 index 000000000000..75aa312a6e8a --- /dev/null +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/MpFuncs.S @@ -0,0 +1,165 @@ +#------------------------------------------------------------------------------ +# +# Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# Module Name: +# +# MpFuncs.S +# +# Abstract: +# +# This is the assembly code for Multi-processor S3 support +# +#------------------------------------------------------------------------------ + +.equ VacantFlag, 0x0 +.equ NotVacantFlag, 0xff + +.equ LockLocation, RendezvousFunnelProcEnd - RendezvousFunnelProcStart +.equ StackStart, RendezvousFunnelProcEnd - RendezvousFunnelProcStart + 0x04 +.equ StackSize, RendezvousFunnelProcEnd - RendezvousFunnelProcStart + 0x08 +.equ RendezvousProc, RendezvousFunnelProcEnd - RendezvousFunnelProcStart + 0x0C +.equ GdtrProfile, RendezvousFunnelProcEnd - RendezvousFunnelProcStart + 0x10 +.equ IdtrProfile, RendezvousFunnelProcEnd - RendezvousFunnelProcStart + 0x16 +.equ BufferStart, RendezvousFunnelProcEnd - RendezvousFunnelProcStart + 0x1C + +#------------------------------------------------------------------------------------- +#RendezvousFunnelProc procedure follows. All APs execute their procedure. This +#procedure serializes all the AP processors through an Init sequence. It must be +#noted that APs arrive here very raw...ie: real mode, no stack. +#ALSO THIS PROCEDURE IS EXECUTED BY APs ONLY ON 16 BIT MODE. HENCE THIS PROC +#IS IN MACHINE CODE. +#------------------------------------------------------------------------------------- +#RendezvousFunnelProc (&WakeUpBuffer,MemAddress); + +ASM_GLOBAL ASM_PFX(RendezvousFunnelProc) +ASM_PFX(RendezvousFunnelProc): +RendezvousFunnelProcStart: + +# At this point CS = 0x(vv00) and ip= 0x0. + + .byte 0x8c,0xc8 # mov ax, cs + .byte 0x8e,0xd8 # mov ds, ax + .byte 0x8e,0xc0 # mov es, ax + .byte 0x8e,0xd0 # mov ss, ax + .byte 0x33,0xc0 # xor ax, ax + .byte 0x8e,0xe0 # mov fs, ax + .byte 0x8e,0xe8 # mov gs, ax + +flat32Start: + + .byte 0xBE + .word BufferStart + .byte 0x66,0x8B,0x14 # mov edx,dword ptr [si] ; EDX is keeping the start address of wakeup buffer + + .byte 0xBE + .word GdtrProfile + .byte 0x66 # db 66h + .byte 0x2E,0xF,0x1,0x14 # lgdt fword ptr cs:[si] + + .byte 0xBE + .word IdtrProfile + .byte 0x66 # db 66h + .byte 0x2E,0xF,0x1,0x1C # lidt fword ptr cs:[si] + + .byte 0x33,0xC0 # xor ax, ax + .byte 0x8E,0xD8 # mov ds, ax + + .byte 0xF,0x20,0xC0 # mov eax, cr0 ; Get control register 0 + .byte 0x66,0x83,0xC8,0x1 # or eax, 000000001h ; Set PE bit (bit #0) + .byte 0xF,0x22,0xC0 # mov cr0, eax + +FLAT32_JUMP: + + .byte 0x66,0x67,0xEA # far jump + .long 0x0 # 32-bit offset + .word 0x20 # 16-bit selector + +PMODE_ENTRY: # protected mode entry point + + movw $0x8,%ax + .byte 0x66 + movw %ax,%ds + .byte 0x66 + movw %ax,%es + .byte 0x66 + movw %ax,%fs + .byte 0x66 + movw %ax,%gs + .byte 0x66 + movw %ax,%ss # Flat mode setup. + + movl %edx,%esi + + movl %esi,%edi + addl $LockLocation, %edi + movb $NotVacantFlag, %al +TestLock: + xchgb (%edi), %al + cmpb $NotVacantFlag, %al + jz TestLock + +ProgramStack: + + movl %esi,%edi + addl $StackSize, %edi + movl (%edi),%eax + movl %esi,%edi + addl $StackStart, %edi + addl (%edi),%eax + movl %eax,%esp + movl %eax,(%edi) + +Releaselock: + + movb $VacantFlag, %al + movl %esi,%edi + addl $LockLocation, %edi + xchgb (%edi), %al + + # + # Call assembly function to initialize FPU. + # + lea ASM_PFX(InitializeFloatingPointUnits), %ebx + call *%ebx + # + # Call C Function + # + movl %esi,%edi + addl $RendezvousProc, %edi + movl (%edi),%eax + + testl %eax,%eax + jz GoToSleep + call *%eax # Call C function + +GoToSleep: + cli + hlt + jmp GoToSleep + +RendezvousFunnelProcEnd: +#------------------------------------------------------------------------------------- +# AsmGetAddressMap (&AddressMap); +#------------------------------------------------------------------------------------- +ASM_GLOBAL ASM_PFX(AsmGetAddressMap) +ASM_PFX(AsmGetAddressMap): + + pushal + movl %esp,%ebp + + movl 0x24(%ebp), %ebx + movl $RendezvousFunnelProcStart, (%ebx) + movl $(PMODE_ENTRY - RendezvousFunnelProcStart), 0x4(%ebx) + movl $(FLAT32_JUMP - RendezvousFunnelProcStart), 0x8(%ebx) + movl $(RendezvousFunnelProcEnd - RendezvousFunnelProcStart), 0x0c(%ebx) + + popal + ret diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/MpFuncs.asm b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/MpFuncs.asm new file mode 100644 index 000000000000..70e24a827048 --- /dev/null +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/MpFuncs.asm @@ -0,0 +1,168 @@ +;------------------------------------------------------------------------------ ; +; Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
+; This program and the accompanying materials +; are licensed and made available under the terms and conditions of the BSD License +; which accompanies this distribution. The full text of the license may be found at +; http://opensource.org/licenses/bsd-license.php. +; +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +; +; Module Name: +; +; MpFuncs.asm +; +; Abstract: +; +; This is the assembly code for Multi-processor S3 support +; +;------------------------------------------------------------------------------- + +.686p +.model flat,C +.code + +EXTERN InitializeFloatingPointUnits:PROC + +VacantFlag Equ 00h +NotVacantFlag Equ 0ffh + +LockLocation equ RendezvousFunnelProcEnd - RendezvousFunnelProcStart +StackStart equ LockLocation + 4h +StackSize equ LockLocation + 8h +RendezvousProc equ LockLocation + 0Ch +GdtrProfile equ LockLocation + 10h +IdtrProfile equ LockLocation + 16h +BufferStart equ LockLocation + 1Ch + +;------------------------------------------------------------------------------------- +;RendezvousFunnelProc procedure follows. All APs execute their procedure. This +;procedure serializes all the AP processors through an Init sequence. It must be +;noted that APs arrive here very raw...ie: real mode, no stack. +;ALSO THIS PROCEDURE IS EXECUTED BY APs ONLY ON 16 BIT MODE. HENCE THIS PROC +;IS IN MACHINE CODE. +;------------------------------------------------------------------------------------- +;RendezvousFunnelProc (&WakeUpBuffer,MemAddress); + +RendezvousFunnelProc PROC near C PUBLIC +RendezvousFunnelProcStart:: + +; At this point CS = 0x(vv00) and ip= 0x0. + + db 8ch, 0c8h ; mov ax, cs + db 8eh, 0d8h ; mov ds, ax + db 8eh, 0c0h ; mov es, ax + db 8eh, 0d0h ; mov ss, ax + db 33h, 0c0h ; xor ax, ax + db 8eh, 0e0h ; mov fs, ax + db 8eh, 0e8h ; mov gs, ax + +flat32Start:: + + db 0BEh + dw BufferStart ; mov si, BufferStart + db 66h, 8Bh, 14h ; mov edx,dword ptr [si] ; EDX is keeping the start address of wakeup buffer + + db 0BEh + dw GdtrProfile ; mov si, GdtrProfile + db 66h ; db 66h + db 2Eh, 0Fh, 01h, 14h ; lgdt fword ptr cs:[si] + + db 0BEh + dw IdtrProfile ; mov si, IdtrProfile + db 66h ; db 66h + db 2Eh, 0Fh, 01h, 1Ch ; lidt fword ptr cs:[si] + + db 33h, 0C0h ; xor ax, ax + db 8Eh, 0D8h ; mov ds, ax + + db 0Fh, 20h, 0C0h ; mov eax, cr0 ; Get control register 0 + db 66h, 83h, 0C8h, 01h ; or eax, 000000001h ; Set PE bit (bit #0) + db 0Fh, 22h, 0C0h ; mov cr0, eax + +FLAT32_JUMP:: + + db 66h, 67h, 0EAh ; far jump + dd 0h ; 32-bit offset + dw 20h ; 16-bit selector + +PMODE_ENTRY:: ; protected mode entry point + + mov ax, 8h + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax ; Flat mode setup. + + mov esi, edx + + mov edi, esi + add edi, LockLocation + mov al, NotVacantFlag +TestLock:: + xchg byte ptr [edi], al + cmp al, NotVacantFlag + jz TestLock + +ProgramStack:: + + mov edi, esi + add edi, StackSize + mov eax, dword ptr [edi] + mov edi, esi + add edi, StackStart + add eax, dword ptr [edi] + mov esp, eax + mov dword ptr [edi], eax + +Releaselock:: + + mov al, VacantFlag + mov edi, esi + add edi, LockLocation + xchg byte ptr [edi], al + + ; + ; Call assembly function to initialize FPU. + ; + mov ebx, InitializeFloatingPointUnits + call ebx + ; + ; Call C Function + ; + mov edi, esi + add edi, RendezvousProc + mov eax, dword ptr [edi] + + test eax, eax + jz GoToSleep + call eax ; Call C function + +GoToSleep:: + cli + hlt + jmp $-2 + +RendezvousFunnelProc ENDP +RendezvousFunnelProcEnd:: +;------------------------------------------------------------------------------------- +; AsmGetAddressMap (&AddressMap); +;------------------------------------------------------------------------------------- +AsmGetAddressMap PROC near C PUBLIC + + pushad + mov ebp,esp + + mov ebx, dword ptr [ebp+24h] + mov dword ptr [ebx], RendezvousFunnelProcStart + mov dword ptr [ebx+4h], PMODE_ENTRY - RendezvousFunnelProcStart + mov dword ptr [ebx+8h], FLAT32_JUMP - RendezvousFunnelProcStart + mov dword ptr [ebx+0ch], RendezvousFunnelProcEnd - RendezvousFunnelProcStart + + popad + ret + +AsmGetAddressMap ENDP + +END diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/PageTbl.c b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/PageTbl.c new file mode 100644 index 000000000000..edebaabb47bd --- /dev/null +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/PageTbl.c @@ -0,0 +1,132 @@ +/** @file +Page table manipulation functions for IA-32 processors + +Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "PiSmmCpuDxeSmm.h" + +SPIN_LOCK mPFLock; + +/** + Create PageTable for SMM use. + + @return PageTable Address + +**/ +UINT32 +SmmInitPageTable ( + VOID + ) +{ + UINTN PageFaultHandlerHookAddress; + IA32_IDT_GATE_DESCRIPTOR *IdtEntry; + + // + // Initialize spin lock + // + InitializeSpinLock (&mPFLock); + + if (FeaturePcdGet (PcdCpuSmmProfileEnable)) { + // + // Set own Page Fault entry instead of the default one, because SMM Profile + // feature depends on IRET instruction to do Single Step + // + PageFaultHandlerHookAddress = (UINTN)PageFaultIdtHandlerSmmProfile; + IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *) gcSmiIdtr.Base; + IdtEntry += EXCEPT_IA32_PAGE_FAULT; + IdtEntry->Bits.OffsetLow = (UINT16)PageFaultHandlerHookAddress; + IdtEntry->Bits.Reserved_0 = 0; + IdtEntry->Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32; + IdtEntry->Bits.OffsetHigh = (UINT16)(PageFaultHandlerHookAddress >> 16); + } else { + // + // Register SMM Page Fault Handler + // + SmmRegisterExceptionHandler (&mSmmCpuService, EXCEPT_IA32_PAGE_FAULT, SmiPFHandler); + } + + // + // Additional SMM IDT initialization for SMM stack guard + // + if (FeaturePcdGet (PcdCpuSmmStackGuard)) { + InitializeIDTSmmStackGuard (); + } + return Gen4GPageTable (0); +} + +/** + Page Fault handler for SMM use. + +**/ +VOID +SmiDefaultPFHandler ( + VOID + ) +{ + CpuDeadLoop (); +} + +/** + ThePage Fault handler wrapper for SMM use. + + @param InterruptType Defines the type of interrupt or exception that + occurred on the processor.This parameter is processor architecture specific. + @param SystemContext A pointer to the processor context when + the interrupt occurred on the processor. +**/ +VOID +EFIAPI +SmiPFHandler ( + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ + UINTN PFAddress; + + ASSERT (InterruptType == EXCEPT_IA32_PAGE_FAULT); + + AcquireSpinLock (&mPFLock); + + PFAddress = AsmReadCr2 (); + + if ((FeaturePcdGet (PcdCpuSmmStackGuard)) && + (PFAddress >= mCpuHotPlugData.SmrrBase) && + (PFAddress < (mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize))) { + DEBUG ((EFI_D_ERROR, "SMM stack overflow!\n")); + CpuDeadLoop (); + } + + // + // If a page fault occurs in SMM range + // + if ((PFAddress < mCpuHotPlugData.SmrrBase) || + (PFAddress >= mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize)) { + if ((SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_ID) != 0) { + DEBUG ((EFI_D_ERROR, "Code executed on IP(0x%x) out of SMM range after SMM is locked!\n", PFAddress)); + DEBUG_CODE ( + DumpModuleInfoByIp (*(UINTN *)(UINTN)SystemContext.SystemContextIa32->Esp); + ); + CpuDeadLoop (); + } + } + + if (FeaturePcdGet (PcdCpuSmmProfileEnable)) { + SmmProfilePFHandler ( + SystemContext.SystemContextIa32->Eip, + SystemContext.SystemContextIa32->ExceptionData + ); + } else { + SmiDefaultPFHandler (); + } + + ReleaseSpinLock (&mPFLock); +} diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/Semaphore.c b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/Semaphore.c new file mode 100644 index 000000000000..02a866b43008 --- /dev/null +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/Semaphore.c @@ -0,0 +1,48 @@ +/** @file +Semaphore mechanism to indicate to the BSP that an AP has exited SMM +after SMBASE relocation. + +Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "PiSmmCpuDxeSmm.h" + +UINTN mSmmRelocationOriginalAddress; +volatile BOOLEAN *mRebasedFlag; + +/** + Hook return address of SMM Save State so that semaphore code + can be executed immediately after AP exits SMM to indicate to + the BSP that an AP has exited SMM after SMBASE relocation. + + @param[in] CpuIndex The processor index. + @param[in] RebasedFlag A pointer to a flag that is set to TRUE + immediately after AP exits SMM. + +**/ +VOID +SemaphoreHook ( + IN UINTN CpuIndex, + IN volatile BOOLEAN *RebasedFlag + ) +{ + SMRAM_SAVE_STATE_MAP *CpuState; + + mRebasedFlag = RebasedFlag; + + CpuState = (SMRAM_SAVE_STATE_MAP *)(UINTN)(SMM_DEFAULT_SMBASE + SMRAM_SAVE_STATE_MAP_OFFSET); + mSmmRelocationOriginalAddress = (UINTN)HookReturnFromSmm ( + CpuIndex, + CpuState, + (UINT64)(UINTN)&SmmRelocationSemaphoreComplete, + (UINT64)(UINTN)&SmmRelocationSemaphoreComplete + ); +} diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.S b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.S new file mode 100644 index 000000000000..6fcf41a677d6 --- /dev/null +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.S @@ -0,0 +1,191 @@ +#------------------------------------------------------------------------------ +# +# Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# Module Name: +# +# SmiEntry.S +# +# Abstract: +# +# Code template of the SMI handler for a particular processor +# +#------------------------------------------------------------------------------ + +ASM_GLOBAL ASM_PFX(gcSmiHandlerTemplate) +ASM_GLOBAL ASM_PFX(gcSmiHandlerSize) +ASM_GLOBAL ASM_PFX(gSmiCr3) +ASM_GLOBAL ASM_PFX(gSmiStack) +ASM_GLOBAL ASM_PFX(gSmbase) +ASM_GLOBAL ASM_PFX(FeaturePcdGet (PcdCpuSmmDebug)) +ASM_GLOBAL ASM_PFX(FeaturePcdGet (PcdCpuSmmStackGuard)) +ASM_GLOBAL ASM_PFX(gSmiHandlerIdtr) + +.equ DSC_OFFSET, 0xfb00 +.equ DSC_GDTPTR, 0x30 +.equ DSC_GDTSIZ, 0x38 +.equ DSC_CS, 14 +.equ DSC_DS, 16 +.equ DSC_SS, 18 +.equ DSC_OTHERSEG, 20 + +.equ PROTECT_MODE_CS, 0x08 +.equ PROTECT_MODE_DS, 0x20 +.equ TSS_SEGMENT, 0x40 + + .text + +ASM_PFX(gcSmiHandlerTemplate): + +_SmiEntryPoint: + .byte 0xbb # mov bx, imm16 + .word _GdtDesc - _SmiEntryPoint + 0x8000 + .byte 0x2e,0xa1 # mov ax, cs:[offset16] + .word DSC_OFFSET + DSC_GDTSIZ + decl %eax + movl %eax, %cs:(%edi) # mov cs:[bx], ax + .byte 0x66,0x2e,0xa1 # mov eax, cs:[offset16] + .word DSC_OFFSET + DSC_GDTPTR + movw %ax, %cs:2(%edi) + movw %ax, %bp # ebp = GDT base + .byte 0x66 + lgdt %cs:(%edi) +# Patch ProtectedMode Segment + .byte 0xb8 # mov ax, imm16 + .word PROTECT_MODE_CS # set AX for segment directly + movl %eax, %cs:-2(%edi) # mov cs:[bx - 2], ax +# Patch ProtectedMode entry + .byte 0x66, 0xbf # mov edi, SMBASE +ASM_PFX(gSmbase): .space 4 + .byte 0x67 + lea ((Start32bit - _SmiEntryPoint) + 0x8000)(%edi), %ax + movw %ax, %cs:-6(%edi) + movl %cr0, %ebx + .byte 0x66 + andl $0x9ffafff3, %ebx + .byte 0x66 + orl $0x23, %ebx + movl %ebx, %cr0 + .byte 0x66,0xea + .space 4 + .space 2 +_GdtDesc: .space 4 + .space 2 + +Start32bit: + movw $PROTECT_MODE_DS, %ax + movl %eax,%ds + movl %eax,%es + movl %eax,%fs + movl %eax,%gs + movl %eax,%ss + .byte 0xbc # mov esp, imm32 +ASM_PFX(gSmiStack): .space 4 + movl $ASM_PFX(gSmiHandlerIdtr), %eax + lidt (%eax) + jmp ProtFlatMode + +ProtFlatMode: + .byte 0xb8 # mov eax, imm32 +ASM_PFX(gSmiCr3): .space 4 + movl %eax, %cr3 +# +# Need to test for CR4 specific bit support +# + movl $1, %eax + cpuid # use CPUID to determine if specific CR4 bits are supported + xorl %eax, %eax # Clear EAX + testl $BIT2, %edx # Check for DE capabilities + jz L8 + orl $BIT3, %eax +L8: + testl $BIT6, %edx # Check for PAE capabilities + jz L9 + orl $BIT5, %eax +L9: + testl $BIT7, %edx # Check for MCE capabilities + jz L10 + orl $BIT6, %eax +L10: + testl $BIT24, %edx # Check for FXSR capabilities + jz L11 + orl $BIT9, %eax +L11: + testl $BIT25, %edx # Check for SSE capabilities + jz L12 + orl $BIT10, %eax +L12: # as cr4.PGE is not set here, refresh cr3 + movl %eax, %cr4 # in PreModifyMtrrs() to flush TLB. + movl %cr0, %ebx + orl $0x080000000, %ebx # enable paging + movl %ebx, %cr0 + leal DSC_OFFSET(%edi),%ebx + movw DSC_DS(%ebx),%ax + movl %eax, %ds + movw DSC_OTHERSEG(%ebx),%ax + movl %eax, %es + movl %eax, %fs + movl %eax, %gs + movw DSC_SS(%ebx),%ax + movl %eax, %ss + + cmpb $0, ASM_PFX(FeaturePcdGet (PcdCpuSmmStackGuard)) + jz L5 + +# Load TSS + movb $0x89, (TSS_SEGMENT + 5)(%ebp) # clear busy flag + movl $TSS_SEGMENT, %eax + ltrw %ax +L5: + +# jmp _SmiHandler # instruction is not needed + +_SmiHandler: + cmpb $0, ASM_PFX(FeaturePcdGet (PcdCpuSmmDebug)) + jz L3 + +L6: + call L1 +L1: + popl %ebp + movl $0x80000001, %eax + cpuid + btl $29, %edx # check cpuid to identify X64 or IA32 + leal (0x7fc8 - (L1 - _SmiEntryPoint))(%ebp), %edi + leal 4(%edi), %esi + jnc L2 + addl $4, %esi +L2: + movl (%esi), %ecx + movl (%edi), %edx +L7: + movl %ecx, %dr6 + movl %edx, %dr7 # restore DR6 & DR7 before running C code +L3: + + pushl (%esp) + + movl $ASM_PFX(SmiRendezvous), %eax + call *%eax + popl %ecx + + + cmpb $0, ASM_PFX(FeaturePcdGet (PcdCpuSmmDebug)) + jz L4 + + movl %dr6, %ecx + movl %dr7, %edx + movl %ecx, (%esi) + movl %edx, (%edi) +L4: + + rsm + +ASM_PFX(gcSmiHandlerSize): .word . - _SmiEntryPoint diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.asm b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.asm new file mode 100644 index 000000000000..b628fe8bd88c --- /dev/null +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.asm @@ -0,0 +1,193 @@ +;------------------------------------------------------------------------------ ; +; Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.
+; This program and the accompanying materials +; are licensed and made available under the terms and conditions of the BSD License +; which accompanies this distribution. The full text of the license may be found at +; http://opensource.org/licenses/bsd-license.php. +; +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +; +; Module Name: +; +; SmiEntry.asm +; +; Abstract: +; +; Code template of the SMI handler for a particular processor +; +;------------------------------------------------------------------------------- + + .686p + .model flat,C + .xmm + +DSC_OFFSET EQU 0fb00h +DSC_GDTPTR EQU 30h +DSC_GDTSIZ EQU 38h +DSC_CS EQU 14 +DSC_DS EQU 16 +DSC_SS EQU 18 +DSC_OTHERSEG EQU 20 + +PROTECT_MODE_CS EQU 08h +PROTECT_MODE_DS EQU 20h +TSS_SEGMENT EQU 40h + +SmiRendezvous PROTO C + +EXTERNDEF gcSmiHandlerTemplate:BYTE +EXTERNDEF gcSmiHandlerSize:WORD +EXTERNDEF gSmiCr3:DWORD +EXTERNDEF gSmiStack:DWORD +EXTERNDEF gSmbase:DWORD +EXTERNDEF FeaturePcdGet (PcdCpuSmmDebug):BYTE +EXTERNDEF FeaturePcdGet (PcdCpuSmmStackGuard):BYTE +EXTERNDEF gSmiHandlerIdtr:FWORD + + .code + +gcSmiHandlerTemplate LABEL BYTE + +_SmiEntryPoint: + DB 0bbh ; mov bx, imm16 + DW offset _GdtDesc - _SmiEntryPoint + 8000h + DB 2eh, 0a1h ; mov ax, cs:[offset16] + DW DSC_OFFSET + DSC_GDTSIZ + dec eax + mov cs:[edi], eax ; mov cs:[bx], ax + DB 66h, 2eh, 0a1h ; mov eax, cs:[offset16] + DW DSC_OFFSET + DSC_GDTPTR + mov cs:[edi + 2], ax ; mov cs:[bx + 2], eax + mov bp, ax ; ebp = GDT base + DB 66h + lgdt fword ptr cs:[edi] ; lgdt fword ptr cs:[bx] +; Patch ProtectedMode Segment + DB 0b8h ; mov ax, imm16 + DW PROTECT_MODE_CS ; set AX for segment directly + mov cs:[edi - 2], eax ; mov cs:[bx - 2], ax +; Patch ProtectedMode entry + DB 66h, 0bfh ; mov edi, SMBASE +gSmbase DD ? + DB 67h + lea ax, [edi + (@32bit - _SmiEntryPoint) + 8000h] + mov cs:[edi - 6], ax ; mov cs:[bx - 6], eax + mov ebx, cr0 + DB 66h + and ebx, 9ffafff3h + DB 66h + or ebx, 23h + mov cr0, ebx + DB 66h, 0eah + DD ? + DW ? +_GdtDesc FWORD ? + +@32bit: + mov ax, PROTECT_MODE_DS + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + DB 0bch ; mov esp, imm32 +gSmiStack DD ? + mov eax, offset gSmiHandlerIdtr + lidt fword ptr [eax] + jmp ProtFlatMode + +ProtFlatMode: + DB 0b8h ; mov eax, imm32 +gSmiCr3 DD ? + mov cr3, eax +; +; Need to test for CR4 specific bit support +; + mov eax, 1 + cpuid ; use CPUID to determine if specific CR4 bits are supported + xor eax, eax ; Clear EAX + test edx, BIT2 ; Check for DE capabilities + jz @f + or eax, BIT3 +@@: + test edx, BIT6 ; Check for PAE capabilities + jz @f + or eax, BIT5 +@@: + test edx, BIT7 ; Check for MCE capabilities + jz @f + or eax, BIT6 +@@: + test edx, BIT24 ; Check for FXSR capabilities + jz @f + or eax, BIT9 +@@: + test edx, BIT25 ; Check for SSE capabilities + jz @f + or eax, BIT10 +@@: ; as cr4.PGE is not set here, refresh cr3 + mov cr4, eax ; in PreModifyMtrrs() to flush TLB. + mov ebx, cr0 + or ebx, 080000000h ; enable paging + mov cr0, ebx + lea ebx, [edi + DSC_OFFSET] + mov ax, [ebx + DSC_DS] + mov ds, eax + mov ax, [ebx + DSC_OTHERSEG] + mov es, eax + mov fs, eax + mov gs, eax + mov ax, [ebx + DSC_SS] + mov ss, eax + + cmp FeaturePcdGet (PcdCpuSmmStackGuard), 0 + jz @F + +; Load TSS + mov byte ptr [ebp + TSS_SEGMENT + 5], 89h ; clear busy flag + mov eax, TSS_SEGMENT + ltr ax +@@: +; jmp _SmiHandler ; instruction is not needed + +_SmiHandler PROC + cmp FeaturePcdGet (PcdCpuSmmDebug), 0 + jz @3 + call @1 +@1: + pop ebp + mov eax, 80000001h + cpuid + bt edx, 29 ; check cpuid to identify X64 or IA32 + lea edi, [ebp - (@1 - _SmiEntryPoint) + 7fc8h] + lea esi, [edi + 4] + jnc @2 + add esi, 4 +@2: + mov ecx, [esi] + mov edx, [edi] +@5: + mov dr6, ecx + mov dr7, edx ; restore DR6 & DR7 before running C code +@3: + mov ecx, [esp] ; CPU Index + + push ecx + mov eax, SmiRendezvous + call eax + pop ecx + + cmp FeaturePcdGet (PcdCpuSmmDebug), 0 + jz @4 + + mov ecx, dr6 + mov edx, dr7 + mov [esi], ecx + mov [edi], edx +@4: + rsm +_SmiHandler ENDP + +gcSmiHandlerSize DW $ - _SmiEntryPoint + + END diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.S b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.S new file mode 100644 index 000000000000..69dfd946de48 --- /dev/null +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.S @@ -0,0 +1,911 @@ +#------------------------------------------------------------------------------ +# +# Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# Module Name: +# +# SmiException.S +# +# Abstract: +# +# Exception handlers used in SM mode +# +#------------------------------------------------------------------------------ + +ASM_GLOBAL ASM_PFX(SmiPFHandler) +ASM_GLOBAL ASM_PFX(PageFaultStubFunction) +ASM_GLOBAL ASM_PFX(gSmiMtrrs) +ASM_GLOBAL ASM_PFX(gcSmiIdtr) +ASM_GLOBAL ASM_PFX(gcSmiGdtr) +ASM_GLOBAL ASM_PFX(gcPsd) +ASM_GLOBAL ASM_PFX(FeaturePcdGet (PcdCpuSmmProfileEnable)) + + .data + +NullSeg: .quad 0 # reserved by architecture +CodeSeg32: + .word -1 # LimitLow + .word 0 # BaseLow + .byte 0 # BaseMid + .byte 0x9b + .byte 0xcf # LimitHigh + .byte 0 # BaseHigh +ProtModeCodeSeg32: + .word -1 # LimitLow + .word 0 # BaseLow + .byte 0 # BaseMid + .byte 0x9b + .byte 0xcf # LimitHigh + .byte 0 # BaseHigh +ProtModeSsSeg32: + .word -1 # LimitLow + .word 0 # BaseLow + .byte 0 # BaseMid + .byte 0x93 + .byte 0xcf # LimitHigh + .byte 0 # BaseHigh +DataSeg32: + .word -1 # LimitLow + .word 0 # BaseLow + .byte 0 # BaseMid + .byte 0x93 + .byte 0xcf # LimitHigh + .byte 0 # BaseHigh +CodeSeg16: + .word -1 + .word 0 + .byte 0 + .byte 0x9b + .byte 0x8f + .byte 0 +DataSeg16: + .word -1 + .word 0 + .byte 0 + .byte 0x93 + .byte 0x8f + .byte 0 +CodeSeg64: + .word -1 # LimitLow + .word 0 # BaseLow + .byte 0 # BaseMid + .byte 0x9b + .byte 0xaf # LimitHigh + .byte 0 # BaseHigh +.equ GDT_SIZE, .- NullSeg + +TssSeg: + .word TSS_DESC_SIZE # LimitLow + .word 0 # BaseLow + .byte 0 # BaseMid + .byte 0x89 + .byte 0x80 # LimitHigh + .byte 0 # BaseHigh +ExceptionTssSeg: + .word TSS_DESC_SIZE # LimitLow + .word 0 # BaseLow + .byte 0 # BaseMid + .byte 0x89 + .byte 0x80 # LimitHigh + .byte 0 # BaseHigh + +.equ CODE_SEL, CodeSeg32 - NullSeg +.equ DATA_SEL, DataSeg32 - NullSeg +.equ TSS_SEL, TssSeg - NullSeg +.equ EXCEPTION_TSS_SEL, ExceptionTssSeg - NullSeg + +# IA32 TSS fields +.equ TSS_ESP0, 4 +.equ TSS_SS0, 8 +.equ TSS_ESP1, 12 +.equ TSS_SS1, 16 +.equ TSS_ESP2, 20 +.equ TSS_SS2, 24 +.equ TSS_CR3, 28 +.equ TSS_EIP, 32 +.equ TSS_EFLAGS, 36 +.equ TSS_EAX, 40 +.equ TSS_ECX, 44 +.equ TSS_EDX, 48 +.equ TSS_EBX, 52 +.equ TSS_ESP, 56 +.equ TSS_EBP, 60 +.equ TSS_ESI, 64 +.equ TSS_EDI, 68 +.equ TSS_ES, 72 +.equ TSS_CS, 76 +.equ TSS_SS, 80 +.equ TSS_DS, 84 +.equ TSS_FS, 88 +.equ TSS_GS, 92 +.equ TSS_LDT, 96 + +# Create 2 TSS segments just after GDT +TssDescriptor: + .word 0 # PreviousTaskLink + .word 0 # Reserved + .long 0 # ESP0 + .word 0 # SS0 + .word 0 # Reserved + .long 0 # ESP1 + .word 0 # SS1 + .word 0 # Reserved + .long 0 # ESP2 + .word 0 # SS2 + .word 0 # Reserved + .long 0 # CR3 + .long 0 # EIP + .long 0 # EFLAGS + .long 0 # EAX + .long 0 # ECX + .long 0 # EDX + .long 0 # EBX + .long 0 # ESP + .long 0 # EBP + .long 0 # ESI + .long 0 # EDI + .word 0 # ES + .word 0 # Reserved + .word 0 # CS + .word 0 # Reserved + .word 0 # SS + .word 0 # Reserved + .word 0 # DS + .word 0 # Reserved + .word 0 # FS + .word 0 # Reserved + .word 0 # GS + .word 0 # Reserved + .word 0 # LDT Selector + .word 0 # Reserved + .word 0 # T + .word 0 # I/O Map Base +.equ TSS_DESC_SIZE, . - TssDescriptor + +ExceptionTssDescriptor: + .word 0 # PreviousTaskLink + .word 0 # Reserved + .long 0 # ESP0 + .word 0 # SS0 + .word 0 # Reserved + .long 0 # ESP1 + .word 0 # SS1 + .word 0 # Reserved + .long 0 # ESP2 + .word 0 # SS2 + .word 0 # Reserved + .long 0 # CR3 + .long PFHandlerEntry # EIP + .long 00000002 # EFLAGS + .long 0 # EAX + .long 0 # ECX + .long 0 # EDX + .long 0 # EBX + .long 0 # ESP + .long 0 # EBP + .long 0 # ESI + .long 0 # EDI + .word DATA_SEL # ES + .word 0 # Reserved + .word CODE_SEL # CS + .word 0 # Reserved + .word DATA_SEL # SS + .word 0 # Reserved + .word DATA_SEL # DS + .word 0 # Reserved + .word DATA_SEL # FS + .word 0 # Reserved + .word DATA_SEL # GS + .word 0 # Reserved + .word 0 # LDT Selector + .word 0 # Reserved + .word 0 # T + .word 0 # I/O Map Base + +ASM_PFX(gcPsd): + .ascii "PSDSIG " + .word PSD_SIZE + .word 2 + .word 1 << 2 + .word CODE_SEL + .word DATA_SEL + .word DATA_SEL + .word DATA_SEL + .word 0 + .long 0 + .long 0 + .long 0 + .long 0 + .quad 0 + .long NullSeg + .long 0 + .long GDT_SIZE + .long 0 + .space 24, 0 + .long ASM_PFX(gSmiMtrrs) + .long 0 +.equ PSD_SIZE, . - ASM_PFX(gcPsd) + +ASM_PFX(gcSmiGdtr): .word GDT_SIZE - 1 + .long NullSeg + +ASM_PFX(gcSmiIdtr): .word IDT_SIZE - 1 + .long _SmiIDT + +_SmiIDT: +# The following segment repeats 32 times: +# No. 1 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 +# No. 2 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 +# No. 3 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 +# No. 4 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 +# No. 5 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 +# No. 6 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 +# No. 7 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 +# No. 8 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 +# No. 9 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 +# No. 10 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 +# No. 11 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 +# No. 12 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 +# No. 13 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 +# No. 14 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 +# No. 15 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 +# No. 16 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 +# No. 17 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 +# No. 18 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 +# No. 19 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 +# No. 20 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 +# No. 21 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 +# No. 22 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 +# No. 23 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 +# No. 24 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 +# No. 25 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 +# No. 26 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 +# No. 27 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 +# No. 28 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 +# No. 29 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 +# No. 30 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 +# No. 31 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 +# No. 32 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 + +.equ IDT_SIZE, . - _SmiIDT + +TaskGateDescriptor: + .word 0 # Reserved + .word EXCEPTION_TSS_SEL # TSS Segment selector + .byte 0 # Reserved + .byte 0x85 # Task Gate, present, DPL = 0 + .word 0 # Reserved + + .text + +#------------------------------------------------------------------------------ +# PageFaultIdtHandlerSmmProfile is the entry point for all exceptions +# +# Stack: +#+---------------------+ +#+ EFlags + +#+---------------------+ +#+ CS + +#+---------------------+ +#+ EIP + +#+---------------------+ +#+ Error Code + +#+---------------------+ +#+ Vector Number + +#+---------------------+ +#+ EBP + +#+---------------------+ <-- EBP +# +# RSP set to odd multiple of 8 means ErrCode PRESENT +#------------------------------------------------------------------------------ +ASM_GLOBAL ASM_PFX(PageFaultIdtHandlerSmmProfile) +ASM_PFX(PageFaultIdtHandlerSmmProfile): + pushl $0x0e # Page Fault + pushl %ebp + movl %esp, %ebp + + + # + # Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32 + # is 16-byte aligned + # + andl $0xfffffff0, %esp + subl $12, %esp + +## UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax; + pushl %eax + pushl %ecx + pushl %edx + pushl %ebx + leal (6*4)(%ebp), %ecx + pushl %ecx # ESP + pushl (%ebp) # EBP + pushl %esi + pushl %edi + +## UINT32 Gs, Fs, Es, Ds, Cs, Ss; + movl %ss, %eax + pushl %eax + movzwl (4*4)(%ebp), %eax + pushl %eax + movl %ds, %eax + pushl %eax + movl %es, %eax + pushl %eax + movl %fs, %eax + pushl %eax + movl %gs, %eax + pushl %eax + +## UINT32 Eip; + movl (3*4)(%ebp), %eax + pushl %eax + +## UINT32 Gdtr[2], Idtr[2]; + subl $8, %esp + sidt (%esp) + movl 2(%esp), %eax + xchgl (%esp), %eax + andl $0xffff, %eax + movl %eax, 4(%esp) + + subl $8, %esp + sgdt (%esp) + movl 2(%esp), %eax + xchgl (%esp), %eax + andl $0xffff, %eax + movl %eax, 4(%esp) + +## UINT32 Ldtr, Tr; + xorl %eax, %eax + strw %ax + pushl %eax + sldtw %ax + pushl %eax + +## UINT32 EFlags; + movl (5*4)(%ebp), %eax + pushl %eax + +## UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; + movl %cr4, %eax + orl $0x208, %eax + movl %eax, %cr4 + pushl %eax + movl %cr3, %eax + pushl %eax + movl %cr2, %eax + pushl %eax + xorl %eax, %eax + pushl %eax + movl %cr0, %eax + pushl %eax + +## UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; + movl %dr7, %eax + pushl %eax + movl %dr6, %eax + pushl %eax + movl %dr3, %eax + pushl %eax + movl %dr2, %eax + pushl %eax + movl %dr1, %eax + pushl %eax + movl %dr0, %eax + pushl %eax + +## FX_SAVE_STATE_IA32 FxSaveState; + subl $512, %esp + movl %esp, %edi + .byte 0x0f, 0xae, 0x07 #fxsave [edi] + +# UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear + cld + +## UINT32 ExceptionData; + pushl (2*4)(%ebp) + +## call into exception handler + +## Prepare parameter and call + movl %esp, %edx + pushl %edx + movl (1*4)(%ebp), %edx + pushl %edx + + # + # Call External Exception Handler + # + movl $ASM_PFX(SmiPFHandler), %eax + call *%eax + addl $8, %esp + jmp L4 + +L4: +## UINT32 ExceptionData; + addl $4, %esp + +## FX_SAVE_STATE_IA32 FxSaveState; + movl %esp, %esi + .byte 0xf, 0xae, 0xe # fxrstor [esi] + addl $512, %esp + +## UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; +## Skip restoration of DRx registers to support debuggers +## that set breakpoints in interrupt/exception context + addl $4*6, %esp + +## UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; + popl %eax + movl %eax, %cr0 + addl $4, %esp # not for Cr1 + popl %eax + movl %eax, %cr2 + popl %eax + movl %eax, %cr3 + popl %eax + movl %eax, %cr4 + +## UINT32 EFlags; + popl (5*4)(%ebp) + +## UINT32 Ldtr, Tr; +## UINT32 Gdtr[2], Idtr[2]; +## Best not let anyone mess with these particular registers... + addl $24, %esp + +## UINT32 Eip; + popl (3*4)(%ebp) + +## UINT32 Gs, Fs, Es, Ds, Cs, Ss; +## NOTE - modified segment registers could hang the debugger... We +## could attempt to insulate ourselves against this possibility, +## but that poses risks as well. +## + popl %gs + popl %fs + popl %es + popl %ds + popl (4*4)(%ebp) + popl %ss + +## UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax; + popl %edi + popl %esi + addl $4, %esp # not for ebp + addl $4, %esp # not for esp + popl %ebx + popl %edx + popl %ecx + popl %eax + + movl %ebp, %esp + popl %ebp + +# Enable TF bit after page fault handler runs + btsl $8, 16(%esp) # EFLAGS + + addl $8, %esp # skip INT# & ErrCode +Return: + iret +# +# Page Fault Exception Handler entry when SMM Stack Guard is enabled +# Executiot starts here after a task switch +# +PFHandlerEntry: +# +# Get this processor's TSS +# + subl $8, %esp + sgdt 2(%esp) + movl 4(%esp), %eax # GDT base + addl $8, %esp + movl (TSS_SEL+2)(%eax), %ecx + shll $8, %ecx + movb (TSS_SEL+7)(%eax), %cl + rorl $8, %ecx # ecx = TSS base + + movl %esp, %ebp + + # + # Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32 + # is 16-byte aligned + # + andl $0xfffffff0, %esp + subl $12, %esp + +## UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax; + pushl TSS_EAX(%ecx) + pushl TSS_ECX(%ecx) + pushl TSS_EDX(%ecx) + pushl TSS_EBX(%ecx) + pushl TSS_ESP(%ecx) + pushl TSS_EBP(%ecx) + pushl TSS_ESI(%ecx) + pushl TSS_EDI(%ecx) + +## UINT32 Gs, Fs, Es, Ds, Cs, Ss; + movzwl TSS_SS(%ecx), %eax + pushl %eax + movzwl TSS_CS(%ecx), %eax + pushl %eax + movzwl TSS_DS(%ecx), %eax + pushl %eax + movzwl TSS_ES(%ecx), %eax + pushl %eax + movzwl TSS_FS(%ecx), %eax + pushl %eax + movzwl TSS_GS(%ecx), %eax + pushl %eax + +## UINT32 Eip; + pushl TSS_EIP(%ecx) + +## UINT32 Gdtr[2], Idtr[2]; + subl $8, %esp + sidt (%esp) + movl 2(%esp), %eax + xchgl (%esp), %eax + andl $0xFFFF, %eax + movl %eax, 4(%esp) + + subl $8, %esp + sgdt (%esp) + movl 2(%esp), %eax + xchgl (%esp), %eax + andl $0xFFFF, %eax + movl %eax, 4(%esp) + +## UINT32 Ldtr, Tr; + movl $TSS_SEL, %eax + pushl %eax + movzwl TSS_LDT(%ecx), %eax + pushl %eax + +## UINT32 EFlags; + pushl TSS_EFLAGS(%ecx) + +## UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; + movl %cr4, %eax + orl $0x208, %eax + movl %eax, %cr4 + pushl %eax + movl %cr3, %eax + pushl %eax + movl %cr2, %eax + pushl %eax + xorl %eax, %eax + pushl %eax + movl %cr0, %eax + pushl %eax + +## UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; + movl %dr7, %eax + pushl %eax + movl %dr6, %eax + pushl %eax + movl %dr3, %eax + pushl %eax + movl %dr2, %eax + pushl %eax + movl %dr1, %eax + pushl %eax + movl %dr0, %eax + pushl %eax + +## FX_SAVE_STATE_IA32 FxSaveState; +## Clear TS bit in CR0 to avoid Device Not Available Exception (#NM) +## when executing fxsave/fxrstor instruction + clts + subl $512, %esp + movl %esp, %edi + .byte 0x0f, 0xae, 0x07 #fxsave [edi] + +# UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear + cld + +## UINT32 ExceptionData; + pushl (%ebp) + +## call into exception handler + movl %ecx, %ebx + movl $ASM_PFX(SmiPFHandler), %eax + +## Prepare parameter and call + movl %esp, %edx + pushl %edx + movl $14, %edx + pushl %edx + + # + # Call External Exception Handler + # + call *%eax + addl $8, %esp + + movl %ebx, %ecx +## UINT32 ExceptionData; + addl $4, %esp + +## FX_SAVE_STATE_IA32 FxSaveState; + movl %esp, %esi + .byte 0xf, 0xae, 0xe # fxrstor [esi] + addl $512, %esp + +## UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; +## Skip restoration of DRx registers to support debuggers +## that set breakpoints in interrupt/exception context + addl $4*6, %esp + +## UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; + popl %eax + movl %eax, %cr0 + addl $4, %esp # not for Cr1 + popl %eax + movl %eax, %cr2 + popl %eax + movl %eax, TSS_CR3(%ecx) + popl %eax + movl %eax, %cr4 + +## UINT32 EFlags; + popl TSS_EFLAGS(%ecx) + +## UINT32 Ldtr, Tr; +## UINT32 Gdtr[2], Idtr[2]; +## Best not let anyone mess with these particular registers... + addl $24, %esp + +## UINT32 Eip; + popl TSS_EIP(%ecx) + +## UINT32 Gs, Fs, Es, Ds, Cs, Ss; +## NOTE - modified segment registers could hang the debugger... We +## could attempt to insulate ourselves against this possibility, +## but that poses risks as well. +## + popl %eax + movw %ax, TSS_GS(%ecx) + popl %eax + movw %ax, TSS_FS(%ecx) + popl %eax + movw %ax, TSS_ES(%ecx) + popl %eax + movw %ax, TSS_DS(%ecx) + popl %eax + movw %ax, TSS_CS(%ecx) + popl %eax + movw %ax, TSS_SS(%ecx) + +## UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax; + popl TSS_EDI(%ecx) + popl TSS_ESI(%ecx) + addl $4, %esp # not for ebp + addl $4, %esp # not for esp + popl TSS_EBX(%ecx) + popl TSS_EDX(%ecx) + popl TSS_ECX(%ecx) + popl TSS_EAX(%ecx) + + movl %ebp, %esp + +# Set single step DB# if SMM profile is enabled and page fault exception happens + cmpb $0, ASM_PFX(FeaturePcdGet (PcdCpuSmmProfileEnable)) + jz Done2 +# Create return context for iret in stub function + movl TSS_ESP(%ecx), %eax # Get old stack pointer + movl TSS_EIP(%ecx), %ebx + movl %ebx, -0xc(%eax) # create EIP in old stack + movzwl TSS_CS(%ecx), %ebx + movl %ebx, -0x8(%eax) # create CS in old stack + movl TSS_EFLAGS(%ecx), %ebx + btsl $8,%ebx + movl %ebx, -0x4(%eax) # create eflags in old stack + movl TSS_ESP(%ecx), %eax # Get old stack pointer + subl $12, %eax # minus 12 byte + movl %eax, TSS_ESP(%ecx) # Set new stack pointer + +# Replace the EIP of interrupted task with stub function + movl $ASM_PFX(PageFaultStubFunction), %eax + movl %eax, TSS_EIP(%ecx) +# Jump to the iret so next page fault handler as a task will start again after iret. + +Done2: + + addl $4, %esp # skip ErrCode + + jmp Return + +ASM_PFX(PageFaultStubFunction): +# +# we need clean TS bit in CR0 to execute +# x87 FPU/MMX/SSE/SSE2/SSE3/SSSE3/SSE4 instructions. +# + clts + iret + +ASM_GLOBAL ASM_PFX(InitializeIDTSmmStackGuard) +ASM_PFX(InitializeIDTSmmStackGuard): + pushl %ebx +# +# If SMM Stack Guard feature is enabled, the Page Fault Exception entry in IDT +# is a Task Gate Descriptor so that when a Page Fault Exception occurs, +# the processors can use a known good stack in case stack ran out. +# + leal _SmiIDT + 14 * 8, %ebx + leal TaskGateDescriptor, %edx + movl (%edx), %eax + movl %eax, (%ebx) + movl 4(%edx), %eax + movl %eax, 4(%ebx) + + popl %ebx + ret diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.asm b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.asm new file mode 100644 index 000000000000..65a120e1e78a --- /dev/null +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.asm @@ -0,0 +1,738 @@ +;------------------------------------------------------------------------------ ; +; Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.
+; This program and the accompanying materials +; are licensed and made available under the terms and conditions of the BSD License +; which accompanies this distribution. The full text of the license may be found at +; http://opensource.org/licenses/bsd-license.php. +; +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +; +; Module Name: +; +; SmiException.asm +; +; Abstract: +; +; Exception handlers used in SM mode +; +;------------------------------------------------------------------------------- + + .686p + .model flat,C + +EXTERNDEF SmiPFHandler:PROC +EXTERNDEF PageFaultStubFunction:PROC +EXTERNDEF gSmiMtrrs:QWORD +EXTERNDEF gcSmiIdtr:FWORD +EXTERNDEF gcSmiGdtr:FWORD +EXTERNDEF gcPsd:BYTE +EXTERNDEF FeaturePcdGet (PcdCpuSmmProfileEnable):BYTE + + + .data + +NullSeg DQ 0 ; reserved by architecture +CodeSeg32 LABEL QWORD + DW -1 ; LimitLow + DW 0 ; BaseLow + DB 0 ; BaseMid + DB 9bh + DB 0cfh ; LimitHigh + DB 0 ; BaseHigh +ProtModeCodeSeg32 LABEL QWORD + DW -1 ; LimitLow + DW 0 ; BaseLow + DB 0 ; BaseMid + DB 9bh + DB 0cfh ; LimitHigh + DB 0 ; BaseHigh +ProtModeSsSeg32 LABEL QWORD + DW -1 ; LimitLow + DW 0 ; BaseLow + DB 0 ; BaseMid + DB 93h + DB 0cfh ; LimitHigh + DB 0 ; BaseHigh +DataSeg32 LABEL QWORD + DW -1 ; LimitLow + DW 0 ; BaseLow + DB 0 ; BaseMid + DB 93h + DB 0cfh ; LimitHigh + DB 0 ; BaseHigh +CodeSeg16 LABEL QWORD + DW -1 + DW 0 + DB 0 + DB 9bh + DB 8fh + DB 0 +DataSeg16 LABEL QWORD + DW -1 + DW 0 + DB 0 + DB 93h + DB 8fh + DB 0 +CodeSeg64 LABEL QWORD + DW -1 ; LimitLow + DW 0 ; BaseLow + DB 0 ; BaseMid + DB 9bh + DB 0afh ; LimitHigh + DB 0 ; BaseHigh +GDT_SIZE = $ - offset NullSeg + +TssSeg LABEL QWORD + DW TSS_DESC_SIZE ; LimitLow + DW 0 ; BaseLow + DB 0 ; BaseMid + DB 89h + DB 080h ; LimitHigh + DB 0 ; BaseHigh +ExceptionTssSeg LABEL QWORD + DW TSS_DESC_SIZE ; LimitLow + DW 0 ; BaseLow + DB 0 ; BaseMid + DB 89h + DB 080h ; LimitHigh + DB 0 ; BaseHigh + +CODE_SEL = offset CodeSeg32 - offset NullSeg +DATA_SEL = offset DataSeg32 - offset NullSeg +TSS_SEL = offset TssSeg - offset NullSeg +EXCEPTION_TSS_SEL = offset ExceptionTssSeg - offset NullSeg + +IA32_TSS STRUC + DW ? + DW ? + ESP0 DD ? + SS0 DW ? + DW ? + ESP1 DD ? + SS1 DW ? + DW ? + ESP2 DD ? + SS2 DW ? + DW ? + _CR3 DD ? + EIP DD ? + EFLAGS DD ? + _EAX DD ? + _ECX DD ? + _EDX DD ? + _EBX DD ? + _ESP DD ? + _EBP DD ? + _ESI DD ? + _EDI DD ? + _ES DW ? + DW ? + _CS DW ? + DW ? + _SS DW ? + DW ? + _DS DW ? + DW ? + _FS DW ? + DW ? + _GS DW ? + DW ? + LDT DW ? + DW ? + DW ? + DW ? +IA32_TSS ENDS + +; Create 2 TSS segments just after GDT +TssDescriptor LABEL BYTE + DW 0 ; PreviousTaskLink + DW 0 ; Reserved + DD 0 ; ESP0 + DW 0 ; SS0 + DW 0 ; Reserved + DD 0 ; ESP1 + DW 0 ; SS1 + DW 0 ; Reserved + DD 0 ; ESP2 + DW 0 ; SS2 + DW 0 ; Reserved + DD 0 ; CR3 + DD 0 ; EIP + DD 0 ; EFLAGS + DD 0 ; EAX + DD 0 ; ECX + DD 0 ; EDX + DD 0 ; EBX + DD 0 ; ESP + DD 0 ; EBP + DD 0 ; ESI + DD 0 ; EDI + DW 0 ; ES + DW 0 ; Reserved + DW 0 ; CS + DW 0 ; Reserved + DW 0 ; SS + DW 0 ; Reserved + DW 0 ; DS + DW 0 ; Reserved + DW 0 ; FS + DW 0 ; Reserved + DW 0 ; GS + DW 0 ; Reserved + DW 0 ; LDT Selector + DW 0 ; Reserved + DW 0 ; T + DW 0 ; I/O Map Base +TSS_DESC_SIZE = $ - offset TssDescriptor + +ExceptionTssDescriptor LABEL BYTE + DW 0 ; PreviousTaskLink + DW 0 ; Reserved + DD 0 ; ESP0 + DW 0 ; SS0 + DW 0 ; Reserved + DD 0 ; ESP1 + DW 0 ; SS1 + DW 0 ; Reserved + DD 0 ; ESP2 + DW 0 ; SS2 + DW 0 ; Reserved + DD 0 ; CR3 + DD offset PFHandlerEntry ; EIP + DD 00000002 ; EFLAGS + DD 0 ; EAX + DD 0 ; ECX + DD 0 ; EDX + DD 0 ; EBX + DD 0 ; ESP + DD 0 ; EBP + DD 0 ; ESI + DD 0 ; EDI + DW DATA_SEL ; ES + DW 0 ; Reserved + DW CODE_SEL ; CS + DW 0 ; Reserved + DW DATA_SEL ; SS + DW 0 ; Reserved + DW DATA_SEL ; DS + DW 0 ; Reserved + DW DATA_SEL ; FS + DW 0 ; Reserved + DW DATA_SEL ; GS + DW 0 ; Reserved + DW 0 ; LDT Selector + DW 0 ; Reserved + DW 0 ; T + DW 0 ; I/O Map Base + +gcPsd LABEL BYTE + DB 'PSDSIG ' + DW PSD_SIZE + DW 2 + DW 1 SHL 2 + DW CODE_SEL + DW DATA_SEL + DW DATA_SEL + DW DATA_SEL + DW 0 + DQ 0 + DQ 0 + DQ 0 + DQ offset NullSeg + DD GDT_SIZE + DD 0 + DB 24 dup (0) + DQ offset gSmiMtrrs +PSD_SIZE = $ - offset gcPsd + +gcSmiGdtr LABEL FWORD + DW GDT_SIZE - 1 + DD offset NullSeg + +gcSmiIdtr LABEL FWORD + DW IDT_SIZE - 1 + DD offset _SmiIDT + +_SmiIDT LABEL QWORD +REPEAT 32 + DW 0 ; Offset 0:15 + DW CODE_SEL ; Segment selector + DB 0 ; Unused + DB 8eh ; Interrupt Gate, Present + DW 0 ; Offset 16:31 + ENDM +IDT_SIZE = $ - offset _SmiIDT + +TaskGateDescriptor LABEL DWORD + DW 0 ; Reserved + DW EXCEPTION_TSS_SEL ; TSS Segment selector + DB 0 ; Reserved + DB 85h ; Task Gate, present, DPL = 0 + DW 0 ; Reserved + + + .code +;------------------------------------------------------------------------------ +; PageFaultIdtHandlerSmmProfile is the entry point page fault only +; +; +; Stack: +; +---------------------+ +; + EFlags + +; +---------------------+ +; + CS + +; +---------------------+ +; + EIP + +; +---------------------+ +; + Error Code + +; +---------------------+ +; + Vector Number + +; +---------------------+ +; + EBP + +; +---------------------+ <-- EBP +; +; +;------------------------------------------------------------------------------ +PageFaultIdtHandlerSmmProfile PROC + push 0eh ; Page Fault + + push ebp + mov ebp, esp + + + ; + ; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32 + ; is 16-byte aligned + ; + and esp, 0fffffff0h + sub esp, 12 + +;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax; + push eax + push ecx + push edx + push ebx + lea ecx, [ebp + 6 * 4] + push ecx ; ESP + push dword ptr [ebp] ; EBP + push esi + push edi + +;; UINT32 Gs, Fs, Es, Ds, Cs, Ss; + mov eax, ss + push eax + movzx eax, word ptr [ebp + 4 * 4] + push eax + mov eax, ds + push eax + mov eax, es + push eax + mov eax, fs + push eax + mov eax, gs + push eax + +;; UINT32 Eip; + mov eax, [ebp + 3 * 4] + push eax + +;; UINT32 Gdtr[2], Idtr[2]; + sub esp, 8 + sidt [esp] + mov eax, [esp + 2] + xchg eax, [esp] + and eax, 0FFFFh + mov [esp+4], eax + + sub esp, 8 + sgdt [esp] + mov eax, [esp + 2] + xchg eax, [esp] + and eax, 0FFFFh + mov [esp+4], eax + +;; UINT32 Ldtr, Tr; + xor eax, eax + str ax + push eax + sldt ax + push eax + +;; UINT32 EFlags; + mov eax, [ebp + 5 * 4] + push eax + +;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; + mov eax, cr4 + or eax, 208h + mov cr4, eax + push eax + mov eax, cr3 + push eax + mov eax, cr2 + push eax + xor eax, eax + push eax + mov eax, cr0 + push eax + +;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; + mov eax, dr7 + push eax + mov eax, dr6 + push eax + mov eax, dr3 + push eax + mov eax, dr2 + push eax + mov eax, dr1 + push eax + mov eax, dr0 + push eax + +;; FX_SAVE_STATE_IA32 FxSaveState; + sub esp, 512 + mov edi, esp + db 0fh, 0aeh, 07h ;fxsave [edi] + +; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear + cld + +;; UINT32 ExceptionData; + push dword ptr [ebp + 2 * 4] + +;; call into exception handler + +;; Prepare parameter and call + mov edx, esp + push edx + mov edx, dword ptr [ebp + 1 * 4] + push edx + + ; + ; Call External Exception Handler + ; + mov eax, SmiPFHandler + call eax + add esp, 8 + +;; UINT32 ExceptionData; + add esp, 4 + +;; FX_SAVE_STATE_IA32 FxSaveState; + mov esi, esp + db 0fh, 0aeh, 0eh ; fxrstor [esi] + add esp, 512 + +;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; +;; Skip restoration of DRx registers to support debuggers +;; that set breakpoint in interrupt/exception context + add esp, 4 * 6 + +;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; + pop eax + mov cr0, eax + add esp, 4 ; not for Cr1 + pop eax + mov cr2, eax + pop eax + mov cr3, eax + pop eax + mov cr4, eax + +;; UINT32 EFlags; + pop dword ptr [ebp + 5 * 4] + +;; UINT32 Ldtr, Tr; +;; UINT32 Gdtr[2], Idtr[2]; +;; Best not let anyone mess with these particular registers... + add esp, 24 + +;; UINT32 Eip; + pop dword ptr [ebp + 3 * 4] + +;; UINT32 Gs, Fs, Es, Ds, Cs, Ss; +;; NOTE - modified segment registers could hang the debugger... We +;; could attempt to insulate ourselves against this possibility, +;; but that poses risks as well. +;; + pop gs + pop fs + pop es + pop ds + pop dword ptr [ebp + 4 * 4] + pop ss + +;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax; + pop edi + pop esi + add esp, 4 ; not for ebp + add esp, 4 ; not for esp + pop ebx + pop edx + pop ecx + pop eax + + mov esp, ebp + pop ebp + +; Enable TF bit after page fault handler runs + bts dword ptr [esp + 16], 8 ; EFLAGS + + add esp, 8 ; skip INT# & ErrCode +Return: + iretd +; +; Page Fault Exception Handler entry when SMM Stack Guard is enabled +; Executiot starts here after a task switch +; +PFHandlerEntry:: +; +; Get this processor's TSS +; + sub esp, 8 + sgdt [esp + 2] + mov eax, [esp + 4] ; GDT base + add esp, 8 + mov ecx, [eax + TSS_SEL + 2] + shl ecx, 8 + mov cl, [eax + TSS_SEL + 7] + ror ecx, 8 ; ecx = TSS base + + mov ebp, esp + + ; + ; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32 + ; is 16-byte aligned + ; + and esp, 0fffffff0h + sub esp, 12 + +;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax; + push (IA32_TSS ptr [ecx])._EAX + push (IA32_TSS ptr [ecx])._ECX + push (IA32_TSS ptr [ecx])._EDX + push (IA32_TSS ptr [ecx])._EBX + push (IA32_TSS ptr [ecx])._ESP + push (IA32_TSS ptr [ecx])._EBP + push (IA32_TSS ptr [ecx])._ESI + push (IA32_TSS ptr [ecx])._EDI + +;; UINT32 Gs, Fs, Es, Ds, Cs, Ss; + movzx eax, (IA32_TSS ptr [ecx])._SS + push eax + movzx eax, (IA32_TSS ptr [ecx])._CS + push eax + movzx eax, (IA32_TSS ptr [ecx])._DS + push eax + movzx eax, (IA32_TSS ptr [ecx])._ES + push eax + movzx eax, (IA32_TSS ptr [ecx])._FS + push eax + movzx eax, (IA32_TSS ptr [ecx])._GS + push eax + +;; UINT32 Eip; + push (IA32_TSS ptr [ecx]).EIP + +;; UINT32 Gdtr[2], Idtr[2]; + sub esp, 8 + sidt [esp] + mov eax, [esp + 2] + xchg eax, [esp] + and eax, 0FFFFh + mov [esp+4], eax + + sub esp, 8 + sgdt [esp] + mov eax, [esp + 2] + xchg eax, [esp] + and eax, 0FFFFh + mov [esp+4], eax + +;; UINT32 Ldtr, Tr; + mov eax, TSS_SEL + push eax + movzx eax, (IA32_TSS ptr [ecx]).LDT + push eax + +;; UINT32 EFlags; + push (IA32_TSS ptr [ecx]).EFLAGS + +;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; + mov eax, cr4 + or eax, 208h + mov cr4, eax + push eax + mov eax, cr3 + push eax + mov eax, cr2 + push eax + xor eax, eax + push eax + mov eax, cr0 + push eax + +;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; + mov eax, dr7 + push eax + mov eax, dr6 + push eax + mov eax, dr3 + push eax + mov eax, dr2 + push eax + mov eax, dr1 + push eax + mov eax, dr0 + push eax + +;; FX_SAVE_STATE_IA32 FxSaveState; +;; Clear TS bit in CR0 to avoid Device Not Available Exception (#NM) +;; when executing fxsave/fxrstor instruction + clts + sub esp, 512 + mov edi, esp + db 0fh, 0aeh, 07h ;fxsave [edi] + +; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear + cld + +;; UINT32 ExceptionData; + push dword ptr [ebp] + +;; call into exception handler + mov ebx, ecx + mov eax, SmiPFHandler + +;; Prepare parameter and call + mov edx, esp + push edx + mov edx, 14 + push edx + + ; + ; Call External Exception Handler + ; + call eax + add esp, 8 + + mov ecx, ebx +;; UINT32 ExceptionData; + add esp, 4 + +;; FX_SAVE_STATE_IA32 FxSaveState; + mov esi, esp + db 0fh, 0aeh, 0eh ; fxrstor [esi] + add esp, 512 + +;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; +;; Skip restoration of DRx registers to support debuggers +;; that set breakpoints in interrupt/exception context + add esp, 4 * 6 + +;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; + pop eax + mov cr0, eax + add esp, 4 ; not for Cr1 + pop eax + mov cr2, eax + pop eax + mov (IA32_TSS ptr [ecx])._CR3, eax + pop eax + mov cr4, eax + +;; UINT32 EFlags; + pop (IA32_TSS ptr [ecx]).EFLAGS + +;; UINT32 Ldtr, Tr; +;; UINT32 Gdtr[2], Idtr[2]; +;; Best not let anyone mess with these particular registers... + add esp, 24 + +;; UINT32 Eip; + pop (IA32_TSS ptr [ecx]).EIP + +;; UINT32 Gs, Fs, Es, Ds, Cs, Ss; +;; NOTE - modified segment registers could hang the debugger... We +;; could attempt to insulate ourselves against this possibility, +;; but that poses risks as well. +;; + pop eax + mov (IA32_TSS ptr [ecx])._GS, ax + pop eax + mov (IA32_TSS ptr [ecx])._FS, ax + pop eax + mov (IA32_TSS ptr [ecx])._ES, ax + pop eax + mov (IA32_TSS ptr [ecx])._DS, ax + pop eax + mov (IA32_TSS ptr [ecx])._CS, ax + pop eax + mov (IA32_TSS ptr [ecx])._SS, ax + +;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax; + pop (IA32_TSS ptr [ecx])._EDI + pop (IA32_TSS ptr [ecx])._ESI + add esp, 4 ; not for ebp + add esp, 4 ; not for esp + pop (IA32_TSS ptr [ecx])._EBX + pop (IA32_TSS ptr [ecx])._EDX + pop (IA32_TSS ptr [ecx])._ECX + pop (IA32_TSS ptr [ecx])._EAX + + mov esp, ebp + +; Set single step DB# if SMM profile is enabled and page fault exception happens + cmp FeaturePcdGet (PcdCpuSmmProfileEnable), 0 + jz @Done2 + +; Create return context for iretd in stub function + mov eax, (IA32_TSS ptr [ecx])._ESP ; Get old stack pointer + mov ebx, (IA32_TSS ptr [ecx]).EIP + mov [eax - 0ch], ebx ; create EIP in old stack + movzx ebx, (IA32_TSS ptr [ecx])._CS + mov [eax - 08h], ebx ; create CS in old stack + mov ebx, (IA32_TSS ptr [ecx]).EFLAGS + bts ebx, 8 + mov [eax - 04h], ebx ; create eflags in old stack + mov eax, (IA32_TSS ptr [ecx])._ESP ; Get old stack pointer + sub eax, 0ch ; minus 12 byte + mov (IA32_TSS ptr [ecx])._ESP, eax ; Set new stack pointer +; Replace the EIP of interrupted task with stub function + mov eax, PageFaultStubFunction + mov (IA32_TSS ptr [ecx]).EIP, eax +; Jump to the iretd so next page fault handler as a task will start again after iretd. +@Done2: + add esp, 4 ; skip ErrCode + + jmp Return +PageFaultIdtHandlerSmmProfile ENDP + +PageFaultStubFunction PROC +; +; we need clean TS bit in CR0 to execute +; x87 FPU/MMX/SSE/SSE2/SSE3/SSSE3/SSE4 instructions. +; + clts + iretd +PageFaultStubFunction ENDP + +InitializeIDTSmmStackGuard PROC USES ebx +; +; If SMM Stack Guard feature is enabled, the Page Fault Exception entry in IDT +; is a Task Gate Descriptor so that when a Page Fault Exception occurs, +; the processors can use a known good stack in case stack is ran out. +; + lea ebx, _SmiIDT + 14 * 8 + lea edx, TaskGateDescriptor + mov eax, [edx] + mov [ebx], eax + mov eax, [edx + 4] + mov [ebx + 4], eax + ret +InitializeIDTSmmStackGuard ENDP + + END diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmmInit.S b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmmInit.S new file mode 100644 index 000000000000..e8db33a45a4d --- /dev/null +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmmInit.S @@ -0,0 +1,84 @@ +#------------------------------------------------------------------------------ +# +# Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# Module Name: +# +# SmmInit.S +# +# Abstract: +# +# Functions for relocating SMBASE's for all processors +# +#------------------------------------------------------------------------------ + +ASM_GLOBAL ASM_PFX(gSmmCr0) +ASM_GLOBAL ASM_PFX(gSmmCr3) +ASM_GLOBAL ASM_PFX(gSmmCr4) +ASM_GLOBAL ASM_PFX(gcSmmInitTemplate) +ASM_GLOBAL ASM_PFX(gcSmmInitSize) +ASM_GLOBAL ASM_PFX(gSmmJmpAddr) +ASM_GLOBAL ASM_PFX(SmmRelocationSemaphoreComplete) +ASM_GLOBAL ASM_PFX(gSmmInitStack) +ASM_GLOBAL ASM_PFX(gcSmiInitGdtr) + +.equ PROTECT_MODE_CS, 0x08 +.equ PROTECT_MODE_DS, 0x20 + + .text + +ASM_PFX(gcSmiInitGdtr): + .word 0 + .quad 0 + +SmmStartup: + .byte 0x66,0xb8 +ASM_PFX(gSmmCr3): .space 4 + movl %eax, %cr3 + .byte 0x67,0x66 + lgdt %cs:(ASM_PFX(gcSmiInitGdtr) - SmmStartup)(%ebp) + .byte 0x66,0xb8 +ASM_PFX(gSmmCr4): .space 4 + movl %eax, %cr4 + .byte 0x66,0xb8 +ASM_PFX(gSmmCr0): .space 4 + .byte 0xbf, PROTECT_MODE_DS, 0 # mov di, PROTECT_MODE_DS + movl %eax, %cr0 + .byte 0x66,0xea # jmp far [ptr48] +ASM_PFX(gSmmJmpAddr): .long Start32bit + .word PROTECT_MODE_CS +Start32bit: + movl %edi,%ds + movl %edi,%es + movl %edi,%fs + movl %edi,%gs + movl %edi,%ss + .byte 0xbc # mov esp, imm32 +ASM_PFX(gSmmInitStack): .space 4 + call ASM_PFX(SmmInitHandler) + rsm + +ASM_PFX(gcSmmInitTemplate): + +_SmmInitTemplate: + .byte 0x66 + movl $SmmStartup, %ebp + .byte 0x66, 0x81, 0xed, 0, 0, 3, 0 # sub ebp, 0x30000 + jmp *%bp # jmp ebp actually + +ASM_PFX(gcSmmInitSize): .word . - ASM_PFX(gcSmmInitTemplate) + + +ASM_PFX(SmmRelocationSemaphoreComplete): + pushl %eax + movl ASM_PFX(mRebasedFlag), %eax + movb $1, (%eax) + popl %eax + jmp *ASM_PFX(mSmmRelocationOriginalAddress) diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmmInit.asm b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmmInit.asm new file mode 100644 index 000000000000..9ba2aebe6925 --- /dev/null +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmmInit.asm @@ -0,0 +1,94 @@ +;------------------------------------------------------------------------------ ; +; Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.
+; This program and the accompanying materials +; are licensed and made available under the terms and conditions of the BSD License +; which accompanies this distribution. The full text of the license may be found at +; http://opensource.org/licenses/bsd-license.php. +; +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +; +; Module Name: +; +; SmmInit.Asm +; +; Abstract: +; +; Functions for relocating SMBASE's for all processors +; +;------------------------------------------------------------------------------- + + .686p + .xmm + .model flat,C + +SmmInitHandler PROTO C + +EXTERNDEF C gSmmCr0:DWORD +EXTERNDEF C gSmmCr3:DWORD +EXTERNDEF C gSmmCr4:DWORD +EXTERNDEF C gcSmmInitTemplate:BYTE +EXTERNDEF C gcSmmInitSize:WORD +EXTERNDEF C gSmmJmpAddr:QWORD +EXTERNDEF C mRebasedFlag:PTR BYTE +EXTERNDEF C mSmmRelocationOriginalAddress:DWORD +EXTERNDEF C gSmmInitStack:DWORD +EXTERNDEF C gcSmiInitGdtr:FWORD + +PROTECT_MODE_CS EQU 08h +PROTECT_MODE_DS EQU 20h + + .code + +gcSmiInitGdtr LABEL FWORD + DW 0 + DQ 0 + +SmmStartup PROC + DB 66h, 0b8h +gSmmCr3 DD ? + mov cr3, eax + DB 67h, 66h + lgdt fword ptr cs:[ebp + (offset gcSmiInitGdtr - SmmStartup)] + DB 66h, 0b8h +gSmmCr4 DD ? + mov cr4, eax + DB 66h, 0b8h +gSmmCr0 DD ? + DB 0bfh, PROTECT_MODE_DS, 0 ; mov di, PROTECT_MODE_DS + mov cr0, eax + DB 66h, 0eah ; jmp far [ptr48] +gSmmJmpAddr LABEL QWORD + DD @32bit + DW PROTECT_MODE_CS +@32bit: + mov ds, edi + mov es, edi + mov fs, edi + mov gs, edi + mov ss, edi + DB 0bch ; mov esp, imm32 +gSmmInitStack DD ? + call SmmInitHandler + rsm +SmmStartup ENDP + +gcSmmInitTemplate LABEL BYTE + +_SmmInitTemplate PROC + DB 66h + mov ebp, SmmStartup + DB 66h, 81h, 0edh, 00h, 00h, 03h, 00 ; sub ebp, 30000h + jmp bp ; jmp ebp actually +_SmmInitTemplate ENDP + +gcSmmInitSize DW $ - gcSmmInitTemplate + +SmmRelocationSemaphoreComplete PROC + push eax + mov eax, mRebasedFlag + mov byte ptr [eax], 1 + pop eax + jmp [mSmmRelocationOriginalAddress] +SmmRelocationSemaphoreComplete ENDP + END diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmmProfileArch.c b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmmProfileArch.c new file mode 100644 index 000000000000..85756d0710cf --- /dev/null +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmmProfileArch.c @@ -0,0 +1,80 @@ +/** @file +IA-32 processor specific functions to enable SMM profile. + +Copyright (c) 2012 - 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "PiSmmCpuDxeSmm.h" +#include "SmmProfileInternal.h" + +/** + Create SMM page table for S3 path. + +**/ +VOID +InitSmmS3Cr3 ( + VOID + ) +{ + mSmmS3ResumeState->SmmS3Cr3 = Gen4GPageTable (0); + + return ; +} + +/** + Allocate pages for creating 4KB-page based on 2MB-page when page fault happens. + 32-bit firmware does not need it. + +**/ +VOID +InitPagesForPFHandler ( + VOID + ) +{ +} + +/** + Update page table to map the memory correctly in order to make the instruction + which caused page fault execute successfully. And it also save the original page + table to be restored in single-step exception. 32-bit firmware does not need it. + + @param PageTable PageTable Address. + @param PFAddress The memory address which caused page fault exception. + @param CpuIndex The index of the processor. + @param ErrorCode The Error code of exception. + @param IsValidPFAddress The flag indicates if SMM profile data need be added. + +**/ +VOID +RestorePageTableAbove4G ( + UINT64 *PageTable, + UINT64 PFAddress, + UINTN CpuIndex, + UINTN ErrorCode, + BOOLEAN *IsValidPFAddress + ) +{ +} + +/** + Clear TF in FLAGS. + + @param SystemContext A pointer to the processor context when + the interrupt occurred on the processor. + +**/ +VOID +ClearTrapFlag ( + IN OUT EFI_SYSTEM_CONTEXT SystemContext + ) +{ + SystemContext.SystemContextIa32->Eflags &= (UINTN) ~BIT8; +} diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmmProfileArch.h b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmmProfileArch.h new file mode 100644 index 000000000000..3e15bffc60a5 --- /dev/null +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmmProfileArch.h @@ -0,0 +1,97 @@ +/** @file +IA-32 processor specific header file to enable SMM profile. + +Copyright (c) 2012 - 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _SMM_PROFILE_ARCH_H_ +#define _SMM_PROFILE_ARCH_H_ + +#pragma pack (1) + +typedef struct _MSR_DS_AREA_STRUCT { + UINT32 BTSBufferBase; + UINT32 BTSIndex; + UINT32 BTSAbsoluteMaximum; + UINT32 BTSInterruptThreshold; + UINT32 PEBSBufferBase; + UINT32 PEBSIndex; + UINT32 PEBSAbsoluteMaximum; + UINT32 PEBSInterruptThreshold; + UINT32 PEBSCounterReset[4]; + UINT32 Reserved; +} MSR_DS_AREA_STRUCT; + +typedef struct _BRANCH_TRACE_RECORD { + UINT32 LastBranchFrom; + UINT32 LastBranchTo; + UINT32 Rsvd0 : 4; + UINT32 BranchPredicted : 1; + UINT32 Rsvd1 : 27; +} BRANCH_TRACE_RECORD; + +typedef struct _PEBS_RECORD { + UINT32 Eflags; + UINT32 LinearIP; + UINT32 Eax; + UINT32 Ebx; + UINT32 Ecx; + UINT32 Edx; + UINT32 Esi; + UINT32 Edi; + UINT32 Ebp; + UINT32 Esp; +} PEBS_RECORD; + +#pragma pack () + +#define PHYSICAL_ADDRESS_MASK ((1ull << 32) - SIZE_4KB) + +/** + Update page table to map the memory correctly in order to make the instruction + which caused page fault execute successfully. And it also save the original page + table to be restored in single-step exception. 32-bit firmware does not need it. + + @param PageTable PageTable Address. + @param PFAddress The memory address which caused page fault exception. + @param CpuIndex The index of the processor. + @param ErrorCode The Error code of exception. + @param IsValidPFAddress The flag indicates if SMM profile data need be added. + +**/ +VOID +RestorePageTableAbove4G ( + UINT64 *PageTable, + UINT64 PFAddress, + UINTN CpuIndex, + UINTN ErrorCode, + BOOLEAN *IsValidPFAddress + ); + +/** + Create SMM page table for S3 path. + +**/ +VOID +InitSmmS3Cr3 ( + VOID + ); + +/** + Allocate pages for creating 4KB-page based on 2MB-page when page fault happens. + +**/ +VOID +InitPagesForPFHandler ( + VOID + ); + +#endif // _SMM_PROFILE_ARCH_H_ From 05aebe5da37b680a03a92121a05937dc9cc83667 Mon Sep 17 00:00:00 2001 From: Michael Kinney Date: Tue, 17 Nov 2015 05:06:29 +0000 Subject: [PATCH 126/525] UefiCpuPkg: Add PiSmmCpuDxeSmm module X64 files Add module that initializes a CPU for the SMM environment and installs the first level SMI handler. This module along with the SMM IPL and SMM Core provide the services required for DXE_SMM_DRIVERS to register hardware and software SMI handlers. CPU specific features are abstracted through the SmmCpuFeaturesLib Platform specific features are abstracted through the SmmCpuPlatformHookLib Several PCDs are added to enable/disable features and configure settings for the PiSmmCpuDxeSmm module (Sync patch r18647 from main trunk.) [jeff.fan@intel.com: Fix code style issues reported by ECC] Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Michael Kinney Reviewed-by: Jeff Fan git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18842 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/PiSmmCpuDxeSmm/X64/MpFuncs.S | 204 ++++++ UefiCpuPkg/PiSmmCpuDxeSmm/X64/MpFuncs.asm | 206 ++++++ UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c | 692 ++++++++++++++++++ UefiCpuPkg/PiSmmCpuDxeSmm/X64/Semaphore.c | 67 ++ UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmiEntry.S | 217 ++++++ UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmiEntry.asm | 221 ++++++ UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmiException.S | 610 +++++++++++++++ .../PiSmmCpuDxeSmm/X64/SmiException.asm | 413 +++++++++++ UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmInit.S | 141 ++++ UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmInit.asm | 132 ++++ .../PiSmmCpuDxeSmm/X64/SmmProfileArch.c | 316 ++++++++ .../PiSmmCpuDxeSmm/X64/SmmProfileArch.h | 105 +++ 12 files changed, 3324 insertions(+) create mode 100644 UefiCpuPkg/PiSmmCpuDxeSmm/X64/MpFuncs.S create mode 100644 UefiCpuPkg/PiSmmCpuDxeSmm/X64/MpFuncs.asm create mode 100644 UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c create mode 100644 UefiCpuPkg/PiSmmCpuDxeSmm/X64/Semaphore.c create mode 100644 UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmiEntry.S create mode 100644 UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmiEntry.asm create mode 100644 UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmiException.S create mode 100644 UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmiException.asm create mode 100644 UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmInit.S create mode 100644 UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmInit.asm create mode 100644 UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmProfileArch.c create mode 100644 UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmProfileArch.h diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/X64/MpFuncs.S b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/MpFuncs.S new file mode 100644 index 000000000000..d7cbc8cdc50b --- /dev/null +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/MpFuncs.S @@ -0,0 +1,204 @@ +#------------------------------------------------------------------------------ +# +# Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# Module Name: +# +# MpFuncs.S +# +# Abstract: +# +# This is the assembly code for Multi-processor S3 support +# +#------------------------------------------------------------------------------ + +.equ VacantFlag, 0x0 +.equ NotVacantFlag, 0xff + +.equ LockLocation, RendezvousFunnelProcEnd - RendezvousFunnelProcStart +.equ StackStartAddressLocation, RendezvousFunnelProcEnd - RendezvousFunnelProcStart + 0x08 +.equ StackSizeLocation, RendezvousFunnelProcEnd - RendezvousFunnelProcStart + 0x10 +.equ CProcedureLocation, RendezvousFunnelProcEnd - RendezvousFunnelProcStart + 0x18 +.equ GdtrLocation, RendezvousFunnelProcEnd - RendezvousFunnelProcStart + 0x20 +.equ IdtrLocation, RendezvousFunnelProcEnd - RendezvousFunnelProcStart + 0x2A +.equ BufferStartLocation, RendezvousFunnelProcEnd - RendezvousFunnelProcStart + 0x34 +.equ Cr3OffsetLocation, RendezvousFunnelProcEnd - RendezvousFunnelProcStart + 0x38 + +#------------------------------------------------------------------------------------- +#RendezvousFunnelProc procedure follows. All APs execute their procedure. This +#procedure serializes all the AP processors through an Init sequence. It must be +#noted that APs arrive here very raw...ie: real mode, no stack. +#ALSO THIS PROCEDURE IS EXECUTED BY APs ONLY ON 16 BIT MODE. HENCE THIS PROC +#IS IN MACHINE CODE. +#------------------------------------------------------------------------------------- +#RendezvousFunnelProc (&WakeUpBuffer,MemAddress); + +.code: + +ASM_GLOBAL ASM_PFX(RendezvousFunnelProc) +ASM_PFX(RendezvousFunnelProc): +RendezvousFunnelProcStart: + +# At this point CS = 0x(vv00) and ip= 0x0. + + .byte 0x8c,0xc8 # mov ax, cs + .byte 0x8e,0xd8 # mov ds, ax + .byte 0x8e,0xc0 # mov es, ax + .byte 0x8e,0xd0 # mov ss, ax + .byte 0x33,0xc0 # xor ax, ax + .byte 0x8e,0xe0 # mov fs, ax + .byte 0x8e,0xe8 # mov gs, ax + +flat32Start: + + .byte 0xBE + .word BufferStartLocation + .byte 0x66,0x8B,0x14 # mov edx,dword ptr [si] ; EDX is keeping the start address of wakeup buffer + + .byte 0xBE + .word Cr3OffsetLocation + .byte 0x66,0x8B,0xC # mov ecx,dword ptr [si] ; ECX is keeping the value of CR3 + + .byte 0xBE + .word GdtrLocation + .byte 0x66 # db 66h + .byte 0x2E,0xF,0x1,0x14 # lgdt fword ptr cs:[si] + + .byte 0xBE + .word IdtrLocation + .byte 0x66 # db 66h + .byte 0x2E,0xF,0x1,0x1C # lidt fword ptr cs:[si] + + .byte 0x33,0xC0 # xor ax, ax + .byte 0x8E,0xD8 # mov ds, ax + + .byte 0xF,0x20,0xC0 # mov eax, cr0 ; Get control register 0 + .byte 0x66,0x83,0xC8,0x1 # or eax, 000000001h ; Set PE bit (bit #0) + .byte 0xF,0x22,0xC0 # mov cr0, eax + +FLAT32_JUMP: + + .byte 0x66,0x67,0xEA # far jump + .long 0x0 # 32-bit offset + .word 0x20 # 16-bit selector + +PMODE_ENTRY: # protected mode entry point + + .byte 0x66,0xB8,0x18,0x0 # mov ax, 18h + .byte 0x66,0x8E,0xD8 # mov ds, ax + .byte 0x66,0x8E,0xC0 # mov es, ax + .byte 0x66,0x8E,0xE0 # mov fs, ax + .byte 0x66,0x8E,0xE8 # mov gs, ax + .byte 0x66,0x8E,0xD0 # mov ss, ax ; Flat mode setup. + + .byte 0xF,0x20,0xE0 # mov eax, cr4 + .byte 0xF,0xBA,0xE8,0x5 # bts eax, 5 + .byte 0xF,0x22,0xE0 # mov cr4, eax + + .byte 0xF,0x22,0xD9 # mov cr3, ecx + + .byte 0x8B,0xF2 # mov esi, edx ; Save wakeup buffer address + + .byte 0xB9 + .long 0xC0000080 # mov ecx, 0c0000080h ; EFER MSR number. + .byte 0xF,0x32 # rdmsr ; Read EFER. + .byte 0xF,0xBA,0xE8,0x8 # bts eax, 8 ; Set LME=1. + .byte 0xF,0x30 # wrmsr ; Write EFER. + + .byte 0xF,0x20,0xC0 # mov eax, cr0 ; Read CR0. + .byte 0xF,0xBA,0xE8,0x1F # bts eax, 31 ; Set PG=1. + .byte 0xF,0x22,0xC0 # mov cr0, eax ; Write CR0. + +LONG_JUMP: + + .byte 0x67,0xEA # far jump + .long 0x0 # 32-bit offset + .word 0x38 # 16-bit selector + +LongModeStart: + + movw $0x30,%ax + .byte 0x66 + movw %ax,%ds + .byte 0x66 + movw %ax,%es + .byte 0x66 + movw %ax,%ss + + movl %esi,%edi + addl $LockLocation, %edi + movb $NotVacantFlag, %al +TestLock: + xchgb (%edi), %al + cmpb $NotVacantFlag, %al + jz TestLock + +ProgramStack: + + movl %esi,%edi + addl $StackSizeLocation, %edi + movq (%edi), %rax + movl %esi,%edi + addl $StackStartAddressLocation, %edi + addq (%edi), %rax + movq %rax, %rsp + movq %rax, (%edi) + +Releaselock: + + movb $VacantFlag, %al + movl %esi,%edi + addl $LockLocation, %edi + xchgb (%edi), %al + + # + # Call assembly function to initialize FPU. + # + movabsq $ASM_PFX(InitializeFloatingPointUnits), %rax + subq $0x20, %rsp + call *%rax + addq $0x20, %rsp + # + # Call C Function + # + movl %esi,%edi + addl $CProcedureLocation, %edi + movq (%edi), %rax + + testq %rax, %rax + jz GoToSleep + + subq $0x20, %rsp + call *%rax + addq $0x20, %rsp + +GoToSleep: + cli + hlt + jmp .-2 + +RendezvousFunnelProcEnd: + + +#------------------------------------------------------------------------------------- +# AsmGetAddressMap (&AddressMap); +#------------------------------------------------------------------------------------- +# comments here for definition of address map +ASM_GLOBAL ASM_PFX(AsmGetAddressMap) +ASM_PFX(AsmGetAddressMap): + movabsq $RendezvousFunnelProcStart, %rax + movq %rax, (%rcx) + movq $(PMODE_ENTRY - RendezvousFunnelProcStart), 0x08(%rcx) + movq $(FLAT32_JUMP - RendezvousFunnelProcStart), 0x10(%rcx) + movq $(RendezvousFunnelProcEnd - RendezvousFunnelProcStart), 0x18(%rcx) + movq $(LongModeStart - RendezvousFunnelProcStart), 0x20(%rcx) + movq $(LONG_JUMP - RendezvousFunnelProcStart), 0x28(%rcx) + ret + diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/X64/MpFuncs.asm b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/MpFuncs.asm new file mode 100644 index 000000000000..2c5a7c9bc2db --- /dev/null +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/MpFuncs.asm @@ -0,0 +1,206 @@ +;------------------------------------------------------------------------------ ; +; Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
+; This program and the accompanying materials +; are licensed and made available under the terms and conditions of the BSD License +; which accompanies this distribution. The full text of the license may be found at +; http://opensource.org/licenses/bsd-license.php. +; +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +; +; Module Name: +; +; MpFuncs.asm +; +; Abstract: +; +; This is the assembly code for Multi-processor S3 support +; +;------------------------------------------------------------------------------- + +EXTERN InitializeFloatingPointUnits:PROC + +VacantFlag Equ 00h +NotVacantFlag Equ 0ffh + +LockLocation equ RendezvousFunnelProcEnd - RendezvousFunnelProcStart +StackStartAddressLocation equ LockLocation + 08h +StackSizeLocation equ LockLocation + 10h +CProcedureLocation equ LockLocation + 18h +GdtrLocation equ LockLocation + 20h +IdtrLocation equ LockLocation + 2Ah +BufferStartLocation equ LockLocation + 34h +Cr3OffsetLocation equ LockLocation + 38h + +;------------------------------------------------------------------------------------- +;RendezvousFunnelProc procedure follows. All APs execute their procedure. This +;procedure serializes all the AP processors through an Init sequence. It must be +;noted that APs arrive here very raw...ie: real mode, no stack. +;ALSO THIS PROCEDURE IS EXECUTED BY APs ONLY ON 16 BIT MODE. HENCE THIS PROC +;IS IN MACHINE CODE. +;------------------------------------------------------------------------------------- +;RendezvousFunnelProc (&WakeUpBuffer,MemAddress); + +;text SEGMENT +.code + +RendezvousFunnelProc PROC +RendezvousFunnelProcStart:: + +; At this point CS = 0x(vv00) and ip= 0x0. + + db 8ch, 0c8h ; mov ax, cs + db 8eh, 0d8h ; mov ds, ax + db 8eh, 0c0h ; mov es, ax + db 8eh, 0d0h ; mov ss, ax + db 33h, 0c0h ; xor ax, ax + db 8eh, 0e0h ; mov fs, ax + db 8eh, 0e8h ; mov gs, ax + +flat32Start:: + + db 0BEh + dw BufferStartLocation ; mov si, BufferStartLocation + db 66h, 8Bh, 14h ; mov edx,dword ptr [si] ; EDX is keeping the start address of wakeup buffer + + db 0BEh + dw Cr3OffsetLocation ; mov si, Cr3Location + db 66h, 8Bh, 0Ch ; mov ecx,dword ptr [si] ; ECX is keeping the value of CR3 + + db 0BEh + dw GdtrLocation ; mov si, GdtrProfile + db 66h ; db 66h + db 2Eh, 0Fh, 01h, 14h ; lgdt fword ptr cs:[si] + + db 0BEh + dw IdtrLocation ; mov si, IdtrProfile + db 66h ; db 66h + db 2Eh, 0Fh, 01h, 1Ch ; lidt fword ptr cs:[si] + + db 33h, 0C0h ; xor ax, ax + db 8Eh, 0D8h ; mov ds, ax + + db 0Fh, 20h, 0C0h ; mov eax, cr0 ; Get control register 0 + db 66h, 83h, 0C8h, 01h ; or eax, 000000001h ; Set PE bit (bit #0) + db 0Fh, 22h, 0C0h ; mov cr0, eax + +FLAT32_JUMP:: + + db 66h, 67h, 0EAh ; far jump + dd 0h ; 32-bit offset + dw 20h ; 16-bit selector + +PMODE_ENTRY:: ; protected mode entry point + + db 66h, 0B8h, 18h, 00h ; mov ax, 18h + db 66h, 8Eh, 0D8h ; mov ds, ax + db 66h, 8Eh, 0C0h ; mov es, ax + db 66h, 8Eh, 0E0h ; mov fs, ax + db 66h, 8Eh, 0E8h ; mov gs, ax + db 66h, 8Eh, 0D0h ; mov ss, ax ; Flat mode setup. + + db 0Fh, 20h, 0E0h ; mov eax, cr4 + db 0Fh, 0BAh, 0E8h, 05h ; bts eax, 5 + db 0Fh, 22h, 0E0h ; mov cr4, eax + + db 0Fh, 22h, 0D9h ; mov cr3, ecx + + db 8Bh, 0F2h ; mov esi, edx ; Save wakeup buffer address + + db 0B9h + dd 0C0000080h ; mov ecx, 0c0000080h ; EFER MSR number. + db 0Fh, 32h ; rdmsr ; Read EFER. + db 0Fh, 0BAh, 0E8h, 08h ; bts eax, 8 ; Set LME=1. + db 0Fh, 30h ; wrmsr ; Write EFER. + + db 0Fh, 20h, 0C0h ; mov eax, cr0 ; Read CR0. + db 0Fh, 0BAh, 0E8h, 1Fh ; bts eax, 31 ; Set PG=1. + db 0Fh, 22h, 0C0h ; mov cr0, eax ; Write CR0. + +LONG_JUMP:: + + db 67h, 0EAh ; far jump + dd 0h ; 32-bit offset + dw 38h ; 16-bit selector + +LongModeStart:: + + mov ax, 30h + mov ds, ax + mov es, ax + mov ss, ax + + mov edi, esi + add edi, LockLocation + mov al, NotVacantFlag +TestLock:: + xchg byte ptr [edi], al + cmp al, NotVacantFlag + jz TestLock + +ProgramStack:: + + mov edi, esi + add edi, StackSizeLocation + mov rax, qword ptr [edi] + mov edi, esi + add edi, StackStartAddressLocation + add rax, qword ptr [edi] + mov rsp, rax + mov qword ptr [edi], rax + +Releaselock:: + + mov al, VacantFlag + mov edi, esi + add edi, LockLocation + xchg byte ptr [edi], al + + ; + ; Call assembly function to initialize FPU. + ; + mov rax, InitializeFloatingPointUnits + sub rsp, 20h + call rax + add rsp, 20h + + ; + ; Call C Function + ; + mov edi, esi + add edi, CProcedureLocation + mov rax, qword ptr [edi] + + test rax, rax + jz GoToSleep + + sub rsp, 20h + call rax + add rsp, 20h + +GoToSleep:: + cli + hlt + jmp $-2 + +RendezvousFunnelProcEnd:: +RendezvousFunnelProc ENDP + + +;------------------------------------------------------------------------------------- +; AsmGetAddressMap (&AddressMap); +;------------------------------------------------------------------------------------- +; comments here for definition of address map +AsmGetAddressMap PROC + mov rax, offset RendezvousFunnelProcStart + mov qword ptr [rcx], rax + mov qword ptr [rcx+8h], PMODE_ENTRY - RendezvousFunnelProcStart + mov qword ptr [rcx+10h], FLAT32_JUMP - RendezvousFunnelProcStart + mov qword ptr [rcx+18h], RendezvousFunnelProcEnd - RendezvousFunnelProcStart + mov qword ptr [rcx+20h], LongModeStart - RendezvousFunnelProcStart + mov qword ptr [rcx+28h], LONG_JUMP - RendezvousFunnelProcStart + ret + +AsmGetAddressMap ENDP + +END diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c new file mode 100644 index 000000000000..a7d790fd8aa0 --- /dev/null +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c @@ -0,0 +1,692 @@ +/** @file +Page Fault (#PF) handler for X64 processors + +Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "PiSmmCpuDxeSmm.h" + +#define PAGE_TABLE_PAGES 8 +#define ACC_MAX_BIT BIT3 +LIST_ENTRY mPagePool = INITIALIZE_LIST_HEAD_VARIABLE (mPagePool); +SPIN_LOCK mPFLock; +BOOLEAN m1GPageTableSupport = FALSE; + +/** + Check if 1-GByte pages is supported by processor or not. + + @retval TRUE 1-GByte pages is supported. + @retval FALSE 1-GByte pages is not supported. + +**/ +BOOLEAN +Is1GPageSupport ( + VOID + ) +{ + UINT32 RegEax; + UINT32 RegEdx; + + AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL); + if (RegEax >= 0x80000001) { + AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx); + if ((RegEdx & BIT26) != 0) { + return TRUE; + } + } + return FALSE; +} + +/** + Set sub-entries number in entry. + + @param[in, out] Entry Pointer to entry + @param[in] SubEntryNum Sub-entries number based on 0: + 0 means there is 1 sub-entry under this entry + 0x1ff means there is 512 sub-entries under this entry + +**/ +VOID +SetSubEntriesNum ( + IN OUT UINT64 *Entry, + IN UINT64 SubEntryNum + ) +{ + // + // Sub-entries number is saved in BIT52 to BIT60 (reserved field) in Entry + // + *Entry = BitFieldWrite64 (*Entry, 52, 60, SubEntryNum); +} + +/** + Return sub-entries number in entry. + + @param[in] Entry Pointer to entry + + @return Sub-entries number based on 0: + 0 means there is 1 sub-entry under this entry + 0x1ff means there is 512 sub-entries under this entry +**/ +UINT64 +GetSubEntriesNum ( + IN UINT64 *Entry + ) +{ + // + // Sub-entries number is saved in BIT52 to BIT60 (reserved field) in Entry + // + return BitFieldRead64 (*Entry, 52, 60); +} + +/** + Create PageTable for SMM use. + + @return The address of PML4 (to set CR3). + +**/ +UINT32 +SmmInitPageTable ( + VOID + ) +{ + EFI_PHYSICAL_ADDRESS Pages; + UINT64 *PTEntry; + LIST_ENTRY *FreePage; + UINTN Index; + UINTN PageFaultHandlerHookAddress; + IA32_IDT_GATE_DESCRIPTOR *IdtEntry; + + // + // Initialize spin lock + // + InitializeSpinLock (&mPFLock); + + m1GPageTableSupport = Is1GPageSupport (); + // + // Generate PAE page table for the first 4GB memory space + // + Pages = Gen4GPageTable (PAGE_TABLE_PAGES + 1); + + // + // Set IA32_PG_PMNT bit to mask this entry + // + PTEntry = (UINT64*)(UINTN)Pages; + for (Index = 0; Index < 4; Index++) { + PTEntry[Index] |= IA32_PG_PMNT; + } + + // + // Fill Page-Table-Level4 (PML4) entry + // + PTEntry = (UINT64*)(UINTN)(Pages - EFI_PAGES_TO_SIZE (PAGE_TABLE_PAGES + 1)); + *PTEntry = Pages + IA32_PG_P; + ZeroMem (PTEntry + 1, EFI_PAGE_SIZE - sizeof (*PTEntry)); + // + // Set sub-entries number + // + SetSubEntriesNum (PTEntry, 3); + + // + // Add remaining pages to page pool + // + FreePage = (LIST_ENTRY*)(PTEntry + EFI_PAGE_SIZE / sizeof (*PTEntry)); + while ((UINTN)FreePage < Pages) { + InsertTailList (&mPagePool, FreePage); + FreePage += EFI_PAGE_SIZE / sizeof (*FreePage); + } + + if (FeaturePcdGet (PcdCpuSmmProfileEnable)) { + // + // Set own Page Fault entry instead of the default one, because SMM Profile + // feature depends on IRET instruction to do Single Step + // + PageFaultHandlerHookAddress = (UINTN)PageFaultIdtHandlerSmmProfile; + IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *) gcSmiIdtr.Base; + IdtEntry += EXCEPT_IA32_PAGE_FAULT; + IdtEntry->Bits.OffsetLow = (UINT16)PageFaultHandlerHookAddress; + IdtEntry->Bits.Reserved_0 = 0; + IdtEntry->Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32; + IdtEntry->Bits.OffsetHigh = (UINT16)(PageFaultHandlerHookAddress >> 16); + IdtEntry->Bits.OffsetUpper = (UINT32)(PageFaultHandlerHookAddress >> 32); + IdtEntry->Bits.Reserved_1 = 0; + } else { + // + // Register Smm Page Fault Handler + // + SmmRegisterExceptionHandler (&mSmmCpuService, EXCEPT_IA32_PAGE_FAULT, SmiPFHandler); + } + + // + // Additional SMM IDT initialization for SMM stack guard + // + if (FeaturePcdGet (PcdCpuSmmStackGuard)) { + InitializeIDTSmmStackGuard (); + } + + // + // Return the address of PML4 (to set CR3) + // + return (UINT32)(UINTN)PTEntry; +} + +/** + Set access record in entry. + + @param[in, out] Entry Pointer to entry + @param[in] Acc Access record value + +**/ +VOID +SetAccNum ( + IN OUT UINT64 *Entry, + IN UINT64 Acc + ) +{ + // + // Access record is saved in BIT9 to BIT11 (reserved field) in Entry + // + *Entry = BitFieldWrite64 (*Entry, 9, 11, Acc); +} + +/** + Return access record in entry. + + @param[in] Entry Pointer to entry + + @return Access record value. + +**/ +UINT64 +GetAccNum ( + IN UINT64 *Entry + ) +{ + // + // Access record is saved in BIT9 to BIT11 (reserved field) in Entry + // + return BitFieldRead64 (*Entry, 9, 11); +} + +/** + Return and update the access record in entry. + + @param[in, out] Entry Pointer to entry + + @return Access record value. + +**/ +UINT64 +GetAndUpdateAccNum ( + IN OUT UINT64 *Entry + ) +{ + UINT64 Acc; + + Acc = GetAccNum (Entry); + if ((*Entry & IA32_PG_A) != 0) { + // + // If this entry has been accessed, clear access flag in Entry and update access record + // to the initial value 7, adding ACC_MAX_BIT is to make it larger than others + // + *Entry &= ~(UINT64)(UINTN)IA32_PG_A; + SetAccNum (Entry, 0x7); + return (0x7 + ACC_MAX_BIT); + } else { + if (Acc != 0) { + // + // If the access record is not the smallest value 0, minus 1 and update the access record field + // + SetAccNum (Entry, Acc - 1); + } + } + return Acc; +} + +/** + Reclaim free pages for PageFault handler. + + Search the whole entries tree to find the leaf entry that has the smallest + access record value. Insert the page pointed by this leaf entry into the + page pool. And check its upper entries if need to be inserted into the page + pool or not. + +**/ +VOID +ReclaimPages ( + VOID + ) +{ + UINT64 *Pml4; + UINT64 *Pdpt; + UINT64 *Pdt; + UINTN Pml4Index; + UINTN PdptIndex; + UINTN PdtIndex; + UINTN MinPml4; + UINTN MinPdpt; + UINTN MinPdt; + UINT64 MinAcc; + UINT64 Acc; + UINT64 SubEntriesNum; + BOOLEAN PML4EIgnore; + BOOLEAN PDPTEIgnore; + UINT64 *ReleasePageAddress; + + Pml4 = NULL; + Pdpt = NULL; + Pdt = NULL; + MinAcc = (UINT64)-1; + MinPml4 = (UINTN)-1; + MinPdpt = (UINTN)-1; + MinPdt = (UINTN)-1; + Acc = 0; + ReleasePageAddress = 0; + + // + // First, find the leaf entry has the smallest access record value + // + Pml4 = (UINT64*)(UINTN)(AsmReadCr3 () & gPhyMask); + for (Pml4Index = 0; Pml4Index < EFI_PAGE_SIZE / sizeof (*Pml4); Pml4Index++) { + if ((Pml4[Pml4Index] & IA32_PG_P) == 0 || (Pml4[Pml4Index] & IA32_PG_PMNT) != 0) { + // + // If the PML4 entry is not present or is masked, skip it + // + continue; + } + Pdpt = (UINT64*)(UINTN)(Pml4[Pml4Index] & gPhyMask); + PML4EIgnore = FALSE; + for (PdptIndex = 0; PdptIndex < EFI_PAGE_SIZE / sizeof (*Pdpt); PdptIndex++) { + if ((Pdpt[PdptIndex] & IA32_PG_P) == 0 || (Pdpt[PdptIndex] & IA32_PG_PMNT) != 0) { + // + // If the PDPT entry is not present or is masked, skip it + // + if ((Pdpt[PdptIndex] & IA32_PG_PMNT) != 0) { + // + // If the PDPT entry is masked, we will ignore checking the PML4 entry + // + PML4EIgnore = TRUE; + } + continue; + } + if ((Pdpt[PdptIndex] & IA32_PG_PS) == 0) { + // + // It's not 1-GByte pages entry, it should be a PDPT entry, + // we will not check PML4 entry more + // + PML4EIgnore = TRUE; + Pdt = (UINT64*)(UINTN)(Pdpt[PdptIndex] & gPhyMask); + PDPTEIgnore = FALSE; + for (PdtIndex = 0; PdtIndex < EFI_PAGE_SIZE / sizeof(*Pdt); PdtIndex++) { + if ((Pdt[PdtIndex] & IA32_PG_P) == 0 || (Pdt[PdtIndex] & IA32_PG_PMNT) != 0) { + // + // If the PD entry is not present or is masked, skip it + // + if ((Pdt[PdtIndex] & IA32_PG_PMNT) != 0) { + // + // If the PD entry is masked, we will not PDPT entry more + // + PDPTEIgnore = TRUE; + } + continue; + } + if ((Pdt[PdtIndex] & IA32_PG_PS) == 0) { + // + // It's not 2 MByte page table entry, it should be PD entry + // we will find the entry has the smallest access record value + // + PDPTEIgnore = TRUE; + Acc = GetAndUpdateAccNum (Pdt + PdtIndex); + if (Acc < MinAcc) { + // + // If the PD entry has the smallest access record value, + // save the Page address to be released + // + MinAcc = Acc; + MinPml4 = Pml4Index; + MinPdpt = PdptIndex; + MinPdt = PdtIndex; + ReleasePageAddress = Pdt + PdtIndex; + } + } + } + if (!PDPTEIgnore) { + // + // If this PDPT entry has no PDT entries pointer to 4 KByte pages, + // it should only has the entries point to 2 MByte Pages + // + Acc = GetAndUpdateAccNum (Pdpt + PdptIndex); + if (Acc < MinAcc) { + // + // If the PDPT entry has the smallest access record value, + // save the Page address to be released + // + MinAcc = Acc; + MinPml4 = Pml4Index; + MinPdpt = PdptIndex; + MinPdt = (UINTN)-1; + ReleasePageAddress = Pdpt + PdptIndex; + } + } + } + } + if (!PML4EIgnore) { + // + // If PML4 entry has no the PDPT entry pointer to 2 MByte pages, + // it should only has the entries point to 1 GByte Pages + // + Acc = GetAndUpdateAccNum (Pml4 + Pml4Index); + if (Acc < MinAcc) { + // + // If the PML4 entry has the smallest access record value, + // save the Page address to be released + // + MinAcc = Acc; + MinPml4 = Pml4Index; + MinPdpt = (UINTN)-1; + MinPdt = (UINTN)-1; + ReleasePageAddress = Pml4 + Pml4Index; + } + } + } + // + // Make sure one PML4/PDPT/PD entry is selected + // + ASSERT (MinAcc != (UINT64)-1); + + // + // Secondly, insert the page pointed by this entry into page pool and clear this entry + // + InsertTailList (&mPagePool, (LIST_ENTRY*)(UINTN)(*ReleasePageAddress & gPhyMask)); + *ReleasePageAddress = 0; + + // + // Lastly, check this entry's upper entries if need to be inserted into page pool + // or not + // + while (TRUE) { + if (MinPdt != (UINTN)-1) { + // + // If 4 KByte Page Table is released, check the PDPT entry + // + Pdpt = (UINT64*)(UINTN)(Pml4[MinPml4] & gPhyMask); + SubEntriesNum = GetSubEntriesNum(Pdpt + MinPdpt); + if (SubEntriesNum == 0) { + // + // Release the empty Page Directory table if there was no more 4 KByte Page Table entry + // clear the Page directory entry + // + InsertTailList (&mPagePool, (LIST_ENTRY*)(UINTN)(Pdpt[MinPdpt] & gPhyMask)); + Pdpt[MinPdpt] = 0; + // + // Go on checking the PML4 table + // + MinPdt = (UINTN)-1; + continue; + } + // + // Update the sub-entries filed in PDPT entry and exit + // + SetSubEntriesNum (Pdpt + MinPdpt, SubEntriesNum - 1); + break; + } + if (MinPdpt != (UINTN)-1) { + // + // One 2MB Page Table is released or Page Directory table is released, check the PML4 entry + // + SubEntriesNum = GetSubEntriesNum (Pml4 + MinPml4); + if (SubEntriesNum == 0) { + // + // Release the empty PML4 table if there was no more 1G KByte Page Table entry + // clear the Page directory entry + // + InsertTailList (&mPagePool, (LIST_ENTRY*)(UINTN)(Pml4[MinPml4] & gPhyMask)); + Pml4[MinPml4] = 0; + MinPdpt = (UINTN)-1; + continue; + } + // + // Update the sub-entries filed in PML4 entry and exit + // + SetSubEntriesNum (Pml4 + MinPml4, SubEntriesNum - 1); + break; + } + // + // PLM4 table has been released before, exit it + // + break; + } +} + +/** + Allocate free Page for PageFault handler use. + + @return Page address. + +**/ +UINT64 +AllocPage ( + VOID + ) +{ + UINT64 RetVal; + + if (IsListEmpty (&mPagePool)) { + // + // If page pool is empty, reclaim the used pages and insert one into page pool + // + ReclaimPages (); + } + + // + // Get one free page and remove it from page pool + // + RetVal = (UINT64)(UINTN)mPagePool.ForwardLink; + RemoveEntryList (mPagePool.ForwardLink); + // + // Clean this page and return + // + ZeroMem ((VOID*)(UINTN)RetVal, EFI_PAGE_SIZE); + return RetVal; +} + +/** + Page Fault handler for SMM use. + +**/ +VOID +SmiDefaultPFHandler ( + VOID + ) +{ + UINT64 *PageTable; + UINT64 *Pml4; + UINT64 PFAddress; + UINTN StartBit; + UINTN EndBit; + UINT64 PTIndex; + UINTN Index; + SMM_PAGE_SIZE_TYPE PageSize; + UINTN NumOfPages; + UINTN PageAttribute; + EFI_STATUS Status; + UINT64 *UpperEntry; + + // + // Set default SMM page attribute + // + PageSize = SmmPageSize2M; + NumOfPages = 1; + PageAttribute = 0; + + EndBit = 0; + Pml4 = (UINT64*)(AsmReadCr3 () & gPhyMask); + PFAddress = AsmReadCr2 (); + + Status = GetPlatformPageTableAttribute (PFAddress, &PageSize, &NumOfPages, &PageAttribute); + // + // If platform not support page table attribute, set default SMM page attribute + // + if (Status != EFI_SUCCESS) { + PageSize = SmmPageSize2M; + NumOfPages = 1; + PageAttribute = 0; + } + if (PageSize >= MaxSmmPageSizeType) { + PageSize = SmmPageSize2M; + } + if (NumOfPages > 512) { + NumOfPages = 512; + } + + switch (PageSize) { + case SmmPageSize4K: + // + // BIT12 to BIT20 is Page Table index + // + EndBit = 12; + break; + case SmmPageSize2M: + // + // BIT21 to BIT29 is Page Directory index + // + EndBit = 21; + PageAttribute |= (UINTN)IA32_PG_PS; + break; + case SmmPageSize1G: + if (!m1GPageTableSupport) { + DEBUG ((EFI_D_ERROR, "1-GByte pages is not supported!")); + ASSERT (FALSE); + } + // + // BIT30 to BIT38 is Page Directory Pointer Table index + // + EndBit = 30; + PageAttribute |= (UINTN)IA32_PG_PS; + break; + default: + ASSERT (FALSE); + } + + // + // If execute-disable is enabled, set NX bit + // + if (mXdEnabled) { + PageAttribute |= IA32_PG_NX; + } + + for (Index = 0; Index < NumOfPages; Index++) { + PageTable = Pml4; + UpperEntry = NULL; + for (StartBit = 39; StartBit > EndBit; StartBit -= 9) { + PTIndex = BitFieldRead64 (PFAddress, StartBit, StartBit + 8); + if ((PageTable[PTIndex] & IA32_PG_P) == 0) { + // + // If the entry is not present, allocate one page from page pool for it + // + PageTable[PTIndex] = AllocPage () | IA32_PG_RW | IA32_PG_P; + } else { + // + // Save the upper entry address + // + UpperEntry = PageTable + PTIndex; + } + // + // BIT9 to BIT11 of entry is used to save access record, + // initialize value is 7 + // + PageTable[PTIndex] |= (UINT64)IA32_PG_A; + SetAccNum (PageTable + PTIndex, 7); + PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & gPhyMask); + } + + PTIndex = BitFieldRead64 (PFAddress, StartBit, StartBit + 8); + if ((PageTable[PTIndex] & IA32_PG_P) != 0) { + // + // Check if the entry has already existed, this issue may occur when the different + // size page entries created under the same entry + // + DEBUG ((EFI_D_ERROR, "PageTable = %lx, PTIndex = %x, PageTable[PTIndex] = %lx\n", PageTable, PTIndex, PageTable[PTIndex])); + DEBUG ((EFI_D_ERROR, "New page table overlapped with old page table!\n")); + ASSERT (FALSE); + } + // + // Fill the new entry + // + PageTable[PTIndex] = (PFAddress & gPhyMask & ~((1ull << EndBit) - 1)) | + PageAttribute | IA32_PG_A | IA32_PG_RW | IA32_PG_P; + if (UpperEntry != NULL) { + SetSubEntriesNum (UpperEntry, GetSubEntriesNum (UpperEntry) + 1); + } + // + // Get the next page address if we need to create more page tables + // + PFAddress += (1ull << EndBit); + } +} + +/** + ThePage Fault handler wrapper for SMM use. + + @param InterruptType Defines the type of interrupt or exception that + occurred on the processor.This parameter is processor architecture specific. + @param SystemContext A pointer to the processor context when + the interrupt occurred on the processor. +**/ +VOID +EFIAPI +SmiPFHandler ( + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ + UINTN PFAddress; + + ASSERT (InterruptType == EXCEPT_IA32_PAGE_FAULT); + + AcquireSpinLock (&mPFLock); + + PFAddress = AsmReadCr2 (); + + // + // If a page fault occurs in SMRAM range, it should be in a SMM stack guard page. + // + if ((FeaturePcdGet (PcdCpuSmmStackGuard)) && + (PFAddress >= mCpuHotPlugData.SmrrBase) && + (PFAddress < (mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize))) { + DEBUG ((EFI_D_ERROR, "SMM stack overflow!\n")); + CpuDeadLoop (); + } + + // + // If a page fault occurs in SMM range + // + if ((PFAddress < mCpuHotPlugData.SmrrBase) || + (PFAddress >= mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize)) { + if ((SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_ID) != 0) { + DEBUG ((EFI_D_ERROR, "Code executed on IP(0x%lx) out of SMM range after SMM is locked!\n", PFAddress)); + DEBUG_CODE ( + DumpModuleInfoByIp (*(UINTN *)(UINTN)SystemContext.SystemContextX64->Rsp); + ); + CpuDeadLoop (); + } + } + + if (FeaturePcdGet (PcdCpuSmmProfileEnable)) { + SmmProfilePFHandler ( + SystemContext.SystemContextX64->Rip, + SystemContext.SystemContextX64->ExceptionData + ); + } else { + SmiDefaultPFHandler (); + } + + ReleaseSpinLock (&mPFLock); +} diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/X64/Semaphore.c b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/Semaphore.c new file mode 100644 index 000000000000..6dbcb086aa4d --- /dev/null +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/Semaphore.c @@ -0,0 +1,67 @@ +/** @file +Semaphore mechanism to indicate to the BSP that an AP has exited SMM +after SMBASE relocation. + +Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "PiSmmCpuDxeSmm.h" + +extern UINT32 mSmmRelocationOriginalAddressPtr32; +extern UINT32 mRebasedFlagAddr32; + +UINTN mSmmRelocationOriginalAddress; +volatile BOOLEAN *mRebasedFlag; + +/** +AP Semaphore operation in 32-bit mode while BSP runs in 64-bit mode. +**/ +VOID +SmmRelocationSemaphoreComplete32 ( + VOID + ); + +/** + Hook return address of SMM Save State so that semaphore code + can be executed immediately after AP exits SMM to indicate to + the BSP that an AP has exited SMM after SMBASE relocation. + + @param[in] CpuIndex The processor index. + @param[in] RebasedFlag A pointer to a flag that is set to TRUE + immediately after AP exits SMM. + +**/ +VOID +SemaphoreHook ( + IN UINTN CpuIndex, + IN volatile BOOLEAN *RebasedFlag + ) +{ + SMRAM_SAVE_STATE_MAP *CpuState; + UINTN TempValue; + + mRebasedFlag = RebasedFlag; + mRebasedFlagAddr32 = (UINT32)(UINTN)mRebasedFlag; + + CpuState = (SMRAM_SAVE_STATE_MAP *)(UINTN)(SMM_DEFAULT_SMBASE + SMRAM_SAVE_STATE_MAP_OFFSET); + mSmmRelocationOriginalAddress = HookReturnFromSmm ( + CpuIndex, + CpuState, + (UINT64)(UINTN)&SmmRelocationSemaphoreComplete32, + (UINT64)(UINTN)&SmmRelocationSemaphoreComplete + ); + + // + // Use temp value to fix ICC complier warning + // + TempValue = (UINTN)&mSmmRelocationOriginalAddress; + mSmmRelocationOriginalAddressPtr32 = (UINT32)TempValue; +} diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmiEntry.S b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmiEntry.S new file mode 100644 index 000000000000..831559357f15 --- /dev/null +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmiEntry.S @@ -0,0 +1,217 @@ +#------------------------------------------------------------------------------ +# +# Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# Module Name: +# +# SmiEntry.S +# +# Abstract: +# +# Code template of the SMI handler for a particular processor +# +#------------------------------------------------------------------------------ + +ASM_GLOBAL ASM_PFX(gcSmiHandlerTemplate) +ASM_GLOBAL ASM_PFX(gcSmiHandlerSize) +ASM_GLOBAL ASM_PFX(gSmiCr3) +ASM_GLOBAL ASM_PFX(gSmiStack) +ASM_GLOBAL ASM_PFX(gSmbase) +ASM_GLOBAL ASM_PFX(FeaturePcdGet (PcdCpuSmmDebug)) +ASM_GLOBAL ASM_PFX(gSmiHandlerIdtr) + +# +# Constants relating to PROCESSOR_SMM_DESCRIPTOR +# +.equ DSC_OFFSET, 0xfb00 +.equ DSC_GDTPTR, 0x30 +.equ DSC_GDTSIZ, 0x38 +.equ DSC_CS, 14 +.equ DSC_DS, 16 +.equ DSC_SS, 18 +.equ DSC_OTHERSEG, 20 +# +# Constants relating to CPU State Save Area +# +.equ SSM_DR6, 0xffd0 +.equ SSM_DR7, 0xffc8 + +.equ PROTECT_MODE_CS, 0x08 +.equ PROTECT_MODE_DS, 0x20 +.equ LONG_MODE_CS, 0x38 +.equ TSS_SEGMENT, 0x40 +.equ GDT_SIZE, 0x50 + + .text + +ASM_PFX(gcSmiHandlerTemplate): + +_SmiEntryPoint: + # + # The encoding of BX in 16-bit addressing mode is the same as of RDI in 64- + # bit addressing mode. And that coincidence has been used in the following + # "64-bit like" 16-bit code. Be aware that once RDI is referenced as a + # base address register, it is actually BX that is referenced. + # + .byte 0xbb # mov bx, imm16 + .word _GdtDesc - _SmiEntryPoint + 0x8000 + # + # fix GDT descriptor + # + .byte 0x2e,0xa1 # mov ax, cs:[offset16] + .word DSC_OFFSET + DSC_GDTSIZ + .byte 0x48 # dec ax + .byte 0x2e + movl %eax, (%rdi) # mov cs:[bx], ax + .byte 0x66,0x2e,0xa1 # mov eax, cs:[offset16] + .word DSC_OFFSET + DSC_GDTPTR + .byte 0x2e + movw %ax, 2(%rdi) + .byte 0x66,0x2e + lgdt (%rdi) + # + # Patch ProtectedMode Segment + # + .byte 0xb8 + .word PROTECT_MODE_CS + .byte 0x2e + movl %eax, -2(%rdi) + # + # Patch ProtectedMode entry + # + .byte 0x66, 0xbf # mov edi, SMBASE +ASM_PFX(gSmbase): .space 4 + lea ((ProtectedMode - _SmiEntryPoint) + 0x8000)(%edi), %ax + .byte 0x2e + movw %ax, -6(%rdi) + # + # Switch into ProtectedMode + # + movq %cr0, %rbx + .byte 0x66 + andl $0x9ffafff3, %ebx + .byte 0x66 + orl $0x00000023, %ebx + + movq %rbx, %cr0 + .byte 0x66, 0xea + .space 6 + +_GdtDesc: .space 6 + +ProtectedMode: + movw $PROTECT_MODE_DS, %ax + movl %eax, %ds + movl %eax, %es + movl %eax, %fs + movl %eax, %gs + movl %eax, %ss + .byte 0xbc # mov esp, imm32 +ASM_PFX(gSmiStack): .space 4 + jmp ProtFlatMode + +ProtFlatMode: + .byte 0xb8 +ASM_PFX(gSmiCr3): .space 4 + movq %rax, %cr3 + movl $0x668,%eax # as cr4.PGE is not set here, refresh cr3 + movq %rax, %cr4 # in PreModifyMtrrs() to flush TLB. +# Load TSS + subl $8, %esp # reserve room in stack + sgdt (%rsp) + movl 2(%rsp), %eax # eax = GDT base + addl $8, %esp + movl %eax, %edx + addl $GDT_SIZE, %edx + movb %dl, (TSS_SEGMENT + 2)(%rax) + movb %dh, (TSS_SEGMENT + 3)(%rax) + .byte 0xc1, 0xea, 0x10 # shr edx, 16 + movb %dl, (TSS_SEGMENT + 4)(%rax) + movb %dh, (TSS_SEGMENT + 7)(%rax) + movl %eax, %edx + movb $0x89, %dl + movb %dl, (TSS_SEGMENT + 5)(%rax) # clear busy flag + movl $TSS_SEGMENT, %eax + ltr %ax + + # + # Switch to LongMode + # + pushq $LONG_MODE_CS # push cs hardcore here + call Base # push return address for retf later +Base: + addl $(LongMode - Base), (%rsp) # offset for far retf, seg is the 1st arg + movl $0xc0000080, %ecx + rdmsr + orb $1,%ah + wrmsr + movq %cr0, %rbx + btsl $31, %ebx + movq %rbx, %cr0 + retf +LongMode: # long mode (64-bit code) starts here + movabsq $ASM_PFX(gSmiHandlerIdtr), %rax + lidt (%rax) + lea (DSC_OFFSET)(%rdi), %ebx + movw DSC_DS(%rbx), %ax + movl %eax,%ds + movw DSC_OTHERSEG(%rbx), %ax + movl %eax,%es + movl %eax,%fs + movl %eax,%gs + movw DSC_SS(%rbx), %ax + movl %eax,%ss +# jmp _SmiHandler ; instruction is not needed + +_SmiHandler: + movabsq $ASM_PFX(FeaturePcdGet (PcdCpuSmmDebug)), %rax + cmpb $0, (%rax) + jz L1 + + .byte 0x48, 0x8b, 0x0d # mov rcx, [rip + disp32] + .long SSM_DR6 - (. + 4 - _SmiEntryPoint + 0x8000) + .byte 0x48, 0x8b, 0x15 # mov rdx, [rip + disp32] + .long SSM_DR7 - (. + 4 - _SmiEntryPoint + 0x8000) + movq %rcx, %dr6 + movq %rdx, %dr7 +L1: + + movabsq $ASM_PFX(SmiRendezvous), %rax + movq (%rsp), %rcx + # Save FP registers + + subq $0x208, %rsp + .byte 0x48 # FXSAVE64 + fxsave (%rsp) + + addq $-0x20, %rsp + call *%rax + addq $0x20, %rsp + + # + # Restore FP registers + # + .byte 0x48 # FXRSTOR64 + fxrstor (%rsp) + + movabsq $ASM_PFX(FeaturePcdGet (PcdCpuSmmDebug)), %rax + cmpb $0, (%rax) + jz L2 + + movq %dr7, %rdx + movq %dr6, %rcx + .byte 0x48, 0x89, 0x15 # mov [rip + disp32], rdx + .long SSM_DR7 - (. + 4 - _SmiEntryPoint + 0x8000) + .byte 0x48, 0x89, 0x0d # mov [rip + disp32], rcx + .long SSM_DR6 - (. + 4 - _SmiEntryPoint + 0x8000) +L2: + rsm + +ASM_PFX(gcSmiHandlerSize): .word . - _SmiEntryPoint diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmiEntry.asm b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmiEntry.asm new file mode 100644 index 000000000000..c556bf5f5b28 --- /dev/null +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmiEntry.asm @@ -0,0 +1,221 @@ +;------------------------------------------------------------------------------ ; +; Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.
+; This program and the accompanying materials +; are licensed and made available under the terms and conditions of the BSD License +; which accompanies this distribution. The full text of the license may be found at +; http://opensource.org/licenses/bsd-license.php. +; +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +; +; Module Name: +; +; SmiEntry.asm +; +; Abstract: +; +; Code template of the SMI handler for a particular processor +; +;------------------------------------------------------------------------------- + +; +; Variables referenced by C code +; +EXTERNDEF SmiRendezvous:PROC +EXTERNDEF gcSmiHandlerTemplate:BYTE +EXTERNDEF gcSmiHandlerSize:WORD +EXTERNDEF gSmiCr3:DWORD +EXTERNDEF gSmiStack:DWORD +EXTERNDEF gSmbase:DWORD +EXTERNDEF FeaturePcdGet (PcdCpuSmmDebug):BYTE +EXTERNDEF gSmiHandlerIdtr:FWORD + + +; +; Constants relating to PROCESSOR_SMM_DESCRIPTOR +; +DSC_OFFSET EQU 0fb00h +DSC_GDTPTR EQU 30h +DSC_GDTSIZ EQU 38h +DSC_CS EQU 14 +DSC_DS EQU 16 +DSC_SS EQU 18 +DSC_OTHERSEG EQU 20 +; +; Constants relating to CPU State Save Area +; +SSM_DR6 EQU 0ffd0h +SSM_DR7 EQU 0ffc8h + +PROTECT_MODE_CS EQU 08h +PROTECT_MODE_DS EQU 20h +LONG_MODE_CS EQU 38h +TSS_SEGMENT EQU 40h +GDT_SIZE EQU 50h + + .code + +gcSmiHandlerTemplate LABEL BYTE + +_SmiEntryPoint: + ; + ; The encoding of BX in 16-bit addressing mode is the same as of RDI in 64- + ; bit addressing mode. And that coincidence has been used in the following + ; "64-bit like" 16-bit code. Be aware that once RDI is referenced as a + ; base address register, it is actually BX that is referenced. + ; + DB 0bbh ; mov bx, imm16 + DW offset _GdtDesc - _SmiEntryPoint + 8000h ; bx = GdtDesc offset +; fix GDT descriptor + DB 2eh, 0a1h ; mov ax, cs:[offset16] + DW DSC_OFFSET + DSC_GDTSIZ + DB 48h ; dec ax + DB 2eh + mov [rdi], eax ; mov cs:[bx], ax + DB 66h, 2eh, 0a1h ; mov eax, cs:[offset16] + DW DSC_OFFSET + DSC_GDTPTR + DB 2eh + mov [rdi + 2], ax ; mov cs:[bx + 2], eax + DB 66h, 2eh + lgdt fword ptr [rdi] ; lgdt fword ptr cs:[bx] +; Patch ProtectedMode Segment + DB 0b8h ; mov ax, imm16 + DW PROTECT_MODE_CS ; set AX for segment directly + DB 2eh + mov [rdi - 2], eax ; mov cs:[bx - 2], ax +; Patch ProtectedMode entry + DB 66h, 0bfh ; mov edi, SMBASE +gSmbase DD ? + lea ax, [edi + (@ProtectedMode - _SmiEntryPoint) + 8000h] + DB 2eh + mov [rdi - 6], ax ; mov cs:[bx - 6], eax +; Switch into @ProtectedMode + mov rbx, cr0 + DB 66h + and ebx, 9ffafff3h + DB 66h + or ebx, 00000023h + + mov cr0, rbx + DB 66h, 0eah + DD ? + DW ? + +_GdtDesc FWORD ? +@ProtectedMode: + mov ax, PROTECT_MODE_DS + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + DB 0bch ; mov esp, imm32 +gSmiStack DD ? + jmp ProtFlatMode + +ProtFlatMode: + DB 0b8h ; mov eax, offset gSmiCr3 +gSmiCr3 DD ? + mov cr3, rax + mov eax, 668h ; as cr4.PGE is not set here, refresh cr3 + mov cr4, rax ; in PreModifyMtrrs() to flush TLB. +; Load TSS + sub esp, 8 ; reserve room in stack + sgdt fword ptr [rsp] + mov eax, [rsp + 2] ; eax = GDT base + add esp, 8 + mov edx, eax + add edx, GDT_SIZE + mov [rax + TSS_SEGMENT + 2], dl + mov [rax + TSS_SEGMENT + 3], dh + DB 0c1h, 0eah, 10h ; shr edx, 16 + mov [rax + TSS_SEGMENT + 4], dl + mov [rax + TSS_SEGMENT + 7], dh + mov edx, eax + mov dl, 89h + mov [rax + TSS_SEGMENT + 5], dl ; clear busy flag + mov eax, TSS_SEGMENT + ltr ax + +; Switch into @LongMode + push LONG_MODE_CS ; push cs hardcore here + call Base ; push return address for retf later +Base: + add dword ptr [rsp], @LongMode - Base; offset for far retf, seg is the 1st arg + mov ecx, 0c0000080h + rdmsr + or ah, 1 + wrmsr + mov rbx, cr0 + bts ebx, 31 + mov cr0, rbx + retf +@LongMode: ; long mode (64-bit code) starts here + mov rax, offset gSmiHandlerIdtr + lidt fword ptr [rax] + lea ebx, [rdi + DSC_OFFSET] + mov ax, [rbx + DSC_DS] + mov ds, eax + mov ax, [rbx + DSC_OTHERSEG] + mov es, eax + mov fs, eax + mov gs, eax + mov ax, [rbx + DSC_SS] + mov ss, eax +; jmp _SmiHandler ; instruction is not needed + +_SmiHandler: +; +; The following lines restore DR6 & DR7 before running C code. They are useful +; when you want to enable hardware breakpoints in SMM. +; +; NOTE: These lines might not be appreciated in runtime since they might +; conflict with OS debugging facilities. Turn them off in RELEASE. +; + mov rax, offset FeaturePcdGet (PcdCpuSmmDebug) ;Get absolute address. Avoid RIP relative addressing + cmp byte ptr [rax], 0 + jz @1 + + DB 48h, 8bh, 0dh ; mov rcx, [rip + disp32] + DD SSM_DR6 - ($ + 4 - _SmiEntryPoint + 8000h) + DB 48h, 8bh, 15h ; mov rdx, [rip + disp32] + DD SSM_DR7 - ($ + 4 - _SmiEntryPoint + 8000h) + mov dr6, rcx + mov dr7, rdx +@1: + mov rcx, [rsp] ; rcx <- CpuIndex + mov rax, SmiRendezvous ; rax <- absolute addr of SmiRedezvous + + ; + ; Save FP registers + ; + sub rsp, 208h + DB 48h ; FXSAVE64 + fxsave [rsp] + + add rsp, -20h + call rax + add rsp, 20h + + ; + ; Restore FP registers + ; + DB 48h ; FXRSTOR64 + fxrstor [rsp] + + mov rax, offset FeaturePcdGet (PcdCpuSmmDebug) ;Get absolute address. Avoid RIP relative addressing + cmp byte ptr [rax], 0 + jz @2 + + mov rdx, dr7 + mov rcx, dr6 + DB 48h, 89h, 15h ; mov [rip + disp32], rdx + DD SSM_DR7 - ($ + 4 - _SmiEntryPoint + 8000h) + DB 48h, 89h, 0dh ; mov [rip + disp32], rcx + DD SSM_DR6 - ($ + 4 - _SmiEntryPoint + 8000h) +@2: + rsm + +gcSmiHandlerSize DW $ - _SmiEntryPoint + + END diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmiException.S b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmiException.S new file mode 100644 index 000000000000..6dbcaa5b6714 --- /dev/null +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmiException.S @@ -0,0 +1,610 @@ +#------------------------------------------------------------------------------ +# +# Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# Module Name: +# +# SmiException.S +# +# Abstract: +# +# Exception handlers used in SM mode +# +#------------------------------------------------------------------------------ + +ASM_GLOBAL ASM_PFX(SmiPFHandler) +ASM_GLOBAL ASM_PFX(gSmiMtrrs) +ASM_GLOBAL ASM_PFX(gcSmiIdtr) +ASM_GLOBAL ASM_PFX(gcSmiGdtr) +ASM_GLOBAL ASM_PFX(gcPsd) + + .data + +NullSeg: .quad 0 # reserved by architecture +CodeSeg32: + .word -1 # LimitLow + .word 0 # BaseLow + .byte 0 # BaseMid + .byte 0x9b + .byte 0xcf # LimitHigh + .byte 0 # BaseHigh +ProtModeCodeSeg32: + .word -1 # LimitLow + .word 0 # BaseLow + .byte 0 # BaseMid + .byte 0x9b + .byte 0xcf # LimitHigh + .byte 0 # BaseHigh +ProtModeSsSeg32: + .word -1 # LimitLow + .word 0 # BaseLow + .byte 0 # BaseMid + .byte 0x93 + .byte 0xcf # LimitHigh + .byte 0 # BaseHigh +DataSeg32: + .word -1 # LimitLow + .word 0 # BaseLow + .byte 0 # BaseMid + .byte 0x93 + .byte 0xcf # LimitHigh + .byte 0 # BaseHigh +CodeSeg16: + .word -1 + .word 0 + .byte 0 + .byte 0x9b + .byte 0x8f + .byte 0 +DataSeg16: + .word -1 + .word 0 + .byte 0 + .byte 0x93 + .byte 0x8f + .byte 0 +CodeSeg64: + .word -1 # LimitLow + .word 0 # BaseLow + .byte 0 # BaseMid + .byte 0x9b + .byte 0xaf # LimitHigh + .byte 0 # BaseHigh +# TSS Segment for X64 specially +TssSeg: + .word TSS_DESC_SIZE # LimitLow + .word 0 # BaseLow + .byte 0 # BaseMid + .byte 0x89 + .byte 0xDB # LimitHigh + .byte 0 # BaseHigh + .long 0 # BaseUpper + .long 0 # Reserved +.equ GDT_SIZE, .- NullSeg + +TssDescriptor: + .space 104, 0 +.equ TSS_DESC_SIZE, .- TssDescriptor + +# +# This structure serves as a template for all processors. +# +ASM_PFX(gcPsd): + .ascii "PSDSIG " + .word PSD_SIZE + .word 2 + .word 1 << 2 + .word CODE_SEL + .word DATA_SEL + .word DATA_SEL + .word DATA_SEL + .word 0 + .quad 0 + .quad 0 + .quad 0 # fixed in InitializeMpServiceData() + .quad NullSeg + .long GDT_SIZE + .long 0 + .space 24, 0 + .quad ASM_PFX(gSmiMtrrs) +.equ PSD_SIZE, . - ASM_PFX(gcPsd) + +# +# CODE & DATA segments for SMM runtime +# +.equ CODE_SEL, CodeSeg64 - NullSeg +.equ DATA_SEL, DataSeg32 - NullSeg +.equ CODE32_SEL, CodeSeg32 - NullSeg + +ASM_PFX(gcSmiGdtr): + .word GDT_SIZE - 1 + .quad NullSeg + +ASM_PFX(gcSmiIdtr): + .word IDT_SIZE - 1 + .quad _SmiIDT + + +# +# Here is the IDT. There are 32 (not 255) entries in it since only processor +# generated exceptions will be handled. +# +_SmiIDT: +# The following segment repeats 32 times: +# No. 1 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 + .quad 0 # Offset 32:63 +# No. 2 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 + .quad 0 # Offset 32:63 +# No. 3 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 + .quad 0 # Offset 32:63 +# No. 4 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 + .quad 0 # Offset 32:63 +# No. 5 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 + .quad 0 # Offset 32:63 +# No. 6 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 + .quad 0 # Offset 32:63 +# No. 7 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 + .quad 0 # Offset 32:63 +# No. 8 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 + .quad 0 # Offset 32:63 +# No. 9 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 + .quad 0 # Offset 32:63 +# No. 10 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 + .quad 0 # Offset 32:63 +# No. 11 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 + .quad 0 # Offset 32:63 +# No. 12 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 + .quad 0 # Offset 32:63 +# No. 13 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 + .quad 0 # Offset 32:63 +# No. 14 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 + .quad 0 # Offset 32:63 +# No. 15 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 + .quad 0 # Offset 32:63 +# No. 16 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 + .quad 0 # Offset 32:63 +# No. 17 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 + .quad 0 # Offset 32:63 +# No. 18 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 + .quad 0 # Offset 32:63 +# No. 19 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 + .quad 0 # Offset 32:63 +# No. 20 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 + .quad 0 # Offset 32:63 +# No. 21 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 + .quad 0 # Offset 32:63 +# No. 22 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 + .quad 0 # Offset 32:63 +# No. 23 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 + .quad 0 # Offset 32:63 +# No. 24 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 + .quad 0 # Offset 32:63 +# No. 25 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 + .quad 0 # Offset 32:63 +# No. 26 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 + .quad 0 # Offset 32:63 +# No. 27 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 + .quad 0 # Offset 32:63 +# No. 28 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 + .quad 0 # Offset 32:63 +# No. 29 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 + .quad 0 # Offset 32:63 +# No. 30 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 + .quad 0 # Offset 32:63 +# No. 31 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 + .quad 0 # Offset 32:63 +# No. 32 + .word 0 # Offset 0:15 + .word CODE_SEL + .byte 0 # Unused + .byte 0x8e # Interrupt Gate, Present + .word 0 # Offset 16:31 + .quad 0 # Offset 32:63 + +_SmiIDTEnd: + +.equ IDT_SIZE, (_SmiIDTEnd - _SmiIDT) + + .text + +#------------------------------------------------------------------------------ +# _SmiExceptionEntryPoints is the collection of exception entry points followed +# by a common exception handler. +# +# Stack frame would be as follows as specified in IA32 manuals: +# +---------------------+ <-- 16-byte aligned ensured by processor +# + Old SS + +# +---------------------+ +# + Old RSP + +# +---------------------+ +# + RFlags + +# +---------------------+ +# + CS + +# +---------------------+ +# + RIP + +# +---------------------+ +# + Error Code + +# +---------------------+ +# + Vector Number + +# +---------------------+ +# + RBP + +# +---------------------+ <-- RBP, 16-byte aligned +# +# RSP set to odd multiple of 8 at @CommonEntryPoint means ErrCode PRESENT +#------------------------------------------------------------------------------ +ASM_GLOBAL ASM_PFX(PageFaultIdtHandlerSmmProfile) +ASM_PFX(PageFaultIdtHandlerSmmProfile): + pushq $0x0e # Page Fault + .byte 0x40, 0xf6, 0xc4, 0x08 #test spl, 8 + jnz L1 + pushq (%rsp) + movq $0, 8(%rsp) +L1: + pushq %rbp + movq %rsp, %rbp + + # + # Since here the stack pointer is 16-byte aligned, so + # EFI_FX_SAVE_STATE_X64 of EFI_SYSTEM_CONTEXT_x64 + # is 16-byte aligned + # + +## UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax; +## UINT64 R8, R9, R10, R11, R12, R13, R14, R15; + pushq %r15 + pushq %r14 + pushq %r13 + pushq %r12 + pushq %r11 + pushq %r10 + pushq %r9 + pushq %r8 + pushq %rax + pushq %rcx + pushq %rdx + pushq %rbx + pushq 48(%rbp) # RSP + pushq (%rbp) # RBP + pushq %rsi + pushq %rdi + +## UINT64 Gs, Fs, Es, Ds, Cs, Ss; insure high 16 bits of each is zero + movzwq 56(%rbp), %rax + pushq %rax # for ss + movzwq 32(%rbp), %rax + pushq %rax # for cs + movq %ds, %rax + pushq %rax + movq %es, %rax + pushq %rax + movq %fs, %rax + pushq %rax + movq %gs, %rax + pushq %rax + +## UINT64 Rip; + pushq 24(%rbp) + +## UINT64 Gdtr[2], Idtr[2]; + subq $16, %rsp + sidt (%rsp) + subq $16, %rsp + sgdt (%rsp) + +## UINT64 Ldtr, Tr; + xorq %rax, %rax + strw %ax + pushq %rax + sldtw %ax + pushq %rax + +## UINT64 RFlags; + pushq 40(%rbp) + +## UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8; + movq %cr8, %rax + pushq %rax + movq %cr4, %rax + orq $0x208, %rax + movq %rax, %cr4 + pushq %rax + movq %cr3, %rax + pushq %rax + movq %cr2, %rax + pushq %rax + xorq %rax, %rax + pushq %rax + movq %cr0, %rax + pushq %rax + +## UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; + movq %dr7, %rax + pushq %rax + movq %dr6, %rax + pushq %rax + movq %dr3, %rax + pushq %rax + movq %dr2, %rax + pushq %rax + movq %dr1, %rax + pushq %rax + movq %dr0, %rax + pushq %rax + +## FX_SAVE_STATE_X64 FxSaveState; + + subq $512, %rsp + movq %rsp, %rdi + .byte 0xf, 0xae, 0x7 # fxsave [rdi] + +# UEFI calling convention for x64 requires that Direction flag in EFLAGs is clear + cld + +## UINT32 ExceptionData; + pushq 16(%rbp) + +## call into exception handler + movq 8(%rbp), %rcx + movabsq $ASM_PFX(SmiPFHandler), %rax + +## Prepare parameter and call + movq %rsp, %rdx + # + # Per X64 calling convention, allocate maximum parameter stack space + # and make sure RSP is 16-byte aligned + # + subq $4 * 8 + 8, %rsp + call *%rax + addq $4 * 8 + 8, %rsp + jmp L5 + +L5: +## UINT64 ExceptionData; + addq $8, %rsp + +## FX_SAVE_STATE_X64 FxSaveState; + + movq %rsp, %rsi + .byte 0xf, 0xae, 0xe # fxrstor [rsi] + addq $512, %rsp + +## UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; +## Skip restoration of DRx registers to support debuggers +## that set breakpoints in interrupt/exception context + addq $8 * 6, %rsp + +## UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8; + popq %rax + movq %rax, %cr0 + addq $8, %rsp # not for Cr1 + popq %rax + movq %rax, %cr2 + popq %rax + movq %rax, %cr3 + popq %rax + movq %rax, %cr4 + popq %rax + movq %rax, %cr8 + +## UINT64 RFlags; + popq 40(%rbp) + +## UINT64 Ldtr, Tr; +## UINT64 Gdtr[2], Idtr[2]; +## Best not let anyone mess with these particular registers... + addq $48, %rsp + +## UINT64 Rip; + popq 24(%rbp) + +## UINT64 Gs, Fs, Es, Ds, Cs, Ss; + popq %rax + # mov gs, rax ; not for gs + popq %rax + # mov fs, rax ; not for fs + # (X64 will not use fs and gs, so we do not restore it) + popq %rax + movq %rax, %es + popq %rax + movq %rax, %ds + popq 32(%rbp) # for cs + popq 56(%rbp) # for ss + +## UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax; +## UINT64 R8, R9, R10, R11, R12, R13, R14, R15; + popq %rdi + popq %rsi + addq $8, %rsp # not for rbp + popq 48(%rbp) # for rsp + popq %rbx + popq %rdx + popq %rcx + popq %rax + popq %r8 + popq %r9 + popq %r10 + popq %r11 + popq %r12 + popq %r13 + popq %r14 + popq %r15 + + movq %rbp, %rsp + +# Enable TF bit after page fault handler runs + btsl $8, 40(%rsp) #RFLAGS + + popq %rbp + addq $16, %rsp # skip INT# & ErrCode + iretq + +ASM_GLOBAL ASM_PFX(InitializeIDTSmmStackGuard) +ASM_PFX(InitializeIDTSmmStackGuard): +# If SMM Stack Guard feature is enabled, set the IST field of +# the interrupt gate for Page Fault Exception to be 1 +# + movabsq $_SmiIDT + 14 * 16, %rax + movb $1, 4(%rax) + ret diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmiException.asm b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmiException.asm new file mode 100644 index 000000000000..3d841c654676 --- /dev/null +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmiException.asm @@ -0,0 +1,413 @@ +;------------------------------------------------------------------------------ ; +; Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.
+; This program and the accompanying materials +; are licensed and made available under the terms and conditions of the BSD License +; which accompanies this distribution. The full text of the license may be found at +; http://opensource.org/licenses/bsd-license.php. +; +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +; +; Module Name: +; +; SmiException.asm +; +; Abstract: +; +; Exception handlers used in SM mode +; +;------------------------------------------------------------------------------- + +EXTERNDEF SmiPFHandler:PROC +EXTERNDEF gSmiMtrrs:QWORD +EXTERNDEF gcSmiIdtr:FWORD +EXTERNDEF gcSmiGdtr:FWORD +EXTERNDEF gcPsd:BYTE + + .const + +NullSeg DQ 0 ; reserved by architecture +CodeSeg32 LABEL QWORD + DW -1 ; LimitLow + DW 0 ; BaseLow + DB 0 ; BaseMid + DB 9bh + DB 0cfh ; LimitHigh + DB 0 ; BaseHigh +ProtModeCodeSeg32 LABEL QWORD + DW -1 ; LimitLow + DW 0 ; BaseLow + DB 0 ; BaseMid + DB 9bh + DB 0cfh ; LimitHigh + DB 0 ; BaseHigh +ProtModeSsSeg32 LABEL QWORD + DW -1 ; LimitLow + DW 0 ; BaseLow + DB 0 ; BaseMid + DB 93h + DB 0cfh ; LimitHigh + DB 0 ; BaseHigh +DataSeg32 LABEL QWORD + DW -1 ; LimitLow + DW 0 ; BaseLow + DB 0 ; BaseMid + DB 93h + DB 0cfh ; LimitHigh + DB 0 ; BaseHigh +CodeSeg16 LABEL QWORD + DW -1 + DW 0 + DB 0 + DB 9bh + DB 8fh + DB 0 +DataSeg16 LABEL QWORD + DW -1 + DW 0 + DB 0 + DB 93h + DB 8fh + DB 0 +CodeSeg64 LABEL QWORD + DW -1 ; LimitLow + DW 0 ; BaseLow + DB 0 ; BaseMid + DB 9bh + DB 0afh ; LimitHigh + DB 0 ; BaseHigh +; TSS Segment for X64 specially +TssSeg LABEL QWORD + DW TSS_DESC_SIZE ; LimitLow + DW 0 ; BaseLow + DB 0 ; BaseMid + DB 89h + DB 080h ; LimitHigh + DB 0 ; BaseHigh + DD 0 ; BaseUpper + DD 0 ; Reserved +GDT_SIZE = $ - offset NullSeg + +; Create TSS Descriptor just after GDT +TssDescriptor LABEL BYTE + DD 0 ; Reserved + DQ 0 ; RSP0 + DQ 0 ; RSP1 + DQ 0 ; RSP2 + DD 0 ; Reserved + DD 0 ; Reserved + DQ 0 ; IST1 + DQ 0 ; IST2 + DQ 0 ; IST3 + DQ 0 ; IST4 + DQ 0 ; IST5 + DQ 0 ; IST6 + DQ 0 ; IST7 + DD 0 ; Reserved + DD 0 ; Reserved + DW 0 ; Reserved + DW 0 ; I/O Map Base Address +TSS_DESC_SIZE = $ - offset TssDescriptor + +; +; This structure serves as a template for all processors. +; +gcPsd LABEL BYTE + DB 'PSDSIG ' + DW PSD_SIZE + DW 2 + DW 1 SHL 2 + DW CODE_SEL + DW DATA_SEL + DW DATA_SEL + DW DATA_SEL + DW 0 + DQ 0 + DQ 0 + DQ 0 ; fixed in InitializeMpServiceData() + DQ offset NullSeg + DD GDT_SIZE + DD 0 + DB 24 dup (0) + DQ offset gSmiMtrrs +PSD_SIZE = $ - offset gcPsd + +; +; CODE & DATA segments for SMM runtime +; +CODE_SEL = offset CodeSeg64 - offset NullSeg +DATA_SEL = offset DataSeg32 - offset NullSeg +CODE32_SEL = offset CodeSeg32 - offset NullSeg + +gcSmiGdtr LABEL FWORD + DW GDT_SIZE - 1 + DQ offset NullSeg + +gcSmiIdtr LABEL FWORD + DW IDT_SIZE - 1 + DQ offset _SmiIDT + + .data + +; +; Here is the IDT. There are 32 (not 255) entries in it since only processor +; generated exceptions will be handled. +; +_SmiIDT: +REPEAT 32 + DW 0 ; Offset 0:15 + DW CODE_SEL ; Segment selector + DB 0 ; Unused + DB 8eh ; Interrupt Gate, Present + DW 0 ; Offset 16:31 + DQ 0 ; Offset 32:63 + ENDM +_SmiIDTEnd: + +IDT_SIZE = (offset _SmiIDTEnd - offset _SmiIDT) + + .code + +;------------------------------------------------------------------------------ +; _SmiExceptionEntryPoints is the collection of exception entry points followed +; by a common exception handler. +; +; Stack frame would be as follows as specified in IA32 manuals: +; +; +---------------------+ <-- 16-byte aligned ensured by processor +; + Old SS + +; +---------------------+ +; + Old RSP + +; +---------------------+ +; + RFlags + +; +---------------------+ +; + CS + +; +---------------------+ +; + RIP + +; +---------------------+ +; + Error Code + +; +---------------------+ +; + Vector Number + +; +---------------------+ +; + RBP + +; +---------------------+ <-- RBP, 16-byte aligned +; +; RSP set to odd multiple of 8 at @CommonEntryPoint means ErrCode PRESENT +;------------------------------------------------------------------------------ +PageFaultIdtHandlerSmmProfile PROC + push 0eh ; Page Fault + test spl, 8 ; odd multiple of 8 => ErrCode present + jnz @F + push [rsp] ; duplicate INT# if no ErrCode + mov qword ptr [rsp + 8], 0 +@@: + push rbp + mov rbp, rsp + + ; + ; Since here the stack pointer is 16-byte aligned, so + ; EFI_FX_SAVE_STATE_X64 of EFI_SYSTEM_CONTEXT_x64 + ; is 16-byte aligned + ; + +;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax; +;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15; + push r15 + push r14 + push r13 + push r12 + push r11 + push r10 + push r9 + push r8 + push rax + push rcx + push rdx + push rbx + push qword ptr [rbp + 48] ; RSP + push qword ptr [rbp] ; RBP + push rsi + push rdi + +;; UINT64 Gs, Fs, Es, Ds, Cs, Ss; insure high 16 bits of each is zero + movzx rax, word ptr [rbp + 56] + push rax ; for ss + movzx rax, word ptr [rbp + 32] + push rax ; for cs + mov rax, ds + push rax + mov rax, es + push rax + mov rax, fs + push rax + mov rax, gs + push rax + +;; UINT64 Rip; + push qword ptr [rbp + 24] + +;; UINT64 Gdtr[2], Idtr[2]; + sub rsp, 16 + sidt fword ptr [rsp] + sub rsp, 16 + sgdt fword ptr [rsp] + +;; UINT64 Ldtr, Tr; + xor rax, rax + str ax + push rax + sldt ax + push rax + +;; UINT64 RFlags; + push qword ptr [rbp + 40] + +;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8; + mov rax, cr8 + push rax + mov rax, cr4 + or rax, 208h + mov cr4, rax + push rax + mov rax, cr3 + push rax + mov rax, cr2 + push rax + xor rax, rax + push rax + mov rax, cr0 + push rax + +;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; + mov rax, dr7 + push rax + mov rax, dr6 + push rax + mov rax, dr3 + push rax + mov rax, dr2 + push rax + mov rax, dr1 + push rax + mov rax, dr0 + push rax + +;; FX_SAVE_STATE_X64 FxSaveState; + + sub rsp, 512 + mov rdi, rsp + db 0fh, 0aeh, 00000111y ;fxsave [rdi] + +; UEFI calling convention for x64 requires that Direction flag in EFLAGs is clear + cld + +;; UINT32 ExceptionData; + push qword ptr [rbp + 16] + +;; call into exception handler + mov rcx, [rbp + 8] + mov rax, SmiPFHandler + +;; Prepare parameter and call + mov rdx, rsp + ; + ; Per X64 calling convention, allocate maximum parameter stack space + ; and make sure RSP is 16-byte aligned + ; + sub rsp, 4 * 8 + 8 + call rax + add rsp, 4 * 8 + 8 + jmp @F + +@@: +;; UINT64 ExceptionData; + add rsp, 8 + +;; FX_SAVE_STATE_X64 FxSaveState; + + mov rsi, rsp + db 0fh, 0aeh, 00001110y ; fxrstor [rsi] + add rsp, 512 + +;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; +;; Skip restoration of DRx registers to support debuggers +;; that set breakpoints in interrupt/exception context + add rsp, 8 * 6 + +;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8; + pop rax + mov cr0, rax + add rsp, 8 ; not for Cr1 + pop rax + mov cr2, rax + pop rax + mov cr3, rax + pop rax + mov cr4, rax + pop rax + mov cr8, rax + +;; UINT64 RFlags; + pop qword ptr [rbp + 40] + +;; UINT64 Ldtr, Tr; +;; UINT64 Gdtr[2], Idtr[2]; +;; Best not let anyone mess with these particular registers... + add rsp, 48 + +;; UINT64 Rip; + pop qword ptr [rbp + 24] + +;; UINT64 Gs, Fs, Es, Ds, Cs, Ss; + pop rax + ; mov gs, rax ; not for gs + pop rax + ; mov fs, rax ; not for fs + ; (X64 will not use fs and gs, so we do not restore it) + pop rax + mov es, rax + pop rax + mov ds, rax + pop qword ptr [rbp + 32] ; for cs + pop qword ptr [rbp + 56] ; for ss + +;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax; +;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15; + pop rdi + pop rsi + add rsp, 8 ; not for rbp + pop qword ptr [rbp + 48] ; for rsp + pop rbx + pop rdx + pop rcx + pop rax + pop r8 + pop r9 + pop r10 + pop r11 + pop r12 + pop r13 + pop r14 + pop r15 + + mov rsp, rbp + +; Enable TF bit after page fault handler runs + bts dword ptr [rsp + 40], 8 ;RFLAGS + + pop rbp + add rsp, 16 ; skip INT# & ErrCode + iretq +PageFaultIdtHandlerSmmProfile ENDP + +InitializeIDTSmmStackGuard PROC +; +; If SMM Stack Guard feature is enabled, set the IST field of +; the interrupt gate for Page Fault Exception to be 1 +; + lea rax, _SmiIDT + 14 * 16 + mov byte ptr [rax + 4], 1 + ret +InitializeIDTSmmStackGuard ENDP + + END diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmInit.S b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmInit.S new file mode 100644 index 000000000000..5e352f57c379 --- /dev/null +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmInit.S @@ -0,0 +1,141 @@ +#------------------------------------------------------------------------------ +# +# Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# Module Name: +# +# SmmInit.S +# +# Abstract: +# +# Functions for relocating SMBASE's for all processors +# +#------------------------------------------------------------------------------ + +ASM_GLOBAL ASM_PFX(gSmmCr0) +ASM_GLOBAL ASM_PFX(gSmmCr3) +ASM_GLOBAL ASM_PFX(gSmmCr4) +ASM_GLOBAL ASM_PFX(gSmmJmpAddr) +ASM_GLOBAL ASM_PFX(gcSmmInitTemplate) +ASM_GLOBAL ASM_PFX(gcSmmInitSize) +ASM_GLOBAL ASM_PFX(mRebasedFlagAddr32) +ASM_GLOBAL ASM_PFX(SmmRelocationSemaphoreComplete) +ASM_GLOBAL ASM_PFX(SmmRelocationSemaphoreComplete32) +ASM_GLOBAL ASM_PFX(mSmmRelocationOriginalAddressPtr32) +ASM_GLOBAL ASM_PFX(gSmmInitStack) +ASM_GLOBAL ASM_PFX(gcSmiInitGdtr) + + + .text + +ASM_PFX(gcSmiInitGdtr): + .word 0 + .quad 0 + +SmmStartup: + .byte 0x66,0xb8 # mov eax, imm32 +ASM_PFX(gSmmCr3): .space 4 + movq %rax, %cr3 + .byte 0x66,0x2e + lgdt (ASM_PFX(gcSmiInitGdtr) - SmmStartup)(%ebp) + .byte 0x66,0xb8 # mov eax, imm32 +ASM_PFX(gSmmCr4): .space 4 + orb $2, %ah # enable XMM registers access + movq %rax, %cr4 + .byte 0x66 + movl $0xc0000080,%ecx # IA32_EFER MSR + rdmsr + orb $1,%ah # set LME bit + wrmsr + .byte 0x66,0xb8 # mov eax, imm32 +ASM_PFX(gSmmCr0): .space 4 + movq %rax, %cr0 + .byte 0x66,0xea # far jmp to long mode +ASM_PFX(gSmmJmpAddr): .quad LongMode +LongMode: # long-mode starts here + .byte 0x48,0xbc # mov rsp, imm64 +ASM_PFX(gSmmInitStack): .space 8 + andw $0xfff0, %sp # make sure RSP is 16-byte aligned + # + # Accoring to X64 calling convention, XMM0~5 are volatile, we need to save + # them before calling C-function. + # + subq $0x60, %rsp + movdqa %xmm0, 0x0(%rsp) + movdqa %xmm1, 0x10(%rsp) + movdqa %xmm2, 0x20(%rsp) + movdqa %xmm3, 0x30(%rsp) + movdqa %xmm4, 0x40(%rsp) + movdqa %xmm5, 0x50(%rsp) + + + addq $-0x20, %rsp + call ASM_PFX(SmmInitHandler) + addq $0x20, %rsp + # + # Restore XMM0~5 after calling C-function. + # + movdqa 0x0(%rsp), %xmm0 + movdqa 0x10(%rsp), %xmm1 + movdqa 0x20(%rsp), %xmm2 + movdqa 0x30(%rsp), %xmm3 + movdqa 0x40(%rsp), %xmm4 + movdqa 0x50(%rsp), %xmm5 + + rsm + +ASM_PFX(gcSmmInitTemplate): + +_SmmInitTemplate: + .byte 0x66,0x2e,0x8b,0x2e # mov ebp, cs:[@F] + .word L1 - _SmmInitTemplate + 0x8000 + .byte 0x66, 0x81, 0xed, 0, 0, 3, 0 # sub ebp, 0x30000 + jmp *%bp # jmp ebp actually +L1: + .quad SmmStartup + +ASM_PFX(gcSmmInitSize): .word . - ASM_PFX(gcSmmInitTemplate) + +ASM_PFX(SmmRelocationSemaphoreComplete): + # Create a simple stack frame to store RAX and the original RSM location + pushq %rax # Used to store return address + pushq %rax + + # Load the original RSM location onto stack + movabsq $ASM_PFX(mSmmRelocationOriginalAddress), %rax + movq (%rax), %rax + movq %rax, 0x08(%rsp) + + # Update rebase flag + movabsq $ASM_PFX(mRebasedFlag), %rax + movq (%rax), %rax + movb $1, (%rax) + + #restore RAX and return to original RSM location + popq %rax + retq + +# +# Semaphore code running in 32-bit mode +# +ASM_PFX(SmmRelocationSemaphoreComplete32): + # + # movb $1, () + # + .byte 0xc6, 0x05 +ASM_PFX(mRebasedFlagAddr32): + .long 0 + .byte 1 + # + # jmpd () + # + .byte 0xff, 0x25 +ASM_PFX(mSmmRelocationOriginalAddressPtr32): + .long 0 diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmInit.asm b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmInit.asm new file mode 100644 index 000000000000..9182f0293a6f --- /dev/null +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmInit.asm @@ -0,0 +1,132 @@ +;------------------------------------------------------------------------------ ; +; Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.
+; This program and the accompanying materials +; are licensed and made available under the terms and conditions of the BSD License +; which accompanies this distribution. The full text of the license may be found at +; http://opensource.org/licenses/bsd-license.php. +; +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +; +; Module Name: +; +; SmmInit.Asm +; +; Abstract: +; +; Functions for relocating SMBASE's for all processors +; +;------------------------------------------------------------------------------- + +EXTERNDEF SmmInitHandler:PROC +EXTERNDEF gSmmCr0:DWORD +EXTERNDEF gSmmCr3:DWORD +EXTERNDEF gSmmCr4:DWORD +EXTERNDEF gSmmJmpAddr:QWORD +EXTERNDEF gcSmmInitTemplate:BYTE +EXTERNDEF gcSmmInitSize:WORD +EXTERNDEF mRebasedFlag:PTR BYTE +EXTERNDEF mSmmRelocationOriginalAddress:QWORD +EXTERNDEF mRebasedFlagAddr32:DWORD +EXTERNDEF mSmmRelocationOriginalAddressPtr32:DWORD +EXTERNDEF gSmmInitStack:QWORD +EXTERNDEF gcSmiInitGdtr:FWORD + + .code + +gcSmiInitGdtr LABEL FWORD + DW 0 + DQ 0 + +SmmStartup PROC + DB 66h, 0b8h ; mov eax, imm32 +gSmmCr3 DD ? + mov cr3, rax + DB 66h, 2eh + lgdt fword ptr [ebp + (offset gcSmiInitGdtr - SmmStartup)] + DB 66h, 0b8h ; mov eax, imm32 +gSmmCr4 DD ? + or ah, 2 ; enable XMM registers access + mov cr4, rax + DB 66h + mov ecx, 0c0000080h ; IA32_EFER MSR + rdmsr + or ah, 1 ; set LME bit + wrmsr + DB 66h, 0b8h ; mov eax, imm32 +gSmmCr0 DD ? + mov cr0, rax ; enable protected mode & paging + DB 66h, 0eah ; far jmp to long mode +gSmmJmpAddr DQ @LongMode +@LongMode: ; long-mode starts here + DB 48h, 0bch ; mov rsp, imm64 +gSmmInitStack DQ ? + and sp, 0fff0h ; make sure RSP is 16-byte aligned + ; + ; Accoring to X64 calling convention, XMM0~5 are volatile, we need to save + ; them before calling C-function. + ; + sub rsp, 60h + movdqa [rsp], xmm0 + movdqa [rsp + 10h], xmm1 + movdqa [rsp + 20h], xmm2 + movdqa [rsp + 30h], xmm3 + movdqa [rsp + 40h], xmm4 + movdqa [rsp + 50h], xmm5 + + add rsp, -20h + call SmmInitHandler + add rsp, 20h + + ; + ; Restore XMM0~5 after calling C-function. + ; + movdqa xmm0, [rsp] + movdqa xmm1, [rsp + 10h] + movdqa xmm2, [rsp + 20h] + movdqa xmm3, [rsp + 30h] + movdqa xmm4, [rsp + 40h] + movdqa xmm5, [rsp + 50h] + + rsm +SmmStartup ENDP + +gcSmmInitTemplate LABEL BYTE + +_SmmInitTemplate PROC + DB 66h, 2eh, 8bh, 2eh ; mov ebp, cs:[@F] + DW @L1 - _SmmInitTemplate + 8000h + DB 66h, 81h, 0edh, 00h, 00h, 03h, 00 ; sub ebp, 30000h + jmp bp ; jmp ebp actually +@L1: + DQ SmmStartup +_SmmInitTemplate ENDP + +gcSmmInitSize DW $ - gcSmmInitTemplate + +SmmRelocationSemaphoreComplete PROC + push rax + mov rax, mRebasedFlag + mov byte ptr [rax], 1 + pop rax + jmp [mSmmRelocationOriginalAddress] +SmmRelocationSemaphoreComplete ENDP + +; +; Semaphore code running in 32-bit mode +; +SmmRelocationSemaphoreComplete32 PROC + ; + ; mov byte ptr [], 1 + ; + db 0c6h, 05h +mRebasedFlagAddr32 dd 0 + db 1 + ; + ; jmp dword ptr [] + ; + db 0ffh, 25h +mSmmRelocationOriginalAddressPtr32 dd 0 +SmmRelocationSemaphoreComplete32 ENDP + + END diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmProfileArch.c b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmProfileArch.c new file mode 100644 index 000000000000..c4ec12debb1c --- /dev/null +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmProfileArch.c @@ -0,0 +1,316 @@ +/** @file +X64 processor specific functions to enable SMM profile. + +Copyright (c) 2012 - 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "PiSmmCpuDxeSmm.h" +#include "SmmProfileInternal.h" + +// +// Current page index. +// +UINTN mPFPageIndex; + +// +// Pool for dynamically creating page table in page fault handler. +// +UINT64 mPFPageBuffer; + +// +// Store the uplink information for each page being used. +// +UINT64 *mPFPageUplink[MAX_PF_PAGE_COUNT]; + +/** + Create SMM page table for S3 path. + +**/ +VOID +InitSmmS3Cr3 ( + VOID + ) +{ + EFI_PHYSICAL_ADDRESS Pages; + UINT64 *PTEntry; + + // + // Generate PAE page table for the first 4GB memory space + // + Pages = Gen4GPageTable (1); + + // + // Fill Page-Table-Level4 (PML4) entry + // + PTEntry = (UINT64*)(UINTN)(Pages - EFI_PAGES_TO_SIZE (1)); + *PTEntry = Pages + IA32_PG_P; + ZeroMem (PTEntry + 1, EFI_PAGE_SIZE - sizeof (*PTEntry)); + + // + // Return the address of PML4 (to set CR3) + // + mSmmS3ResumeState->SmmS3Cr3 = (UINT32)(UINTN)PTEntry; + + return ; +} + +/** + Allocate pages for creating 4KB-page based on 2MB-page when page fault happens. + +**/ +VOID +InitPagesForPFHandler ( + VOID + ) +{ + VOID *Address; + + // + // Pre-Allocate memory for page fault handler + // + Address = NULL; + Address = AllocatePages (MAX_PF_PAGE_COUNT); + ASSERT_EFI_ERROR (Address != NULL); + + mPFPageBuffer = (UINT64)(UINTN) Address; + mPFPageIndex = 0; + ZeroMem ((VOID *) (UINTN) mPFPageBuffer, EFI_PAGE_SIZE * MAX_PF_PAGE_COUNT); + ZeroMem (mPFPageUplink, sizeof (mPFPageUplink)); + + return; +} + +/** + Allocate one page for creating 4KB-page based on 2MB-page. + + @param Uplink The address of Page-Directory entry. + +**/ +VOID +AcquirePage ( + UINT64 *Uplink + ) +{ + UINT64 Address; + + // + // Get the buffer + // + Address = mPFPageBuffer + EFI_PAGES_TO_SIZE (mPFPageIndex); + ZeroMem ((VOID *) (UINTN) Address, EFI_PAGE_SIZE); + + // + // Cut the previous uplink if it exists and wasn't overwritten + // + if ((mPFPageUplink[mPFPageIndex] != NULL) && ((*mPFPageUplink[mPFPageIndex] & PHYSICAL_ADDRESS_MASK) == Address)) { + *mPFPageUplink[mPFPageIndex] = 0; + } + + // + // Link & Record the current uplink + // + *Uplink = Address | IA32_PG_P | IA32_PG_RW; + mPFPageUplink[mPFPageIndex] = Uplink; + + mPFPageIndex = (mPFPageIndex + 1) % MAX_PF_PAGE_COUNT; +} + +/** + Update page table to map the memory correctly in order to make the instruction + which caused page fault execute successfully. And it also save the original page + table to be restored in single-step exception. + + @param PageTable PageTable Address. + @param PFAddress The memory address which caused page fault exception. + @param CpuIndex The index of the processor. + @param ErrorCode The Error code of exception. + @param IsValidPFAddress The flag indicates if SMM profile data need be added. + +**/ +VOID +RestorePageTableAbove4G ( + UINT64 *PageTable, + UINT64 PFAddress, + UINTN CpuIndex, + UINTN ErrorCode, + BOOLEAN *IsValidPFAddress + ) +{ + UINTN PTIndex; + UINT64 Address; + BOOLEAN Nx; + BOOLEAN Existed; + UINTN Index; + UINTN PFIndex; + + ASSERT ((PageTable != NULL) && (IsValidPFAddress != NULL)); + + // + // If page fault address is 4GB above. + // + + // + // Check if page fault address has existed in page table. + // If it exists in page table but page fault is generated, + // there are 2 possible reasons: 1. present flag is set to 0; 2. instruction fetch in protected memory range. + // + Existed = FALSE; + PageTable = (UINT64*)(AsmReadCr3 () & PHYSICAL_ADDRESS_MASK); + PTIndex = BitFieldRead64 (PFAddress, 39, 47); + if ((PageTable[PTIndex] & IA32_PG_P) != 0) { + // PML4E + PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & PHYSICAL_ADDRESS_MASK); + PTIndex = BitFieldRead64 (PFAddress, 30, 38); + if ((PageTable[PTIndex] & IA32_PG_P) != 0) { + // PDPTE + PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & PHYSICAL_ADDRESS_MASK); + PTIndex = BitFieldRead64 (PFAddress, 21, 29); + // PD + if ((PageTable[PTIndex] & IA32_PG_PS) != 0) { + // + // 2MB page + // + Address = (UINT64)(PageTable[PTIndex] & PHYSICAL_ADDRESS_MASK); + if ((Address & PHYSICAL_ADDRESS_MASK & ~((1ull << 21) - 1)) == ((PFAddress & PHYSICAL_ADDRESS_MASK & ~((1ull << 21) - 1)))) { + Existed = TRUE; + } + } else { + // + // 4KB page + // + PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & PHYSICAL_ADDRESS_MASK); + if (PageTable != 0) { + // + // When there is a valid entry to map to 4KB page, need not create a new entry to map 2MB. + // + PTIndex = BitFieldRead64 (PFAddress, 12, 20); + Address = (UINT64)(PageTable[PTIndex] & PHYSICAL_ADDRESS_MASK); + if ((Address & PHYSICAL_ADDRESS_MASK & ~((1ull << 12) - 1)) == (PFAddress & PHYSICAL_ADDRESS_MASK & ~((1ull << 12) - 1))) { + Existed = TRUE; + } + } + } + } + } + + // + // If page entry does not existed in page table at all, create a new entry. + // + if (!Existed) { + + if (IsAddressValid (PFAddress, &Nx)) { + // + // If page fault address above 4GB is in protected range but it causes a page fault exception, + // Will create a page entry for this page fault address, make page table entry as present/rw and execution-disable. + // this access is not saved into SMM profile data. + // + *IsValidPFAddress = TRUE; + } + + // + // Create one entry in page table for page fault address. + // + SmiDefaultPFHandler (); + // + // Find the page table entry created just now. + // + PageTable = (UINT64*)(AsmReadCr3 () & PHYSICAL_ADDRESS_MASK); + PFAddress = AsmReadCr2 (); + // PML4E + PTIndex = BitFieldRead64 (PFAddress, 39, 47); + PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & PHYSICAL_ADDRESS_MASK); + // PDPTE + PTIndex = BitFieldRead64 (PFAddress, 30, 38); + PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & PHYSICAL_ADDRESS_MASK); + // PD + PTIndex = BitFieldRead64 (PFAddress, 21, 29); + Address = PageTable[PTIndex] & PHYSICAL_ADDRESS_MASK; + // + // Check if 2MB-page entry need be changed to 4KB-page entry. + // + if (IsAddressSplit (Address)) { + AcquirePage (&PageTable[PTIndex]); + + // PTE + PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & PHYSICAL_ADDRESS_MASK); + for (Index = 0; Index < 512; Index++) { + PageTable[Index] = Address | IA32_PG_RW | IA32_PG_P; + if (!IsAddressValid (Address, &Nx)) { + PageTable[Index] = PageTable[Index] & (INTN)(INT32)(~(IA32_PG_RW | IA32_PG_P)); + } + if (Nx && mXdSupported) { + PageTable[Index] = PageTable[Index] | IA32_PG_NX; + } + if (Address == (PFAddress & PHYSICAL_ADDRESS_MASK & ~((1ull << 12) - 1))) { + PTIndex = Index; + } + Address += SIZE_4KB; + } // end for PT + } else { + // + // Update 2MB page entry. + // + if (!IsAddressValid (Address, &Nx)) { + // + // Patch to remove present flag and rw flag. + // + PageTable[PTIndex] = PageTable[PTIndex] & (INTN)(INT32)(~(IA32_PG_RW | IA32_PG_P)); + } + // + // Set XD bit to 1 + // + if (Nx && mXdSupported) { + PageTable[PTIndex] = PageTable[PTIndex] | IA32_PG_NX; + } + } + } + + // + // Record old entries with non-present status + // Old entries include the memory which instruction is at and the memory which instruction access. + // + // + ASSERT (mPFEntryCount[CpuIndex] < MAX_PF_ENTRY_COUNT); + if (mPFEntryCount[CpuIndex] < MAX_PF_ENTRY_COUNT) { + PFIndex = mPFEntryCount[CpuIndex]; + mLastPFEntryValue[CpuIndex][PFIndex] = PageTable[PTIndex]; + mLastPFEntryPointer[CpuIndex][PFIndex] = &PageTable[PTIndex]; + mPFEntryCount[CpuIndex]++; + } + + // + // Add present flag or clear XD flag to make page fault handler succeed. + // + PageTable[PTIndex] |= (UINT64)(IA32_PG_RW | IA32_PG_P); + if ((ErrorCode & IA32_PF_EC_ID) != 0) { + // + // If page fault is caused by instruction fetch, clear XD bit in the entry. + // + PageTable[PTIndex] &= ~IA32_PG_NX; + } + + return; +} + +/** + Clear TF in FLAGS. + + @param SystemContext A pointer to the processor context when + the interrupt occurred on the processor. + +**/ +VOID +ClearTrapFlag ( + IN OUT EFI_SYSTEM_CONTEXT SystemContext + ) +{ + SystemContext.SystemContextX64->Rflags &= (UINTN) ~BIT8; +} diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmProfileArch.h b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmProfileArch.h new file mode 100644 index 000000000000..32f33139bfc9 --- /dev/null +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmProfileArch.h @@ -0,0 +1,105 @@ +/** @file +X64 processor specific header file to enable SMM profile. + +Copyright (c) 2012 - 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _SMM_PROFILE_ARCH_H_ +#define _SMM_PROFILE_ARCH_H_ + +#pragma pack (1) + +typedef struct _MSR_DS_AREA_STRUCT { + UINT64 BTSBufferBase; + UINT64 BTSIndex; + UINT64 BTSAbsoluteMaximum; + UINT64 BTSInterruptThreshold; + UINT64 PEBSBufferBase; + UINT64 PEBSIndex; + UINT64 PEBSAbsoluteMaximum; + UINT64 PEBSInterruptThreshold; + UINT64 PEBSCounterReset[2]; + UINT64 Reserved; +} MSR_DS_AREA_STRUCT; + +typedef struct _BRANCH_TRACE_RECORD { + UINT64 LastBranchFrom; + UINT64 LastBranchTo; + UINT64 Rsvd0 : 4; + UINT64 BranchPredicted : 1; + UINT64 Rsvd1 : 59; +} BRANCH_TRACE_RECORD; + +typedef struct _PEBS_RECORD { + UINT64 Rflags; + UINT64 LinearIP; + UINT64 Rax; + UINT64 Rbx; + UINT64 Rcx; + UINT64 Rdx; + UINT64 Rsi; + UINT64 Rdi; + UINT64 Rbp; + UINT64 Rsp; + UINT64 R8; + UINT64 R9; + UINT64 R10; + UINT64 R11; + UINT64 R12; + UINT64 R13; + UINT64 R14; + UINT64 R15; +} PEBS_RECORD; + +#pragma pack () + +#define PHYSICAL_ADDRESS_MASK ((1ull << 52) - SIZE_4KB) + +/** + Update page table to map the memory correctly in order to make the instruction + which caused page fault execute successfully. And it also save the original page + table to be restored in single-step exception. + + @param PageTable PageTable Address. + @param PFAddress The memory address which caused page fault exception. + @param CpuIndex The index of the processor. + @param ErrorCode The Error code of exception. + @param IsValidPFAddress The flag indicates if SMM profile data need be added. + +**/ +VOID +RestorePageTableAbove4G ( + UINT64 *PageTable, + UINT64 PFAddress, + UINTN CpuIndex, + UINTN ErrorCode, + BOOLEAN *IsValidPFAddress + ); + +/** + Create SMM page table for S3 path. + +**/ +VOID +InitSmmS3Cr3 ( + VOID + ); + +/** + Allocate pages for creating 4KB-page based on 2MB-page when page fault happens. + +**/ +VOID +InitPagesForPFHandler ( + VOID + ); + +#endif // _SMM_PROFILE_ARCH_H_ From 41edf829e9f98d3947bb614ce7fabc51f2cc74d9 Mon Sep 17 00:00:00 2001 From: Michael Kinney Date: Tue, 17 Nov 2015 05:07:49 +0000 Subject: [PATCH 127/525] UefiCpuPkg: Add PiSmmCpuDxeSmm module to DSC file Add the PiSmmCpuDxeSmm module to the UefiCpuPkg DSC file along with this modules dependent libraries. (Sync patch r18648 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Michael Kinney Reviewed-by: Jeff Fan git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18843 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/UefiCpuPkg.dsc | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc index 961c970418d6..10197d4c876c 100644 --- a/UefiCpuPkg/UefiCpuPkg.dsc +++ b/UefiCpuPkg/UefiCpuPkg.dsc @@ -32,7 +32,7 @@ BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf CpuLib|MdePkg/Library/BaseCpuLib/BaseCpuLib.inf DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf - SerialPortLib|MdePkg/Library/BaseSerialPortLibNull/BaseSerialPortLibNull.inf + SerialPortLib|MdePkg/Library/BaseSerialPortLibNull/BaseSerialPortLibNull.inf DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf UefiCpuLib|UefiCpuPkg/Library/BaseUefiCpuLib/BaseUefiCpuLib.inf @@ -54,6 +54,10 @@ ReportStatusCodeLib|MdePkg/Library/BaseReportStatusCodeLibNull/BaseReportStatusCodeLibNull.inf SynchronizationLib|MdePkg/Library/BaseSynchronizationLib/BaseSynchronizationLib.inf SmmMemLib|MdePkg/Library/SmmMemLib/SmmMemLib.inf + CacheMaintenanceLib|MdePkg/Library/BaseCacheMaintenanceLib/BaseCacheMaintenanceLib.inf + SmmLib|MdePkg/Library/SmmLibNull/SmmLibNull.inf + PciLib|MdePkg/Library/BasePciLibPciExpress/BasePciLibPciExpress.inf + PciExpressLib|MdePkg/Library/BasePciExpressLib/BasePciExpressLib.inf SmmCpuPlatformHookLib|UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.inf SmmCpuFeaturesLib|UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf @@ -62,7 +66,7 @@ [LibraryClasses.common.SEC] PlatformSecLib|UefiCpuPkg/Library/PlatformSecLibNull/PlatformSecLibNull.inf CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf - + [LibraryClasses.common.PEIM] MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf @@ -95,20 +99,21 @@ UefiCpuPkg/Library/SecPeiDxeTimerLibUefiCpu/SecPeiDxeTimerLibUefiCpu.inf [Components.IA32, Components.X64] - UefiCpuPkg/CpuMpPei/CpuMpPei.inf UefiCpuPkg/CpuDxe/CpuDxe.inf UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf + UefiCpuPkg/CpuMpPei/CpuMpPei.inf UefiCpuPkg/Library/BaseUefiCpuLib/BaseUefiCpuLib.inf - UefiCpuPkg/Library/MtrrLib/MtrrLib.inf - UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.inf UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.inf - UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf + UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.inf UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf + UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.inf + UefiCpuPkg/Library/MtrrLib/MtrrLib.inf UefiCpuPkg/Library/PlatformSecLibNull/PlatformSecLibNull.inf UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.inf UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationPei.inf UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationSmm.inf UefiCpuPkg/SecCore/SecCore.inf + UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume2Pei.inf From 86e35c4168b5407b61f9fd53e2092dcb59926d01 Mon Sep 17 00:00:00 2001 From: Michael Kinney Date: Tue, 17 Nov 2015 05:09:20 +0000 Subject: [PATCH 128/525] UefiCpuPkg: PiSmmCpuDxeSmm: Remove unused references to SmmLib The PiSmmCpuDxeSmm module does not use any services from the SmmLib. This change removes the SmmLib from PiSmmCpuDxeSmm module and also removes the lib mapping in the UefiCpuPkg DSC file because no other modules in the UefiCpuPkg use the SmmLib. Removal of SmmLib is now possible because the only API call to it, ClearSmi(), was ultimately removed from PiSmmCpuDxeSmm -- see the "BUGBUG" comment in git commit 529a5a86. (Sync patch r18673 from main trunk.) Cc: "Yao, Jiewen" Cc: Jeff Fan Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Michael Kinney Reviewed-by: "Yao, Jiewen" git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18844 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h | 1 - UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf | 1 - UefiCpuPkg/UefiCpuPkg.dsc | 1 - 3 files changed, 3 deletions(-) diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h index 9ea11894cdd5..162bdadf0bce 100644 --- a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h @@ -30,7 +30,6 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include #include -#include #include #include #include diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf index 45ab16c07f2b..f559947ee420 100644 --- a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf @@ -101,7 +101,6 @@ SynchronizationLib BaseMemoryLib MtrrLib - SmmLib IoLib TimerLib SmmServicesTableLib diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc index 10197d4c876c..756645f728d4 100644 --- a/UefiCpuPkg/UefiCpuPkg.dsc +++ b/UefiCpuPkg/UefiCpuPkg.dsc @@ -55,7 +55,6 @@ SynchronizationLib|MdePkg/Library/BaseSynchronizationLib/BaseSynchronizationLib.inf SmmMemLib|MdePkg/Library/SmmMemLib/SmmMemLib.inf CacheMaintenanceLib|MdePkg/Library/BaseCacheMaintenanceLib/BaseCacheMaintenanceLib.inf - SmmLib|MdePkg/Library/SmmLibNull/SmmLibNull.inf PciLib|MdePkg/Library/BasePciLibPciExpress/BasePciLibPciExpress.inf PciExpressLib|MdePkg/Library/BasePciExpressLib/BasePciExpressLib.inf SmmCpuPlatformHookLib|UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.inf From e5240a6e42757b8637c8c56589f3978c6d4a7e41 Mon Sep 17 00:00:00 2001 From: Michael Kinney Date: Tue, 17 Nov 2015 05:10:07 +0000 Subject: [PATCH 129/525] UefiCpuPkg: PiSmmCpuDxeSmm: Replace PcdSet## with PcdSet##S PcdSet## has no error status returned, then the caller has no idea about whether the set operation is successful or not. PcdSet##S were added to return error status and PcdSet## APIs were put in ifndef DISABLE_NEW_DEPRECATED_INTERFACES condition. To adopt PcdSet##S and further code development with DISABLE_NEW_DEPRECATED_INTERFACES defined, we need to Replace PcdSet## usage with PcdSet##S. Normally, DynamicDefault PCD set is expected to be success, but DynamicHii PCD set failure is a legal case. So for DynamicDefault, we add assert when set failure. For DynamicHii, we add logic to handle it. (Sync patch r18686 from main trunk.) Cc: "Yao, Jiewen" Cc: Jeff Fan Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Michael Kinney Reviewed-by: Jeff Fan git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18845 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c index 0e39173cbbe8..e210c8d44659 100644 --- a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c @@ -1140,7 +1140,8 @@ PiCpuSmmEntry ( // Expose address of CPU Hot Plug Data structure if CPU hot plug is supported. // if (FeaturePcdGet (PcdCpuHotPlugSupport)) { - PcdSet64 (PcdCpuHotPlugDataAddress, (UINT64)(UINTN)&mCpuHotPlugData); + Status = PcdSet64S (PcdCpuHotPlugDataAddress, (UINT64)(UINTN)&mCpuHotPlugData); + ASSERT_EFI_ERROR (Status); } // From a8f7592e4e1ae1f80f6ee847a91c7012ea3073cc Mon Sep 17 00:00:00 2001 From: Michael Kinney Date: Tue, 17 Nov 2015 05:10:45 +0000 Subject: [PATCH 130/525] UefiCpuPkg: SmmCpuFeaturesLib: Add MSR_SMM_FEATURE_CONTROL support Add support for the reading and writing MSR_SMM_FEATURE_CONTROL through the SmmCpuFeaturesIsSmmRegisterSupported(), SmmCpuFeaturesGetSmmRegister(), and SmmCpuFeaturesSetSmmRegister() functions. This MSR is supported if the Family/Model is 06_3C, 06_45, or 06_46. (Sync patch r18690 from main trunk.) Cc: "Yao, Jiewen" Cc: Jeff Fan Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Michael Kinney Reviewed-by: "Yao, Jiewen" git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18846 6f19259b-4bc3-4df7-8a09-765794883524 --- .../SmmCpuFeaturesLib/SmmCpuFeaturesLib.c | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.c b/UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.c index 4f2f9b65fa37..0c1610d9777c 100644 --- a/UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.c +++ b/UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.c @@ -33,12 +33,18 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #define SMM_FEATURES_LIB_IA32_CORE_SMRR_PHYSMASK 0x0A1 #define EFI_MSR_SMRR_MASK 0xFFFFF000 #define EFI_MSR_SMRR_PHYS_MASK_VALID BIT11 +#define SMM_FEATURES_LIB_SMM_FEATURE_CONTROL 0x4E0 // // Set default value to assume SMRR is not supported // BOOLEAN mSmrrSupported = FALSE; +// +// Set default value to assume MSR_SMM_FEATURE_CONTROL is not supported +// +BOOLEAN mSmmFeatureControlSupported = FALSE; + // // Set default value to assume IA-32 Architectural MSRs are used // @@ -125,6 +131,20 @@ SmmCpuFeaturesLibConstructor ( } } + // + // Intel(R) 64 and IA-32 Architectures Software Developer's Manual + // Volume 3C, Section 35.10.1 MSRs in 4th Generation Intel(R) Core(TM) + // Processor Family + // + // If CPU Family/Model is 06_3C, 06_45, or 06_46 then use 4th Generation + // Intel(R) Core(TM) Processor Family MSRs + // + if (FamilyId == 0x06) { + if (ModelId == 0x3C || ModelId == 0x45 || ModelId == 0x46) { + mSmmFeatureControlSupported = TRUE; + } + } + // // Intel(R) 64 and IA-32 Architectures Software Developer's Manual // Volume 3C, Section 34.4.2 SMRAM Caching @@ -457,6 +477,9 @@ SmmCpuFeaturesIsSmmRegisterSupported ( IN SMM_REG_NAME RegName ) { + if (mSmmFeatureControlSupported && RegName == SmmRegFeatureControl) { + return TRUE; + } return FALSE; } @@ -479,6 +502,9 @@ SmmCpuFeaturesGetSmmRegister ( IN SMM_REG_NAME RegName ) { + if (mSmmFeatureControlSupported && RegName == SmmRegFeatureControl) { + return AsmReadMsr64 (SMM_FEATURES_LIB_SMM_FEATURE_CONTROL); + } return 0; } @@ -501,6 +527,9 @@ SmmCpuFeaturesSetSmmRegister ( IN UINT64 Value ) { + if (mSmmFeatureControlSupported && RegName == SmmRegFeatureControl) { + AsmWriteMsr64 (SMM_FEATURES_LIB_SMM_FEATURE_CONTROL, Value); + } } /** From 0d0f9ed1cd6416299b9717d2820914fec7e5e0f1 Mon Sep 17 00:00:00 2001 From: Michael Kinney Date: Tue, 17 Nov 2015 05:11:24 +0000 Subject: [PATCH 131/525] UefiCpuPkg: CpuDxe: Update GDT to be consistent with DxeIplPeim The PiSmmCpuDxeSmm module makes some assumptions about GDT selectors that are based on the GDT layout from the DxeIplPeim. For example, the protected mode entry code and (where appropriate) the long mode entry code in the UefiCpuPkg/PiSmmCpuDxeSmm/*/MpFuncs.* assembly files, which are used during S3 resume, open-code segment selector values that depend on DxeIplPeim's GDT layout. This updates the CpuDxe module to use the same GDT layout as the DxeIplPeim. This enables modules that are dispatched after CpuDxe to find, and potentially save and restore, a GDT layout that matches that of DxeIplPeim. The DxeIplPeim has a 2 GDT entries for data selectors that are identical. These are LINEAR_SEL (GDT Offset 0x08)and LINEAR_DATA64_SEL (GDT offset 0x30). LINEAL_SEL is used for for IA32 DXE and the LINEAR_DATA64_SEL is used for X64 DXE. This duplicate data selector was added to the CpuDxe module to keep the GDT and all selectors consistent. Using a consistent GDT also improves debug experience. (Sync patch r18710 from main trunk.) Reported-by: Laszlo Ersek Analyzed-by: Laszlo Ersek Link: http://article.gmane.org/gmane.comp.bios.edk2.devel/3568 Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Michael Kinney Reviewed-by: Laszlo Ersek Tested-by: Laszlo Ersek git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18847 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/CpuDxe/CpuGdt.c | 83 +++++++++++++++++++++----------------- UefiCpuPkg/CpuDxe/CpuGdt.h | 10 +++-- 2 files changed, 53 insertions(+), 40 deletions(-) diff --git a/UefiCpuPkg/CpuDxe/CpuGdt.c b/UefiCpuPkg/CpuDxe/CpuGdt.c index 35a87a6e453e..9ef2fdfefbcb 100644 --- a/UefiCpuPkg/CpuDxe/CpuGdt.c +++ b/UefiCpuPkg/CpuDxe/CpuGdt.c @@ -2,7 +2,7 @@ C based implemention of IA32 interrupt handling only requiring a minimal assembly interrupt entry point. - Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
+ Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -35,10 +35,10 @@ STATIC GDT_ENTRIES GdtTemplate = { // LINEAR_SEL // { - 0x0FFFF, // limit 0xFFFFF - 0x0, // base 0 - 0x0, - 0x092, // present, ring 0, data, expand-up, writable + 0x0FFFF, // limit 15:0 + 0x0, // base 15:0 + 0x0, // base 23:16 + 0x092, // present, ring 0, data, read/write 0x0CF, // page-granular, 32-bit 0x0, }, @@ -46,10 +46,10 @@ STATIC GDT_ENTRIES GdtTemplate = { // LINEAR_CODE_SEL // { - 0x0FFFF, // limit 0xFFFFF - 0x0, // base 0 - 0x0, - 0x09A, // present, ring 0, data, expand-up, writable + 0x0FFFF, // limit 15:0 + 0x0, // base 15:0 + 0x0, // base 23:16 + 0x09F, // present, ring 0, code, execute/read, conforming, accessed 0x0CF, // page-granular, 32-bit 0x0, }, @@ -57,10 +57,10 @@ STATIC GDT_ENTRIES GdtTemplate = { // SYS_DATA_SEL // { - 0x0FFFF, // limit 0xFFFFF - 0x0, // base 0 - 0x0, - 0x092, // present, ring 0, data, expand-up, writable + 0x0FFFF, // limit 15:0 + 0x0, // base 15:0 + 0x0, // base 23:16 + 0x093, // present, ring 0, data, read/write, accessed 0x0CF, // page-granular, 32-bit 0x0, }, @@ -68,45 +68,56 @@ STATIC GDT_ENTRIES GdtTemplate = { // SYS_CODE_SEL // { - 0x0FFFF, // limit 0xFFFFF - 0x0, // base 0 - 0x0, - 0x09A, // present, ring 0, data, expand-up, writable + 0x0FFFF, // limit 15:0 + 0x0, // base 15:0 + 0x0, // base 23:16 + 0x09A, // present, ring 0, code, execute/read 0x0CF, // page-granular, 32-bit 0x0, }, // - // LINEAR_CODE64_SEL + // SPARE4_SEL // { - 0x0FFFF, // limit 0xFFFFF - 0x0, // base 0 - 0x0, - 0x09B, // present, ring 0, code, expand-up, writable - 0x0AF, // LimitHigh (CS.L=1, CS.D=0) - 0x0, // base (high) + 0x0, // limit 15:0 + 0x0, // base 15:0 + 0x0, // base 23:16 + 0x0, // type + 0x0, // limit 19:16, flags + 0x0, // base 31:24 }, // - // SPARE4_SEL + // LINEAR_DATA64_SEL // { - 0x0, // limit 0 - 0x0, // base 0 - 0x0, - 0x0, // present, ring 0, data, expand-up, writable - 0x0, // page-granular, 32-bit + 0x0FFFF, // limit 15:0 + 0x0, // base 15:0 + 0x0, // base 23:16 + 0x092, // present, ring 0, data, read/write + 0x0CF, // page-granular, 32-bit 0x0, }, // + // LINEAR_CODE64_SEL + // + { + 0x0FFFF, // limit 15:0 + 0x0, // base 15:0 + 0x0, // base 23:16 + 0x09A, // present, ring 0, code, execute/read + 0x0AF, // page-granular, 64-bit code + 0x0, // base (high) + }, + // // SPARE5_SEL // { - 0x0, // limit 0 - 0x0, // base 0 - 0x0, - 0x0, // present, ring 0, data, expand-up, writable - 0x0, // page-granular, 32-bit - 0x0, + 0x0, // limit 15:0 + 0x0, // base 15:0 + 0x0, // base 23:16 + 0x0, // type + 0x0, // limit 19:16, flags + 0x0, // base 31:24 }, }; diff --git a/UefiCpuPkg/CpuDxe/CpuGdt.h b/UefiCpuPkg/CpuDxe/CpuGdt.h index 7ecec5d5d9f7..2a007516024b 100644 --- a/UefiCpuPkg/CpuDxe/CpuGdt.h +++ b/UefiCpuPkg/CpuDxe/CpuGdt.h @@ -2,7 +2,7 @@ C based implemention of IA32 interrupt handling only requiring a minimal assembly interrupt entry point. - Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
+ Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -42,8 +42,9 @@ struct _GDT_ENTRIES { GDT_ENTRY LinearCode; GDT_ENTRY SysData; GDT_ENTRY SysCode; - GDT_ENTRY LinearCode64; GDT_ENTRY Spare4; + GDT_ENTRY LinearData64; + GDT_ENTRY LinearCode64; GDT_ENTRY Spare5; } GDT_ENTRIES; @@ -54,8 +55,9 @@ struct _GDT_ENTRIES { #define LINEAR_CODE_SEL OFFSET_OF (GDT_ENTRIES, LinearCode) #define SYS_DATA_SEL OFFSET_OF (GDT_ENTRIES, SysData) #define SYS_CODE_SEL OFFSET_OF (GDT_ENTRIES, SysCode) -#define LINEAR_CODE64_SEL OFFSET_OF (GDT_ENTRIES, LinearCode64) #define SPARE4_SEL OFFSET_OF (GDT_ENTRIES, Spare4) +#define LINEAR_DATA64_SEL OFFSET_OF (GDT_ENTRIES, LinearData64) +#define LINEAR_CODE64_SEL OFFSET_OF (GDT_ENTRIES, LinearCode64) #define SPARE5_SEL OFFSET_OF (GDT_ENTRIES, Spare5) #if defined (MDE_CPU_IA32) @@ -63,7 +65,7 @@ struct _GDT_ENTRIES { #define CPU_DATA_SEL LINEAR_SEL #elif defined (MDE_CPU_X64) #define CPU_CODE_SEL LINEAR_CODE64_SEL -#define CPU_DATA_SEL LINEAR_SEL +#define CPU_DATA_SEL LINEAR_DATA64_SEL #else #error CPU type not supported for CPU GDT initialization! #endif From b6f16ba332354607f73f5cb871ec0907d5923070 Mon Sep 17 00:00:00 2001 From: Michael Kinney Date: Tue, 17 Nov 2015 05:12:32 +0000 Subject: [PATCH 132/525] UefiCpuPkg: LocalApicLib: Add API to set SoftwareEnable bit The LocalApicLib does not provide a function to manage the state of the Local APIC SoftwareEnable bit in the Spurious Vector register. There are cases where this bit needs to be managed without side effects to. other Local APIC registers. One use case is in the DebugAgent in the SourceLevelDebugPkg. (Sync patch r18711 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Michael Kinney Reviewed-by: Hao Wu Reviewed-by: Jeff Fan git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18848 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/Include/Library/LocalApicLib.h | 16 +++++++- .../Library/BaseXApicLib/BaseXApicLib.c | 38 +++++++++++++++++-- .../BaseXApicX2ApicLib/BaseXApicX2ApicLib.c | 38 +++++++++++++++++-- 3 files changed, 83 insertions(+), 9 deletions(-) diff --git a/UefiCpuPkg/Include/Library/LocalApicLib.h b/UefiCpuPkg/Include/Library/LocalApicLib.h index b92b99e11519..cd4e613ef5f8 100644 --- a/UefiCpuPkg/Include/Library/LocalApicLib.h +++ b/UefiCpuPkg/Include/Library/LocalApicLib.h @@ -4,7 +4,7 @@ Local APIC library assumes local APIC is enabled. It does not handles cases where local APIC is disabled. - Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.
+ Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -227,6 +227,20 @@ SendInitSipiSipiAllExcludingSelf ( IN UINT32 StartupRoutine ); +/** + Initialize the state of the SoftwareEnable bit in the Local APIC + Spurious Interrupt Vector register. + + @param Enable If TRUE, then set SoftwareEnable to 1 + If FALSE, then set SoftwareEnable to 0. + +**/ +VOID +EFIAPI +InitializeLocalApicSoftwareEnable ( + IN BOOLEAN Enable + ); + /** Programming Virtual Wire Mode. diff --git a/UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.c b/UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.c index b73b1d3da930..7090cd4911ff 100644 --- a/UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.c +++ b/UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.c @@ -563,6 +563,39 @@ SendInitSipiSipiAllExcludingSelf ( SendIpi (IcrLow.Uint32, 0); } +/** + Initialize the state of the SoftwareEnable bit in the Local APIC + Spurious Interrupt Vector register. + + @param Enable If TRUE, then set SoftwareEnable to 1 + If FALSE, then set SoftwareEnable to 0. + +**/ +VOID +EFIAPI +InitializeLocalApicSoftwareEnable ( + IN BOOLEAN Enable + ) +{ + LOCAL_APIC_SVR Svr; + + // + // Set local APIC software-enabled bit. + // + Svr.Uint32 = ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET); + if (Enable) { + if (Svr.Bits.SoftwareEnable == 0) { + Svr.Bits.SoftwareEnable = 1; + WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32); + } + } else { + if (Svr.Bits.SoftwareEnable == 1) { + Svr.Bits.SoftwareEnable = 0; + WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32); + } + } +} + /** Programming Virtual Wire Mode. @@ -679,7 +712,6 @@ InitializeApicTimer ( IN UINT8 Vector ) { - LOCAL_APIC_SVR Svr; LOCAL_APIC_DCR Dcr; LOCAL_APIC_LVT_TIMER LvtTimer; UINT32 Divisor; @@ -687,9 +719,7 @@ InitializeApicTimer ( // // Ensure local APIC is in software-enabled state. // - Svr.Uint32 = ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET); - Svr.Bits.SoftwareEnable = 1; - WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32); + InitializeLocalApicSoftwareEnable (TRUE); // // Program init-count register. diff --git a/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c b/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c index 9bbaca45dc6b..bc3d0a57e246 100644 --- a/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c +++ b/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c @@ -658,6 +658,39 @@ SendInitSipiSipiAllExcludingSelf ( SendIpi (IcrLow.Uint32, 0); } +/** + Initialize the state of the SoftwareEnable bit in the Local APIC + Spurious Interrupt Vector register. + + @param Enable If TRUE, then set SoftwareEnable to 1 + If FALSE, then set SoftwareEnable to 0. + +**/ +VOID +EFIAPI +InitializeLocalApicSoftwareEnable ( + IN BOOLEAN Enable + ) +{ + LOCAL_APIC_SVR Svr; + + // + // Set local APIC software-enabled bit. + // + Svr.Uint32 = ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET); + if (Enable) { + if (Svr.Bits.SoftwareEnable == 0) { + Svr.Bits.SoftwareEnable = 1; + WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32); + } + } else { + if (Svr.Bits.SoftwareEnable == 1) { + Svr.Bits.SoftwareEnable = 0; + WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32); + } + } +} + /** Programming Virtual Wire Mode. @@ -774,7 +807,6 @@ InitializeApicTimer ( IN UINT8 Vector ) { - LOCAL_APIC_SVR Svr; LOCAL_APIC_DCR Dcr; LOCAL_APIC_LVT_TIMER LvtTimer; UINT32 Divisor; @@ -782,9 +814,7 @@ InitializeApicTimer ( // // Ensure local APIC is in software-enabled state. // - Svr.Uint32 = ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET); - Svr.Bits.SoftwareEnable = 1; - WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32); + InitializeLocalApicSoftwareEnable (TRUE); // // Program init-count register. From e92b7ed5ced134bff7fe259798f5459aadfa8f82 Mon Sep 17 00:00:00 2001 From: Jeff Fan Date: Tue, 17 Nov 2015 05:13:43 +0000 Subject: [PATCH 133/525] UefiCpuPkg/PiSmmCpuDxeSmm: Shouldn't use gSmst->CurrentlyExecutingCpu In ConfigSmmCodeAccessCheck(), we used gSmst->CurrentlyExecutingCpu to get the current SMM BSP. But ConfigSmmCodeAccessCheck() maybe invoked before executing SmmCoreEntry() and gSmst->CurrentlyExecutingCpu hasn't been updated to the latest value. The code flow is as below: BSPHandler() gSmmCpuPrivate->SmmCoreEntryContext.CurrentlyExecutingCpu = CpuIndex; // // when mRestoreSmmConfigurationInS3 is set: // ConfigSmmCodeAccessCheck() // // reads gSmst->CurrentlyExecutingCpu to early // gSmmCpuPrivate->SmmCoreEntry (&gSmmCpuPrivate->SmmCoreEntryContext) // // sets gSmst->CurrentlyExecutingCpu with CopyMem() too late // CopyMem (&gSmmCoreSmst.SmmStartupThisAp, SmmEntryContext, sizeof (EFI_SMM_ENTRY_CONTEXT)); Instead, we should use gSmmCpuPrivate->SmmCoreEntryContext.CurrentlyExecutingCpu directly. (Sync patch r18715 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan Reviewed-by: Laszlo Ersek git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18849 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c index e210c8d44659..c351875262b4 100644 --- a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c @@ -1386,7 +1386,7 @@ ConfigSmmCodeAccessCheck ( // // Check to see if the Feature Control MSR is supported on this CPU // - Index = gSmst->CurrentlyExecutingCpu; + Index = gSmmCpuPrivate->SmmCoreEntryContext.CurrentlyExecutingCpu; if (!SmmCpuFeaturesIsSmmRegisterSupported (Index, SmmRegFeatureControl)) { mSmmCodeAccessCheckEnable = FALSE; return; @@ -1428,7 +1428,7 @@ ConfigSmmCodeAccessCheck ( // Enable SMM Code Access Check feature for the APs. // for (Index = 0; Index < gSmst->NumberOfCpus; Index++) { - if (Index != gSmst->CurrentlyExecutingCpu) { + if (Index != gSmmCpuPrivate->SmmCoreEntryContext.CurrentlyExecutingCpu) { // // Acquire Config SMM Code Access Check spin lock. The AP will release the From 6a3eb62baf07b2d102a4f946b5d25bfac24e39d0 Mon Sep 17 00:00:00 2001 From: Michael Kinney Date: Tue, 17 Nov 2015 05:14:39 +0000 Subject: [PATCH 134/525] UefiCpuPkg: PiSmmCpuDxeSmm: Remove Framework compatibility The PiSmmCpuDxeSmm module is using PcdFrameworkCompatibilitySupport to provide compatibility with the SMM support in the IntelFrameworkPkg. This change removes the Framework compatibility and requires all SMM modules that provide SMI handlers to follow the PI Specification. (Sync patch r18726 from main trunk.) Cc: Jeff Fan Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Michael Kinney Reviewed-by: Jeff Fan git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18850 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c | 60 +++----------------- UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h | 1 - UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf | 3 - 3 files changed, 8 insertions(+), 56 deletions(-) diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c index c351875262b4..de681c0a3069 100644 --- a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c @@ -76,13 +76,6 @@ EFI_SMM_CPU_PROTOCOL mSmmCpu = { EFI_CPU_INTERRUPT_HANDLER mExternalVectorTable[EXCEPTION_VECTOR_NUMBER]; -/// -/// SMM CPU Save State Protocol instance -/// -EFI_SMM_CPU_SAVE_STATE_PROTOCOL mSmmCpuSaveState = { - NULL -}; - // // SMM stack information // @@ -530,18 +523,13 @@ SmmRestoreCpu ( } // - // Do below CPU things for native platform only + // Skip initialization if mAcpiCpuData is not valid // - if (!FeaturePcdGet(PcdFrameworkCompatibilitySupport)) { + if (mAcpiCpuData.NumberOfCpus > 0) { // - // Skip initialization if mAcpiCpuData is not valid + // First time microcode load and restore MTRRs // - if (mAcpiCpuData.NumberOfCpus > 0) { - // - // First time microcode load and restore MTRRs - // - EarlyInitializeCpu (); - } + EarlyInitializeCpu (); } // @@ -550,18 +538,13 @@ SmmRestoreCpu ( SmmRelocateBases (); // - // Do below CPU things for native platform only + // Skip initialization if mAcpiCpuData is not valid // - if (!FeaturePcdGet(PcdFrameworkCompatibilitySupport)) { + if (mAcpiCpuData.NumberOfCpus > 0) { // - // Skip initialization if mAcpiCpuData is not valid + // Restore MSRs for BSP and all APs // - if (mAcpiCpuData.NumberOfCpus > 0) { - // - // Restore MSRs for BSP and all APs - // - InitializeCpu (); - } + InitializeCpu (); } // @@ -686,13 +669,6 @@ SmmReadyToLockEventNotify ( // mAcpiCpuData.NumberOfCpus = 0; - // - // If FrameworkCompatibilitySspport is enabled, then do not copy CPU S3 Data into SMRAM - // - if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) { - goto Done; - } - // // If PcdCpuS3DataAddress was never set, then do not copy CPU S3 Data into SMRAM // @@ -1009,7 +985,6 @@ PiCpuSmmEntry ( mSmmCpuPrivateData.SmmCoreEntryContext.CpuSaveStateSize = gSmmCpuPrivate->CpuSaveStateSize; mSmmCpuPrivateData.SmmCoreEntryContext.CpuSaveState = gSmmCpuPrivate->CpuSaveState; - mSmmCpuSaveState.CpuSaveState = (EFI_SMM_CPU_STATE **)gSmmCpuPrivate->CpuSaveState; // // Allocate buffer for pointers to array in CPU_HOT_PLUG_DATA. @@ -1150,25 +1125,6 @@ PiCpuSmmEntry ( Status = InitializeSmmCpuServices (mSmmCpuHandle); ASSERT_EFI_ERROR (Status); - if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) { - // - // Install Framework SMM Save State Protocol into UEFI protocol database for backward compatibility - // - Status = SystemTable->BootServices->InstallMultipleProtocolInterfaces ( - &gSmmCpuPrivate->SmmCpuHandle, - &gEfiSmmCpuSaveStateProtocolGuid, - &mSmmCpuSaveState, - NULL - ); - ASSERT_EFI_ERROR (Status); - // - // The SmmStartupThisAp service in Framework SMST should always be non-null. - // Update SmmStartupThisAp pointer in PI SMST here so that PI/Framework SMM thunk - // can have it ready when constructing Framework SMST. - // - gSmst->SmmStartupThisAp = SmmStartupThisAp; - } - // // register SMM Ready To Lock Protocol notification // diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h index 162bdadf0bce..cfbf2ca6dae3 100644 --- a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h @@ -21,7 +21,6 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include #include -#include #include #include diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf index f559947ee420..a293a88e9914 100644 --- a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf @@ -89,7 +89,6 @@ MdePkg/MdePkg.dec MdeModulePkg/MdeModulePkg.dec UefiCpuPkg/UefiCpuPkg.dec - IntelFrameworkPkg/IntelFrameworkPkg.dec [LibraryClasses] UefiDriverEntryPoint @@ -126,7 +125,6 @@ gEfiSmmCpuProtocolGuid ## PRODUCES gEfiSmmReadyToLockProtocolGuid ## NOTIFY gEfiSmmCpuServiceProtocolGuid ## PRODUCES - gEfiSmmCpuSaveStateProtocolGuid ## SOMETIMES_PRODUCES [Guids] gEfiAcpiVariableGuid ## SOMETIMES_CONSUMES ## HOB # it is used for S3 boot. @@ -135,7 +133,6 @@ gEfiAcpi10TableGuid ## SOMETIMES_CONSUMES ## SystemTable [FeaturePcd] - gEfiMdeModulePkgTokenSpaceGuid.PcdFrameworkCompatibilitySupport ## CONSUMES gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmDebug ## CONSUMES gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmBlockStartupThisAp ## CONSUMES gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmEnableBspElection ## CONSUMES From 0499b7bfda33b1e78cda8176c9f7a68d85605a69 Mon Sep 17 00:00:00 2001 From: Zhang Chao Date: Wed, 18 Nov 2015 08:03:37 +0000 Subject: [PATCH 135/525] SecurityPkg: Remove temp return solution in PeiRsa2048Sha256 Section Lib PeiCore supports EFI_PEI_SECURITY_PPI to handle section extraction failure. The wrong returning status is no longer needed. (Sync patch r18732 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Zhang Chao Reviewed-by: Gao Liming git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18869 6f19259b-4bc3-4df7-8a09-765794883524 --- .../PeiRsa2048Sha256GuidedSectionExtractLib.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/SecurityPkg/Library/PeiRsa2048Sha256GuidedSectionExtractLib/PeiRsa2048Sha256GuidedSectionExtractLib.c b/SecurityPkg/Library/PeiRsa2048Sha256GuidedSectionExtractLib/PeiRsa2048Sha256GuidedSectionExtractLib.c index e448164a5a33..473370300a0e 100644 --- a/SecurityPkg/Library/PeiRsa2048Sha256GuidedSectionExtractLib/PeiRsa2048Sha256GuidedSectionExtractLib.c +++ b/SecurityPkg/Library/PeiRsa2048Sha256GuidedSectionExtractLib/PeiRsa2048Sha256GuidedSectionExtractLib.c @@ -357,12 +357,6 @@ Rsa2048Sha256GuidedSectionHandler ( FreePool (HashContext); } - // - // Temp solution until PeiCore checks AUTH Status. - // - if ((*AuthenticationStatus & (EFI_AUTH_STATUS_TEST_FAILED | EFI_AUTH_STATUS_NOT_TESTED)) != 0) { - Status = EFI_ACCESS_DENIED; - } DEBUG ((DEBUG_VERBOSE, "PeiRsa2048Sha256: Status = %r AuthenticationStatus = %08x\n", Status, *AuthenticationStatus)); return Status; From f065557152aa598aa1bbd399aa970a82a4b9aa8a Mon Sep 17 00:00:00 2001 From: "Yao, Jiewen" Date: Wed, 18 Nov 2015 08:04:29 +0000 Subject: [PATCH 136/525] Add error handling for TPM in S3 resume failure. If TPM2_Startup(TPM_SU_STATE) to return an error, the system firmware that resumes from S3 MUST deal with a TPM2_Startup error appropriately. For example, issuing a TPM2_Startup(TPM_SU_CLEAR) command and configuring the device securely by taking actions like extending a separator with an error digest (0x01) into PCRs 0 through 7. (Sync patch r18760 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: "Yao, Jiewen" Reviewed-by: "Zhang, Chao B" git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18870 6f19259b-4bc3-4df7-8a09-765794883524 --- SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.c | 50 +++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.c b/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.c index ec94c24e4c40..3743bfbb1117 100644 --- a/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.c +++ b/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.c @@ -827,6 +827,33 @@ PeimEntryMP ( return Status; } +/** + Measure and log Separator event with error, and extend the measurement result into a specific PCR. + + @param[in] PCRIndex PCR index. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The operation was unsuccessful. + +**/ +EFI_STATUS +MeasureSeparatorEventWithError ( + IN TPM_PCRINDEX PCRIndex + ) +{ + TCG_PCR_EVENT_HDR TcgEvent; + UINT32 EventData; + + // + // Use EventData 0x1 to indicate there is error. + // + EventData = 0x1; + TcgEvent.PCRIndex = PCRIndex; + TcgEvent.EventType = EV_SEPARATOR; + TcgEvent.EventSize = (UINT32)sizeof (EventData); + return HashLogExtendEvent(0,(UINT8 *)&EventData, TcgEvent.EventSize, &TcgEvent,(UINT8 *)&EventData); +} + /** Entry point of this module. @@ -846,6 +873,8 @@ PeimEntryMA ( EFI_STATUS Status; EFI_STATUS Status2; EFI_BOOT_MODE BootMode; + TPM_PCRINDEX PcrIndex; + BOOLEAN S3ErrorReport; if (CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceNoneGuid) || CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm12Guid)){ @@ -884,11 +913,15 @@ PeimEntryMA ( goto Done; } + S3ErrorReport = FALSE; if (PcdGet8 (PcdTpm2InitializationPolicy) == 1) { if (BootMode == BOOT_ON_S3_RESUME) { Status = Tpm2Startup (TPM_SU_STATE); if (EFI_ERROR (Status) ) { Status = Tpm2Startup (TPM_SU_CLEAR); + if (!EFI_ERROR(Status)) { + S3ErrorReport = TRUE; + } } } else { Status = Tpm2Startup (TPM_SU_CLEAR); @@ -902,6 +935,23 @@ PeimEntryMA ( // Update Tpm2HashMask according to PCR bank. // SetTpm2HashMask (); + + if (S3ErrorReport) { + // + // The system firmware that resumes from S3 MUST deal with a + // TPM2_Startup error appropriately. + // For example, issue a TPM2_Startup(TPM_SU_CLEAR) command and + // configuring the device securely by taking actions like extending a + // separator with an error digest (0x01) into PCRs 0 through 7. + // + for (PcrIndex = 0; PcrIndex < 8; PcrIndex++) { + Status = MeasureSeparatorEventWithError (PcrIndex); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Separator Event with Error not Measured. Error!\n")); + } + } + } + // // TpmSelfTest is optional on S3 path, skip it to save S3 time // From 65a512014904ce251bb183f41812595c0f8b256f Mon Sep 17 00:00:00 2001 From: Liming Gao Date: Wed, 18 Nov 2015 08:05:27 +0000 Subject: [PATCH 137/525] MdePkg: Add more DataBits support to Port80 output The BasePostCodeLibPort80 instance just prints UINT8 to IoPort 80. Some boards may support 16bit or 32bit. To support them, new PCD PcdPort80DataWidth is introduced to specify the width of data bits to Port80. (Sync patch r18765 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Liming Gao Reviewed-by: Star Zeng Reviewed-by: Jiewen Yao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18871 6f19259b-4bc3-4df7-8a09-765794883524 --- .../BasePostCodeLibPort80.inf | 5 ++-- .../Library/BasePostCodeLibPort80/PostCode.c | 24 +++++++++++++++--- MdePkg/MdePkg.dec | 5 ++++ MdePkg/MdePkg.uni | Bin 69604 -> 70116 bytes 4 files changed, 29 insertions(+), 5 deletions(-) diff --git a/MdePkg/Library/BasePostCodeLibPort80/BasePostCodeLibPort80.inf b/MdePkg/Library/BasePostCodeLibPort80/BasePostCodeLibPort80.inf index e2f0be551d46..ebe115872883 100644 --- a/MdePkg/Library/BasePostCodeLibPort80/BasePostCodeLibPort80.inf +++ b/MdePkg/Library/BasePostCodeLibPort80/BasePostCodeLibPort80.inf @@ -3,7 +3,7 @@ # # Post Code Library that writes post code values to I/O port 0x80. # -# Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.
+# Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.
# # This program and the accompanying materials # are licensed and made available under the terms and conditions of the BSD License @@ -40,8 +40,9 @@ [LibraryClasses] IoLib PcdLib + DebugLib [Pcd] gEfiMdePkgTokenSpaceGuid.PcdPostCodePropertyMask ## CONSUMES - + gEfiMdePkgTokenSpaceGuid.PcdPort80DataWidth ## CONSUMES diff --git a/MdePkg/Library/BasePostCodeLibPort80/PostCode.c b/MdePkg/Library/BasePostCodeLibPort80/PostCode.c index 925c7404bc39..f1fdbabce4b4 100644 --- a/MdePkg/Library/BasePostCodeLibPort80/PostCode.c +++ b/MdePkg/Library/BasePostCodeLibPort80/PostCode.c @@ -1,7 +1,7 @@ /** @file Post Code Library instance that writes post code values to I/O port 0x80. - Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
+ Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -17,6 +17,7 @@ #include #include #include +#include /** Sends an 32-bit value to a POST card. @@ -42,7 +43,24 @@ PostCode ( IN UINT32 Value ) { - IoWrite8 (0x80, (UINT8)(Value)); + switch (PcdGet8 (PcdPort80DataWidth)) { + case 8: + IoWrite8 (0x80, (UINT8)(Value)); + break; + case 16: + IoWrite16 (0x80, (UINT16)(Value)); + break; + case 32: + IoWrite32 (0x80, Value); + break; + default: + // + // Assert on the invalid data width + // + ASSERT (FALSE); + break; + } + return Value; } @@ -78,7 +96,7 @@ PostCodeWithDescription ( IN CONST CHAR8 *Description OPTIONAL ) { - IoWrite8 (0x80, (UINT8)(Value)); + PostCode (Value); return Value; } diff --git a/MdePkg/MdePkg.dec b/MdePkg/MdePkg.dec index 337059a6a602..7ab0cbbcfbfb 100644 --- a/MdePkg/MdePkg.dec +++ b/MdePkg/MdePkg.dec @@ -1938,6 +1938,11 @@ # @Expression 0x80000002 | (gEfiMdePkgTokenSpaceGuid.PcdPostCodePropertyMask & 0xFC) == 0 gEfiMdePkgTokenSpaceGuid.PcdPostCodePropertyMask|0|UINT8|0x0000000b + ## The bit width of data to be written to Port80. The default value is 8. + # @Prompt Port80 Data Width + # @ValidList 0x80000001 | 8, 16, 32 + gEfiMdePkgTokenSpaceGuid.PcdPort80DataWidth|8|UINT8|0x0000002d + ## This value is used to configure X86 Processor FSB clock. # @Prompt FSB Clock. gEfiMdePkgTokenSpaceGuid.PcdFSBClock|200000000|UINT32|0x0000000c diff --git a/MdePkg/MdePkg.uni b/MdePkg/MdePkg.uni index 38211344e0ae01e984d5d9b916e42f4f8b4c1c66..5a5126213e4f72ea8c47772aebf5e31e007bbc46 100644 GIT binary patch delta 257 zcmaDdpXJG7mWC~iPxvRx?GKO*V8~}EVklv-U@%~CVMqkB5*fl7G8s~Utc=NqV&?J) zc?Gx%1tc|&YvM(*nlSl%is|GHt2pYDfaaAjC@_@6%muRZ8Pb4c3e-jgpnN`%pTv*~ zR#ybpQ3B-U0r?O)WS8mzMMD@ez^YS#WE#+%QidF`EoDG<4v+^jDU+d?L4g Date: Wed, 18 Nov 2015 08:06:21 +0000 Subject: [PATCH 138/525] MdeModulePkg PeiCore: PEI dispatcher need retry to process NOT_DISPATCHED FV A corner case like below will cause a NOT_DISPATCHED FV has no opportunity to be dispatched. 1. FV_RECOVERY has SecCore, PeiCore and some other PEI modules, a module will report FVMAIN_COMPACT and FV_RECOVERY2 in sequence. 2. FVMAIN_COMPACT has a FV image file with GUIDED FV image section in it. 3. FV_RECOVERY2 has DxeIpl and other PEI modules, the DxeIpl will install SectionExtractionPpi If ALL the PEIMs in FV_RECOVERY and FV_RECOVERY2 have DEPEX satisfied and executed in one loop, PeimNeedingDispatch will be always FALSE, FVMAIN_COMPACT will have no opportunity to be decompressed and dispatched as DxeIpl executes after the first processing to FVMAIN_COMPACT. The patch is to set PeimNeedingDispatch to TRUE when ProcessFvFile() not successfully, then the NOT_DISPATCHED FV could have another opportunity to be processed. (Sync patch r18781 from main trunk.) Cc: Liming Gao Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Star Zeng Reviewed-by: Eugene Cohen Reviewed-by: Liming Gao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18872 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c b/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c index 7480b662c579..e7e795d123d6 100644 --- a/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c +++ b/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c @@ -1056,7 +1056,7 @@ PeiDispatcher ( ASSERT_EFI_ERROR (Status); if (FvFileInfo.FileType == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) { // - // For Fv type file, Produce new FV PPI and FV hob + // For Fv type file, Produce new FvInfo PPI and FV hob // Status = ProcessFvFile (Private, &Private->Fv[FvCount], PeimFileHandle); if (Status == EFI_SUCCESS) { @@ -1065,6 +1065,13 @@ PeiDispatcher ( // Private->Fv[FvCount].PeimState[PeimCount]++; Private->PeimDispatchOnThisPass = TRUE; + } else { + // + // The related GuidedSectionExtraction/Decompress PPI for the + // encapsulated FV image section may be installed in the rest + // of this do-while loop, so need to make another pass. + // + Private->PeimNeedingDispatch = TRUE; } } else { // @@ -1192,11 +1199,11 @@ PeiDispatcher ( Private->CurrentPeimFvCount = 0; // - // PeimNeedingDispatch being TRUE means we found a PEIM that did not get + // PeimNeedingDispatch being TRUE means we found a PEIM/FV that did not get // dispatched. So we need to make another pass // - // PeimDispatchOnThisPass being TRUE means we dispatched a PEIM on this - // pass. If we did not dispatch a PEIM there is no point in trying again + // PeimDispatchOnThisPass being TRUE means we dispatched a PEIM/FV on this + // pass. If we did not dispatch a PEIM/FV there is no point in trying again // as it will fail the next time too (nothing has changed). // } while (Private->PeimNeedingDispatch && Private->PeimDispatchOnThisPass); From ba82c72fc4d4f9230d3bf5d0a69b14e44d5105cf Mon Sep 17 00:00:00 2001 From: Nagaraj Hegde Date: Wed, 18 Nov 2015 08:34:44 +0000 Subject: [PATCH 139/525] NetworkPkg:Missing CloseEvent() in HttpResponseWorker Two additional scenarios in which CloseEvent() needs to be called: When sending a request to http server using HTTP Head method, if the process is success, we did a response call, and then go to exit without close the event in Rxtoken in wrap structure and in httpinstance struceure, so another call() to response using http get method to receive http header, those events are not closed either.. (Sync patch r18735 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Nagaraj Hegde Reviewed-by: Fu Siyuan Reviewed-by: Zhang Lubo git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18873 6f19259b-4bc3-4df7-8a09-765794883524 --- NetworkPkg/HttpDxe/HttpImpl.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/NetworkPkg/HttpDxe/HttpImpl.c b/NetworkPkg/HttpDxe/HttpImpl.c index 09ee379150a9..de3ec9c28400 100644 --- a/NetworkPkg/HttpDxe/HttpImpl.c +++ b/NetworkPkg/HttpDxe/HttpImpl.c @@ -1131,6 +1131,18 @@ HttpResponseWorker ( } Token->Status = Status; gBS->SignalEvent (Token->Event); + + if (Wrap != NULL) { + if (Wrap->TcpWrap.RxToken.CompletionToken.Event != NULL) { + gBS->CloseEvent (Wrap->TcpWrap.RxToken.CompletionToken.Event); + } + } + + if (HttpInstance->RxToken.CompletionToken.Event != NULL) { + gBS->CloseEvent (HttpInstance->RxToken.CompletionToken.Event); + HttpInstance->RxToken.CompletionToken.Event = NULL; + } + FreePool (Wrap); return Status; From 0e772049c65ad249b70808b456fc7f8ad694b275 Mon Sep 17 00:00:00 2001 From: Zhang Lubo Date: Wed, 18 Nov 2015 08:36:42 +0000 Subject: [PATCH 140/525] NetworkPkg:Enable Http Boot over Ipv6 stack Add new features to support Http boot over ipv6 stack. (Sync patch r18743 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Zhang Lubo Reviewed-by: Fu Siyuan Reviewed-by: Ye Ting Reviewed-by: Wu Jiaxin git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18874 6f19259b-4bc3-4df7-8a09-765794883524 --- NetworkPkg/HttpBootDxe/HttpBootClient.c | 234 ++- .../HttpBootDxe/HttpBootComponentName.c | 5 +- NetworkPkg/HttpBootDxe/HttpBootDhcp4.c | 12 +- NetworkPkg/HttpBootDxe/HttpBootDhcp4.h | 11 + NetworkPkg/HttpBootDxe/HttpBootDhcp6.c | 984 +++++++++++++ NetworkPkg/HttpBootDxe/HttpBootDhcp6.h | 198 +++ NetworkPkg/HttpBootDxe/HttpBootDxe.c | 903 ++++++++++-- NetworkPkg/HttpBootDxe/HttpBootDxe.h | 159 ++- NetworkPkg/HttpBootDxe/HttpBootDxe.inf | 9 + NetworkPkg/HttpBootDxe/HttpBootDxe.uni | Bin 2008 -> 2040 bytes NetworkPkg/HttpBootDxe/HttpBootImpl.c | 109 +- NetworkPkg/HttpBootDxe/HttpBootImpl.h | 2 +- NetworkPkg/HttpBootDxe/HttpBootSupport.c | 292 +++- NetworkPkg/HttpBootDxe/HttpBootSupport.h | 70 + NetworkPkg/HttpDxe/HttpDns.c | 207 ++- NetworkPkg/HttpDxe/HttpDns.h | 20 + NetworkPkg/HttpDxe/HttpDriver.c | 806 ++++++++--- NetworkPkg/HttpDxe/HttpDriver.h | 143 +- NetworkPkg/HttpDxe/HttpDxe.inf | 5 + NetworkPkg/HttpDxe/HttpDxe.uni | Bin 1822 -> 1854 bytes NetworkPkg/HttpDxe/HttpImpl.c | 374 ++--- NetworkPkg/HttpDxe/HttpProto.c | 1249 ++++++++++++++--- NetworkPkg/HttpDxe/HttpProto.h | 193 ++- 23 files changed, 5071 insertions(+), 914 deletions(-) create mode 100644 NetworkPkg/HttpBootDxe/HttpBootDhcp6.c create mode 100644 NetworkPkg/HttpBootDxe/HttpBootDhcp6.h diff --git a/NetworkPkg/HttpBootDxe/HttpBootClient.c b/NetworkPkg/HttpBootDxe/HttpBootClient.c index 5669c5f37ce1..b81b03c96070 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootClient.c +++ b/NetworkPkg/HttpBootDxe/HttpBootClient.c @@ -54,14 +54,27 @@ HttpBootUpdateDevicePath ( Node->Ipv4.StaticIpAddress = FALSE; CopyMem (&Node->Ipv4.GatewayIpAddress, &Private->GatewayIp, sizeof (EFI_IPv4_ADDRESS)); CopyMem (&Node->Ipv4.SubnetMask, &Private->SubnetMask, sizeof (EFI_IPv4_ADDRESS)); - - TmpDevicePath = AppendDevicePathNode (Private->ParentDevicePath, (EFI_DEVICE_PATH_PROTOCOL*) Node); - FreePool (Node); - if (TmpDevicePath == NULL) { + } else { + Node = AllocateZeroPool (sizeof (IPv6_DEVICE_PATH)); + if (Node == NULL) { return EFI_OUT_OF_RESOURCES; } - } else { - ASSERT (FALSE); + Node->Ipv6.Header.Type = MESSAGING_DEVICE_PATH; + Node->Ipv6.Header.SubType = MSG_IPv6_DP; + SetDevicePathNodeLength (Node, sizeof (IPv6_DEVICE_PATH)); + Node->Ipv6.PrefixLength = IP6_PREFIX_LENGTH; + Node->Ipv6.RemotePort = Private->Port; + Node->Ipv6.Protocol = EFI_IP_PROTO_TCP; + Node->Ipv6.IpAddressOrigin = 0; + CopyMem (&Node->Ipv6.LocalIpAddress, &Private->StationIp.v6, sizeof (EFI_IPv6_ADDRESS)); + CopyMem (&Node->Ipv6.RemoteIpAddress, &Private->ServerIp.v6, sizeof (EFI_IPv6_ADDRESS)); + CopyMem (&Node->Ipv6.GatewayIpAddress, &Private->GatewayIp.v6, sizeof (EFI_IPv6_ADDRESS)); + } + + TmpDevicePath = AppendDevicePathNode (Private->ParentDevicePath, (EFI_DEVICE_PATH_PROTOCOL*) Node); + FreePool (Node); + if (TmpDevicePath == NULL) { + return EFI_OUT_OF_RESOURCES; } // @@ -85,21 +98,39 @@ HttpBootUpdateDevicePath ( return EFI_OUT_OF_RESOURCES; } - // - // Reinstall the device path protocol of the child handle. - // - Status = gBS->ReinstallProtocolInterface ( - Private->ChildHandle, - &gEfiDevicePathProtocolGuid, - Private->DevicePath, - NewDevicePath - ); - if (EFI_ERROR (Status)) { - return Status; + if (!Private->UsingIpv6) { + // + // Reinstall the device path protocol of the child handle. + // + Status = gBS->ReinstallProtocolInterface ( + Private->Ip4Nic->Controller, + &gEfiDevicePathProtocolGuid, + Private->Ip4Nic->DevicePath, + NewDevicePath + ); + if (EFI_ERROR (Status)) { + return Status; + } + + FreePool (Private->Ip4Nic->DevicePath); + Private->Ip4Nic->DevicePath = NewDevicePath; + } else { + // + // Reinstall the device path protocol of the child handle. + // + Status = gBS->ReinstallProtocolInterface ( + Private->Ip6Nic->Controller, + &gEfiDevicePathProtocolGuid, + Private->Ip6Nic->DevicePath, + NewDevicePath + ); + if (EFI_ERROR (Status)) { + return Status; + } + FreePool (Private->Ip6Nic->DevicePath); + Private->Ip6Nic->DevicePath = NewDevicePath; } - FreePool (Private->DevicePath); - Private->DevicePath = NewDevicePath; return EFI_SUCCESS; } @@ -113,7 +144,7 @@ HttpBootUpdateDevicePath ( **/ EFI_STATUS -HttpBootExtractUriInfo ( +HttpBootDhcp4ExtractUriInfo ( IN HTTP_BOOT_PRIVATE_DATA *Private ) { @@ -192,6 +223,159 @@ HttpBootExtractUriInfo ( return Status; } +/** + Parse the boot file URI information from the selected Dhcp6 offer packet. + + @param[in] Private The pointer to the driver's private data. + + @retval EFI_SUCCESS Successfully parsed out all the boot information. + @retval Others Failed to parse out the boot information. + +**/ +EFI_STATUS +HttpBootDhcp6ExtractUriInfo ( + IN HTTP_BOOT_PRIVATE_DATA *Private + ) +{ + HTTP_BOOT_DHCP6_PACKET_CACHE *SelectOffer; + HTTP_BOOT_DHCP6_PACKET_CACHE *HttpOffer; + UINT32 SelectIndex; + UINT32 ProxyIndex; + EFI_DHCP6_PACKET_OPTION *Option; + EFI_IPv6_ADDRESS IpAddr; + CHAR8 *HostName; + CHAR16 *HostNameStr; + EFI_STATUS Status; + + ASSERT (Private != NULL); + ASSERT (Private->SelectIndex != 0); + SelectIndex = Private->SelectIndex - 1; + ASSERT (SelectIndex < HTTP_BOOT_OFFER_MAX_NUM); + + Status = EFI_SUCCESS; + HostName = NULL; + // + // SelectOffer contains the IP address configuration and name server configuration. + // HttpOffer contains the boot file URL. + // + SelectOffer = &Private->OfferBuffer[SelectIndex].Dhcp6; + if ((SelectOffer->OfferType == HttpOfferTypeDhcpIpUri) || (SelectOffer->OfferType == HttpOfferTypeDhcpNameUriDns)) { + HttpOffer = SelectOffer; + } else { + ASSERT (Private->SelectProxyType != HttpOfferTypeMax); + ProxyIndex = Private->OfferIndex[Private->SelectProxyType][0]; + HttpOffer = &Private->OfferBuffer[ProxyIndex].Dhcp6; + } + + // + // Set the Local station address to IP layer. + // + Status = HttpBootSetIp6Address (Private); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Configure the default DNS server if server assigned. + // + if ((SelectOffer->OfferType == HttpOfferTypeDhcpNameUriDns) || (SelectOffer->OfferType == HttpOfferTypeDhcpDns)) { + Option = SelectOffer->OptList[HTTP_BOOT_DHCP6_IDX_DNS_SERVER]; + ASSERT (Option != NULL); + Status = HttpBootSetIp6Dns ( + Private, + HTONS (Option->OpLen), + Option->Data + ); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // Extract the HTTP server Ip frome URL. This is used to Check route table + // whether can send message to HTTP Server Ip through the GateWay. + // + Status = HttpUrlGetIp6 ( + (CHAR8*) HttpOffer->OptList[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL]->Data, + HttpOffer->UriParser, + &IpAddr + ); + + if (EFI_ERROR (Status)) { + // + // The Http server address is expressed by Name Ip, so perform DNS resolution + // + Status = HttpUrlGetHostName ( + (CHAR8*) HttpOffer->OptList[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL]->Data, + HttpOffer->UriParser, + &HostName + ); + if (EFI_ERROR (Status)) { + return Status; + } + + HostNameStr = AllocateZeroPool ((AsciiStrLen (HostName) + 1) * sizeof (CHAR16)); + if (HostNameStr == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Error; + } + + AsciiStrToUnicodeStr (HostName, HostNameStr); + Status = HttpBootDns (Private, HostNameStr, &IpAddr); + FreePool (HostNameStr); + if (EFI_ERROR (Status)) { + goto Error; + } + } + + CopyMem (&Private->ServerIp.v6, &IpAddr, sizeof (EFI_IPv6_ADDRESS)); + + // + // register the IPv6 gateway address to the network device. + // + Status = HttpBootSetIp6Gateway (Private); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Extract the port from URL, and use default HTTP port 80 if not provided. + // + Status = HttpUrlGetPort ( + (CHAR8*) HttpOffer->OptList[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL]->Data, + HttpOffer->UriParser, + &Private->Port + ); + if (EFI_ERROR (Status) || Private->Port == 0) { + Private->Port = 80; + } + + // + // Record the URI of boot file from the selected HTTP offer. + // + Private->BootFileUriParser = HttpOffer->UriParser; + Private->BootFileUri = (CHAR8*) HttpOffer->OptList[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL]->Data; + + + // + // All boot informations are valid here. + // + AsciiPrint ("\n URI: %a", Private->BootFileUri); + // + // Update the device path to include the IP and boot URI information. + // + Status = HttpBootUpdateDevicePath (Private); + +Error: + + if (HostName != NULL) { + FreePool (HostName); + } + + return Status; +} + + /** Discover all the boot information for boot file. @@ -218,9 +402,9 @@ HttpBootDiscoverBootInfo ( } if (!Private->UsingIpv6) { - Status = HttpBootExtractUriInfo (Private); + Status = HttpBootDhcp4ExtractUriInfo (Private); } else { - ASSERT (FALSE); + Status = HttpBootDhcp6ExtractUriInfo (Private); } return Status; @@ -247,12 +431,14 @@ HttpBootCreateHttpIo ( ZeroMem (&ConfigData, sizeof (HTTP_IO_CONFIG_DATA)); if (!Private->UsingIpv6) { - ConfigData.Config4.HttpVersion = HttpVersion11; + ConfigData.Config4.HttpVersion = HttpVersion11; ConfigData.Config4.RequestTimeOut = HTTP_BOOT_REQUEST_TIMEOUT; IP4_COPY_ADDRESS (&ConfigData.Config4.LocalIp, &Private->StationIp.v4); IP4_COPY_ADDRESS (&ConfigData.Config4.SubnetMask, &Private->SubnetMask.v4); } else { - ASSERT (FALSE); + ConfigData.Config6.HttpVersion = HttpVersion11; + ConfigData.Config6.RequestTimeOut = HTTP_BOOT_REQUEST_TIMEOUT; + IP6_COPY_ADDRESS (&ConfigData.Config6.LocalIp, &Private->StationIp.v6); } Status = HttpIoCreateIo ( diff --git a/NetworkPkg/HttpBootDxe/HttpBootComponentName.c b/NetworkPkg/HttpBootDxe/HttpBootComponentName.c index 0708598c4faf..2c39089da3f7 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootComponentName.c +++ b/NetworkPkg/HttpBootDxe/HttpBootComponentName.c @@ -151,7 +151,10 @@ HttpBootDxeComponentNameGetControllerName ( NicHandle = HttpBootGetNicByIp4Children (ControllerHandle); if (NicHandle == NULL) { - return EFI_UNSUPPORTED; + NicHandle = HttpBootGetNicByIp6Children(ControllerHandle); + if (NicHandle == NULL) { + return EFI_UNSUPPORTED; + } } // diff --git a/NetworkPkg/HttpBootDxe/HttpBootDhcp4.c b/NetworkPkg/HttpBootDxe/HttpBootDhcp4.c index 217c60823370..9a947a6ea63c 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootDhcp4.c +++ b/NetworkPkg/HttpBootDxe/HttpBootDhcp4.c @@ -319,7 +319,7 @@ HttpBootParseDhcp4Packet ( } // - // The offer with "HttpClient" is a Http offer. + // The offer with "HTTPClient" is a Http offer. // Option = Options[HTTP_BOOT_DHCP4_TAG_INDEX_CLASS_ID]; if ((Option != NULL) && (Option->Length >= 9) && @@ -461,13 +461,13 @@ HttpBootCacheDhcp4Offer ( } /** - Select an DHCPv4 offer, and record SelectIndex and SelectProxyType. + Select an DHCPv4 or DHCP6 offer, and record SelectIndex and SelectProxyType. @param[in] Private Pointer to HTTP boot driver private data. **/ VOID -HttpBootSelectDhcp4Offer ( +HttpBootSelectDhcpOffer ( IN HTTP_BOOT_PRIVATE_DATA *Private ) { @@ -590,7 +590,7 @@ HttpBootDhcp4CallBack ( // Select offer according to the priority in UEFI spec, and record the SelectIndex // and SelectProxyType. // - HttpBootSelectDhcp4Offer (Private); + HttpBootSelectDhcpOffer (Private); if (Private->SelectIndex == 0) { Status = EFI_ABORTED; @@ -689,7 +689,7 @@ HttpBootRegisterIp4Dns ( **/ EFI_STATUS -HttpBootSetIpPolicy ( +HttpBootSetIp4Policy ( IN HTTP_BOOT_PRIVATE_DATA *Private ) { @@ -752,7 +752,7 @@ HttpBootDhcp4Dora ( Dhcp4 = Private->Dhcp4; ASSERT (Dhcp4 != NULL); - Status = HttpBootSetIpPolicy (Private); + Status = HttpBootSetIp4Policy (Private); if (EFI_ERROR (Status)) { return Status; } diff --git a/NetworkPkg/HttpBootDxe/HttpBootDhcp4.h b/NetworkPkg/HttpBootDxe/HttpBootDhcp4.h index 200501666b2a..2bc46deafd41 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootDhcp4.h +++ b/NetworkPkg/HttpBootDxe/HttpBootDhcp4.h @@ -245,6 +245,17 @@ typedef struct { EFI_DHCP4_PACKET_OPTION *OptList[HTTP_BOOT_DHCP4_TAG_INDEX_MAX]; } HTTP_BOOT_DHCP4_PACKET_CACHE; +/** + Select an DHCPv4 or DHCP6 offer, and record SelectIndex and SelectProxyType. + + @param[in] Private Pointer to HTTP boot driver private data. + +**/ +VOID +HttpBootSelectDhcpOffer ( + IN HTTP_BOOT_PRIVATE_DATA *Private + ); + /** Start the D.O.R.A DHCPv4 process to acquire the IPv4 address and other Http boot information. diff --git a/NetworkPkg/HttpBootDxe/HttpBootDhcp6.c b/NetworkPkg/HttpBootDxe/HttpBootDhcp6.c new file mode 100644 index 000000000000..e5cf894714e1 --- /dev/null +++ b/NetworkPkg/HttpBootDxe/HttpBootDhcp6.c @@ -0,0 +1,984 @@ +/** @file + Functions implementation related with DHCPv6 for HTTP boot driver. + +Copyright (c) 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials are licensed and made available under +the terms and conditions of the BSD License that accompanies this distribution. +The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php. + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "HttpBootDxe.h" + +/** + Build the options buffer for the DHCPv6 request packet. + + @param[in] Private The pointer to HTTP BOOT driver private data. + @param[out] OptList The pointer to the option pointer array. + @param[in] Buffer The pointer to the buffer to contain the option list. + + @return Index The count of the built-in options. + +**/ +UINT32 +HttpBootBuildDhcp6Options ( + IN HTTP_BOOT_PRIVATE_DATA *Private, + OUT EFI_DHCP6_PACKET_OPTION **OptList, + IN UINT8 *Buffer + ) +{ + HTTP_BOOT_DHCP6_OPTION_ENTRY OptEnt; + UINT16 Value; + UINT32 Index; + + Index = 0; + OptList[0] = (EFI_DHCP6_PACKET_OPTION *) Buffer; + + // + // Append client option request option + // + OptList[Index]->OpCode = HTONS (HTTP_BOOT_DHCP6_OPT_ORO); + OptList[Index]->OpLen = HTONS (8); + OptEnt.Oro = (HTTP_BOOT_DHCP6_OPTION_ORO *) OptList[Index]->Data; + OptEnt.Oro->OpCode[0] = HTONS(HTTP_BOOT_DHCP6_OPT_BOOT_FILE_URL); + OptEnt.Oro->OpCode[1] = HTONS(HTTP_BOOT_DHCP6_OPT_BOOT_FILE_PARAM); + OptEnt.Oro->OpCode[2] = HTONS(HTTP_BOOT_DHCP6_OPT_DNS_SERVERS); + OptEnt.Oro->OpCode[3] = HTONS(HTTP_BOOT_DHCP6_OPT_VENDOR_CLASS); + Index++; + OptList[Index] = GET_NEXT_DHCP6_OPTION (OptList[Index - 1]); + + // + // Append client network device interface option + // + OptList[Index]->OpCode = HTONS (HTTP_BOOT_DHCP6_OPT_UNDI); + OptList[Index]->OpLen = HTONS ((UINT16)3); + OptEnt.Undi = (HTTP_BOOT_DHCP6_OPTION_UNDI *) OptList[Index]->Data; + + if (Private->Nii != NULL) { + OptEnt.Undi->Type = Private->Nii->Type; + OptEnt.Undi->MajorVer = Private->Nii->MajorVer; + OptEnt.Undi->MinorVer = Private->Nii->MinorVer; + } else { + OptEnt.Undi->Type = DEFAULT_UNDI_TYPE; + OptEnt.Undi->MajorVer = DEFAULT_UNDI_MAJOR; + OptEnt.Undi->MinorVer = DEFAULT_UNDI_MINOR; + } + + Index++; + OptList[Index] = GET_NEXT_DHCP6_OPTION (OptList[Index - 1]); + + // + // Append client system architecture option + // + OptList[Index]->OpCode = HTONS (HTTP_BOOT_DHCP6_OPT_ARCH); + OptList[Index]->OpLen = HTONS ((UINT16) sizeof (HTTP_BOOT_DHCP6_OPTION_ARCH)); + OptEnt.Arch = (HTTP_BOOT_DHCP6_OPTION_ARCH *) OptList[Index]->Data; + Value = HTONS (EFI_HTTP_BOOT_CLIENT_SYSTEM_ARCHITECTURE); + CopyMem (&OptEnt.Arch->Type, &Value, sizeof (UINT16)); + Index++; + OptList[Index] = GET_NEXT_DHCP6_OPTION (OptList[Index - 1]); + + // + // Append vendor class identify option. + // + OptList[Index]->OpCode = HTONS (HTTP_BOOT_DHCP6_OPT_VENDOR_CLASS); + OptList[Index]->OpLen = HTONS ((UINT16) sizeof (HTTP_BOOT_DHCP6_OPTION_VENDOR_CLASS)); + OptEnt.VendorClass = (HTTP_BOOT_DHCP6_OPTION_VENDOR_CLASS *) OptList[Index]->Data; + OptEnt.VendorClass->Vendor = HTONL (HTTP_BOOT_DHCP6_ENTERPRISE_NUM); + OptEnt.VendorClass->ClassLen = HTONS ((UINT16) sizeof (HTTP_BOOT_CLASS_ID)); + CopyMem ( + &OptEnt.VendorClass->ClassId, + DEFAULT_CLASS_ID_DATA, + sizeof (HTTP_BOOT_CLASS_ID) + ); + HttpBootUintnToAscDecWithFormat ( + EFI_HTTP_BOOT_CLIENT_SYSTEM_ARCHITECTURE, + OptEnt.VendorClass->ClassId.ArchitectureType, + sizeof (OptEnt.VendorClass->ClassId.ArchitectureType) + ); + + if (Private->Nii != NULL) { + CopyMem ( + OptEnt.VendorClass->ClassId.InterfaceName, + Private->Nii->StringId, + sizeof (OptEnt.VendorClass->ClassId.InterfaceName) + ); + HttpBootUintnToAscDecWithFormat ( + Private->Nii->MajorVer, + OptEnt.VendorClass->ClassId.UndiMajor, + sizeof (OptEnt.VendorClass->ClassId.UndiMajor) + ); + HttpBootUintnToAscDecWithFormat ( + Private->Nii->MinorVer, + OptEnt.VendorClass->ClassId.UndiMinor, + sizeof (OptEnt.VendorClass->ClassId.UndiMinor) + ); + } + + Index++; + + return Index; +} + +/** + Parse out a DHCPv6 option by OptTag, and find the position in buffer. + + @param[in] Buffer The pointer to the option buffer. + @param[in] Length Length of the option buffer. + @param[in] OptTag The required option tag. + + @retval NULL Failed to parse the required option. + @retval Others The postion of the required option in buffer. + +**/ +EFI_DHCP6_PACKET_OPTION * +HttpBootParseDhcp6Options ( + IN UINT8 *Buffer, + IN UINT32 Length, + IN UINT16 OptTag + ) +{ + EFI_DHCP6_PACKET_OPTION *Option; + UINT32 Offset; + + Option = (EFI_DHCP6_PACKET_OPTION *) Buffer; + Offset = 0; + + // + // OpLen and OpCode here are both stored in network order. + // + while (Offset < Length) { + + if (NTOHS (Option->OpCode) == OptTag) { + + return Option; + } + + Offset += (NTOHS(Option->OpLen) + 4); + Option = (EFI_DHCP6_PACKET_OPTION *) (Buffer + Offset); + } + + return NULL; + +} + +/** + Parse the cached DHCPv6 packet, including all the options. + + @param[in] Cache6 The pointer to a cached DHCPv6 packet. + + @retval EFI_SUCCESS Parsed the DHCPv6 packet successfully. + @retval EFI_DEVICE_ERROR Failed to parse and invalid the packet. + +**/ +EFI_STATUS +HttpBootParseDhcp6Packet ( + IN HTTP_BOOT_DHCP6_PACKET_CACHE *Cache6 + ) +{ + EFI_DHCP6_PACKET *Offer; + EFI_DHCP6_PACKET_OPTION **Options; + EFI_DHCP6_PACKET_OPTION *Option; + HTTP_BOOT_OFFER_TYPE OfferType; + EFI_IPv6_ADDRESS IpAddr; + BOOLEAN IsProxyOffer; + BOOLEAN IsHttpOffer; + BOOLEAN IsDnsOffer; + BOOLEAN IpExpressedUri; + EFI_STATUS Status; + UINT32 Offset; + UINT32 Length; + + IsDnsOffer = FALSE; + IpExpressedUri = FALSE; + IsProxyOffer = TRUE; + IsHttpOffer = FALSE; + Offer = &Cache6->Packet.Offer; + Options = Cache6->OptList; + + ZeroMem (Cache6->OptList, sizeof (Cache6->OptList)); + + Option = (EFI_DHCP6_PACKET_OPTION *) (Offer->Dhcp6.Option); + Offset = 0; + Length = GET_DHCP6_OPTION_SIZE (Offer); + + // + // OpLen and OpCode here are both stored in network order, since they are from original packet. + // + while (Offset < Length) { + + if (NTOHS (Option->OpCode) == HTTP_BOOT_DHCP6_OPT_IA_NA) { + Options[HTTP_BOOT_DHCP6_IDX_IA_NA] = Option; + } else if (NTOHS (Option->OpCode) == HTTP_BOOT_DHCP6_OPT_BOOT_FILE_URL) { + // + // The server sends this option to inform the client about an URL to a boot file. + // + Options[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL] = Option; + } else if (NTOHS (Option->OpCode) == HTTP_BOOT_DHCP6_OPT_BOOT_FILE_PARAM) { + Options[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_PARAM] = Option; + } else if (NTOHS (Option->OpCode) == HTTP_BOOT_DHCP6_OPT_VENDOR_CLASS) { + Options[HTTP_BOOT_DHCP6_IDX_VENDOR_CLASS] = Option; + } else if (NTOHS (Option->OpCode) == HTTP_BOOT_DHCP6_OPT_DNS_SERVERS) { + Options[HTTP_BOOT_DHCP6_IDX_DNS_SERVER] = Option; + } + + Offset += (NTOHS (Option->OpLen) + 4); + Option = (EFI_DHCP6_PACKET_OPTION *) (Offer->Dhcp6.Option + Offset); + } + // + // The offer with assigned client address is NOT a proxy offer. + // An ia_na option, embeded with valid ia_addr option and a status_code of success. + // + Option = Options[HTTP_BOOT_DHCP6_IDX_IA_NA]; + if (Option != NULL) { + Option = HttpBootParseDhcp6Options ( + Option->Data + 12, + NTOHS (Option->OpLen), + HTTP_BOOT_DHCP6_OPT_STATUS_CODE + ); + if ((Option != NULL && Option->Data[0] == 0) || (Option == NULL)) { + IsProxyOffer = FALSE; + } + } + + // + // The offer with "HTTPClient" is a Http offer. + // + Option = Options[HTTP_BOOT_DHCP6_IDX_VENDOR_CLASS]; + + if (Option != NULL && + NTOHS(Option->OpLen) >= 10 && + CompareMem (Option->Data, DEFAULT_CLASS_ID_DATA, 10) == 0) { + IsHttpOffer = TRUE; + } + + // + // The offer with Domain Server is a DNS offer. + // + Option = Options[HTTP_BOOT_DHCP6_IDX_DNS_SERVER]; + if (Option != NULL) { + IsDnsOffer = TRUE; + } + + // + // Http offer must have a boot URI. + // + if (IsHttpOffer && Options[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL] == NULL) { + return EFI_DEVICE_ERROR; + } + + // + // Try to retrieve the IP of HTTP server from URI. + // + if (IsHttpOffer) { + Status = HttpParseUrl ( + (CHAR8*) Options[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL]->Data, + (UINT32) AsciiStrLen ((CHAR8*) Options[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL]->Data), + FALSE, + &Cache6->UriParser + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + Status = HttpUrlGetIp6 ( + (CHAR8*) Options[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL]->Data, + Cache6->UriParser, + &IpAddr + ); + IpExpressedUri = !EFI_ERROR (Status); + } + + // + // Determine offer type of the DHCPv6 packet. + // + if (IsHttpOffer) { + if (IpExpressedUri) { + OfferType = IsProxyOffer ? HttpOfferTypeProxyIpUri : HttpOfferTypeDhcpIpUri; + } else { + if (!IsProxyOffer) { + OfferType = IsDnsOffer ? HttpOfferTypeDhcpNameUriDns : HttpOfferTypeDhcpNameUri; + } else { + OfferType = HttpOfferTypeProxyNameUri; + } + } + + } else { + if (!IsProxyOffer) { + OfferType = IsDnsOffer ? HttpOfferTypeDhcpDns : HttpOfferTypeDhcpOnly; + } else { + return EFI_DEVICE_ERROR; + } + } + + Cache6->OfferType = OfferType; + return EFI_SUCCESS; +} + +/** + Cache the DHCPv6 packet. + + @param[in] Dst The pointer to the cache buffer for DHCPv6 packet. + @param[in] Src The pointer to the DHCPv6 packet to be cached. + +**/ +VOID +HttpBootCacheDhcp6Packet ( + IN EFI_DHCP6_PACKET *Dst, + IN EFI_DHCP6_PACKET *Src + ) +{ + ASSERT (Dst->Size >= Src->Length); + + CopyMem (&Dst->Dhcp6, &Src->Dhcp6, Src->Length); + Dst->Length = Src->Length; +} + +/** + Cache all the received DHCPv6 offers, and set OfferIndex and OfferCount. + + @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA. + @param[in] RcvdOffer The pointer to the received offer packet. + +**/ +VOID +HttpBootCacheDhcp6Offer ( + IN HTTP_BOOT_PRIVATE_DATA *Private, + IN EFI_DHCP6_PACKET *RcvdOffer + ) +{ + HTTP_BOOT_DHCP6_PACKET_CACHE *Cache6; + EFI_DHCP6_PACKET *Offer; + HTTP_BOOT_OFFER_TYPE OfferType; + + Cache6 = &Private->OfferBuffer[Private->OfferNum].Dhcp6; + Offer = &Cache6->Packet.Offer; + + // + // Cache the content of DHCPv6 packet firstly. + // + HttpBootCacheDhcp6Packet(Offer, RcvdOffer); + + // + // Validate the DHCPv6 packet, and parse the options and offer type. + // + if (EFI_ERROR (HttpBootParseDhcp6Packet (Cache6))) { + return ; + } + + // + // Determine whether cache the current offer by type, and record OfferIndex and OfferCount. + // + OfferType = Cache6->OfferType; + ASSERT (OfferType < HttpOfferTypeMax); + ASSERT (Private->OfferCount[OfferType] < HTTP_BOOT_OFFER_MAX_NUM); + Private->OfferIndex[OfferType][Private->OfferCount[OfferType]] = Private->OfferNum; + Private->OfferCount[OfferType]++; + Private->OfferNum++; +} + +/** + EFI_DHCP6_CALLBACK is provided by the consumer of the EFI DHCPv6 Protocol driver + to intercept events that occurred in the configuration process. + + @param[in] This The pointer to the EFI DHCPv6 Protocol. + @param[in] Context The pointer to the context set by EFI_DHCP6_PROTOCOL.Configure(). + @param[in] CurrentState The current operational state of the EFI DHCPv Protocol driver. + @param[in] Dhcp6Event The event that occurs in the current state, which usually means a + state transition. + @param[in] Packet The DHCPv6 packet that is going to be sent or was already received. + @param[out] NewPacket The packet that is used to replace the Packet above. + + @retval EFI_SUCCESS Told the EFI DHCPv6 Protocol driver to continue the DHCP process. + @retval EFI_NOT_READY Only used in the Dhcp6Selecting state. The EFI DHCPv6 Protocol + driver will continue to wait for more packets. + @retval EFI_ABORTED Told the EFI DHCPv6 Protocol driver to abort the current process. + +**/ +EFI_STATUS +EFIAPI +HttpBootDhcp6CallBack ( + IN EFI_DHCP6_PROTOCOL *This, + IN VOID *Context, + IN EFI_DHCP6_STATE CurrentState, + IN EFI_DHCP6_EVENT Dhcp6Event, + IN EFI_DHCP6_PACKET *Packet, + OUT EFI_DHCP6_PACKET **NewPacket OPTIONAL + ) +{ + HTTP_BOOT_PRIVATE_DATA *Private; + EFI_DHCP6_PACKET *SelectAd; + EFI_STATUS Status; + if ((Dhcp6Event != Dhcp6RcvdAdvertise) && (Dhcp6Event != Dhcp6SelectAdvertise)) { + return EFI_SUCCESS; + } + + ASSERT (Packet != NULL); + + Private = (HTTP_BOOT_PRIVATE_DATA *) Context; + Status = EFI_SUCCESS; + switch (Dhcp6Event) { + + case Dhcp6RcvdAdvertise: + Status = EFI_NOT_READY; + if (Private->OfferNum < HTTP_BOOT_OFFER_MAX_NUM) { + // + // Cache the dhcp offers to OfferBuffer[] for select later, and record + // the OfferIndex and OfferCount. + // + HttpBootCacheDhcp6Offer (Private, Packet); + } + break; + + case Dhcp6SelectAdvertise: + // + // Select offer by the default policy or by order, and record the SelectIndex + // and SelectProxyType. + // + HttpBootSelectDhcpOffer (Private); + + if (Private->SelectIndex == 0) { + Status = EFI_ABORTED; + } else { + ASSERT (NewPacket != NULL); + SelectAd = &Private->OfferBuffer[Private->SelectIndex - 1].Dhcp6.Packet.Offer; + *NewPacket = AllocateZeroPool (SelectAd->Size); + ASSERT (*NewPacket != NULL); + CopyMem (*NewPacket, SelectAd, SelectAd->Size); + } + break; + + default: + break; + } + + return Status; +} + +/** + Check whether IP driver could route the message which will be sent to ServerIp address. + + This function will check the IP6 route table every 1 seconds until specified timeout is expired, if a valid + route is found in IP6 route table, the address will be filed in GatewayAddr and return. + + @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA. + @param[in] TimeOutInSecond Timeout value in seconds. + @param[out] GatewayAddr Pointer to store the gateway IP address. + + @retval EFI_SUCCESS Found a valid gateway address successfully. + @retval EFI_TIMEOUT The operation is time out. + @retval Other Unexpect error happened. + +**/ +EFI_STATUS +HttpBootCheckRouteTable ( + IN HTTP_BOOT_PRIVATE_DATA *Private, + IN UINTN TimeOutInSecond, + OUT EFI_IPv6_ADDRESS *GatewayAddr + ) +{ + EFI_STATUS Status; + EFI_IP6_PROTOCOL *Ip6; + EFI_IP6_MODE_DATA Ip6ModeData; + UINTN Index; + EFI_EVENT TimeOutEvt; + UINTN RetryCount; + BOOLEAN GatewayIsFound; + + ASSERT (GatewayAddr != NULL); + ASSERT (Private != NULL); + + Ip6 = Private->Ip6; + GatewayIsFound = FALSE; + RetryCount = 0; + TimeOutEvt = NULL; + Status = EFI_SUCCESS; + ZeroMem (GatewayAddr, sizeof (EFI_IPv6_ADDRESS)); + + while (TRUE) { + Status = Ip6->GetModeData (Ip6, &Ip6ModeData, NULL, NULL); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + // + // Find out the gateway address which can route the message which send to ServerIp. + // + for (Index = 0; Index < Ip6ModeData.RouteCount; Index++) { + if (NetIp6IsNetEqual (&Private->ServerIp.v6, &Ip6ModeData.RouteTable[Index].Destination, Ip6ModeData.RouteTable[Index].PrefixLength)) { + IP6_COPY_ADDRESS (GatewayAddr, &Ip6ModeData.RouteTable[Index].Gateway); + GatewayIsFound = TRUE; + break; + } + } + + if (Ip6ModeData.AddressList != NULL) { + FreePool (Ip6ModeData.AddressList); + } + if (Ip6ModeData.GroupTable != NULL) { + FreePool (Ip6ModeData.GroupTable); + } + if (Ip6ModeData.RouteTable != NULL) { + FreePool (Ip6ModeData.RouteTable); + } + if (Ip6ModeData.NeighborCache != NULL) { + FreePool (Ip6ModeData.NeighborCache); + } + if (Ip6ModeData.PrefixTable != NULL) { + FreePool (Ip6ModeData.PrefixTable); + } + if (Ip6ModeData.IcmpTypeList != NULL) { + FreePool (Ip6ModeData.IcmpTypeList); + } + + if (GatewayIsFound || RetryCount == TimeOutInSecond) { + break; + } + + RetryCount++; + + // + // Delay 1 second then recheck it again. + // + if (TimeOutEvt == NULL) { + Status = gBS->CreateEvent ( + EVT_TIMER, + TPL_CALLBACK, + NULL, + NULL, + &TimeOutEvt + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + } + + Status = gBS->SetTimer (TimeOutEvt, TimerRelative, TICKS_PER_SECOND); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + while (EFI_ERROR (gBS->CheckEvent (TimeOutEvt))) { + Ip6->Poll (Ip6); + } + } + +ON_EXIT: + if (TimeOutEvt != NULL) { + gBS->CloseEvent (TimeOutEvt); + } + + if (GatewayIsFound) { + Status = EFI_SUCCESS; + } else if (RetryCount == TimeOutInSecond) { + Status = EFI_TIMEOUT; + } + + return Status; +} + +/** + Set the IP6 policy to Automatic. + + @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA. + + @retval EFI_SUCCESS Switch the IP policy succesfully. + @retval Others Unexpect error happened. + +**/ +EFI_STATUS +HttpBootSetIp6Policy ( + IN HTTP_BOOT_PRIVATE_DATA *Private + ) +{ + EFI_IP6_CONFIG_POLICY Policy; + EFI_IP6_CONFIG_PROTOCOL *Ip6Config; + EFI_STATUS Status; + UINTN DataSize; + + Ip6Config = Private->Ip6Config; + DataSize = sizeof (EFI_IP6_CONFIG_POLICY); + + // + // Get and store the current policy of IP6 driver. + // + Status = Ip6Config->GetData ( + Ip6Config, + Ip6ConfigDataTypePolicy, + &DataSize, + &Policy + ); + if (EFI_ERROR (Status)) { + return Status; + } + + if (Policy == Ip6ConfigPolicyManual) { + Policy = Ip6ConfigPolicyAutomatic; + Status = Ip6Config->SetData ( + Ip6Config, + Ip6ConfigDataTypePolicy, + sizeof(EFI_IP6_CONFIG_POLICY), + &Policy + ); + if (EFI_ERROR (Status)) { + return Status; + } + } + return EFI_SUCCESS; +} + +/** + This function will register the default DNS addresses to the network device. + + @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA. + @param[in] DataLength Size of the buffer pointed to by DnsServerData in bytes. + @param[in] DnsServerData Point a list of DNS server address in an array + of EFI_IPv6_ADDRESS instances. + + @retval EFI_SUCCESS The DNS configuration has been configured successfully. + @retval Others Failed to configure the address. + +**/ +EFI_STATUS +HttpBootSetIp6Dns ( + IN HTTP_BOOT_PRIVATE_DATA *Private, + IN UINTN DataLength, + IN VOID *DnsServerData + ) +{ + EFI_IP6_CONFIG_PROTOCOL *Ip6Config; + + ASSERT (Private->UsingIpv6); + + Ip6Config = Private->Ip6Config; + + return Ip6Config->SetData ( + Ip6Config, + Ip6ConfigDataTypeDnsServer, + DataLength, + DnsServerData + ); +} + +/** + This function will register the IPv6 gateway address to the network device. + + @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA. + + @retval EFI_SUCCESS The new IP configuration has been configured successfully. + @retval Others Failed to configure the address. + +**/ +EFI_STATUS +HttpBootSetIp6Gateway ( + IN HTTP_BOOT_PRIVATE_DATA *Private + ) +{ + EFI_IP6_CONFIG_PROTOCOL *Ip6Config; + EFI_STATUS Status; + + ASSERT (Private->UsingIpv6); + Ip6Config = Private->Ip6Config; + + // + // Set the default gateway address. + // + if (!Private->NoGateway && !NetIp6IsUnspecifiedAddr (&Private->GatewayIp.v6)) { + Status = Ip6Config->SetData ( + Ip6Config, + Ip6ConfigDataTypeGateway, + sizeof (EFI_IPv6_ADDRESS), + &Private->GatewayIp.v6 + ); + if (EFI_ERROR(Status)) { + return Status; + } + } + + return EFI_SUCCESS; +} + +/** + This function will register the station IP address. + + @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA. + + @retval EFI_SUCCESS The new IP address has been configured successfully. + @retval Others Failed to configure the address. + +**/ +EFI_STATUS +HttpBootSetIp6Address ( + IN HTTP_BOOT_PRIVATE_DATA *Private +) +{ + EFI_STATUS Status; + EFI_IP6_PROTOCOL *Ip6; + EFI_IP6_CONFIG_PROTOCOL *Ip6Cfg; + EFI_IP6_CONFIG_POLICY Policy; + EFI_IP6_CONFIG_MANUAL_ADDRESS CfgAddr; + EFI_IPv6_ADDRESS *Ip6Addr; + EFI_IPv6_ADDRESS GatewayAddr; + EFI_IP6_CONFIG_DATA Ip6CfgData; + EFI_EVENT MappedEvt; + UINTN DataSize; + BOOLEAN IsAddressOk; + UINTN Index; + + ASSERT (Private->UsingIpv6); + + MappedEvt = NULL; + IsAddressOk = FALSE; + Ip6Addr = NULL; + Ip6Cfg = Private->Ip6Config; + Ip6 = Private->Ip6; + + ZeroMem (&CfgAddr, sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS)); + CopyMem (&CfgAddr, &Private->StationIp.v6, sizeof (EFI_IPv6_ADDRESS)); + ZeroMem (&Ip6CfgData, sizeof (EFI_IP6_CONFIG_DATA)); + + Ip6CfgData.AcceptIcmpErrors = TRUE; + Ip6CfgData.DefaultProtocol = IP6_ICMP; + Ip6CfgData.HopLimit = HTTP_BOOT_DEFAULT_HOPLIMIT; + Ip6CfgData.ReceiveTimeout = HTTP_BOOT_DEFAULT_LIFETIME; + Ip6CfgData.TransmitTimeout = HTTP_BOOT_DEFAULT_LIFETIME; + + Status = Ip6->Configure (Ip6, &Ip6CfgData); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + // + // Retrieve the gateway address from IP6 route table. + // + Status = HttpBootCheckRouteTable (Private, HTTP_BOOT_IP6_ROUTE_TABLE_TIMEOUT, &GatewayAddr); + if (EFI_ERROR (Status)) { + Private->NoGateway = TRUE; + } else { + IP6_COPY_ADDRESS (&Private->GatewayIp.v6, &GatewayAddr); + } + + // + // Set the new address by Ip6ConfigProtocol manually. + // + Policy = Ip6ConfigPolicyManual; + Status = Ip6Cfg->SetData ( + Ip6Cfg, + Ip6ConfigDataTypePolicy, + sizeof(EFI_IP6_CONFIG_POLICY), + &Policy + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + // + // Create a notify event to set address flag when DAD if IP6 driver succeeded. + // + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + HttpBootCommonNotify, + &IsAddressOk, + &MappedEvt + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + // + // Set static host ip6 address. This is a asynchronous process. + // + Status = Ip6Cfg->RegisterDataNotify ( + Ip6Cfg, + Ip6ConfigDataTypeManualAddress, + MappedEvt + ); + if (EFI_ERROR(Status)) { + goto ON_EXIT; + } + + Status = Ip6Cfg->SetData ( + Ip6Cfg, + Ip6ConfigDataTypeManualAddress, + sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS), + &CfgAddr + ); + if (EFI_ERROR (Status) && Status != EFI_NOT_READY) { + goto ON_EXIT; + } else if (Status == EFI_NOT_READY) { + // + // Poll the network until the asynchronous process is finished. + // + while (!IsAddressOk) { + Ip6->Poll (Ip6); + } + // + // Check whether the Ip6 Address setting is successed. + // + DataSize = 0; + Status = Ip6Cfg->GetData ( + Ip6Cfg, + Ip6ConfigDataTypeManualAddress, + &DataSize, + NULL + ); + if (Status != EFI_BUFFER_TOO_SMALL || DataSize == 0) { + Status = EFI_DEVICE_ERROR; + goto ON_EXIT; + } + + Ip6Addr = AllocatePool (DataSize); + if (Ip6Addr == NULL) { + return EFI_OUT_OF_RESOURCES; + } + Status = Ip6Cfg->GetData ( + Ip6Cfg, + Ip6ConfigDataTypeManualAddress, + &DataSize, + (VOID *) Ip6Addr + ); + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + goto ON_EXIT; + } + + for (Index = 0; Index < DataSize / sizeof (EFI_IPv6_ADDRESS); Index ++) { + if (CompareMem (Ip6Addr + Index, &CfgAddr, sizeof (EFI_IPv6_ADDRESS)) == 0) { + break; + } + } + if (Index == DataSize / sizeof (EFI_IPv6_ADDRESS)) { + Status = EFI_ABORTED; + goto ON_EXIT; + } + } + +ON_EXIT: + if (MappedEvt != NULL) { + Ip6Cfg->UnregisterDataNotify ( + Ip6Cfg, + Ip6ConfigDataTypeManualAddress, + MappedEvt + ); + gBS->CloseEvent (MappedEvt); + } + + if (Ip6Addr != NULL) { + FreePool (Ip6Addr); + } + + return Status; +} + +/** + Start the S.A.R.R DHCPv6 process to acquire the IPv6 address and other Http boot information. + + @param[in] Private Pointer to HTTP_BOOT private data. + + @retval EFI_SUCCESS The S.A.R.R process successfully finished. + @retval Others Failed to finish the S.A.R.R process. + +**/ +EFI_STATUS +HttpBootDhcp6Sarr ( + IN HTTP_BOOT_PRIVATE_DATA *Private + ) +{ + EFI_DHCP6_PROTOCOL *Dhcp6; + EFI_DHCP6_CONFIG_DATA Config; + EFI_DHCP6_MODE_DATA Mode; + EFI_DHCP6_RETRANSMISSION *Retransmit; + EFI_DHCP6_PACKET_OPTION *OptList[HTTP_BOOT_DHCP6_OPTION_MAX_NUM]; + UINT32 OptCount; + UINT8 Buffer[HTTP_BOOT_DHCP6_OPTION_MAX_SIZE]; + EFI_STATUS Status; + + Dhcp6 = Private->Dhcp6; + ASSERT (Dhcp6 != NULL); + + // + // Build options list for the request packet. + // + OptCount = HttpBootBuildDhcp6Options (Private, OptList, Buffer); + ASSERT (OptCount >0); + + Retransmit = AllocateZeroPool (sizeof (EFI_DHCP6_RETRANSMISSION)); + if (Retransmit == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + ZeroMem (&Mode, sizeof (EFI_DHCP6_MODE_DATA)); + ZeroMem (&Config, sizeof (EFI_DHCP6_CONFIG_DATA)); + + Config.OptionCount = OptCount; + Config.OptionList = OptList; + Config.Dhcp6Callback = HttpBootDhcp6CallBack; + Config.CallbackContext = Private; + Config.IaInfoEvent = NULL; + Config.RapidCommit = FALSE; + Config.ReconfigureAccept = FALSE; + Config.IaDescriptor.IaId = NET_RANDOM (NetRandomInitSeed ()); + Config.IaDescriptor.Type = EFI_DHCP6_IA_TYPE_NA; + Config.SolicitRetransmission = Retransmit; + Retransmit->Irt = 4; + Retransmit->Mrc = 4; + Retransmit->Mrt = 32; + Retransmit->Mrd = 60; + + // + // Configure the DHCPv6 instance for HTTP boot. + // + Status = Dhcp6->Configure (Dhcp6, &Config); + FreePool (Retransmit); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + // + // Initialize the record fields for DHCPv6 offer in private data. + // + Private->OfferNum = 0; + Private->SelectIndex = 0; + ZeroMem (Private->OfferCount, sizeof (Private->OfferCount)); + ZeroMem (Private->OfferIndex, sizeof (Private->OfferIndex)); + + // + // Start DHCPv6 S.A.R.R. process to acquire IPv6 address. + // + Status = Dhcp6->Start (Dhcp6); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + // + // Get the acquired IPv6 address and store them. + // + Status = Dhcp6->GetModeData (Dhcp6, &Mode, NULL); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + ASSERT (Mode.Ia->State == Dhcp6Bound); + CopyMem (&Private->StationIp.v6, &Mode.Ia->IaAddress[0].IpAddress, sizeof (EFI_IPv6_ADDRESS)); + + AsciiPrint ("\n Station IPv6 address is "); + HttpBootShowIp6Addr (&Private->StationIp.v6); + AsciiPrint ("\n"); + +ON_EXIT: + if (EFI_ERROR (Status)) { + Dhcp6->Stop (Dhcp6); + Dhcp6->Configure (Dhcp6, NULL); + } else { + ZeroMem (&Config, sizeof (EFI_DHCP6_CONFIG_DATA)); + ZeroMem (&Mode, sizeof (EFI_DHCP6_MODE_DATA)); + Dhcp6->Configure (Dhcp6, &Config); + } + + return Status; + +} + diff --git a/NetworkPkg/HttpBootDxe/HttpBootDhcp6.h b/NetworkPkg/HttpBootDxe/HttpBootDhcp6.h new file mode 100644 index 000000000000..59ca19e464ff --- /dev/null +++ b/NetworkPkg/HttpBootDxe/HttpBootDhcp6.h @@ -0,0 +1,198 @@ +/** @file + Functions declaration related with DHCPv6 for HTTP boot driver. + +Copyright (c) 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials are licensed and made available under +the terms and conditions of the BSD License that accompanies this distribution. +The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php. + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + + +#ifndef __EFI_HTTP_BOOT_DHCP6_H__ +#define __EFI_HTTP_BOOT_DHCP6_H__ + +#define HTTP_BOOT_OFFER_MAX_NUM 16 +#define HTTP_BOOT_DHCP6_OPTION_MAX_NUM 16 +#define HTTP_BOOT_DHCP6_OPTION_MAX_SIZE 312 +#define HTTP_BOOT_DHCP6_PACKET_MAX_SIZE 1472 +#define HTTP_BOOT_IP6_ROUTE_TABLE_TIMEOUT 10 +#define HTTP_BOOT_DEFAULT_HOPLIMIT 64 +#define HTTP_BOOT_DEFAULT_LIFETIME 50000 + + +#define HTTP_BOOT_DHCP6_OPT_CLIENT_ID 1 +#define HTTP_BOOT_DHCP6_OPT_SERVER_ID 2 +#define HTTP_BOOT_DHCP6_OPT_IA_NA 3 +#define HTTP_BOOT_DHCP6_OPT_IA_TA 4 +#define HTTP_BOOT_DHCP6_OPT_IAADDR 5 +#define HTTP_BOOT_DHCP6_OPT_ORO 6 +#define HTTP_BOOT_DHCP6_OPT_PREFERENCE 7 +#define HTTP_BOOT_DHCP6_OPT_ELAPSED_TIME 8 +#define HTTP_BOOT_DHCP6_OPT_REPLAY_MSG 9 +#define HTTP_BOOT_DHCP6_OPT_AUTH 11 +#define HTTP_BOOT_DHCP6_OPT_UNICAST 12 +#define HTTP_BOOT_DHCP6_OPT_STATUS_CODE 13 +#define HTTP_BOOT_DHCP6_OPT_RAPID_COMMIT 14 +#define HTTP_BOOT_DHCP6_OPT_USER_CLASS 15 +#define HTTP_BOOT_DHCP6_OPT_VENDOR_CLASS 16 +#define HTTP_BOOT_DHCP6_OPT_VENDOR_OPTS 17 +#define HTTP_BOOT_DHCP6_OPT_INTERFACE_ID 18 +#define HTTP_BOOT_DHCP6_OPT_RECONFIG_MSG 19 +#define HTTP_BOOT_DHCP6_OPT_RECONFIG_ACCEPT 20 +#define HTTP_BOOT_DHCP6_OPT_DNS_SERVERS 23 +#define HTTP_BOOT_DHCP6_OPT_BOOT_FILE_URL 59 // Assigned by IANA, RFC 5970 +#define HTTP_BOOT_DHCP6_OPT_BOOT_FILE_PARAM 60 // Assigned by IANA, RFC 5970 +#define HTTP_BOOT_DHCP6_OPT_ARCH 61 // Assigned by IANA, RFC 5970 +#define HTTP_BOOT_DHCP6_OPT_UNDI 62 // Assigned by IANA, RFC 5970 +#define HTTP_BOOT_DHCP6_ENTERPRISE_NUM 343 // TODO: IANA TBD: temporarily using Intel's +#define HTTP_BOOT_DHCP6_MAX_BOOT_FILE_SIZE 65535 // It's a limitation of bit length, 65535*512 bytes. + +#define HTTP_BOOT_DHCP6_IDX_IA_NA 0 +#define HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL 1 +#define HTTP_BOOT_DHCP6_IDX_BOOT_FILE_PARAM 2 +#define HTTP_BOOT_DHCP6_IDX_VENDOR_CLASS 3 +#define HTTP_BOOT_DHCP6_IDX_DNS_SERVER 4 +#define HTTP_BOOT_DHCP6_IDX_MAX 5 + +#pragma pack(1) +typedef struct { + UINT16 OpCode[256]; +} HTTP_BOOT_DHCP6_OPTION_ORO; + +typedef struct { + UINT8 Type; + UINT8 MajorVer; + UINT8 MinorVer; +} HTTP_BOOT_DHCP6_OPTION_UNDI; + +typedef struct { + UINT16 Type; +} HTTP_BOOT_DHCP6_OPTION_ARCH; + +typedef struct { + UINT8 ClassIdentifier[10]; + UINT8 ArchitecturePrefix[5]; + UINT8 ArchitectureType[5]; + UINT8 Lit3[1]; + UINT8 InterfaceName[4]; + UINT8 Lit4[1]; + UINT8 UndiMajor[3]; + UINT8 UndiMinor[3]; +} HTTP_BOOT_CLASS_ID; + +typedef struct { + UINT32 Vendor; + UINT16 ClassLen; + HTTP_BOOT_CLASS_ID ClassId; +} HTTP_BOOT_DHCP6_OPTION_VENDOR_CLASS; + +#pragma pack() + +typedef union { + HTTP_BOOT_DHCP6_OPTION_ORO *Oro; + HTTP_BOOT_DHCP6_OPTION_UNDI *Undi; + HTTP_BOOT_DHCP6_OPTION_ARCH *Arch; + HTTP_BOOT_DHCP6_OPTION_VENDOR_CLASS *VendorClass; +} HTTP_BOOT_DHCP6_OPTION_ENTRY; + +typedef union { + EFI_DHCP6_PACKET Offer; + EFI_DHCP6_PACKET Ack; + UINT8 Buffer[HTTP_BOOT_DHCP6_PACKET_MAX_SIZE]; +} HTTP_BOOT_DHCP6_PACKET; + +typedef struct { + HTTP_BOOT_DHCP6_PACKET Packet; + HTTP_BOOT_OFFER_TYPE OfferType; + EFI_DHCP6_PACKET_OPTION *OptList[HTTP_BOOT_DHCP6_IDX_MAX]; + VOID *UriParser; +} HTTP_BOOT_DHCP6_PACKET_CACHE; + +#define GET_NEXT_DHCP6_OPTION(Opt) \ + (EFI_DHCP6_PACKET_OPTION *) ((UINT8 *) (Opt) + \ + sizeof (EFI_DHCP6_PACKET_OPTION) + (NTOHS ((Opt)->OpLen)) - 1) + +#define GET_DHCP6_OPTION_SIZE(Pkt) \ + ((Pkt)->Length - sizeof (EFI_DHCP6_HEADER)) + +/** + Start the S.A.R.R DHCPv6 process to acquire the IPv6 address and other Http boot information. + + @param[in] Private Pointer to HTTP_BOOT private data. + + @retval EFI_SUCCESS The S.A.R.R process successfully finished. + @retval Others Failed to finish the S.A.R.R process. + +**/ +EFI_STATUS +HttpBootDhcp6Sarr ( + IN HTTP_BOOT_PRIVATE_DATA *Private + ); + +/** + Set the IP6 policy to Automatic. + + @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA. + + @retval EFI_SUCCESS Switch the IP policy succesfully. + @retval Others Unexpect error happened. + +**/ +EFI_STATUS +HttpBootSetIp6Policy ( + IN HTTP_BOOT_PRIVATE_DATA *Private + ); + +/** + This function will register the default DNS addresses to the network device. + + @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA. + @param[in] DataLength Size of the buffer pointed to by DnsServerData in bytes. + @param[in] DnsServerData Point a list of DNS server address in an array + of EFI_IPv6_ADDRESS instances. + + @retval EFI_SUCCESS The DNS configuration has been configured successfully. + @retval Others Failed to configure the address. + +**/ +EFI_STATUS +HttpBootSetIp6Dns ( + IN HTTP_BOOT_PRIVATE_DATA *Private, + IN UINTN DataLength, + IN VOID *DnsServerData + ); + +/** + This function will register the IPv6 gateway address to the network device. + + @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA. + + @retval EFI_SUCCESS The new IP configuration has been configured successfully. + @retval Others Failed to configure the address. + +**/ +EFI_STATUS +HttpBootSetIp6Gateway ( + IN HTTP_BOOT_PRIVATE_DATA *Private + ); + +/** + This function will register the station IP address. + + @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA. + + @retval EFI_SUCCESS The new IP address has been configured successfully. + @retval Others Failed to configure the address. + +**/ +EFI_STATUS +HttpBootSetIp6Address ( + IN HTTP_BOOT_PRIVATE_DATA *Private + ); + +#endif diff --git a/NetworkPkg/HttpBootDxe/HttpBootDxe.c b/NetworkPkg/HttpBootDxe/HttpBootDxe.c index 49be59b8c8e3..a7fc8a8e2e63 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootDxe.c +++ b/NetworkPkg/HttpBootDxe/HttpBootDxe.c @@ -26,6 +26,15 @@ EFI_DRIVER_BINDING_PROTOCOL gHttpBootIp4DxeDriverBinding = { NULL }; +EFI_DRIVER_BINDING_PROTOCOL gHttpBootIp6DxeDriverBinding = { + HttpBootIp6DxeDriverBindingSupported, + HttpBootIp6DxeDriverBindingStart, + HttpBootIp6DxeDriverBindingStop, + HTTP_BOOT_DXE_VERSION, + NULL, + NULL +}; + /** Destroy the HTTP child based on IPv4 stack. @@ -45,11 +54,11 @@ HttpBootDestroyIp4Children ( if (Private->Dhcp4Child != NULL) { gBS->CloseProtocol ( - Private->Dhcp4Child, - &gEfiDhcp4ProtocolGuid, - This->DriverBindingHandle, - Private->Controller - ); + Private->Dhcp4Child, + &gEfiDhcp4ProtocolGuid, + This->DriverBindingHandle, + Private->Controller + ); NetLibDestroyServiceChild ( Private->Controller, @@ -64,25 +73,102 @@ HttpBootDestroyIp4Children ( Private->HttpCreated = FALSE; } - gBS->CloseProtocol ( - Private->Controller, - &gEfiCallerIdGuid, - This->DriverBindingHandle, - Private->ChildHandle - ); + if (Private->Ip4Nic != NULL) { + + gBS->CloseProtocol ( + Private->Controller, + &gEfiCallerIdGuid, + This->DriverBindingHandle, + Private->Ip4Nic->Controller + ); + + gBS->UninstallMultipleProtocolInterfaces ( + Private->Ip4Nic->Controller, + &gEfiLoadFileProtocolGuid, + &Private->Ip4Nic->LoadFile, + &gEfiDevicePathProtocolGuid, + Private->Ip4Nic->DevicePath, + NULL + ); + FreePool (Private->Ip4Nic); + Private->Ip4Nic = NULL; + } + +} + +/** + Destroy the HTTP child based on IPv6 stack. + + @param[in] This Pointer to the EFI_DRIVER_BINDING_PROTOCOL. + @param[in] Private Pointer to HTTP_BOOT_PRIVATE_DATA. + +**/ +VOID +HttpBootDestroyIp6Children ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN HTTP_BOOT_PRIVATE_DATA *Private + ) +{ + ASSERT (This != NULL); + ASSERT (Private != NULL); + ASSERT (Private->UsingIpv6 == TRUE); + + if (Private->Ip6Child != NULL) { + gBS->CloseProtocol ( + Private->Ip6Child, + &gEfiIp6ProtocolGuid, + This->DriverBindingHandle, + Private->Controller + ); + + NetLibDestroyServiceChild ( + Private->Controller, + This->DriverBindingHandle, + &gEfiIp6ServiceBindingProtocolGuid, + Private->Ip6Child + ); + } + + if (Private->Dhcp6Child != NULL) { + gBS->CloseProtocol ( + Private->Dhcp6Child, + &gEfiDhcp6ProtocolGuid, + This->DriverBindingHandle, + Private->Controller + ); - gBS->UninstallMultipleProtocolInterfaces ( - Private->ChildHandle, - &gEfiLoadFileProtocolGuid, - &Private->LoadFile, - &gEfiDevicePathProtocolGuid, - Private->DevicePath, - NULL - ); + NetLibDestroyServiceChild ( + Private->Controller, + This->DriverBindingHandle, + &gEfiDhcp6ServiceBindingProtocolGuid, + Private->Dhcp6Child + ); + } - if (Private->DevicePath != NULL) { - FreePool (Private->DevicePath); - Private->DevicePath = NULL; + if (Private->HttpCreated) { + HttpIoDestroyIo(&Private->HttpIo); + Private->HttpCreated = FALSE; + } + + if (Private->Ip6Nic != NULL) { + + gBS->CloseProtocol ( + Private->Controller, + &gEfiCallerIdGuid, + This->DriverBindingHandle, + Private->Ip6Nic->Controller + ); + + gBS->UninstallMultipleProtocolInterfaces ( + Private->Ip6Nic->Controller, + &gEfiLoadFileProtocolGuid, + &Private->Ip6Nic->LoadFile, + &gEfiDevicePathProtocolGuid, + Private->Ip6Nic->DevicePath, + NULL + ); + FreePool (Private->Ip6Nic); + Private->Ip6Nic = NULL; } } @@ -142,37 +228,37 @@ HttpBootIp4DxeDriverBindingSupported ( // Try to open the DHCP4, HTTP4 and Device Path protocol. // Status = gBS->OpenProtocol ( - ControllerHandle, - &gEfiDhcp4ServiceBindingProtocolGuid, - NULL, - This->DriverBindingHandle, - ControllerHandle, - EFI_OPEN_PROTOCOL_TEST_PROTOCOL - ); + ControllerHandle, + &gEfiDhcp4ServiceBindingProtocolGuid, + NULL, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); if (EFI_ERROR (Status)) { return Status; } Status = gBS->OpenProtocol ( - ControllerHandle, - &gEfiHttpServiceBindingProtocolGuid, - NULL, - This->DriverBindingHandle, - ControllerHandle, - EFI_OPEN_PROTOCOL_TEST_PROTOCOL - ); + ControllerHandle, + &gEfiHttpServiceBindingProtocolGuid, + NULL, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); if (EFI_ERROR (Status)) { return Status; } Status = gBS->OpenProtocol ( - ControllerHandle, - &gEfiDevicePathProtocolGuid, - NULL, - This->DriverBindingHandle, - ControllerHandle, - EFI_OPEN_PROTOCOL_TEST_PROTOCOL - ); + ControllerHandle, + &gEfiDevicePathProtocolGuid, + NULL, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); return Status; } @@ -235,25 +321,83 @@ HttpBootIp4DxeDriverBindingStart ( ControllerHandle, EFI_OPEN_PROTOCOL_GET_PROTOCOL ); + if (!EFI_ERROR (Status)) { - return EFI_ALREADY_STARTED; - } + Private = HTTP_BOOT_PRIVATE_DATA_FROM_ID(Id); + } else { + // + // Initialize the private data structure. + // + Private = AllocateZeroPool (sizeof (HTTP_BOOT_PRIVATE_DATA)); + if (Private == NULL) { + return EFI_OUT_OF_RESOURCES; + } + Private->Signature = HTTP_BOOT_PRIVATE_DATA_SIGNATURE; + Private->Controller = ControllerHandle; + Private->Image = This->ImageHandle; + InitializeListHead (&Private->CacheList); + // + // Get the NII interface if it exists, it's not required. + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiNetworkInterfaceIdentifierProtocolGuid_31, + (VOID **) &Private->Nii, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + Private->Nii = NULL; + } - // - // Initialize the private data structure. - // - Private = AllocateZeroPool (sizeof (HTTP_BOOT_PRIVATE_DATA)); - if (Private == NULL) { + // + // Open Device Path Protocol to prepare for appending IP and URI node. + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiDevicePathProtocolGuid, + (VOID **) &Private->ParentDevicePath, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + // + // Install a protocol with Caller Id Guid to the NIC, this is just to build the relationship between + // NIC handle and the private data. + // + Status = gBS->InstallProtocolInterface ( + &ControllerHandle, + &gEfiCallerIdGuid, + EFI_NATIVE_INTERFACE, + &Private->Id + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + } + + if (Private->Ip4Nic != NULL) { + // + // Already created before + // + return EFI_SUCCESS; + } + + Private->Ip4Nic = AllocateZeroPool (sizeof (HTTP_BOOT_VIRTUAL_NIC)); + if (Private->Ip4Nic == NULL) { return EFI_OUT_OF_RESOURCES; } - Private->Signature = HTTP_BOOT_PRIVATE_DATA_SIGNATURE; - Private->Controller = ControllerHandle; - Private->Image = This->ImageHandle; - Private->UsingIpv6 = FALSE; - InitializeListHead (&Private->CacheList); - + Private->Ip4Nic->Private = Private; + Private->Ip4Nic->Signature = HTTP_BOOT_VIRTUAL_NIC_SIGNATURE; + // - // Create DHCP child instance. + // Create DHCP4 child instance. // Status = NetLibCreateServiceChild ( ControllerHandle, @@ -264,7 +408,7 @@ HttpBootIp4DxeDriverBindingStart ( if (EFI_ERROR (Status)) { goto ON_ERROR; } - + Status = gBS->OpenProtocol ( Private->Dhcp4Child, &gEfiDhcp4ProtocolGuid, @@ -276,7 +420,7 @@ HttpBootIp4DxeDriverBindingStart ( if (EFI_ERROR (Status)) { goto ON_ERROR; } - + // // Get the Ip4Config2 protocol, it's required to configure the default gateway address. // @@ -291,37 +435,7 @@ HttpBootIp4DxeDriverBindingStart ( if (EFI_ERROR (Status)) { goto ON_ERROR; } - - // - // Get the NII interface if it exists, it's not required. - // - Status = gBS->OpenProtocol ( - ControllerHandle, - &gEfiNetworkInterfaceIdentifierProtocolGuid_31, - (VOID **) &Private->Nii, - This->DriverBindingHandle, - ControllerHandle, - EFI_OPEN_PROTOCOL_GET_PROTOCOL - ); - if (EFI_ERROR (Status)) { - Private->Nii = NULL; - } - - // - // Open Device Path Protocol to prepare for appending IP and URI node. - // - Status = gBS->OpenProtocol ( - ControllerHandle, - &gEfiDevicePathProtocolGuid, - (VOID **) &Private->ParentDevicePath, - This->DriverBindingHandle, - ControllerHandle, - EFI_OPEN_PROTOCOL_GET_PROTOCOL - ); - if (EFI_ERROR (Status)) { - goto ON_ERROR; - } - + // // Append IPv4 device path node. // @@ -340,7 +454,7 @@ HttpBootIp4DxeDriverBindingStart ( Status = EFI_OUT_OF_RESOURCES; goto ON_ERROR; } - + // // Append URI device path node. // @@ -352,62 +466,49 @@ HttpBootIp4DxeDriverBindingStart ( Node->DevPath.Type = MESSAGING_DEVICE_PATH; Node->DevPath.SubType = MSG_URI_DP; SetDevicePathNodeLength (Node, sizeof (EFI_DEVICE_PATH_PROTOCOL)); - Private->DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL*) Node); + Private->Ip4Nic->DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL*) Node); FreePool (Node); FreePool (DevicePath); - if (Private->DevicePath == NULL) { + if (Private->Ip4Nic->DevicePath == NULL) { Status = EFI_OUT_OF_RESOURCES; goto ON_ERROR; } - + // // Create a child handle for the HTTP boot and install DevPath and Load file protocol on it. // - CopyMem (&Private->LoadFile, &gHttpBootDxeLoadFile, sizeof (Private->LoadFile)); + CopyMem (&Private->Ip4Nic->LoadFile, &gHttpBootDxeLoadFile, sizeof (EFI_LOAD_FILE_PROTOCOL)); Status = gBS->InstallMultipleProtocolInterfaces ( - &Private->ChildHandle, + &Private->Ip4Nic->Controller, &gEfiLoadFileProtocolGuid, - &Private->LoadFile, + &Private->Ip4Nic->LoadFile, &gEfiDevicePathProtocolGuid, - Private->DevicePath, + Private->Ip4Nic->DevicePath, NULL ); if (EFI_ERROR (Status)) { goto ON_ERROR; } - - // - // Install a protocol with Caller Id Guid to the NIC, this is just to build the relationship between - // NIC handle and the private data. - // - Status = gBS->InstallProtocolInterface ( - &ControllerHandle, - &gEfiCallerIdGuid, - EFI_NATIVE_INTERFACE, - &Private->Id - ); - if (EFI_ERROR (Status)) { - goto ON_ERROR; - } - + // // Open the Caller Id child to setup a parent-child relationship between - // real NIC handle and the HTTP boot child handle. + // real NIC handle and the HTTP boot Ipv4 NIC handle. // Status = gBS->OpenProtocol ( ControllerHandle, &gEfiCallerIdGuid, (VOID **) &Id, This->DriverBindingHandle, - Private->ChildHandle, + Private->Ip4Nic->Controller, EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER ); if (EFI_ERROR (Status)) { goto ON_ERROR; } - + return EFI_SUCCESS; + ON_ERROR: HttpBootDestroyIp4Children (This, Private); @@ -416,6 +517,7 @@ HttpBootIp4DxeDriverBindingStart ( return Status; } + /** Stops a device controller or a bus controller. @@ -509,51 +611,560 @@ HttpBootIp4DxeDriverBindingStop ( // Destory all child instance and uninstall protocol interface. // HttpBootDestroyIp4Children (This, Private); + + if (Private->Ip4Nic == NULL && Private->Ip6Nic == NULL) { + // + // Release the cached data. + // + HttpBootFreeCacheList (Private); + + gBS->UninstallProtocolInterface ( + NicHandle, + &gEfiCallerIdGuid, + &Private->Id + ); + FreePool (Private); - // - // Release the cached data. - // - HttpBootFreeCacheList (Private); - - gBS->UninstallProtocolInterface ( - NicHandle, - &gEfiCallerIdGuid, - &Private->Id - ); - FreePool (Private); + } return EFI_SUCCESS; } /** - This is the declaration of an EFI image entry point. This entry point is - the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including - both device drivers and bus drivers. + Tests to see if this driver supports a given controller. If a child device is provided, + it further tests to see if this driver supports creating a handle for the specified child device. - @param[in] ImageHandle The firmware allocated handle for the UEFI image. - @param[in] SystemTable A pointer to the EFI System Table. + This function checks to see if the driver specified by This supports the device specified by + ControllerHandle. Drivers will typically use the device path attached to + ControllerHandle and/or the services from the bus I/O abstraction attached to + ControllerHandle to determine if the driver supports ControllerHandle. This function + may be called many times during platform initialization. In order to reduce boot times, the tests + performed by this function must be very small, and take as little time as possible to execute. This + function must not change the state of any hardware devices, and this function must be aware that the + device specified by ControllerHandle may already be managed by the same driver or a + different driver. This function must match its calls to AllocatePages() with FreePages(), + AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol(). + Because ControllerHandle may have been previously started by the same driver, if a protocol is + already in the opened state, then it must not be closed with CloseProtocol(). This is required + to guarantee the state of ControllerHandle is not modified by this function. - @retval EFI_SUCCESS The operation completed successfully. - @retval Others An unexpected error occurred. + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle The handle of the controller to test. This handle + must support a protocol interface that supplies + an I/O abstraction to the driver. + @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This + parameter is ignored by device drivers, and is optional for bus + drivers. For bus drivers, if this parameter is not NULL, then + the bus driver must determine if the bus controller specified + by ControllerHandle and the child controller specified + by RemainingDevicePath are both supported by this + bus driver. + @retval EFI_SUCCESS The device specified by ControllerHandle and + RemainingDevicePath is supported by the driver specified by This. + @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and + RemainingDevicePath is already being managed by the driver + specified by This. + @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and + RemainingDevicePath is already being managed by a different + driver or an application that requires exclusive access. + Currently not implemented. + @retval EFI_UNSUPPORTED The device specified by ControllerHandle and + RemainingDevicePath is not supported by the driver specified by This. **/ EFI_STATUS EFIAPI -HttpBootDxeDriverEntryPoint ( - IN EFI_HANDLE ImageHandle, - IN EFI_SYSTEM_TABLE *SystemTable +HttpBootIp6DxeDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL ) { + EFI_STATUS Status; + // - // Install UEFI Driver Model protocol(s). + // Try to open the DHCP6, HTTP and Device Path protocol. // - return EfiLibInstallDriverBindingComponentName2 ( - ImageHandle, - SystemTable, - &gHttpBootIp4DxeDriverBinding, - ImageHandle, - &gHttpBootDxeComponentName, - &gHttpBootDxeComponentName2 - ); + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiDhcp6ServiceBindingProtocolGuid, + NULL, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiHttpServiceBindingProtocolGuid, + NULL, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiDevicePathProtocolGuid, + NULL, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + + return Status; + +} + +/** + Starts a device controller or a bus controller. + + The Start() function is designed to be invoked from the EFI boot service ConnectController(). + As a result, much of the error checking on the parameters to Start() has been moved into this + common boot service. It is legal to call Start() from other locations, + but the following calling restrictions must be followed, or the system behavior will not be deterministic. + 1. ControllerHandle must be a valid EFI_HANDLE. + 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned + EFI_DEVICE_PATH_PROTOCOL. + 3. Prior to calling Start(), the Supported() function for the driver specified by This must + have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle The handle of the controller to start. This handle + must support a protocol interface that supplies + an I/O abstraction to the driver. + @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This + parameter is ignored by device drivers, and is optional for bus + drivers. For a bus driver, if this parameter is NULL, then handles + for all the children of Controller are created by this driver. + If this parameter is not NULL and the first Device Path Node is + not the End of Device Path Node, then only the handle for the + child device specified by the first Device Path Node of + RemainingDevicePath is created by this driver. + If the first Device Path Node of RemainingDevicePath is + the End of Device Path Node, no child handle is created by this + driver. + + @retval EFI_SUCCESS The device was started. + @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval Others The driver failded to start the device. + +**/ +EFI_STATUS +EFIAPI +HttpBootIp6DxeDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ) +{ + EFI_STATUS Status; + HTTP_BOOT_PRIVATE_DATA *Private; + EFI_DEV_PATH *Node; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + UINT32 *Id; + + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiCallerIdGuid, + (VOID **) &Id, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (!EFI_ERROR (Status)) { + Private = HTTP_BOOT_PRIVATE_DATA_FROM_ID(Id); + } else { + // + // Initialize the private data structure. + // + Private = AllocateZeroPool (sizeof (HTTP_BOOT_PRIVATE_DATA)); + if (Private == NULL) { + return EFI_OUT_OF_RESOURCES; + } + Private->Signature = HTTP_BOOT_PRIVATE_DATA_SIGNATURE; + Private->Controller = ControllerHandle; + Private->Image = This->ImageHandle; + InitializeListHead (&Private->CacheList); + // + // Get the NII interface if it exists, it's not required. + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiNetworkInterfaceIdentifierProtocolGuid_31, + (VOID **) &Private->Nii, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + Private->Nii = NULL; + } + + // + // Open Device Path Protocol to prepare for appending IP and URI node. + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiDevicePathProtocolGuid, + (VOID **) &Private->ParentDevicePath, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + // + // Install a protocol with Caller Id Guid to the NIC, this is just to build the relationship between + // NIC handle and the private data. + // + Status = gBS->InstallProtocolInterface ( + &ControllerHandle, + &gEfiCallerIdGuid, + EFI_NATIVE_INTERFACE, + &Private->Id + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + } + + if (Private->Ip6Nic != NULL) { + // + // Already created before + // + return EFI_SUCCESS; + } + + Private->Ip6Nic = AllocateZeroPool (sizeof (HTTP_BOOT_VIRTUAL_NIC)); + if (Private->Ip6Nic == NULL) { + return EFI_OUT_OF_RESOURCES; + } + Private->Ip6Nic->Private = Private; + Private->Ip6Nic->Signature = HTTP_BOOT_VIRTUAL_NIC_SIGNATURE; + + // + // Create Dhcp6 child and open Dhcp6 protocol + Status = NetLibCreateServiceChild ( + ControllerHandle, + This->DriverBindingHandle, + &gEfiDhcp6ServiceBindingProtocolGuid, + &Private->Dhcp6Child + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + Status = gBS->OpenProtocol ( + Private->Dhcp6Child, + &gEfiDhcp6ProtocolGuid, + (VOID **) &Private->Dhcp6, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + // + // Create Ip6 child and open Ip6 protocol for background ICMP packets. + // + Status = NetLibCreateServiceChild ( + ControllerHandle, + This->DriverBindingHandle, + &gEfiIp6ServiceBindingProtocolGuid, + &Private->Ip6Child + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + Status = gBS->OpenProtocol ( + Private->Ip6Child, + &gEfiIp6ProtocolGuid, + (VOID **) &Private->Ip6, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + // + // Locate Ip6Config protocol, it's required to configure the default gateway address. + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiIp6ConfigProtocolGuid, + (VOID **) &Private->Ip6Config, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + // + // Append IPv6 device path node. + // + Node = AllocateZeroPool (sizeof (IPv6_DEVICE_PATH)); + if (Node == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; + } + Node->Ipv6.Header.Type = MESSAGING_DEVICE_PATH; + Node->Ipv6.Header.SubType = MSG_IPv6_DP; + Node->Ipv6.PrefixLength = IP6_PREFIX_LENGTH; + SetDevicePathNodeLength (Node, sizeof (IPv6_DEVICE_PATH)); + DevicePath = AppendDevicePathNode(Private->ParentDevicePath, (EFI_DEVICE_PATH*) Node); + FreePool(Node); + if (DevicePath == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; + } + + // + // Append URI device path node. + // + Node = AllocateZeroPool (sizeof (EFI_DEVICE_PATH_PROTOCOL)); + if (Node == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; + } + Node->DevPath.Type = MESSAGING_DEVICE_PATH; + Node->DevPath.SubType = MSG_URI_DP; + SetDevicePathNodeLength (Node, sizeof (EFI_DEVICE_PATH_PROTOCOL)); + Private->Ip6Nic->DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL*) Node); + FreePool (Node); + FreePool (DevicePath); + if (Private->Ip6Nic->DevicePath == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; + } + + // + // Create a child handle for the HTTP boot and install DevPath and Load file protocol on it. + // + CopyMem (&Private->Ip6Nic->LoadFile, &gHttpBootDxeLoadFile, sizeof (Private->LoadFile)); + Status = gBS->InstallMultipleProtocolInterfaces ( + &Private->Ip6Nic->Controller, + &gEfiLoadFileProtocolGuid, + &Private->Ip6Nic->LoadFile, + &gEfiDevicePathProtocolGuid, + Private->Ip6Nic->DevicePath, + NULL + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + // + // Open the Caller Id child to setup a parent-child relationship between + // real NIC handle and the HTTP boot child handle. + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiCallerIdGuid, + (VOID **) &Id, + This->DriverBindingHandle, + Private->Ip6Nic->Controller, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + return EFI_SUCCESS; + +ON_ERROR: + + HttpBootDestroyIp6Children(This, Private); + FreePool (Private); + + return Status; + +} + +/** + Stops a device controller or a bus controller. + + The Stop() function is designed to be invoked from the EFI boot service DisconnectController(). + As a result, much of the error checking on the parameters to Stop() has been moved + into this common boot service. It is legal to call Stop() from other locations, + but the following calling restrictions must be followed, or the system behavior will not be deterministic. + 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this + same driver's Start() function. + 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid + EFI_HANDLE. In addition, all of these handles must have been created in this driver's + Start() function, and the Start() function must have called OpenProtocol() on + ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle A handle to the device being stopped. The handle must + support a bus specific I/O protocol for the driver + to use to stop the device. + @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer. + @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL + if NumberOfChildren is 0. + + @retval EFI_SUCCESS The device was stopped. + @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error. + +**/ +EFI_STATUS +EFIAPI +HttpBootIp6DxeDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer OPTIONAL + ) +{ + EFI_STATUS Status; + EFI_LOAD_FILE_PROTOCOL *LoadFile; + HTTP_BOOT_PRIVATE_DATA *Private; + EFI_HANDLE NicHandle; + UINT32 *Id; + + // + // Try to get the Load File Protocol from the controller handle. + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiLoadFileProtocolGuid, + (VOID **) &LoadFile, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + // + // If failed, try to find the NIC handle for this controller. + // + NicHandle = HttpBootGetNicByIp6Children (ControllerHandle); + if (NicHandle == NULL) { + return EFI_SUCCESS; + } + + // + // Try to retrieve the private data by the Caller Id Guid. + // + Status = gBS->OpenProtocol ( + NicHandle, + &gEfiCallerIdGuid, + (VOID **) &Id, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + Private = HTTP_BOOT_PRIVATE_DATA_FROM_ID (Id); + } else { + Private = HTTP_BOOT_PRIVATE_DATA_FROM_LOADFILE (LoadFile); + NicHandle = Private->Controller; + } + + // + // Disable the HTTP boot function. + // + Status = HttpBootStop (Private); + if (Status != EFI_SUCCESS && Status != EFI_NOT_STARTED) { + return Status; + } + + // + // Destory all child instance and uninstall protocol interface. + // + HttpBootDestroyIp6Children (This, Private); + + if (Private->Ip4Nic == NULL && Private->Ip6Nic == NULL) { + // + // Release the cached data. + // + HttpBootFreeCacheList (Private); + + gBS->UninstallProtocolInterface ( + NicHandle, + &gEfiCallerIdGuid, + &Private->Id + ); + FreePool (Private); + + } + + return EFI_SUCCESS; +} +/** + This is the declaration of an EFI image entry point. This entry point is + the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including + both device drivers and bus drivers. + + @param[in] ImageHandle The firmware allocated handle for the UEFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The operation completed successfully. + @retval Others An unexpected error occurred. + +**/ +EFI_STATUS +EFIAPI +HttpBootDxeDriverEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + // + // Install UEFI Driver Model protocol(s). + // + Status = EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, + SystemTable, + &gHttpBootIp4DxeDriverBinding, + ImageHandle, + &gHttpBootDxeComponentName, + &gHttpBootDxeComponentName2 + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, + SystemTable, + &gHttpBootIp6DxeDriverBinding, + NULL, + &gHttpBootDxeComponentName, + &gHttpBootDxeComponentName2 + ); + if (EFI_ERROR (Status)) { + gBS->UninstallMultipleProtocolInterfaces( + ImageHandle, + &gEfiDriverBindingProtocolGuid, + &gHttpBootIp4DxeDriverBinding, + &gEfiComponentName2ProtocolGuid, + &gHttpBootDxeComponentName2, + &gEfiComponentNameProtocolGuid, + &gHttpBootDxeComponentName, + NULL + ); + } + return Status; } diff --git a/NetworkPkg/HttpBootDxe/HttpBootDxe.h b/NetworkPkg/HttpBootDxe/HttpBootDxe.h index 08415f6e0c3c..452c8f4906db 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootDxe.h +++ b/NetworkPkg/HttpBootDxe/HttpBootDxe.h @@ -41,9 +41,11 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. // #include #include +#include +#include #include #include - +#include // // Produced Protocols // @@ -65,29 +67,45 @@ extern EFI_COMPONENT_NAME_PROTOCOL gHttpBootDxeComponentName; // Private data structure // typedef struct _HTTP_BOOT_PRIVATE_DATA HTTP_BOOT_PRIVATE_DATA; +typedef struct _HTTP_BOOT_VIRTUAL_NIC HTTP_BOOT_VIRTUAL_NIC; // // Include files with internal function prototypes // #include "HttpBootComponentName.h" #include "HttpBootDhcp4.h" +#include "HttpBootDhcp6.h" #include "HttpBootImpl.h" #include "HttpBootSupport.h" #include "HttpBootClient.h" typedef union { HTTP_BOOT_DHCP4_PACKET_CACHE Dhcp4; + HTTP_BOOT_DHCP6_PACKET_CACHE Dhcp6; } HTTP_BOOT_DHCP_PACKET_CACHE; +struct _HTTP_BOOT_VIRTUAL_NIC { + UINT32 Signature; + EFI_HANDLE Controller; + EFI_LOAD_FILE_PROTOCOL LoadFile; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + HTTP_BOOT_PRIVATE_DATA *Private; +}; + struct _HTTP_BOOT_PRIVATE_DATA { UINT32 Signature; EFI_HANDLE Controller; EFI_HANDLE Image; + HTTP_BOOT_VIRTUAL_NIC *Ip4Nic; + HTTP_BOOT_VIRTUAL_NIC *Ip6Nic; + // // Cousumed children // + EFI_HANDLE Ip6Child; EFI_HANDLE Dhcp4Child; + EFI_HANDLE Dhcp6Child; HTTP_IO HttpIo; BOOLEAN HttpCreated; @@ -95,14 +113,13 @@ struct _HTTP_BOOT_PRIVATE_DATA { // Consumed protocol // EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *Nii; + EFI_IP6_PROTOCOL *Ip6; EFI_IP4_CONFIG2_PROTOCOL *Ip4Config2; + EFI_IP6_CONFIG_PROTOCOL *Ip6Config; EFI_DHCP4_PROTOCOL *Dhcp4; + EFI_DHCP6_PROTOCOL *Dhcp6; EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; - // - // Produced children - // - EFI_HANDLE ChildHandle; // // Produced protocol @@ -119,10 +136,12 @@ struct _HTTP_BOOT_PRIVATE_DATA { EFI_IP_ADDRESS StationIp; EFI_IP_ADDRESS SubnetMask; EFI_IP_ADDRESS GatewayIp; + EFI_IP_ADDRESS ServerIp; UINT16 Port; CHAR8 *BootFileUri; VOID *BootFileUriParser; UINTN BootFileSize; + BOOLEAN NoGateway; // // Cached HTTP data @@ -167,9 +186,10 @@ struct _HTTP_BOOT_PRIVATE_DATA { }; #define HTTP_BOOT_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('H', 'B', 'P', 'D') +#define HTTP_BOOT_VIRTUAL_NIC_SIGNATURE SIGNATURE_32 ('H', 'B', 'V', 'N') #define HTTP_BOOT_PRIVATE_DATA_FROM_LOADFILE(a) CR (a, HTTP_BOOT_PRIVATE_DATA, LoadFile, HTTP_BOOT_PRIVATE_DATA_SIGNATURE) #define HTTP_BOOT_PRIVATE_DATA_FROM_ID(a) CR (a, HTTP_BOOT_PRIVATE_DATA, Id, HTTP_BOOT_PRIVATE_DATA_SIGNATURE) - +#define HTTP_BOOT_VIRTUAL_NIC_FROM_LOADFILE(a) CR (a, HTTP_BOOT_VIRTUAL_NIC, LoadFile, HTTP_BOOT_VIRTUAL_NIC_SIGNATURE) extern EFI_LOAD_FILE_PROTOCOL gHttpBootDxeLoadFile; /** @@ -300,4 +320,131 @@ HttpBootIp4DxeDriverBindingStop ( IN EFI_HANDLE *ChildHandleBuffer OPTIONAL ); +/** + Tests to see if this driver supports a given controller. If a child device is provided, + it further tests to see if this driver supports creating a handle for the specified child device. + + This function checks to see if the driver specified by This supports the device specified by + ControllerHandle. Drivers will typically use the device path attached to + ControllerHandle and/or the services from the bus I/O abstraction attached to + ControllerHandle to determine if the driver supports ControllerHandle. This function + may be called many times during platform initialization. In order to reduce boot times, the tests + performed by this function must be very small, and take as little time as possible to execute. This + function must not change the state of any hardware devices, and this function must be aware that the + device specified by ControllerHandle may already be managed by the same driver or a + different driver. This function must match its calls to AllocatePages() with FreePages(), + AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol(). + Because ControllerHandle may have been previously started by the same driver, if a protocol is + already in the opened state, then it must not be closed with CloseProtocol(). This is required + to guarantee the state of ControllerHandle is not modified by this function. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle The handle of the controller to test. This handle + must support a protocol interface that supplies + an I/O abstraction to the driver. + @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This + parameter is ignored by device drivers, and is optional for bus + drivers. For bus drivers, if this parameter is not NULL, then + the bus driver must determine if the bus controller specified + by ControllerHandle and the child controller specified + by RemainingDevicePath are both supported by this + bus driver. + + @retval EFI_SUCCESS The device specified by ControllerHandle and + RemainingDevicePath is supported by the driver specified by This. + @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and + RemainingDevicePath is already being managed by the driver + specified by This. + @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and + RemainingDevicePath is already being managed by a different + driver or an application that requires exclusive access. + Currently not implemented. + @retval EFI_UNSUPPORTED The device specified by ControllerHandle and + RemainingDevicePath is not supported by the driver specified by This. +**/ +EFI_STATUS +EFIAPI +HttpBootIp6DxeDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ); + +/** + Starts a device controller or a bus controller. + + The Start() function is designed to be invoked from the EFI boot service ConnectController(). + As a result, much of the error checking on the parameters to Start() has been moved into this + common boot service. It is legal to call Start() from other locations, + but the following calling restrictions must be followed, or the system behavior will not be deterministic. + 1. ControllerHandle must be a valid EFI_HANDLE. + 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned + EFI_DEVICE_PATH_PROTOCOL. + 3. Prior to calling Start(), the Supported() function for the driver specified by This must + have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle The handle of the controller to start. This handle + must support a protocol interface that supplies + an I/O abstraction to the driver. + @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This + parameter is ignored by device drivers, and is optional for bus + drivers. For a bus driver, if this parameter is NULL, then handles + for all the children of Controller are created by this driver. + If this parameter is not NULL and the first Device Path Node is + not the End of Device Path Node, then only the handle for the + child device specified by the first Device Path Node of + RemainingDevicePath is created by this driver. + If the first Device Path Node of RemainingDevicePath is + the End of Device Path Node, no child handle is created by this + driver. + + @retval EFI_SUCCESS The device was started. + @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval Others The driver failded to start the device. + +**/ +EFI_STATUS +EFIAPI +HttpBootIp6DxeDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ); + +/** + Stops a device controller or a bus controller. + + The Stop() function is designed to be invoked from the EFI boot service DisconnectController(). + As a result, much of the error checking on the parameters to Stop() has been moved + into this common boot service. It is legal to call Stop() from other locations, + but the following calling restrictions must be followed, or the system behavior will not be deterministic. + 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this + same driver's Start() function. + 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid + EFI_HANDLE. In addition, all of these handles must have been created in this driver's + Start() function, and the Start() function must have called OpenProtocol() on + ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle A handle to the device being stopped. The handle must + support a bus specific I/O protocol for the driver + to use to stop the device. + @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer. + @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL + if NumberOfChildren is 0. + + @retval EFI_SUCCESS The device was stopped. + @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error. + +**/ +EFI_STATUS +EFIAPI +HttpBootIp6DxeDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer OPTIONAL + ); #endif diff --git a/NetworkPkg/HttpBootDxe/HttpBootDxe.inf b/NetworkPkg/HttpBootDxe/HttpBootDxe.inf index 18f8f796f0cb..e24b568ddc88 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootDxe.inf +++ b/NetworkPkg/HttpBootDxe/HttpBootDxe.inf @@ -35,6 +35,8 @@ HttpBootImpl.c HttpBootDhcp4.h HttpBootDhcp4.c + HttpBootDhcp6.h + HttpBootDhcp6.c HttpBootSupport.h HttpBootSupport.c HttpBootClient.h @@ -62,6 +64,13 @@ gEfiDhcp4ServiceBindingProtocolGuid ## TO_START gEfiDhcp4ProtocolGuid ## TO_START gEfiIp4Config2ProtocolGuid ## TO_START + gEfiDhcp6ServiceBindingProtocolGuid ## TO_START + gEfiDhcp6ProtocolGuid ## TO_START + gEfiDns6ServiceBindingProtocolGuid ## SOMETIMES_CONSUMES + gEfiDns6ProtocolGuid ## SOMETIMES_CONSUMES + gEfiIp6ServiceBindingProtocolGuid ## TO_START + gEfiIp6ProtocolGuid ## TO_START + gEfiIp6ConfigProtocolGuid ## TO_START gEfiNetworkInterfaceIdentifierProtocolGuid_31 ## SOMETIMES_CONSUMES [UserExtensions.TianoCore."ExtraFiles"] diff --git a/NetworkPkg/HttpBootDxe/HttpBootDxe.uni b/NetworkPkg/HttpBootDxe/HttpBootDxe.uni index 68a33794b27664cc8e6c615017d8eb3b8ce6fe20..fe743df852821e3069aa7411f3ca1f91d394da02 100644 GIT binary patch delta 44 ncmcb?|AT)+0V8idLlJ`lgC|1(Lm7kF=3K^5HdLX>``IM{2FMDe delta 16 Xcmeyte}jKR0psQd#vr!IkJ!ZkJCFu0 diff --git a/NetworkPkg/HttpBootDxe/HttpBootImpl.c b/NetworkPkg/HttpBootDxe/HttpBootImpl.c index eee63c21d3a9..9ea0d7f95f93 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootImpl.c +++ b/NetworkPkg/HttpBootDxe/HttpBootImpl.c @@ -18,6 +18,9 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. Enable the use of UEFI HTTP boot function. @param[in] Private The pointer to the driver's private data. + @param[in] UsingIpv6 Specifies the type of IP addresses that are to be + used during the session that is being started. + Set to TRUE for IPv6, and FALSE for IPv4. @retval EFI_SUCCESS HTTP boot was successfully enabled. @retval EFI_INVALID_PARAMETER Private is NULL. @@ -26,10 +29,12 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ EFI_STATUS HttpBootStart ( - IN HTTP_BOOT_PRIVATE_DATA *Private + IN HTTP_BOOT_PRIVATE_DATA *Private, + IN BOOLEAN UsingIpv6 ) { - UINTN Index; + UINTN Index; + EFI_STATUS Status; if (Private == NULL) { return EFI_INVALID_PARAMETER; @@ -39,25 +44,47 @@ HttpBootStart ( return EFI_ALREADY_STARTED; } + // + // Detect whether using ipv6 or not, and set it to the private data. + // + if (UsingIpv6 && Private->Ip6Nic != NULL) { + Private->UsingIpv6 = TRUE; + } else if (!UsingIpv6 && Private->Ip4Nic != NULL) { + Private->UsingIpv6 = FALSE; + } else { + return EFI_UNSUPPORTED; + } + + // + // Init the content of cached DHCP offer list. + // + ZeroMem (Private->OfferBuffer, sizeof (Private->OfferBuffer)); if (!Private->UsingIpv6) { - // - // Init the content of cached DHCP offer list. - // - ZeroMem (Private->OfferBuffer, sizeof (Private->OfferBuffer)); for (Index = 0; Index < HTTP_BOOT_OFFER_MAX_NUM; Index++) { Private->OfferBuffer[Index].Dhcp4.Packet.Offer.Size = HTTP_BOOT_DHCP4_PACKET_MAX_SIZE; } } else { - ASSERT (FALSE); + for (Index = 0; Index < HTTP_BOOT_OFFER_MAX_NUM; Index++) { + Private->OfferBuffer[Index].Dhcp6.Packet.Offer.Size = HTTP_BOOT_DHCP6_PACKET_MAX_SIZE; + } } + if (Private->UsingIpv6) { + // + // Set Ip6 policy to Automatic to start the Ip6 router discovery. + // + Status = HttpBootSetIp6Policy (Private); + if (EFI_ERROR (Status)) { + return Status; + } + } Private->Started = TRUE; return EFI_SUCCESS; } /** - Attempt to complete a DHCPv4 D.O.R.A sequence to retrieve the boot resource information. + Attempt to complete a DHCPv4 D.O.R.A or DHCPv6 S.R.A.A sequence to retrieve the boot resource information. @param[in] Private The pointer to the driver's private data. @@ -86,9 +113,15 @@ HttpBootDhcp ( Status = EFI_DEVICE_ERROR; if (!Private->UsingIpv6) { + // + // Start D.O.R.A process to get a IPv4 address and other boot information. + // Status = HttpBootDhcp4Dora (Private); } else { - ASSERT (FALSE); + // + // Start S.A.R.R process to get a IPv6 address and other boot information. + // + Status = HttpBootDhcp6Sarr (Private); } return Status; @@ -241,7 +274,7 @@ HttpBootStop ( Private->BootFileUriParser = NULL; Private->BootFileSize = 0; Private->SelectIndex = 0; - Private->SelectProxyType = HttpOfferTypeMax; + Private->SelectProxyType = HttpOfferTypeMax; if (!Private->UsingIpv6) { // @@ -256,7 +289,17 @@ HttpBootStop ( } } } else { - ASSERT (FALSE); + // + // Stop and release the DHCP6 child. + // + Private->Dhcp6->Stop (Private->Dhcp6); + Private->Dhcp6->Configure (Private->Dhcp6, NULL); + + for (Index = 0; Index < HTTP_BOOT_OFFER_MAX_NUM; Index++) { + if (Private->OfferBuffer[Index].Dhcp6.UriParser) { + HttpUrlFreeParser (Private->OfferBuffer[Index].Dhcp6.UriParser); + } + } } ZeroMem (Private->OfferBuffer, sizeof (Private->OfferBuffer)); @@ -309,7 +352,9 @@ HttpBootDxeLoadFile ( ) { HTTP_BOOT_PRIVATE_DATA *Private; + HTTP_BOOT_VIRTUAL_NIC *VirtualNic; BOOLEAN MediaPresent; + BOOLEAN UsingIpv6; EFI_STATUS Status; if (This == NULL || BufferSize == NULL) { @@ -323,8 +368,10 @@ HttpBootDxeLoadFile ( return EFI_UNSUPPORTED; } - Private = HTTP_BOOT_PRIVATE_DATA_FROM_LOADFILE (This); - + VirtualNic = HTTP_BOOT_VIRTUAL_NIC_FROM_LOADFILE (This); + Private = VirtualNic->Private; + UsingIpv6 = FALSE; + // // Check media status before HTTP boot start // @@ -334,10 +381,26 @@ HttpBootDxeLoadFile ( return EFI_NO_MEDIA; } + // + // Check whether the virtual nic is using IPv6 or not. + // + if (VirtualNic == Private->Ip6Nic) { + UsingIpv6 = TRUE; + } + // // Initialize HTTP boot and load the boot file. // - Status = HttpBootStart (Private); + Status = HttpBootStart (Private, UsingIpv6); + if (Status == EFI_ALREADY_STARTED && UsingIpv6 != Private->UsingIpv6) { + // + // Http boot Driver has already been started but not on the required IP version, restart it. + // + Status = HttpBootStop (Private); + if (!EFI_ERROR (Status)) { + Status = HttpBootStart (Private, UsingIpv6); + } + } if (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED) { Status = HttpBootLoadFile (Private, BufferSize, Buffer); } @@ -345,11 +408,19 @@ HttpBootDxeLoadFile ( if (Status != EFI_SUCCESS && Status != EFI_BUFFER_TOO_SMALL) { HttpBootStop (Private); } else { - // - // Stop and release the DHCP4 child. - // - Private->Dhcp4->Stop (Private->Dhcp4); - Private->Dhcp4->Configure (Private->Dhcp4, NULL); + if (!Private->UsingIpv6) { + // + // Stop and release the DHCP4 child. + // + Private->Dhcp4->Stop (Private->Dhcp4); + Private->Dhcp4->Configure (Private->Dhcp4, NULL); + } else { + // + // Stop and release the DHCP6 child. + // + Private->Dhcp6->Stop (Private->Dhcp6); + Private->Dhcp6->Configure (Private->Dhcp6, NULL); + } } return Status; diff --git a/NetworkPkg/HttpBootDxe/HttpBootImpl.h b/NetworkPkg/HttpBootDxe/HttpBootImpl.h index a2e9f5a3281c..70663381752c 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootImpl.h +++ b/NetworkPkg/HttpBootDxe/HttpBootImpl.h @@ -15,7 +15,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #define __EFI_HTTP_BOOT_IMPL_H__ /** - Attempt to complete a DHCPv4 D.O.R.A sequence to retrieve the boot resource information. + Attempt to complete a DHCPv4 D.O.R.A or DHCPv6 S.R.A.A sequence to retrieve the boot resource information. @param[in] Private The pointer to the driver's private data. diff --git a/NetworkPkg/HttpBootDxe/HttpBootSupport.c b/NetworkPkg/HttpBootDxe/HttpBootSupport.c index 761643141f91..d08111f66107 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootSupport.c +++ b/NetworkPkg/HttpBootDxe/HttpBootSupport.c @@ -42,6 +42,31 @@ HttpBootGetNicByIp4Children ( return NicHandle; } +/** + Get the Nic handle using any child handle in the IPv6 stack. + + @param[in] ControllerHandle Pointer to child handle over IPv6. + + @return NicHandle The pointer to the Nic handle. + @return NULL Can't find the Nic handle. + +**/ +EFI_HANDLE +HttpBootGetNicByIp6Children ( + IN EFI_HANDLE ControllerHandle + ) +{ + EFI_HANDLE NicHandle; + NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiHttpProtocolGuid); + if (NicHandle == NULL) { + NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiDhcp6ProtocolGuid); + if (NicHandle == NULL) { + return NULL; + } + } + + return NicHandle; +} /** This function is to convert UINTN to ASCII string with the required formatting. @@ -89,6 +114,242 @@ HttpBootShowIp4Addr ( } } +/** + This function is to display the IPv6 address. + + @param[in] Ip The pointer to the IPv6 address. + +**/ +VOID +HttpBootShowIp6Addr ( + IN EFI_IPv6_ADDRESS *Ip + ) +{ + UINTN Index; + + for (Index = 0; Index < 16; Index++) { + + if (Ip->Addr[Index] != 0) { + AsciiPrint ("%x", Ip->Addr[Index]); + } + Index++; + if (Index > 15) { + return; + } + if (((Ip->Addr[Index] & 0xf0) == 0) && (Ip->Addr[Index - 1] != 0)) { + AsciiPrint ("0"); + } + AsciiPrint ("%x", Ip->Addr[Index]); + if (Index < 15) { + AsciiPrint (":"); + } + } +} + +/** + Notify the callback function when an event is triggered. + + @param[in] Event The triggered event. + @param[in] Context The opaque parameter to the function. + +**/ +VOID +EFIAPI +HttpBootCommonNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + *((BOOLEAN *) Context) = TRUE; +} + +/** + Retrieve the host address using the EFI_DNS6_PROTOCOL. + + @param[in] Private The pointer to the driver's private data. + @param[in] HostName Pointer to buffer containing hostname. + @param[out] IpAddress On output, pointer to buffer containing IPv6 address. + + @retval EFI_SUCCESS Operation succeeded. + @retval EFI_DEVICE_ERROR An unexpected network error occurred. + @retval Others Other errors as indicated. +**/ +EFI_STATUS +HttpBootDns ( + IN HTTP_BOOT_PRIVATE_DATA *Private, + IN CHAR16 *HostName, + OUT EFI_IPv6_ADDRESS *IpAddress + ) +{ + EFI_STATUS Status; + EFI_DNS6_PROTOCOL *Dns6; + EFI_DNS6_CONFIG_DATA Dns6ConfigData; + EFI_DNS6_COMPLETION_TOKEN Token; + EFI_HANDLE Dns6Handle; + EFI_IP6_CONFIG_PROTOCOL *Ip6Config; + EFI_IPv6_ADDRESS *DnsServerList; + UINTN DnsServerListCount; + UINTN DataSize; + BOOLEAN IsDone; + + DnsServerList = NULL; + DnsServerListCount = 0; + Dns6 = NULL; + Dns6Handle = NULL; + ZeroMem (&Token, sizeof (EFI_DNS6_COMPLETION_TOKEN)); + + // + // Get DNS server list from EFI IPv6 Configuration protocol. + // + Status = gBS->HandleProtocol (Private->Controller, &gEfiIp6ConfigProtocolGuid, (VOID **) &Ip6Config); + if (!EFI_ERROR (Status)) { + // + // Get the required size. + // + DataSize = 0; + Status = Ip6Config->GetData (Ip6Config, Ip6ConfigDataTypeDnsServer, &DataSize, NULL); + if (Status == EFI_BUFFER_TOO_SMALL) { + DnsServerList = AllocatePool (DataSize); + if (DnsServerList == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status = Ip6Config->GetData (Ip6Config, Ip6ConfigDataTypeDnsServer, &DataSize, DnsServerList); + if (EFI_ERROR (Status)) { + FreePool (DnsServerList); + DnsServerList = NULL; + } else { + DnsServerListCount = DataSize / sizeof (EFI_IPv6_ADDRESS); + } + } + } + // + // Create a DNSv6 child instance and get the protocol. + // + Status = NetLibCreateServiceChild ( + Private->Controller, + Private->Image, + &gEfiDns6ServiceBindingProtocolGuid, + &Dns6Handle + ); + if (EFI_ERROR (Status)) { + goto Exit; + } + + Status = gBS->OpenProtocol ( + Dns6Handle, + &gEfiDns6ProtocolGuid, + (VOID **) &Dns6, + Private->Image, + Private->Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + goto Exit; + } + + // + // Configure DNS6 instance for the DNS server address and protocol. + // + ZeroMem (&Dns6ConfigData, sizeof (EFI_DNS6_CONFIG_DATA)); + Dns6ConfigData.DnsServerCount = (UINT32)DnsServerListCount; + Dns6ConfigData.DnsServerList = DnsServerList; + Dns6ConfigData.EnableDnsCache = TRUE; + Dns6ConfigData.Protocol = EFI_IP_PROTO_UDP; + IP6_COPY_ADDRESS (&Dns6ConfigData.StationIp,&Private->StationIp.v6); + Status = Dns6->Configure ( + Dns6, + &Dns6ConfigData + ); + if (EFI_ERROR (Status)) { + goto Exit; + } + + Token.Status = EFI_NOT_READY; + IsDone = FALSE; + // + // Create event to set the IsDone flag when name resolution is finished. + // + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + HttpBootCommonNotify, + &IsDone, + &Token.Event + ); + if (EFI_ERROR (Status)) { + goto Exit; + } + + // + // Start asynchronous name resolution. + // + Status = Dns6->HostNameToIp (Dns6, HostName, &Token); + if (EFI_ERROR (Status)) { + goto Exit; + } + + while (!IsDone) { + Dns6->Poll (Dns6); + } + + // + // Name resolution is done, check result. + // + Status = Token.Status; + if (!EFI_ERROR (Status)) { + if (Token.RspData.H2AData == NULL) { + Status = EFI_DEVICE_ERROR; + goto Exit; + } + if (Token.RspData.H2AData->IpCount == 0 || Token.RspData.H2AData->IpList == NULL) { + Status = EFI_DEVICE_ERROR; + goto Exit; + } + // + // We just return the first IPv6 address from DNS protocol. + // + IP6_COPY_ADDRESS (IpAddress, Token.RspData.H2AData->IpList); + Status = EFI_SUCCESS; + } +Exit: + + if (Token.Event != NULL) { + gBS->CloseEvent (Token.Event); + } + if (Token.RspData.H2AData != NULL) { + if (Token.RspData.H2AData->IpList != NULL) { + FreePool (Token.RspData.H2AData->IpList); + } + FreePool (Token.RspData.H2AData); + } + + if (Dns6 != NULL) { + Dns6->Configure (Dns6, NULL); + + gBS->CloseProtocol ( + Dns6Handle, + &gEfiDns6ProtocolGuid, + Private->Image, + Private->Controller + ); + } + + if (Dns6Handle != NULL) { + NetLibDestroyServiceChild ( + Private->Controller, + Private->Image, + &gEfiDns6ServiceBindingProtocolGuid, + Dns6Handle + ); + } + + if (DnsServerList != NULL) { + FreePool (DnsServerList); + } + + return Status; +} /** Create a HTTP_IO_HEADER to hold the HTTP header items. @@ -100,7 +361,7 @@ HttpBootShowIp4Addr ( HTTP_IO_HEADER * HttpBootCreateHeader ( UINTN MaxHeaderCount -) + ) { HTTP_IO_HEADER *HttpIoHeader; @@ -254,23 +515,6 @@ HttpBootSetHeader ( return EFI_SUCCESS; } -/** - Notify the callback function when an event is triggered. - - @param[in] Event The triggered event. - @param[in] Context The opaque parameter to the function. - -**/ -VOID -EFIAPI -HttpIoCommonNotify ( - IN EFI_EVENT Event, - IN VOID *Context - ) -{ - *((BOOLEAN *) Context) = TRUE; -} - /** Create a HTTP_IO to access the HTTP service. It will create and configure a HTTP child handle. @@ -301,6 +545,7 @@ HttpIoCreateIo ( EFI_STATUS Status; EFI_HTTP_CONFIG_DATA HttpConfigData; EFI_HTTPv4_ACCESS_POINT Http4AccessPoint; + EFI_HTTPv6_ACCESS_POINT Http6AccessPoint; EFI_HTTP_PROTOCOL *Http; EFI_EVENT Event; @@ -359,7 +604,10 @@ HttpIoCreateIo ( IP4_COPY_ADDRESS (&Http4AccessPoint.LocalSubnet, &ConfigData->Config4.SubnetMask); HttpConfigData.AccessPoint.IPv4Node = &Http4AccessPoint; } else { - ASSERT (FALSE); + HttpConfigData.LocalAddressIsIPv6 = TRUE; + Http6AccessPoint.LocalPort = ConfigData->Config6.LocalPort; + IP6_COPY_ADDRESS (&Http6AccessPoint.LocalAddress, &ConfigData->Config6.LocalIp); + HttpConfigData.AccessPoint.IPv6Node = &Http6AccessPoint; } Status = Http->Configure (Http, &HttpConfigData); @@ -373,7 +621,7 @@ HttpIoCreateIo ( Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL, TPL_NOTIFY, - HttpIoCommonNotify, + HttpBootCommonNotify, &HttpIo->IsTxDone, &Event ); @@ -386,7 +634,7 @@ HttpIoCreateIo ( Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL, TPL_NOTIFY, - HttpIoCommonNotify, + HttpBootCommonNotify, &HttpIo->IsRxDone, &Event ); @@ -579,7 +827,7 @@ HttpIoRecvResponse ( // // Store the received data into the wrapper. // - Status = HttpIo->ReqToken.Status; + Status = HttpIo->RspToken.Status; if (!EFI_ERROR (Status)) { ResponseData->HeaderCount = HttpIo->RspToken.Message->HeaderCount; ResponseData->Headers = HttpIo->RspToken.Message->Headers; diff --git a/NetworkPkg/HttpBootDxe/HttpBootSupport.h b/NetworkPkg/HttpBootDxe/HttpBootSupport.h index bef80e81d874..d5956720a7cf 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootSupport.h +++ b/NetworkPkg/HttpBootDxe/HttpBootSupport.h @@ -29,6 +29,20 @@ HttpBootGetNicByIp4Children ( IN EFI_HANDLE ControllerHandle ); +/** + Get the Nic handle using any child handle in the IPv6 stack. + + @param[in] ControllerHandle Pointer to child handle over IPv6. + + @return NicHandle The pointer to the Nic handle. + @return NULL Can't find the Nic handle. + +**/ +EFI_HANDLE +HttpBootGetNicByIp6Children ( + IN EFI_HANDLE ControllerHandle + ); + /** This function is to convert UINTN to ASCII string with the required formatting. @@ -56,6 +70,17 @@ HttpBootShowIp4Addr ( IN EFI_IPv4_ADDRESS *Ip ); +/** + This function is to display the IPv6 address. + + @param[in] Ip The pointer to the IPv6 address. + +**/ +VOID +HttpBootShowIp6Addr ( + IN EFI_IPv6_ADDRESS *Ip + ); + // // A wrapper structure to hold the HTTP headers. // @@ -122,11 +147,24 @@ typedef struct { UINT16 LocalPort; } HTTP4_IO_CONFIG_DATA; +// +// HTTP_IO configuration data for IPv6 +// +typedef struct { + EFI_HTTP_VERSION HttpVersion; + UINT32 RequestTimeOut; // In milliseconds. + BOOLEAN UseDefaultAddress; + EFI_IPv6_ADDRESS LocalIp; + UINT16 LocalPort; +} HTTP6_IO_CONFIG_DATA; + + // // HTTP_IO configuration // typedef union { HTTP4_IO_CONFIG_DATA Config4; + HTTP6_IO_CONFIG_DATA Config6; } HTTP_IO_CONFIG_DATA; // @@ -160,6 +198,38 @@ typedef struct { CHAR8 *Body; } HTTP_IO_RESOPNSE_DATA; +/** + Retrieve the host address using the EFI_DNS6_PROTOCOL. + + @param[in] Private The pointer to the driver's private data. + @param[in] HostName Pointer to buffer containing hostname. + @param[out] IpAddress On output, pointer to buffer containing IPv6 address. + + @retval EFI_SUCCESS Operation succeeded. + @retval EFI_DEVICE_ERROR An unexpected network error occurred. + @retval Others Other errors as indicated. +**/ +EFI_STATUS +HttpBootDns ( + IN HTTP_BOOT_PRIVATE_DATA *Private, + IN CHAR16 *HostName, + OUT EFI_IPv6_ADDRESS *IpAddress + ); + +/** + Notify the callback function when an event is triggered. + + @param[in] Event The triggered event. + @param[in] Context The opaque parameter to the function. + +**/ +VOID +EFIAPI +HttpBootCommonNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ); + /** Create a HTTP_IO to access the HTTP service. It will create and configure a HTTP child handle. diff --git a/NetworkPkg/HttpDxe/HttpDns.c b/NetworkPkg/HttpDxe/HttpDns.c index daebc173b5e9..0f5fe1807270 100644 --- a/NetworkPkg/HttpDxe/HttpDns.c +++ b/NetworkPkg/HttpDxe/HttpDns.c @@ -194,11 +194,11 @@ HttpDns4 ( Dns4->Configure (Dns4, NULL); gBS->CloseProtocol ( - Dns4Handle, - &gEfiDns4ProtocolGuid, - Service->ImageHandle, - Service->ControllerHandle - ); + Dns4Handle, + &gEfiDns4ProtocolGuid, + Service->ImageHandle, + Service->ControllerHandle + ); } if (Dns4Handle != NULL) { @@ -216,3 +216,200 @@ HttpDns4 ( return Status; } + +/** + Retrieve the host address using the EFI_DNS6_PROTOCOL. + + @param[in] HttpInstance Pointer to HTTP_PROTOCOL instance. + @param[in] HostName Pointer to buffer containing hostname. + @param[out] IpAddress On output, pointer to buffer containing IPv6 address. + + @retval EFI_SUCCESS Operation succeeded. + @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources. + @retval EFI_DEVICE_ERROR An unexpected network error occurred. + @retval Others Other errors as indicated. + +**/ +EFI_STATUS +HttpDns6 ( + IN HTTP_PROTOCOL *HttpInstance, + IN CHAR16 *HostName, + OUT EFI_IPv6_ADDRESS *IpAddress + ) +{ + EFI_STATUS Status; + HTTP_SERVICE *Service; + EFI_DNS6_PROTOCOL *Dns6; + EFI_DNS6_CONFIG_DATA Dns6ConfigData; + EFI_DNS6_COMPLETION_TOKEN Token; + EFI_HANDLE Dns6Handle; + EFI_IP6_CONFIG_PROTOCOL *Ip6Config; + EFI_IPv6_ADDRESS *DnsServerList; + UINTN DnsServerListCount; + UINTN DataSize; + BOOLEAN IsDone; + + + Service = HttpInstance->Service; + ASSERT (Service != NULL); + + DnsServerList = NULL; + DnsServerListCount = 0; + Dns6 = NULL; + Dns6Handle = NULL; + ZeroMem (&Token, sizeof (EFI_DNS6_COMPLETION_TOKEN)); + + // + // Get DNS server list from EFI IPv6 Configuration protocol. + // + Status = gBS->HandleProtocol (Service->ControllerHandle, &gEfiIp6ConfigProtocolGuid, (VOID **) &Ip6Config); + if (!EFI_ERROR (Status)) { + // + // Get the required size. + // + DataSize = 0; + Status = Ip6Config->GetData (Ip6Config, Ip6ConfigDataTypeDnsServer, &DataSize, NULL); + if (Status == EFI_BUFFER_TOO_SMALL) { + DnsServerList = AllocatePool (DataSize); + if (DnsServerList == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status = Ip6Config->GetData (Ip6Config, Ip6ConfigDataTypeDnsServer, &DataSize, DnsServerList); + if (EFI_ERROR (Status)) { + FreePool (DnsServerList); + DnsServerList = NULL; + } else { + DnsServerListCount = DataSize / sizeof (EFI_IPv6_ADDRESS); + } + } + } + + // + // Create a DNSv6 child instance and get the protocol. + // + Status = NetLibCreateServiceChild ( + Service->ControllerHandle, + Service->ImageHandle, + &gEfiDns6ServiceBindingProtocolGuid, + &Dns6Handle + ); + if (EFI_ERROR (Status)) { + goto Exit; + } + + Status = gBS->OpenProtocol ( + Dns6Handle, + &gEfiDns6ProtocolGuid, + (VOID **) &Dns6, + Service->ImageHandle, + Service->ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + goto Exit; + } + + // + // Configure DNS6 instance for the DNS server address and protocol. + // + ZeroMem (&Dns6ConfigData, sizeof (EFI_DNS6_CONFIG_DATA)); + Dns6ConfigData.DnsServerCount = (UINT32)DnsServerListCount; + Dns6ConfigData.DnsServerList = DnsServerList; + Dns6ConfigData.EnableDnsCache = TRUE; + Dns6ConfigData.Protocol = EFI_IP_PROTO_UDP; + IP6_COPY_ADDRESS (&Dns6ConfigData.StationIp, &HttpInstance->Ipv6Node.LocalAddress); + Status = Dns6->Configure ( + Dns6, + &Dns6ConfigData + ); + if (EFI_ERROR (Status)) { + goto Exit; + } + + Token.Status = EFI_NOT_READY; + IsDone = FALSE; + // + // Create event to set the IsDone flag when name resolution is finished. + // + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + HttpCommonNotify, + &IsDone, + &Token.Event + ); + if (EFI_ERROR (Status)) { + goto Exit; + } + + // + // Start asynchronous name resolution. + // + Status = Dns6->HostNameToIp (Dns6, HostName, &Token); + if (EFI_ERROR (Status)) { + goto Exit; + } + + while (!IsDone) { + Dns6->Poll (Dns6); + } + + // + // Name resolution is done, check result. + // + Status = Token.Status; + if (!EFI_ERROR (Status)) { + if (Token.RspData.H2AData == NULL) { + Status = EFI_DEVICE_ERROR; + goto Exit; + } + if (Token.RspData.H2AData->IpCount == 0 || Token.RspData.H2AData->IpList == NULL) { + Status = EFI_DEVICE_ERROR; + goto Exit; + } + // + // We just return the first IPv6 address from DNS protocol. + // + IP6_COPY_ADDRESS (IpAddress, Token.RspData.H2AData->IpList); + Status = EFI_SUCCESS; + } + +Exit: + + if (Token.Event != NULL) { + gBS->CloseEvent (Token.Event); + } + if (Token.RspData.H2AData != NULL) { + if (Token.RspData.H2AData->IpList != NULL) { + FreePool (Token.RspData.H2AData->IpList); + } + FreePool (Token.RspData.H2AData); + } + + if (Dns6 != NULL) { + Dns6->Configure (Dns6, NULL); + + gBS->CloseProtocol ( + Dns6Handle, + &gEfiDns6ProtocolGuid, + Service->ImageHandle, + Service->ControllerHandle + ); + } + + if (Dns6Handle != NULL) { + NetLibDestroyServiceChild ( + Service->ControllerHandle, + Service->ImageHandle, + &gEfiDns6ServiceBindingProtocolGuid, + Dns6Handle + ); + } + + if (DnsServerList != NULL) { + FreePool (DnsServerList); + } + + return Status; +} diff --git a/NetworkPkg/HttpDxe/HttpDns.h b/NetworkPkg/HttpDxe/HttpDns.h index 0fb418635ca5..fa0c8f4a99f3 100644 --- a/NetworkPkg/HttpDxe/HttpDns.h +++ b/NetworkPkg/HttpDxe/HttpDns.h @@ -35,4 +35,24 @@ HttpDns4 ( OUT EFI_IPv4_ADDRESS *IpAddress ); +/** + Retrieve the host address using the EFI_DNS6_PROTOCOL. + + @param[in] HttpInstance Pointer to HTTP_PROTOCOL instance. + @param[in] HostName Pointer to buffer containing hostname. + @param[out] IpAddress On output, pointer to buffer containing IPv6 address. + + @retval EFI_SUCCESS Operation succeeded. + @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources. + @retval EFI_DEVICE_ERROR An unexpected network error occurred. + @retval Others Other errors as indicated. + +**/ +EFI_STATUS +HttpDns6 ( + IN HTTP_PROTOCOL *HttpInstance, + IN CHAR16 *HostName, + OUT EFI_IPv6_ADDRESS *IpAddress + ); + #endif \ No newline at end of file diff --git a/NetworkPkg/HttpDxe/HttpDriver.c b/NetworkPkg/HttpDxe/HttpDriver.c index bd1d04e78cc4..2518f4e707b6 100644 --- a/NetworkPkg/HttpDxe/HttpDriver.c +++ b/NetworkPkg/HttpDxe/HttpDriver.c @@ -20,15 +20,25 @@ EFI_HTTP_UTILITIES_PROTOCOL *mHttpUtilities = NULL; /// /// Driver Binding Protocol instance /// -EFI_DRIVER_BINDING_PROTOCOL gHttpDxeDriverBinding = { - HttpDxeDriverBindingSupported, - HttpDxeDriverBindingStart, - HttpDxeDriverBindingStop, +EFI_DRIVER_BINDING_PROTOCOL gHttpDxeIp4DriverBinding = { + HttpDxeIp4DriverBindingSupported, + HttpDxeIp4DriverBindingStart, + HttpDxeIp4DriverBindingStop, HTTP_DRIVER_VERSION, NULL, NULL }; +EFI_DRIVER_BINDING_PROTOCOL gHttpDxeIp6DriverBinding = { + HttpDxeIp6DriverBindingSupported, + HttpDxeIp6DriverBindingStart, + HttpDxeIp6DriverBindingStop, + HTTP_DRIVER_VERSION, + NULL, + NULL +}; + + /** Create a HTTP driver service binding private instance. @@ -73,33 +83,59 @@ HttpCreateService ( /** Release all the resource used the HTTP service binding instance. - @param HttpService The HTTP private instance. - + @param[in] HttpService The HTTP private instance. + @param[in] UsingIpv6 Indicate use TCP4 protocol or TCP6 protocol. + if TRUE, use Tcp6 protocol. + if FALSE, use Tcp4 protocl. **/ VOID HttpCleanService ( - IN HTTP_SERVICE *HttpService + IN HTTP_SERVICE *HttpService, + IN BOOLEAN UsingIpv6 ) -{ +{ + if (HttpService == NULL) { return ; } - - if (HttpService->TcpChildHandle != NULL) { - gBS->CloseProtocol ( - HttpService->TcpChildHandle, - &gEfiTcp4ProtocolGuid, - HttpService->ImageHandle, - HttpService->ControllerHandle - ); - - NetLibDestroyServiceChild ( - HttpService->ControllerHandle, - HttpService->ImageHandle, - &gEfiTcp4ServiceBindingProtocolGuid, - HttpService->TcpChildHandle - ); + if (!UsingIpv6) { + if (HttpService->Tcp4ChildHandle != NULL) { + gBS->CloseProtocol ( + HttpService->Tcp4ChildHandle, + &gEfiTcp4ProtocolGuid, + HttpService->ImageHandle, + HttpService->ControllerHandle + ); + + NetLibDestroyServiceChild ( + HttpService->ControllerHandle, + HttpService->ImageHandle, + &gEfiTcp4ServiceBindingProtocolGuid, + HttpService->Tcp4ChildHandle + ); + + HttpService->Tcp4ChildHandle = NULL; + } + } else { + if (HttpService->Tcp6ChildHandle != NULL) { + gBS->CloseProtocol ( + HttpService->Tcp6ChildHandle, + &gEfiTcp6ProtocolGuid, + HttpService->ImageHandle, + HttpService->ControllerHandle + ); + + NetLibDestroyServiceChild ( + HttpService->ControllerHandle, + HttpService->ImageHandle, + &gEfiTcp6ServiceBindingProtocolGuid, + HttpService->Tcp6ChildHandle + ); + + HttpService->Tcp6ChildHandle = NULL; + } } + } /** @@ -107,7 +143,7 @@ HttpCleanService ( in the system. @param[in] Event Not used. - @param[in] Context The pointer to the IP4 config2 instance data. + @param[in] Context The pointer to the IP4 config2 instance data or IP6 Config instance data. **/ VOID @@ -122,7 +158,7 @@ HttpUtilitiesInstalledCallback ( NULL, (VOID **) &mHttpUtilities ); - + // // Close the event if Http utilities protocol is loacted. // @@ -150,6 +186,7 @@ HttpDxeDriverEntryPoint ( IN EFI_SYSTEM_TABLE *SystemTable ) { + EFI_STATUS Status; VOID *Registration; gBS->LocateProtocol ( @@ -174,14 +211,39 @@ HttpDxeDriverEntryPoint ( // // Install UEFI Driver Model protocol(s). // - return EfiLibInstallDriverBindingComponentName2 ( - ImageHandle, - SystemTable, - &gHttpDxeDriverBinding, + Status = EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, + SystemTable, + &gHttpDxeIp4DriverBinding, + ImageHandle, + &gHttpDxeComponentName, + &gHttpDxeComponentName2 + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, + SystemTable, + &gHttpDxeIp6DriverBinding, + NULL, + &gHttpDxeComponentName, + &gHttpDxeComponentName2 + ); + if (EFI_ERROR (Status)) { + gBS->UninstallMultipleProtocolInterfaces ( ImageHandle, + &gEfiDriverBindingProtocolGuid, + &gHttpDxeIp4DriverBinding, + &gEfiComponentName2ProtocolGuid, + &gHttpDxeComponentName2, + &gEfiComponentNameProtocolGuid, &gHttpDxeComponentName, - &gHttpDxeComponentName2 + NULL ); + } + return Status; } /** @@ -223,6 +285,309 @@ HttpDestroyChildEntryInHandleBuffer ( return ServiceBinding->DestroyChild (ServiceBinding, HttpInstance->Handle); } +/** + Test to see if this driver supports ControllerHandle. This is the worker function for + HttpDxeIp4(6)DriverBindingSupported. + + @param[in] This The pointer to the driver binding protocol. + @param[in] ControllerHandle The handle of device to be tested. + @param[in] RemainingDevicePath Optional parameter used to pick a specific child + device to be started. + @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6. + + @retval EFI_SUCCESS This driver supports this device. + @retval EFI_UNSUPPORTED This driver does not support this device. + +**/ +EFI_STATUS +EFIAPI +HttpDxeSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL, + IN UINT8 IpVersion + ) +{ + EFI_STATUS Status; + EFI_GUID *TcpServiceBindingProtocolGuid; + + if (IpVersion == IP_VERSION_4) { + TcpServiceBindingProtocolGuid = &gEfiTcp4ServiceBindingProtocolGuid; + } else { + TcpServiceBindingProtocolGuid = &gEfiTcp6ServiceBindingProtocolGuid; + } + + Status = gBS->OpenProtocol ( + ControllerHandle, + TcpServiceBindingProtocolGuid, + NULL, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} + +/** + Start this driver on ControllerHandle. This is the worker function for + HttpDxeIp4(6)DriverBindingStart. + + @param[in] This The pointer to the driver binding protocol. + @param[in] ControllerHandle The handle of device to be started. + @param[in] RemainingDevicePath Optional parameter used to pick a specific child + device to be started. + @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6. + + + @retval EFI_SUCCESS This driver is installed to ControllerHandle. + @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle. + @retval other This driver does not support this device. + +**/ +EFI_STATUS +EFIAPI +HttpDxeStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL, + IN UINT8 IpVersion + ) +{ + EFI_STATUS Status; + EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding; + HTTP_SERVICE *HttpService; + VOID *Interface; + BOOLEAN UsingIpv6; + + UsingIpv6 = FALSE; + + // + // Test for the Http service binding protocol + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiHttpServiceBindingProtocolGuid, + (VOID **) &ServiceBinding, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (!EFI_ERROR (Status)) { + HttpService = HTTP_SERVICE_FROM_PROTOCOL (ServiceBinding); + } else { + Status = HttpCreateService (ControllerHandle, This->DriverBindingHandle, &HttpService); + if (EFI_ERROR (Status)) { + return Status; + } + + ASSERT (HttpService != NULL); + + // + // Install the HttpServiceBinding Protocol onto Controller + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &ControllerHandle, + &gEfiHttpServiceBindingProtocolGuid, + &HttpService->ServiceBinding, + NULL + ); + + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + } + + if (IpVersion == IP_VERSION_4) { + + if (HttpService->Tcp4ChildHandle == NULL) { + // + // Create a TCP4 child instance, but do not configure it. This will establish the parent-child relationship. + // + Status = NetLibCreateServiceChild ( + ControllerHandle, + This->DriverBindingHandle, + &gEfiTcp4ServiceBindingProtocolGuid, + &HttpService->Tcp4ChildHandle + ); + + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + Status = gBS->OpenProtocol ( + HttpService->Tcp4ChildHandle, + &gEfiTcp4ProtocolGuid, + &Interface, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + } else { + return EFI_ALREADY_STARTED; + } + + } else { + UsingIpv6 = TRUE; + + if (HttpService->Tcp6ChildHandle == NULL) { + // + // Create a TCP6 child instance, but do not configure it. This will establish the parent-child relationship. + // + Status = NetLibCreateServiceChild ( + ControllerHandle, + This->DriverBindingHandle, + &gEfiTcp6ServiceBindingProtocolGuid, + &HttpService->Tcp6ChildHandle + ); + + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + Status = gBS->OpenProtocol ( + HttpService->Tcp6ChildHandle, + &gEfiTcp6ProtocolGuid, + &Interface, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + } else { + return EFI_ALREADY_STARTED; + } + + } + + return EFI_SUCCESS; + +ON_ERROR: + + if (HttpService != NULL) { + HttpCleanService (HttpService, UsingIpv6); + if (HttpService->Tcp4ChildHandle == NULL && HttpService->Tcp6ChildHandle == NULL) { + FreePool (HttpService); + } + } + + return Status; + + +} + +/** + Stop this driver on ControllerHandle. This is the worker function for + HttpDxeIp4(6)DriverBindingStop. + + @param[in] This Protocol instance pointer. + @param[in] ControllerHandle Handle of device to stop driver on. + @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If number of + children is zero stop the entire bus driver. + @param[in] ChildHandleBuffer List of Child Handles to Stop. + @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6. + + @retval EFI_SUCCESS This driver was removed ControllerHandle. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + @retval Others This driver was not removed from this device + +**/ +EFI_STATUS +EFIAPI +HttpDxeStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer, + IN UINT8 IpVersion + ) +{ + EFI_HANDLE NicHandle; + EFI_STATUS Status; + EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding; + HTTP_SERVICE *HttpService; + LIST_ENTRY *List; + HTTP_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT Context; + BOOLEAN UsingIpv6; + + // + // HTTP driver opens TCP4(6) child, So, Controller is a TCP4(6) + // child handle. Locate the Nic handle first. Then get the + // HTTP private data back. + // + if (IpVersion == IP_VERSION_4) { + UsingIpv6 = FALSE; + NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiTcp4ProtocolGuid); + } else { + UsingIpv6 = TRUE; + NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiTcp6ProtocolGuid); + } + + if (NicHandle == NULL) { + return EFI_SUCCESS; + } + + Status = gBS->OpenProtocol ( + NicHandle, + &gEfiHttpServiceBindingProtocolGuid, + (VOID **) &ServiceBinding, + This->DriverBindingHandle, + NicHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (!EFI_ERROR (Status)) { + + HttpService = HTTP_SERVICE_FROM_PROTOCOL (ServiceBinding); + + if (NumberOfChildren != 0) { + // + // Destroy the HTTP child instance in ChildHandleBuffer. + // + List = &HttpService->ChildrenList; + Context.ServiceBinding = ServiceBinding; + Context.NumberOfChildren = NumberOfChildren; + Context.ChildHandleBuffer = ChildHandleBuffer; + Status = NetDestroyLinkList ( + List, + HttpDestroyChildEntryInHandleBuffer, + &Context, + NULL + ); + } else { + + HttpCleanService (HttpService, UsingIpv6); + + if (HttpService->Tcp4ChildHandle == NULL && HttpService->Tcp6ChildHandle == NULL) { + gBS->UninstallProtocolInterface ( + NicHandle, + &gEfiHttpServiceBindingProtocolGuid, + ServiceBinding + ); + FreePool (HttpService); + } + Status = EFI_SUCCESS; + } + } + + return Status; + +} + /** Tests to see if this driver supports a given controller. If a child device is provided, it further tests to see if this driver supports creating a handle for the specified child device. @@ -267,41 +632,18 @@ HttpDestroyChildEntryInHandleBuffer ( **/ EFI_STATUS EFIAPI -HttpDxeDriverBindingSupported ( +HttpDxeIp4DriverBindingSupported ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL ) { - EFI_STATUS Status; - - // - // Test for the HttpServiceBinding protocol. - // - Status = gBS->OpenProtocol ( - ControllerHandle, - &gEfiHttpServiceBindingProtocolGuid, - NULL, - This->DriverBindingHandle, - ControllerHandle, - EFI_OPEN_PROTOCOL_TEST_PROTOCOL - ); - if (!EFI_ERROR (Status)) { - return EFI_ALREADY_STARTED; - } - - // - // Test for the Tcp4 Protocol - // - return gBS->OpenProtocol ( - ControllerHandle, - &gEfiTcp4ServiceBindingProtocolGuid, - NULL, - This->DriverBindingHandle, - ControllerHandle, - EFI_OPEN_PROTOCOL_TEST_PROTOCOL - ); - + return HttpDxeSupported ( + This, + ControllerHandle, + RemainingDevicePath, + IP_VERSION_4 + ); } /** @@ -342,90 +684,173 @@ HttpDxeDriverBindingSupported ( **/ EFI_STATUS EFIAPI -HttpDxeDriverBindingStart ( +HttpDxeIp4DriverBindingStart ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL ) { - EFI_STATUS Status; - HTTP_SERVICE *HttpService; - VOID *Interface; + return HttpDxeStart ( + This, + ControllerHandle, + RemainingDevicePath, + IP_VERSION_4 + ); +} + +/** + Stops a device controller or a bus controller. - // - // Test for the Http service binding protocol - // - Status = gBS->OpenProtocol ( - ControllerHandle, - &gEfiHttpServiceBindingProtocolGuid, - NULL, - This->DriverBindingHandle, - ControllerHandle, - EFI_OPEN_PROTOCOL_TEST_PROTOCOL - ); + The Stop() function is designed to be invoked from the EFI boot service DisconnectController(). + As a result, much of the error checking on the parameters to Stop() has been moved + into this common boot service. It is legal to call Stop() from other locations, + but the following calling restrictions must be followed, or the system behavior will not be deterministic. + 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this + same driver's Start() function. + 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid + EFI_HANDLE. In addition, all of these handles must have been created in this driver's + Start() function, and the Start() function must have called OpenProtocol() on + ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle A handle to the device being stopped. The handle must + support a bus specific I/O protocol for the driver + to use to stop the device. + @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer. + @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL + if NumberOfChildren is 0. - if (Status == EFI_SUCCESS) { - return EFI_ALREADY_STARTED; - } + @retval EFI_SUCCESS The device was stopped. + @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error. - Status = HttpCreateService (ControllerHandle, This->DriverBindingHandle, &HttpService); - if (EFI_ERROR (Status)) { - return Status; - } +**/ +EFI_STATUS +EFIAPI +HttpDxeIp4DriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer OPTIONAL + ) +{ + return HttpDxeStop ( + This, + ControllerHandle, + NumberOfChildren, + ChildHandleBuffer, + IP_VERSION_4 + ); +} - ASSERT (HttpService != NULL); +/** + Tests to see if this driver supports a given controller. If a child device is provided, + it further tests to see if this driver supports creating a handle for the specified child device. - // - // Create a TCP child instance, but do not configure it. This will establish the parent-child relationship. - // - Status = NetLibCreateServiceChild ( - ControllerHandle, - This->DriverBindingHandle, - &gEfiTcp4ServiceBindingProtocolGuid, - &HttpService->TcpChildHandle - ); + This function checks to see if the driver specified by This supports the device specified by + ControllerHandle. Drivers will typically use the device path attached to + ControllerHandle and/or the services from the bus I/O abstraction attached to + ControllerHandle to determine if the driver supports ControllerHandle. This function + may be called many times during platform initialization. In order to reduce boot times, the tests + performed by this function must be very small, and take as little time as possible to execute. This + function must not change the state of any hardware devices, and this function must be aware that the + device specified by ControllerHandle may already be managed by the same driver or a + different driver. This function must match its calls to AllocatePages() with FreePages(), + AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol(). + Because ControllerHandle may have been previously started by the same driver, if a protocol is + already in the opened state, then it must not be closed with CloseProtocol(). This is required + to guarantee the state of ControllerHandle is not modified by this function. - if (EFI_ERROR (Status)) { - goto ON_ERROR; - } + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle The handle of the controller to test. This handle + must support a protocol interface that supplies + an I/O abstraction to the driver. + @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This + parameter is ignored by device drivers, and is optional for bus + drivers. For bus drivers, if this parameter is not NULL, then + the bus driver must determine if the bus controller specified + by ControllerHandle and the child controller specified + by RemainingDevicePath are both supported by this + bus driver. - Status = gBS->OpenProtocol ( - HttpService->TcpChildHandle, - &gEfiTcp4ProtocolGuid, - &Interface, - This->DriverBindingHandle, - ControllerHandle, - EFI_OPEN_PROTOCOL_BY_DRIVER - ); - - if (EFI_ERROR (Status)) { - goto ON_ERROR; - } + @retval EFI_SUCCESS The device specified by ControllerHandle and + RemainingDevicePath is supported by the driver specified by This. + @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and + RemainingDevicePath is already being managed by the driver + specified by This. + @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and + RemainingDevicePath is already being managed by a different + driver or an application that requires exclusive access. + Currently not implemented. + @retval EFI_UNSUPPORTED The device specified by ControllerHandle and + RemainingDevicePath is not supported by the driver specified by This. +**/ +EFI_STATUS +EFIAPI +HttpDxeIp6DriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ) +{ + return HttpDxeSupported ( + This, + ControllerHandle, + RemainingDevicePath, + IP_VERSION_6 + ); - // - // Install the HttpServiceBinding Protocol onto Controller - // - Status = gBS->InstallMultipleProtocolInterfaces ( - &ControllerHandle, - &gEfiHttpServiceBindingProtocolGuid, - &HttpService->ServiceBinding, - NULL - ); +} - if (EFI_ERROR (Status)) { - goto ON_ERROR; - } +/** + Starts a device controller or a bus controller. - return EFI_SUCCESS; + The Start() function is designed to be invoked from the EFI boot service ConnectController(). + As a result, much of the error checking on the parameters to Start() has been moved into this + common boot service. It is legal to call Start() from other locations, + but the following calling restrictions must be followed, or the system behavior will not be deterministic. + 1. ControllerHandle must be a valid EFI_HANDLE. + 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned + EFI_DEVICE_PATH_PROTOCOL. + 3. Prior to calling Start(), the Supported() function for the driver specified by This must + have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS. -ON_ERROR: + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle The handle of the controller to start. This handle + must support a protocol interface that supplies + an I/O abstraction to the driver. + @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This + parameter is ignored by device drivers, and is optional for bus + drivers. For a bus driver, if this parameter is NULL, then handles + for all the children of Controller are created by this driver. + If this parameter is not NULL and the first Device Path Node is + not the End of Device Path Node, then only the handle for the + child device specified by the first Device Path Node of + RemainingDevicePath is created by this driver. + If the first Device Path Node of RemainingDevicePath is + the End of Device Path Node, no child handle is created by this + driver. - if (HttpService != NULL) { - HttpCleanService (HttpService); - FreePool (HttpService); - } - - return Status; + @retval EFI_SUCCESS The device was started. + @retval EFI_ALREADY_STARTED This device is already running on ControllerHandle. + @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval Others The driver failded to start the device. + +**/ +EFI_STATUS +EFIAPI +HttpDxeIp6DriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ) +{ + return HttpDxeStart ( + This, + ControllerHandle, + RemainingDevicePath, + IP_VERSION_6 + ); } /** @@ -456,78 +881,21 @@ HttpDxeDriverBindingStart ( **/ EFI_STATUS EFIAPI -HttpDxeDriverBindingStop ( +HttpDxeIp6DriverBindingStop ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, IN UINTN NumberOfChildren, IN EFI_HANDLE *ChildHandleBuffer OPTIONAL ) { - EFI_HANDLE NicHandle; - EFI_STATUS Status; - EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding; - HTTP_SERVICE *HttpService; - LIST_ENTRY *List; - HTTP_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT Context; - - // - // HTTP driver opens TCP child, So, Controller is a TCP - // child handle. Locate the Nic handle first. Then get the - // HTTP private data back. - // - NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiTcp4ProtocolGuid); - if (NicHandle == NULL) { - return EFI_SUCCESS; - } - - Status = gBS->OpenProtocol ( - NicHandle, - &gEfiHttpServiceBindingProtocolGuid, - (VOID **) &ServiceBinding, - This->DriverBindingHandle, - NicHandle, - EFI_OPEN_PROTOCOL_GET_PROTOCOL - ); - - if (EFI_ERROR (Status)) { - return EFI_DEVICE_ERROR; - } - - HttpService = HTTP_SERVICE_FROM_PROTOCOL (ServiceBinding); - - if (!IsListEmpty (&HttpService->ChildrenList)) { - // - // Destroy the HTTP child instance in ChildHandleBuffer. - // - List = &HttpService->ChildrenList; - Context.ServiceBinding = ServiceBinding; - Context.NumberOfChildren = NumberOfChildren; - Context.ChildHandleBuffer = ChildHandleBuffer; - Status = NetDestroyLinkList ( - List, - HttpDestroyChildEntryInHandleBuffer, - &Context, - NULL - ); - } - - if (NumberOfChildren == 0 && IsListEmpty (&HttpService->ChildrenList)) { - gBS->UninstallProtocolInterface ( - NicHandle, - &gEfiHttpServiceBindingProtocolGuid, - ServiceBinding + return HttpDxeStop ( + This, + ControllerHandle, + NumberOfChildren, + ChildHandleBuffer, + IP_VERSION_6 ); - - HttpCleanService (HttpService); - - FreePool (HttpService); - - Status = EFI_SUCCESS; - } - - return Status; } - /** Creates a child handle and installs a protocol. @@ -557,7 +925,6 @@ HttpServiceBindingCreateChild ( HTTP_SERVICE *HttpService; HTTP_PROTOCOL *HttpInstance; EFI_STATUS Status; - VOID *Interface; EFI_TPL OldTpl; if ((This == NULL) || (ChildHandle == NULL)) { @@ -569,6 +936,12 @@ HttpServiceBindingCreateChild ( if (HttpInstance == NULL) { return EFI_OUT_OF_RESOURCES; } + + HttpInstance->Signature = HTTP_PROTOCOL_SIGNATURE; + HttpInstance->Service = HttpService; + CopyMem (&HttpInstance->Http, &mEfiHttpTemplate, sizeof (HttpInstance->Http)); + NetMapInit (&HttpInstance->TxTokens); + NetMapInit (&HttpInstance->RxTokens); // // Install HTTP protocol onto ChildHandle @@ -584,27 +957,7 @@ HttpServiceBindingCreateChild ( goto ON_ERROR; } - HttpInstance->Handle = *ChildHandle; - - Status = HttpInitProtocol (HttpService, HttpInstance); - if (EFI_ERROR (Status)) { - goto ON_ERROR; - } - - // - // Open the default Tcp4 protocol by child. - // - Status = gBS->OpenProtocol ( - HttpService->TcpChildHandle, - &gEfiTcp4ProtocolGuid, - (VOID **) &Interface, - gHttpDxeDriverBinding.DriverBindingHandle, - HttpInstance->Handle, - EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER - ); - if (EFI_ERROR (Status)) { - goto ON_ERROR; - } + HttpInstance->Handle = *ChildHandle; // // Add it to the HTTP service's child list. @@ -619,8 +972,9 @@ HttpServiceBindingCreateChild ( return EFI_SUCCESS; ON_ERROR: - - HttpCleanProtocol (HttpInstance); + + NetMapClean (&HttpInstance->TxTokens); + NetMapClean (&HttpInstance->RxTokens); FreePool (HttpInstance); return Status; @@ -664,8 +1018,8 @@ HttpServiceBindingDestroyChild ( ChildHandle, &gEfiHttpProtocolGuid, (VOID **) &Http, - gHttpDxeDriverBinding.DriverBindingHandle, - ChildHandle, + NULL, + NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL ); if (EFI_ERROR (Status)) { @@ -681,16 +1035,6 @@ HttpServiceBindingDestroyChild ( return EFI_SUCCESS; } - // - // Close the Tcp4 protocol. - // - gBS->CloseProtocol ( - HttpService->TcpChildHandle, - &gEfiTcp4ProtocolGuid, - gHttpDxeDriverBinding.DriverBindingHandle, - ChildHandle - ); - HttpInstance->InDestroy = TRUE; // @@ -706,11 +1050,11 @@ HttpServiceBindingDestroyChild ( HttpInstance->InDestroy = FALSE; return Status; } - - OldTpl = gBS->RaiseTPL (TPL_CALLBACK); - + HttpCleanProtocol (HttpInstance); - + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + RemoveEntryList (&HttpInstance->Link); HttpService->ChildrenNumber--; diff --git a/NetworkPkg/HttpDxe/HttpDriver.h b/NetworkPkg/HttpDxe/HttpDriver.h index eea8d5169e71..8fda6b2be470 100644 --- a/NetworkPkg/HttpDxe/HttpDriver.h +++ b/NetworkPkg/HttpDxe/HttpDriver.h @@ -43,8 +43,12 @@ // #include #include +#include #include +#include #include +#include + // // Produced Protocols @@ -59,7 +63,9 @@ // // Protocol instances // -extern EFI_DRIVER_BINDING_PROTOCOL gHttpDxeDriverBinding; +extern EFI_DRIVER_BINDING_PROTOCOL gHttpDxeIp4DriverBinding; +extern EFI_DRIVER_BINDING_PROTOCOL gHttpDxeIp6DriverBinding; + extern EFI_COMPONENT_NAME2_PROTOCOL gHttpDxeComponentName2; extern EFI_COMPONENT_NAME_PROTOCOL gHttpDxeComponentName; @@ -123,7 +129,7 @@ typedef struct { **/ EFI_STATUS EFIAPI -HttpDxeDriverBindingSupported ( +HttpDxeIp4DriverBindingSupported ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL @@ -166,7 +172,7 @@ HttpDxeDriverBindingSupported ( **/ EFI_STATUS EFIAPI -HttpDxeDriverBindingStart ( +HttpDxeIp4DriverBindingStart ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL @@ -200,13 +206,142 @@ HttpDxeDriverBindingStart ( **/ EFI_STATUS EFIAPI -HttpDxeDriverBindingStop ( +HttpDxeIp4DriverBindingStop ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, IN UINTN NumberOfChildren, IN EFI_HANDLE *ChildHandleBuffer OPTIONAL ); +/** + Tests to see if this driver supports a given controller. If a child device is provided, + it further tests to see if this driver supports creating a handle for the specified child device. + + This function checks to see if the driver specified by This supports the device specified by + ControllerHandle. Drivers will typically use the device path attached to + ControllerHandle and/or the services from the bus I/O abstraction attached to + ControllerHandle to determine if the driver supports ControllerHandle. This function + may be called many times during platform initialization. In order to reduce boot times, the tests + performed by this function must be very small, and take as little time as possible to execute. This + function must not change the state of any hardware devices, and this function must be aware that the + device specified by ControllerHandle may already be managed by the same driver or a + different driver. This function must match its calls to AllocatePages() with FreePages(), + AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol(). + Because ControllerHandle may have been previously started by the same driver, if a protocol is + already in the opened state, then it must not be closed with CloseProtocol(). This is required + to guarantee the state of ControllerHandle is not modified by this function. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle The handle of the controller to test. This handle + must support a protocol interface that supplies + an I/O abstraction to the driver. + @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This + parameter is ignored by device drivers, and is optional for bus + drivers. For bus drivers, if this parameter is not NULL, then + the bus driver must determine if the bus controller specified + by ControllerHandle and the child controller specified + by RemainingDevicePath are both supported by this + bus driver. + + @retval EFI_SUCCESS The device specified by ControllerHandle and + RemainingDevicePath is supported by the driver specified by This. + @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and + RemainingDevicePath is already being managed by the driver + specified by This. + @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and + RemainingDevicePath is already being managed by a different + driver or an application that requires exclusive access. + Currently not implemented. + @retval EFI_UNSUPPORTED The device specified by ControllerHandle and + RemainingDevicePath is not supported by the driver specified by This. +**/ +EFI_STATUS +EFIAPI +HttpDxeIp6DriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ); + +/** + Starts a device controller or a bus controller. + + The Start() function is designed to be invoked from the EFI boot service ConnectController(). + As a result, much of the error checking on the parameters to Start() has been moved into this + common boot service. It is legal to call Start() from other locations, + but the following calling restrictions must be followed, or the system behavior will not be deterministic. + 1. ControllerHandle must be a valid EFI_HANDLE. + 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned + EFI_DEVICE_PATH_PROTOCOL. + 3. Prior to calling Start(), the Supported() function for the driver specified by This must + have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle The handle of the controller to start. This handle + must support a protocol interface that supplies + an I/O abstraction to the driver. + @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This + parameter is ignored by device drivers, and is optional for bus + drivers. For a bus driver, if this parameter is NULL, then handles + for all the children of Controller are created by this driver. + If this parameter is not NULL and the first Device Path Node is + not the End of Device Path Node, then only the handle for the + child device specified by the first Device Path Node of + RemainingDevicePath is created by this driver. + If the first Device Path Node of RemainingDevicePath is + the End of Device Path Node, no child handle is created by this + driver. + + @retval EFI_SUCCESS The device was started. + @retval EFI_ALREADY_STARTED This device is already running on ControllerHandle. + @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval Others The driver failded to start the device. + +**/ +EFI_STATUS +EFIAPI +HttpDxeIp6DriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ); + +/** + Stops a device controller or a bus controller. + + The Stop() function is designed to be invoked from the EFI boot service DisconnectController(). + As a result, much of the error checking on the parameters to Stop() has been moved + into this common boot service. It is legal to call Stop() from other locations, + but the following calling restrictions must be followed, or the system behavior will not be deterministic. + 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this + same driver's Start() function. + 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid + EFI_HANDLE. In addition, all of these handles must have been created in this driver's + Start() function, and the Start() function must have called OpenProtocol() on + ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle A handle to the device being stopped. The handle must + support a bus specific I/O protocol for the driver + to use to stop the device. + @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer. + @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL + if NumberOfChildren is 0. + + @retval EFI_SUCCESS The device was stopped. + @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error. + +**/ +EFI_STATUS +EFIAPI +HttpDxeIp6DriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer OPTIONAL + ); + /** Creates a child handle and installs a protocol. diff --git a/NetworkPkg/HttpDxe/HttpDxe.inf b/NetworkPkg/HttpDxe/HttpDxe.inf index 0d3bd00cf7b7..bf2cbee5f7c9 100644 --- a/NetworkPkg/HttpDxe/HttpDxe.inf +++ b/NetworkPkg/HttpDxe/HttpDxe.inf @@ -56,9 +56,14 @@ gEfiHttpUtilitiesProtocolGuid ## CONSUMES gEfiTcp4ServiceBindingProtocolGuid ## TO_START gEfiTcp4ProtocolGuid ## TO_START + gEfiTcp6ServiceBindingProtocolGuid ## TO_START + gEfiTcp6ProtocolGuid ## TO_START gEfiDns4ServiceBindingProtocolGuid ## SOMETIMES_CONSUMES gEfiDns4ProtocolGuid ## SOMETIMES_CONSUMES + gEfiDns6ServiceBindingProtocolGuid ## SOMETIMES_CONSUMES + gEfiDns6ProtocolGuid ## SOMETIMES_CONSUMES gEfiIp4Config2ProtocolGuid ## SOMETIMES_CONSUMES + gEfiIp6ConfigProtocolGuid ## SOMETIMES_CONSUMES [UserExtensions.TianoCore."ExtraFiles"] HttpDxeExtra.uni \ No newline at end of file diff --git a/NetworkPkg/HttpDxe/HttpDxe.uni b/NetworkPkg/HttpDxe/HttpDxe.uni index f9c2ac812e573faa9e5ff1e6d2ecd630be2ff395..d6792dd41eb4c2642d65eb7e01c0833b43f92761 100644 GIT binary patch delta 63 zcmbQow~ueaC*FL9A_fHpPlf=7G6u7a?State < HTTP_STATE_HTTP_CONFIGED) { return EFI_NOT_STARTED; } - if (HttpConfigData->AccessPoint.IPv4Node == NULL) { - return EFI_INVALID_PARAMETER; - } - HttpConfigData->HttpVersion = HttpInstance->HttpVersion; HttpConfigData->TimeOutMillisec = HttpInstance->TimeOutMillisec; HttpConfigData->LocalAddressIsIPv6 = HttpInstance->LocalAddressIsIPv6; - CopyMem ( - HttpConfigData->AccessPoint.IPv4Node, - &HttpInstance->IPv4Node, - sizeof (HttpInstance->IPv4Node) + if (HttpInstance->LocalAddressIsIPv6) { + Http6AccessPoint = AllocateZeroPool (sizeof (EFI_HTTPv6_ACCESS_POINT)); + CopyMem ( + Http6AccessPoint, + &HttpInstance->Ipv6Node, + sizeof (HttpInstance->Ipv6Node) ); + HttpConfigData->AccessPoint.IPv6Node = Http6AccessPoint; + } else { + Http4AccessPoint = AllocateZeroPool (sizeof (EFI_HTTPv4_ACCESS_POINT)); + CopyMem ( + Http4AccessPoint, + &HttpInstance->IPv4Node, + sizeof (HttpInstance->IPv4Node) + ); + HttpConfigData->AccessPoint.IPv4Node = Http4AccessPoint; + } return EFI_SUCCESS; } @@ -119,8 +129,13 @@ EfiHttpConfigure ( { HTTP_PROTOCOL *HttpInstance; EFI_STATUS Status; - - if (This == NULL) { + + // + // Check input parameters. + // + if (This == NULL || + (HttpConfigData != NULL && ((HttpConfigData->LocalAddressIsIPv6 && HttpConfigData->AccessPoint.IPv6Node == NULL) || + (!HttpConfigData->LocalAddressIsIPv6 && HttpConfigData->AccessPoint.IPv4Node == NULL)))) { return EFI_INVALID_PARAMETER; } @@ -128,18 +143,7 @@ EfiHttpConfigure ( ASSERT (HttpInstance != NULL && HttpInstance->Service != NULL); if (HttpConfigData != NULL) { - // - // Check input parameters. - // - if (HttpConfigData->LocalAddressIsIPv6) { - if (HttpConfigData->AccessPoint.IPv6Node == NULL) { - return EFI_INVALID_PARAMETER; - } - } else { - if (HttpConfigData->AccessPoint.IPv4Node == NULL) { - return EFI_INVALID_PARAMETER; - } - } + // // Now configure this HTTP instance. // @@ -150,33 +154,38 @@ EfiHttpConfigure ( HttpInstance->HttpVersion = HttpConfigData->HttpVersion; HttpInstance->TimeOutMillisec = HttpConfigData->TimeOutMillisec; HttpInstance->LocalAddressIsIPv6 = HttpConfigData->LocalAddressIsIPv6; - - if (HttpConfigData->LocalAddressIsIPv6) { - return EFI_UNSUPPORTED; + + if (HttpConfigData->LocalAddressIsIPv6) { + CopyMem ( + &HttpInstance->Ipv6Node, + HttpConfigData->AccessPoint.IPv6Node, + sizeof (HttpInstance->Ipv6Node) + ); } else { CopyMem ( &HttpInstance->IPv4Node, HttpConfigData->AccessPoint.IPv4Node, sizeof (HttpInstance->IPv4Node) ); - - HttpInstance->State = HTTP_STATE_HTTP_CONFIGED; - return EFI_SUCCESS; } + // + // Creat Tcp child + // + Status = HttpInitProtocol (HttpInstance, HttpInstance->LocalAddressIsIPv6); + if (EFI_ERROR (Status)) { + return Status; + } + + HttpInstance->State = HTTP_STATE_HTTP_CONFIGED; + return EFI_SUCCESS; } else { - if (HttpInstance->LocalAddressIsIPv6) { - return EFI_UNSUPPORTED; - } else { - HttpCleanProtocol (HttpInstance); - Status = HttpInitProtocol (HttpInstance->Service, HttpInstance); - if (EFI_ERROR (Status)) { - return Status; - } - - HttpInstance->State = HTTP_STATE_UNCONFIGED; - return EFI_SUCCESS; - } + // + // Reset all the resources related to HttpInsance. + // + HttpCleanProtocol (HttpInstance); + HttpInstance->State = HTTP_STATE_UNCONFIGED; + return EFI_SUCCESS; } } @@ -264,10 +273,6 @@ EfiHttpRequest ( return EFI_NOT_STARTED; } - if (HttpInstance->LocalAddressIsIPv6) { - return EFI_UNSUPPORTED; - } - // // Check whether the token already existed. // @@ -292,7 +297,8 @@ EfiHttpRequest ( } FreePool (HttpInstance->Url); HttpInstance->Url = Url; - } + } + UnicodeStrToAsciiStr (Request->Url, Url); UrlParser = NULL; @@ -341,7 +347,7 @@ EfiHttpRequest ( Wrap->HttpToken = Token; Wrap->HttpInstance = HttpInstance; - Status = HttpCreateTcp4TxEvent (Wrap); + Status = HttpCreateTcpTxEvent (Wrap); if (EFI_ERROR (Status)) { goto Error1; } @@ -380,24 +386,35 @@ EfiHttpRequest ( if (Configure) { // - // Parse Url for IPv4 address, if failed, perform DNS resolution. + // Parse Url for IPv4 or IPv6 address, if failed, perform DNS resolution. // - Status = NetLibAsciiStrToIp4 (HostName, &HttpInstance->RemoteAddr); + if (!HttpInstance->LocalAddressIsIPv6) { + Status = NetLibAsciiStrToIp4 (HostName, &HttpInstance->RemoteAddr); + } else { + Status = NetLibAsciiStrToIp6 (HostName, &HttpInstance->RemoteIpv6Addr); + } + if (EFI_ERROR (Status)) { - HostNameStr = AllocateZeroPool ((AsciiStrLen (HostName) + 1) * sizeof (UINT16)); + HostNameStr = AllocateZeroPool ((AsciiStrLen (HostName) + 1) * sizeof (CHAR16)); if (HostNameStr == NULL) { Status = EFI_OUT_OF_RESOURCES; goto Error1; } - + AsciiStrToUnicodeStr (HostName, HostNameStr); - Status = HttpDns4 (HttpInstance, HostNameStr, &HttpInstance->RemoteAddr); + if (!HttpInstance->LocalAddressIsIPv6) { + Status = HttpDns4 (HttpInstance, HostNameStr, &HttpInstance->RemoteAddr); + } else { + Status = HttpDns6 (HttpInstance, HostNameStr, &HttpInstance->RemoteIpv6Addr); + } + FreePool (HostNameStr); if (EFI_ERROR (Status)) { goto Error1; } } + // // Save the RemotePort and RemoteHost. // @@ -411,7 +428,7 @@ EfiHttpRequest ( // // The request URL is different from previous calls to Request(), close existing TCP instance. // - ASSERT (HttpInstance->Tcp4 != NULL); + ASSERT (HttpInstance->Tcp4 != NULL &&HttpInstance->Tcp6 != NULL); HttpCloseConnection (HttpInstance); EfiHttpCancel (This, NULL); } @@ -430,25 +447,16 @@ EfiHttpRequest ( Wrap->TcpWrap.Method = Request->Method; if (Configure) { - // - // Configure TCP instance. - // - Status = HttpConfigureTcp4 (HttpInstance, Wrap); - if (EFI_ERROR (Status)) { - goto Error1; - } - // - // Connect TCP. - // - Status = HttpConnectTcp4 (HttpInstance); + Status = HttpInitTcp (HttpInstance, Wrap); if (EFI_ERROR (Status)) { goto Error2; } + } else { // // For the new HTTP token, create TX TCP token events. // - Status = HttpCreateTcp4TxEvent (Wrap); + Status = HttpCreateTcpTxEvent (Wrap); if (EFI_ERROR (Status)) { goto Error1; } @@ -489,7 +497,7 @@ EfiHttpRequest ( // // Transmit the request message. // - Status = HttpTransmitTcp4 ( + Status = HttpTransmitTcp ( HttpInstance, Wrap, (UINT8*) RequestStr, @@ -500,11 +508,11 @@ EfiHttpRequest ( } DispatchDpc (); - + if (HostName != NULL) { FreePool (HostName); } - + return EFI_SUCCESS; Error5: @@ -518,15 +526,19 @@ EfiHttpRequest ( Error3: HttpCloseConnection (HttpInstance); - Error2: - HttpCloseTcp4ConnCloseEvent (HttpInstance); - if (NULL != Wrap->TcpWrap.TxToken.CompletionToken.Event) { - gBS->CloseEvent (Wrap->TcpWrap.TxToken.CompletionToken.Event); - Wrap->TcpWrap.TxToken.CompletionToken.Event = NULL; + HttpCloseTcpConnCloseEvent (HttpInstance); + if (NULL != Wrap->TcpWrap.Tx4Token.CompletionToken.Event) { + gBS->CloseEvent (Wrap->TcpWrap.Tx4Token.CompletionToken.Event); + Wrap->TcpWrap.Tx4Token.CompletionToken.Event = NULL; + } + if (NULL != Wrap->TcpWrap.Tx6Token.CompletionToken.Event) { + gBS->CloseEvent (Wrap->TcpWrap.Tx6Token.CompletionToken.Event); + Wrap->TcpWrap.Tx6Token.CompletionToken.Event = NULL; } Error1: + if (HostName != NULL) { FreePool (HostName); } @@ -542,7 +554,7 @@ EfiHttpRequest ( } /** - Cancel a TxToken or RxToken. + Cancel a user's Token. @param[in] Map The HTTP instance's token queue. @param[in] Item Object container for one HTTP token and token's wrap. @@ -563,6 +575,7 @@ HttpCancelTokens ( EFI_HTTP_TOKEN *Token; HTTP_TOKEN_WRAP *Wrap; + HTTP_PROTOCOL *HttpInstance; Token = (EFI_HTTP_TOKEN *) Context; @@ -576,24 +589,41 @@ HttpCancelTokens ( Wrap = (HTTP_TOKEN_WRAP *) Item->Value; ASSERT (Wrap != NULL); + HttpInstance = Wrap->HttpInstance; // // Free resources. // NetMapRemoveItem (Map, Item, NULL); - if (Wrap->TcpWrap.TxToken.CompletionToken.Event != NULL) { - gBS->CloseEvent (Wrap->TcpWrap.TxToken.CompletionToken.Event); - } + if (!HttpInstance->LocalAddressIsIPv6) { + if (Wrap->TcpWrap.Tx4Token.CompletionToken.Event != NULL) { + gBS->CloseEvent (Wrap->TcpWrap.Tx4Token.CompletionToken.Event); + } + + if (Wrap->TcpWrap.Rx4Token.CompletionToken.Event != NULL) { + gBS->CloseEvent (Wrap->TcpWrap.Rx4Token.CompletionToken.Event); + } + + if (Wrap->TcpWrap.Rx4Token.Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) { + FreePool (Wrap->TcpWrap.Rx4Token.Packet.RxData->FragmentTable[0].FragmentBuffer); + } - if (Wrap->TcpWrap.RxToken.CompletionToken.Event != NULL) { - gBS->CloseEvent (Wrap->TcpWrap.RxToken.CompletionToken.Event); - } + } else { + if (Wrap->TcpWrap.Tx6Token.CompletionToken.Event != NULL) { + gBS->CloseEvent (Wrap->TcpWrap.Tx6Token.CompletionToken.Event); + } + + if (Wrap->TcpWrap.Rx6Token.CompletionToken.Event != NULL) { + gBS->CloseEvent (Wrap->TcpWrap.Rx6Token.CompletionToken.Event); + } - if (Wrap->TcpWrap.RxToken.Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) { - FreePool (Wrap->TcpWrap.RxToken.Packet.RxData->FragmentTable[0].FragmentBuffer); + if (Wrap->TcpWrap.Rx6Token.Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) { + FreePool (Wrap->TcpWrap.Rx6Token.Packet.RxData->FragmentTable[0].FragmentBuffer); + } } + FreePool (Wrap); // @@ -748,7 +778,7 @@ HttpBodyParserCallback ( Wrap->HttpInstance->NextMsg = Data; // - // Free TxToken since already received corrsponding HTTP response. + // Free Tx4Token or Tx6Token since already received corrsponding HTTP response. // FreePool (Wrap); @@ -762,7 +792,7 @@ HttpBodyParserCallback ( @retval EFI_SUCCESS Allocation succeeded. @retval EFI_OUT_OF_RESOURCES Failed to complete the opration due to lack of resources. - @retval EFI_NOT_READY Can't find a corresponding TxToken or + @retval EFI_NOT_READY Can't find a corresponding Tx4Token/Tx6Token or the EFI_HTTP_UTILITIES_PROTOCOL is not available. **/ @@ -773,12 +803,9 @@ HttpResponseWorker ( { EFI_STATUS Status; EFI_HTTP_MESSAGE *HttpMsg; - EFI_TCP4_IO_TOKEN *RxToken; - EFI_TCP4_PROTOCOL *Tcp4; CHAR8 *EndofHeader; CHAR8 *HttpHeaders; UINTN SizeofHeaders; - CHAR8 *Buffer; UINTN BufferSize; UINTN StatusCode; CHAR8 *Tmp; @@ -797,23 +824,21 @@ HttpResponseWorker ( HttpInstance = Wrap->HttpInstance; Token = Wrap->HttpToken; - HttpMsg = Token->Message; - Tcp4 = HttpInstance->Tcp4; - ASSERT (Tcp4 != NULL); - HttpMsg->Headers = NULL; - HttpHeaders = NULL; - SizeofHeaders = 0; - Buffer = NULL; - BufferSize = 0; - EndofHeader = NULL; + HttpInstance->EndofHeader = NULL; + HttpInstance->HttpHeaders = NULL; + HttpMsg->Headers = NULL; + HttpHeaders = NULL; + SizeofHeaders = 0; + BufferSize = 0; + EndofHeader = NULL; if (HttpMsg->Data.Response != NULL) { // // Need receive the HTTP headers, prepare buffer. // - Status = HttpCreateTcp4RxEventForHeader (HttpInstance); + Status = HttpCreateTcpRxEventForHeader (HttpInstance); if (EFI_ERROR (Status)) { goto Error; } @@ -844,70 +869,15 @@ HttpResponseWorker ( // Check whether we cached the whole HTTP headers. // EndofHeader = AsciiStrStr (HttpHeaders, HTTP_END_OF_HDR_STR); - } - - RxToken = &HttpInstance->RxToken; - RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer = AllocateZeroPool (DEF_BUF_LEN); - if (RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer == NULL) { - Status = EFI_OUT_OF_RESOURCES; - goto Error; - } - - // - // Receive the HTTP headers only when EFI_HTTP_RESPONSE_DATA is not NULL. - // - while (EndofHeader == NULL) { - HttpInstance->IsRxDone = FALSE; - RxToken->Packet.RxData->DataLength = DEF_BUF_LEN; - RxToken->Packet.RxData->FragmentTable[0].FragmentLength = DEF_BUF_LEN; - Status = Tcp4->Receive (Tcp4, RxToken); - if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "Tcp4 receive failed: %r\n", Status)); - goto Error; - } - - while (!HttpInstance->IsRxDone) { - Tcp4->Poll (Tcp4); - } - - Status = RxToken->CompletionToken.Status; - if (EFI_ERROR (Status)) { - goto Error; - } - - // - // Append the response string. - // - BufferSize = SizeofHeaders + RxToken->Packet.RxData->FragmentTable[0].FragmentLength; - Buffer = AllocateZeroPool (BufferSize); - if (Buffer == NULL) { - Status = EFI_OUT_OF_RESOURCES; - goto Error; - } - - if (HttpHeaders != NULL) { - CopyMem (Buffer, HttpHeaders, SizeofHeaders); - FreePool (HttpHeaders); - } - - CopyMem ( - Buffer + SizeofHeaders, - RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer, - RxToken->Packet.RxData->FragmentTable[0].FragmentLength - ); - HttpHeaders = Buffer; - SizeofHeaders = BufferSize; + } - // - // Check whether we received end of HTTP headers. - // - EndofHeader = AsciiStrStr (HttpHeaders, HTTP_END_OF_HDR_STR); - }; + HttpInstance->EndofHeader = &EndofHeader; + HttpInstance->HttpHeaders = &HttpHeaders; - // - // Skip the CRLF after the HTTP headers. - // - EndofHeader = EndofHeader + AsciiStrLen (HTTP_END_OF_HDR_STR); + Status = HttpTcpReceiveHeader (HttpInstance, &SizeofHeaders, &BufferSize); + if (EFI_ERROR (Status)) { + goto Error; + } // // Cache the part of body. @@ -928,9 +898,6 @@ HttpResponseWorker ( HttpInstance->CacheLen = BodyLen; } - FreePool (RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer); - RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL; - // // Search for Status Code. // @@ -998,7 +965,7 @@ HttpResponseWorker ( } // - // The first TxToken not transmitted yet, insert back and return error. + // The first Tx Token not transmitted yet, insert back and return error. // if (!ValueInItem->TcpWrap.IsTxDone) { goto Error2; @@ -1109,16 +1076,8 @@ HttpResponseWorker ( // // We still need receive more data when there is no cache data and MsgParser is not NULL; // - RxToken = &Wrap->TcpWrap.RxToken; - - RxToken->Packet.RxData->DataLength = (UINT32) HttpMsg->BodyLength; - RxToken->Packet.RxData->FragmentTable[0].FragmentLength = (UINT32) HttpMsg->BodyLength; - RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer = (VOID *) HttpMsg->Body; - - RxToken->CompletionToken.Status = EFI_NOT_READY; - Status = Tcp4->Receive (Tcp4, RxToken); + Status = HttpTcpReceiveBody (Wrap, HttpMsg); if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "Tcp4 receive failed: %r\n", Status)); goto Error; } @@ -1131,18 +1090,7 @@ HttpResponseWorker ( } Token->Status = Status; gBS->SignalEvent (Token->Event); - - if (Wrap != NULL) { - if (Wrap->TcpWrap.RxToken.CompletionToken.Event != NULL) { - gBS->CloseEvent (Wrap->TcpWrap.RxToken.CompletionToken.Event); - } - } - - if (HttpInstance->RxToken.CompletionToken.Event != NULL) { - gBS->CloseEvent (HttpInstance->RxToken.CompletionToken.Event); - HttpInstance->RxToken.CompletionToken.Event = NULL; - } - + HttpCloseTcpRxEvent (Wrap); FreePool (Wrap); return Status; @@ -1150,28 +1098,7 @@ HttpResponseWorker ( NetMapInsertHead (&HttpInstance->TxTokens, ValueInItem->HttpToken, ValueInItem); Error: - if (Wrap != NULL) { - if (Wrap->TcpWrap.RxToken.CompletionToken.Event != NULL) { - gBS->CloseEvent (Wrap->TcpWrap.RxToken.CompletionToken.Event); - } - RxToken = &Wrap->TcpWrap.RxToken; - if (RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) { - FreePool (RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer); - RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL; - } - FreePool (Wrap); - } - - if (HttpInstance->RxToken.CompletionToken.Event != NULL) { - gBS->CloseEvent (HttpInstance->RxToken.CompletionToken.Event); - HttpInstance->RxToken.CompletionToken.Event = NULL; - } - - RxToken = &HttpInstance->RxToken; - if (RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) { - FreePool (RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer); - RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL; - } + HttpTcpTokenCleanup (Wrap); if (HttpHeaders != NULL) { FreePool (HttpHeaders); @@ -1269,10 +1196,6 @@ EfiHttpResponse ( return EFI_NOT_STARTED; } - if (HttpInstance->LocalAddressIsIPv6) { - return EFI_UNSUPPORTED; - } - // // Check whether the token already existed. // @@ -1288,7 +1211,7 @@ EfiHttpResponse ( Wrap->HttpInstance = HttpInstance; Wrap->HttpToken = Token; - Status = HttpCreateTcp4RxEvent (Wrap); + Status = HttpCreateTcpRxEvent (Wrap); if (EFI_ERROR (Status)) { goto Error; } @@ -1309,8 +1232,12 @@ EfiHttpResponse ( Error: if (Wrap != NULL) { - if (Wrap->TcpWrap.RxToken.CompletionToken.Event != NULL) { - gBS->CloseEvent (Wrap->TcpWrap.RxToken.CompletionToken.Event); + if (Wrap->TcpWrap.Rx4Token.CompletionToken.Event != NULL) { + gBS->CloseEvent (Wrap->TcpWrap.Rx4Token.CompletionToken.Event); + } + + if (Wrap->TcpWrap.Rx6Token.CompletionToken.Event != NULL) { + gBS->CloseEvent (Wrap->TcpWrap.Rx6Token.CompletionToken.Event); } FreePool (Wrap); } @@ -1344,8 +1271,8 @@ EfiHttpPoll ( IN EFI_HTTP_PROTOCOL *This ) { - HTTP_PROTOCOL *HttpInstance; EFI_STATUS Status; + HTTP_PROTOCOL *HttpInstance; if (This == NULL) { return EFI_INVALID_PARAMETER; @@ -1354,17 +1281,18 @@ EfiHttpPoll ( HttpInstance = HTTP_INSTANCE_FROM_PROTOCOL (This); ASSERT (HttpInstance != NULL); - if (HttpInstance->LocalAddressIsIPv6) { - return EFI_UNSUPPORTED; - } - - if (HttpInstance->Tcp4 == NULL || HttpInstance->State != HTTP_STATE_TCP_CONNECTED) { + if (HttpInstance->State != HTTP_STATE_TCP_CONNECTED || (HttpInstance->Tcp4 == NULL && + HttpInstance->Tcp6 == NULL)) { return EFI_NOT_STARTED; } - - Status = HttpInstance->Tcp4->Poll (HttpInstance->Tcp4); - + + if (HttpInstance->LocalAddressIsIPv6) { + Status = HttpInstance->Tcp6->Poll (HttpInstance->Tcp6); + } else { + Status = HttpInstance->Tcp4->Poll (HttpInstance->Tcp4); + } + DispatchDpc (); - + return Status; } diff --git a/NetworkPkg/HttpDxe/HttpProto.c b/NetworkPkg/HttpDxe/HttpProto.c index 13d5748378e3..c4ffef2bc236 100644 --- a/NetworkPkg/HttpDxe/HttpProto.c +++ b/NetworkPkg/HttpDxe/HttpProto.c @@ -37,7 +37,7 @@ HttpCommonNotify ( } /** - The notify function associated with TxToken for Tcp4->Transmit(). + The notify function associated with Tx4Token for Tcp4->Transmit() or Tx6Token for Tcp6->Transmit(). @param[in] Context The context. @@ -49,25 +49,46 @@ HttpTcpTransmitNotifyDpc ( ) { HTTP_TOKEN_WRAP *Wrap; + HTTP_PROTOCOL *HttpInstance; if (Context == NULL) { return ; } + + Wrap = (HTTP_TOKEN_WRAP *) Context; + HttpInstance = Wrap->HttpInstance; + + if (!HttpInstance->LocalAddressIsIPv6) { + Wrap->HttpToken->Status = Wrap->TcpWrap.Tx4Token.CompletionToken.Status; + gBS->SignalEvent (Wrap->HttpToken->Event); + + // + // Free resources. + // + if (Wrap->TcpWrap.Tx4Token.Packet.TxData->FragmentTable[0].FragmentBuffer != NULL) { + FreePool (Wrap->TcpWrap.Tx4Token.Packet.TxData->FragmentTable[0].FragmentBuffer); + } - Wrap = (HTTP_TOKEN_WRAP *) Context; - Wrap->HttpToken->Status = Wrap->TcpWrap.TxToken.CompletionToken.Status; - gBS->SignalEvent (Wrap->HttpToken->Event); + if (Wrap->TcpWrap.Tx4Token.CompletionToken.Event != NULL) { + gBS->CloseEvent (Wrap->TcpWrap.Tx4Token.CompletionToken.Event); + } + + } else { + Wrap->HttpToken->Status = Wrap->TcpWrap.Tx6Token.CompletionToken.Status; + gBS->SignalEvent (Wrap->HttpToken->Event); + + // + // Free resources. + // + if (Wrap->TcpWrap.Tx6Token.Packet.TxData->FragmentTable[0].FragmentBuffer != NULL) { + FreePool (Wrap->TcpWrap.Tx6Token.Packet.TxData->FragmentTable[0].FragmentBuffer); + } - // - // Free resources. - // - if (Wrap->TcpWrap.TxToken.Packet.TxData->FragmentTable[0].FragmentBuffer != NULL) { - FreePool (Wrap->TcpWrap.TxToken.Packet.TxData->FragmentTable[0].FragmentBuffer); + if (Wrap->TcpWrap.Tx6Token.CompletionToken.Event != NULL) { + gBS->CloseEvent (Wrap->TcpWrap.Tx6Token.CompletionToken.Event); + } } - if (Wrap->TcpWrap.TxToken.CompletionToken.Event != NULL) { - gBS->CloseEvent (Wrap->TcpWrap.TxToken.CompletionToken.Event); - } Wrap->TcpWrap.IsTxDone = TRUE; @@ -98,9 +119,8 @@ HttpTcpTransmitNotify ( QueueDpc (TPL_CALLBACK, HttpTcpTransmitNotifyDpc, Context); } - /** - The notify function associated with RxToken for Tcp4->Receive (). + The notify function associated with Rx4Token for Tcp4->Receive () or Rx6Token for Tcp6->Receive(). @param[in] Context The context. @@ -116,25 +136,41 @@ HttpTcpReceiveNotifyDpc ( UINTN Length; EFI_STATUS Status; HTTP_PROTOCOL *HttpInstance; + BOOLEAN UsingIpv6; if (Context == NULL) { return ; } Wrap = (HTTP_TOKEN_WRAP *) Context; - gBS->CloseEvent (Wrap->TcpWrap.RxToken.CompletionToken.Event); - if (EFI_ERROR (Wrap->TcpWrap.RxToken.CompletionToken.Status)) { - return ; - } - HttpInstance = Wrap->HttpInstance; + UsingIpv6 = HttpInstance->LocalAddressIsIPv6; + + if (UsingIpv6) { + gBS->CloseEvent (Wrap->TcpWrap.Rx6Token.CompletionToken.Event); + + if (EFI_ERROR (Wrap->TcpWrap.Rx6Token.CompletionToken.Status)) { + return ; + } + + } else { + gBS->CloseEvent (Wrap->TcpWrap.Rx4Token.CompletionToken.Event); + + if (EFI_ERROR (Wrap->TcpWrap.Rx4Token.CompletionToken.Status)) { + return ; + } + } // // Check whether we receive a complete HTTP message. // ASSERT (HttpInstance->MsgParser != NULL); + if (UsingIpv6) { + Length = (UINTN) Wrap->TcpWrap.Rx6Data.FragmentTable[0].FragmentLength; + } else { + Length = (UINTN) Wrap->TcpWrap.Rx4Data.FragmentTable[0].FragmentLength; + } - Length = (UINTN) Wrap->TcpWrap.RxData.FragmentTable[0].FragmentLength; Status = HttpParseMessageBody ( HttpInstance->MsgParser, Length, @@ -179,7 +215,12 @@ HttpTcpReceiveNotifyDpc ( Wrap->TcpWrap.IsRxDone = TRUE; - Wrap->HttpToken->Status = Wrap->TcpWrap.RxToken.CompletionToken.Status; + if (UsingIpv6) { + Wrap->HttpToken->Status = Wrap->TcpWrap.Rx6Token.CompletionToken.Status; + } else { + Wrap->HttpToken->Status = Wrap->TcpWrap.Rx4Token.CompletionToken.Status; + } + gBS->SignalEvent (Wrap->HttpToken->Event); @@ -211,9 +252,8 @@ HttpTcpReceiveNotify ( QueueDpc (TPL_CALLBACK, HttpTcpReceiveNotifyDpc, Context); } - /** - Create events for the TCP4 connection token and TCP4 close token. + Create events for the TCP connection token and TCP close token. @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure. @@ -222,11 +262,13 @@ HttpTcpReceiveNotify ( **/ EFI_STATUS -HttpCreateTcp4ConnCloseEvent ( +HttpCreateTcpConnCloseEvent ( IN HTTP_PROTOCOL *HttpInstance ) { EFI_STATUS Status; + + if (!HttpInstance->LocalAddressIsIPv6) { // // Create events for variuos asynchronous operations. // @@ -234,66 +276,109 @@ HttpCreateTcp4ConnCloseEvent ( EVT_NOTIFY_SIGNAL, TPL_NOTIFY, HttpCommonNotify, - &HttpInstance->IsConnDone, - &HttpInstance->ConnToken.CompletionToken.Event + &HttpInstance->IsTcp4ConnDone, + &HttpInstance->Tcp4ConnToken.CompletionToken.Event ); if (EFI_ERROR (Status)) { goto ERROR; } // - // Initialize CloseToken + // Initialize Tcp4CloseToken // Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL, TPL_NOTIFY, HttpCommonNotify, - &HttpInstance->IsCloseDone, - &HttpInstance->CloseToken.CompletionToken.Event + &HttpInstance->IsTcp4CloseDone, + &HttpInstance->Tcp4CloseToken.CompletionToken.Event + ); + if (EFI_ERROR (Status)) { + goto ERROR; + } + + } else { + // + // Create events for variuos asynchronous operations. + // + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + HttpCommonNotify, + &HttpInstance->IsTcp6ConnDone, + &HttpInstance->Tcp6ConnToken.CompletionToken.Event ); if (EFI_ERROR (Status)) { goto ERROR; } - + // + // Initialize Tcp6CloseToken + // + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + HttpCommonNotify, + &HttpInstance->IsTcp6CloseDone, + &HttpInstance->Tcp6CloseToken.CompletionToken.Event + ); + if (EFI_ERROR (Status)) { + goto ERROR; + } + } + return EFI_SUCCESS; ERROR: // // Error handling // - HttpCloseTcp4ConnCloseEvent (HttpInstance); + HttpCloseTcpConnCloseEvent (HttpInstance); return Status; } /** - Close events in the TCP4 connection token and TCP4 close token. + Close events in the TCP connection token and TCP close token. @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure. **/ VOID -HttpCloseTcp4ConnCloseEvent ( +HttpCloseTcpConnCloseEvent ( IN HTTP_PROTOCOL *HttpInstance ) { ASSERT (HttpInstance != NULL); - if (NULL != HttpInstance->ConnToken.CompletionToken.Event) { - gBS->CloseEvent (HttpInstance->ConnToken.CompletionToken.Event); - HttpInstance->ConnToken.CompletionToken.Event = NULL; - } + if (HttpInstance->LocalAddressIsIPv6) { + if (NULL != HttpInstance->Tcp6ConnToken.CompletionToken.Event) { + gBS->CloseEvent (HttpInstance->Tcp6ConnToken.CompletionToken.Event); + HttpInstance->Tcp6ConnToken.CompletionToken.Event = NULL; + } - if (NULL != HttpInstance->CloseToken.CompletionToken.Event) { - gBS->CloseEvent(HttpInstance->CloseToken.CompletionToken.Event); - HttpInstance->CloseToken.CompletionToken.Event = NULL; - } + if (NULL != HttpInstance->Tcp6CloseToken.CompletionToken.Event) { + gBS->CloseEvent(HttpInstance->Tcp6CloseToken.CompletionToken.Event); + HttpInstance->Tcp6CloseToken.CompletionToken.Event = NULL; + } + + } else { + if (NULL != HttpInstance->Tcp4ConnToken.CompletionToken.Event) { + gBS->CloseEvent (HttpInstance->Tcp4ConnToken.CompletionToken.Event); + HttpInstance->Tcp4ConnToken.CompletionToken.Event = NULL; + } + + if (NULL != HttpInstance->Tcp4CloseToken.CompletionToken.Event) { + gBS->CloseEvent(HttpInstance->Tcp4CloseToken.CompletionToken.Event); + HttpInstance->Tcp4CloseToken.CompletionToken.Event = NULL; + } + } + } /** - Create event for the TCP4 transmit token. + Create event for the TCP transmit token. @param[in] Wrap Point to HTTP token's wrap data. @@ -302,7 +387,7 @@ HttpCloseTcp4ConnCloseEvent ( **/ EFI_STATUS -HttpCreateTcp4TxEvent ( +HttpCreateTcpTxEvent ( IN HTTP_TOKEN_WRAP *Wrap ) { @@ -313,28 +398,50 @@ HttpCreateTcp4TxEvent ( HttpInstance = Wrap->HttpInstance; TcpWrap = &Wrap->TcpWrap; - Status = gBS->CreateEvent ( - EVT_NOTIFY_SIGNAL, - TPL_NOTIFY, - HttpTcpTransmitNotify, - Wrap, - &TcpWrap->TxToken.CompletionToken.Event - ); - if (EFI_ERROR (Status)) { - return Status; - } + if (!HttpInstance->LocalAddressIsIPv6) { + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + HttpTcpTransmitNotify, + Wrap, + &TcpWrap->Tx4Token.CompletionToken.Event + ); + if (EFI_ERROR (Status)) { + return Status; + } + + TcpWrap->Tx4Data.Push = TRUE; + TcpWrap->Tx4Data.Urgent = FALSE; + TcpWrap->Tx4Data.FragmentCount = 1; + TcpWrap->Tx4Token.Packet.TxData = &Wrap->TcpWrap.Tx4Data; + TcpWrap->Tx4Token.CompletionToken.Status = EFI_NOT_READY; - TcpWrap->TxData.Push = TRUE; - TcpWrap->TxData.Urgent = FALSE; - TcpWrap->TxData.FragmentCount = 1; - TcpWrap->TxToken.Packet.TxData = &Wrap->TcpWrap.TxData; - TcpWrap->TxToken.CompletionToken.Status = EFI_NOT_READY; + } else { + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + HttpTcpTransmitNotify, + Wrap, + &TcpWrap->Tx6Token.CompletionToken.Event + ); + if (EFI_ERROR (Status)) { + return Status; + } + TcpWrap->Tx6Data.Push = TRUE; + TcpWrap->Tx6Data.Urgent = FALSE; + TcpWrap->Tx6Data.FragmentCount = 1; + TcpWrap->Tx6Token.Packet.TxData = &Wrap->TcpWrap.Tx6Data; + TcpWrap->Tx6Token.CompletionToken.Status =EFI_NOT_READY; + + + } + return EFI_SUCCESS; } /** - Create event for the TCP4 receive token which is used to receive HTTP header. + Create event for the TCP receive token which is used to receive HTTP header. @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure. @@ -343,33 +450,52 @@ HttpCreateTcp4TxEvent ( **/ EFI_STATUS -HttpCreateTcp4RxEventForHeader ( +HttpCreateTcpRxEventForHeader ( IN HTTP_PROTOCOL *HttpInstance ) { EFI_STATUS Status; + if (!HttpInstance->LocalAddressIsIPv6) { + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + HttpCommonNotify, + &HttpInstance->IsRxDone, + &HttpInstance->Rx4Token.CompletionToken.Event + ); + if (EFI_ERROR (Status)) { + return Status; + } + + HttpInstance->Rx4Data.FragmentCount = 1; + HttpInstance->Rx4Token.Packet.RxData = &HttpInstance->Rx4Data; + HttpInstance->Rx4Token.CompletionToken.Status = EFI_NOT_READY; - Status = gBS->CreateEvent ( - EVT_NOTIFY_SIGNAL, - TPL_NOTIFY, - HttpCommonNotify, - &HttpInstance->IsRxDone, - &HttpInstance->RxToken.CompletionToken.Event - ); - if (EFI_ERROR (Status)) { - return Status; + } else { + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + HttpCommonNotify, + &HttpInstance->IsRxDone, + &HttpInstance->Rx6Token.CompletionToken.Event + ); + if (EFI_ERROR (Status)) { + return Status; + } + + HttpInstance->Rx6Data.FragmentCount =1; + HttpInstance->Rx6Token.Packet.RxData = &HttpInstance->Rx6Data; + HttpInstance->Rx6Token.CompletionToken.Status = EFI_NOT_READY; + } - HttpInstance->RxData.FragmentCount = 1; - HttpInstance->RxToken.Packet.RxData = &HttpInstance->RxData; - HttpInstance->RxToken.CompletionToken.Status = EFI_NOT_READY; return EFI_SUCCESS; } /** - Create event for the TCP4 receive token which is used to receive HTTP body. + Create event for the TCP receive token which is used to receive HTTP body. @param[in] Wrap Point to HTTP token's wrap data. @@ -378,7 +504,7 @@ HttpCreateTcp4RxEventForHeader ( **/ EFI_STATUS -HttpCreateTcp4RxEvent ( +HttpCreateTcpRxEvent ( IN HTTP_TOKEN_WRAP *Wrap ) { @@ -388,30 +514,91 @@ HttpCreateTcp4RxEvent ( HttpInstance = Wrap->HttpInstance; TcpWrap = &Wrap->TcpWrap; + if (!HttpInstance->LocalAddressIsIPv6) { + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + HttpTcpReceiveNotify, + Wrap, + &TcpWrap->Rx4Token.CompletionToken.Event + ); + if (EFI_ERROR (Status)) { + return Status; + } + + TcpWrap->Rx4Data.FragmentCount = 1; + TcpWrap->Rx4Token.Packet.RxData = &Wrap->TcpWrap.Rx4Data; + TcpWrap->Rx4Token.CompletionToken.Status = EFI_NOT_READY; - Status = gBS->CreateEvent ( - EVT_NOTIFY_SIGNAL, - TPL_NOTIFY, - HttpTcpReceiveNotify, - Wrap, - &TcpWrap->RxToken.CompletionToken.Event - ); - if (EFI_ERROR (Status)) { - return Status; + } else { + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + HttpTcpReceiveNotify, + Wrap, + &TcpWrap->Rx6Token.CompletionToken.Event + ); + if (EFI_ERROR (Status)) { + return Status; + } + + TcpWrap->Rx6Data.FragmentCount = 1; + TcpWrap->Rx6Token.Packet.RxData = &Wrap->TcpWrap.Rx6Data; + TcpWrap->Rx6Token.CompletionToken.Status = EFI_NOT_READY; } + + return EFI_SUCCESS; +} - TcpWrap->RxData.FragmentCount = 1; - TcpWrap->RxToken.Packet.RxData = &Wrap->TcpWrap.RxData; - TcpWrap->RxToken.CompletionToken.Status = EFI_NOT_READY; +/** + Close Events for Tcp Receive Tokens for HTTP body and HTTP header. - return EFI_SUCCESS; + @param[in] Wrap Pointer to HTTP token's wrap data. + +**/ +VOID +HttpCloseTcpRxEvent ( + IN HTTP_TOKEN_WRAP *Wrap + ) +{ + HTTP_PROTOCOL *HttpInstance; + EFI_TCP4_IO_TOKEN *Rx4Token; + EFI_TCP6_IO_TOKEN *Rx6Token; + + HttpInstance = Wrap->HttpInstance; + Rx4Token = NULL; + Rx6Token = NULL; + + if (HttpInstance->LocalAddressIsIPv6) { + if (Wrap != NULL) { + if (Wrap->TcpWrap.Rx6Token.CompletionToken.Event != NULL) { + gBS->CloseEvent (Wrap->TcpWrap.Rx6Token.CompletionToken.Event); + } + } + + if (HttpInstance->Rx6Token.CompletionToken.Event != NULL) { + gBS->CloseEvent (HttpInstance->Rx6Token.CompletionToken.Event); + HttpInstance->Rx6Token.CompletionToken.Event = NULL; + } + } else { + if (Wrap != NULL) { + if (Wrap->TcpWrap.Rx4Token.CompletionToken.Event != NULL) { + gBS->CloseEvent (Wrap->TcpWrap.Rx4Token.CompletionToken.Event); + } + } + + if (HttpInstance->Rx4Token.CompletionToken.Event != NULL) { + gBS->CloseEvent (HttpInstance->Rx4Token.CompletionToken.Event); + HttpInstance->Rx4Token.CompletionToken.Event = NULL; + } + } } /** Intiialize the HTTP_PROTOCOL structure to the unconfigured state. - @param[in] HttpSb The HTTP service private instance. @param[in, out] HttpInstance Pointer to HTTP_PROTOCOL structure. + @param[in] IpVersion Indicate us TCP4 protocol or TCP6 protocol. @retval EFI_SUCCESS HTTP_PROTOCOL structure is initialized successfully. @retval Others Other error as indicated. @@ -419,95 +606,198 @@ HttpCreateTcp4RxEvent ( **/ EFI_STATUS HttpInitProtocol ( - IN HTTP_SERVICE *HttpSb, - IN OUT HTTP_PROTOCOL *HttpInstance + IN OUT HTTP_PROTOCOL *HttpInstance, + IN BOOLEAN IpVersion ) { EFI_STATUS Status; VOID *Interface; + BOOLEAN UsingIpv6; + + ASSERT (HttpInstance != NULL); + UsingIpv6 = IpVersion; + + if (!UsingIpv6) { + // + // Create TCP4 child. + // + Status = NetLibCreateServiceChild ( + HttpInstance->Service->ControllerHandle, + HttpInstance->Service->ImageHandle, + &gEfiTcp4ServiceBindingProtocolGuid, + &HttpInstance->Tcp4ChildHandle + ); - ASSERT ((HttpSb != NULL) && (HttpInstance != NULL)); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } - HttpInstance->Signature = HTTP_PROTOCOL_SIGNATURE; - CopyMem (&HttpInstance->Http, &mEfiHttpTemplate, sizeof (HttpInstance->Http)); - HttpInstance->Service = HttpSb; + Status = gBS->OpenProtocol ( + HttpInstance->Tcp4ChildHandle, + &gEfiTcp4ProtocolGuid, + (VOID **) &Interface, + HttpInstance->Service->ImageHandle, + HttpInstance->Service->ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } - // - // Create TCP child. - // - Status = NetLibCreateServiceChild ( - HttpInstance->Service->ControllerHandle, - HttpInstance->Service->ImageHandle, - &gEfiTcp4ServiceBindingProtocolGuid, - &HttpInstance->TcpChildHandle - ); + Status = gBS->OpenProtocol ( + HttpInstance->Tcp4ChildHandle, + &gEfiTcp4ProtocolGuid, + (VOID **) &HttpInstance->Tcp4, + HttpInstance->Service->ImageHandle, + HttpInstance->Handle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + if (EFI_ERROR(Status)) { + goto ON_ERROR; + } - if (EFI_ERROR (Status)) { - goto ON_ERROR; - } + Status = gBS->OpenProtocol ( + HttpInstance->Service->Tcp4ChildHandle, + &gEfiTcp4ProtocolGuid, + (VOID **) &Interface, + HttpInstance->Service->ImageHandle, + HttpInstance->Handle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + if (EFI_ERROR(Status)) { + goto ON_ERROR; + } + } else { + // + // Create TCP6 Child. + // + Status = NetLibCreateServiceChild ( + HttpInstance->Service->ControllerHandle, + HttpInstance->Service->ImageHandle, + &gEfiTcp6ServiceBindingProtocolGuid, + &HttpInstance->Tcp6ChildHandle + ); - Status = gBS->OpenProtocol ( - HttpInstance->TcpChildHandle, - &gEfiTcp4ProtocolGuid, - (VOID **) &Interface, - HttpInstance->Service->ImageHandle, - HttpInstance->Service->ControllerHandle, - EFI_OPEN_PROTOCOL_BY_DRIVER - ); - - if (EFI_ERROR (Status)) { - goto ON_ERROR; - } + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } - Status = gBS->OpenProtocol ( - HttpInstance->TcpChildHandle, - &gEfiTcp4ProtocolGuid, - (VOID **) &HttpInstance->Tcp4, - HttpInstance->Service->ImageHandle, - HttpInstance->Handle, - EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER - ); - if (EFI_ERROR(Status)) { - goto ON_ERROR; - } + Status = gBS->OpenProtocol ( + HttpInstance->Tcp6ChildHandle, + &gEfiTcp6ProtocolGuid, + (VOID **) &Interface, + HttpInstance->Service->ImageHandle, + HttpInstance->Service->ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + Status = gBS->OpenProtocol ( + HttpInstance->Tcp6ChildHandle, + &gEfiTcp6ProtocolGuid, + (VOID **) &HttpInstance->Tcp6, + HttpInstance->Service->ImageHandle, + HttpInstance->Handle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + + if (EFI_ERROR(Status)) { + goto ON_ERROR; + } + + Status = gBS->OpenProtocol ( + HttpInstance->Service->Tcp6ChildHandle, + &gEfiTcp6ProtocolGuid, + (VOID **) &Interface, + HttpInstance->Service->ImageHandle, + HttpInstance->Handle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + if (EFI_ERROR(Status)) { + goto ON_ERROR; + } + } + HttpInstance->Url = AllocateZeroPool (HTTP_URL_BUFFER_LEN); if (HttpInstance->Url == NULL) { Status = EFI_OUT_OF_RESOURCES; goto ON_ERROR; } - NetMapInit (&HttpInstance->TxTokens); - NetMapInit (&HttpInstance->RxTokens); - return EFI_SUCCESS; ON_ERROR: - if (HttpInstance->TcpChildHandle != NULL) { + if (HttpInstance->Tcp4ChildHandle != NULL) { gBS->CloseProtocol ( - HttpInstance->TcpChildHandle, + HttpInstance->Tcp4ChildHandle, &gEfiTcp4ProtocolGuid, HttpInstance->Service->ImageHandle, HttpInstance->Service->ControllerHandle ); gBS->CloseProtocol ( - HttpInstance->TcpChildHandle, + HttpInstance->Tcp4ChildHandle, &gEfiTcp4ProtocolGuid, HttpInstance->Service->ImageHandle, HttpInstance->Handle - ); + ); NetLibDestroyServiceChild ( HttpInstance->Service->ControllerHandle, HttpInstance->Service->ImageHandle, &gEfiTcp4ServiceBindingProtocolGuid, - HttpInstance->TcpChildHandle + HttpInstance->Tcp4ChildHandle ); } + + if (HttpInstance->Service->Tcp4ChildHandle != NULL) { + gBS->CloseProtocol ( + HttpInstance->Service->Tcp4ChildHandle, + &gEfiTcp4ProtocolGuid, + HttpInstance->Service->ImageHandle, + HttpInstance->Handle + ); + } + + if (HttpInstance->Tcp6ChildHandle != NULL) { + gBS->CloseProtocol ( + HttpInstance->Tcp6ChildHandle, + &gEfiTcp6ProtocolGuid, + HttpInstance->Service->ImageHandle, + HttpInstance->Service->ControllerHandle + ); - return Status; + gBS->CloseProtocol ( + HttpInstance->Tcp6ChildHandle, + &gEfiTcp6ProtocolGuid, + HttpInstance->Service->ImageHandle, + HttpInstance->Handle + ); + + NetLibDestroyServiceChild ( + HttpInstance->Service->ControllerHandle, + HttpInstance->Service->ImageHandle, + &gEfiTcp6ServiceBindingProtocolGuid, + HttpInstance->Tcp6ChildHandle + ); + } + + if (HttpInstance->Service->Tcp6ChildHandle != NULL) { + gBS->CloseProtocol ( + HttpInstance->Service->Tcp6ChildHandle, + &gEfiTcp6ProtocolGuid, + HttpInstance->Service->ImageHandle, + HttpInstance->Handle + ); + } + + return EFI_UNSUPPORTED; } @@ -524,7 +814,7 @@ HttpCleanProtocol ( { HttpCloseConnection (HttpInstance); - HttpCloseTcp4ConnCloseEvent (HttpInstance); + HttpCloseTcpConnCloseEvent (HttpInstance); if (HttpInstance->CacheBody != NULL) { FreePool (HttpInstance->CacheBody); @@ -541,25 +831,25 @@ HttpCleanProtocol ( HttpFreeMsgParser (HttpInstance->MsgParser); HttpInstance->MsgParser = NULL; } - + if (HttpInstance->Url != NULL) { FreePool (HttpInstance->Url); HttpInstance->Url = NULL; } - + NetMapClean (&HttpInstance->TxTokens); NetMapClean (&HttpInstance->RxTokens); - if (HttpInstance->TcpChildHandle != NULL) { + if (HttpInstance->Tcp4ChildHandle != NULL) { gBS->CloseProtocol ( - HttpInstance->TcpChildHandle, + HttpInstance->Tcp4ChildHandle, &gEfiTcp4ProtocolGuid, HttpInstance->Service->ImageHandle, HttpInstance->Service->ControllerHandle ); gBS->CloseProtocol ( - HttpInstance->TcpChildHandle, + HttpInstance->Tcp4ChildHandle, &gEfiTcp4ProtocolGuid, HttpInstance->Service->ImageHandle, HttpInstance->Handle @@ -569,9 +859,51 @@ HttpCleanProtocol ( HttpInstance->Service->ControllerHandle, HttpInstance->Service->ImageHandle, &gEfiTcp4ServiceBindingProtocolGuid, - HttpInstance->TcpChildHandle + HttpInstance->Tcp4ChildHandle + ); + } + + if (HttpInstance->Service->Tcp4ChildHandle != NULL) { + gBS->CloseProtocol ( + HttpInstance->Service->Tcp4ChildHandle, + &gEfiTcp4ProtocolGuid, + HttpInstance->Service->ImageHandle, + HttpInstance->Handle + ); + } + + if (HttpInstance->Tcp6ChildHandle != NULL) { + gBS->CloseProtocol ( + HttpInstance->Tcp6ChildHandle, + &gEfiTcp6ProtocolGuid, + HttpInstance->Service->ImageHandle, + HttpInstance->Service->ControllerHandle + ); + + gBS->CloseProtocol ( + HttpInstance->Tcp6ChildHandle, + &gEfiTcp6ProtocolGuid, + HttpInstance->Service->ImageHandle, + HttpInstance->Handle + ); + + NetLibDestroyServiceChild ( + HttpInstance->Service->ControllerHandle, + HttpInstance->Service->ImageHandle, + &gEfiTcp6ServiceBindingProtocolGuid, + HttpInstance->Tcp6ChildHandle ); } + + if (HttpInstance->Service->Tcp6ChildHandle != NULL) { + gBS->CloseProtocol ( + HttpInstance->Service->Tcp6ChildHandle, + &gEfiTcp6ProtocolGuid, + HttpInstance->Service->ImageHandle, + HttpInstance->Handle + ); + } + } /** @@ -590,27 +922,40 @@ HttpCreateConnection ( { EFI_STATUS Status; - // - // Create events for variuos asynchronous operations. - // - HttpInstance->IsConnDone = FALSE; - // // Connect to Http server // - HttpInstance->ConnToken.CompletionToken.Status = EFI_NOT_READY; - Status = HttpInstance->Tcp4->Connect (HttpInstance->Tcp4, &HttpInstance->ConnToken); - if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "HttpCreateConnection: Tcp4->Connect() = %r\n", Status)); - return Status; - } - - while (!HttpInstance->IsConnDone) { - HttpInstance->Tcp4->Poll (HttpInstance->Tcp4); - } + if (!HttpInstance->LocalAddressIsIPv6) { + HttpInstance->IsTcp4ConnDone = FALSE; + HttpInstance->Tcp4ConnToken.CompletionToken.Status = EFI_NOT_READY; + Status = HttpInstance->Tcp4->Connect (HttpInstance->Tcp4, &HttpInstance->Tcp4ConnToken); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "HttpCreateConnection: Tcp4->Connect() = %r\n", Status)); + return Status; + } + + while (!HttpInstance->IsTcp4ConnDone) { + HttpInstance->Tcp4->Poll (HttpInstance->Tcp4); + } + + Status = HttpInstance->Tcp4ConnToken.CompletionToken.Status; + + } else { + HttpInstance->IsTcp6ConnDone = FALSE; + HttpInstance->Tcp6ConnToken.CompletionToken.Status = EFI_NOT_READY; + Status = HttpInstance->Tcp6->Connect (HttpInstance->Tcp6, &HttpInstance->Tcp6ConnToken); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "HttpCreateConnection: Tcp6->Connect() = %r\n", Status)); + return Status; + } - Status = HttpInstance->ConnToken.CompletionToken.Status; + while(!HttpInstance->IsTcp6ConnDone) { + HttpInstance->Tcp6->Poll (HttpInstance->Tcp6); + } + Status = HttpInstance->Tcp6ConnToken.CompletionToken.Status; + } + if (!EFI_ERROR (Status)) { HttpInstance->State = HTTP_STATE_TCP_CONNECTED; } @@ -635,17 +980,32 @@ HttpCloseConnection ( EFI_STATUS Status; if (HttpInstance->State == HTTP_STATE_TCP_CONNECTED) { - HttpInstance->CloseToken.AbortOnClose = TRUE; - HttpInstance->IsCloseDone = FALSE; - - Status = HttpInstance->Tcp4->Close (HttpInstance->Tcp4, &HttpInstance->CloseToken); - if (EFI_ERROR (Status)) { - return Status; - } - while (!HttpInstance->IsCloseDone) { - HttpInstance->Tcp4->Poll (HttpInstance->Tcp4); + if (HttpInstance->LocalAddressIsIPv6) { + HttpInstance->Tcp6CloseToken.AbortOnClose = TRUE; + HttpInstance->IsTcp6CloseDone = FALSE; + Status = HttpInstance->Tcp6->Close (HttpInstance->Tcp6, &HttpInstance->Tcp6CloseToken); + if (EFI_ERROR (Status)) { + return Status; + } + + while (!HttpInstance->IsTcp6CloseDone) { + HttpInstance->Tcp6->Poll (HttpInstance->Tcp6); + } + + } else { + HttpInstance->Tcp4CloseToken.AbortOnClose = TRUE; + HttpInstance->IsTcp4CloseDone = FALSE; + Status = HttpInstance->Tcp4->Close (HttpInstance->Tcp4, &HttpInstance->Tcp4CloseToken); + if (EFI_ERROR (Status)) { + return Status; + } + + while (!HttpInstance->IsTcp4CloseDone) { + HttpInstance->Tcp4->Poll (HttpInstance->Tcp4); + } } + } HttpInstance->State = HTTP_STATE_TCP_CLOSED; @@ -716,12 +1076,82 @@ HttpConfigureTcp4 ( return Status; } - Status = HttpCreateTcp4ConnCloseEvent (HttpInstance); + Status = HttpCreateTcpConnCloseEvent (HttpInstance); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = HttpCreateTcpTxEvent (Wrap); + if (EFI_ERROR (Status)) { + return Status; + } + + HttpInstance->State = HTTP_STATE_TCP_CONFIGED; + + return EFI_SUCCESS; +} + +/** + Configure TCP6 protocol child. + + @param[in] HttpInstance The HTTP instance private data. + @param[in] Wrap The HTTP token's wrap data. + + @retval EFI_SUCCESS The TCP6 protocol child is configured. + @retval Others Other error as indicated. + +**/ +EFI_STATUS +HttpConfigureTcp6 ( + IN HTTP_PROTOCOL *HttpInstance, + IN HTTP_TOKEN_WRAP *Wrap + ) +{ + EFI_STATUS Status; + EFI_TCP6_CONFIG_DATA *Tcp6CfgData; + EFI_TCP6_ACCESS_POINT *Tcp6Ap; + EFI_TCP6_OPTION *Tcp6Option; + + ASSERT (HttpInstance != NULL); + + Tcp6CfgData = &HttpInstance->Tcp6CfgData; + ZeroMem (Tcp6CfgData, sizeof (EFI_TCP6_CONFIG_DATA)); + + Tcp6CfgData->TrafficClass = 0; + Tcp6CfgData->HopLimit = 255; + Tcp6CfgData->ControlOption = &HttpInstance->Tcp6Option; + + Tcp6Ap = &Tcp6CfgData->AccessPoint; + Tcp6Ap->ActiveFlag = TRUE; + Tcp6Ap->StationPort = HttpInstance->Ipv6Node.LocalPort; + Tcp6Ap->RemotePort = HttpInstance->RemotePort; + IP6_COPY_ADDRESS (&Tcp6Ap->StationAddress, &HttpInstance->Ipv6Node.LocalAddress); + IP6_COPY_ADDRESS (&Tcp6Ap->RemoteAddress , &HttpInstance->RemoteIpv6Addr); + + Tcp6Option = Tcp6CfgData->ControlOption; + Tcp6Option->ReceiveBufferSize = HTTP_BUFFER_SIZE_DEAULT; + Tcp6Option->SendBufferSize = HTTP_BUFFER_SIZE_DEAULT; + Tcp6Option->MaxSynBackLog = HTTP_MAX_SYN_BACK_LOG; + Tcp6Option->ConnectionTimeout = HTTP_CONNECTION_TIMEOUT; + Tcp6Option->DataRetries = HTTP_DATA_RETRIES; + Tcp6Option->FinTimeout = HTTP_FIN_TIMEOUT; + Tcp6Option->KeepAliveProbes = HTTP_KEEP_ALIVE_PROBES; + Tcp6Option->KeepAliveTime = HTTP_KEEP_ALIVE_TIME; + Tcp6Option->KeepAliveInterval = HTTP_KEEP_ALIVE_INTERVAL; + Tcp6Option->EnableNagle = TRUE; + + Status = HttpInstance->Tcp6->Configure (HttpInstance->Tcp6, Tcp6CfgData); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "HttpConfigureTcp6 - %r\n", Status)); + return Status; + } + + Status = HttpCreateTcpConnCloseEvent (HttpInstance); if (EFI_ERROR (Status)) { return Status; } - Status = HttpCreateTcp4TxEvent (Wrap); + Status = HttpCreateTcpTxEvent (Wrap); if (EFI_ERROR (Status)) { return Status; } @@ -729,10 +1159,11 @@ HttpConfigureTcp4 ( HttpInstance->State = HTTP_STATE_TCP_CONFIGED; return EFI_SUCCESS; + } /** - Check existing TCP connection, if in error state, receover TCP4 connection. + Check existing TCP connection, if in error state, recover TCP4 connection. @param[in] HttpInstance The HTTP instance private data. @@ -775,7 +1206,105 @@ HttpConnectTcp4 ( } /** - Send the HTTP message through TCP4. + Check existing TCP connection, if in error state, recover TCP6 connection. + + @param[in] HttpInstance The HTTP instance private data. + + @retval EFI_SUCCESS The TCP connection is established. + @retval EFI_NOT_READY TCP6 protocol child is not created or configured. + @retval Others Other error as indicated. + +**/ +EFI_STATUS +HttpConnectTcp6 ( + IN HTTP_PROTOCOL *HttpInstance + ) +{ + EFI_STATUS Status; + EFI_TCP6_CONNECTION_STATE Tcp6State; + + if (HttpInstance->State != HTTP_STATE_TCP_CONFIGED || HttpInstance->Tcp6 == NULL) { + return EFI_NOT_READY; + } + + Status = HttpInstance->Tcp6->GetModeData ( + HttpInstance->Tcp6, + &Tcp6State, + NULL, + NULL, + NULL, + NULL + ); + + if (EFI_ERROR(Status)){ + DEBUG ((EFI_D_ERROR, "Tcp6 GetModeData fail - %x\n", Status)); + return Status; + } + + if (Tcp6State > Tcp6StateEstablished) { + HttpCloseConnection (HttpInstance); + } + + return HttpCreateConnection (HttpInstance); +} + +/** + Initialize TCP related data. + + @param[in] HttpInstance The HTTP instance private data. + @param[in] Wrap The HTTP token's wrap data. + + @retval EFI_SUCCESS The initialization of TCP instance is done. + @retval Others Other error as indicated. + +**/ +EFI_STATUS +HttpInitTcp ( + IN HTTP_PROTOCOL *HttpInstance, + IN HTTP_TOKEN_WRAP *Wrap + ) +{ + EFI_STATUS Status; + ASSERT (HttpInstance != NULL); + + if (!HttpInstance->LocalAddressIsIPv6) { + // + // Configure TCP instance. + // + Status = HttpConfigureTcp4 (HttpInstance, Wrap); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Connect TCP. + // + Status = HttpConnectTcp4 (HttpInstance); + if (EFI_ERROR (Status)) { + return Status; + } + } else { + // + // Configure TCP instance. + // + Status = HttpConfigureTcp6 (HttpInstance, Wrap); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Connect TCP. + // + Status = HttpConnectTcp6 (HttpInstance); + if (EFI_ERROR (Status)) { + return Status; + } + } + + return EFI_SUCCESS; + +} + +/** + Send the HTTP message through TCP4 or TCP6. @param[in] HttpInstance The HTTP instance private data. @param[in] Wrap The HTTP token's wrap data. @@ -787,7 +1316,7 @@ HttpConnectTcp4 ( **/ EFI_STATUS -HttpTransmitTcp4 ( +HttpTransmitTcp ( IN HTTP_PROTOCOL *HttpInstance, IN HTTP_TOKEN_WRAP *Wrap, IN UINT8 *TxString, @@ -795,23 +1324,44 @@ HttpTransmitTcp4 ( ) { EFI_STATUS Status; - EFI_TCP4_IO_TOKEN *TxToken; + EFI_TCP4_IO_TOKEN *Tx4Token; EFI_TCP4_PROTOCOL *Tcp4; + EFI_TCP6_IO_TOKEN *Tx6Token; + EFI_TCP6_PROTOCOL *Tcp6; - Tcp4 = HttpInstance->Tcp4; - TxToken = &Wrap->TcpWrap.TxToken; + if (!HttpInstance->LocalAddressIsIPv6) { + Tcp4 = HttpInstance->Tcp4; + Tx4Token = &Wrap->TcpWrap.Tx4Token; + + Tx4Token->Packet.TxData->DataLength = (UINT32) TxStringLen; + Tx4Token->Packet.TxData->FragmentTable[0].FragmentLength = (UINT32) TxStringLen; + Tx4Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *) TxString; + Tx4Token->CompletionToken.Status = EFI_NOT_READY; + + Wrap->TcpWrap.IsTxDone = FALSE; + Status = Tcp4->Transmit (Tcp4, Tx4Token); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Transmit failed: %r\n", Status)); + return Status; + } - TxToken->Packet.TxData->DataLength = (UINT32) TxStringLen; - TxToken->Packet.TxData->FragmentTable[0].FragmentLength = (UINT32) TxStringLen; - TxToken->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *) TxString; - TxToken->CompletionToken.Status = EFI_NOT_READY; + } else { + Tcp6 = HttpInstance->Tcp6; + Tx6Token = &Wrap->TcpWrap.Tx6Token; - Wrap->TcpWrap.IsTxDone = FALSE; - Status = Tcp4->Transmit (Tcp4, TxToken); - if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "Transmit failed: %r\n", Status)); - return Status; + Tx6Token->Packet.TxData->DataLength = (UINT32) TxStringLen; + Tx6Token->Packet.TxData->FragmentTable[0].FragmentLength = (UINT32) TxStringLen; + Tx6Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *) TxString; + Tx6Token->CompletionToken.Status = EFI_NOT_READY; + + Wrap->TcpWrap.IsTxDone = FALSE; + Status = Tcp6->Transmit (Tcp6, Tx6Token); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Transmit failed: %r\n", Status)); + return Status; + } } + return Status; } @@ -919,7 +1469,7 @@ HttpMappingToStatusCode ( /** Check whether the user's token or event has already - been enqueue on HTTP TxToken or RxToken list. + been enqueue on HTTP Tx or Rx Token list. @param[in] Map The container of either user's transmit or receive token. @@ -953,9 +1503,9 @@ HttpTokenExist ( } /** - Check whether the HTTP message associated with TxToken is already sent out. + Check whether the HTTP message associated with Tx4Token or Tx6Token is already sent out. - @param[in] Map The container of TxToken. + @param[in] Map The container of Tx4Token or Tx6Token. @param[in] Item Current item to check against. @param[in] Context The Token to check againist. @@ -985,7 +1535,7 @@ HttpTcpNotReady ( /** Transmit the HTTP mssage by processing the associated HTTP token. - @param[in] Map The container of TxToken. + @param[in] Map The container of Tx4Token or Tx6Token. @param[in] Item Current item to check against. @param[in] Context The Token to check againist. @@ -1038,7 +1588,7 @@ HttpTcpTransmit ( // // Transmit the request message. // - Status = HttpTransmitTcp4 ( + Status = HttpTransmitTcp ( ValueInItem->HttpInstance, ValueInItem, (UINT8*) RequestStr, @@ -1051,7 +1601,7 @@ HttpTcpTransmit ( /** Receive the HTTP response by processing the associated HTTP token. - @param[in] Map The container of RxToken. + @param[in] Map The container of Rx4Token or Rx6Token. @param[in] Item Current item to check against. @param[in] Context The Token to check againist. @@ -1074,6 +1624,319 @@ HttpTcpReceive ( return HttpResponseWorker ((HTTP_TOKEN_WRAP *) Item->Value); } +/** + Receive the HTTP header by processing the associated HTTP token. + + @param[in] HttpInstance The HTTP instance private data. + @param[in, out] SizeofHeaders The HTTP header length. + @param[in, out] BufferSize The size of buffer to cacahe the header message. + + @retval EFI_SUCCESS The HTTP header is received. + @retval Others Other errors as indicated. + +**/ +EFI_STATUS +HttpTcpReceiveHeader ( + IN HTTP_PROTOCOL *HttpInstance, + IN OUT UINTN *SizeofHeaders, + IN OUT UINTN *BufferSize + ) +{ + EFI_STATUS Status; + EFI_TCP4_IO_TOKEN *Rx4Token; + EFI_TCP4_PROTOCOL *Tcp4; + EFI_TCP6_IO_TOKEN *Rx6Token; + EFI_TCP6_PROTOCOL *Tcp6; + CHAR8 **EndofHeader; + CHAR8 **HttpHeaders; + CHAR8 *Buffer; + + ASSERT (HttpInstance != NULL); + + EndofHeader = HttpInstance->EndofHeader; + HttpHeaders = HttpInstance->HttpHeaders; + Tcp4 = HttpInstance->Tcp4; + Tcp6 = HttpInstance->Tcp6; + Buffer = NULL; + Rx4Token = NULL; + Rx6Token = NULL; + + if (HttpInstance->LocalAddressIsIPv6) { + ASSERT (Tcp6 != NULL); + } else { + ASSERT (Tcp4 != NULL); + } + + if (!HttpInstance->LocalAddressIsIPv6) { + Rx4Token = &HttpInstance->Rx4Token; + Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = AllocateZeroPool (DEF_BUF_LEN); + if (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer == NULL) { + Status = EFI_OUT_OF_RESOURCES; + return Status; + } + + // + // Receive the HTTP headers only when EFI_HTTP_RESPONSE_DATA is not NULL. + // + while (*EndofHeader == NULL) { + HttpInstance->IsRxDone = FALSE; + Rx4Token->Packet.RxData->DataLength = DEF_BUF_LEN; + Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength = DEF_BUF_LEN; + Status = Tcp4->Receive (Tcp4, Rx4Token); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Tcp4 receive failed: %r\n", Status)); + return Status; + } + + while (!HttpInstance->IsRxDone) { + Tcp4->Poll (Tcp4); + } + + Status = Rx4Token->CompletionToken.Status; + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Append the response string. + // + *BufferSize = (*SizeofHeaders) + Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength; + Buffer = AllocateZeroPool (*BufferSize); + if (Buffer == NULL) { + Status = EFI_OUT_OF_RESOURCES; + return Status; + } + + if (*HttpHeaders != NULL) { + CopyMem (Buffer, *HttpHeaders, (*SizeofHeaders)); + FreePool (*HttpHeaders); + } + + CopyMem ( + Buffer + (*SizeofHeaders), + Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer, + Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength + ); + *HttpHeaders = Buffer; + *SizeofHeaders = *BufferSize; + + // + // Check whether we received end of HTTP headers. + // + *EndofHeader = AsciiStrStr (*HttpHeaders, HTTP_END_OF_HDR_STR); + } + FreePool (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer); + Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL; + + } else { + Rx6Token = &HttpInstance->Rx6Token; + Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = AllocateZeroPool (DEF_BUF_LEN); + if (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer == NULL) { + Status = EFI_OUT_OF_RESOURCES; + return Status; + } + + // + // Receive the HTTP headers only when EFI_HTTP_RESPONSE_DATA is not NULL. + // + while (*EndofHeader == NULL) { + HttpInstance->IsRxDone = FALSE; + Rx6Token->Packet.RxData->DataLength = DEF_BUF_LEN; + Rx6Token->Packet.RxData->FragmentTable[0].FragmentLength = DEF_BUF_LEN; + Status = Tcp6->Receive (Tcp6, Rx6Token); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Tcp6 receive failed: %r\n", Status)); + return Status; + } + + while (!HttpInstance->IsRxDone) { + Tcp6->Poll (Tcp6); + } + + Status = Rx6Token->CompletionToken.Status; + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Append the response string. + // + *BufferSize = (*SizeofHeaders) + Rx6Token->Packet.RxData->FragmentTable[0].FragmentLength; + Buffer = AllocateZeroPool (*BufferSize); + if (Buffer == NULL) { + Status = EFI_OUT_OF_RESOURCES; + return Status; + } + + if (*HttpHeaders != NULL) { + CopyMem (Buffer, *HttpHeaders, (*SizeofHeaders)); + FreePool (*HttpHeaders); + } + + CopyMem ( + Buffer + (*SizeofHeaders), + Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer, + Rx6Token->Packet.RxData->FragmentTable[0].FragmentLength + ); + *HttpHeaders = Buffer; + *SizeofHeaders = *BufferSize; + + // + // Check whether we received end of HTTP headers. + // + *EndofHeader = AsciiStrStr (*HttpHeaders, HTTP_END_OF_HDR_STR); + + } + FreePool (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer); + Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL; + } + + // + // Skip the CRLF after the HTTP headers. + // + *EndofHeader = *EndofHeader + AsciiStrLen (HTTP_END_OF_HDR_STR); + + return EFI_SUCCESS; +} + +/** + Receive the HTTP body by processing the associated HTTP token. + + @param[in] Wrap The HTTP token's wrap data. + @param[in] HttpMsg The HTTP message data. + + @retval EFI_SUCCESS The HTTP body is received. + @retval Others Other error as indicated. + +**/ +EFI_STATUS +HttpTcpReceiveBody ( + IN HTTP_TOKEN_WRAP *Wrap, + IN EFI_HTTP_MESSAGE *HttpMsg + ) +{ + EFI_STATUS Status; + HTTP_PROTOCOL *HttpInstance; + EFI_TCP6_PROTOCOL *Tcp6; + EFI_TCP6_IO_TOKEN *Rx6Token; + EFI_TCP4_PROTOCOL *Tcp4; + EFI_TCP4_IO_TOKEN *Rx4Token; + + HttpInstance = Wrap->HttpInstance; + Tcp4 = HttpInstance->Tcp4; + Tcp6 = HttpInstance->Tcp6; + Rx4Token = NULL; + Rx6Token = NULL; + + + if (HttpInstance->LocalAddressIsIPv6) { + ASSERT (Tcp6 != NULL); + } else { + ASSERT (Tcp4 != NULL); + } + + if (HttpInstance->LocalAddressIsIPv6) { + Rx6Token = &Wrap->TcpWrap.Rx6Token; + Rx6Token ->Packet.RxData->DataLength = (UINT32) HttpMsg->BodyLength; + Rx6Token ->Packet.RxData->FragmentTable[0].FragmentLength = (UINT32) HttpMsg->BodyLength; + Rx6Token ->Packet.RxData->FragmentTable[0].FragmentBuffer = (VOID *) HttpMsg->Body; + Rx6Token->CompletionToken.Status = EFI_NOT_READY; + + Status = Tcp6->Receive (Tcp6, Rx6Token); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Tcp6 receive failed: %r\n", Status)); + return Status; + } + + } else { + Rx4Token = &Wrap->TcpWrap.Rx4Token; + Rx4Token->Packet.RxData->DataLength = (UINT32) HttpMsg->BodyLength; + Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength = (UINT32) HttpMsg->BodyLength; + Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = (VOID *) HttpMsg->Body; + + Rx4Token->CompletionToken.Status = EFI_NOT_READY; + Status = Tcp4->Receive (Tcp4, Rx4Token); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Tcp4 receive failed: %r\n", Status)); + return Status; + } + } + + return EFI_SUCCESS; + +} + +/** + Clean up Tcp Tokens while the Tcp transmission error occurs. + + @param[in] Wrap Pointer to HTTP token's wrap data. + +**/ +VOID +HttpTcpTokenCleanup ( + IN HTTP_TOKEN_WRAP *Wrap + ) +{ + HTTP_PROTOCOL *HttpInstance; + EFI_TCP4_IO_TOKEN *Rx4Token; + EFI_TCP6_IO_TOKEN *Rx6Token; + + HttpInstance = Wrap->HttpInstance; + Rx4Token = NULL; + Rx6Token = NULL; + + if (HttpInstance->LocalAddressIsIPv6) { + if (Wrap != NULL) { + if (Wrap->TcpWrap.Rx6Token.CompletionToken.Event != NULL) { + gBS->CloseEvent (Wrap->TcpWrap.Rx6Token.CompletionToken.Event); + } + + Rx6Token = &Wrap->TcpWrap.Rx6Token; + if (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) { + FreePool (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer); + Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL; + } + FreePool (Wrap); + } + + if (HttpInstance->Rx6Token.CompletionToken.Event != NULL) { + gBS->CloseEvent (HttpInstance->Rx6Token.CompletionToken.Event); + HttpInstance->Rx6Token.CompletionToken.Event = NULL; + } + + Rx6Token = &HttpInstance->Rx6Token; + if (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) { + FreePool (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer); + Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL; + } + + } else { + if (Wrap != NULL) { + if (Wrap->TcpWrap.Rx4Token.CompletionToken.Event != NULL) { + gBS->CloseEvent (Wrap->TcpWrap.Rx4Token.CompletionToken.Event); + } + Rx4Token = &Wrap->TcpWrap.Rx4Token; + if (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) { + FreePool (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer); + Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL; + } + FreePool (Wrap); + } + + if (HttpInstance->Rx4Token.CompletionToken.Event != NULL) { + gBS->CloseEvent (HttpInstance->Rx4Token.CompletionToken.Event); + HttpInstance->Rx4Token.CompletionToken.Event = NULL; + } + + Rx4Token = &HttpInstance->Rx4Token; + if (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) { + FreePool (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer); + Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL; + } + } + +} + /** Generate HTTP request string. diff --git a/NetworkPkg/HttpDxe/HttpProto.h b/NetworkPkg/HttpDxe/HttpProto.h index c37b80c8ec74..a15e0a87be53 100644 --- a/NetworkPkg/HttpDxe/HttpProto.h +++ b/NetworkPkg/HttpDxe/HttpProto.h @@ -27,6 +27,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. HTTP_SERVICE_SIGNATURE \ ) + // // The state of HTTP protocol. It starts from UNCONFIGED. // @@ -58,18 +59,23 @@ typedef struct _HTTP_SERVICE { EFI_SERVICE_BINDING_PROTOCOL ServiceBinding; EFI_HANDLE ImageHandle; EFI_HANDLE ControllerHandle; + EFI_HANDLE Tcp4ChildHandle; + EFI_HANDLE Tcp6ChildHandle; LIST_ENTRY ChildrenList; UINTN ChildrenNumber; - EFI_HANDLE TcpChildHandle; INTN State; } HTTP_SERVICE; typedef struct { - EFI_TCP4_IO_TOKEN TxToken; - EFI_TCP4_TRANSMIT_DATA TxData; + EFI_TCP4_IO_TOKEN Tx4Token; + EFI_TCP4_TRANSMIT_DATA Tx4Data; + EFI_TCP6_IO_TOKEN Tx6Token; + EFI_TCP6_TRANSMIT_DATA Tx6Data; + EFI_TCP4_IO_TOKEN Rx4Token; + EFI_TCP4_RECEIVE_DATA Rx4Data; + EFI_TCP6_IO_TOKEN Rx6Token; + EFI_TCP6_RECEIVE_DATA Rx6Data; BOOLEAN IsTxDone; - EFI_TCP4_IO_TOKEN RxToken; - EFI_TCP4_RECEIVE_DATA RxData; BOOLEAN IsRxDone; UINTN BodyLen; EFI_HTTP_METHOD Method; @@ -84,26 +90,43 @@ typedef struct _HTTP_PROTOCOL { BOOLEAN InDestroy; INTN State; - EFI_HANDLE TcpChildHandle; + EFI_HANDLE Tcp4ChildHandle; EFI_TCP4_PROTOCOL *Tcp4; EFI_TCP4_CONFIG_DATA Tcp4CfgData; EFI_TCP4_OPTION Tcp4Option; - EFI_TCP4_CONNECTION_TOKEN ConnToken; - BOOLEAN IsConnDone; - EFI_TCP4_CLOSE_TOKEN CloseToken; - BOOLEAN IsCloseDone; - + EFI_TCP4_CONNECTION_TOKEN Tcp4ConnToken; + BOOLEAN IsTcp4ConnDone; + EFI_TCP4_CLOSE_TOKEN Tcp4CloseToken; + BOOLEAN IsTcp4CloseDone; CHAR8 *RemoteHost; UINT16 RemotePort; EFI_IPv4_ADDRESS RemoteAddr; + + EFI_HANDLE Tcp6ChildHandle; + EFI_TCP6_PROTOCOL *Tcp6; + EFI_TCP6_CONFIG_DATA Tcp6CfgData; + EFI_TCP6_OPTION Tcp6Option; + + EFI_TCP6_CONNECTION_TOKEN Tcp6ConnToken; + BOOLEAN IsTcp6ConnDone; + EFI_TCP6_CLOSE_TOKEN Tcp6CloseToken; + BOOLEAN IsTcp6CloseDone; + EFI_IPv6_ADDRESS RemoteIpv6Addr; + + + // - // RxToken used for receiving HTTP header. + // Rx4Token or Rx6Token used for receiving HTTP header. // - EFI_TCP4_IO_TOKEN RxToken; - EFI_TCP4_RECEIVE_DATA RxData; + EFI_TCP4_IO_TOKEN Rx4Token; + EFI_TCP4_RECEIVE_DATA Rx4Data; + EFI_TCP6_IO_TOKEN Rx6Token; + EFI_TCP6_RECEIVE_DATA Rx6Data; BOOLEAN IsRxDone; + CHAR8 **EndofHeader; + CHAR8 **HttpHeaders; CHAR8 *CacheBody; CHAR8 *NextMsg; UINTN CacheLen; @@ -119,6 +142,7 @@ typedef struct _HTTP_PROTOCOL { BOOLEAN LocalAddressIsIPv6; EFI_HTTPv4_ACCESS_POINT IPv4Node; + EFI_HTTPv6_ACCESS_POINT Ipv6Node; NET_MAP TxTokens; NET_MAP RxTokens; @@ -158,7 +182,7 @@ HttpCommonNotify ( ); /** - Create events for the TCP4 connection token and TCP4 close token. + Create events for the TCP connection token and TCP close token. @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure. @@ -167,23 +191,23 @@ HttpCommonNotify ( **/ EFI_STATUS -HttpCreateTcp4ConnCloseEvent ( +HttpCreateTcpConnCloseEvent ( IN HTTP_PROTOCOL *HttpInstance ); /** - Close events in the TCP4 connection token and TCP4 close token. + Close events in the TCP connection token and TCP close token. @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure. **/ VOID -HttpCloseTcp4ConnCloseEvent ( +HttpCloseTcpConnCloseEvent ( IN HTTP_PROTOCOL *HttpInstance ); /** - Create event for the TCP4 transmit token. + Create event for the TCP transmit token. @param[in] Wrap Point to HTTP token's wrap data. @@ -192,12 +216,12 @@ HttpCloseTcp4ConnCloseEvent ( **/ EFI_STATUS -HttpCreateTcp4TxEvent ( +HttpCreateTcpTxEvent ( IN HTTP_TOKEN_WRAP *Wrap ); /** - Create event for the TCP4 receive token which is used to receive HTTP header. + Create event for the TCP receive token which is used to receive HTTP header. @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure. @@ -206,12 +230,12 @@ HttpCreateTcp4TxEvent ( **/ EFI_STATUS -HttpCreateTcp4RxEventForHeader ( +HttpCreateTcpRxEventForHeader ( IN HTTP_PROTOCOL *HttpInstance ); /** - Create event for the TCP4 receive token which is used to receive HTTP body. + Create event for the TCP receive token which is used to receive HTTP body. @param[in] Wrap Point to HTTP token's wrap data. @@ -220,15 +244,26 @@ HttpCreateTcp4RxEventForHeader ( **/ EFI_STATUS -HttpCreateTcp4RxEvent ( +HttpCreateTcpRxEvent ( IN HTTP_TOKEN_WRAP *Wrap ); +/** + Close Events for Tcp Receive Tokens for HTTP body and HTTP header. + + @param[in] Wrap Pointer to HTTP token's wrap data. + +**/ +VOID +HttpCloseTcpRxEvent ( + IN HTTP_TOKEN_WRAP *Wrap + ); + /** Intiialize the HTTP_PROTOCOL structure to the unconfigured state. - @param[in] HttpSb The HTTP service private instance. @param[in, out] HttpInstance Pointer to HTTP_PROTOCOL structure. + @param[in] IpVersion Indicate us TCP4 protocol or TCP6 protocol. @retval EFI_SUCCESS HTTP_PROTOCOL structure is initialized successfully. @retval Others Other error as indicated. @@ -236,8 +271,8 @@ HttpCreateTcp4RxEvent ( **/ EFI_STATUS HttpInitProtocol ( - IN HTTP_SERVICE *HttpSb, - IN OUT HTTP_PROTOCOL *HttpInstance + IN OUT HTTP_PROTOCOL *HttpInstance, + IN BOOLEAN IpVersion ); /** @@ -295,6 +330,22 @@ HttpConfigureTcp4 ( IN HTTP_TOKEN_WRAP *Wrap ); +/** + Configure TCP6 protocol child. + + @param[in] HttpInstance The HTTP instance private data. + @param[in] Wrap The HTTP token's wrap data. + + @retval EFI_SUCCESS The TCP6 protocol child is configured. + @retval Others Other error as indicated. + +**/ +EFI_STATUS +HttpConfigureTcp6 ( + IN HTTP_PROTOCOL *HttpInstance, + IN HTTP_TOKEN_WRAP *Wrap + ); + /** Check existing TCP connection, if in error state, receover TCP4 connection. @@ -311,7 +362,22 @@ HttpConnectTcp4 ( ); /** - Send the HTTP message through TCP4. + Check existing TCP connection, if in error state, recover TCP6 connection. + + @param[in] HttpInstance The HTTP instance private data. + + @retval EFI_SUCCESS The TCP connection is established. + @retval EFI_NOT_READY TCP6 protocol child is not created or configured. + @retval Others Other error as indicated. + +**/ +EFI_STATUS +HttpConnectTcp6 ( + IN HTTP_PROTOCOL *HttpInstance + ); + +/** + Send the HTTP message through TCP4 or TCP6. @param[in] HttpInstance The HTTP instance private data. @param[in] Wrap The HTTP token's wrap data. @@ -323,7 +389,7 @@ HttpConnectTcp4 ( **/ EFI_STATUS -HttpTransmitTcp4 ( +HttpTransmitTcp ( IN HTTP_PROTOCOL *HttpInstance, IN HTTP_TOKEN_WRAP *Wrap, IN UINT8 *TxString, @@ -346,7 +412,7 @@ HttpMappingToStatusCode ( /** Check whether the user's token or event has already - been enqueue on HTTP TxToken or RxToken list. + been enqueue on HTTP Tx or Rx Token list. @param[in] Map The container of either user's transmit or receive token. @@ -367,7 +433,7 @@ HttpTokenExist ( ); /** - Check whether the HTTP message associated with TxToken is already sent out. + Check whether the HTTP message associated with TxToken or Tx6Token is already sent out. @param[in] Map The container of TxToken. @param[in] Item Current item to check against. @@ -385,10 +451,26 @@ HttpTcpNotReady ( IN VOID *Context ); +/** + Initialize TCP related data. + + @param[in] HttpInstance The HTTP instance private data. + @param[in] Wrap The HTTP token's wrap data. + + @retval EFI_SUCCESS The initialization of TCP instance is done. + @retval Others Other error as indicated. + +**/ +EFI_STATUS +HttpInitTcp ( + IN HTTP_PROTOCOL *HttpInstance, + IN HTTP_TOKEN_WRAP *Wrap + ); + /** Transmit the HTTP mssage by processing the associated HTTP token. - @param[in] Map The container of TxToken. + @param[in] Map The container of TxToken or Tx6Token. @param[in] Item Current item to check against. @param[in] Context The Token to check againist. @@ -408,7 +490,7 @@ HttpTcpTransmit ( /** Receive the HTTP response by processing the associated HTTP token. - @param[in] Map The container of RxToken. + @param[in] Map The container of Rx4Token or Rx6Token. @param[in] Item Current item to check against. @param[in] Context The Token to check againist. @@ -425,6 +507,51 @@ HttpTcpReceive ( IN VOID *Context ); +/** + Receive the HTTP header by processing the associated HTTP token. + + @param[in] HttpInstance The HTTP instance private data. + @param[in, out] SizeofHeaders The HTTP header length. + @param[in, out] BufferSize The size of buffer to cacahe the header message. + + @retval EFI_SUCCESS The HTTP header is received. + @retval Others Other errors as indicated. + +**/ +EFI_STATUS +HttpTcpReceiveHeader ( + IN HTTP_PROTOCOL *HttpInstance, + IN OUT UINTN *SizeofHeaders, + IN OUT UINTN *BufferSize + ); + +/** + Receive the HTTP body by processing the associated HTTP token. + + @param[in] Wrap The HTTP token's wrap data. + @param[in] HttpMsg The HTTP message data. + + @retval EFI_SUCCESS The HTTP body is received. + @retval Others Other error as indicated. + +**/ +EFI_STATUS +HttpTcpReceiveBody ( + IN HTTP_TOKEN_WRAP *Wrap, + IN EFI_HTTP_MESSAGE *HttpMsg + ); + +/** + Clean up Tcp Tokens while the Tcp transmission error occurs. + + @param[in] Wrap Pointer to HTTP token's wrap data. + +**/ +VOID +HttpTcpTokenCleanup ( + IN HTTP_TOKEN_WRAP *Wrap + ); + /** Generate HTTP request string. From 234dee51b1e1d7e42143b0a93832eccaced455ea Mon Sep 17 00:00:00 2001 From: Zhang Lubo Date: Wed, 18 Nov 2015 08:37:41 +0000 Subject: [PATCH 141/525] MdeModulePkg:Fix a bug that HttpLib can not parse Ipv6 address correctly. When parsing the authority component of the input URL, it can not distinguish the ":" is the flag that indicates the port or the separator between the ipv6 address. (Sync patch r18744 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Zhang Lubo Reviewed-by: Fu Siyuan Reviewed-by: Wu Jiaxin Reviewed-by: Gary Ching-Pang Lin git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18875 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Library/DxeHttpLib/DxeHttpLib.c | 33 +++++++++++++++++--- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/MdeModulePkg/Library/DxeHttpLib/DxeHttpLib.c b/MdeModulePkg/Library/DxeHttpLib/DxeHttpLib.c index aeb52d008857..500b3c72b38f 100644 --- a/MdeModulePkg/Library/DxeHttpLib/DxeHttpLib.c +++ b/MdeModulePkg/Library/DxeHttpLib/DxeHttpLib.c @@ -70,6 +70,7 @@ typedef enum { UrlParserUserInfo, UrlParserHostStart, // "@" UrlParserHost, + UrlParserHostIpv6, // "["(Ipv6 address) "]" UrlParserPortStart, // ":" UrlParserPort, UrlParserStateMax @@ -138,13 +139,16 @@ UriPercentDecode ( @param[in] Char Next character. @param[in] State Current value of the parser state machine. + @param[in] IsRightBracket TRUE if there is an sign ']' in the authority component and + indicates the next part is ':' before Port. @return Updated state value. **/ HTTP_URL_PARSE_STATE NetHttpParseAuthorityChar ( IN CHAR8 Char, - IN HTTP_URL_PARSE_STATE State + IN HTTP_URL_PARSE_STATE State, + IN BOOLEAN *IsRightBracket ) { @@ -169,12 +173,27 @@ NetHttpParseAuthorityChar ( break; case UrlParserHost: - case UrlParserHostStart: + case UrlParserHostStart: + if (Char == '[') { + return UrlParserHostIpv6; + } + if (Char == ':') { return UrlParserPortStart; } + return UrlParserHost; - + + case UrlParserHostIpv6: + if (Char == ']') { + *IsRightBracket = TRUE; + } + + if (Char == ':' && *IsRightBracket == TRUE) { + return UrlParserPortStart; + } + return UrlParserHostIpv6; + case UrlParserPort: case UrlParserPortStart: return UrlParserPort; @@ -210,6 +229,7 @@ NetHttpParseAuthority ( HTTP_URL_PARSE_STATE State; UINT32 Field; UINT32 OldField; + BOOLEAN IsrightBracket; ASSERT ((UrlParser->FieldBitMap & BIT (HTTP_URI_FIELD_AUTHORITY)) != 0); @@ -222,12 +242,13 @@ NetHttpParseAuthority ( State = UrlParserHost; } + IsrightBracket = FALSE; Field = HTTP_URI_FIELD_MAX; OldField = Field; Authority = Url + UrlParser->FieldData[HTTP_URI_FIELD_AUTHORITY].Offset; Length = UrlParser->FieldData[HTTP_URI_FIELD_AUTHORITY].Length; for (Char = Authority; Char < Authority + Length; Char++) { - State = NetHttpParseAuthorityChar (*Char, State); + State = NetHttpParseAuthorityChar (*Char, State, &IsrightBracket); switch (State) { case UrlParserStateMax: return EFI_INVALID_PARAMETER; @@ -243,6 +264,10 @@ NetHttpParseAuthority ( case UrlParserHost: Field = HTTP_URI_FIELD_HOST; break; + + case UrlParserHostIpv6: + Field = HTTP_URI_FIELD_HOST; + break; case UrlParserPort: Field = HTTP_URI_FIELD_PORT; From 13d4db31c299c657400de060f2836c8cc6b8bdbc Mon Sep 17 00:00:00 2001 From: Zhang Lubo Date: Wed, 18 Nov 2015 08:38:44 +0000 Subject: [PATCH 142/525] NetworkPkg:Fix the issue that cannot parse ipv6 address correctly. If there is a ipv6 expressed url, the NetLibAsciiStrToIp6 cannot get the Ipv6 address from the host name, because the host name contains left and right bracket which cannot be used to configure the Tcp6 connection. (Sync patch r18745 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Zhang Lubo Reviewed-by: Ye Ting Reviewed-by: Fu Siyuan Reviewed-by: Wu Jiaxin git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18876 6f19259b-4bc3-4df7-8a09-765794883524 --- NetworkPkg/HttpDxe/HttpImpl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NetworkPkg/HttpDxe/HttpImpl.c b/NetworkPkg/HttpDxe/HttpImpl.c index fc9d691f2299..37064d15bc97 100644 --- a/NetworkPkg/HttpDxe/HttpImpl.c +++ b/NetworkPkg/HttpDxe/HttpImpl.c @@ -391,7 +391,7 @@ EfiHttpRequest ( if (!HttpInstance->LocalAddressIsIPv6) { Status = NetLibAsciiStrToIp4 (HostName, &HttpInstance->RemoteAddr); } else { - Status = NetLibAsciiStrToIp6 (HostName, &HttpInstance->RemoteIpv6Addr); + Status = HttpUrlGetIp6 (Url, UrlParser, &HttpInstance->RemoteIpv6Addr); } if (EFI_ERROR (Status)) { From 627c5e88d43b42d4bf3fee6d36a4f85964bbd2f7 Mon Sep 17 00:00:00 2001 From: Zhang Lubo Date: Wed, 18 Nov 2015 08:39:33 +0000 Subject: [PATCH 143/525] NetworkPkg: Report Http Errors to screen when http layer occurs an error Http server will return error status in http header when http connection cannot be established,so the http boot driver should print the error code code to the screen and the users can know what happened. (Sync patch r18761 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Zhang Lubo Reviewed-by: Sriram Subramanian Reviewed-by: Ye Ting Reviewed-by: Fu Siyuan git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18877 6f19259b-4bc3-4df7-8a09-765794883524 --- NetworkPkg/HttpBootDxe/HttpBootSupport.c | 151 ++++++++++++++++++++++- 1 file changed, 150 insertions(+), 1 deletion(-) diff --git a/NetworkPkg/HttpBootDxe/HttpBootSupport.c b/NetworkPkg/HttpBootDxe/HttpBootSupport.c index d08111f66107..1fc4e768806c 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootSupport.c +++ b/NetworkPkg/HttpBootDxe/HttpBootSupport.c @@ -146,6 +146,149 @@ HttpBootShowIp6Addr ( } } +/** + This function is to display the HTTP error status. + + @param[in] StatusCode The status code value in HTTP message. + +**/ +VOID +HttpBootPrintErrorMessage ( + EFI_HTTP_STATUS_CODE StatusCode + ) +{ + AsciiPrint ("\n"); + + switch (StatusCode) { + case HTTP_STATUS_300_MULTIPLE_CHIOCES: + AsciiPrint ("\n Redirection: 300 Multiple Choices"); + break; + + case HTTP_STATUS_301_MOVED_PERMANENTLY: + AsciiPrint ("\n Redirection: 301 Moved Permanently"); + break; + + case HTTP_STATUS_302_FOUND: + AsciiPrint ("\n Redirection: 302 Found"); + break; + + case HTTP_STATUS_303_SEE_OTHER: + AsciiPrint ("\n Redirection: 303 See Other"); + break; + + case HTTP_STATUS_304_NOT_MODIFIED: + AsciiPrint ("\n Redirection: 304 Not Modified"); + break; + + case HTTP_STATUS_305_USE_PROXY: + AsciiPrint ("\n Redirection: 305 Use Proxy"); + break; + + case HTTP_STATUS_307_TEMPORARY_REDIRECT: + AsciiPrint ("\n Redirection: 307 Temporary Redirect"); + break; + + case HTTP_STATUS_400_BAD_REQUEST: + AsciiPrint ("\n Client Error: 400 Bad Request"); + break; + + case HTTP_STATUS_401_UNAUTHORIZED: + AsciiPrint ("\n Client Error: 401 Unauthorized"); + break; + + case HTTP_STATUS_402_PAYMENT_REQUIRED: + AsciiPrint ("\n Client Error: 402 Payment Required"); + break; + + case HTTP_STATUS_403_FORBIDDEN: + AsciiPrint ("\n Client Error: 403 Forbidden"); + break; + + case HTTP_STATUS_404_NOT_FOUND: + AsciiPrint ("\n Client Error: 404 Not Found"); + break; + + case HTTP_STATUS_405_METHOD_NOT_ALLOWED: + AsciiPrint ("\n Client Error: 405 Method Not Allowed"); + break; + + case HTTP_STATUS_406_NOT_ACCEPTABLE: + AsciiPrint ("\n Client Error: 406 Not Acceptable"); + break; + + case HTTP_STATUS_407_PROXY_AUTHENTICATION_REQUIRED: + AsciiPrint ("\n Client Error: 407 Proxy Authentication Required"); + break; + + case HTTP_STATUS_408_REQUEST_TIME_OUT: + AsciiPrint ("\n Client Error: 408 Request Timeout"); + break; + + case HTTP_STATUS_409_CONFLICT: + AsciiPrint ("\n Client Error: 409 Conflict"); + break; + + case HTTP_STATUS_410_GONE: + AsciiPrint ("\n Client Error: 410 Gone"); + break; + + case HTTP_STATUS_411_LENGTH_REQUIRED: + AsciiPrint ("\n Client Error: 411 Length Required"); + break; + + case HTTP_STATUS_412_PRECONDITION_FAILED: + AsciiPrint ("\n Client Error: 412 Precondition Failed"); + break; + + case HTTP_STATUS_413_REQUEST_ENTITY_TOO_LARGE: + AsciiPrint ("\n Client Error: 413 Request Entity Too Large"); + break; + + case HTTP_STATUS_414_REQUEST_URI_TOO_LARGE: + AsciiPrint ("\n Client Error: 414 Request URI Too Long"); + break; + + case HTTP_STATUS_415_UNSUPPORTED_MEDIA_TYPE: + AsciiPrint ("\n Client Error: 415 Unsupported Media Type"); + break; + + case HTTP_STATUS_416_REQUESTED_RANGE_NOT_SATISFIED: + AsciiPrint ("\n Client Error: 416 Requested Range Not Satisfiable"); + break; + + case HTTP_STATUS_417_EXPECTATION_FAILED: + AsciiPrint ("\n Client Error: 417 Expectation Failed"); + break; + + case HTTP_STATUS_500_INTERNAL_SERVER_ERROR: + AsciiPrint ("\n Server Error: 500 Internal Server Error"); + break; + + case HTTP_STATUS_501_NOT_IMPLEMENTED: + AsciiPrint ("\n Server Error: 501 Not Implemented"); + break; + + case HTTP_STATUS_502_BAD_GATEWAY: + AsciiPrint ("\n Server Error: 502 Bad Gateway"); + break; + + case HTTP_STATUS_503_SERVICE_UNAVAILABLE: + AsciiPrint ("\n Server Error: 503 Service Unavailable"); + break; + + case HTTP_STATUS_504_GATEWAY_TIME_OUT: + AsciiPrint ("\n Server Error: 504 Gateway Timeout"); + break; + + case HTTP_STATUS_505_HTTP_VERSION_NOT_SUPPORTED: + AsciiPrint ("\n Server Error: 505 HTTP Version Not Supported"); + break; + + default: ; + + } +} + /** Notify the callback function when an event is triggered. @@ -787,6 +930,7 @@ HttpIoRecvResponse ( { EFI_STATUS Status; EFI_HTTP_PROTOCOL *Http; + EFI_HTTP_STATUS_CODE StatusCode; if (HttpIo == NULL || HttpIo->Http == NULL || ResponseData == NULL) { return EFI_INVALID_PARAMETER; @@ -818,7 +962,7 @@ HttpIoRecvResponse ( } // - // Poll the network until transmit finish. + // Poll the network until receive finish. // while (!HttpIo->IsRxDone) { Http->Poll (Http); @@ -833,6 +977,11 @@ HttpIoRecvResponse ( ResponseData->Headers = HttpIo->RspToken.Message->Headers; ResponseData->BodyLength = HttpIo->RspToken.Message->BodyLength; } + + if (RecvMsgHeader) { + StatusCode = HttpIo->RspToken.Message->Data.Response->StatusCode; + HttpBootPrintErrorMessage (StatusCode); + } return Status; } From dfa8506445ed92a3fa1505422820d84217dbdd83 Mon Sep 17 00:00:00 2001 From: Zhang Lubo Date: Wed, 18 Nov 2015 08:40:26 +0000 Subject: [PATCH 144/525] NetworkPkg: Httpboot will fail the 2nd time result by wrong TCP state. If the 2nd boot quickly after the first succeed boot, it will function well. But if you wait for some time after 1nd succeed boot and boot again, the TCP state may change from established to closed wait as the http server send fin flag, then boot fail occurred. (Sync patch r18783 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Zhang Lubo Reviewed-by: Ye Ting Reviewed-by: Fu Siyuan git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18878 6f19259b-4bc3-4df7-8a09-765794883524 --- NetworkPkg/HttpDxe/HttpImpl.c | 25 ++++++++++++++-------- NetworkPkg/HttpDxe/HttpProto.c | 38 ++++++++++++++++++++++------------ NetworkPkg/HttpDxe/HttpProto.h | 4 +++- 3 files changed, 44 insertions(+), 23 deletions(-) diff --git a/NetworkPkg/HttpDxe/HttpImpl.c b/NetworkPkg/HttpDxe/HttpImpl.c index 37064d15bc97..ce28f07efa1f 100644 --- a/NetworkPkg/HttpDxe/HttpImpl.c +++ b/NetworkPkg/HttpDxe/HttpImpl.c @@ -318,7 +318,11 @@ EfiHttpRequest ( if (EFI_ERROR (Status)) { RemotePort = HTTP_DEFAULT_PORT; } - + // + // If Configure is TRUE, it indicates the first time to call Request(); + // If ReConfigure is TRUE, it indicates the request URL is not same + // with the previous call to Request(); + // Configure = TRUE; ReConfigure = TRUE; @@ -428,7 +432,11 @@ EfiHttpRequest ( // // The request URL is different from previous calls to Request(), close existing TCP instance. // - ASSERT (HttpInstance->Tcp4 != NULL &&HttpInstance->Tcp6 != NULL); + if (!HttpInstance->LocalAddressIsIPv6) { + ASSERT (HttpInstance->Tcp4 != NULL); + } else { + ASSERT (HttpInstance->Tcp6 != NULL); + } HttpCloseConnection (HttpInstance); EfiHttpCancel (This, NULL); } @@ -446,13 +454,12 @@ EfiHttpRequest ( Wrap->HttpInstance = HttpInstance; Wrap->TcpWrap.Method = Request->Method; - if (Configure) { - Status = HttpInitTcp (HttpInstance, Wrap); - if (EFI_ERROR (Status)) { - goto Error2; - } + Status = HttpInitTcp (HttpInstance, Wrap, Configure); + if (EFI_ERROR (Status)) { + goto Error2; + } - } else { + if (!Configure) { // // For the new HTTP token, create TX TCP token events. // @@ -461,7 +468,7 @@ EfiHttpRequest ( goto Error1; } } - + // // Create request message. // diff --git a/NetworkPkg/HttpDxe/HttpProto.c b/NetworkPkg/HttpDxe/HttpProto.c index c4ffef2bc236..22aed253cb36 100644 --- a/NetworkPkg/HttpDxe/HttpProto.c +++ b/NetworkPkg/HttpDxe/HttpProto.c @@ -1181,7 +1181,7 @@ HttpConnectTcp4 ( EFI_TCP4_CONNECTION_STATE Tcp4State; - if (HttpInstance->State != HTTP_STATE_TCP_CONFIGED || HttpInstance->Tcp4 == NULL) { + if (HttpInstance->State < HTTP_STATE_TCP_CONFIGED || HttpInstance->Tcp4 == NULL) { return EFI_NOT_READY; } @@ -1198,9 +1198,11 @@ HttpConnectTcp4 ( return Status; } - if (Tcp4State > Tcp4StateEstablished) { + if (Tcp4State == Tcp4StateEstablished) { + return EFI_SUCCESS; + } else if (Tcp4State > Tcp4StateEstablished ) { HttpCloseConnection(HttpInstance); - } + } return HttpCreateConnection (HttpInstance); } @@ -1223,7 +1225,7 @@ HttpConnectTcp6 ( EFI_STATUS Status; EFI_TCP6_CONNECTION_STATE Tcp6State; - if (HttpInstance->State != HTTP_STATE_TCP_CONFIGED || HttpInstance->Tcp6 == NULL) { + if (HttpInstance->State < HTTP_STATE_TCP_CONFIGED || HttpInstance->Tcp6 == NULL) { return EFI_NOT_READY; } @@ -1241,8 +1243,10 @@ HttpConnectTcp6 ( return Status; } - if (Tcp6State > Tcp6StateEstablished) { - HttpCloseConnection (HttpInstance); + if (Tcp6State == Tcp6StateEstablished) { + return EFI_SUCCESS; + } else if (Tcp6State > Tcp6StateEstablished ) { + HttpCloseConnection(HttpInstance); } return HttpCreateConnection (HttpInstance); @@ -1253,6 +1257,7 @@ HttpConnectTcp6 ( @param[in] HttpInstance The HTTP instance private data. @param[in] Wrap The HTTP token's wrap data. + @param[in] Configure The Flag indicates whether the first time to initialize Tcp. @retval EFI_SUCCESS The initialization of TCP instance is done. @retval Others Other error as indicated. @@ -1261,7 +1266,8 @@ HttpConnectTcp6 ( EFI_STATUS HttpInitTcp ( IN HTTP_PROTOCOL *HttpInstance, - IN HTTP_TOKEN_WRAP *Wrap + IN HTTP_TOKEN_WRAP *Wrap, + IN BOOLEAN Configure ) { EFI_STATUS Status; @@ -1271,10 +1277,13 @@ HttpInitTcp ( // // Configure TCP instance. // - Status = HttpConfigureTcp4 (HttpInstance, Wrap); - if (EFI_ERROR (Status)) { - return Status; + if (Configure) { + Status = HttpConfigureTcp4 (HttpInstance, Wrap); + if (EFI_ERROR (Status)) { + return Status; + } } + // // Connect TCP. // @@ -1286,10 +1295,13 @@ HttpInitTcp ( // // Configure TCP instance. // - Status = HttpConfigureTcp6 (HttpInstance, Wrap); - if (EFI_ERROR (Status)) { - return Status; + if (Configure) { + Status = HttpConfigureTcp6 (HttpInstance, Wrap); + if (EFI_ERROR (Status)) { + return Status; + } } + // // Connect TCP. // diff --git a/NetworkPkg/HttpDxe/HttpProto.h b/NetworkPkg/HttpDxe/HttpProto.h index a15e0a87be53..e43a2dc01c54 100644 --- a/NetworkPkg/HttpDxe/HttpProto.h +++ b/NetworkPkg/HttpDxe/HttpProto.h @@ -456,6 +456,7 @@ HttpTcpNotReady ( @param[in] HttpInstance The HTTP instance private data. @param[in] Wrap The HTTP token's wrap data. + @param[in] Configure The Flag indicates whether the first time to initialize Tcp. @retval EFI_SUCCESS The initialization of TCP instance is done. @retval Others Other error as indicated. @@ -464,7 +465,8 @@ HttpTcpNotReady ( EFI_STATUS HttpInitTcp ( IN HTTP_PROTOCOL *HttpInstance, - IN HTTP_TOKEN_WRAP *Wrap + IN HTTP_TOKEN_WRAP *Wrap, + IN BOOLEAN Configure ); /** From 25e3b3522b9a5028002e8fc1c5a5b6915b9709f7 Mon Sep 17 00:00:00 2001 From: Ruiyu Ni Date: Wed, 18 Nov 2015 08:50:23 +0000 Subject: [PATCH 145/525] MdeModulePkg: Add PlatformLogo protocol definition. (Sync patch r18769 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ruiyu Ni Reviewed-by: Feng Tian Reviewed-by: Jordan Justen git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18879 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Include/Protocol/PlatformLogo.h | 86 ++++++++++++++++++++ MdeModulePkg/MdeModulePkg.dec | 3 + 2 files changed, 89 insertions(+) create mode 100644 MdeModulePkg/Include/Protocol/PlatformLogo.h diff --git a/MdeModulePkg/Include/Protocol/PlatformLogo.h b/MdeModulePkg/Include/Protocol/PlatformLogo.h new file mode 100644 index 000000000000..9ac87f1748d3 --- /dev/null +++ b/MdeModulePkg/Include/Protocol/PlatformLogo.h @@ -0,0 +1,86 @@ +/** @file + The Platform Logo Protocol defines the interface to get the Platform logo + image with the display attribute. + +Copyright (c) 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials are licensed and made available under +the terms and conditions of the BSD License that accompanies this distribution. +The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php. + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __PLATFORM_LOGO_H__ +#define __PLATFORM_LOGO_H__ + +// +// GUID for EDKII Platform Logo Protocol +// +#define EDKII_PLATFORM_LOGO_PROTOCOL_GUID \ + { 0x9b517978, 0xeba1, 0x44e7, { 0xba, 0x65, 0x7c, 0x2c, 0xd0, 0x8b, 0xf8, 0xe9 } } + +typedef struct _EDKII_PLATFORM_LOGO_PROTOCOL EDKII_PLATFORM_LOGO_PROTOCOL; + +typedef enum { + ImageFormatUnknown, + ImageFormatBmp, + ImageFormatJpeg, + ImageFormatTiff, + ImageFormatGif +} IMAGE_FORMAT; + +typedef enum { + EdkiiPlatformLogoDisplayAttributeLeftTop, + EdkiiPlatformLogoDisplayAttributeCenterTop, + EdkiiPlatformLogoDisplayAttributeRightTop, + EdkiiPlatformLogoDisplayAttributeCenterRight, + EdkiiPlatformLogoDisplayAttributeRightBottom, + EdkiiPlatformLogoDisplayAttributeCenterBottom, + EdkiiPlatformLogoDisplayAttributeLeftBottom, + EdkiiPlatformLogoDisplayAttributeCenterLeft, + EdkiiPlatformLogoDisplayAttributeCenter +} EDKII_PLATFORM_LOGO_DISPLAY_ATTRIBUTE; + +/** + + Load a platform logo image and return its data and attributes. + + @param This The pointer to this protocol instance. + @param Instance The visible image instance is found. + @param Format The format of the image. Examples: BMP, JPEG. + @param ImageData The image data for the badge file. Currently only + supports the .bmp file format. + @param ImageSize The size of the image returned. + @param Attribute The display attributes of the image returned. + @param CoordinateX The X coordinate of the image. + @param CoordinateY The Y coordinate of the image. + + @retval EFI_SUCCESS The image was fetched successfully. + @retval EFI_NOT_FOUND The specified image could not be found. + +**/ +typedef +EFI_STATUS +(EFIAPI *EDKII_PLATFORM_LOGO_GET_IMAGE)( + IN EDKII_PLATFORM_LOGO_PROTOCOL *This, + IN OUT UINT32 *Instance, + OUT IMAGE_FORMAT *Format, + OUT UINT8 **ImageData, + OUT UINTN *ImageSize, + OUT EDKII_PLATFORM_LOGO_DISPLAY_ATTRIBUTE *Attribute, + OUT UINTN *CoordinateX, + OUT UINTN *CoordinateY +); + + +struct _EDKII_PLATFORM_LOGO_PROTOCOL { + EDKII_PLATFORM_LOGO_GET_IMAGE GetImage; +}; + + +extern EFI_GUID gEdkiiPlatformLogoProtocolGuid; + +#endif diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec index 3dfcd6a77f64..08148e39d938 100644 --- a/MdeModulePkg/MdeModulePkg.dec +++ b/MdeModulePkg/MdeModulePkg.dec @@ -449,6 +449,9 @@ ## Include/Protocol/SmmReadyToBoot.h gEdkiiSmmReadyToBootProtocolGuid = { 0x6e057ecf, 0xfa99, 0x4f39, { 0x95, 0xbc, 0x59, 0xf9, 0x92, 0x1d, 0x17, 0xe4 } } + ## Include/Protocol/PlatformLogo.h + gEdkiiPlatformLogoProtocolGuid = { 0x9b517978, 0xeba1, 0x44e7, { 0xba, 0x65, 0x7c, 0x2c, 0xd0, 0x8b, 0xf8, 0xe9 } } + # # [Error.gEfiMdeModulePkgTokenSpaceGuid] # 0x80000001 | Invalid value provided. From 6aaf1ccb97ea99817ca27600289e47d25acf9615 Mon Sep 17 00:00:00 2001 From: Ruiyu Ni Date: Wed, 18 Nov 2015 08:51:42 +0000 Subject: [PATCH 146/525] MdeModulePkg: Add ImageDecoderLib to provide image decoding service. The library itself doesn't provide any image decoding capabilities but manages the different image decoders. (Sync patch r18770 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ruiyu Ni Reviewed-by: Feng Tian Reviewed-by: Jordan Justen git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18880 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Include/Library/ImageDecoderLib.h | 76 +++++++++++ .../Library/ImageDecoderLib/ImageDecoderLib.c | 121 ++++++++++++++++++ .../ImageDecoderLib/ImageDecoderLib.inf | 42 ++++++ MdeModulePkg/MdeModulePkg.dec | 4 + MdeModulePkg/MdeModulePkg.dsc | 2 + 5 files changed, 245 insertions(+) create mode 100644 MdeModulePkg/Include/Library/ImageDecoderLib.h create mode 100644 MdeModulePkg/Library/ImageDecoderLib/ImageDecoderLib.c create mode 100644 MdeModulePkg/Library/ImageDecoderLib/ImageDecoderLib.inf diff --git a/MdeModulePkg/Include/Library/ImageDecoderLib.h b/MdeModulePkg/Include/Library/ImageDecoderLib.h new file mode 100644 index 000000000000..928a09483aea --- /dev/null +++ b/MdeModulePkg/Include/Library/ImageDecoderLib.h @@ -0,0 +1,76 @@ +/** @file + This library provides image decoding service by managing the different + image decoding libraries. + +Copyright (c) 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials are licensed and made available under +the terms and conditions of the BSD License that accompanies this distribution. +The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php. + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ +#ifndef __IMAGE_DECODER_LIB_H__ +#define __IMAGE_DECODER_LIB_H__ +#include + +typedef +EFI_STATUS +(EFIAPI *DECODE_IMAGE)( + IN IMAGE_FORMAT ImageFormat, + IN UINT8 *Image, + IN UINTN ImageSize, + OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL **GopBlt, + OUT UINTN *GopBltSize, + OUT UINTN *PixelWidth, + OUT UINTN *PixelHeight + ); + +/** + Convert a graphics image to a callee allocated GOP blt buffer. + + @param ImageFormat Format of the image file. + @param Image Pointer to image file. + @param ImageSize Number of bytes in Image. + @param GopBlt Buffer containing GOP version of Image. + @param GopBltSize Size of GopBlt in bytes. + @param PixelWidth Width of GopBlt/Image in pixels. + @param PixelHeight Height of GopBlt/Image in pixels. + + @retval EFI_SUCCESS GopBlt and GopBltSize are returned. + @retval EFI_INVALID_PARAMETER GopBlt or GopBltSize is NULL. + @retval EFI_INVALID_PARAMETER Image is NULL or ImageSize is 0. + @retval EFI_UNSUPPORTED Image is not supported. + @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate. + +**/ +EFI_STATUS +EFIAPI +DecodeImage ( + IN IMAGE_FORMAT ImageFormat, + IN UINT8 *Image, + IN UINTN ImageSize, + OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL **GopBlt, + OUT UINTN *GopBltSize, + OUT UINTN *PixelWidth, + OUT UINTN *PixelHeight + ); + +/** + Register an image decoder. + + @param Decoder An image decoder. + + @retval EFI_SUCCESS The decoder was successfully registered. + @retval EFI_OUT_OF_RESOURCES No enough resource to register the decoder. + +**/ +EFI_STATUS +EFIAPI +RegisterImageDecoder ( + IN DECODE_IMAGE Decoder + ); + +#endif diff --git a/MdeModulePkg/Library/ImageDecoderLib/ImageDecoderLib.c b/MdeModulePkg/Library/ImageDecoderLib/ImageDecoderLib.c new file mode 100644 index 000000000000..4a6219bbb138 --- /dev/null +++ b/MdeModulePkg/Library/ImageDecoderLib/ImageDecoderLib.c @@ -0,0 +1,121 @@ +/** @file + This library provides image decoding service by managing the different + image decoding libraries. + +Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials are licensed and made available under +the terms and conditions of the BSD License that accompanies this distribution. +The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php. + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include +#include +#include + +typedef struct { + UINT32 Signature; + DECODE_IMAGE Decoder; + LIST_ENTRY Link; +} IMAGE_DECODER_ENTRY; +#define IMAGE_DECODER_ENTRY_SIGNATURE SIGNATURE_32 ('i', 'm', 'g', 'd') +#define IMAGE_DECODER_ENTRY_FROM_LINK(Link) \ + CR (Link, IMAGE_DECODER_ENTRY, Link, IMAGE_DECODER_ENTRY_SIGNATURE) + +LIST_ENTRY mImageDecoderLibDecoders = INITIALIZE_LIST_HEAD_VARIABLE (mImageDecoderLibDecoders); + +/** + Convert a graphics image to a callee allocated GOP blt buffer. + + @param ImageFormat Format of the image file. + @param Image Pointer to image file. + @param ImageSize Number of bytes in Image. + @param GopBlt Buffer containing GOP version of Image. + @param GopBltSize Size of GopBlt in bytes. + @param PixelWidth Width of GopBlt/Image in pixels. + @param PixelHeight Height of GopBlt/Image in pixels. + + @retval EFI_SUCCESS GopBlt and GopBltSize are returned. + @retval EFI_INVALID_PARAMETER GopBlt or GopBltSize is NULL. + @retval EFI_INVALID_PARAMETER Image is NULL or ImageSize is 0. + @retval EFI_UNSUPPORTED Image is not supported. + @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate. + +**/ +EFI_STATUS +EFIAPI +DecodeImage ( + IN IMAGE_FORMAT ImageFormat, + IN UINT8 *Image, + IN UINTN ImageSize, + OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL **GopBlt, + OUT UINTN *GopBltSize, + OUT UINTN *PixelWidth, + OUT UINTN *PixelHeight + ) +{ + IMAGE_DECODER_ENTRY *Entry; + LIST_ENTRY *Link; + EFI_STATUS Status; + + if ((GopBlt == NULL) || (GopBltSize == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if ((Image == NULL) || (ImageSize == 0)) { + return EFI_INVALID_PARAMETER; + } + + for ( Link = GetFirstNode (&mImageDecoderLibDecoders) + ; !IsNull (&mImageDecoderLibDecoders, Link) + ; Link = GetNextNode (&mImageDecoderLibDecoders, Link) + ) { + Entry = IMAGE_DECODER_ENTRY_FROM_LINK (Link); + Status = Entry->Decoder (ImageFormat, Image, ImageSize, GopBlt, GopBltSize, PixelWidth, PixelHeight); + if (!EFI_ERROR (Status)) { + break; + } + } + + if (IsNull (&mImageDecoderLibDecoders, Link)) { + return EFI_UNSUPPORTED; + } else { + return EFI_SUCCESS; + } +} + +/** + Register an image decoder. + + @param Decoder An image decoder. + + @retval EFI_SUCCESS The decoder was successfully registered. + @retval EFI_OUT_OF_RESOURCES No enough resource to register the decoder. + +**/ +EFI_STATUS +EFIAPI +RegisterImageDecoder ( + IN DECODE_IMAGE Decoder + ) +{ + IMAGE_DECODER_ENTRY *Entry; + + Entry = AllocatePool (sizeof (IMAGE_DECODER_ENTRY)); + if (Entry == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Entry->Signature = IMAGE_DECODER_ENTRY_SIGNATURE; + Entry->Decoder = Decoder; + InsertTailList (&mImageDecoderLibDecoders, &Entry->Link); + + return EFI_SUCCESS; +} \ No newline at end of file diff --git a/MdeModulePkg/Library/ImageDecoderLib/ImageDecoderLib.inf b/MdeModulePkg/Library/ImageDecoderLib/ImageDecoderLib.inf new file mode 100644 index 000000000000..5d2ee7b429b5 --- /dev/null +++ b/MdeModulePkg/Library/ImageDecoderLib/ImageDecoderLib.inf @@ -0,0 +1,42 @@ +## @file +# This library provides image decoding service by managing the different +# image decoding libraries. +# +# Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.
+# This program and the accompanying materials are licensed and made available under +# the terms and conditions of the BSD License that accompanies this distribution. +# The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = ImageDecoderLib + FILE_GUID = 5ACDA5F7-AE20-4A17-90C1-7D087F730202 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = ImageDecoderLib|DXE_DRIVER UEFI_APPLICATION + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + ImageDecoderLib.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + BaseLib + MemoryAllocationLib + UefiLib + BaseMemoryLib + DebugLib \ No newline at end of file diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec index 08148e39d938..c35f533adc9b 100644 --- a/MdeModulePkg/MdeModulePkg.dec +++ b/MdeModulePkg/MdeModulePkg.dec @@ -131,6 +131,10 @@ # PlatformVarCleanupLib|Include/Library/PlatformVarCleanupLib.h + ## @libraryclass Provides image decoding service. + # + ImageDecoderLib|Include/Library/ImageDecoderLib.h + [Guids] ## MdeModule package token space guid # Include/Guid/MdeModulePkgTokenSpace.h diff --git a/MdeModulePkg/MdeModulePkg.dsc b/MdeModulePkg/MdeModulePkg.dsc index c43093260453..a57c7ebdebd9 100644 --- a/MdeModulePkg/MdeModulePkg.dsc +++ b/MdeModulePkg/MdeModulePkg.dsc @@ -47,6 +47,7 @@ PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf SortLib|MdeModulePkg/Library/BaseSortLib/BaseSortLib.inf + ImageDecoderLib|MdeModulePkg/Library/ImageDecoderLib/ImageDecoderLib.inf # # UEFI & PI # @@ -276,6 +277,7 @@ MdeModulePkg/Library/PeiDxeDebugLibReportStatusCode/PeiDxeDebugLibReportStatusCode.inf MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf MdeModulePkg/Library/PlatformBootManagerLibNull/PlatformBootManagerLibNull.inf + MdeModulePkg/Library/ImageDecoderLib/ImageDecoderLib.inf MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.inf MdeModulePkg/Library/VarCheckLib/VarCheckLib.inf From 8fa0a25d5ac17e7c121550e5aff1e57caa0b239c Mon Sep 17 00:00:00 2001 From: Ruiyu Ni Date: Wed, 18 Nov 2015 08:52:41 +0000 Subject: [PATCH 147/525] MdeModulePkg: Add BmpImageDecoderLib to provide BMP decoding capability (Sync patch r18771 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ruiyu Ni Reviewed-by: Feng Tian Reviewed-by: Jordan Justen git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18881 6f19259b-4bc3-4df7-8a09-765794883524 --- .../BmpImageDecoderLib/BmpImageDecoderLib.c | 272 ++++++++++++++++++ .../BmpImageDecoderLib/BmpImageDecoderLib.inf | 42 +++ MdeModulePkg/MdeModulePkg.dsc | 1 + 3 files changed, 315 insertions(+) create mode 100644 MdeModulePkg/Library/BmpImageDecoderLib/BmpImageDecoderLib.c create mode 100644 MdeModulePkg/Library/BmpImageDecoderLib/BmpImageDecoderLib.inf diff --git a/MdeModulePkg/Library/BmpImageDecoderLib/BmpImageDecoderLib.c b/MdeModulePkg/Library/BmpImageDecoderLib/BmpImageDecoderLib.c new file mode 100644 index 000000000000..86dcc918c2c6 --- /dev/null +++ b/MdeModulePkg/Library/BmpImageDecoderLib/BmpImageDecoderLib.c @@ -0,0 +1,272 @@ +/** @file + This library provides BMP image decoding capability. + +Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials are licensed and made available under +the terms and conditions of the BSD License that accompanies this distribution. +The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php. + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include +#include +#include +#include + +/** + Convert a *.BMP graphics image to a callee allocated GOP blt buffer. + + @param ImageFormat Format of the image file. + @param BmpImage Pointer to BMP file + @param BmpImageSize Number of bytes in BmpImage + @param GopBlt Buffer containing GOP version of BmpImage. + @param GopBltSize Size of GopBlt in bytes. + @param PixelHeight Height of GopBlt/BmpImage in pixels + @param PixelWidth Width of GopBlt/BmpImage in pixels + + @retval EFI_SUCCESS GopBlt and GopBltSize are returned. + @retval EFI_INVALID_PARAMETER GopBlt or GopBltSize is NULL. + @retval EFI_UNSUPPORTED BmpImage is not a valid *.BMP image + @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate. + +**/ +EFI_STATUS +EFIAPI +BmpImageDecoderLibConvertBmpToGopBlt ( + IN IMAGE_FORMAT ImageFormat, + IN UINT8 *BmpImage, + IN UINTN BmpImageSize, + OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL **GopBlt, + OUT UINTN *GopBltSize, + OUT UINTN *PixelWidth, + OUT UINTN *PixelHeight + ) +{ + UINT8 *Image; + UINT8 *ImageHeader; + BMP_IMAGE_HEADER *BmpHeader; + BMP_COLOR_MAP *BmpColorMap; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt; + UINT64 BltBufferSize; + UINTN Index; + UINTN Height; + UINTN Width; + UINTN ImageIndex; + UINT32 DataSizePerLine; + UINT32 ColorMapNum; + + ASSERT ((GopBlt != NULL) && (GopBltSize != NULL)); + + if (ImageFormat != ImageFormatBmp) { + return EFI_UNSUPPORTED; + } + + if (sizeof (BMP_IMAGE_HEADER) > BmpImageSize) { + return EFI_UNSUPPORTED; + } + + BmpHeader = (BMP_IMAGE_HEADER *) BmpImage; + + if (BmpHeader->CharB != 'B' || BmpHeader->CharM != 'M') { + return EFI_UNSUPPORTED; + } + + // + // Doesn't support compress. + // + if (BmpHeader->CompressionType != 0) { + return EFI_UNSUPPORTED; + } + + // + // Only support BITMAPINFOHEADER format. + // BITMAPFILEHEADER + BITMAPINFOHEADER = BMP_IMAGE_HEADER + // + if (BmpHeader->HeaderSize != sizeof (BMP_IMAGE_HEADER) - OFFSET_OF(BMP_IMAGE_HEADER, HeaderSize)) { + return EFI_UNSUPPORTED; + } + + // + // The data size in each line must be 4 byte alignment. + // + DataSizePerLine = ((BmpHeader->PixelWidth * BmpHeader->BitPerPixel + 31) >> 3) & (~0x3); + BltBufferSize = MultU64x32 (DataSizePerLine, BmpHeader->PixelHeight); + if (BltBufferSize > (UINT32) ~0) { + return EFI_INVALID_PARAMETER; + } + + if ((BmpHeader->Size != BmpImageSize) || + (BmpHeader->Size < BmpHeader->ImageOffset) || + (BmpHeader->Size - BmpHeader->ImageOffset != BmpHeader->PixelHeight * DataSizePerLine)) { + return EFI_INVALID_PARAMETER; + } + + // + // Calculate Color Map offset in the image. + // + Image = BmpImage; + BmpColorMap = (BMP_COLOR_MAP *) (Image + sizeof (BMP_IMAGE_HEADER)); + if (BmpHeader->ImageOffset < sizeof (BMP_IMAGE_HEADER)) { + return EFI_INVALID_PARAMETER; + } + + if (BmpHeader->ImageOffset > sizeof (BMP_IMAGE_HEADER)) { + switch (BmpHeader->BitPerPixel) { + case 1: + ColorMapNum = 2; + break; + case 4: + ColorMapNum = 16; + break; + case 8: + ColorMapNum = 256; + break; + default: + ColorMapNum = 0; + break; + } + // + // BMP file may has padding data between the bmp header section and the bmp data section. + // + if (BmpHeader->ImageOffset - sizeof (BMP_IMAGE_HEADER) < sizeof (BMP_COLOR_MAP) * ColorMapNum) { + return EFI_INVALID_PARAMETER; + } + } + + // + // Calculate graphics image data address in the image + // + Image = ((UINT8 *) BmpImage) + BmpHeader->ImageOffset; + ImageHeader = Image; + + // + // Calculate the BltBuffer needed size. + // + BltBufferSize = MultU64x32 ((UINT64) BmpHeader->PixelWidth, BmpHeader->PixelHeight); + // + // Ensure the BltBufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) doesn't overflow + // + if (BltBufferSize > DivU64x32 ((UINTN) ~0, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) { + return EFI_UNSUPPORTED; + } + BltBufferSize = MultU64x32 (BltBufferSize, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); + + *GopBltSize = (UINTN) BltBufferSize; + *GopBlt = AllocatePool (*GopBltSize); + if (*GopBlt == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + *PixelWidth = BmpHeader->PixelWidth; + *PixelHeight = BmpHeader->PixelHeight; + + // + // Convert image from BMP to Blt buffer format + // + BltBuffer = *GopBlt; + for (Height = 0; Height < BmpHeader->PixelHeight; Height++) { + Blt = &BltBuffer[(BmpHeader->PixelHeight - Height - 1) * BmpHeader->PixelWidth]; + for (Width = 0; Width < BmpHeader->PixelWidth; Width++, Image++, Blt++) { + switch (BmpHeader->BitPerPixel) { + case 1: + // + // Convert 1-bit (2 colors) BMP to 24-bit color + // + for (Index = 0; Index < 8 && Width < BmpHeader->PixelWidth; Index++) { + Blt->Red = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Red; + Blt->Green = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Green; + Blt->Blue = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Blue; + Blt++; + Width++; + } + + Blt--; + Width--; + break; + + case 4: + // + // Convert 4-bit (16 colors) BMP Palette to 24-bit color + // + Index = (*Image) >> 4; + Blt->Red = BmpColorMap[Index].Red; + Blt->Green = BmpColorMap[Index].Green; + Blt->Blue = BmpColorMap[Index].Blue; + if (Width < (BmpHeader->PixelWidth - 1)) { + Blt++; + Width++; + Index = (*Image) & 0x0f; + Blt->Red = BmpColorMap[Index].Red; + Blt->Green = BmpColorMap[Index].Green; + Blt->Blue = BmpColorMap[Index].Blue; + } + break; + + case 8: + // + // Convert 8-bit (256 colors) BMP Palette to 24-bit color + // + Blt->Red = BmpColorMap[*Image].Red; + Blt->Green = BmpColorMap[*Image].Green; + Blt->Blue = BmpColorMap[*Image].Blue; + break; + + case 24: + // + // It is 24-bit BMP. + // + Blt->Blue = *Image++; + Blt->Green = *Image++; + Blt->Red = *Image; + break; + + default: + // + // Other bit format BMP is not supported. + // + return EFI_UNSUPPORTED; + break; + }; + + } + + ImageIndex = (UINTN) (Image - ImageHeader); + if ((ImageIndex % 4) != 0) { + // + // Bmp Image starts each row on a 32-bit boundary! + // + Image = Image + (4 - (ImageIndex % 4)); + } + } + + return EFI_SUCCESS; +} + +/** + Initialize BmpImageDecoderLib library. + + @param ImageHandle The image handle. + @param SystemTable The system table. + + @retval EFI_SUCCESS The BmpImageDecoderLib library is initialized correctly. + @return Other value if failed to initialize the BmpImageDecoderLib library. +**/ +EFI_STATUS +EFIAPI +BmpImageDecoderLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable +) +{ + RegisterImageDecoder (BmpImageDecoderLibConvertBmpToGopBlt); + return EFI_SUCCESS; +} + diff --git a/MdeModulePkg/Library/BmpImageDecoderLib/BmpImageDecoderLib.inf b/MdeModulePkg/Library/BmpImageDecoderLib/BmpImageDecoderLib.inf new file mode 100644 index 000000000000..2d1c16084e39 --- /dev/null +++ b/MdeModulePkg/Library/BmpImageDecoderLib/BmpImageDecoderLib.inf @@ -0,0 +1,42 @@ +## @file +# This library provides BMP image decoding capability. +# +# Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.
+# This program and the accompanying materials are licensed and made available under +# the terms and conditions of the BSD License that accompanies this distribution. +# The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = BmpImageDecoderLib + FILE_GUID = DF414223-F17C-4022-A1F4-4062612AB00D + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = NULL|DXE_DRIVER UEFI_APPLICATION + CONSTRUCTOR = BmpImageDecoderLibConstructor + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + BmpImageDecoderLib.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + BaseLib + MemoryAllocationLib + BaseMemoryLib + DebugLib + ImageDecoderLib \ No newline at end of file diff --git a/MdeModulePkg/MdeModulePkg.dsc b/MdeModulePkg/MdeModulePkg.dsc index a57c7ebdebd9..e15782044018 100644 --- a/MdeModulePkg/MdeModulePkg.dsc +++ b/MdeModulePkg/MdeModulePkg.dsc @@ -278,6 +278,7 @@ MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf MdeModulePkg/Library/PlatformBootManagerLibNull/PlatformBootManagerLibNull.inf MdeModulePkg/Library/ImageDecoderLib/ImageDecoderLib.inf + MdeModulePkg/Library/BmpImageDecoderLib/BmpImageDecoderLib.inf MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.inf MdeModulePkg/Library/VarCheckLib/VarCheckLib.inf From 0d56f058ed2ae43f997425d4902e9250693102f9 Mon Sep 17 00:00:00 2001 From: Ruiyu Ni Date: Wed, 18 Nov 2015 08:53:30 +0000 Subject: [PATCH 148/525] MdeModulePkg: Add BootLogoLib to provide interfaces about logo display. (Sync patch r18772 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ruiyu Ni Reviewed-by: Feng Tian Reviewed-by: Jordan Justen git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18882 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Include/Library/BootLogoLib.h | 82 +++ .../Library/BootLogoLib/BootLogoLib.c | 584 ++++++++++++++++++ .../Library/BootLogoLib/BootLogoLib.inf | 59 ++ MdeModulePkg/MdeModulePkg.dec | 4 + MdeModulePkg/MdeModulePkg.dsc | 1 + 5 files changed, 730 insertions(+) create mode 100644 MdeModulePkg/Include/Library/BootLogoLib.h create mode 100644 MdeModulePkg/Library/BootLogoLib/BootLogoLib.c create mode 100644 MdeModulePkg/Library/BootLogoLib/BootLogoLib.inf diff --git a/MdeModulePkg/Include/Library/BootLogoLib.h b/MdeModulePkg/Include/Library/BootLogoLib.h new file mode 100644 index 000000000000..363740537107 --- /dev/null +++ b/MdeModulePkg/Include/Library/BootLogoLib.h @@ -0,0 +1,82 @@ +/** @file + This library is only intended to be used by PlatformBootManagerLib + to show progress bar and LOGO. + +Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials are licensed and made available under +the terms and conditions of the BSD License that accompanies this distribution. +The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php. + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _BOOT_LOGO_LIB_H_ +#define _BOOT_LOGO_LIB_H_ + +#include + +/** + Show LOGO on all consoles. + + @param[in] ImageFormat Format of the image file. + @param[in] LogoFile The file name of logo to display. + @param[in] Attribute The display attributes of the image returned. + @param[in] CoordinateX The X coordinate of the image. + @param[in] CoordinateY The Y coordinate of the image. + + @retval EFI_SUCCESS Logo was displayed. + @retval EFI_UNSUPPORTED Logo was not found or cannot be displayed. +**/ +EFI_STATUS +EFIAPI +BootLogoEnableLogo ( + IN IMAGE_FORMAT ImageFormat, + IN EFI_GUID *Logo, + IN EDKII_PLATFORM_LOGO_DISPLAY_ATTRIBUTE Attribute, + IN UINTN CoordinateX, + IN UINTN CoordinateY + ); + + +/** + Use SystemTable ConOut to turn on video based Simple Text Out consoles. The + Simple Text Out screens will now be synced up with all non-video output devices. + + @retval EFI_SUCCESS UGA devices are back in text mode and synced up. + +**/ +EFI_STATUS +EFIAPI +BootLogoDisableLogo ( + VOID + ); + +/** + + Update progress bar with title above it. It only works in Graphics mode. + + @param TitleForeground Foreground color for Title. + @param TitleBackground Background color for Title. + @param Title Title above progress bar. + @param ProgressColor Progress bar color. + @param Progress Progress (0-100) + @param PreviousValue The previous value of the progress. + + @retval EFI_STATUS Successly update the progress bar + +**/ +EFI_STATUS +EFIAPI +BootLogoUpdateProgress ( + IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL TitleForeground, + IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL TitleBackground, + IN CHAR16 *Title, + IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL ProgressColor, + IN UINTN Progress, + IN UINTN PreviousValue + ); + +#endif diff --git a/MdeModulePkg/Library/BootLogoLib/BootLogoLib.c b/MdeModulePkg/Library/BootLogoLib/BootLogoLib.c new file mode 100644 index 000000000000..312adb04db42 --- /dev/null +++ b/MdeModulePkg/Library/BootLogoLib/BootLogoLib.c @@ -0,0 +1,584 @@ +/** @file + This library is only intended to be used by PlatformBootManagerLib + to show progress bar and LOGO. + +Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials are licensed and made available under +the terms and conditions of the BSD License that accompanies this distribution. +The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php. + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + Show LOGO on all consoles. + + @param[in] ImageFormat Format of the image file. + @param[in] LogoFile The file name of logo to display. + @param[in] Attribute The display attributes of the image returned. + @param[in] CoordinateX The X coordinate of the image. + @param[in] CoordinateY The Y coordinate of the image. + + @retval EFI_SUCCESS Logo was displayed. + @retval EFI_UNSUPPORTED Logo was not found or cannot be displayed. +**/ +EFI_STATUS +EFIAPI +BootLogoEnableLogo ( + IN IMAGE_FORMAT ImageFormat, + IN EFI_GUID *Logo, + IN EDKII_PLATFORM_LOGO_DISPLAY_ATTRIBUTE Attribute, + IN UINTN CoordinateX, + IN UINTN CoordinateY + ) +{ + EFI_STATUS Status; + EDKII_PLATFORM_LOGO_PROTOCOL *PlatformLogo; + UINT32 SizeOfX; + UINT32 SizeOfY; + INTN DestX; + INTN DestY; + UINT8 *ImageData; + UINTN ImageSize; + UINTN BltSize; + UINT32 Instance; + UINTN Height; + UINTN Width; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt; + EFI_UGA_DRAW_PROTOCOL *UgaDraw; + UINT32 ColorDepth; + UINT32 RefreshRate; + EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput; + EFI_BOOT_LOGO_PROTOCOL *BootLogo; + UINTN NumberOfLogos; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *LogoBlt; + UINTN LogoDestX; + UINTN LogoDestY; + UINTN LogoHeight; + UINTN LogoWidth; + UINTN NewDestX; + UINTN NewDestY; + UINTN NewHeight; + UINTN NewWidth; + UINTN BufferSize; + + UgaDraw = NULL; + // + // Try to open GOP first + // + Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **) &GraphicsOutput); + if (EFI_ERROR (Status) && FeaturePcdGet (PcdUgaConsumeSupport)) { + GraphicsOutput = NULL; + // + // Open GOP failed, try to open UGA + // + Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiUgaDrawProtocolGuid, (VOID **) &UgaDraw); + if (EFI_ERROR (Status)) { + UgaDraw = NULL; + } + } + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + Status = gBS->LocateProtocol (&gEdkiiPlatformLogoProtocolGuid, NULL, (VOID **) &PlatformLogo); + if (EFI_ERROR (Status)) { + PlatformLogo = NULL; + } + + if ((Logo == NULL) && (PlatformLogo == NULL)) { + return EFI_UNSUPPORTED; + } + + // + // Try to open Boot Logo Protocol. + // + Status = gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo); + if (EFI_ERROR (Status)) { + BootLogo = NULL; + } + + // + // Erase Cursor from screen + // + gST->ConOut->EnableCursor (gST->ConOut, FALSE); + + if (GraphicsOutput != NULL) { + SizeOfX = GraphicsOutput->Mode->Info->HorizontalResolution; + SizeOfY = GraphicsOutput->Mode->Info->VerticalResolution; + + } else { + ASSERT (UgaDraw != NULL); + Status = UgaDraw->GetMode (UgaDraw, &SizeOfX, &SizeOfY, &ColorDepth, &RefreshRate); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + } + + Blt = NULL; + NumberOfLogos = 0; + LogoDestX = 0; + LogoDestY = 0; + LogoHeight = 0; + LogoWidth = 0; + NewDestX = 0; + NewDestY = 0; + NewHeight = 0; + NewWidth = 0; + Instance = 0; + while (TRUE) { + ImageData = NULL; + ImageSize = 0; + + if (PlatformLogo != NULL) { + // + // Get image from OEMBadging protocol. + // + Status = PlatformLogo->GetImage ( + PlatformLogo, + &Instance, + &ImageFormat, + &ImageData, + &ImageSize, + &Attribute, + &CoordinateX, + &CoordinateY + ); + if (EFI_ERROR (Status)) { + break; + } + + } else { + // + // Get the specified image from FV. + // + Status = GetSectionFromAnyFv (Logo, EFI_SECTION_RAW, 0, (VOID **) &ImageData, &ImageSize); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + } + + if (Blt != NULL) { + FreePool (Blt); + } + + Status = DecodeImage (ImageFormat, ImageData, ImageSize, &Blt, &BltSize, &Width, &Height); + FreePool (ImageData); + if (EFI_ERROR (Status)) { + if (Logo != NULL) { + // + // Directly return failure for single LOGO + // + return Status; + } else { + continue; + } + } + + // + // Calculate the display position according to Attribute. + // + switch (Attribute) { + case EdkiiPlatformLogoDisplayAttributeLeftTop: + DestX = CoordinateX; + DestY = CoordinateY; + break; + + case EdkiiPlatformLogoDisplayAttributeCenterTop: + DestX = (SizeOfX - Width) / 2; + DestY = CoordinateY; + break; + + case EdkiiPlatformLogoDisplayAttributeRightTop: + DestX = (SizeOfX - Width - CoordinateX); + DestY = CoordinateY;; + break; + + case EdkiiPlatformLogoDisplayAttributeCenterRight: + DestX = (SizeOfX - Width - CoordinateX); + DestY = (SizeOfY - Height) / 2; + break; + + case EdkiiPlatformLogoDisplayAttributeRightBottom: + DestX = (SizeOfX - Width - CoordinateX); + DestY = (SizeOfY - Height - CoordinateY); + break; + + case EdkiiPlatformLogoDisplayAttributeCenterBottom: + DestX = (SizeOfX - Width) / 2; + DestY = (SizeOfY - Height - CoordinateY); + break; + + case EdkiiPlatformLogoDisplayAttributeLeftBottom: + DestX = CoordinateX; + DestY = (SizeOfY - Height - CoordinateY); + break; + + case EdkiiPlatformLogoDisplayAttributeCenterLeft: + DestX = CoordinateX; + DestY = (SizeOfY - Height) / 2; + break; + + case EdkiiPlatformLogoDisplayAttributeCenter: + DestX = (SizeOfX - Width) / 2; + DestY = (SizeOfY - Height) / 2; + break; + + default: + ASSERT (FALSE); + break; + } + + if ((DestX >= 0) && (DestY >= 0)) { + if (GraphicsOutput != NULL) { + Status = GraphicsOutput->Blt ( + GraphicsOutput, + Blt, + EfiBltBufferToVideo, + 0, + 0, + (UINTN) DestX, + (UINTN) DestY, + Width, + Height, + Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) + ); + } else { + ASSERT (UgaDraw != NULL); + Status = UgaDraw->Blt ( + UgaDraw, + (EFI_UGA_PIXEL *) Blt, + EfiUgaBltBufferToVideo, + 0, + 0, + (UINTN) DestX, + (UINTN) DestY, + Width, + Height, + Width * sizeof (EFI_UGA_PIXEL) + ); + } + + // + // Report displayed Logo information. + // + if (!EFI_ERROR (Status)) { + NumberOfLogos++; + + if (LogoWidth == 0) { + // + // The first Logo. + // + LogoDestX = (UINTN) DestX; + LogoDestY = (UINTN) DestY; + LogoWidth = Width; + LogoHeight = Height; + } else { + // + // Merge new logo with old one. + // + NewDestX = MIN ((UINTN) DestX, LogoDestX); + NewDestY = MIN ((UINTN) DestY, LogoDestY); + NewWidth = MAX ((UINTN) DestX + Width, LogoDestX + LogoWidth) - NewDestX; + NewHeight = MAX ((UINTN) DestY + Height, LogoDestY + LogoHeight) - NewDestY; + + LogoDestX = NewDestX; + LogoDestY = NewDestY; + LogoWidth = NewWidth; + LogoHeight = NewHeight; + } + } + } + + if (PlatformLogo == NULL) { + break; + } + } + + if (BootLogo == NULL || NumberOfLogos == 0) { + // + // No logo displayed. + // + if (Blt != NULL) { + FreePool (Blt); + } + + return Status; + } + + // + // Advertise displayed Logo information. + // + if (NumberOfLogos == 1) { + // + // Only one logo displayed, use its Blt buffer directly for BootLogo protocol. + // + LogoBlt = Blt; + Status = EFI_SUCCESS; + } else { + // + // More than one Logo displayed, get merged BltBuffer using VideoToBuffer operation. + // + if (Blt != NULL) { + FreePool (Blt); + } + + // + // Ensure the LogoHeight * LogoWidth * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) doesn't overflow + // + if (LogoHeight > MAX_UINTN / LogoWidth / sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)) { + return EFI_UNSUPPORTED; + } + BufferSize = LogoWidth * LogoHeight * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL); + + LogoBlt = AllocatePool (BufferSize); + if (LogoBlt == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + if (GraphicsOutput != NULL) { + Status = GraphicsOutput->Blt ( + GraphicsOutput, + LogoBlt, + EfiBltVideoToBltBuffer, + LogoDestX, + LogoDestY, + 0, + 0, + LogoWidth, + LogoHeight, + LogoWidth * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) + ); + } else { + Status = UgaDraw->Blt ( + UgaDraw, + (EFI_UGA_PIXEL *) LogoBlt, + EfiUgaVideoToBltBuffer, + LogoDestX, + LogoDestY, + 0, + 0, + LogoWidth, + LogoHeight, + LogoWidth * sizeof (EFI_UGA_PIXEL) + ); + } + } + + if (!EFI_ERROR (Status)) { + BootLogo->SetBootLogo (BootLogo, LogoBlt, LogoDestX, LogoDestY, LogoWidth, LogoHeight); + } + FreePool (LogoBlt); + + return Status; +} + +/** + Use SystemTable Conout to turn on video based Simple Text Out consoles. The + Simple Text Out screens will now be synced up with all non video output devices + + @retval EFI_SUCCESS UGA devices are back in text mode and synced up. + +**/ +EFI_STATUS +EFIAPI +BootLogoDisableLogo ( + VOID + ) +{ + + // + // Enable Cursor on Screen + // + gST->ConOut->EnableCursor (gST->ConOut, TRUE); + return EFI_SUCCESS; +} + + +/** + + Update progress bar with title above it. It only works in Graphics mode. + + @param TitleForeground Foreground color for Title. + @param TitleBackground Background color for Title. + @param Title Title above progress bar. + @param ProgressColor Progress bar color. + @param Progress Progress (0-100) + @param PreviousValue The previous value of the progress. + + @retval EFI_STATUS Success update the progress bar + +**/ +EFI_STATUS +EFIAPI +BootLogoUpdateProgress ( + IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL TitleForeground, + IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL TitleBackground, + IN CHAR16 *Title, + IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL ProgressColor, + IN UINTN Progress, + IN UINTN PreviousValue + ) +{ + EFI_STATUS Status; + EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput; + EFI_UGA_DRAW_PROTOCOL *UgaDraw; + UINT32 SizeOfX; + UINT32 SizeOfY; + UINT32 ColorDepth; + UINT32 RefreshRate; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color; + UINTN BlockHeight; + UINTN BlockWidth; + UINTN BlockNum; + UINTN PosX; + UINTN PosY; + UINTN Index; + + if (Progress > 100) { + return EFI_INVALID_PARAMETER; + } + + UgaDraw = NULL; + Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **) &GraphicsOutput); + if (EFI_ERROR (Status) && FeaturePcdGet (PcdUgaConsumeSupport)) { + GraphicsOutput = NULL; + + Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiUgaDrawProtocolGuid, (VOID **) &UgaDraw); + if (EFI_ERROR (Status)) { + UgaDraw = NULL; + } + } + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + SizeOfX = 0; + SizeOfY = 0; + if (GraphicsOutput != NULL) { + SizeOfX = GraphicsOutput->Mode->Info->HorizontalResolution; + SizeOfY = GraphicsOutput->Mode->Info->VerticalResolution; + } else if (UgaDraw != NULL) { + Status = UgaDraw->GetMode ( + UgaDraw, + &SizeOfX, + &SizeOfY, + &ColorDepth, + &RefreshRate + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + } else { + return EFI_UNSUPPORTED; + } + + BlockWidth = SizeOfX / 100; + BlockHeight = SizeOfY / 50; + + BlockNum = Progress; + + PosX = 0; + PosY = SizeOfY * 48 / 50; + + if (BlockNum == 0) { + // + // Clear progress area + // + SetMem (&Color, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0x0); + + if (GraphicsOutput != NULL) { + Status = GraphicsOutput->Blt ( + GraphicsOutput, + &Color, + EfiBltVideoFill, + 0, + 0, + 0, + PosY - EFI_GLYPH_HEIGHT - 1, + SizeOfX, + SizeOfY - (PosY - EFI_GLYPH_HEIGHT - 1), + SizeOfX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) + ); + } else if (FeaturePcdGet (PcdUgaConsumeSupport)) { + Status = UgaDraw->Blt ( + UgaDraw, + (EFI_UGA_PIXEL *) &Color, + EfiUgaVideoFill, + 0, + 0, + 0, + PosY - EFI_GLYPH_HEIGHT - 1, + SizeOfX, + SizeOfY - (PosY - EFI_GLYPH_HEIGHT - 1), + SizeOfX * sizeof (EFI_UGA_PIXEL) + ); + } else { + return EFI_UNSUPPORTED; + } + } + // + // Show progress by drawing blocks + // + for (Index = PreviousValue; Index < BlockNum; Index++) { + PosX = Index * BlockWidth; + if (GraphicsOutput != NULL) { + Status = GraphicsOutput->Blt ( + GraphicsOutput, + &ProgressColor, + EfiBltVideoFill, + 0, + 0, + PosX, + PosY, + BlockWidth - 1, + BlockHeight, + (BlockWidth) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) + ); + } else if (FeaturePcdGet (PcdUgaConsumeSupport)) { + Status = UgaDraw->Blt ( + UgaDraw, + (EFI_UGA_PIXEL *) &ProgressColor, + EfiUgaVideoFill, + 0, + 0, + PosX, + PosY, + BlockWidth - 1, + BlockHeight, + (BlockWidth) * sizeof (EFI_UGA_PIXEL) + ); + } else { + return EFI_UNSUPPORTED; + } + } + + PrintXY ( + (SizeOfX - StrLen (Title) * EFI_GLYPH_WIDTH) / 2, + PosY - EFI_GLYPH_HEIGHT - 1, + &TitleForeground, + &TitleBackground, + Title + ); + + return EFI_SUCCESS; +} diff --git a/MdeModulePkg/Library/BootLogoLib/BootLogoLib.inf b/MdeModulePkg/Library/BootLogoLib/BootLogoLib.inf new file mode 100644 index 000000000000..51e68edfea7a --- /dev/null +++ b/MdeModulePkg/Library/BootLogoLib/BootLogoLib.inf @@ -0,0 +1,59 @@ +## @file +# This library is only intended to be used by PlatformBootManagerLib +# to show progress bar and logo. +# +# Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.
+# This program and the accompanying materials are licensed and made available under +# the terms and conditions of the BSD License that accompanies this distribution. +# The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = BootLogoLib + FILE_GUID = F5AE5B5C-42E8-4A9B-829D-5B631CD5367A + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = BootLogoLib|DXE_DRIVER UEFI_APPLICATION + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + BootLogoLib.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + BaseLib + UefiBootServicesTableLib + MemoryAllocationLib + UefiLib + BaseMemoryLib + DebugLib + PrintLib + PcdLib + DxeServicesLib + ImageDecoderLib + +[Guids] + +[Protocols] + gEfiGraphicsOutputProtocolGuid # PROTOCOL SOMETIMES_CONSUMES + gEfiUgaDrawProtocolGuid |PcdUgaConsumeSupport # PROTOCOL SOMETIMES_CONSUMES + gEfiBootLogoProtocolGuid # PROTOCOL SOMETIMES_CONSUMES + gEfiUserManagerProtocolGuid # PROTOCOL CONSUMES + gEdkiiPlatformLogoProtocolGuid # PROTOCOL CONSUMES + +[FeaturePcd] + gEfiMdePkgTokenSpaceGuid.PcdUgaConsumeSupport diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec index c35f533adc9b..f00d6f030ad5 100644 --- a/MdeModulePkg/MdeModulePkg.dec +++ b/MdeModulePkg/MdeModulePkg.dec @@ -135,6 +135,10 @@ # ImageDecoderLib|Include/Library/ImageDecoderLib.h + ## @libraryclass Provides interfaces about logo display. + # + BootLogoLib|Include/Library/BootLogoLib.h + [Guids] ## MdeModule package token space guid # Include/Guid/MdeModulePkgTokenSpace.h diff --git a/MdeModulePkg/MdeModulePkg.dsc b/MdeModulePkg/MdeModulePkg.dsc index e15782044018..b80be9d67619 100644 --- a/MdeModulePkg/MdeModulePkg.dsc +++ b/MdeModulePkg/MdeModulePkg.dsc @@ -278,6 +278,7 @@ MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf MdeModulePkg/Library/PlatformBootManagerLibNull/PlatformBootManagerLibNull.inf MdeModulePkg/Library/ImageDecoderLib/ImageDecoderLib.inf + MdeModulePkg/Library/BootLogoLib/BootLogoLib.inf MdeModulePkg/Library/BmpImageDecoderLib/BmpImageDecoderLib.inf MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.inf From fd3eb25595fdd3e42d6a30b145261cc3aa5c8045 Mon Sep 17 00:00:00 2001 From: Ruiyu Ni Date: Wed, 18 Nov 2015 08:54:23 +0000 Subject: [PATCH 149/525] Nt32Pkg: Use BootLogoLib for logo and progress bar drawing. (Sync patch r18773 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ruiyu Ni Reviewed-by: Jordan Justen Reviewed-by: Eric Dong git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18883 6f19259b-4bc3-4df7-8a09-765794883524 --- .../PlatformBootManagerLib/MemoryTest.c | 833 +----------------- .../PlatformBootManager.c | 6 +- .../PlatformBootManager.h | 6 +- .../PlatformBootManagerLib.inf | 2 +- Nt32Pkg/Nt32Pkg.dsc | 7 +- 5 files changed, 14 insertions(+), 840 deletions(-) diff --git a/Nt32Pkg/Library/PlatformBootManagerLib/MemoryTest.c b/Nt32Pkg/Library/PlatformBootManagerLib/MemoryTest.c index 9f57466e8c18..93ecc7d88cf3 100644 --- a/Nt32Pkg/Library/PlatformBootManagerLib/MemoryTest.c +++ b/Nt32Pkg/Library/PlatformBootManagerLib/MemoryTest.c @@ -23,179 +23,6 @@ EFI_GUID mPlatformBootManagerStringPackGuid = { // // BDS Platform Functions // -/** - - Show progress bar with title above it. It only works in Graphics mode. - - - @param TitleForeground Foreground color for Title. - @param TitleBackground Background color for Title. - @param Title Title above progress bar. - @param ProgressColor Progress bar color. - @param Progress Progress (0-100) - @param PreviousValue The previous value of the progress. - - @retval EFI_STATUS Success update the progress bar - -**/ -EFI_STATUS -PlatformBootManagerShowProgress ( - IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL TitleForeground, - IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL TitleBackground, - IN CHAR16 *Title, - IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL ProgressColor, - IN UINTN Progress, - IN UINTN PreviousValue - ) -{ - EFI_STATUS Status; - EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput; - EFI_UGA_DRAW_PROTOCOL *UgaDraw; - UINT32 SizeOfX; - UINT32 SizeOfY; - UINT32 ColorDepth; - UINT32 RefreshRate; - EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color; - UINTN BlockHeight; - UINTN BlockWidth; - UINTN BlockNum; - UINTN PosX; - UINTN PosY; - UINTN Index; - - if (Progress > 100) { - return EFI_INVALID_PARAMETER; - } - - UgaDraw = NULL; - Status = gBS->HandleProtocol ( - gST->ConsoleOutHandle, - &gEfiGraphicsOutputProtocolGuid, - (VOID **) &GraphicsOutput - ); - if (EFI_ERROR (Status) && FeaturePcdGet (PcdUgaConsumeSupport)) { - GraphicsOutput = NULL; - - Status = gBS->HandleProtocol ( - gST->ConsoleOutHandle, - &gEfiUgaDrawProtocolGuid, - (VOID **) &UgaDraw - ); - } - if (EFI_ERROR (Status)) { - return EFI_UNSUPPORTED; - } - - SizeOfX = 0; - SizeOfY = 0; - if (GraphicsOutput != NULL) { - SizeOfX = GraphicsOutput->Mode->Info->HorizontalResolution; - SizeOfY = GraphicsOutput->Mode->Info->VerticalResolution; - } else if (UgaDraw != NULL) { - Status = UgaDraw->GetMode ( - UgaDraw, - &SizeOfX, - &SizeOfY, - &ColorDepth, - &RefreshRate - ); - if (EFI_ERROR (Status)) { - return EFI_UNSUPPORTED; - } - } else { - return EFI_UNSUPPORTED; - } - - BlockWidth = SizeOfX / 100; - BlockHeight = SizeOfY / 50; - - BlockNum = Progress; - - PosX = 0; - PosY = SizeOfY * 48 / 50; - - if (BlockNum == 0) { - // - // Clear progress area - // - SetMem (&Color, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0x0); - - if (GraphicsOutput != NULL) { - Status = GraphicsOutput->Blt ( - GraphicsOutput, - &Color, - EfiBltVideoFill, - 0, - 0, - 0, - PosY - EFI_GLYPH_HEIGHT - 1, - SizeOfX, - SizeOfY - (PosY - EFI_GLYPH_HEIGHT - 1), - SizeOfX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) - ); - } else if (FeaturePcdGet (PcdUgaConsumeSupport)) { - Status = UgaDraw->Blt ( - UgaDraw, - (EFI_UGA_PIXEL *) &Color, - EfiUgaVideoFill, - 0, - 0, - 0, - PosY - EFI_GLYPH_HEIGHT - 1, - SizeOfX, - SizeOfY - (PosY - EFI_GLYPH_HEIGHT - 1), - SizeOfX * sizeof (EFI_UGA_PIXEL) - ); - } else { - return EFI_UNSUPPORTED; - } - } - // - // Show progress by drawing blocks - // - for (Index = PreviousValue; Index < BlockNum; Index++) { - PosX = Index * BlockWidth; - if (GraphicsOutput != NULL) { - Status = GraphicsOutput->Blt ( - GraphicsOutput, - &ProgressColor, - EfiBltVideoFill, - 0, - 0, - PosX, - PosY, - BlockWidth - 1, - BlockHeight, - (BlockWidth) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) - ); - } else if (FeaturePcdGet (PcdUgaConsumeSupport)) { - Status = UgaDraw->Blt ( - UgaDraw, - (EFI_UGA_PIXEL *) &ProgressColor, - EfiUgaVideoFill, - 0, - 0, - PosX, - PosY, - BlockWidth - 1, - BlockHeight, - (BlockWidth) * sizeof (EFI_UGA_PIXEL) - ); - } else { - return EFI_UNSUPPORTED; - } - } - - PrintXY ( - (SizeOfX - StrLen (Title) * EFI_GLYPH_WIDTH) / 2, - PosY - EFI_GLYPH_HEIGHT - 1, - &TitleForeground, - &TitleBackground, - Title - ); - - return EFI_SUCCESS; -} /** Perform the memory test base on the memory test intensive level, @@ -346,7 +173,7 @@ PlatformBootManagerMemoryTest ( TmpStr = HiiGetString (gStringPackHandle, STRING_TOKEN (STR_PERFORM_MEM_TEST), NULL); if (TmpStr != NULL) { - PlatformBootManagerShowProgress ( + BootLogoUpdateProgress ( Foreground, Background, TmpStr, @@ -370,7 +197,7 @@ PlatformBootManagerMemoryTest ( if (!FeaturePcdGet(PcdBootlogoOnlyEnable)) { TmpStr = HiiGetString (gStringPackHandle, STRING_TOKEN (STR_PERFORM_MEM_TEST), NULL); if (TmpStr != NULL) { - PlatformBootManagerShowProgress ( + BootLogoUpdateProgress ( Foreground, Background, TmpStr, @@ -414,7 +241,7 @@ PlatformBootManagerMemoryTest ( } PrintXY (10, 10, NULL, NULL, StrTotalMemory); - PlatformBootManagerShowProgress ( + BootLogoUpdateProgress ( Foreground, Background, StrTotalMemory, @@ -430,657 +257,3 @@ PlatformBootManagerMemoryTest ( FreePool (Pos); return ReturnStatus; } - -/** - Convert a *.BMP graphics image to a GOP blt buffer. If a NULL Blt buffer - is passed in a GopBlt buffer will be allocated by this routine. If a GopBlt - buffer is passed in it will be used if it is big enough. - - @param BmpImage Pointer to BMP file - @param BmpImageSize Number of bytes in BmpImage - @param GopBlt Buffer containing GOP version of BmpImage. - @param GopBltSize Size of GopBlt in bytes. - @param PixelHeight Height of GopBlt/BmpImage in pixels - @param PixelWidth Width of GopBlt/BmpImage in pixels - - @retval EFI_SUCCESS GopBlt and GopBltSize are returned. - @retval EFI_UNSUPPORTED BmpImage is not a valid *.BMP image - @retval EFI_BUFFER_TOO_SMALL The passed in GopBlt buffer is not big enough. - GopBltSize will contain the required size. - @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate. - -**/ -EFI_STATUS -PlatformBootManagerConvertBmpToGopBlt ( - IN VOID *BmpImage, - IN UINTN BmpImageSize, - IN OUT VOID **GopBlt, - IN OUT UINTN *GopBltSize, - OUT UINTN *PixelHeight, - OUT UINTN *PixelWidth - ) -{ - UINT8 *Image; - UINT8 *ImageHeader; - BMP_IMAGE_HEADER *BmpHeader; - BMP_COLOR_MAP *BmpColorMap; - EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer; - EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt; - UINT64 BltBufferSize; - UINTN Index; - UINTN Height; - UINTN Width; - UINTN ImageIndex; - UINT32 DataSizePerLine; - BOOLEAN IsAllocated; - UINT32 ColorMapNum; - - if (sizeof (BMP_IMAGE_HEADER) > BmpImageSize) { - return EFI_INVALID_PARAMETER; - } - - BmpHeader = (BMP_IMAGE_HEADER *) BmpImage; - - if (BmpHeader->CharB != 'B' || BmpHeader->CharM != 'M') { - return EFI_UNSUPPORTED; - } - - // - // Doesn't support compress. - // - if (BmpHeader->CompressionType != 0) { - return EFI_UNSUPPORTED; - } - - // - // Only support BITMAPINFOHEADER format. - // BITMAPFILEHEADER + BITMAPINFOHEADER = BMP_IMAGE_HEADER - // - if (BmpHeader->HeaderSize != sizeof (BMP_IMAGE_HEADER) - OFFSET_OF(BMP_IMAGE_HEADER, HeaderSize)) { - return EFI_UNSUPPORTED; - } - - // - // The data size in each line must be 4 byte alignment. - // - DataSizePerLine = ((BmpHeader->PixelWidth * BmpHeader->BitPerPixel + 31) >> 3) & (~0x3); - BltBufferSize = MultU64x32 (DataSizePerLine, BmpHeader->PixelHeight); - if (BltBufferSize > (UINT32) ~0) { - return EFI_INVALID_PARAMETER; - } - - if ((BmpHeader->Size != BmpImageSize) || - (BmpHeader->Size < BmpHeader->ImageOffset) || - (BmpHeader->Size - BmpHeader->ImageOffset != BmpHeader->PixelHeight * DataSizePerLine)) { - return EFI_INVALID_PARAMETER; - } - - // - // Calculate Color Map offset in the image. - // - Image = BmpImage; - BmpColorMap = (BMP_COLOR_MAP *) (Image + sizeof (BMP_IMAGE_HEADER)); - if (BmpHeader->ImageOffset < sizeof (BMP_IMAGE_HEADER)) { - return EFI_INVALID_PARAMETER; - } - - if (BmpHeader->ImageOffset > sizeof (BMP_IMAGE_HEADER)) { - switch (BmpHeader->BitPerPixel) { - case 1: - ColorMapNum = 2; - break; - case 4: - ColorMapNum = 16; - break; - case 8: - ColorMapNum = 256; - break; - default: - ColorMapNum = 0; - break; - } - // - // BMP file may has padding data between the bmp header section and the bmp data section. - // - if (BmpHeader->ImageOffset - sizeof (BMP_IMAGE_HEADER) < sizeof (BMP_COLOR_MAP) * ColorMapNum) { - return EFI_INVALID_PARAMETER; - } - } - - // - // Calculate graphics image data address in the image - // - Image = ((UINT8 *) BmpImage) + BmpHeader->ImageOffset; - ImageHeader = Image; - - // - // Calculate the BltBuffer needed size. - // - BltBufferSize = MultU64x32 ((UINT64) BmpHeader->PixelWidth, BmpHeader->PixelHeight); - // - // Ensure the BltBufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) doesn't overflow - // - if (BltBufferSize > DivU64x32 ((UINTN) ~0, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) { - return EFI_UNSUPPORTED; - } - BltBufferSize = MultU64x32 (BltBufferSize, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); - - IsAllocated = FALSE; - if (*GopBlt == NULL) { - // - // GopBlt is not allocated by caller. - // - *GopBltSize = (UINTN) BltBufferSize; - *GopBlt = AllocatePool (*GopBltSize); - IsAllocated = TRUE; - if (*GopBlt == NULL) { - return EFI_OUT_OF_RESOURCES; - } - } else { - // - // GopBlt has been allocated by caller. - // - if (*GopBltSize < (UINTN) BltBufferSize) { - *GopBltSize = (UINTN) BltBufferSize; - return EFI_BUFFER_TOO_SMALL; - } - } - - *PixelWidth = BmpHeader->PixelWidth; - *PixelHeight = BmpHeader->PixelHeight; - - // - // Convert image from BMP to Blt buffer format - // - BltBuffer = *GopBlt; - for (Height = 0; Height < BmpHeader->PixelHeight; Height++) { - Blt = &BltBuffer[(BmpHeader->PixelHeight - Height - 1) * BmpHeader->PixelWidth]; - for (Width = 0; Width < BmpHeader->PixelWidth; Width++, Image++, Blt++) { - switch (BmpHeader->BitPerPixel) { - case 1: - // - // Convert 1-bit (2 colors) BMP to 24-bit color - // - for (Index = 0; Index < 8 && Width < BmpHeader->PixelWidth; Index++) { - Blt->Red = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Red; - Blt->Green = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Green; - Blt->Blue = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Blue; - Blt++; - Width++; - } - - Blt--; - Width--; - break; - - case 4: - // - // Convert 4-bit (16 colors) BMP Palette to 24-bit color - // - Index = (*Image) >> 4; - Blt->Red = BmpColorMap[Index].Red; - Blt->Green = BmpColorMap[Index].Green; - Blt->Blue = BmpColorMap[Index].Blue; - if (Width < (BmpHeader->PixelWidth - 1)) { - Blt++; - Width++; - Index = (*Image) & 0x0f; - Blt->Red = BmpColorMap[Index].Red; - Blt->Green = BmpColorMap[Index].Green; - Blt->Blue = BmpColorMap[Index].Blue; - } - break; - - case 8: - // - // Convert 8-bit (256 colors) BMP Palette to 24-bit color - // - Blt->Red = BmpColorMap[*Image].Red; - Blt->Green = BmpColorMap[*Image].Green; - Blt->Blue = BmpColorMap[*Image].Blue; - break; - - case 24: - // - // It is 24-bit BMP. - // - Blt->Blue = *Image++; - Blt->Green = *Image++; - Blt->Red = *Image; - break; - - default: - // - // Other bit format BMP is not supported. - // - if (IsAllocated) { - FreePool (*GopBlt); - *GopBlt = NULL; - } - return EFI_UNSUPPORTED; - break; - }; - - } - - ImageIndex = (UINTN) (Image - ImageHeader); - if ((ImageIndex % 4) != 0) { - // - // Bmp Image starts each row on a 32-bit boundary! - // - Image = Image + (4 - (ImageIndex % 4)); - } - } - - return EFI_SUCCESS; -} - -/** - Use SystemTable Conout to stop video based Simple Text Out consoles from going - to the video device. Put up LogoFile on every video device that is a console. - - @param[in] LogoFile File name of logo to display on the center of the screen. - - @retval EFI_SUCCESS ConsoleControl has been flipped to graphics and logo displayed. - @retval EFI_UNSUPPORTED Logo not found - -**/ -EFI_STATUS -PlatformBootManagerEnableQuietBoot ( - IN EFI_GUID *LogoFile - ) -{ - EFI_STATUS Status; - EFI_OEM_BADGING_PROTOCOL *Badging; - UINT32 SizeOfX; - UINT32 SizeOfY; - INTN DestX; - INTN DestY; - UINT8 *ImageData; - UINTN ImageSize; - UINTN BltSize; - UINT32 Instance; - EFI_BADGING_FORMAT Format; - EFI_BADGING_DISPLAY_ATTRIBUTE Attribute; - UINTN CoordinateX; - UINTN CoordinateY; - UINTN Height; - UINTN Width; - EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt; - EFI_UGA_DRAW_PROTOCOL *UgaDraw; - UINT32 ColorDepth; - UINT32 RefreshRate; - EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput; - EFI_BOOT_LOGO_PROTOCOL *BootLogo; - UINTN NumberOfLogos; - EFI_GRAPHICS_OUTPUT_BLT_PIXEL *LogoBlt; - UINTN LogoDestX; - UINTN LogoDestY; - UINTN LogoHeight; - UINTN LogoWidth; - UINTN NewDestX; - UINTN NewDestY; - UINTN NewHeight; - UINTN NewWidth; - UINT64 BufferSize; - - UgaDraw = NULL; - // - // Try to open GOP first - // - Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **) &GraphicsOutput); - if (EFI_ERROR (Status) && FeaturePcdGet (PcdUgaConsumeSupport)) { - GraphicsOutput = NULL; - // - // Open GOP failed, try to open UGA - // - Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiUgaDrawProtocolGuid, (VOID **) &UgaDraw); - } - if (EFI_ERROR (Status)) { - return EFI_UNSUPPORTED; - } - - // - // Try to open Boot Logo Protocol. - // - BootLogo = NULL; - gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo); - - // - // Erase Cursor from screen - // - gST->ConOut->EnableCursor (gST->ConOut, FALSE); - - Badging = NULL; - Status = gBS->LocateProtocol (&gEfiOEMBadgingProtocolGuid, NULL, (VOID **) &Badging); - - if (GraphicsOutput != NULL) { - SizeOfX = GraphicsOutput->Mode->Info->HorizontalResolution; - SizeOfY = GraphicsOutput->Mode->Info->VerticalResolution; - - } else if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) { - Status = UgaDraw->GetMode (UgaDraw, &SizeOfX, &SizeOfY, &ColorDepth, &RefreshRate); - if (EFI_ERROR (Status)) { - return EFI_UNSUPPORTED; - } - } else { - return EFI_UNSUPPORTED; - } - - Blt = NULL; - NumberOfLogos = 0; - LogoDestX = 0; - LogoDestY = 0; - LogoHeight = 0; - LogoWidth = 0; - NewDestX = 0; - NewDestY = 0; - NewHeight = 0; - NewWidth = 0; - Instance = 0; - while (1) { - ImageData = NULL; - ImageSize = 0; - - if (Badging != NULL) { - // - // Get image from OEMBadging protocol. - // - Status = Badging->GetImage ( - Badging, - &Instance, - &Format, - &ImageData, - &ImageSize, - &Attribute, - &CoordinateX, - &CoordinateY - ); - if (EFI_ERROR (Status)) { - goto Done; - } - - // - // Currently only support BMP format. - // - if (Format != EfiBadgingFormatBMP) { - if (ImageData != NULL) { - FreePool (ImageData); - } - continue; - } - } else { - // - // Get the specified image from FV. - // - Status = GetSectionFromAnyFv (LogoFile, EFI_SECTION_RAW, 0, (VOID **) &ImageData, &ImageSize); - if (EFI_ERROR (Status)) { - return EFI_UNSUPPORTED; - } - - CoordinateX = 0; - CoordinateY = 0; - if (!FeaturePcdGet(PcdBootlogoOnlyEnable)) { - Attribute = EfiBadgingDisplayAttributeCenter; - } else { - Attribute = EfiBadgingDisplayAttributeCustomized; - } - } - - if (Blt != NULL) { - FreePool (Blt); - } - Blt = NULL; - Status = PlatformBootManagerConvertBmpToGopBlt ( - ImageData, - ImageSize, - (VOID **) &Blt, - &BltSize, - &Height, - &Width - ); - if (EFI_ERROR (Status)) { - FreePool (ImageData); - - if (Badging == NULL) { - return Status; - } else { - continue; - } - } - - // - // Calculate the display position according to Attribute. - // - switch (Attribute) { - case EfiBadgingDisplayAttributeLeftTop: - DestX = CoordinateX; - DestY = CoordinateY; - break; - - case EfiBadgingDisplayAttributeCenterTop: - DestX = (SizeOfX - Width) / 2; - DestY = CoordinateY; - break; - - case EfiBadgingDisplayAttributeRightTop: - DestX = (SizeOfX - Width - CoordinateX); - DestY = CoordinateY;; - break; - - case EfiBadgingDisplayAttributeCenterRight: - DestX = (SizeOfX - Width - CoordinateX); - DestY = (SizeOfY - Height) / 2; - break; - - case EfiBadgingDisplayAttributeRightBottom: - DestX = (SizeOfX - Width - CoordinateX); - DestY = (SizeOfY - Height - CoordinateY); - break; - - case EfiBadgingDisplayAttributeCenterBottom: - DestX = (SizeOfX - Width) / 2; - DestY = (SizeOfY - Height - CoordinateY); - break; - - case EfiBadgingDisplayAttributeLeftBottom: - DestX = CoordinateX; - DestY = (SizeOfY - Height - CoordinateY); - break; - - case EfiBadgingDisplayAttributeCenterLeft: - DestX = CoordinateX; - DestY = (SizeOfY - Height) / 2; - break; - - case EfiBadgingDisplayAttributeCenter: - DestX = (SizeOfX - Width) / 2; - DestY = (SizeOfY - Height) / 2; - break; - - case EfiBadgingDisplayAttributeCustomized: - DestX = (SizeOfX - Width) / 2; - DestY = ((SizeOfY * 382) / 1000) - Height / 2; - break; - - default: - DestX = CoordinateX; - DestY = CoordinateY; - break; - } - - if ((DestX >= 0) && (DestY >= 0)) { - if (GraphicsOutput != NULL) { - Status = GraphicsOutput->Blt ( - GraphicsOutput, - Blt, - EfiBltBufferToVideo, - 0, - 0, - (UINTN) DestX, - (UINTN) DestY, - Width, - Height, - Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) - ); - } else if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) { - Status = UgaDraw->Blt ( - UgaDraw, - (EFI_UGA_PIXEL *) Blt, - EfiUgaBltBufferToVideo, - 0, - 0, - (UINTN) DestX, - (UINTN) DestY, - Width, - Height, - Width * sizeof (EFI_UGA_PIXEL) - ); - } else { - Status = EFI_UNSUPPORTED; - } - - // - // Report displayed Logo information. - // - if (!EFI_ERROR (Status)) { - NumberOfLogos++; - - if (LogoWidth == 0) { - // - // The first Logo. - // - LogoDestX = (UINTN) DestX; - LogoDestY = (UINTN) DestY; - LogoWidth = Width; - LogoHeight = Height; - } else { - // - // Merge new logo with old one. - // - NewDestX = MIN ((UINTN) DestX, LogoDestX); - NewDestY = MIN ((UINTN) DestY, LogoDestY); - NewWidth = MAX ((UINTN) DestX + Width, LogoDestX + LogoWidth) - NewDestX; - NewHeight = MAX ((UINTN) DestY + Height, LogoDestY + LogoHeight) - NewDestY; - - LogoDestX = NewDestX; - LogoDestY = NewDestY; - LogoWidth = NewWidth; - LogoHeight = NewHeight; - } - } - } - - FreePool (ImageData); - - if (Badging == NULL) { - break; - } - } - -Done: - if (BootLogo == NULL || NumberOfLogos == 0) { - // - // No logo displayed. - // - if (Blt != NULL) { - FreePool (Blt); - } - - return Status; - } - - // - // Advertise displayed Logo information. - // - if (NumberOfLogos == 1) { - // - // Only one logo displayed, use its Blt buffer directly for BootLogo protocol. - // - LogoBlt = Blt; - Status = EFI_SUCCESS; - } else { - // - // More than one Logo displayed, get merged BltBuffer using VideoToBuffer operation. - // - if (Blt != NULL) { - FreePool (Blt); - } - - // - // Ensure the LogoHeight * LogoWidth doesn't overflow - // - if (LogoHeight > DivU64x64Remainder ((UINTN) ~0, LogoWidth, NULL)) { - return EFI_UNSUPPORTED; - } - BufferSize = MultU64x64 (LogoWidth, LogoHeight); - - // - // Ensure the BufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) doesn't overflow - // - if (BufferSize > DivU64x32 ((UINTN) ~0, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) { - return EFI_UNSUPPORTED; - } - - LogoBlt = AllocateZeroPool ((UINTN)BufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); - if (LogoBlt == NULL) { - return EFI_OUT_OF_RESOURCES; - } - - if (GraphicsOutput != NULL) { - Status = GraphicsOutput->Blt ( - GraphicsOutput, - LogoBlt, - EfiBltVideoToBltBuffer, - LogoDestX, - LogoDestY, - 0, - 0, - LogoWidth, - LogoHeight, - LogoWidth * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) - ); - } else if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) { - Status = UgaDraw->Blt ( - UgaDraw, - (EFI_UGA_PIXEL *) LogoBlt, - EfiUgaVideoToBltBuffer, - LogoDestX, - LogoDestY, - 0, - 0, - LogoWidth, - LogoHeight, - LogoWidth * sizeof (EFI_UGA_PIXEL) - ); - } else { - Status = EFI_UNSUPPORTED; - } - } - - if (!EFI_ERROR (Status)) { - BootLogo->SetBootLogo (BootLogo, LogoBlt, LogoDestX, LogoDestY, LogoWidth, LogoHeight); - } - FreePool (LogoBlt); - - return Status; -} - -/** - Use SystemTable Conout to turn on video based Simple Text Out consoles. The - Simple Text Out screens will now be synced up with all non video output devices - - @retval EFI_SUCCESS UGA devices are back in text mode and synced up. - -**/ -EFI_STATUS -PlatformBootManagerDisableQuietBoot ( - VOID - ) -{ - // - // Enable Cursor on Screen - // - gST->ConOut->EnableCursor (gST->ConOut, TRUE); - return EFI_SUCCESS; -} diff --git a/Nt32Pkg/Library/PlatformBootManagerLib/PlatformBootManager.c b/Nt32Pkg/Library/PlatformBootManagerLib/PlatformBootManager.c index e944105b3925..82f7647c7039 100644 --- a/Nt32Pkg/Library/PlatformBootManagerLib/PlatformBootManager.c +++ b/Nt32Pkg/Library/PlatformBootManagerLib/PlatformBootManager.c @@ -38,14 +38,14 @@ PlatformBootManagerDiagnostics ( // from the graphic lib // if (QuietBoot) { - PlatformBootManagerEnableQuietBoot (PcdGetPtr(PcdLogoFile)); + BootLogoEnableLogo (ImageFormatBmp, PcdGetPtr(PcdLogoFile), EdkiiPlatformLogoDisplayAttributeCenter, 0, 0); // // Perform system diagnostic // Status = PlatformBootManagerMemoryTest (MemoryTestLevel); if (EFI_ERROR (Status)) { - PlatformBootManagerDisableQuietBoot (); + BootLogoDisableLogo (); } return; @@ -271,7 +271,7 @@ PlatformBootManagerWaitCallback ( Black.Blue = Black.Green = Black.Red = Black.Reserved = 0; White.Blue = White.Green = White.Red = White.Reserved = 0xFF; - PlatformBootManagerShowProgress ( + BootLogoUpdateProgress ( White, Black, L"Start boot option", diff --git a/Nt32Pkg/Library/PlatformBootManagerLib/PlatformBootManager.h b/Nt32Pkg/Library/PlatformBootManagerLib/PlatformBootManager.h index 7e0fae847fb6..e2c6681702fd 100644 --- a/Nt32Pkg/Library/PlatformBootManagerLib/PlatformBootManager.h +++ b/Nt32Pkg/Library/PlatformBootManagerLib/PlatformBootManager.h @@ -15,16 +15,11 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #define _PLATFORM_BOOT_MANAGER_H #include -#include #include #include #include #include #include -#include -#include -#include -#include #include #include @@ -40,6 +35,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include #include +#include typedef struct { diff --git a/Nt32Pkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf b/Nt32Pkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf index 9b1eeaba02ed..71e8738a6a9d 100644 --- a/Nt32Pkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf +++ b/Nt32Pkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf @@ -52,6 +52,7 @@ DevicePathLib HiiLib PrintLib + BootLogoLib [Guids] gEfiWinNtSystemConfigGuid @@ -60,7 +61,6 @@ gEfiGenericMemTestProtocolGuid ## CONSUMES gEfiGraphicsOutputProtocolGuid ## CONSUMES gEfiUgaDrawProtocolGuid ## CONSUMES - gEfiOEMBadgingProtocolGuid ## CONSUMES gEfiBootLogoProtocolGuid ## CONSUMES [Pcd] diff --git a/Nt32Pkg/Nt32Pkg.dsc b/Nt32Pkg/Nt32Pkg.dsc index 21e1f69353bf..a9df9b11dc65 100644 --- a/Nt32Pkg/Nt32Pkg.dsc +++ b/Nt32Pkg/Nt32Pkg.dsc @@ -117,6 +117,8 @@ TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf SerialPortLib|MdePkg/Library/BaseSerialPortLibNull/BaseSerialPortLibNull.inf CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf + ImageDecoderLib|MdeModulePkg/Library/ImageDecoderLib/ImageDecoderLib.inf + BootLogoLib|MdeModulePkg/Library/BootLogoLib/BootLogoLib.inf # # Platform # @@ -440,7 +442,10 @@ NetworkPkg/HttpDxe/HttpDxe.inf NetworkPkg/HttpUtilitiesDxe/HttpUtilitiesDxe.inf - MdeModulePkg/Universal/BdsDxe/BdsDxe.inf + MdeModulePkg/Universal/BdsDxe/BdsDxe.inf { + + NULL|MdeModulePkg/Library/BmpImageDecoderLib/BmpImageDecoderLib.inf + } MdeModulePkg/Application/UiApp/UiApp.inf MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthManagerDxe.inf MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf From d6ca0be1685b76bbe5d0ee507c6250f00bf435d5 Mon Sep 17 00:00:00 2001 From: Ruiyu Ni Date: Wed, 18 Nov 2015 08:55:06 +0000 Subject: [PATCH 150/525] MdeModulePkg/BmpImageDecoderLib: Support ImageFormatUnknown type Enhance the library to handle unknown image format. (Sync patch r18774 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ruiyu Ni Reviewed-by: Feng Tian git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18884 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Library/BmpImageDecoderLib/BmpImageDecoderLib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MdeModulePkg/Library/BmpImageDecoderLib/BmpImageDecoderLib.c b/MdeModulePkg/Library/BmpImageDecoderLib/BmpImageDecoderLib.c index 86dcc918c2c6..28afd4fa9a9b 100644 --- a/MdeModulePkg/Library/BmpImageDecoderLib/BmpImageDecoderLib.c +++ b/MdeModulePkg/Library/BmpImageDecoderLib/BmpImageDecoderLib.c @@ -65,7 +65,7 @@ BmpImageDecoderLibConvertBmpToGopBlt ( ASSERT ((GopBlt != NULL) && (GopBltSize != NULL)); - if (ImageFormat != ImageFormatBmp) { + if ((ImageFormat != ImageFormatBmp) && (ImageFormat != ImageFormatUnknown)) { return EFI_UNSUPPORTED; } From 9688300b28a17aea7f392f9d0d31abdda2cd0998 Mon Sep 17 00:00:00 2001 From: Ruiyu Ni Date: Wed, 18 Nov 2015 08:56:06 +0000 Subject: [PATCH 151/525] MdeModulePkg: Change PlatformLogo.GetImage use INTN for minus value The parameter name is also changed from Coordinate* to Offset* to reflect that it's the offset to the location specified by Attribute. For example, when the Attribute is Center, OffsetX and OffsetY are used to specify the offset to the Center. OffsetX = 100 means 100 pixels right to the Center. (Sync patch r18866 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ruiyu Ni Reviewed-by: Feng Tian git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18885 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Include/Protocol/PlatformLogo.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/MdeModulePkg/Include/Protocol/PlatformLogo.h b/MdeModulePkg/Include/Protocol/PlatformLogo.h index 9ac87f1748d3..8c1d3cad40f7 100644 --- a/MdeModulePkg/Include/Protocol/PlatformLogo.h +++ b/MdeModulePkg/Include/Protocol/PlatformLogo.h @@ -55,8 +55,8 @@ typedef enum { supports the .bmp file format. @param ImageSize The size of the image returned. @param Attribute The display attributes of the image returned. - @param CoordinateX The X coordinate of the image. - @param CoordinateY The Y coordinate of the image. + @param OffsetX The X offset of the image regarding the Attribute. + @param 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. @@ -71,8 +71,8 @@ EFI_STATUS OUT UINT8 **ImageData, OUT UINTN *ImageSize, OUT EDKII_PLATFORM_LOGO_DISPLAY_ATTRIBUTE *Attribute, - OUT UINTN *CoordinateX, - OUT UINTN *CoordinateY + OUT INTN *OffsetX, + OUT INTN *OffsetY ); From ca8497a5f7b79f25952945d9c5a13d5762c20f88 Mon Sep 17 00:00:00 2001 From: Ruiyu Ni Date: Wed, 18 Nov 2015 08:56:57 +0000 Subject: [PATCH 152/525] MdeModulePkg: Change BootLogoEnableLogo use INTN for minus value The parameter name is also changed from Coordinate* to Offset* to reflect that it's the offset to the location specified by Attribute. For example, when the Attribute is Center, OffsetX and OffsetY are used to specify the offset to the Center. OffsetX = 100 means 100 pixels right to the Center. (Sync patch r18867 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ruiyu Ni Reviewed-by: Feng Tian git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18886 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Include/Library/BootLogoLib.h | 8 +-- .../Library/BootLogoLib/BootLogoLib.c | 63 +++++++++---------- 2 files changed, 34 insertions(+), 37 deletions(-) diff --git a/MdeModulePkg/Include/Library/BootLogoLib.h b/MdeModulePkg/Include/Library/BootLogoLib.h index 363740537107..b39d61b7c3e5 100644 --- a/MdeModulePkg/Include/Library/BootLogoLib.h +++ b/MdeModulePkg/Include/Library/BootLogoLib.h @@ -24,8 +24,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. @param[in] ImageFormat Format of the image file. @param[in] LogoFile The file name of logo to display. @param[in] Attribute The display attributes of the image returned. - @param[in] CoordinateX The X coordinate of the image. - @param[in] CoordinateY The Y coordinate of the image. + @param[in] OffsetX The X offset of the image regarding the Attribute. + @param[in] OffsetY The Y offset of the image regarding the Attribute. @retval EFI_SUCCESS Logo was displayed. @retval EFI_UNSUPPORTED Logo was not found or cannot be displayed. @@ -36,8 +36,8 @@ BootLogoEnableLogo ( IN IMAGE_FORMAT ImageFormat, IN EFI_GUID *Logo, IN EDKII_PLATFORM_LOGO_DISPLAY_ATTRIBUTE Attribute, - IN UINTN CoordinateX, - IN UINTN CoordinateY + IN INTN OffsetX, + IN INTN OffsetY ); diff --git a/MdeModulePkg/Library/BootLogoLib/BootLogoLib.c b/MdeModulePkg/Library/BootLogoLib/BootLogoLib.c index 312adb04db42..f824ae13c286 100644 --- a/MdeModulePkg/Library/BootLogoLib/BootLogoLib.c +++ b/MdeModulePkg/Library/BootLogoLib/BootLogoLib.c @@ -35,8 +35,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. @param[in] ImageFormat Format of the image file. @param[in] LogoFile The file name of logo to display. @param[in] Attribute The display attributes of the image returned. - @param[in] CoordinateX The X coordinate of the image. - @param[in] CoordinateY The Y coordinate of the image. + @param[in] OffsetX The X offset of the image regarding the Attribute. + @param[in] OffsetY The Y offset of the image regarding the Attribute. @retval EFI_SUCCESS Logo was displayed. @retval EFI_UNSUPPORTED Logo was not found or cannot be displayed. @@ -47,8 +47,8 @@ BootLogoEnableLogo ( IN IMAGE_FORMAT ImageFormat, IN EFI_GUID *Logo, IN EDKII_PLATFORM_LOGO_DISPLAY_ATTRIBUTE Attribute, - IN UINTN CoordinateX, - IN UINTN CoordinateY + IN INTN OffsetX, + IN INTN OffsetY ) { EFI_STATUS Status; @@ -160,8 +160,8 @@ BootLogoEnableLogo ( &ImageData, &ImageSize, &Attribute, - &CoordinateX, - &CoordinateY + &OffsetX, + &OffsetY ); if (EFI_ERROR (Status)) { break; @@ -199,48 +199,42 @@ BootLogoEnableLogo ( // switch (Attribute) { case EdkiiPlatformLogoDisplayAttributeLeftTop: - DestX = CoordinateX; - DestY = CoordinateY; + DestX = 0; + DestY = 0; break; - case EdkiiPlatformLogoDisplayAttributeCenterTop: DestX = (SizeOfX - Width) / 2; - DestY = CoordinateY; + DestY = 0; break; - case EdkiiPlatformLogoDisplayAttributeRightTop: - DestX = (SizeOfX - Width - CoordinateX); - DestY = CoordinateY;; + DestX = SizeOfX - Width; + DestY = 0; break; - case EdkiiPlatformLogoDisplayAttributeCenterRight: - DestX = (SizeOfX - Width - CoordinateX); + case EdkiiPlatformLogoDisplayAttributeCenterLeft: + DestX = 0; DestY = (SizeOfY - Height) / 2; break; - - case EdkiiPlatformLogoDisplayAttributeRightBottom: - DestX = (SizeOfX - Width - CoordinateX); - DestY = (SizeOfY - Height - CoordinateY); - break; - - case EdkiiPlatformLogoDisplayAttributeCenterBottom: + case EdkiiPlatformLogoDisplayAttributeCenter: DestX = (SizeOfX - Width) / 2; - DestY = (SizeOfY - Height - CoordinateY); - break; - - case EdkiiPlatformLogoDisplayAttributeLeftBottom: - DestX = CoordinateX; - DestY = (SizeOfY - Height - CoordinateY); + DestY = (SizeOfY - Height) / 2; break; - - case EdkiiPlatformLogoDisplayAttributeCenterLeft: - DestX = CoordinateX; + case EdkiiPlatformLogoDisplayAttributeCenterRight: + DestX = SizeOfX - Width; DestY = (SizeOfY - Height) / 2; break; - case EdkiiPlatformLogoDisplayAttributeCenter: + case EdkiiPlatformLogoDisplayAttributeLeftBottom: + DestX = 0; + DestY = SizeOfY - Height; + break; + case EdkiiPlatformLogoDisplayAttributeCenterBottom: DestX = (SizeOfX - Width) / 2; - DestY = (SizeOfY - Height) / 2; + DestY = SizeOfY - Height; + break; + case EdkiiPlatformLogoDisplayAttributeRightBottom: + DestX = SizeOfX - Width; + DestY = SizeOfY - Height; break; default: @@ -248,6 +242,9 @@ BootLogoEnableLogo ( break; } + DestX += OffsetX; + DestY += OffsetY; + if ((DestX >= 0) && (DestY >= 0)) { if (GraphicsOutput != NULL) { Status = GraphicsOutput->Blt ( From 8021dff6657c6330d80e38c53c256cd96e43b35f Mon Sep 17 00:00:00 2001 From: Jeff Fan Date: Wed, 18 Nov 2015 13:06:17 +0000 Subject: [PATCH 153/525] External link to BaseTools Win binary r103(main trunk r18767) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18892 6f19259b-4bc3-4df7-8a09-765794883524 From 04d5cc639b207b0d3b9922acc7c669fffe25ef79 Mon Sep 17 00:00:00 2001 From: Star Zeng Date: Thu, 19 Nov 2015 02:32:03 +0000 Subject: [PATCH 154/525] MdeModulePkg PeiCore: PeiInstallPeiMemory improper ASSERT test on second call The ASSERT (PrivateData->PeiMemoryInstalled) in if (PrivateData->PeiMemoryInstalled) condition is useless, it should be ASSERT (FALSE) to follow the code's expectation. (Sync patch r18887 from main trunk.) Cc: Liming Gao Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Star Zeng Reviewed-by: Liming Gao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18901 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Core/Pei/Memory/MemoryServices.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MdeModulePkg/Core/Pei/Memory/MemoryServices.c b/MdeModulePkg/Core/Pei/Memory/MemoryServices.c index 36bdc73ebdc5..2f9b9dea3149 100644 --- a/MdeModulePkg/Core/Pei/Memory/MemoryServices.c +++ b/MdeModulePkg/Core/Pei/Memory/MemoryServices.c @@ -96,7 +96,7 @@ PeiInstallPeiMemory ( // if (PrivateData->PeiMemoryInstalled) { DEBUG ((EFI_D_ERROR, "ERROR: PeiInstallPeiMemory is called more than once!\n")); - ASSERT (PrivateData->PeiMemoryInstalled); + ASSERT (FALSE); return EFI_SUCCESS; } From b324f3af6461691f004d2aac7727e59f9548b3ef Mon Sep 17 00:00:00 2001 From: Jeff Fan Date: Fri, 20 Nov 2015 03:11:40 +0000 Subject: [PATCH 155/525] Rollback the changes from r18879 - r18886. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18911 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Include/Library/BootLogoLib.h | 82 -- .../Include/Library/ImageDecoderLib.h | 76 -- MdeModulePkg/Include/Protocol/PlatformLogo.h | 86 -- .../BmpImageDecoderLib/BmpImageDecoderLib.c | 272 ------ .../BmpImageDecoderLib/BmpImageDecoderLib.inf | 42 - .../Library/BootLogoLib/BootLogoLib.c | 581 ------------ .../Library/BootLogoLib/BootLogoLib.inf | 59 -- .../Library/ImageDecoderLib/ImageDecoderLib.c | 121 --- .../ImageDecoderLib/ImageDecoderLib.inf | 42 - MdeModulePkg/MdeModulePkg.dec | 11 - MdeModulePkg/MdeModulePkg.dsc | 4 - .../PlatformBootManagerLib/MemoryTest.c | 833 +++++++++++++++++- .../PlatformBootManager.c | 6 +- .../PlatformBootManager.h | 6 +- .../PlatformBootManagerLib.inf | 2 +- Nt32Pkg/Nt32Pkg.dsc | 7 +- 16 files changed, 840 insertions(+), 1390 deletions(-) delete mode 100644 MdeModulePkg/Include/Library/BootLogoLib.h delete mode 100644 MdeModulePkg/Include/Library/ImageDecoderLib.h delete mode 100644 MdeModulePkg/Include/Protocol/PlatformLogo.h delete mode 100644 MdeModulePkg/Library/BmpImageDecoderLib/BmpImageDecoderLib.c delete mode 100644 MdeModulePkg/Library/BmpImageDecoderLib/BmpImageDecoderLib.inf delete mode 100644 MdeModulePkg/Library/BootLogoLib/BootLogoLib.c delete mode 100644 MdeModulePkg/Library/BootLogoLib/BootLogoLib.inf delete mode 100644 MdeModulePkg/Library/ImageDecoderLib/ImageDecoderLib.c delete mode 100644 MdeModulePkg/Library/ImageDecoderLib/ImageDecoderLib.inf diff --git a/MdeModulePkg/Include/Library/BootLogoLib.h b/MdeModulePkg/Include/Library/BootLogoLib.h deleted file mode 100644 index b39d61b7c3e5..000000000000 --- a/MdeModulePkg/Include/Library/BootLogoLib.h +++ /dev/null @@ -1,82 +0,0 @@ -/** @file - This library is only intended to be used by PlatformBootManagerLib - to show progress bar and LOGO. - -Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.
-This program and the accompanying materials are licensed and made available under -the terms and conditions of the BSD License that accompanies this distribution. -The full text of the license may be found at -http://opensource.org/licenses/bsd-license.php. - -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -#ifndef _BOOT_LOGO_LIB_H_ -#define _BOOT_LOGO_LIB_H_ - -#include - -/** - Show LOGO on all consoles. - - @param[in] ImageFormat Format of the image file. - @param[in] LogoFile The file name of logo to display. - @param[in] Attribute The display attributes of the image returned. - @param[in] OffsetX The X offset of the image regarding the Attribute. - @param[in] OffsetY The Y offset of the image regarding the Attribute. - - @retval EFI_SUCCESS Logo was displayed. - @retval EFI_UNSUPPORTED Logo was not found or cannot be displayed. -**/ -EFI_STATUS -EFIAPI -BootLogoEnableLogo ( - IN IMAGE_FORMAT ImageFormat, - IN EFI_GUID *Logo, - IN EDKII_PLATFORM_LOGO_DISPLAY_ATTRIBUTE Attribute, - IN INTN OffsetX, - IN INTN OffsetY - ); - - -/** - Use SystemTable ConOut to turn on video based Simple Text Out consoles. The - Simple Text Out screens will now be synced up with all non-video output devices. - - @retval EFI_SUCCESS UGA devices are back in text mode and synced up. - -**/ -EFI_STATUS -EFIAPI -BootLogoDisableLogo ( - VOID - ); - -/** - - Update progress bar with title above it. It only works in Graphics mode. - - @param TitleForeground Foreground color for Title. - @param TitleBackground Background color for Title. - @param Title Title above progress bar. - @param ProgressColor Progress bar color. - @param Progress Progress (0-100) - @param PreviousValue The previous value of the progress. - - @retval EFI_STATUS Successly update the progress bar - -**/ -EFI_STATUS -EFIAPI -BootLogoUpdateProgress ( - IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL TitleForeground, - IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL TitleBackground, - IN CHAR16 *Title, - IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL ProgressColor, - IN UINTN Progress, - IN UINTN PreviousValue - ); - -#endif diff --git a/MdeModulePkg/Include/Library/ImageDecoderLib.h b/MdeModulePkg/Include/Library/ImageDecoderLib.h deleted file mode 100644 index 928a09483aea..000000000000 --- a/MdeModulePkg/Include/Library/ImageDecoderLib.h +++ /dev/null @@ -1,76 +0,0 @@ -/** @file - This library provides image decoding service by managing the different - image decoding libraries. - -Copyright (c) 2015, Intel Corporation. All rights reserved.
-This program and the accompanying materials are licensed and made available under -the terms and conditions of the BSD License that accompanies this distribution. -The full text of the license may be found at -http://opensource.org/licenses/bsd-license.php. - -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ -#ifndef __IMAGE_DECODER_LIB_H__ -#define __IMAGE_DECODER_LIB_H__ -#include - -typedef -EFI_STATUS -(EFIAPI *DECODE_IMAGE)( - IN IMAGE_FORMAT ImageFormat, - IN UINT8 *Image, - IN UINTN ImageSize, - OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL **GopBlt, - OUT UINTN *GopBltSize, - OUT UINTN *PixelWidth, - OUT UINTN *PixelHeight - ); - -/** - Convert a graphics image to a callee allocated GOP blt buffer. - - @param ImageFormat Format of the image file. - @param Image Pointer to image file. - @param ImageSize Number of bytes in Image. - @param GopBlt Buffer containing GOP version of Image. - @param GopBltSize Size of GopBlt in bytes. - @param PixelWidth Width of GopBlt/Image in pixels. - @param PixelHeight Height of GopBlt/Image in pixels. - - @retval EFI_SUCCESS GopBlt and GopBltSize are returned. - @retval EFI_INVALID_PARAMETER GopBlt or GopBltSize is NULL. - @retval EFI_INVALID_PARAMETER Image is NULL or ImageSize is 0. - @retval EFI_UNSUPPORTED Image is not supported. - @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate. - -**/ -EFI_STATUS -EFIAPI -DecodeImage ( - IN IMAGE_FORMAT ImageFormat, - IN UINT8 *Image, - IN UINTN ImageSize, - OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL **GopBlt, - OUT UINTN *GopBltSize, - OUT UINTN *PixelWidth, - OUT UINTN *PixelHeight - ); - -/** - Register an image decoder. - - @param Decoder An image decoder. - - @retval EFI_SUCCESS The decoder was successfully registered. - @retval EFI_OUT_OF_RESOURCES No enough resource to register the decoder. - -**/ -EFI_STATUS -EFIAPI -RegisterImageDecoder ( - IN DECODE_IMAGE Decoder - ); - -#endif diff --git a/MdeModulePkg/Include/Protocol/PlatformLogo.h b/MdeModulePkg/Include/Protocol/PlatformLogo.h deleted file mode 100644 index 8c1d3cad40f7..000000000000 --- a/MdeModulePkg/Include/Protocol/PlatformLogo.h +++ /dev/null @@ -1,86 +0,0 @@ -/** @file - The Platform Logo Protocol defines the interface to get the Platform logo - image with the display attribute. - -Copyright (c) 2015, Intel Corporation. All rights reserved.
-This program and the accompanying materials are licensed and made available under -the terms and conditions of the BSD License that accompanies this distribution. -The full text of the license may be found at -http://opensource.org/licenses/bsd-license.php. - -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -#ifndef __PLATFORM_LOGO_H__ -#define __PLATFORM_LOGO_H__ - -// -// GUID for EDKII Platform Logo Protocol -// -#define EDKII_PLATFORM_LOGO_PROTOCOL_GUID \ - { 0x9b517978, 0xeba1, 0x44e7, { 0xba, 0x65, 0x7c, 0x2c, 0xd0, 0x8b, 0xf8, 0xe9 } } - -typedef struct _EDKII_PLATFORM_LOGO_PROTOCOL EDKII_PLATFORM_LOGO_PROTOCOL; - -typedef enum { - ImageFormatUnknown, - ImageFormatBmp, - ImageFormatJpeg, - ImageFormatTiff, - ImageFormatGif -} IMAGE_FORMAT; - -typedef enum { - EdkiiPlatformLogoDisplayAttributeLeftTop, - EdkiiPlatformLogoDisplayAttributeCenterTop, - EdkiiPlatformLogoDisplayAttributeRightTop, - EdkiiPlatformLogoDisplayAttributeCenterRight, - EdkiiPlatformLogoDisplayAttributeRightBottom, - EdkiiPlatformLogoDisplayAttributeCenterBottom, - EdkiiPlatformLogoDisplayAttributeLeftBottom, - EdkiiPlatformLogoDisplayAttributeCenterLeft, - EdkiiPlatformLogoDisplayAttributeCenter -} EDKII_PLATFORM_LOGO_DISPLAY_ATTRIBUTE; - -/** - - Load a platform logo image and return its data and attributes. - - @param This The pointer to this protocol instance. - @param Instance The visible image instance is found. - @param Format The format of the image. Examples: BMP, JPEG. - @param ImageData The image data for the badge file. Currently only - supports the .bmp file format. - @param ImageSize The size of the image returned. - @param Attribute The display attributes of the image returned. - @param OffsetX The X offset of the image regarding the Attribute. - @param 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. - -**/ -typedef -EFI_STATUS -(EFIAPI *EDKII_PLATFORM_LOGO_GET_IMAGE)( - IN EDKII_PLATFORM_LOGO_PROTOCOL *This, - IN OUT UINT32 *Instance, - OUT IMAGE_FORMAT *Format, - OUT UINT8 **ImageData, - OUT UINTN *ImageSize, - OUT EDKII_PLATFORM_LOGO_DISPLAY_ATTRIBUTE *Attribute, - OUT INTN *OffsetX, - OUT INTN *OffsetY -); - - -struct _EDKII_PLATFORM_LOGO_PROTOCOL { - EDKII_PLATFORM_LOGO_GET_IMAGE GetImage; -}; - - -extern EFI_GUID gEdkiiPlatformLogoProtocolGuid; - -#endif diff --git a/MdeModulePkg/Library/BmpImageDecoderLib/BmpImageDecoderLib.c b/MdeModulePkg/Library/BmpImageDecoderLib/BmpImageDecoderLib.c deleted file mode 100644 index 28afd4fa9a9b..000000000000 --- a/MdeModulePkg/Library/BmpImageDecoderLib/BmpImageDecoderLib.c +++ /dev/null @@ -1,272 +0,0 @@ -/** @file - This library provides BMP image decoding capability. - -Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.
-This program and the accompanying materials are licensed and made available under -the terms and conditions of the BSD License that accompanies this distribution. -The full text of the license may be found at -http://opensource.org/licenses/bsd-license.php. - -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -#include -#include -#include -#include -#include -#include -#include - -/** - Convert a *.BMP graphics image to a callee allocated GOP blt buffer. - - @param ImageFormat Format of the image file. - @param BmpImage Pointer to BMP file - @param BmpImageSize Number of bytes in BmpImage - @param GopBlt Buffer containing GOP version of BmpImage. - @param GopBltSize Size of GopBlt in bytes. - @param PixelHeight Height of GopBlt/BmpImage in pixels - @param PixelWidth Width of GopBlt/BmpImage in pixels - - @retval EFI_SUCCESS GopBlt and GopBltSize are returned. - @retval EFI_INVALID_PARAMETER GopBlt or GopBltSize is NULL. - @retval EFI_UNSUPPORTED BmpImage is not a valid *.BMP image - @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate. - -**/ -EFI_STATUS -EFIAPI -BmpImageDecoderLibConvertBmpToGopBlt ( - IN IMAGE_FORMAT ImageFormat, - IN UINT8 *BmpImage, - IN UINTN BmpImageSize, - OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL **GopBlt, - OUT UINTN *GopBltSize, - OUT UINTN *PixelWidth, - OUT UINTN *PixelHeight - ) -{ - UINT8 *Image; - UINT8 *ImageHeader; - BMP_IMAGE_HEADER *BmpHeader; - BMP_COLOR_MAP *BmpColorMap; - EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer; - EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt; - UINT64 BltBufferSize; - UINTN Index; - UINTN Height; - UINTN Width; - UINTN ImageIndex; - UINT32 DataSizePerLine; - UINT32 ColorMapNum; - - ASSERT ((GopBlt != NULL) && (GopBltSize != NULL)); - - if ((ImageFormat != ImageFormatBmp) && (ImageFormat != ImageFormatUnknown)) { - return EFI_UNSUPPORTED; - } - - if (sizeof (BMP_IMAGE_HEADER) > BmpImageSize) { - return EFI_UNSUPPORTED; - } - - BmpHeader = (BMP_IMAGE_HEADER *) BmpImage; - - if (BmpHeader->CharB != 'B' || BmpHeader->CharM != 'M') { - return EFI_UNSUPPORTED; - } - - // - // Doesn't support compress. - // - if (BmpHeader->CompressionType != 0) { - return EFI_UNSUPPORTED; - } - - // - // Only support BITMAPINFOHEADER format. - // BITMAPFILEHEADER + BITMAPINFOHEADER = BMP_IMAGE_HEADER - // - if (BmpHeader->HeaderSize != sizeof (BMP_IMAGE_HEADER) - OFFSET_OF(BMP_IMAGE_HEADER, HeaderSize)) { - return EFI_UNSUPPORTED; - } - - // - // The data size in each line must be 4 byte alignment. - // - DataSizePerLine = ((BmpHeader->PixelWidth * BmpHeader->BitPerPixel + 31) >> 3) & (~0x3); - BltBufferSize = MultU64x32 (DataSizePerLine, BmpHeader->PixelHeight); - if (BltBufferSize > (UINT32) ~0) { - return EFI_INVALID_PARAMETER; - } - - if ((BmpHeader->Size != BmpImageSize) || - (BmpHeader->Size < BmpHeader->ImageOffset) || - (BmpHeader->Size - BmpHeader->ImageOffset != BmpHeader->PixelHeight * DataSizePerLine)) { - return EFI_INVALID_PARAMETER; - } - - // - // Calculate Color Map offset in the image. - // - Image = BmpImage; - BmpColorMap = (BMP_COLOR_MAP *) (Image + sizeof (BMP_IMAGE_HEADER)); - if (BmpHeader->ImageOffset < sizeof (BMP_IMAGE_HEADER)) { - return EFI_INVALID_PARAMETER; - } - - if (BmpHeader->ImageOffset > sizeof (BMP_IMAGE_HEADER)) { - switch (BmpHeader->BitPerPixel) { - case 1: - ColorMapNum = 2; - break; - case 4: - ColorMapNum = 16; - break; - case 8: - ColorMapNum = 256; - break; - default: - ColorMapNum = 0; - break; - } - // - // BMP file may has padding data between the bmp header section and the bmp data section. - // - if (BmpHeader->ImageOffset - sizeof (BMP_IMAGE_HEADER) < sizeof (BMP_COLOR_MAP) * ColorMapNum) { - return EFI_INVALID_PARAMETER; - } - } - - // - // Calculate graphics image data address in the image - // - Image = ((UINT8 *) BmpImage) + BmpHeader->ImageOffset; - ImageHeader = Image; - - // - // Calculate the BltBuffer needed size. - // - BltBufferSize = MultU64x32 ((UINT64) BmpHeader->PixelWidth, BmpHeader->PixelHeight); - // - // Ensure the BltBufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) doesn't overflow - // - if (BltBufferSize > DivU64x32 ((UINTN) ~0, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) { - return EFI_UNSUPPORTED; - } - BltBufferSize = MultU64x32 (BltBufferSize, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); - - *GopBltSize = (UINTN) BltBufferSize; - *GopBlt = AllocatePool (*GopBltSize); - if (*GopBlt == NULL) { - return EFI_OUT_OF_RESOURCES; - } - - *PixelWidth = BmpHeader->PixelWidth; - *PixelHeight = BmpHeader->PixelHeight; - - // - // Convert image from BMP to Blt buffer format - // - BltBuffer = *GopBlt; - for (Height = 0; Height < BmpHeader->PixelHeight; Height++) { - Blt = &BltBuffer[(BmpHeader->PixelHeight - Height - 1) * BmpHeader->PixelWidth]; - for (Width = 0; Width < BmpHeader->PixelWidth; Width++, Image++, Blt++) { - switch (BmpHeader->BitPerPixel) { - case 1: - // - // Convert 1-bit (2 colors) BMP to 24-bit color - // - for (Index = 0; Index < 8 && Width < BmpHeader->PixelWidth; Index++) { - Blt->Red = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Red; - Blt->Green = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Green; - Blt->Blue = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Blue; - Blt++; - Width++; - } - - Blt--; - Width--; - break; - - case 4: - // - // Convert 4-bit (16 colors) BMP Palette to 24-bit color - // - Index = (*Image) >> 4; - Blt->Red = BmpColorMap[Index].Red; - Blt->Green = BmpColorMap[Index].Green; - Blt->Blue = BmpColorMap[Index].Blue; - if (Width < (BmpHeader->PixelWidth - 1)) { - Blt++; - Width++; - Index = (*Image) & 0x0f; - Blt->Red = BmpColorMap[Index].Red; - Blt->Green = BmpColorMap[Index].Green; - Blt->Blue = BmpColorMap[Index].Blue; - } - break; - - case 8: - // - // Convert 8-bit (256 colors) BMP Palette to 24-bit color - // - Blt->Red = BmpColorMap[*Image].Red; - Blt->Green = BmpColorMap[*Image].Green; - Blt->Blue = BmpColorMap[*Image].Blue; - break; - - case 24: - // - // It is 24-bit BMP. - // - Blt->Blue = *Image++; - Blt->Green = *Image++; - Blt->Red = *Image; - break; - - default: - // - // Other bit format BMP is not supported. - // - return EFI_UNSUPPORTED; - break; - }; - - } - - ImageIndex = (UINTN) (Image - ImageHeader); - if ((ImageIndex % 4) != 0) { - // - // Bmp Image starts each row on a 32-bit boundary! - // - Image = Image + (4 - (ImageIndex % 4)); - } - } - - return EFI_SUCCESS; -} - -/** - Initialize BmpImageDecoderLib library. - - @param ImageHandle The image handle. - @param SystemTable The system table. - - @retval EFI_SUCCESS The BmpImageDecoderLib library is initialized correctly. - @return Other value if failed to initialize the BmpImageDecoderLib library. -**/ -EFI_STATUS -EFIAPI -BmpImageDecoderLibConstructor ( - IN EFI_HANDLE ImageHandle, - IN EFI_SYSTEM_TABLE *SystemTable -) -{ - RegisterImageDecoder (BmpImageDecoderLibConvertBmpToGopBlt); - return EFI_SUCCESS; -} - diff --git a/MdeModulePkg/Library/BmpImageDecoderLib/BmpImageDecoderLib.inf b/MdeModulePkg/Library/BmpImageDecoderLib/BmpImageDecoderLib.inf deleted file mode 100644 index 2d1c16084e39..000000000000 --- a/MdeModulePkg/Library/BmpImageDecoderLib/BmpImageDecoderLib.inf +++ /dev/null @@ -1,42 +0,0 @@ -## @file -# This library provides BMP image decoding capability. -# -# Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.
-# This program and the accompanying materials are licensed and made available under -# the terms and conditions of the BSD License that accompanies this distribution. -# The full text of the license may be found at -# http://opensource.org/licenses/bsd-license.php. -# -# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -# -## - -[Defines] - INF_VERSION = 0x00010005 - BASE_NAME = BmpImageDecoderLib - FILE_GUID = DF414223-F17C-4022-A1F4-4062612AB00D - MODULE_TYPE = DXE_DRIVER - VERSION_STRING = 1.0 - LIBRARY_CLASS = NULL|DXE_DRIVER UEFI_APPLICATION - CONSTRUCTOR = BmpImageDecoderLibConstructor - -# -# The following information is for reference only and not required by the build tools. -# -# VALID_ARCHITECTURES = IA32 X64 IPF EBC -# - -[Sources] - BmpImageDecoderLib.c - -[Packages] - MdePkg/MdePkg.dec - MdeModulePkg/MdeModulePkg.dec - -[LibraryClasses] - BaseLib - MemoryAllocationLib - BaseMemoryLib - DebugLib - ImageDecoderLib \ No newline at end of file diff --git a/MdeModulePkg/Library/BootLogoLib/BootLogoLib.c b/MdeModulePkg/Library/BootLogoLib/BootLogoLib.c deleted file mode 100644 index f824ae13c286..000000000000 --- a/MdeModulePkg/Library/BootLogoLib/BootLogoLib.c +++ /dev/null @@ -1,581 +0,0 @@ -/** @file - This library is only intended to be used by PlatformBootManagerLib - to show progress bar and LOGO. - -Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.
-This program and the accompanying materials are licensed and made available under -the terms and conditions of the BSD License that accompanies this distribution. -The full text of the license may be found at -http://opensource.org/licenses/bsd-license.php. - -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/** - Show LOGO on all consoles. - - @param[in] ImageFormat Format of the image file. - @param[in] LogoFile The file name of logo to display. - @param[in] Attribute The display attributes of the image returned. - @param[in] OffsetX The X offset of the image regarding the Attribute. - @param[in] OffsetY The Y offset of the image regarding the Attribute. - - @retval EFI_SUCCESS Logo was displayed. - @retval EFI_UNSUPPORTED Logo was not found or cannot be displayed. -**/ -EFI_STATUS -EFIAPI -BootLogoEnableLogo ( - IN IMAGE_FORMAT ImageFormat, - IN EFI_GUID *Logo, - IN EDKII_PLATFORM_LOGO_DISPLAY_ATTRIBUTE Attribute, - IN INTN OffsetX, - IN INTN OffsetY - ) -{ - EFI_STATUS Status; - EDKII_PLATFORM_LOGO_PROTOCOL *PlatformLogo; - UINT32 SizeOfX; - UINT32 SizeOfY; - INTN DestX; - INTN DestY; - UINT8 *ImageData; - UINTN ImageSize; - UINTN BltSize; - UINT32 Instance; - UINTN Height; - UINTN Width; - EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt; - EFI_UGA_DRAW_PROTOCOL *UgaDraw; - UINT32 ColorDepth; - UINT32 RefreshRate; - EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput; - EFI_BOOT_LOGO_PROTOCOL *BootLogo; - UINTN NumberOfLogos; - EFI_GRAPHICS_OUTPUT_BLT_PIXEL *LogoBlt; - UINTN LogoDestX; - UINTN LogoDestY; - UINTN LogoHeight; - UINTN LogoWidth; - UINTN NewDestX; - UINTN NewDestY; - UINTN NewHeight; - UINTN NewWidth; - UINTN BufferSize; - - UgaDraw = NULL; - // - // Try to open GOP first - // - Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **) &GraphicsOutput); - if (EFI_ERROR (Status) && FeaturePcdGet (PcdUgaConsumeSupport)) { - GraphicsOutput = NULL; - // - // Open GOP failed, try to open UGA - // - Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiUgaDrawProtocolGuid, (VOID **) &UgaDraw); - if (EFI_ERROR (Status)) { - UgaDraw = NULL; - } - } - if (EFI_ERROR (Status)) { - return EFI_UNSUPPORTED; - } - - Status = gBS->LocateProtocol (&gEdkiiPlatformLogoProtocolGuid, NULL, (VOID **) &PlatformLogo); - if (EFI_ERROR (Status)) { - PlatformLogo = NULL; - } - - if ((Logo == NULL) && (PlatformLogo == NULL)) { - return EFI_UNSUPPORTED; - } - - // - // Try to open Boot Logo Protocol. - // - Status = gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo); - if (EFI_ERROR (Status)) { - BootLogo = NULL; - } - - // - // Erase Cursor from screen - // - gST->ConOut->EnableCursor (gST->ConOut, FALSE); - - if (GraphicsOutput != NULL) { - SizeOfX = GraphicsOutput->Mode->Info->HorizontalResolution; - SizeOfY = GraphicsOutput->Mode->Info->VerticalResolution; - - } else { - ASSERT (UgaDraw != NULL); - Status = UgaDraw->GetMode (UgaDraw, &SizeOfX, &SizeOfY, &ColorDepth, &RefreshRate); - if (EFI_ERROR (Status)) { - return EFI_UNSUPPORTED; - } - } - - Blt = NULL; - NumberOfLogos = 0; - LogoDestX = 0; - LogoDestY = 0; - LogoHeight = 0; - LogoWidth = 0; - NewDestX = 0; - NewDestY = 0; - NewHeight = 0; - NewWidth = 0; - Instance = 0; - while (TRUE) { - ImageData = NULL; - ImageSize = 0; - - if (PlatformLogo != NULL) { - // - // Get image from OEMBadging protocol. - // - Status = PlatformLogo->GetImage ( - PlatformLogo, - &Instance, - &ImageFormat, - &ImageData, - &ImageSize, - &Attribute, - &OffsetX, - &OffsetY - ); - if (EFI_ERROR (Status)) { - break; - } - - } else { - // - // Get the specified image from FV. - // - Status = GetSectionFromAnyFv (Logo, EFI_SECTION_RAW, 0, (VOID **) &ImageData, &ImageSize); - if (EFI_ERROR (Status)) { - return EFI_UNSUPPORTED; - } - } - - if (Blt != NULL) { - FreePool (Blt); - } - - Status = DecodeImage (ImageFormat, ImageData, ImageSize, &Blt, &BltSize, &Width, &Height); - FreePool (ImageData); - if (EFI_ERROR (Status)) { - if (Logo != NULL) { - // - // Directly return failure for single LOGO - // - return Status; - } else { - continue; - } - } - - // - // Calculate the display position according to Attribute. - // - switch (Attribute) { - case EdkiiPlatformLogoDisplayAttributeLeftTop: - DestX = 0; - DestY = 0; - break; - case EdkiiPlatformLogoDisplayAttributeCenterTop: - DestX = (SizeOfX - Width) / 2; - DestY = 0; - break; - case EdkiiPlatformLogoDisplayAttributeRightTop: - DestX = SizeOfX - Width; - DestY = 0; - break; - - case EdkiiPlatformLogoDisplayAttributeCenterLeft: - DestX = 0; - DestY = (SizeOfY - Height) / 2; - break; - case EdkiiPlatformLogoDisplayAttributeCenter: - DestX = (SizeOfX - Width) / 2; - DestY = (SizeOfY - Height) / 2; - break; - case EdkiiPlatformLogoDisplayAttributeCenterRight: - DestX = SizeOfX - Width; - DestY = (SizeOfY - Height) / 2; - break; - - case EdkiiPlatformLogoDisplayAttributeLeftBottom: - DestX = 0; - DestY = SizeOfY - Height; - break; - case EdkiiPlatformLogoDisplayAttributeCenterBottom: - DestX = (SizeOfX - Width) / 2; - DestY = SizeOfY - Height; - break; - case EdkiiPlatformLogoDisplayAttributeRightBottom: - DestX = SizeOfX - Width; - DestY = SizeOfY - Height; - break; - - default: - ASSERT (FALSE); - break; - } - - DestX += OffsetX; - DestY += OffsetY; - - if ((DestX >= 0) && (DestY >= 0)) { - if (GraphicsOutput != NULL) { - Status = GraphicsOutput->Blt ( - GraphicsOutput, - Blt, - EfiBltBufferToVideo, - 0, - 0, - (UINTN) DestX, - (UINTN) DestY, - Width, - Height, - Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) - ); - } else { - ASSERT (UgaDraw != NULL); - Status = UgaDraw->Blt ( - UgaDraw, - (EFI_UGA_PIXEL *) Blt, - EfiUgaBltBufferToVideo, - 0, - 0, - (UINTN) DestX, - (UINTN) DestY, - Width, - Height, - Width * sizeof (EFI_UGA_PIXEL) - ); - } - - // - // Report displayed Logo information. - // - if (!EFI_ERROR (Status)) { - NumberOfLogos++; - - if (LogoWidth == 0) { - // - // The first Logo. - // - LogoDestX = (UINTN) DestX; - LogoDestY = (UINTN) DestY; - LogoWidth = Width; - LogoHeight = Height; - } else { - // - // Merge new logo with old one. - // - NewDestX = MIN ((UINTN) DestX, LogoDestX); - NewDestY = MIN ((UINTN) DestY, LogoDestY); - NewWidth = MAX ((UINTN) DestX + Width, LogoDestX + LogoWidth) - NewDestX; - NewHeight = MAX ((UINTN) DestY + Height, LogoDestY + LogoHeight) - NewDestY; - - LogoDestX = NewDestX; - LogoDestY = NewDestY; - LogoWidth = NewWidth; - LogoHeight = NewHeight; - } - } - } - - if (PlatformLogo == NULL) { - break; - } - } - - if (BootLogo == NULL || NumberOfLogos == 0) { - // - // No logo displayed. - // - if (Blt != NULL) { - FreePool (Blt); - } - - return Status; - } - - // - // Advertise displayed Logo information. - // - if (NumberOfLogos == 1) { - // - // Only one logo displayed, use its Blt buffer directly for BootLogo protocol. - // - LogoBlt = Blt; - Status = EFI_SUCCESS; - } else { - // - // More than one Logo displayed, get merged BltBuffer using VideoToBuffer operation. - // - if (Blt != NULL) { - FreePool (Blt); - } - - // - // Ensure the LogoHeight * LogoWidth * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) doesn't overflow - // - if (LogoHeight > MAX_UINTN / LogoWidth / sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)) { - return EFI_UNSUPPORTED; - } - BufferSize = LogoWidth * LogoHeight * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL); - - LogoBlt = AllocatePool (BufferSize); - if (LogoBlt == NULL) { - return EFI_OUT_OF_RESOURCES; - } - - if (GraphicsOutput != NULL) { - Status = GraphicsOutput->Blt ( - GraphicsOutput, - LogoBlt, - EfiBltVideoToBltBuffer, - LogoDestX, - LogoDestY, - 0, - 0, - LogoWidth, - LogoHeight, - LogoWidth * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) - ); - } else { - Status = UgaDraw->Blt ( - UgaDraw, - (EFI_UGA_PIXEL *) LogoBlt, - EfiUgaVideoToBltBuffer, - LogoDestX, - LogoDestY, - 0, - 0, - LogoWidth, - LogoHeight, - LogoWidth * sizeof (EFI_UGA_PIXEL) - ); - } - } - - if (!EFI_ERROR (Status)) { - BootLogo->SetBootLogo (BootLogo, LogoBlt, LogoDestX, LogoDestY, LogoWidth, LogoHeight); - } - FreePool (LogoBlt); - - return Status; -} - -/** - Use SystemTable Conout to turn on video based Simple Text Out consoles. The - Simple Text Out screens will now be synced up with all non video output devices - - @retval EFI_SUCCESS UGA devices are back in text mode and synced up. - -**/ -EFI_STATUS -EFIAPI -BootLogoDisableLogo ( - VOID - ) -{ - - // - // Enable Cursor on Screen - // - gST->ConOut->EnableCursor (gST->ConOut, TRUE); - return EFI_SUCCESS; -} - - -/** - - Update progress bar with title above it. It only works in Graphics mode. - - @param TitleForeground Foreground color for Title. - @param TitleBackground Background color for Title. - @param Title Title above progress bar. - @param ProgressColor Progress bar color. - @param Progress Progress (0-100) - @param PreviousValue The previous value of the progress. - - @retval EFI_STATUS Success update the progress bar - -**/ -EFI_STATUS -EFIAPI -BootLogoUpdateProgress ( - IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL TitleForeground, - IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL TitleBackground, - IN CHAR16 *Title, - IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL ProgressColor, - IN UINTN Progress, - IN UINTN PreviousValue - ) -{ - EFI_STATUS Status; - EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput; - EFI_UGA_DRAW_PROTOCOL *UgaDraw; - UINT32 SizeOfX; - UINT32 SizeOfY; - UINT32 ColorDepth; - UINT32 RefreshRate; - EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color; - UINTN BlockHeight; - UINTN BlockWidth; - UINTN BlockNum; - UINTN PosX; - UINTN PosY; - UINTN Index; - - if (Progress > 100) { - return EFI_INVALID_PARAMETER; - } - - UgaDraw = NULL; - Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **) &GraphicsOutput); - if (EFI_ERROR (Status) && FeaturePcdGet (PcdUgaConsumeSupport)) { - GraphicsOutput = NULL; - - Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiUgaDrawProtocolGuid, (VOID **) &UgaDraw); - if (EFI_ERROR (Status)) { - UgaDraw = NULL; - } - } - if (EFI_ERROR (Status)) { - return EFI_UNSUPPORTED; - } - - SizeOfX = 0; - SizeOfY = 0; - if (GraphicsOutput != NULL) { - SizeOfX = GraphicsOutput->Mode->Info->HorizontalResolution; - SizeOfY = GraphicsOutput->Mode->Info->VerticalResolution; - } else if (UgaDraw != NULL) { - Status = UgaDraw->GetMode ( - UgaDraw, - &SizeOfX, - &SizeOfY, - &ColorDepth, - &RefreshRate - ); - if (EFI_ERROR (Status)) { - return EFI_UNSUPPORTED; - } - } else { - return EFI_UNSUPPORTED; - } - - BlockWidth = SizeOfX / 100; - BlockHeight = SizeOfY / 50; - - BlockNum = Progress; - - PosX = 0; - PosY = SizeOfY * 48 / 50; - - if (BlockNum == 0) { - // - // Clear progress area - // - SetMem (&Color, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0x0); - - if (GraphicsOutput != NULL) { - Status = GraphicsOutput->Blt ( - GraphicsOutput, - &Color, - EfiBltVideoFill, - 0, - 0, - 0, - PosY - EFI_GLYPH_HEIGHT - 1, - SizeOfX, - SizeOfY - (PosY - EFI_GLYPH_HEIGHT - 1), - SizeOfX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) - ); - } else if (FeaturePcdGet (PcdUgaConsumeSupport)) { - Status = UgaDraw->Blt ( - UgaDraw, - (EFI_UGA_PIXEL *) &Color, - EfiUgaVideoFill, - 0, - 0, - 0, - PosY - EFI_GLYPH_HEIGHT - 1, - SizeOfX, - SizeOfY - (PosY - EFI_GLYPH_HEIGHT - 1), - SizeOfX * sizeof (EFI_UGA_PIXEL) - ); - } else { - return EFI_UNSUPPORTED; - } - } - // - // Show progress by drawing blocks - // - for (Index = PreviousValue; Index < BlockNum; Index++) { - PosX = Index * BlockWidth; - if (GraphicsOutput != NULL) { - Status = GraphicsOutput->Blt ( - GraphicsOutput, - &ProgressColor, - EfiBltVideoFill, - 0, - 0, - PosX, - PosY, - BlockWidth - 1, - BlockHeight, - (BlockWidth) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) - ); - } else if (FeaturePcdGet (PcdUgaConsumeSupport)) { - Status = UgaDraw->Blt ( - UgaDraw, - (EFI_UGA_PIXEL *) &ProgressColor, - EfiUgaVideoFill, - 0, - 0, - PosX, - PosY, - BlockWidth - 1, - BlockHeight, - (BlockWidth) * sizeof (EFI_UGA_PIXEL) - ); - } else { - return EFI_UNSUPPORTED; - } - } - - PrintXY ( - (SizeOfX - StrLen (Title) * EFI_GLYPH_WIDTH) / 2, - PosY - EFI_GLYPH_HEIGHT - 1, - &TitleForeground, - &TitleBackground, - Title - ); - - return EFI_SUCCESS; -} diff --git a/MdeModulePkg/Library/BootLogoLib/BootLogoLib.inf b/MdeModulePkg/Library/BootLogoLib/BootLogoLib.inf deleted file mode 100644 index 51e68edfea7a..000000000000 --- a/MdeModulePkg/Library/BootLogoLib/BootLogoLib.inf +++ /dev/null @@ -1,59 +0,0 @@ -## @file -# This library is only intended to be used by PlatformBootManagerLib -# to show progress bar and logo. -# -# Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.
-# This program and the accompanying materials are licensed and made available under -# the terms and conditions of the BSD License that accompanies this distribution. -# The full text of the license may be found at -# http://opensource.org/licenses/bsd-license.php. -# -# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -# -## - -[Defines] - INF_VERSION = 0x00010005 - BASE_NAME = BootLogoLib - FILE_GUID = F5AE5B5C-42E8-4A9B-829D-5B631CD5367A - MODULE_TYPE = DXE_DRIVER - VERSION_STRING = 1.0 - LIBRARY_CLASS = BootLogoLib|DXE_DRIVER UEFI_APPLICATION - -# -# The following information is for reference only and not required by the build tools. -# -# VALID_ARCHITECTURES = IA32 X64 IPF EBC -# - -[Sources] - BootLogoLib.c - -[Packages] - MdePkg/MdePkg.dec - MdeModulePkg/MdeModulePkg.dec - -[LibraryClasses] - BaseLib - UefiBootServicesTableLib - MemoryAllocationLib - UefiLib - BaseMemoryLib - DebugLib - PrintLib - PcdLib - DxeServicesLib - ImageDecoderLib - -[Guids] - -[Protocols] - gEfiGraphicsOutputProtocolGuid # PROTOCOL SOMETIMES_CONSUMES - gEfiUgaDrawProtocolGuid |PcdUgaConsumeSupport # PROTOCOL SOMETIMES_CONSUMES - gEfiBootLogoProtocolGuid # PROTOCOL SOMETIMES_CONSUMES - gEfiUserManagerProtocolGuid # PROTOCOL CONSUMES - gEdkiiPlatformLogoProtocolGuid # PROTOCOL CONSUMES - -[FeaturePcd] - gEfiMdePkgTokenSpaceGuid.PcdUgaConsumeSupport diff --git a/MdeModulePkg/Library/ImageDecoderLib/ImageDecoderLib.c b/MdeModulePkg/Library/ImageDecoderLib/ImageDecoderLib.c deleted file mode 100644 index 4a6219bbb138..000000000000 --- a/MdeModulePkg/Library/ImageDecoderLib/ImageDecoderLib.c +++ /dev/null @@ -1,121 +0,0 @@ -/** @file - This library provides image decoding service by managing the different - image decoding libraries. - -Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.
-This program and the accompanying materials are licensed and made available under -the terms and conditions of the BSD License that accompanies this distribution. -The full text of the license may be found at -http://opensource.org/licenses/bsd-license.php. - -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -#include -#include -#include -#include -#include -#include - -typedef struct { - UINT32 Signature; - DECODE_IMAGE Decoder; - LIST_ENTRY Link; -} IMAGE_DECODER_ENTRY; -#define IMAGE_DECODER_ENTRY_SIGNATURE SIGNATURE_32 ('i', 'm', 'g', 'd') -#define IMAGE_DECODER_ENTRY_FROM_LINK(Link) \ - CR (Link, IMAGE_DECODER_ENTRY, Link, IMAGE_DECODER_ENTRY_SIGNATURE) - -LIST_ENTRY mImageDecoderLibDecoders = INITIALIZE_LIST_HEAD_VARIABLE (mImageDecoderLibDecoders); - -/** - Convert a graphics image to a callee allocated GOP blt buffer. - - @param ImageFormat Format of the image file. - @param Image Pointer to image file. - @param ImageSize Number of bytes in Image. - @param GopBlt Buffer containing GOP version of Image. - @param GopBltSize Size of GopBlt in bytes. - @param PixelWidth Width of GopBlt/Image in pixels. - @param PixelHeight Height of GopBlt/Image in pixels. - - @retval EFI_SUCCESS GopBlt and GopBltSize are returned. - @retval EFI_INVALID_PARAMETER GopBlt or GopBltSize is NULL. - @retval EFI_INVALID_PARAMETER Image is NULL or ImageSize is 0. - @retval EFI_UNSUPPORTED Image is not supported. - @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate. - -**/ -EFI_STATUS -EFIAPI -DecodeImage ( - IN IMAGE_FORMAT ImageFormat, - IN UINT8 *Image, - IN UINTN ImageSize, - OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL **GopBlt, - OUT UINTN *GopBltSize, - OUT UINTN *PixelWidth, - OUT UINTN *PixelHeight - ) -{ - IMAGE_DECODER_ENTRY *Entry; - LIST_ENTRY *Link; - EFI_STATUS Status; - - if ((GopBlt == NULL) || (GopBltSize == NULL)) { - return EFI_INVALID_PARAMETER; - } - - if ((Image == NULL) || (ImageSize == 0)) { - return EFI_INVALID_PARAMETER; - } - - for ( Link = GetFirstNode (&mImageDecoderLibDecoders) - ; !IsNull (&mImageDecoderLibDecoders, Link) - ; Link = GetNextNode (&mImageDecoderLibDecoders, Link) - ) { - Entry = IMAGE_DECODER_ENTRY_FROM_LINK (Link); - Status = Entry->Decoder (ImageFormat, Image, ImageSize, GopBlt, GopBltSize, PixelWidth, PixelHeight); - if (!EFI_ERROR (Status)) { - break; - } - } - - if (IsNull (&mImageDecoderLibDecoders, Link)) { - return EFI_UNSUPPORTED; - } else { - return EFI_SUCCESS; - } -} - -/** - Register an image decoder. - - @param Decoder An image decoder. - - @retval EFI_SUCCESS The decoder was successfully registered. - @retval EFI_OUT_OF_RESOURCES No enough resource to register the decoder. - -**/ -EFI_STATUS -EFIAPI -RegisterImageDecoder ( - IN DECODE_IMAGE Decoder - ) -{ - IMAGE_DECODER_ENTRY *Entry; - - Entry = AllocatePool (sizeof (IMAGE_DECODER_ENTRY)); - if (Entry == NULL) { - return EFI_OUT_OF_RESOURCES; - } - - Entry->Signature = IMAGE_DECODER_ENTRY_SIGNATURE; - Entry->Decoder = Decoder; - InsertTailList (&mImageDecoderLibDecoders, &Entry->Link); - - return EFI_SUCCESS; -} \ No newline at end of file diff --git a/MdeModulePkg/Library/ImageDecoderLib/ImageDecoderLib.inf b/MdeModulePkg/Library/ImageDecoderLib/ImageDecoderLib.inf deleted file mode 100644 index 5d2ee7b429b5..000000000000 --- a/MdeModulePkg/Library/ImageDecoderLib/ImageDecoderLib.inf +++ /dev/null @@ -1,42 +0,0 @@ -## @file -# This library provides image decoding service by managing the different -# image decoding libraries. -# -# Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.
-# This program and the accompanying materials are licensed and made available under -# the terms and conditions of the BSD License that accompanies this distribution. -# The full text of the license may be found at -# http://opensource.org/licenses/bsd-license.php. -# -# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -# -## - -[Defines] - INF_VERSION = 0x00010005 - BASE_NAME = ImageDecoderLib - FILE_GUID = 5ACDA5F7-AE20-4A17-90C1-7D087F730202 - MODULE_TYPE = DXE_DRIVER - VERSION_STRING = 1.0 - LIBRARY_CLASS = ImageDecoderLib|DXE_DRIVER UEFI_APPLICATION - -# -# The following information is for reference only and not required by the build tools. -# -# VALID_ARCHITECTURES = IA32 X64 IPF EBC -# - -[Sources] - ImageDecoderLib.c - -[Packages] - MdePkg/MdePkg.dec - MdeModulePkg/MdeModulePkg.dec - -[LibraryClasses] - BaseLib - MemoryAllocationLib - UefiLib - BaseMemoryLib - DebugLib \ No newline at end of file diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec index f00d6f030ad5..3dfcd6a77f64 100644 --- a/MdeModulePkg/MdeModulePkg.dec +++ b/MdeModulePkg/MdeModulePkg.dec @@ -131,14 +131,6 @@ # PlatformVarCleanupLib|Include/Library/PlatformVarCleanupLib.h - ## @libraryclass Provides image decoding service. - # - ImageDecoderLib|Include/Library/ImageDecoderLib.h - - ## @libraryclass Provides interfaces about logo display. - # - BootLogoLib|Include/Library/BootLogoLib.h - [Guids] ## MdeModule package token space guid # Include/Guid/MdeModulePkgTokenSpace.h @@ -457,9 +449,6 @@ ## Include/Protocol/SmmReadyToBoot.h gEdkiiSmmReadyToBootProtocolGuid = { 0x6e057ecf, 0xfa99, 0x4f39, { 0x95, 0xbc, 0x59, 0xf9, 0x92, 0x1d, 0x17, 0xe4 } } - ## Include/Protocol/PlatformLogo.h - gEdkiiPlatformLogoProtocolGuid = { 0x9b517978, 0xeba1, 0x44e7, { 0xba, 0x65, 0x7c, 0x2c, 0xd0, 0x8b, 0xf8, 0xe9 } } - # # [Error.gEfiMdeModulePkgTokenSpaceGuid] # 0x80000001 | Invalid value provided. diff --git a/MdeModulePkg/MdeModulePkg.dsc b/MdeModulePkg/MdeModulePkg.dsc index b80be9d67619..c43093260453 100644 --- a/MdeModulePkg/MdeModulePkg.dsc +++ b/MdeModulePkg/MdeModulePkg.dsc @@ -47,7 +47,6 @@ PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf SortLib|MdeModulePkg/Library/BaseSortLib/BaseSortLib.inf - ImageDecoderLib|MdeModulePkg/Library/ImageDecoderLib/ImageDecoderLib.inf # # UEFI & PI # @@ -277,9 +276,6 @@ MdeModulePkg/Library/PeiDxeDebugLibReportStatusCode/PeiDxeDebugLibReportStatusCode.inf MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf MdeModulePkg/Library/PlatformBootManagerLibNull/PlatformBootManagerLibNull.inf - MdeModulePkg/Library/ImageDecoderLib/ImageDecoderLib.inf - MdeModulePkg/Library/BootLogoLib/BootLogoLib.inf - MdeModulePkg/Library/BmpImageDecoderLib/BmpImageDecoderLib.inf MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.inf MdeModulePkg/Library/VarCheckLib/VarCheckLib.inf diff --git a/Nt32Pkg/Library/PlatformBootManagerLib/MemoryTest.c b/Nt32Pkg/Library/PlatformBootManagerLib/MemoryTest.c index 93ecc7d88cf3..9f57466e8c18 100644 --- a/Nt32Pkg/Library/PlatformBootManagerLib/MemoryTest.c +++ b/Nt32Pkg/Library/PlatformBootManagerLib/MemoryTest.c @@ -23,6 +23,179 @@ EFI_GUID mPlatformBootManagerStringPackGuid = { // // BDS Platform Functions // +/** + + Show progress bar with title above it. It only works in Graphics mode. + + + @param TitleForeground Foreground color for Title. + @param TitleBackground Background color for Title. + @param Title Title above progress bar. + @param ProgressColor Progress bar color. + @param Progress Progress (0-100) + @param PreviousValue The previous value of the progress. + + @retval EFI_STATUS Success update the progress bar + +**/ +EFI_STATUS +PlatformBootManagerShowProgress ( + IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL TitleForeground, + IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL TitleBackground, + IN CHAR16 *Title, + IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL ProgressColor, + IN UINTN Progress, + IN UINTN PreviousValue + ) +{ + EFI_STATUS Status; + EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput; + EFI_UGA_DRAW_PROTOCOL *UgaDraw; + UINT32 SizeOfX; + UINT32 SizeOfY; + UINT32 ColorDepth; + UINT32 RefreshRate; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color; + UINTN BlockHeight; + UINTN BlockWidth; + UINTN BlockNum; + UINTN PosX; + UINTN PosY; + UINTN Index; + + if (Progress > 100) { + return EFI_INVALID_PARAMETER; + } + + UgaDraw = NULL; + Status = gBS->HandleProtocol ( + gST->ConsoleOutHandle, + &gEfiGraphicsOutputProtocolGuid, + (VOID **) &GraphicsOutput + ); + if (EFI_ERROR (Status) && FeaturePcdGet (PcdUgaConsumeSupport)) { + GraphicsOutput = NULL; + + Status = gBS->HandleProtocol ( + gST->ConsoleOutHandle, + &gEfiUgaDrawProtocolGuid, + (VOID **) &UgaDraw + ); + } + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + SizeOfX = 0; + SizeOfY = 0; + if (GraphicsOutput != NULL) { + SizeOfX = GraphicsOutput->Mode->Info->HorizontalResolution; + SizeOfY = GraphicsOutput->Mode->Info->VerticalResolution; + } else if (UgaDraw != NULL) { + Status = UgaDraw->GetMode ( + UgaDraw, + &SizeOfX, + &SizeOfY, + &ColorDepth, + &RefreshRate + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + } else { + return EFI_UNSUPPORTED; + } + + BlockWidth = SizeOfX / 100; + BlockHeight = SizeOfY / 50; + + BlockNum = Progress; + + PosX = 0; + PosY = SizeOfY * 48 / 50; + + if (BlockNum == 0) { + // + // Clear progress area + // + SetMem (&Color, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0x0); + + if (GraphicsOutput != NULL) { + Status = GraphicsOutput->Blt ( + GraphicsOutput, + &Color, + EfiBltVideoFill, + 0, + 0, + 0, + PosY - EFI_GLYPH_HEIGHT - 1, + SizeOfX, + SizeOfY - (PosY - EFI_GLYPH_HEIGHT - 1), + SizeOfX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) + ); + } else if (FeaturePcdGet (PcdUgaConsumeSupport)) { + Status = UgaDraw->Blt ( + UgaDraw, + (EFI_UGA_PIXEL *) &Color, + EfiUgaVideoFill, + 0, + 0, + 0, + PosY - EFI_GLYPH_HEIGHT - 1, + SizeOfX, + SizeOfY - (PosY - EFI_GLYPH_HEIGHT - 1), + SizeOfX * sizeof (EFI_UGA_PIXEL) + ); + } else { + return EFI_UNSUPPORTED; + } + } + // + // Show progress by drawing blocks + // + for (Index = PreviousValue; Index < BlockNum; Index++) { + PosX = Index * BlockWidth; + if (GraphicsOutput != NULL) { + Status = GraphicsOutput->Blt ( + GraphicsOutput, + &ProgressColor, + EfiBltVideoFill, + 0, + 0, + PosX, + PosY, + BlockWidth - 1, + BlockHeight, + (BlockWidth) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) + ); + } else if (FeaturePcdGet (PcdUgaConsumeSupport)) { + Status = UgaDraw->Blt ( + UgaDraw, + (EFI_UGA_PIXEL *) &ProgressColor, + EfiUgaVideoFill, + 0, + 0, + PosX, + PosY, + BlockWidth - 1, + BlockHeight, + (BlockWidth) * sizeof (EFI_UGA_PIXEL) + ); + } else { + return EFI_UNSUPPORTED; + } + } + + PrintXY ( + (SizeOfX - StrLen (Title) * EFI_GLYPH_WIDTH) / 2, + PosY - EFI_GLYPH_HEIGHT - 1, + &TitleForeground, + &TitleBackground, + Title + ); + + return EFI_SUCCESS; +} /** Perform the memory test base on the memory test intensive level, @@ -173,7 +346,7 @@ PlatformBootManagerMemoryTest ( TmpStr = HiiGetString (gStringPackHandle, STRING_TOKEN (STR_PERFORM_MEM_TEST), NULL); if (TmpStr != NULL) { - BootLogoUpdateProgress ( + PlatformBootManagerShowProgress ( Foreground, Background, TmpStr, @@ -197,7 +370,7 @@ PlatformBootManagerMemoryTest ( if (!FeaturePcdGet(PcdBootlogoOnlyEnable)) { TmpStr = HiiGetString (gStringPackHandle, STRING_TOKEN (STR_PERFORM_MEM_TEST), NULL); if (TmpStr != NULL) { - BootLogoUpdateProgress ( + PlatformBootManagerShowProgress ( Foreground, Background, TmpStr, @@ -241,7 +414,7 @@ PlatformBootManagerMemoryTest ( } PrintXY (10, 10, NULL, NULL, StrTotalMemory); - BootLogoUpdateProgress ( + PlatformBootManagerShowProgress ( Foreground, Background, StrTotalMemory, @@ -257,3 +430,657 @@ PlatformBootManagerMemoryTest ( FreePool (Pos); return ReturnStatus; } + +/** + Convert a *.BMP graphics image to a GOP blt buffer. If a NULL Blt buffer + is passed in a GopBlt buffer will be allocated by this routine. If a GopBlt + buffer is passed in it will be used if it is big enough. + + @param BmpImage Pointer to BMP file + @param BmpImageSize Number of bytes in BmpImage + @param GopBlt Buffer containing GOP version of BmpImage. + @param GopBltSize Size of GopBlt in bytes. + @param PixelHeight Height of GopBlt/BmpImage in pixels + @param PixelWidth Width of GopBlt/BmpImage in pixels + + @retval EFI_SUCCESS GopBlt and GopBltSize are returned. + @retval EFI_UNSUPPORTED BmpImage is not a valid *.BMP image + @retval EFI_BUFFER_TOO_SMALL The passed in GopBlt buffer is not big enough. + GopBltSize will contain the required size. + @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate. + +**/ +EFI_STATUS +PlatformBootManagerConvertBmpToGopBlt ( + IN VOID *BmpImage, + IN UINTN BmpImageSize, + IN OUT VOID **GopBlt, + IN OUT UINTN *GopBltSize, + OUT UINTN *PixelHeight, + OUT UINTN *PixelWidth + ) +{ + UINT8 *Image; + UINT8 *ImageHeader; + BMP_IMAGE_HEADER *BmpHeader; + BMP_COLOR_MAP *BmpColorMap; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt; + UINT64 BltBufferSize; + UINTN Index; + UINTN Height; + UINTN Width; + UINTN ImageIndex; + UINT32 DataSizePerLine; + BOOLEAN IsAllocated; + UINT32 ColorMapNum; + + if (sizeof (BMP_IMAGE_HEADER) > BmpImageSize) { + return EFI_INVALID_PARAMETER; + } + + BmpHeader = (BMP_IMAGE_HEADER *) BmpImage; + + if (BmpHeader->CharB != 'B' || BmpHeader->CharM != 'M') { + return EFI_UNSUPPORTED; + } + + // + // Doesn't support compress. + // + if (BmpHeader->CompressionType != 0) { + return EFI_UNSUPPORTED; + } + + // + // Only support BITMAPINFOHEADER format. + // BITMAPFILEHEADER + BITMAPINFOHEADER = BMP_IMAGE_HEADER + // + if (BmpHeader->HeaderSize != sizeof (BMP_IMAGE_HEADER) - OFFSET_OF(BMP_IMAGE_HEADER, HeaderSize)) { + return EFI_UNSUPPORTED; + } + + // + // The data size in each line must be 4 byte alignment. + // + DataSizePerLine = ((BmpHeader->PixelWidth * BmpHeader->BitPerPixel + 31) >> 3) & (~0x3); + BltBufferSize = MultU64x32 (DataSizePerLine, BmpHeader->PixelHeight); + if (BltBufferSize > (UINT32) ~0) { + return EFI_INVALID_PARAMETER; + } + + if ((BmpHeader->Size != BmpImageSize) || + (BmpHeader->Size < BmpHeader->ImageOffset) || + (BmpHeader->Size - BmpHeader->ImageOffset != BmpHeader->PixelHeight * DataSizePerLine)) { + return EFI_INVALID_PARAMETER; + } + + // + // Calculate Color Map offset in the image. + // + Image = BmpImage; + BmpColorMap = (BMP_COLOR_MAP *) (Image + sizeof (BMP_IMAGE_HEADER)); + if (BmpHeader->ImageOffset < sizeof (BMP_IMAGE_HEADER)) { + return EFI_INVALID_PARAMETER; + } + + if (BmpHeader->ImageOffset > sizeof (BMP_IMAGE_HEADER)) { + switch (BmpHeader->BitPerPixel) { + case 1: + ColorMapNum = 2; + break; + case 4: + ColorMapNum = 16; + break; + case 8: + ColorMapNum = 256; + break; + default: + ColorMapNum = 0; + break; + } + // + // BMP file may has padding data between the bmp header section and the bmp data section. + // + if (BmpHeader->ImageOffset - sizeof (BMP_IMAGE_HEADER) < sizeof (BMP_COLOR_MAP) * ColorMapNum) { + return EFI_INVALID_PARAMETER; + } + } + + // + // Calculate graphics image data address in the image + // + Image = ((UINT8 *) BmpImage) + BmpHeader->ImageOffset; + ImageHeader = Image; + + // + // Calculate the BltBuffer needed size. + // + BltBufferSize = MultU64x32 ((UINT64) BmpHeader->PixelWidth, BmpHeader->PixelHeight); + // + // Ensure the BltBufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) doesn't overflow + // + if (BltBufferSize > DivU64x32 ((UINTN) ~0, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) { + return EFI_UNSUPPORTED; + } + BltBufferSize = MultU64x32 (BltBufferSize, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); + + IsAllocated = FALSE; + if (*GopBlt == NULL) { + // + // GopBlt is not allocated by caller. + // + *GopBltSize = (UINTN) BltBufferSize; + *GopBlt = AllocatePool (*GopBltSize); + IsAllocated = TRUE; + if (*GopBlt == NULL) { + return EFI_OUT_OF_RESOURCES; + } + } else { + // + // GopBlt has been allocated by caller. + // + if (*GopBltSize < (UINTN) BltBufferSize) { + *GopBltSize = (UINTN) BltBufferSize; + return EFI_BUFFER_TOO_SMALL; + } + } + + *PixelWidth = BmpHeader->PixelWidth; + *PixelHeight = BmpHeader->PixelHeight; + + // + // Convert image from BMP to Blt buffer format + // + BltBuffer = *GopBlt; + for (Height = 0; Height < BmpHeader->PixelHeight; Height++) { + Blt = &BltBuffer[(BmpHeader->PixelHeight - Height - 1) * BmpHeader->PixelWidth]; + for (Width = 0; Width < BmpHeader->PixelWidth; Width++, Image++, Blt++) { + switch (BmpHeader->BitPerPixel) { + case 1: + // + // Convert 1-bit (2 colors) BMP to 24-bit color + // + for (Index = 0; Index < 8 && Width < BmpHeader->PixelWidth; Index++) { + Blt->Red = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Red; + Blt->Green = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Green; + Blt->Blue = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Blue; + Blt++; + Width++; + } + + Blt--; + Width--; + break; + + case 4: + // + // Convert 4-bit (16 colors) BMP Palette to 24-bit color + // + Index = (*Image) >> 4; + Blt->Red = BmpColorMap[Index].Red; + Blt->Green = BmpColorMap[Index].Green; + Blt->Blue = BmpColorMap[Index].Blue; + if (Width < (BmpHeader->PixelWidth - 1)) { + Blt++; + Width++; + Index = (*Image) & 0x0f; + Blt->Red = BmpColorMap[Index].Red; + Blt->Green = BmpColorMap[Index].Green; + Blt->Blue = BmpColorMap[Index].Blue; + } + break; + + case 8: + // + // Convert 8-bit (256 colors) BMP Palette to 24-bit color + // + Blt->Red = BmpColorMap[*Image].Red; + Blt->Green = BmpColorMap[*Image].Green; + Blt->Blue = BmpColorMap[*Image].Blue; + break; + + case 24: + // + // It is 24-bit BMP. + // + Blt->Blue = *Image++; + Blt->Green = *Image++; + Blt->Red = *Image; + break; + + default: + // + // Other bit format BMP is not supported. + // + if (IsAllocated) { + FreePool (*GopBlt); + *GopBlt = NULL; + } + return EFI_UNSUPPORTED; + break; + }; + + } + + ImageIndex = (UINTN) (Image - ImageHeader); + if ((ImageIndex % 4) != 0) { + // + // Bmp Image starts each row on a 32-bit boundary! + // + Image = Image + (4 - (ImageIndex % 4)); + } + } + + return EFI_SUCCESS; +} + +/** + Use SystemTable Conout to stop video based Simple Text Out consoles from going + to the video device. Put up LogoFile on every video device that is a console. + + @param[in] LogoFile File name of logo to display on the center of the screen. + + @retval EFI_SUCCESS ConsoleControl has been flipped to graphics and logo displayed. + @retval EFI_UNSUPPORTED Logo not found + +**/ +EFI_STATUS +PlatformBootManagerEnableQuietBoot ( + IN EFI_GUID *LogoFile + ) +{ + EFI_STATUS Status; + EFI_OEM_BADGING_PROTOCOL *Badging; + UINT32 SizeOfX; + UINT32 SizeOfY; + INTN DestX; + INTN DestY; + UINT8 *ImageData; + UINTN ImageSize; + UINTN BltSize; + UINT32 Instance; + EFI_BADGING_FORMAT Format; + EFI_BADGING_DISPLAY_ATTRIBUTE Attribute; + UINTN CoordinateX; + UINTN CoordinateY; + UINTN Height; + UINTN Width; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt; + EFI_UGA_DRAW_PROTOCOL *UgaDraw; + UINT32 ColorDepth; + UINT32 RefreshRate; + EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput; + EFI_BOOT_LOGO_PROTOCOL *BootLogo; + UINTN NumberOfLogos; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *LogoBlt; + UINTN LogoDestX; + UINTN LogoDestY; + UINTN LogoHeight; + UINTN LogoWidth; + UINTN NewDestX; + UINTN NewDestY; + UINTN NewHeight; + UINTN NewWidth; + UINT64 BufferSize; + + UgaDraw = NULL; + // + // Try to open GOP first + // + Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **) &GraphicsOutput); + if (EFI_ERROR (Status) && FeaturePcdGet (PcdUgaConsumeSupport)) { + GraphicsOutput = NULL; + // + // Open GOP failed, try to open UGA + // + Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiUgaDrawProtocolGuid, (VOID **) &UgaDraw); + } + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + // + // Try to open Boot Logo Protocol. + // + BootLogo = NULL; + gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo); + + // + // Erase Cursor from screen + // + gST->ConOut->EnableCursor (gST->ConOut, FALSE); + + Badging = NULL; + Status = gBS->LocateProtocol (&gEfiOEMBadgingProtocolGuid, NULL, (VOID **) &Badging); + + if (GraphicsOutput != NULL) { + SizeOfX = GraphicsOutput->Mode->Info->HorizontalResolution; + SizeOfY = GraphicsOutput->Mode->Info->VerticalResolution; + + } else if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) { + Status = UgaDraw->GetMode (UgaDraw, &SizeOfX, &SizeOfY, &ColorDepth, &RefreshRate); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + } else { + return EFI_UNSUPPORTED; + } + + Blt = NULL; + NumberOfLogos = 0; + LogoDestX = 0; + LogoDestY = 0; + LogoHeight = 0; + LogoWidth = 0; + NewDestX = 0; + NewDestY = 0; + NewHeight = 0; + NewWidth = 0; + Instance = 0; + while (1) { + ImageData = NULL; + ImageSize = 0; + + if (Badging != NULL) { + // + // Get image from OEMBadging protocol. + // + Status = Badging->GetImage ( + Badging, + &Instance, + &Format, + &ImageData, + &ImageSize, + &Attribute, + &CoordinateX, + &CoordinateY + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Currently only support BMP format. + // + if (Format != EfiBadgingFormatBMP) { + if (ImageData != NULL) { + FreePool (ImageData); + } + continue; + } + } else { + // + // Get the specified image from FV. + // + Status = GetSectionFromAnyFv (LogoFile, EFI_SECTION_RAW, 0, (VOID **) &ImageData, &ImageSize); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + CoordinateX = 0; + CoordinateY = 0; + if (!FeaturePcdGet(PcdBootlogoOnlyEnable)) { + Attribute = EfiBadgingDisplayAttributeCenter; + } else { + Attribute = EfiBadgingDisplayAttributeCustomized; + } + } + + if (Blt != NULL) { + FreePool (Blt); + } + Blt = NULL; + Status = PlatformBootManagerConvertBmpToGopBlt ( + ImageData, + ImageSize, + (VOID **) &Blt, + &BltSize, + &Height, + &Width + ); + if (EFI_ERROR (Status)) { + FreePool (ImageData); + + if (Badging == NULL) { + return Status; + } else { + continue; + } + } + + // + // Calculate the display position according to Attribute. + // + switch (Attribute) { + case EfiBadgingDisplayAttributeLeftTop: + DestX = CoordinateX; + DestY = CoordinateY; + break; + + case EfiBadgingDisplayAttributeCenterTop: + DestX = (SizeOfX - Width) / 2; + DestY = CoordinateY; + break; + + case EfiBadgingDisplayAttributeRightTop: + DestX = (SizeOfX - Width - CoordinateX); + DestY = CoordinateY;; + break; + + case EfiBadgingDisplayAttributeCenterRight: + DestX = (SizeOfX - Width - CoordinateX); + DestY = (SizeOfY - Height) / 2; + break; + + case EfiBadgingDisplayAttributeRightBottom: + DestX = (SizeOfX - Width - CoordinateX); + DestY = (SizeOfY - Height - CoordinateY); + break; + + case EfiBadgingDisplayAttributeCenterBottom: + DestX = (SizeOfX - Width) / 2; + DestY = (SizeOfY - Height - CoordinateY); + break; + + case EfiBadgingDisplayAttributeLeftBottom: + DestX = CoordinateX; + DestY = (SizeOfY - Height - CoordinateY); + break; + + case EfiBadgingDisplayAttributeCenterLeft: + DestX = CoordinateX; + DestY = (SizeOfY - Height) / 2; + break; + + case EfiBadgingDisplayAttributeCenter: + DestX = (SizeOfX - Width) / 2; + DestY = (SizeOfY - Height) / 2; + break; + + case EfiBadgingDisplayAttributeCustomized: + DestX = (SizeOfX - Width) / 2; + DestY = ((SizeOfY * 382) / 1000) - Height / 2; + break; + + default: + DestX = CoordinateX; + DestY = CoordinateY; + break; + } + + if ((DestX >= 0) && (DestY >= 0)) { + if (GraphicsOutput != NULL) { + Status = GraphicsOutput->Blt ( + GraphicsOutput, + Blt, + EfiBltBufferToVideo, + 0, + 0, + (UINTN) DestX, + (UINTN) DestY, + Width, + Height, + Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) + ); + } else if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) { + Status = UgaDraw->Blt ( + UgaDraw, + (EFI_UGA_PIXEL *) Blt, + EfiUgaBltBufferToVideo, + 0, + 0, + (UINTN) DestX, + (UINTN) DestY, + Width, + Height, + Width * sizeof (EFI_UGA_PIXEL) + ); + } else { + Status = EFI_UNSUPPORTED; + } + + // + // Report displayed Logo information. + // + if (!EFI_ERROR (Status)) { + NumberOfLogos++; + + if (LogoWidth == 0) { + // + // The first Logo. + // + LogoDestX = (UINTN) DestX; + LogoDestY = (UINTN) DestY; + LogoWidth = Width; + LogoHeight = Height; + } else { + // + // Merge new logo with old one. + // + NewDestX = MIN ((UINTN) DestX, LogoDestX); + NewDestY = MIN ((UINTN) DestY, LogoDestY); + NewWidth = MAX ((UINTN) DestX + Width, LogoDestX + LogoWidth) - NewDestX; + NewHeight = MAX ((UINTN) DestY + Height, LogoDestY + LogoHeight) - NewDestY; + + LogoDestX = NewDestX; + LogoDestY = NewDestY; + LogoWidth = NewWidth; + LogoHeight = NewHeight; + } + } + } + + FreePool (ImageData); + + if (Badging == NULL) { + break; + } + } + +Done: + if (BootLogo == NULL || NumberOfLogos == 0) { + // + // No logo displayed. + // + if (Blt != NULL) { + FreePool (Blt); + } + + return Status; + } + + // + // Advertise displayed Logo information. + // + if (NumberOfLogos == 1) { + // + // Only one logo displayed, use its Blt buffer directly for BootLogo protocol. + // + LogoBlt = Blt; + Status = EFI_SUCCESS; + } else { + // + // More than one Logo displayed, get merged BltBuffer using VideoToBuffer operation. + // + if (Blt != NULL) { + FreePool (Blt); + } + + // + // Ensure the LogoHeight * LogoWidth doesn't overflow + // + if (LogoHeight > DivU64x64Remainder ((UINTN) ~0, LogoWidth, NULL)) { + return EFI_UNSUPPORTED; + } + BufferSize = MultU64x64 (LogoWidth, LogoHeight); + + // + // Ensure the BufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) doesn't overflow + // + if (BufferSize > DivU64x32 ((UINTN) ~0, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) { + return EFI_UNSUPPORTED; + } + + LogoBlt = AllocateZeroPool ((UINTN)BufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); + if (LogoBlt == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + if (GraphicsOutput != NULL) { + Status = GraphicsOutput->Blt ( + GraphicsOutput, + LogoBlt, + EfiBltVideoToBltBuffer, + LogoDestX, + LogoDestY, + 0, + 0, + LogoWidth, + LogoHeight, + LogoWidth * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) + ); + } else if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) { + Status = UgaDraw->Blt ( + UgaDraw, + (EFI_UGA_PIXEL *) LogoBlt, + EfiUgaVideoToBltBuffer, + LogoDestX, + LogoDestY, + 0, + 0, + LogoWidth, + LogoHeight, + LogoWidth * sizeof (EFI_UGA_PIXEL) + ); + } else { + Status = EFI_UNSUPPORTED; + } + } + + if (!EFI_ERROR (Status)) { + BootLogo->SetBootLogo (BootLogo, LogoBlt, LogoDestX, LogoDestY, LogoWidth, LogoHeight); + } + FreePool (LogoBlt); + + return Status; +} + +/** + Use SystemTable Conout to turn on video based Simple Text Out consoles. The + Simple Text Out screens will now be synced up with all non video output devices + + @retval EFI_SUCCESS UGA devices are back in text mode and synced up. + +**/ +EFI_STATUS +PlatformBootManagerDisableQuietBoot ( + VOID + ) +{ + // + // Enable Cursor on Screen + // + gST->ConOut->EnableCursor (gST->ConOut, TRUE); + return EFI_SUCCESS; +} diff --git a/Nt32Pkg/Library/PlatformBootManagerLib/PlatformBootManager.c b/Nt32Pkg/Library/PlatformBootManagerLib/PlatformBootManager.c index 82f7647c7039..e944105b3925 100644 --- a/Nt32Pkg/Library/PlatformBootManagerLib/PlatformBootManager.c +++ b/Nt32Pkg/Library/PlatformBootManagerLib/PlatformBootManager.c @@ -38,14 +38,14 @@ PlatformBootManagerDiagnostics ( // from the graphic lib // if (QuietBoot) { - BootLogoEnableLogo (ImageFormatBmp, PcdGetPtr(PcdLogoFile), EdkiiPlatformLogoDisplayAttributeCenter, 0, 0); + PlatformBootManagerEnableQuietBoot (PcdGetPtr(PcdLogoFile)); // // Perform system diagnostic // Status = PlatformBootManagerMemoryTest (MemoryTestLevel); if (EFI_ERROR (Status)) { - BootLogoDisableLogo (); + PlatformBootManagerDisableQuietBoot (); } return; @@ -271,7 +271,7 @@ PlatformBootManagerWaitCallback ( Black.Blue = Black.Green = Black.Red = Black.Reserved = 0; White.Blue = White.Green = White.Red = White.Reserved = 0xFF; - BootLogoUpdateProgress ( + PlatformBootManagerShowProgress ( White, Black, L"Start boot option", diff --git a/Nt32Pkg/Library/PlatformBootManagerLib/PlatformBootManager.h b/Nt32Pkg/Library/PlatformBootManagerLib/PlatformBootManager.h index e2c6681702fd..7e0fae847fb6 100644 --- a/Nt32Pkg/Library/PlatformBootManagerLib/PlatformBootManager.h +++ b/Nt32Pkg/Library/PlatformBootManagerLib/PlatformBootManager.h @@ -15,11 +15,16 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #define _PLATFORM_BOOT_MANAGER_H #include +#include #include #include #include #include #include +#include +#include +#include +#include #include #include @@ -35,7 +40,6 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include #include -#include typedef struct { diff --git a/Nt32Pkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf b/Nt32Pkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf index 71e8738a6a9d..9b1eeaba02ed 100644 --- a/Nt32Pkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf +++ b/Nt32Pkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf @@ -52,7 +52,6 @@ DevicePathLib HiiLib PrintLib - BootLogoLib [Guids] gEfiWinNtSystemConfigGuid @@ -61,6 +60,7 @@ gEfiGenericMemTestProtocolGuid ## CONSUMES gEfiGraphicsOutputProtocolGuid ## CONSUMES gEfiUgaDrawProtocolGuid ## CONSUMES + gEfiOEMBadgingProtocolGuid ## CONSUMES gEfiBootLogoProtocolGuid ## CONSUMES [Pcd] diff --git a/Nt32Pkg/Nt32Pkg.dsc b/Nt32Pkg/Nt32Pkg.dsc index a9df9b11dc65..21e1f69353bf 100644 --- a/Nt32Pkg/Nt32Pkg.dsc +++ b/Nt32Pkg/Nt32Pkg.dsc @@ -117,8 +117,6 @@ TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf SerialPortLib|MdePkg/Library/BaseSerialPortLibNull/BaseSerialPortLibNull.inf CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf - ImageDecoderLib|MdeModulePkg/Library/ImageDecoderLib/ImageDecoderLib.inf - BootLogoLib|MdeModulePkg/Library/BootLogoLib/BootLogoLib.inf # # Platform # @@ -442,10 +440,7 @@ NetworkPkg/HttpDxe/HttpDxe.inf NetworkPkg/HttpUtilitiesDxe/HttpUtilitiesDxe.inf - MdeModulePkg/Universal/BdsDxe/BdsDxe.inf { - - NULL|MdeModulePkg/Library/BmpImageDecoderLib/BmpImageDecoderLib.inf - } + MdeModulePkg/Universal/BdsDxe/BdsDxe.inf MdeModulePkg/Application/UiApp/UiApp.inf MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthManagerDxe.inf MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf From b787ece3293b19f7f340ddfe2070d020beb0a6fc Mon Sep 17 00:00:00 2001 From: Jeff Fan Date: Fri, 20 Nov 2015 05:19:05 +0000 Subject: [PATCH 156/525] UefiCpuPkg: Not touch SmmFeatureControl if Code_Access_Chk not Set Bit SMM_Code_Access_Chk (SMM-RO) in MSR_SMM_MCA_CAP is defined in SDM. If set to 1 indicates that the SMM code access restriction is supported and the MSR_SMM_FEATURE_CONTROL is supported. If this bit is not set, we needn't to access register SmmFetureControl. Otherwise, #GP exception may happen. (Sync patch r18905 from main trunk.) Cc: Michael Kinney Cc: Jiewen Yao Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan Reviewed-by: Michael Kinney Reviewed-by: Jiewen Yao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18912 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c index de681c0a3069..532ac0974b7d 100644 --- a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c @@ -1309,9 +1309,9 @@ ConfigSmmCodeAccessCheckOnCurrentProcessor ( NewSmmFeatureControlMsr = SmmFeatureControlMsr; if (mSmmCodeAccessCheckEnable) { NewSmmFeatureControlMsr |= SMM_CODE_CHK_EN_BIT; - } - if (FeaturePcdGet (PcdCpuSmmFeatureControlMsrLock)) { - NewSmmFeatureControlMsr |= SMM_FEATURE_CONTROL_LOCK_BIT; + if (FeaturePcdGet (PcdCpuSmmFeatureControlMsrLock)) { + NewSmmFeatureControlMsr |= SMM_FEATURE_CONTROL_LOCK_BIT; + } } // @@ -1354,13 +1354,6 @@ ConfigSmmCodeAccessCheck ( // if ((AsmReadMsr64 (EFI_MSR_SMM_MCA_CAP) & SMM_CODE_ACCESS_CHK_BIT) == 0) { mSmmCodeAccessCheckEnable = FALSE; - } - - // - // If the SMM Code Access Check feature is disabled and the Feature Control MSR - // is not being locked, then no additional work is required - // - if (!mSmmCodeAccessCheckEnable && !FeaturePcdGet (PcdCpuSmmFeatureControlMsrLock)) { return; } From 181abae03616d46ffe577a8fab09b087ea3df218 Mon Sep 17 00:00:00 2001 From: Jeff Fan Date: Fri, 20 Nov 2015 05:19:55 +0000 Subject: [PATCH 157/525] UefiCpuPkg/SmmFeatureLib: Check SmmFeatureControl by Code_Access_Chk Bit SMM_Code_Access_Chk (SMM-RO) in MSR_SMM_MCA_CAP is defined in SDM. If set to 1 indicates that the SMM code access restriction is supported and the MSR_SMM_FEATURE_CONTROL is supported. If this bit is not set, we needn't to access register SmmFetureControl. Otherwise, #GP exception may happen. We need to check if SmmFeatureControl support or not by checking SMM_Code_Access_Chk (SMM-RO) in MSR_SMM_MCA_CAP. Because MSR_SMM_MCA_CAP is SMM-RO register, we should move this check from SmmCpuFeaturesLibConstructor (non-SMM) to SmmCpuFeaturesInitializeProcessor (SMM). (Sync patch r18906 from main trunk.) Cc: Michael Kinney Cc: Jiewen Yao Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan Reviewed-by: Michael Kinney Reviewed-by: Jiewen Yao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18913 6f19259b-4bc3-4df7-8a09-765794883524 --- .../SmmCpuFeaturesLib/SmmCpuFeaturesLib.c | 54 ++++++++++++++----- 1 file changed, 40 insertions(+), 14 deletions(-) diff --git a/UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.c b/UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.c index 0c1610d9777c..b839d3192f56 100644 --- a/UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.c +++ b/UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.c @@ -35,6 +35,12 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #define EFI_MSR_SMRR_PHYS_MASK_VALID BIT11 #define SMM_FEATURES_LIB_SMM_FEATURE_CONTROL 0x4E0 +// +// MSRs required for configuration of SMM Code Access Check +// +#define SMM_FEATURES_LIB_IA32_MCA_CAP 0x17D +#define SMM_CODE_ACCESS_CHK_BIT BIT58 + // // Set default value to assume SMRR is not supported // @@ -131,20 +137,6 @@ SmmCpuFeaturesLibConstructor ( } } - // - // Intel(R) 64 and IA-32 Architectures Software Developer's Manual - // Volume 3C, Section 35.10.1 MSRs in 4th Generation Intel(R) Core(TM) - // Processor Family - // - // If CPU Family/Model is 06_3C, 06_45, or 06_46 then use 4th Generation - // Intel(R) Core(TM) Processor Family MSRs - // - if (FamilyId == 0x06) { - if (ModelId == 0x3C || ModelId == 0x45 || ModelId == 0x46) { - mSmmFeatureControlSupported = TRUE; - } - } - // // Intel(R) 64 and IA-32 Architectures Software Developer's Manual // Volume 3C, Section 34.4.2 SMRAM Caching @@ -214,6 +206,10 @@ SmmCpuFeaturesInitializeProcessor ( { SMRAM_SAVE_STATE_MAP *CpuState; UINT64 FeatureControl; + UINT32 RegEax; + UINT32 RegEdx; + UINTN FamilyId; + UINTN ModelId; // // Configure SMBASE. @@ -253,6 +249,36 @@ SmmCpuFeaturesInitializeProcessor ( AsmWriteMsr64 (mSmrrPhysMaskMsr, (~(CpuHotPlugData->SmrrSize - 1) & EFI_MSR_SMRR_MASK)); mSmrrEnabled[CpuIndex] = FALSE; } + + // + // Retrieve CPU Family and Model + // + AsmCpuid (CPUID_VERSION_INFO, &RegEax, NULL, NULL, &RegEdx); + FamilyId = (RegEax >> 8) & 0xf; + ModelId = (RegEax >> 4) & 0xf; + if (FamilyId == 0x06 || FamilyId == 0x0f) { + ModelId = ModelId | ((RegEax >> 12) & 0xf0); + } + + // + // Intel(R) 64 and IA-32 Architectures Software Developer's Manual + // Volume 3C, Section 35.10.1 MSRs in 4th Generation Intel(R) Core(TM) + // Processor Family. + // + // If CPU Family/Model is 06_3C, 06_45, or 06_46 then use 4th Generation + // Intel(R) Core(TM) Processor Family MSRs. + // + if (FamilyId == 0x06) { + if (ModelId == 0x3C || ModelId == 0x45 || ModelId == 0x46) { + // + // Check to see if the CPU supports the SMM Code Access Check feature + // Do not access this MSR unless the CPU supports the SmmRegFeatureControl + // + if ((AsmReadMsr64 (SMM_FEATURES_LIB_IA32_MCA_CAP) & SMM_CODE_ACCESS_CHK_BIT) != 0) { + mSmmFeatureControlSupported = TRUE; + } + } + } } /** From 1acb4a137e46d4ce8013d7712ca25f2f13294fc3 Mon Sep 17 00:00:00 2001 From: Ruiyu Ni Date: Wed, 25 Nov 2015 06:42:16 +0000 Subject: [PATCH 158/525] MdeModulePkg/UefiBootManagerLib: Always create MemoryTypeInfo variable Align to old BDS behavior (IntelFrameworkModulePkg/BDS) to always create MemoryTypeInfo variable regardless of the PcdResetOnMemoryTypeInformationChange value. (Sync patch r18926 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ruiyu Ni Reviewed-by: Michael Kinney git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18939 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c | 8 +++----- MdeModulePkg/Library/UefiBootManagerLib/BmMisc.c | 15 ++++++++++----- .../Library/UefiBootManagerLib/InternalBm.h | 9 +++++++-- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c b/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c index 8f14cf6d3f81..4afd9c25ff2e 100644 --- a/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c +++ b/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c @@ -1689,11 +1689,9 @@ EfiBootManagerBoot ( // 6. Adjust the different type memory page number just before booting // and save the updated info into the variable for next boot to use // - if ((BootOption->Attributes & LOAD_OPTION_CATEGORY) == LOAD_OPTION_CATEGORY_BOOT) { - if (PcdGetBool (PcdResetOnMemoryTypeInformationChange)) { - BmSetMemoryTypeInformationVariable (); - } - } + BmSetMemoryTypeInformationVariable ( + (BOOLEAN) ((BootOption->Attributes & LOAD_OPTION_CATEGORY) == LOAD_OPTION_CATEGORY_BOOT) + ); DEBUG_CODE_BEGIN(); if (BootOption->Description == NULL) { diff --git a/MdeModulePkg/Library/UefiBootManagerLib/BmMisc.c b/MdeModulePkg/Library/UefiBootManagerLib/BmMisc.c index 97d1a48cd5a2..e675904857bb 100644 --- a/MdeModulePkg/Library/UefiBootManagerLib/BmMisc.c +++ b/MdeModulePkg/Library/UefiBootManagerLib/BmMisc.c @@ -122,11 +122,16 @@ BmMatchDevicePaths ( /** This routine adjust the memory information for different memory type and - save them into the variables for next boot. + save them into the variables for next boot. It resets the system when + memory information is updated and the current boot option belongs to + boot category instead of application category. + + @param Boot TRUE if current boot option belongs to boot category instead of + application category. **/ VOID BmSetMemoryTypeInformationVariable ( - VOID + IN BOOLEAN Boot ) { EFI_STATUS Status; @@ -267,11 +272,11 @@ BmSetMemoryTypeInformationVariable ( if (!EFI_ERROR (Status)) { // - // If the Memory Type Information settings have been modified, then reset the platform - // so the new Memory Type Information setting will be used to guarantee that an S4 + // If the Memory Type Information settings have been modified and the boot option belongs to boot category, + // then reset the platform so the new Memory Type Information setting will be used to guarantee that an S4 // entry/resume cycle will not fail. // - if (MemoryTypeInformationModified) { + if (MemoryTypeInformationModified && Boot && PcdGetBool (PcdResetOnMemoryTypeInformationChange)) { DEBUG ((EFI_D_INFO, "Memory Type Information settings change. Warm Reset!!!\n")); gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL); } diff --git a/MdeModulePkg/Library/UefiBootManagerLib/InternalBm.h b/MdeModulePkg/Library/UefiBootManagerLib/InternalBm.h index d415442e2399..c808ed2ffe21 100644 --- a/MdeModulePkg/Library/UefiBootManagerLib/InternalBm.h +++ b/MdeModulePkg/Library/UefiBootManagerLib/InternalBm.h @@ -232,11 +232,16 @@ BmGetImageHeader ( /** This routine adjust the memory information for different memory type and - save them into the variables for next boot. + save them into the variables for next boot. It resets the system when + memory information is updated and the current boot option belongs to + boot category instead of application category. + + @param Boot TRUE if current boot option belongs to boot category instead of + application category. **/ VOID BmSetMemoryTypeInformationVariable ( - VOID + IN BOOLEAN Boot ); /** From 4c98fa255a6c6307ad2d12ec86c9333bcdcb106e Mon Sep 17 00:00:00 2001 From: "Zeng, Star" Date: Wed, 25 Nov 2015 06:42:46 +0000 Subject: [PATCH 159/525] Check InternalAllocPoolByIndex status before refer buffer. Original code refers FreePoolHdr without check Status. It is obvious wrong and has risk. Aslo, if InternalAllocPoolByIndex() returns an error, then *FreePoolHdr is assigned to an uninitialized value. So we init Hdr be NULL. (Sync patch r18932 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: "Zeng, Star" Reviewed-by: "Yao, Jiewen" Reviewed-by: "Fan, Jeff" Reviewed-by: "Kinney, Michael D" git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18940 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Core/PiSmmCore/Pool.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/MdeModulePkg/Core/PiSmmCore/Pool.c b/MdeModulePkg/Core/PiSmmCore/Pool.c index 34dcc93f1ab4..761988e4162b 100644 --- a/MdeModulePkg/Core/PiSmmCore/Pool.c +++ b/MdeModulePkg/Core/PiSmmCore/Pool.c @@ -1,7 +1,7 @@ /** @file SMM Memory pool management functions. - Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.
+ Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -120,6 +120,7 @@ InternalAllocPoolByIndex ( ASSERT (PoolIndex <= MAX_POOL_INDEX); Status = EFI_SUCCESS; + Hdr = NULL; if (PoolIndex == MAX_POOL_INDEX) { Status = SmmInternalAllocatePages (AllocateAnyPages, EfiRuntimeServicesData, EFI_SIZE_TO_PAGES (MAX_POOL_SIZE << 1), &Address); if (EFI_ERROR (Status)) { @@ -228,7 +229,9 @@ SmmInternalAllocatePool ( } Status = InternalAllocPoolByIndex (PoolIndex, &FreePoolHdr); - *Buffer = &FreePoolHdr->Header + 1; + if (!EFI_ERROR(Status)) { + *Buffer = &FreePoolHdr->Header + 1; + } return Status; } From 3630da170ebf995a43e540196f7aed09d95c2f4c Mon Sep 17 00:00:00 2001 From: Jeff Fan Date: Wed, 25 Nov 2015 06:43:11 +0000 Subject: [PATCH 160/525] UefiCpuPkg/CpuMpPei: Set X2APIC flag if one x2APIC ID larger than 254 If there are any logical processor reporting an APIC ID of 255 or greater, set X2ApicEnable flag. GetInitialApicId() will return x2APIC ID if CPUID leaf B supported. (Sync patch r18933 from main trunk.) Cc: Feng Tian Cc: Michael Kinney Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan Reviewed-by: Michael Kinney git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18941 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/CpuMpPei/CpuMpPei.c | 21 ++++++++++++++++----- UefiCpuPkg/CpuMpPei/CpuMpPei.h | 2 ++ 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.c b/UefiCpuPkg/CpuMpPei/CpuMpPei.c index 8e35f288fe3c..8ed52436c98f 100644 --- a/UefiCpuPkg/CpuMpPei/CpuMpPei.c +++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.c @@ -146,11 +146,20 @@ ApCFunction ( PeiCpuMpData = ExchangeInfo->PeiCpuMpData; if (PeiCpuMpData->InitFlag) { // - // This is first time AP wakeup, get BIST inforamtion from AP stack + // This is first time AP wakeup, get BIST information from AP stack // BistData = *(UINTN *) (PeiCpuMpData->Buffer + NumApsExecuting * PeiCpuMpData->CpuApStackSize - sizeof (UINTN)); - PeiCpuMpData->CpuData[NumApsExecuting].ApicId = GetInitialApicId (); PeiCpuMpData->CpuData[NumApsExecuting].Health.Uint32 = (UINT32) BistData; + PeiCpuMpData->CpuData[NumApsExecuting].ApicId = GetInitialApicId (); + if (PeiCpuMpData->CpuData[NumApsExecuting].ApicId >= 0xFF) { + // + // Set x2APIC mode if there are any logical processor reporting + // an APIC ID of 255 or greater. + // + AcquireSpinLock(&PeiCpuMpData->MpLock); + PeiCpuMpData->X2ApicEnable = TRUE; + ReleaseSpinLock(&PeiCpuMpData->MpLock); + } // // Sync BSP's Mtrr table to all wakeup APs and load microcode on APs. // @@ -363,15 +372,16 @@ CountProcessorNumber ( // if (PcdGet32 (PcdCpuMaxLogicalProcessorNumber) > 1) { // - // Send broadcast IPI to APs to wakeup APs + // Send 1st broadcast IPI to APs to wakeup APs // - PeiCpuMpData->InitFlag = 1; + PeiCpuMpData->InitFlag = TRUE; + PeiCpuMpData->X2ApicEnable = FALSE; WakeUpAP (PeiCpuMpData, TRUE, 0, NULL, NULL); // // Wait for AP task to complete and then exit. // MicroSecondDelay (PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds)); - PeiCpuMpData->InitFlag = 0; + PeiCpuMpData->InitFlag = FALSE; PeiCpuMpData->CpuCount += (UINT32)PeiCpuMpData->MpCpuExchangeInfo->NumApsExecuting; ASSERT (PeiCpuMpData->CpuCount <= PcdGet32 (PcdCpuMaxLogicalProcessorNumber)); // @@ -439,6 +449,7 @@ PrepareAPStartupVector ( PeiCpuMpData->CpuData[0].ApicId = GetInitialApicId (); PeiCpuMpData->CpuData[0].Health.Uint32 = 0; PeiCpuMpData->EndOfPeiFlag = FALSE; + InitializeSpinLock(&PeiCpuMpData->MpLock); CopyMem (&PeiCpuMpData->AddressMap, &AddressMap, sizeof (MP_ASSEMBLY_ADDRESS_MAP)); // diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.h b/UefiCpuPkg/CpuMpPei/CpuMpPei.h index 9325a12d4ceb..de9011329c08 100644 --- a/UefiCpuPkg/CpuMpPei/CpuMpPei.h +++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.h @@ -124,6 +124,7 @@ typedef struct { // PEI CPU MP Data save in memory // struct _PEI_CPU_MP_DATA { + SPIN_LOCK MpLock; UINT32 CpuCount; UINT32 BspNumber; UINTN Buffer; @@ -137,6 +138,7 @@ struct _PEI_CPU_MP_DATA { volatile UINT32 FinishedCount; BOOLEAN EndOfPeiFlag; BOOLEAN InitFlag; + BOOLEAN X2ApicEnable; CPU_EXCHANGE_ROLE_INFO BSPInfo; CPU_EXCHANGE_ROLE_INFO APInfo; MTRR_SETTINGS MtrrTable; From 7e215c2d8ed8b1ea3b7e53a32769d64e3edccc2b Mon Sep 17 00:00:00 2001 From: Jeff Fan Date: Wed, 25 Nov 2015 06:43:39 +0000 Subject: [PATCH 161/525] UefiCpuPkg/CpuMpPei: Enable x2APIC mode on BSP/APs If x2APIC flag is set, enable x2APIC mode on all APs and BSP. Before we wakeup APs to enable x2APIC mode, we should wait all APs have finished initialization. (Sync patch r18934 from main trunk.) Cc: Feng Tian Cc: Michael Kinney Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan Reviewed-by: Michael Kinney git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18942 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/CpuMpPei/CpuMpPei.c | 39 ++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.c b/UefiCpuPkg/CpuMpPei/CpuMpPei.c index 8ed52436c98f..c22252220316 100644 --- a/UefiCpuPkg/CpuMpPei/CpuMpPei.c +++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.c @@ -101,6 +101,20 @@ SortApicId ( } } +/** + Enable x2APIC mode on APs. + + @param Buffer Pointer to private data buffer. +**/ +VOID +EFIAPI +ApFuncEnableX2Apic ( + IN OUT VOID *Buffer + ) +{ + SetApicMode (LOCAL_APIC_MODE_X2APIC); +} + /** Get CPU MP Data pointer from the Guided HOB. @@ -385,6 +399,31 @@ CountProcessorNumber ( PeiCpuMpData->CpuCount += (UINT32)PeiCpuMpData->MpCpuExchangeInfo->NumApsExecuting; ASSERT (PeiCpuMpData->CpuCount <= PcdGet32 (PcdCpuMaxLogicalProcessorNumber)); // + // Wait for all APs finished the initialization + // + while (PeiCpuMpData->FinishedCount < (PeiCpuMpData->CpuCount - 1)) { + CpuPause (); + } + + if (PeiCpuMpData->X2ApicEnable) { + DEBUG ((EFI_D_INFO, "Force x2APIC mode!\n")); + // + // Send 2nd broadcast IPI to all APs to enable x2APIC mode + // + WakeUpAP (PeiCpuMpData, TRUE, 0, ApFuncEnableX2Apic, NULL); + // + // Wait for all known APs finished + // + while (PeiCpuMpData->FinishedCount < (PeiCpuMpData->CpuCount - 1)) { + CpuPause (); + } + // + // Enable x2APIC on BSP + // + SetApicMode (LOCAL_APIC_MODE_X2APIC); + } + DEBUG ((EFI_D_INFO, "APIC MODE is %d\n", GetApicMode ())); + // // Sort BSP/Aps by CPU APIC ID in ascending order // SortApicId (PeiCpuMpData); From 94b76c954e6d37a95b8ab2753384b97d40bf4bfd Mon Sep 17 00:00:00 2001 From: "Yao, Jiewen" Date: Wed, 25 Nov 2015 08:54:22 +0000 Subject: [PATCH 162/525] Uninstall LoadedImage protocol if SMM driver returns error and is unloaded. Original code does not uninstall LoadedImage protocol if SMM driver returns error and is unloaded. It causes a wrong LoadedImage protocol existing in system. (Sync patch r18936 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: "Yao, Jiewen" Reviewed-by: "Zeng, Star" Reviewed-by: "Kinney, Michael D" git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18947 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Core/PiSmmCore/Dispatcher.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/MdeModulePkg/Core/PiSmmCore/Dispatcher.c b/MdeModulePkg/Core/PiSmmCore/Dispatcher.c index 81e8a0dc827a..cbaf549066e3 100644 --- a/MdeModulePkg/Core/PiSmmCore/Dispatcher.c +++ b/MdeModulePkg/Core/PiSmmCore/Dispatcher.c @@ -881,6 +881,20 @@ SmmDispatcher ( if (EFI_ERROR(Status)){ UnregisterSmramProfileImage (DriverEntry, TRUE); SmmFreePages(DriverEntry->ImageBuffer, DriverEntry->NumberOfPage); + // + // Uninstall LoadedImage + // + Status = gBS->UninstallProtocolInterface ( + DriverEntry->ImageHandle, + &gEfiLoadedImageProtocolGuid, + DriverEntry->LoadedImage + ); + if (!EFI_ERROR (Status)) { + if (DriverEntry->LoadedImage->FilePath != NULL) { + gBS->FreePool (DriverEntry->LoadedImage->FilePath); + } + gBS->FreePool (DriverEntry->LoadedImage); + } } REPORT_STATUS_CODE_WITH_EXTENDED_DATA ( From a3a09c3812661a14f57eb47f1e9ece7594be4cf2 Mon Sep 17 00:00:00 2001 From: "Yao, Jiewen" Date: Wed, 25 Nov 2015 08:54:57 +0000 Subject: [PATCH 163/525] Install LoadedImage protocol for PiSmmCore. PiSmmCore installs LoadedImage for each SMM driver. However itself is missing. So we follow DxeCore style, let PiSmmCore installs LoadedImage protocol for itself, then the SMM image information is complete. (Sync patch r18945 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: "Yao, Jiewen" Reviewed-by: "Zeng, Star" Reviewed-by: "Kinney, Michael D" git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@18948 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Core/PiSmmCore/Dispatcher.c | 33 +++++++++++++++- MdeModulePkg/Core/PiSmmCore/PiSmmCore.c | 49 ++++++++++++++++++++++++ MdeModulePkg/Core/PiSmmCore/PiSmmCore.h | 2 + 3 files changed, 82 insertions(+), 2 deletions(-) diff --git a/MdeModulePkg/Core/PiSmmCore/Dispatcher.c b/MdeModulePkg/Core/PiSmmCore/Dispatcher.c index cbaf549066e3..1f85ae8def61 100644 --- a/MdeModulePkg/Core/PiSmmCore/Dispatcher.c +++ b/MdeModulePkg/Core/PiSmmCore/Dispatcher.c @@ -103,7 +103,8 @@ BOOLEAN gRequestDispatch = FALSE; // EFI_FV_FILETYPE mSmmFileTypes[] = { EFI_FV_FILETYPE_SMM, - EFI_FV_FILETYPE_COMBINED_SMM_DXE + EFI_FV_FILETYPE_COMBINED_SMM_DXE, + EFI_FV_FILETYPE_SMM_CORE, // // Note: DXE core will process the FV image file, so skip it in SMM core // EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE @@ -1283,6 +1284,7 @@ SmmDriverDispatchHandler ( // // Discover Drivers in FV and add them to the Discovered Driver List. // Process EFI_FV_FILETYPE_SMM type and then EFI_FV_FILETYPE_COMBINED_SMM_DXE + // EFI_FV_FILETYPE_SMM_CORE is processed to produce a Loaded Image protocol for the core // for (SmmTypeIndex = 0; SmmTypeIndex < sizeof (mSmmFileTypes)/sizeof (EFI_FV_FILETYPE); SmmTypeIndex++) { // @@ -1300,7 +1302,34 @@ SmmDriverDispatchHandler ( &Size ); if (!EFI_ERROR (GetNextFileStatus)) { - SmmAddToDriverList (Fv, FvHandle, &NameGuid); + if (Type == EFI_FV_FILETYPE_SMM_CORE) { + // + // If this is the SMM core fill in it's DevicePath & DeviceHandle + // + if (mSmmCoreLoadedImage->FilePath == NULL) { + // + // Maybe one special FV contains only one SMM_CORE module, so its device path must + // be initialized completely. + // + EfiInitializeFwVolDevicepathNode (&mFvDevicePath.File, &NameGuid); + SetDevicePathEndNode (&mFvDevicePath.End); + + // + // Make an EfiBootServicesData buffer copy of FilePath + // + Status = gBS->AllocatePool ( + EfiBootServicesData, + GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath), + (VOID **)&mSmmCoreLoadedImage->FilePath + ); + ASSERT_EFI_ERROR (Status); + CopyMem (mSmmCoreLoadedImage->FilePath, &mFvDevicePath, GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath)); + + mSmmCoreLoadedImage->DeviceHandle = FvHandle; + } + } else { + SmmAddToDriverList (Fv, FvHandle, &NameGuid); + } } } while (!EFI_ERROR (GetNextFileStatus)); } diff --git a/MdeModulePkg/Core/PiSmmCore/PiSmmCore.c b/MdeModulePkg/Core/PiSmmCore/PiSmmCore.c index 496638a17ed1..aaa7efd8e07d 100644 --- a/MdeModulePkg/Core/PiSmmCore/PiSmmCore.c +++ b/MdeModulePkg/Core/PiSmmCore/PiSmmCore.c @@ -87,6 +87,8 @@ SMM_CORE_SMI_HANDLERS mSmmCoreSmiHandlers[] = { UINTN mFullSmramRangeCount; EFI_SMRAM_DESCRIPTOR *mFullSmramRanges; +EFI_LOADED_IMAGE_PROTOCOL *mSmmCoreLoadedImage; + /** Place holder function until all the SMM System Table Service are available. @@ -516,6 +518,51 @@ SmmEntryPoint ( PERF_END (NULL, "SMM", NULL, 0) ; } +/** + Install LoadedImage protocol for SMM Core. +**/ +VOID +SmmCoreInstallLoadedImage ( + VOID + ) +{ + EFI_STATUS Status; + EFI_HANDLE Handle; + + // + // Allocate a Loaded Image Protocol in EfiBootServicesData + // + Status = gBS->AllocatePool (EfiBootServicesData, sizeof(EFI_LOADED_IMAGE_PROTOCOL), (VOID **)&mSmmCoreLoadedImage); + ASSERT_EFI_ERROR (Status); + + ZeroMem (mSmmCoreLoadedImage, sizeof (EFI_LOADED_IMAGE_PROTOCOL)); + // + // Fill in the remaining fields of the Loaded Image Protocol instance. + // Note: ImageBase is an SMRAM address that can not be accessed outside of SMRAM if SMRAM window is closed. + // + mSmmCoreLoadedImage->Revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION; + mSmmCoreLoadedImage->ParentHandle = gSmmCorePrivate->SmmIplImageHandle; + mSmmCoreLoadedImage->SystemTable = gST; + + mSmmCoreLoadedImage->ImageBase = (VOID *)(UINTN)gSmmCorePrivate->PiSmmCoreImageBase; + mSmmCoreLoadedImage->ImageSize = gSmmCorePrivate->PiSmmCoreImageSize; + mSmmCoreLoadedImage->ImageCodeType = EfiRuntimeServicesCode; + mSmmCoreLoadedImage->ImageDataType = EfiRuntimeServicesData; + + // + // Create a new image handle in the UEFI handle database for the SMM Driver + // + Handle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces ( + &Handle, + &gEfiLoadedImageProtocolGuid, mSmmCoreLoadedImage, + NULL + ); + ASSERT_EFI_ERROR (Status); + + return ; +} + /** The Entry Point for SMM Core @@ -582,5 +629,7 @@ SmmMain ( RegisterSmramProfileHandler (); + SmmCoreInstallLoadedImage (); + return EFI_SUCCESS; } diff --git a/MdeModulePkg/Core/PiSmmCore/PiSmmCore.h b/MdeModulePkg/Core/PiSmmCore/PiSmmCore.h index e34bd8a640f3..0e9c92abef9a 100644 --- a/MdeModulePkg/Core/PiSmmCore/PiSmmCore.h +++ b/MdeModulePkg/Core/PiSmmCore/PiSmmCore.h @@ -959,6 +959,8 @@ SmramProfileReadyToLock ( extern UINTN mFullSmramRangeCount; extern EFI_SMRAM_DESCRIPTOR *mFullSmramRanges; +extern EFI_LOADED_IMAGE_PROTOCOL *mSmmCoreLoadedImage; + // // Page management // From 15bf315a1e829fd8a32c9002aace328cd130fe11 Mon Sep 17 00:00:00 2001 From: Jeff Fan Date: Mon, 30 Nov 2015 02:52:10 +0000 Subject: [PATCH 164/525] Sync two missing files when sync BaseTools from main trunk r18767. Reported-by: Mike Maslenkin Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19006 6f19259b-4bc3-4df7-8a09-765794883524 --- BaseTools/Scripts/PatchCheck.py | 607 ++++++++++++++++++ .../Source/Python/Common/MultipleWorkspace.py | 148 +++++ 2 files changed, 755 insertions(+) create mode 100644 BaseTools/Scripts/PatchCheck.py create mode 100644 BaseTools/Source/Python/Common/MultipleWorkspace.py diff --git a/BaseTools/Scripts/PatchCheck.py b/BaseTools/Scripts/PatchCheck.py new file mode 100644 index 000000000000..340a9972b838 --- /dev/null +++ b/BaseTools/Scripts/PatchCheck.py @@ -0,0 +1,607 @@ +## @file +# Check a patch for various format issues +# +# Copyright (c) 2015, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials are licensed and made +# available under the terms and conditions of the BSD License which +# accompanies this distribution. The full text of the license may be +# found at http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" +# BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER +# EXPRESS OR IMPLIED. +# + +from __future__ import print_function + +VersionNumber = '0.1' +__copyright__ = "Copyright (c) 2015, Intel Corporation All rights reserved." + +import email +import argparse +import os +import re +import subprocess +import sys + +class Verbose: + SILENT, ONELINE, NORMAL = range(3) + level = NORMAL + +class CommitMessageCheck: + """Checks the contents of a git commit message.""" + + def __init__(self, subject, message): + self.ok = True + + if subject is None and message is None: + self.error('Commit message is missing!') + return + + self.subject = subject + self.msg = message + + self.check_contributed_under() + self.check_signed_off_by() + self.check_misc_signatures() + self.check_overall_format() + self.report_message_result() + + url = 'https://github.com/tianocore/tianocore.github.io/wiki/Commit-Message-Format' + + def report_message_result(self): + if Verbose.level < Verbose.NORMAL: + return + if self.ok: + # All checks passed + return_code = 0 + print('The commit message format passed all checks.') + else: + return_code = 1 + if not self.ok: + print(self.url) + + def error(self, *err): + if self.ok and Verbose.level > Verbose.ONELINE: + print('The commit message format is not valid:') + self.ok = False + if Verbose.level < Verbose.NORMAL: + return + count = 0 + for line in err: + prefix = (' *', ' ')[count > 0] + print(prefix, line) + count += 1 + + def check_contributed_under(self): + cu_msg='Contributed-under: TianoCore Contribution Agreement 1.0' + if self.msg.find(cu_msg) < 0: + self.error('Missing Contributed-under! (Note: this must be ' + + 'added by the code contributor!)') + + @staticmethod + def make_signature_re(sig, re_input=False): + if re_input: + sub_re = sig + else: + sub_re = sig.replace('-', r'[-\s]+') + re_str = (r'^(?P' + sub_re + + r')(\s*):(\s*)(?P\S.*?)(?:\s*)$') + try: + return re.compile(re_str, re.MULTILINE|re.IGNORECASE) + except Exception: + print("Tried to compile re:", re_str) + raise + + sig_block_re = \ + re.compile(r'''^ + (?: (?P[^:]+) \s* : \s* + (?P\S.*?) ) + | + (?: \[ (?P[^:]+) \s* : \s* + (?P.+?) \s* \] ) + \s* $''', + re.VERBOSE | re.MULTILINE) + + def find_signatures(self, sig): + if not sig.endswith('-by') and sig != 'Cc': + sig += '-by' + regex = self.make_signature_re(sig) + + sigs = regex.findall(self.msg) + + bad_case_sigs = filter(lambda m: m[0] != sig, sigs) + for s in bad_case_sigs: + self.error("'" +s[0] + "' should be '" + sig + "'") + + for s in sigs: + if s[1] != '': + self.error('There should be no spaces between ' + sig + + " and the ':'") + if s[2] != ' ': + self.error("There should be a space after '" + sig + ":'") + + self.check_email_address(s[3]) + + return sigs + + email_re1 = re.compile(r'(?:\s*)(.*?)(\s*)<(.+)>\s*$', + re.MULTILINE|re.IGNORECASE) + + def check_email_address(self, email): + email = email.strip() + mo = self.email_re1.match(email) + if mo is None: + self.error("Email format is invalid: " + email.strip()) + return + + name = mo.group(1).strip() + if name == '': + self.error("Name is not provided with email address: " + + email) + else: + quoted = len(name) > 2 and name[0] == '"' and name[-1] == '"' + if name.find(',') >= 0 and not quoted: + self.error('Add quotes (") around name with a comma: ' + + name) + + if mo.group(2) == '': + self.error("There should be a space between the name and " + + "email address: " + email) + + if mo.group(3).find(' ') >= 0: + self.error("The email address cannot contain a space: " + + mo.group(3)) + + def check_signed_off_by(self): + sob='Signed-off-by' + if self.msg.find(sob) < 0: + self.error('Missing Signed-off-by! (Note: this must be ' + + 'added by the code contributor!)') + return + + sobs = self.find_signatures('Signed-off') + + if len(sobs) == 0: + self.error('Invalid Signed-off-by format!') + return + + sig_types = ( + 'Reviewed', + 'Reported', + 'Tested', + 'Suggested', + 'Acked', + 'Cc' + ) + + def check_misc_signatures(self): + for sig in self.sig_types: + self.find_signatures(sig) + + def check_overall_format(self): + lines = self.msg.splitlines() + + if len(lines) >= 1 and lines[0].endswith('\r\n'): + empty_line = '\r\n' + else: + empty_line = '\n' + + lines.insert(0, empty_line) + lines.insert(0, self.subject + empty_line) + + count = len(lines) + + if count <= 0: + self.error('Empty commit message!') + return + + if count >= 1 and len(lines[0]) > 76: + self.error('First line of commit message (subject line) ' + + 'is too long.') + + if count >= 1 and len(lines[0].strip()) == 0: + self.error('First line of commit message (subject line) ' + + 'is empty.') + + if count >= 2 and lines[1].strip() != '': + self.error('Second line of commit message should be ' + + 'empty.') + + for i in range(2, count): + if (len(lines[i]) > 76 and + len(lines[i].split()) > 1 and + not lines[i].startswith('git-svn-id:')): + self.error('Line %d of commit message is too long.' % (i + 1)) + + last_sig_line = None + for i in range(count - 1, 0, -1): + line = lines[i] + mo = self.sig_block_re.match(line) + if mo is None: + if line.strip() == '': + break + elif last_sig_line is not None: + err2 = 'Add empty line before "%s"?' % last_sig_line + self.error('The line before the signature block ' + + 'should be empty', err2) + else: + self.error('The signature block was not found') + break + last_sig_line = line.strip() + +(START, PRE_PATCH, PATCH) = range(3) + +class GitDiffCheck: + """Checks the contents of a git diff.""" + + def __init__(self, diff): + self.ok = True + self.format_ok = True + self.lines = diff.splitlines(True) + self.count = len(self.lines) + self.line_num = 0 + self.state = START + while self.line_num < self.count and self.format_ok: + line_num = self.line_num + self.run() + assert(self.line_num > line_num) + self.report_message_result() + + def report_message_result(self): + if Verbose.level < Verbose.NORMAL: + return + if self.ok: + print('The code passed all checks.') + + def run(self): + line = self.lines[self.line_num] + + if self.state in (PRE_PATCH, PATCH): + if line.startswith('diff --git'): + self.state = START + if self.state == PATCH: + if line.startswith('@@ '): + self.state = PRE_PATCH + elif len(line) >= 1 and line[0] not in ' -+' and \ + not line.startswith(r'\ No newline '): + for line in self.lines[self.line_num + 1:]: + if line.startswith('diff --git'): + self.format_error('diff found after end of patch') + break + self.line_num = self.count + return + + if self.state == START: + if line.startswith('diff --git'): + self.state = PRE_PATCH + self.set_filename(None) + elif len(line.rstrip()) != 0: + self.format_error("didn't find diff command") + self.line_num += 1 + elif self.state == PRE_PATCH: + if line.startswith('+++ b/'): + self.set_filename(line[6:].rstrip()) + if line.startswith('@@ '): + self.state = PATCH + else: + ok = False + for pfx in self.pre_patch_prefixes: + if line.startswith(pfx): + ok = True + if not ok: + self.format_error("didn't find diff hunk marker (@@)") + self.line_num += 1 + elif self.state == PATCH: + if line.startswith('-'): + pass + elif line.startswith('+'): + self.check_added_line(line[1:]) + elif line.startswith(r'\ No newline '): + pass + elif not line.startswith(' '): + self.format_error("unexpected patch line") + self.line_num += 1 + + pre_patch_prefixes = ( + '--- ', + '+++ ', + 'index ', + 'new file ', + 'deleted file ', + 'old mode ', + 'new mode ', + 'similarity index ', + 'rename ', + 'Binary files ', + ) + + line_endings = ('\r\n', '\n\r', '\n', '\r') + + def set_filename(self, filename): + self.hunk_filename = filename + if filename: + self.force_crlf = not filename.endswith('.sh') + else: + self.force_crlf = True + + def added_line_error(self, msg, line): + lines = [ msg ] + if self.hunk_filename is not None: + lines.append('File: ' + self.hunk_filename) + lines.append('Line: ' + line) + + self.error(*lines) + + def check_added_line(self, line): + eol = '' + for an_eol in self.line_endings: + if line.endswith(an_eol): + eol = an_eol + line = line[:-len(eol)] + + stripped = line.rstrip() + + if self.force_crlf and eol != '\r\n': + self.added_line_error('Line ending (%s) is not CRLF' % repr(eol), + line) + if '\t' in line: + self.added_line_error('Tab character used', line) + if len(stripped) < len(line): + self.added_line_error('Trailing whitespace found', line) + + split_diff_re = re.compile(r''' + (?P + ^ diff \s+ --git \s+ a/.+ \s+ b/.+ $ + ) + (?P + ^ index \s+ .+ $ + ) + ''', + re.IGNORECASE | re.VERBOSE | re.MULTILINE) + + def format_error(self, err): + self.format_ok = False + err = 'Patch format error: ' + err + err2 = 'Line: ' + self.lines[self.line_num].rstrip() + self.error(err, err2) + + def error(self, *err): + if self.ok and Verbose.level > Verbose.ONELINE: + print('Code format is not valid:') + self.ok = False + if Verbose.level < Verbose.NORMAL: + return + count = 0 + for line in err: + prefix = (' *', ' ')[count > 0] + print(prefix, line) + count += 1 + +class CheckOnePatch: + """Checks the contents of a git email formatted patch. + + Various checks are performed on both the commit message and the + patch content. + """ + + def __init__(self, name, patch): + self.patch = patch + self.find_patch_pieces() + + msg_check = CommitMessageCheck(self.commit_subject, self.commit_msg) + msg_ok = msg_check.ok + + diff_ok = True + if self.diff is not None: + diff_check = GitDiffCheck(self.diff) + diff_ok = diff_check.ok + + self.ok = msg_ok and diff_ok + + if Verbose.level == Verbose.ONELINE: + if self.ok: + result = 'ok' + else: + result = list() + if not msg_ok: + result.append('commit message') + if not diff_ok: + result.append('diff content') + result = 'bad ' + ' and '.join(result) + print(name, result) + + + git_diff_re = re.compile(r''' + ^ diff \s+ --git \s+ a/.+ \s+ b/.+ $ + ''', + re.IGNORECASE | re.VERBOSE | re.MULTILINE) + + stat_re = \ + re.compile(r''' + (?P [\s\S\r\n]* ) + (?P + ^ --- $ [\r\n]+ + (?: ^ \s+ .+ \s+ \| \s+ \d+ \s+ \+* \-* + $ [\r\n]+ )+ + [\s\S\r\n]+ + ) + ''', + re.IGNORECASE | re.VERBOSE | re.MULTILINE) + + def find_patch_pieces(self): + if sys.version_info < (3, 0): + patch = self.patch.encode('ascii', 'ignore') + else: + patch = self.patch + + self.commit_msg = None + self.stat = None + self.commit_subject = None + self.commit_prefix = None + self.diff = None + + if patch.startswith('diff --git'): + self.diff = patch + return + + pmail = email.message_from_string(patch) + parts = list(pmail.walk()) + assert(len(parts) == 1) + assert(parts[0].get_content_type() == 'text/plain') + content = parts[0].get_payload(decode=True).decode('utf-8', 'ignore') + + mo = self.git_diff_re.search(content) + if mo is not None: + self.diff = content[mo.start():] + content = content[:mo.start()] + + mo = self.stat_re.search(content) + if mo is None: + self.commit_msg = content + else: + self.stat = mo.group('stat') + self.commit_msg = mo.group('commit_message') + + self.commit_subject = pmail['subject'].replace('\r\n', '') + self.commit_subject = self.commit_subject.replace('\n', '') + + pfx_start = self.commit_subject.find('[') + if pfx_start >= 0: + pfx_end = self.commit_subject.find(']') + if pfx_end > pfx_start: + self.commit_prefix = self.commit_subject[pfx_start + 1 : pfx_end] + self.commit_subject = self.commit_subject[pfx_end + 1 :].lstrip() + + +class CheckGitCommits: + """Reads patches from git based on the specified git revision range. + + The patches are read from git, and then checked. + """ + + def __init__(self, rev_spec, max_count): + commits = self.read_commit_list_from_git(rev_spec, max_count) + if len(commits) == 1 and Verbose.level > Verbose.ONELINE: + commits = [ rev_spec ] + self.ok = True + blank_line = False + for commit in commits: + if Verbose.level > Verbose.ONELINE: + if blank_line: + print() + else: + blank_line = True + print('Checking git commit:', commit) + patch = self.read_patch_from_git(commit) + self.ok &= CheckOnePatch(commit, patch).ok + + def read_commit_list_from_git(self, rev_spec, max_count): + # Run git to get the commit patch + cmd = [ 'rev-list', '--abbrev-commit', '--no-walk' ] + if max_count is not None: + cmd.append('--max-count=' + str(max_count)) + cmd.append(rev_spec) + out = self.run_git(*cmd) + return out.split() + + def read_patch_from_git(self, commit): + # Run git to get the commit patch + return self.run_git('show', '--pretty=email', commit) + + def run_git(self, *args): + cmd = [ 'git' ] + cmd += args + p = subprocess.Popen(cmd, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + return p.communicate()[0].decode('utf-8', 'ignore') + +class CheckOnePatchFile: + """Performs a patch check for a single file. + + stdin is used when the filename is '-'. + """ + + def __init__(self, patch_filename): + if patch_filename == '-': + patch = sys.stdin.read() + patch_filename = 'stdin' + else: + f = open(patch_filename, 'rb') + patch = f.read().decode('utf-8', 'ignore') + f.close() + if Verbose.level > Verbose.ONELINE: + print('Checking patch file:', patch_filename) + self.ok = CheckOnePatch(patch_filename, patch).ok + +class CheckOneArg: + """Performs a patch check for a single command line argument. + + The argument will be handed off to a file or git-commit based + checker. + """ + + def __init__(self, param, max_count=None): + self.ok = True + if param == '-' or os.path.exists(param): + checker = CheckOnePatchFile(param) + else: + checker = CheckGitCommits(param, max_count) + self.ok = checker.ok + +class PatchCheckApp: + """Checks patches based on the command line arguments.""" + + def __init__(self): + self.parse_options() + patches = self.args.patches + + if len(patches) == 0: + patches = [ 'HEAD' ] + + self.ok = True + self.count = None + for patch in patches: + self.process_one_arg(patch) + + if self.count is not None: + self.process_one_arg('HEAD') + + if self.ok: + self.retval = 0 + else: + self.retval = -1 + + def process_one_arg(self, arg): + if len(arg) >= 2 and arg[0] == '-': + try: + self.count = int(arg[1:]) + return + except ValueError: + pass + self.ok &= CheckOneArg(arg, self.count).ok + self.count = None + + def parse_options(self): + parser = argparse.ArgumentParser(description=__copyright__) + parser.add_argument('--version', action='version', + version='%(prog)s ' + VersionNumber) + parser.add_argument('patches', nargs='*', + help='[patch file | git rev list]') + group = parser.add_mutually_exclusive_group() + group.add_argument("--oneline", + action="store_true", + help="Print one result per line") + group.add_argument("--silent", + action="store_true", + help="Print nothing") + self.args = parser.parse_args() + if self.args.oneline: + Verbose.level = Verbose.ONELINE + if self.args.silent: + Verbose.level = Verbose.SILENT + +if __name__ == "__main__": + sys.exit(PatchCheckApp().retval) diff --git a/BaseTools/Source/Python/Common/MultipleWorkspace.py b/BaseTools/Source/Python/Common/MultipleWorkspace.py new file mode 100644 index 000000000000..feb1f8d5ebe6 --- /dev/null +++ b/BaseTools/Source/Python/Common/MultipleWorkspace.py @@ -0,0 +1,148 @@ +## @file +# manage multiple workspace file. +# +# This file is required to make Python interpreter treat the directory +# as containing package. +# +# Copyright (c) 2015, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# + +import Common.LongFilePathOs as os +from Common.DataType import TAB_WORKSPACE + +## MultipleWorkspace +# +# This class manage multiple workspace behavior +# +# @param class: +# +# @var WORKSPACE: defined the current WORKSPACE +# @var PACKAGES_PATH: defined the other WORKSAPCE, if current WORKSPACE is invalid, search valid WORKSPACE from PACKAGES_PATH +# +class MultipleWorkspace(object): + WORKSPACE = '' + PACKAGES_PATH = None + + ## convertPackagePath() + # + # Convert path to match workspace. + # + # @param cls The class pointer + # @param Ws The current WORKSPACE + # @param Path Path to be converted to match workspace. + # + @classmethod + def convertPackagePath(cls, Ws, Path): + if str(os.path.normcase (Path)).startswith(Ws): + return os.path.join(Ws, os.path.relpath(Path, Ws)) + return Path + + ## setWs() + # + # set WORKSPACE and PACKAGES_PATH environment + # + # @param cls The class pointer + # @param Ws initialize WORKSPACE variable + # @param PackagesPath initialize PackagesPath variable + # + @classmethod + def setWs(cls, Ws, PackagesPath=None): + cls.WORKSPACE = Ws + if PackagesPath: + cls.PACKAGES_PATH = [cls.convertPackagePath (Ws, os.path.normpath(Path.strip())) for Path in PackagesPath.split(os.pathsep)] + else: + cls.PACKAGES_PATH = [] + + ## join() + # + # rewrite os.path.join function + # + # @param cls The class pointer + # @param Ws the current WORKSPACE + # @param *p path of the inf/dec/dsc/fdf/conf file + # @retval Path the absolute path of specified file + # + @classmethod + def join(cls, Ws, *p): + Path = os.path.join(Ws, *p) + if not os.path.exists(Path): + for Pkg in cls.PACKAGES_PATH: + Path = os.path.join(Pkg, *p) + if os.path.exists(Path): + return Path + Path = os.path.join(Ws, *p) + return Path + + ## relpath() + # + # rewrite os.path.relpath function + # + # @param cls The class pointer + # @param Path path of the inf/dec/dsc/fdf/conf file + # @param Ws the current WORKSPACE + # @retval Path the relative path of specified file + # + @classmethod + def relpath(cls, Path, Ws): + for Pkg in cls.PACKAGES_PATH: + if Path.lower().startswith(Pkg.lower()): + Path = os.path.relpath(Path, Pkg) + return Path + if Path.lower().startswith(Ws.lower()): + Path = os.path.relpath(Path, Ws) + return Path + + ## getWs() + # + # get valid workspace for the path + # + # @param cls The class pointer + # @param Ws the current WORKSPACE + # @param Path path of the inf/dec/dsc/fdf/conf file + # @retval Ws the valid workspace relative to the specified file path + # + @classmethod + def getWs(cls, Ws, Path): + absPath = os.path.join(Ws, Path) + if not os.path.exists(absPath): + for Pkg in cls.PACKAGES_PATH: + absPath = os.path.join(Pkg, Path) + if os.path.exists(absPath): + return Pkg + return Ws + + ## handleWsMacro() + # + # handle the $(WORKSPACE) tag, if current workspace is invalid path relative the tool, replace it. + # + # @param cls The class pointer + # @retval PathStr Path string include the $(WORKSPACE) + # + @classmethod + def handleWsMacro(cls, PathStr): + if TAB_WORKSPACE in PathStr: + Path = PathStr.replace(TAB_WORKSPACE, cls.WORKSPACE).strip() + if not os.path.exists(Path): + for Pkg in cls.PACKAGES_PATH: + Path = PathStr.replace(TAB_WORKSPACE, Pkg).strip() + if os.path.exists(Path): + return Path + return PathStr + + ## getPkgPath() + # + # get all package pathes. + # + # @param cls The class pointer + # + @classmethod + def getPkgPath(cls): + return cls.PACKAGES_PATH + \ No newline at end of file From 564fc1ffa38b802c553039292b1d74d2dd6f485e Mon Sep 17 00:00:00 2001 From: Star Zeng Date: Mon, 30 Nov 2015 03:13:42 +0000 Subject: [PATCH 165/525] MdePkg SerialIo.h: Fix typo "buts" to "bits" (Sync patch r18907 from main trunk.) Cc: Michael D Kinney Cc: Liming Gao Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Star Zeng Reviewed-by: Michael D Kinney git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19008 6f19259b-4bc3-4df7-8a09-765794883524 --- MdePkg/Include/Protocol/SerialIo.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MdePkg/Include/Protocol/SerialIo.h b/MdePkg/Include/Protocol/SerialIo.h index c66abef818c0..31cd46614ed0 100644 --- a/MdePkg/Include/Protocol/SerialIo.h +++ b/MdePkg/Include/Protocol/SerialIo.h @@ -4,7 +4,7 @@ Abstraction of a basic serial device. Targeted at 16550 UART, but could be much more generic. - Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.
+ Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -105,7 +105,7 @@ EFI_STATUS /** Sets the baud rate, receive FIFO depth, transmit/receice time out, parity, - data buts, and stop bits on a serial device. + data bits, and stop bits on a serial device. @param This Protocol instance pointer. @param BaudRate The requested baud rate. A BaudRate value of 0 will use the From 960da7f74c795d4ac26732a944aeb0d71915c4b6 Mon Sep 17 00:00:00 2001 From: Star Zeng Date: Mon, 30 Nov 2015 03:14:14 +0000 Subject: [PATCH 166/525] MdePkg SerialPortLib: Fix typo in SerialPortWrite() The "read" word in SerialPortWrite() header comment block should be "write". (Sync patch r18908 from main trunk.) Cc: Michael D Kinney Cc: Liming Gao Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Star Zeng Reviewed-by: Michael D Kinney git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19009 6f19259b-4bc3-4df7-8a09-765794883524 --- MdePkg/Include/Library/SerialPortLib.h | 4 ++-- MdePkg/Library/BaseSerialPortLibNull/BaseSerialPortLibNull.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/MdePkg/Include/Library/SerialPortLib.h b/MdePkg/Include/Library/SerialPortLib.h index 8f957864d858..1b129a71c1d8 100644 --- a/MdePkg/Include/Library/SerialPortLib.h +++ b/MdePkg/Include/Library/SerialPortLib.h @@ -1,7 +1,7 @@ /** @file This library class provides common serial I/O port functions. -Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.
+Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -46,7 +46,7 @@ SerialPortInitialize ( @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. + If this value is less than NumberOfBytes, then the write operation failed. **/ UINTN diff --git a/MdePkg/Library/BaseSerialPortLibNull/BaseSerialPortLibNull.c b/MdePkg/Library/BaseSerialPortLibNull/BaseSerialPortLibNull.c index d44fa523c2d8..72ae23815b37 100644 --- a/MdePkg/Library/BaseSerialPortLibNull/BaseSerialPortLibNull.c +++ b/MdePkg/Library/BaseSerialPortLibNull/BaseSerialPortLibNull.c @@ -1,7 +1,7 @@ /** @file Null Serial Port library instance with empty functions. - Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
+ Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -50,7 +50,7 @@ SerialPortInitialize ( @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. + If this value is less than NumberOfBytes, then the write operation failed. **/ UINTN From f7c016a6ae6e8f2a5464b5f0afd9f65014925903 Mon Sep 17 00:00:00 2001 From: Star Zeng Date: Mon, 30 Nov 2015 03:14:42 +0000 Subject: [PATCH 167/525] PcAtChipsetPkg SerialIoLib: Fix typo in SerialPortWrite() The "read" word in SerialPortWrite() header comment block should be "write". (Sync patch r18909 from main trunk.) Cc: Michael D Kinney Cc: Liming Gao Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Star Zeng Reviewed-by: Michael D Kinney git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19010 6f19259b-4bc3-4df7-8a09-765794883524 --- PcAtChipsetPkg/Library/SerialIoLib/SerialPortLib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PcAtChipsetPkg/Library/SerialIoLib/SerialPortLib.c b/PcAtChipsetPkg/Library/SerialIoLib/SerialPortLib.c index 6bf705312d88..b364a5c8ab2c 100644 --- a/PcAtChipsetPkg/Library/SerialIoLib/SerialPortLib.c +++ b/PcAtChipsetPkg/Library/SerialIoLib/SerialPortLib.c @@ -1,7 +1,7 @@ /** @file UART Serial Port library functions - Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.
+ Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -118,7 +118,7 @@ SerialPortInitialize ( @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. + If this value is less than NumberOfBytes, then the write operation failed. **/ UINTN From 714246d34b1f6541d9294e501b01f05083794876 Mon Sep 17 00:00:00 2001 From: Star Zeng Date: Mon, 30 Nov 2015 03:15:07 +0000 Subject: [PATCH 168/525] MdeModulePkg BaseSerialPortLib16550: Fix typo in SerialPortWrite() The "read" word in SerialPortWrite() header comment block should be "write". (Sync patch r18910 from main trunk.) Cc: Michael D Kinney Cc: Liming Gao Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Star Zeng Reviewed-by: Michael D Kinney git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19011 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Library/BaseSerialPortLib16550/BaseSerialPortLib16550.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.c b/MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.c index 3209115a3f88..5b6608d40082 100644 --- a/MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.c +++ b/MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.c @@ -574,7 +574,7 @@ SerialPortInitialize ( @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. + If this value is less than NumberOfBytes, then the write operation failed. **/ UINTN From 5b57cac303683249163eb55e6a8bce30ff03a6d3 Mon Sep 17 00:00:00 2001 From: Star Zeng Date: Mon, 30 Nov 2015 03:15:41 +0000 Subject: [PATCH 169/525] MdeModulePkg: TerminalDxe: avoid checking uninitialized variable The SerialIo->GetControl() function is not required to set the Control output parameter on error. Make sure we apply the EFI_SERIAL_INPUT_BUFFER_EMPTY optimization in TerminalConInTimerHandler() only if the SerialIo->GetControl() function call set that bit in the Control variable. (Sync patch r18962 from main trunk.) Cc: Michael D Kinney Cc: Liming Gao Cc: Feng Tian Cc: Laszlo Ersek Contributed-under: TianoCore Contribution Agreement 1.0 Suggested-by: Laszlo Ersek Signed-off-by: Star Zeng Reviewed-by: Michael Kinney Reviewed-by: Laszlo Ersek git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19012 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c b/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c index c216ed900fc5..3be877b4661e 100644 --- a/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c +++ b/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c @@ -2,7 +2,7 @@ Implementation for EFI_SIMPLE_TEXT_INPUT_PROTOCOL protocol. (C) Copyright 2014 Hewlett-Packard Development Company, L.P.
-Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.
+Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -562,10 +562,11 @@ TerminalConInTimerHandler ( } // // Check whether serial buffer is empty. + // Skip the key transfer loop only if the SerialIo protocol instance + // successfully reports EFI_SERIAL_INPUT_BUFFER_EMPTY. // Status = SerialIo->GetControl (SerialIo, &Control); - - if ((Control & EFI_SERIAL_INPUT_BUFFER_EMPTY) == 0) { + if (EFI_ERROR (Status) || ((Control & EFI_SERIAL_INPUT_BUFFER_EMPTY) == 0)) { // // Fetch all the keys in the serial buffer, // and insert the byte stream into RawFIFO. From caba346f89d3bad2f0eef8db4a81b305d32557d6 Mon Sep 17 00:00:00 2001 From: Star Zeng Date: Mon, 30 Nov 2015 03:16:14 +0000 Subject: [PATCH 170/525] MdePkg SerialPortLib: Upstream Get(Set)Control/SetAttributes interfaces The extended interfaces GetControl/SetControl/SetAttributes are from EmbeddedPkg/Include/Library/SerialPortExtLib.h. (Sync patch r18963 from main trunk.) Cc: Michael D Kinney Cc: Liming Gao Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Star Zeng Reviewed-by: Liming Gao Reviewed-by: Michael D Kinney git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19013 6f19259b-4bc3-4df7-8a09-765794883524 --- MdePkg/Include/Library/SerialPortLib.h | 80 +++++++++++++++++ .../BaseSerialPortLibNull.c | 85 +++++++++++++++++++ 2 files changed, 165 insertions(+) diff --git a/MdePkg/Include/Library/SerialPortLib.h b/MdePkg/Include/Library/SerialPortLib.h index 1b129a71c1d8..965a2d964b02 100644 --- a/MdePkg/Include/Library/SerialPortLib.h +++ b/MdePkg/Include/Library/SerialPortLib.h @@ -2,6 +2,7 @@ This library class provides common serial I/O port functions. Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
+Copyright (c) 2012 - 2014, ARM Ltd. All rights reserved. This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -15,6 +16,9 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #ifndef __SERIAL_PORT_LIB__ #define __SERIAL_PORT_LIB__ +#include +#include + /** Initialize the serial device hardware. @@ -97,4 +101,80 @@ SerialPortPoll ( VOID ); +/** + Sets the control bits on a serial device. + + @param 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 + ); + +/** + Retrieve the status of the control bits on a serial device. + + @param 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 + ); + +/** + Sets the baud rate, receive FIFO depth, transmit/receice time out, parity, + data bits, and stop bits on a serial device. + + @param 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 ReveiveFifoDepth 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 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 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 DataBits The number of data bits to use on the serial device. A DataBits + vaule of 0 will use the device's default data bit setting. + On output, the value actually set. + @param 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 + ); + #endif diff --git a/MdePkg/Library/BaseSerialPortLibNull/BaseSerialPortLibNull.c b/MdePkg/Library/BaseSerialPortLibNull/BaseSerialPortLibNull.c index 72ae23815b37..e29fdf55bbfb 100644 --- a/MdePkg/Library/BaseSerialPortLibNull/BaseSerialPortLibNull.c +++ b/MdePkg/Library/BaseSerialPortLibNull/BaseSerialPortLibNull.c @@ -110,3 +110,88 @@ SerialPortPoll ( return FALSE; } +/** + Sets the control bits on a serial device. + + @param 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 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/receice time out, parity, + data bits, and stop bits on a serial device. + + @param 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 ReveiveFifoDepth 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 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 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 DataBits The number of data bits to use on the serial device. A DataBits + vaule of 0 will use the device's default data bit setting. + On output, the value actually set. + @param 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; +} + From 877d347b3e6b0ad5fd505e492448657212edb5c1 Mon Sep 17 00:00:00 2001 From: Star Zeng Date: Mon, 30 Nov 2015 03:16:39 +0000 Subject: [PATCH 171/525] PcAtChipsetPkg SerialIoLib: Implement Get(Set)Control/SetAttributes (Sync patch r18964 from main trunk.) Cc: Michael D Kinney Cc: Liming Gao Cc: Ruiyu Ni Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Star Zeng Reviewed-by: Liming Gao Reviewed-by: Michael D Kinney git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19014 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Library/SerialIoLib/SerialPortLib.c | 276 ++++++++++++++++++ 1 file changed, 276 insertions(+) diff --git a/PcAtChipsetPkg/Library/SerialIoLib/SerialPortLib.c b/PcAtChipsetPkg/Library/SerialIoLib/SerialPortLib.c index b364a5c8ab2c..8656785347b2 100644 --- a/PcAtChipsetPkg/Library/SerialIoLib/SerialPortLib.c +++ b/PcAtChipsetPkg/Library/SerialIoLib/SerialPortLib.c @@ -39,6 +39,12 @@ #define LSR_TXRDY 0x20 #define LSR_RXDA 0x01 #define DLAB 0x01 +#define MCR_DTRC 0x01 +#define MCR_RTS 0x02 +#define MSR_CTS 0x10 +#define MSR_DSR 0x20 +#define MSR_RI 0x40 +#define MSR_DCD 0x80 //--------------------------------------------- // UART Settings @@ -219,3 +225,273 @@ SerialPortPoll ( return (BOOLEAN) ((Data & LSR_RXDA) != 0); } +/** + Sets the control bits on a serial device. + + @param 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 + ) +{ + UINT8 Mcr; + + // + // First determine the parameter is invalid. + // + if ((Control & (~(EFI_SERIAL_REQUEST_TO_SEND | EFI_SERIAL_DATA_TERMINAL_READY))) != 0) { + return RETURN_UNSUPPORTED; + } + + // + // Read the Modem Control Register. + // + Mcr = IoRead8 ((UINT16) gUartBase + MCR_OFFSET); + Mcr &= (~(MCR_DTRC | MCR_RTS)); + + if ((Control & EFI_SERIAL_DATA_TERMINAL_READY) == EFI_SERIAL_DATA_TERMINAL_READY) { + Mcr |= MCR_DTRC; + } + + if ((Control & EFI_SERIAL_REQUEST_TO_SEND) == EFI_SERIAL_REQUEST_TO_SEND) { + Mcr |= MCR_RTS; + } + + // + // Write the Modem Control Register. + // + IoWrite8 ((UINT16) gUartBase + MCR_OFFSET, Mcr); + + return RETURN_SUCCESS; +} + +/** + Retrieve the status of the control bits on a serial device. + + @param 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 + ) +{ + UINT8 Msr; + UINT8 Mcr; + UINT8 Lsr; + + *Control = 0; + + // + // Read the Modem Status Register. + // + Msr = IoRead8 ((UINT16) gUartBase + MSR_OFFSET); + + if ((Msr & MSR_CTS) == MSR_CTS) { + *Control |= EFI_SERIAL_CLEAR_TO_SEND; + } + + if ((Msr & MSR_DSR) == MSR_DSR) { + *Control |= EFI_SERIAL_DATA_SET_READY; + } + + if ((Msr & MSR_RI) == MSR_RI) { + *Control |= EFI_SERIAL_RING_INDICATE; + } + + if ((Msr & MSR_DCD) == MSR_DCD) { + *Control |= EFI_SERIAL_CARRIER_DETECT; + } + + // + // Read the Modem Control Register. + // + Mcr = IoRead8 ((UINT16) gUartBase + MCR_OFFSET); + + if ((Mcr & MCR_DTRC) == MCR_DTRC) { + *Control |= EFI_SERIAL_DATA_TERMINAL_READY; + } + + if ((Mcr & MCR_RTS) == MCR_RTS) { + *Control |= EFI_SERIAL_REQUEST_TO_SEND; + } + + // + // Read the Line Status Register. + // + Lsr = IoRead8 ((UINT16) gUartBase + LSR_OFFSET); + + if ((Lsr & LSR_TXRDY) == LSR_TXRDY) { + *Control |= EFI_SERIAL_OUTPUT_BUFFER_EMPTY; + } + + if ((Lsr & LSR_RXDA) == 0) { + *Control |= EFI_SERIAL_INPUT_BUFFER_EMPTY; + } + + return RETURN_SUCCESS; +} + +/** + Sets the baud rate, receive FIFO depth, transmit/receice time out, parity, + data bits, and stop bits on a serial device. + + @param 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 ReveiveFifoDepth 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 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 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 DataBits The number of data bits to use on the serial device. A DataBits + vaule of 0 will use the device's default data bit setting. + On output, the value actually set. + @param 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 + ) +{ + UINTN Divisor; + UINT8 OutputData; + UINT8 LcrData; + UINT8 LcrParity; + UINT8 LcrStop; + + // + // Check for default settings and fill in actual values. + // + if (*BaudRate == 0) { + *BaudRate = gBps; + } + + if (*DataBits == 0) { + *DataBits = gData; + } + + if (*Parity == DefaultParity) { + *Parity = NoParity; + } + + if (*StopBits == DefaultStopBits) { + *StopBits = OneStopBit; + } + + if ((*DataBits < 5) || (*DataBits > 8)) { + return RETURN_INVALID_PARAMETER; + } + + if ((*Parity < NoParity) || (*Parity > SpaceParity)) { + return RETURN_INVALID_PARAMETER; + } + + if ((*StopBits < OneStopBit) || (*StopBits > TwoStopBits)) { + return RETURN_INVALID_PARAMETER; + } + + // + // Map 5..8 to 0..3 + // + LcrData = (UINT8) (*DataBits - (UINT8) 5); + + switch (*Parity) { + case NoParity: + LcrParity = 0; + break; + + case EvenParity: + LcrParity = 3; + break; + + case OddParity: + LcrParity = 1; + break; + + case SpaceParity: + LcrParity = 7; + break; + + case MarkParity: + LcrParity = 5; + break; + + default: + break; + } + + switch (*StopBits) { + case OneStopBit: + LcrStop = 0; + break; + + case OneFiveStopBits: + case TwoStopBits: + LcrStop = 1; + break; + + default: + break; + } + + // + // Calculate divisor for baud generator + // + Divisor = 115200 / (UINTN) *BaudRate; + + // + // Set communications format + // + OutputData = (UINT8) ((DLAB << 7) | (gBreakSet << 6) | (LcrParity << 3) | (LcrStop << 2) | LcrData); + IoWrite8 ((UINTN) (gUartBase + LCR_OFFSET), OutputData); + + // + // Configure baud rate + // + IoWrite8 ((UINTN) (gUartBase + BAUD_HIGH_OFFSET), (UINT8) (Divisor >> 8)); + IoWrite8 ((UINTN) (gUartBase + BAUD_LOW_OFFSET), (UINT8) (Divisor & 0xff)); + + // + // Switch back to bank 0 + // + OutputData = (UINT8) ((~DLAB << 7) | (gBreakSet << 6) | (LcrParity << 3) | (LcrStop << 2) | LcrData); + IoWrite8 ((UINTN) (gUartBase + LCR_OFFSET), OutputData); + + return RETURN_SUCCESS; +} + From f840bd9cbe2c46bab903186b6b8562b2bb35eaba Mon Sep 17 00:00:00 2001 From: Star Zeng Date: Mon, 30 Nov 2015 03:17:04 +0000 Subject: [PATCH 172/525] MdeModulePkg BaseSerialPortLib16550:Implement Get(Set)Control/SetAttributes (Sync patch r18965 from main trunk.) Cc: Michael D Kinney Cc: Liming Gao Cc: Feng Tian Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Star Zeng Reviewed-by: Liming Gao Reviewed-by: Michael D Kinney git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19015 6f19259b-4bc3-4df7-8a09-765794883524 --- .../BaseSerialPortLib16550.c | 337 ++++++++++++++++++ 1 file changed, 337 insertions(+) diff --git a/MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.c b/MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.c index 5b6608d40082..f4fc31913bea 100644 --- a/MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.c +++ b/MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.c @@ -40,6 +40,7 @@ #define R_UART_LCR 3 #define B_UART_LCR_DLAB BIT7 #define R_UART_MCR 4 +#define B_UART_MCR_DTRC BIT0 #define B_UART_MCR_RTS BIT1 #define R_UART_LSR 5 #define B_UART_LSR_RXRDY BIT0 @@ -48,6 +49,8 @@ #define R_UART_MSR 6 #define B_UART_MSR_CTS BIT4 #define B_UART_MSR_DSR BIT5 +#define B_UART_MSR_RI BIT6 +#define B_UART_MSR_DCD BIT7 // // 4-byte structure for each PCI node in PcdSerialPciDeviceInfo @@ -761,3 +764,337 @@ SerialPortPoll ( return FALSE; } + +/** + Sets the control bits on a serial device. + + @param 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 + ) +{ + UINTN SerialRegisterBase; + UINT8 Mcr; + + // + // First determine the parameter is invalid. + // + if ((Control & (~(EFI_SERIAL_REQUEST_TO_SEND | EFI_SERIAL_DATA_TERMINAL_READY | + EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE))) != 0) { + return RETURN_UNSUPPORTED; + } + + SerialRegisterBase = GetSerialRegisterBase (); + if (SerialRegisterBase ==0) { + return RETURN_UNSUPPORTED; + } + + // + // Read the Modem Control Register. + // + Mcr = SerialPortReadRegister (SerialRegisterBase, R_UART_MCR); + Mcr &= (~(B_UART_MCR_DTRC | B_UART_MCR_RTS)); + + if ((Control & EFI_SERIAL_DATA_TERMINAL_READY) == EFI_SERIAL_DATA_TERMINAL_READY) { + Mcr |= B_UART_MCR_DTRC; + } + + if ((Control & EFI_SERIAL_REQUEST_TO_SEND) == EFI_SERIAL_REQUEST_TO_SEND) { + Mcr |= B_UART_MCR_RTS; + } + + // + // Write the Modem Control Register. + // + SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, Mcr); + + return RETURN_SUCCESS; +} + +/** + Retrieve the status of the control bits on a serial device. + + @param 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 + ) +{ + UINTN SerialRegisterBase; + UINT8 Msr; + UINT8 Mcr; + UINT8 Lsr; + + SerialRegisterBase = GetSerialRegisterBase (); + if (SerialRegisterBase ==0) { + return RETURN_UNSUPPORTED; + } + + *Control = 0; + + // + // Read the Modem Status Register. + // + Msr = SerialPortReadRegister (SerialRegisterBase, R_UART_MSR); + + if ((Msr & B_UART_MSR_CTS) == B_UART_MSR_CTS) { + *Control |= EFI_SERIAL_CLEAR_TO_SEND; + } + + if ((Msr & B_UART_MSR_DSR) == B_UART_MSR_DSR) { + *Control |= EFI_SERIAL_DATA_SET_READY; + } + + if ((Msr & B_UART_MSR_RI) == B_UART_MSR_RI) { + *Control |= EFI_SERIAL_RING_INDICATE; + } + + if ((Msr & B_UART_MSR_DCD) == B_UART_MSR_DCD) { + *Control |= EFI_SERIAL_CARRIER_DETECT; + } + + // + // Read the Modem Control Register. + // + Mcr = SerialPortReadRegister (SerialRegisterBase, R_UART_MCR); + + if ((Mcr & B_UART_MCR_DTRC) == B_UART_MCR_DTRC) { + *Control |= EFI_SERIAL_DATA_TERMINAL_READY; + } + + if ((Mcr & B_UART_MCR_RTS) == B_UART_MCR_RTS) { + *Control |= EFI_SERIAL_REQUEST_TO_SEND; + } + + if (PcdGetBool (PcdSerialUseHardwareFlowControl)) { + *Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE; + } + + // + // Read the Line Status Register. + // + Lsr = SerialPortReadRegister (SerialRegisterBase, R_UART_LSR); + + if ((Lsr & (B_UART_LSR_TEMT | B_UART_LSR_TXRDY)) == (B_UART_LSR_TEMT | B_UART_LSR_TXRDY)) { + *Control |= EFI_SERIAL_OUTPUT_BUFFER_EMPTY; + } + + if ((Lsr & B_UART_LSR_RXRDY) == 0) { + *Control |= EFI_SERIAL_INPUT_BUFFER_EMPTY; + } + + return RETURN_SUCCESS; +} + +/** + Sets the baud rate, receive FIFO depth, transmit/receice time out, parity, + data bits, and stop bits on a serial device. + + @param 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 ReveiveFifoDepth 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 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 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 DataBits The number of data bits to use on the serial device. A DataBits + vaule of 0 will use the device's default data bit setting. + On output, the value actually set. + @param 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 + ) +{ + UINTN SerialRegisterBase; + UINT32 SerialBaudRate; + UINTN Divisor; + UINT8 Lcr; + UINT8 LcrData; + UINT8 LcrParity; + UINT8 LcrStop; + + SerialRegisterBase = GetSerialRegisterBase (); + if (SerialRegisterBase ==0) { + return RETURN_UNSUPPORTED; + } + + // + // Check for default settings and fill in actual values. + // + if (*BaudRate == 0) { + *BaudRate = PcdGet32 (PcdSerialBaudRate); + } + SerialBaudRate = (UINT32) *BaudRate; + + if (*DataBits == 0) { + LcrData = (UINT8) (PcdGet8 (PcdSerialLineControl) & 0x3); + *DataBits = LcrData + 5; + } else { + if ((*DataBits < 5) || (*DataBits > 8)) { + return RETURN_INVALID_PARAMETER; + } + // + // Map 5..8 to 0..3 + // + LcrData = (UINT8) (*DataBits - (UINT8) 5); + } + + if (*Parity == DefaultParity) { + LcrParity = (UINT8) ((PcdGet8 (PcdSerialLineControl) >> 3) & 0x7); + switch (LcrParity) { + case 0: + *Parity = NoParity; + break; + + case 3: + *Parity = EvenParity; + break; + + case 1: + *Parity = OddParity; + break; + + case 7: + *Parity = SpaceParity; + break; + + case 5: + *Parity = MarkParity; + break; + + default: + break; + } + } else { + if ((*Parity < NoParity) || (*Parity > SpaceParity)) { + return RETURN_INVALID_PARAMETER; + } + switch (*Parity) { + case NoParity: + LcrParity = 0; + break; + + case EvenParity: + LcrParity = 3; + break; + + case OddParity: + LcrParity = 1; + break; + + case SpaceParity: + LcrParity = 7; + break; + + case MarkParity: + LcrParity = 5; + break; + + default: + break; + } + } + + if (*StopBits == DefaultStopBits) { + LcrStop = (UINT8) ((PcdGet8 (PcdSerialLineControl) >> 2) & 0x1); + switch (LcrStop) { + case 0: + *StopBits = OneStopBit; + break; + + case 1: + if (*DataBits == 5) { + *StopBits = OneFiveStopBits; + } else { + *StopBits = TwoStopBits; + } + break; + + default: + break; + } + } else { + if ((*StopBits < OneStopBit) || (*StopBits > TwoStopBits)) { + return RETURN_INVALID_PARAMETER; + } + switch (*StopBits) { + case OneStopBit: + LcrStop = 0; + break; + + case OneFiveStopBits: + case TwoStopBits: + LcrStop = 1; + break; + + default: + break; + } + } + + // + // Calculate divisor for baud generator + // Ref_Clk_Rate / Baud_Rate / 16 + // + Divisor = PcdGet32 (PcdSerialClockRate) / (SerialBaudRate * 16); + if ((PcdGet32 (PcdSerialClockRate) % (SerialBaudRate * 16)) >= SerialBaudRate * 8) { + Divisor++; + } + + // + // Configure baud rate + // + SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, B_UART_LCR_DLAB); + SerialPortWriteRegister (SerialRegisterBase, R_UART_BAUD_HIGH, (UINT8) (Divisor >> 8)); + SerialPortWriteRegister (SerialRegisterBase, R_UART_BAUD_LOW, (UINT8) (Divisor & 0xff)); + + // + // Clear DLAB and configure Data Bits, Parity, and Stop Bits. + // Strip reserved bits from line control value + // + Lcr = (UINT8) ((LcrParity << 3) | (LcrStop << 2) | LcrData); + SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, (UINT8) (Lcr & 0x3F)); + + return RETURN_SUCCESS; +} + From 6e191400ecaf98dc7cdb9750fbf9af7cbc48b15a Mon Sep 17 00:00:00 2001 From: Star Zeng Date: Mon, 30 Nov 2015 03:17:29 +0000 Subject: [PATCH 173/525] MdeModulePkg: Upstream SerialDxe from EmbeddedPkg This Serial driver layers on top of a Serial Port Library instance to produce serial IO protocol. There is also another SerialDxe implementation in CorebootPayloadPkg, but SerialDxe from EmbeddedPkg should be better that also consumes the extended interfaces GetControl/SetControl/SetAttributes in EmbeddedPkg/Include/Library/SerialPortExtLib.h for serial IO protocol. And the extended interfaces GetControl/SetControl/SetAttributes in EmbeddedPkg/Include/Library/SerialPortExtLib.h has been upstream to MdePkg/Include/Library/SerialPortLib.h. (Sync patch r18966 from main trunk.) Cc: Michael D Kinney Cc: Liming Gao Cc: Feng Tian Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Star Zeng Reviewed-by: Liming Gao Reviewed-by: Michael Kinney git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19016 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/MdeModulePkg.dsc | 2 + .../Universal/SerialDxe/SerialDxe.inf | 49 ++ .../Universal/SerialDxe/SerialDxe.uni | Bin 0 -> 1892 bytes .../Universal/SerialDxe/SerialDxeExtra.uni | Bin 0 -> 1324 bytes MdeModulePkg/Universal/SerialDxe/SerialIo.c | 526 ++++++++++++++++++ 5 files changed, 577 insertions(+) create mode 100644 MdeModulePkg/Universal/SerialDxe/SerialDxe.inf create mode 100644 MdeModulePkg/Universal/SerialDxe/SerialDxe.uni create mode 100644 MdeModulePkg/Universal/SerialDxe/SerialDxeExtra.uni create mode 100644 MdeModulePkg/Universal/SerialDxe/SerialIo.c diff --git a/MdeModulePkg/MdeModulePkg.dsc b/MdeModulePkg/MdeModulePkg.dsc index c43093260453..602b4bba818f 100644 --- a/MdeModulePkg/MdeModulePkg.dsc +++ b/MdeModulePkg/MdeModulePkg.dsc @@ -370,6 +370,8 @@ MdeModulePkg/Universal/PropertiesTableAttributesDxe/PropertiesTableAttributesDxe.inf + MdeModulePkg/Universal/SerialDxe/SerialDxe.inf + [Components.IA32, Components.X64, Components.IPF] MdeModulePkg/Universal/Network/UefiPxeBcDxe/UefiPxeBcDxe.inf MdeModulePkg/Universal/DebugSupportDxe/DebugSupportDxe.inf diff --git a/MdeModulePkg/Universal/SerialDxe/SerialDxe.inf b/MdeModulePkg/Universal/SerialDxe/SerialDxe.inf new file mode 100644 index 000000000000..145101b708df --- /dev/null +++ b/MdeModulePkg/Universal/SerialDxe/SerialDxe.inf @@ -0,0 +1,49 @@ +## @file +# Serial driver that layers on top of a Serial Port Library instance. +# +# Copyright (c) 2008 - 2015, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = SerialDxe + FILE_GUID = D3987D4B-971A-435F-8CAF-4967EB627241 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = SerialDxeInitialize + +[Sources.common] + SerialIo.c + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + UefiBootServicesTableLib + DebugLib + PcdLib + SerialPortLib + +[Protocols] + gEfiSerialIoProtocolGuid ## PRODUCES + gEfiDevicePathProtocolGuid ## PRODUCES + +[Pcd] + gEfiMdePkgTokenSpaceGuid.PcdUartDefaultBaudRate ## CONSUMES + gEfiMdePkgTokenSpaceGuid.PcdUartDefaultDataBits ## CONSUMES + gEfiMdePkgTokenSpaceGuid.PcdUartDefaultParity ## CONSUMES + gEfiMdePkgTokenSpaceGuid.PcdUartDefaultStopBits ## CONSUMES + +[Depex] + TRUE diff --git a/MdeModulePkg/Universal/SerialDxe/SerialDxe.uni b/MdeModulePkg/Universal/SerialDxe/SerialDxe.uni new file mode 100644 index 0000000000000000000000000000000000000000..9df8bea8aaae0a1f5a77571fc823eb758a43dd0e GIT binary patch literal 1892 zcmdUv-HX#u5XI+N@P7#17nR*s1wll_){Pp}P3Z@#Pm;FVZeZI=8h7nKzw7VJZIf0i z_@)waKju!(oH;W$cegETS;YH@C$iTzwcM`k!tUEWtUBwnE3jtRBb)g8+HH}Qc8R^j ze#N|Y>x$jd7K|nHH{VSeGv0lyF6V`R{So{T>x_4eU(WX{PBP{(sLhJczt8K9XT5fv zX6Pez9+1UD=BM_U=Q*pB&F+akvt!l?nU-WKjfGI4oJOgevs$1*WNpsnp?U;tsa^2h z%C%QrCV0NIj`i%-0o4XD%JGiCFTkC7j5&L0Jz-W&FML0S_0r~e>TK;*nQ=0AR&`gb zsyIRs8}&o(l~WzXsm9mWlTCzc*6O#6>Z|J_`|d1+T{Dp`1yRL%%Tmn5H?Q;weWy;_ zX3(MEPT8xw)J1_y-9b05#h6jJ``PCB3sG1>FU3+%O8XH!ck3cm#eRxCR7jkE;G?^+ z%V}Siprtx~wE2FyQ9z8!9bMH&C6##Lw^H{i-jOGO+g+!=_93r1p-nZJ*dDC>f!p<^k4({u;81UEiUdF~`^=YyqLxKB1puJo=8D zvQi&wY%mK~s14?h@3lML;dIWqP*aZ>**RW4XLg1?0aX~ONAIx{ci9wkfUkTMHF&+n zSJA&Pf8a#Sb^qc`l#oSipDUaiJwb~u-K3bO2meX>i?*D*G}U`l^~{3W=np9UzJip3 zF$67U*CzLH(nhTTe!qK;sG;t_jJjux>N<7830PvWDe|1lv%+*=l Rs$z#U_&@S*Qip8^`~=5~DT)99 literal 0 HcmV?d00001 diff --git a/MdeModulePkg/Universal/SerialDxe/SerialDxeExtra.uni b/MdeModulePkg/Universal/SerialDxe/SerialDxeExtra.uni new file mode 100644 index 0000000000000000000000000000000000000000..bfb8420d055ce7cbf6dbdd8268a9d7d99257d2ac GIT binary patch literal 1324 zcmZvcTW`}q5QXO%iT|()FM!$vkdP2Uh=v%jC{2_mDm+C_LQ_k*R89&FKOXqbtS?PL zmiIDy_RQI{WB>Wxv5p1ar#!*l*`?*SwD0!N9uU>qIkSRjM!aXY%z~ZT#%3PL?H7@` z<93c)+rqZYGh2K7J=nGFK&h>Gt3H_4uWj#p7j^|E*kjnA(7&)}Jg*oXm$T>g(vBFX zCFhc{7z#MlX6(;BW1E!|Gz%g9kz2|Nv}}0``{CN#_Qtw4w736JH$qYF=eY*Ifkio1 zuvF*UfsiK|nr9$ZDAC%Ueexm@k*dbUZJkHEq$Z#;XSY0(GWl8YYxmqS8G18tOWG-| z_T8{Us|DjqNzAo6xCJQ_GOzuS6C3Wk+1KT+d(2M{v@|#M)4iC{{(IUS4Pumr=$CSB znalerI`7_#T$TDu;_-&0`4-H5O^3cjFZZCP<^E0SfD|>=72x0TT-$4}VpUl5R`|l5 zZgcvA`{~^CeoJJE@;Nnkn7s|l6>sCn$Ua$ungP|*w~w?Z_Jw(hlL0T)kBFw!*O*b_ z{*LX8J|P~6MTW-vlzL7;oI7)$k?L4&i(b59ZP9mquG!HYO&6?-weJ~&U4R<8vNPf- ztm5c<_8~KAS4=raV1-fEi249l*}u_$W<|>N{Uv3Vc#6cn);tY+iWdW_NjZDgt~ECP z>95oAxMGj$dWqjn^lnnRJAh?apI`!aAJ#GaiA~TY=XDp6N#BTAZs-?YE4u$<@X{wt Vi&67UR)4mh*Q@>u1qk7)_b(`Z%trtK literal 0 HcmV?d00001 diff --git a/MdeModulePkg/Universal/SerialDxe/SerialIo.c b/MdeModulePkg/Universal/SerialDxe/SerialIo.c new file mode 100644 index 000000000000..de928d1719e9 --- /dev/null +++ b/MdeModulePkg/Universal/SerialDxe/SerialIo.c @@ -0,0 +1,526 @@ +/** @file + Serial driver that layers on top of a Serial Port Library instance. + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+ Copyright (c) 2013-2014, ARM Ltd. All rights reserved.
+ Copyright (c) 2015, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include + +#include +#include + +typedef struct { + VENDOR_DEVICE_PATH Guid; + UART_DEVICE_PATH Uart; + EFI_DEVICE_PATH_PROTOCOL End; +} SERIAL_DEVICE_PATH; + +/** + Reset the serial device. + + @param This Protocol instance pointer. + + @retval EFI_SUCCESS The device was reset. + @retval EFI_DEVICE_ERROR The serial device could not be reset. + +**/ +EFI_STATUS +EFIAPI +SerialReset ( + IN EFI_SERIAL_IO_PROTOCOL *This + ); + +/** + Sets the baud rate, receive FIFO depth, transmit/receive time out, parity, + data bits, and stop bits on a serial device. + + @param This Protocol instance pointer. + @param BaudRate The requested baud rate. A BaudRate value of 0 will use the the + device's default interface speed. + @param 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. + @param 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. + @param Parity The type of parity to use on this serial device. A Parity value of + DefaultParity will use the device's default parity value. + @param 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. + @param 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. + + @retval EFI_SUCCESS The device was reset. + @retval EFI_DEVICE_ERROR The serial device could not be reset. + +**/ +EFI_STATUS +EFIAPI +SerialSetAttributes ( + IN EFI_SERIAL_IO_PROTOCOL *This, + IN UINT64 BaudRate, + IN UINT32 ReceiveFifoDepth, + IN UINT32 Timeout, + IN EFI_PARITY_TYPE Parity, + IN UINT8 DataBits, + IN EFI_STOP_BITS_TYPE StopBits + ); + +/** + Set the control bits on a serial device + + @param This Protocol instance pointer. + @param Control Set the bits of Control that are settable. + + @retval EFI_SUCCESS The new control bits were set on the serial device. + @retval EFI_UNSUPPORTED The serial device does not support this operation. + @retval EFI_DEVICE_ERROR The serial device is not functioning correctly. + +**/ +EFI_STATUS +EFIAPI +SerialSetControl ( + IN EFI_SERIAL_IO_PROTOCOL *This, + IN UINT32 Control + ); + +/** + Retrieves the status of the control bits on a serial device + + @param This Protocol instance pointer. + @param Control A pointer to return the current Control signals from the serial device. + + @retval EFI_SUCCESS The control bits were read from the serial device. + @retval EFI_DEVICE_ERROR The serial device is not functioning correctly. + +**/ +EFI_STATUS +EFIAPI +SerialGetControl ( + IN EFI_SERIAL_IO_PROTOCOL *This, + OUT UINT32 *Control + ); + +/** + Writes data to a serial device. + + @param This Protocol instance pointer. + @param BufferSize On input, the size of the Buffer. On output, the amount of + data actually written. + @param Buffer The buffer of data to write + + @retval EFI_SUCCESS The data was written. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_TIMEOUT The data write was stopped due to a timeout. + +**/ +EFI_STATUS +EFIAPI +SerialWrite ( + IN EFI_SERIAL_IO_PROTOCOL *This, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + ); + +/** + Reads data from a serial device. + + @param This Protocol instance pointer. + @param BufferSize On input, the size of the Buffer. On output, the amount of + data returned in Buffer. + @param Buffer The buffer to return the data into. + + @retval EFI_SUCCESS The data was read. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_TIMEOUT The data write was stopped due to a timeout. + +**/ +EFI_STATUS +EFIAPI +SerialRead ( + IN EFI_SERIAL_IO_PROTOCOL *This, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ); + +EFI_HANDLE mSerialHandle = NULL; + +SERIAL_DEVICE_PATH mSerialDevicePath = { + { + { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, { sizeof (VENDOR_DEVICE_PATH), 0} }, + EFI_CALLER_ID_GUID // Use the driver's GUID + }, + { + { MESSAGING_DEVICE_PATH, MSG_UART_DP, { sizeof (UART_DEVICE_PATH), 0} }, + 0, // Reserved + 0, // BaudRate + 0, // DataBits + 0, // Parity + 0 // StopBits + }, + { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 } } +}; + +// +// Template used to initialize the Serial IO protocols. +// +EFI_SERIAL_IO_MODE mSerialIoMode = { + 0, // ControlMask + 0, // Timeout + 0, // BaudRate + 1, // ReceiveFifoDepth + 0, // DataBits + 0, // Parity + 0 // StopBits +}; + +EFI_SERIAL_IO_PROTOCOL mSerialIoTemplate = { + SERIAL_IO_INTERFACE_REVISION, + SerialReset, + SerialSetAttributes, + SerialSetControl, + SerialGetControl, + SerialWrite, + SerialRead, + &mSerialIoMode +}; + +/** + Reset the serial device. + + @param This Protocol instance pointer. + + @retval EFI_SUCCESS The device was reset. + @retval EFI_DEVICE_ERROR The serial device could not be reset. + +**/ +EFI_STATUS +EFIAPI +SerialReset ( + IN EFI_SERIAL_IO_PROTOCOL *This + ) +{ + EFI_STATUS Status; + EFI_TPL Tpl; + + Status = SerialPortInitialize (); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Set the Serial I/O mode and update the device path + // + + Tpl = gBS->RaiseTPL (TPL_NOTIFY); + + // + // Set the Serial I/O mode + // + This->Mode->ReceiveFifoDepth = 1; + This->Mode->Timeout = 0; + This->Mode->BaudRate = PcdGet64 (PcdUartDefaultBaudRate); + This->Mode->DataBits = (UINT32) PcdGet8 (PcdUartDefaultDataBits); + This->Mode->Parity = (UINT32) PcdGet8 (PcdUartDefaultParity); + This->Mode->StopBits = (UINT32) PcdGet8 (PcdUartDefaultStopBits); + + // + // Check if the device path has actually changed + // + if (mSerialDevicePath.Uart.BaudRate == This->Mode->BaudRate && + mSerialDevicePath.Uart.DataBits == (UINT8) This->Mode->DataBits && + mSerialDevicePath.Uart.Parity == (UINT8) This->Mode->Parity && + mSerialDevicePath.Uart.StopBits == (UINT8) This->Mode->StopBits + ) { + gBS->RestoreTPL (Tpl); + return EFI_SUCCESS; + } + + // + // Update the device path + // + mSerialDevicePath.Uart.BaudRate = This->Mode->BaudRate; + mSerialDevicePath.Uart.DataBits = (UINT8) This->Mode->DataBits; + mSerialDevicePath.Uart.Parity = (UINT8) This->Mode->Parity; + mSerialDevicePath.Uart.StopBits = (UINT8) This->Mode->StopBits; + + Status = gBS->ReinstallProtocolInterface ( + mSerialHandle, + &gEfiDevicePathProtocolGuid, + &mSerialDevicePath, + &mSerialDevicePath + ); + + gBS->RestoreTPL (Tpl); + + return Status; +} + +/** + Sets the baud rate, receive FIFO depth, transmit/receive time out, parity, + data bits, and stop bits on a serial device. + + @param This Protocol instance pointer. + @param BaudRate The requested baud rate. A BaudRate value of 0 will use the the + device's default interface speed. + @param 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. + @param 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. + @param Parity The type of parity to use on this serial device. A Parity value of + DefaultParity will use the device's default parity value. + @param 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. + @param 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. + + @retval EFI_SUCCESS The device was reset. + @retval EFI_DEVICE_ERROR The serial device could not be reset. + +**/ +EFI_STATUS +EFIAPI +SerialSetAttributes ( + IN EFI_SERIAL_IO_PROTOCOL *This, + IN UINT64 BaudRate, + IN UINT32 ReceiveFifoDepth, + IN UINT32 Timeout, + IN EFI_PARITY_TYPE Parity, + IN UINT8 DataBits, + IN EFI_STOP_BITS_TYPE StopBits + ) +{ + EFI_STATUS Status; + EFI_TPL Tpl; + + Status = SerialPortSetAttributes (&BaudRate, &ReceiveFifoDepth, &Timeout, &Parity, &DataBits, &StopBits); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Set the Serial I/O mode and update the device path + // + + Tpl = gBS->RaiseTPL (TPL_NOTIFY); + + // + // Set the Serial I/O mode + // + This->Mode->ReceiveFifoDepth = ReceiveFifoDepth; + This->Mode->Timeout = Timeout; + This->Mode->BaudRate = BaudRate; + This->Mode->DataBits = (UINT32) DataBits; + This->Mode->Parity = (UINT32) Parity; + This->Mode->StopBits = (UINT32) StopBits; + + // + // Check if the device path has actually changed + // + if (mSerialDevicePath.Uart.BaudRate == BaudRate && + mSerialDevicePath.Uart.DataBits == DataBits && + mSerialDevicePath.Uart.Parity == (UINT8) Parity && + mSerialDevicePath.Uart.StopBits == (UINT8) StopBits + ) { + gBS->RestoreTPL (Tpl); + return EFI_SUCCESS; + } + + // + // Update the device path + // + mSerialDevicePath.Uart.BaudRate = BaudRate; + mSerialDevicePath.Uart.DataBits = DataBits; + mSerialDevicePath.Uart.Parity = (UINT8) Parity; + mSerialDevicePath.Uart.StopBits = (UINT8) StopBits; + + Status = gBS->ReinstallProtocolInterface ( + mSerialHandle, + &gEfiDevicePathProtocolGuid, + &mSerialDevicePath, + &mSerialDevicePath + ); + + gBS->RestoreTPL (Tpl); + + return Status; +} + +/** + Set the control bits on a serial device + + @param This Protocol instance pointer. + @param Control Set the bits of Control that are settable. + + @retval EFI_SUCCESS The new control bits were set on the serial device. + @retval EFI_UNSUPPORTED The serial device does not support this operation. + @retval EFI_DEVICE_ERROR The serial device is not functioning correctly. + +**/ +EFI_STATUS +EFIAPI +SerialSetControl ( + IN EFI_SERIAL_IO_PROTOCOL *This, + IN UINT32 Control + ) +{ + return SerialPortSetControl (Control); +} + +/** + Retrieves the status of the control bits on a serial device + + @param This Protocol instance pointer. + @param Control A pointer to return the current Control signals from the serial device. + + @retval EFI_SUCCESS The control bits were read from the serial device. + @retval EFI_DEVICE_ERROR The serial device is not functioning correctly. + +**/ +EFI_STATUS +EFIAPI +SerialGetControl ( + IN EFI_SERIAL_IO_PROTOCOL *This, + OUT UINT32 *Control + ) +{ + return SerialPortGetControl (Control); +} + +/** + Writes data to a serial device. + + @param This Protocol instance pointer. + @param BufferSize On input, the size of the Buffer. On output, the amount of + data actually written. + @param Buffer The buffer of data to write + + @retval EFI_SUCCESS The data was written. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_TIMEOUT The data write was stopped due to a timeout. + +**/ +EFI_STATUS +EFIAPI +SerialWrite ( + IN EFI_SERIAL_IO_PROTOCOL *This, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + ) +{ + UINTN Count; + + Count = SerialPortWrite (Buffer, *BufferSize); + + if (Count != *BufferSize) { + *BufferSize = Count; + return EFI_TIMEOUT; + } + + return EFI_SUCCESS; +} + +/** + Reads data from a serial device. + + @param This Protocol instance pointer. + @param BufferSize On input, the size of the Buffer. On output, the amount of + data returned in Buffer. + @param Buffer The buffer to return the data into. + + @retval EFI_SUCCESS The data was read. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_TIMEOUT The data write was stopped due to a timeout. + +**/ +EFI_STATUS +EFIAPI +SerialRead ( + IN EFI_SERIAL_IO_PROTOCOL *This, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +{ + UINTN Count; + + Count = 0; + + if (SerialPortPoll ()) { + Count = SerialPortRead (Buffer, *BufferSize); + } + + if (Count != *BufferSize) { + *BufferSize = Count; + return EFI_TIMEOUT; + } + + return EFI_SUCCESS; +} + +/** + Initialization for the Serial Io Protocol. + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + @retval other Some error occurs when executing this entry point. + +**/ +EFI_STATUS +EFIAPI +SerialDxeInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + Status = SerialPortInitialize (); + if (EFI_ERROR (Status)) { + return Status; + } + + mSerialIoMode.BaudRate = PcdGet64 (PcdUartDefaultBaudRate); + mSerialIoMode.DataBits = (UINT32) PcdGet8 (PcdUartDefaultDataBits); + mSerialIoMode.Parity = (UINT32) PcdGet8 (PcdUartDefaultParity); + mSerialIoMode.StopBits = (UINT32) PcdGet8 (PcdUartDefaultStopBits); + mSerialDevicePath.Uart.BaudRate = PcdGet64 (PcdUartDefaultBaudRate); + mSerialDevicePath.Uart.DataBits = PcdGet8 (PcdUartDefaultDataBits); + mSerialDevicePath.Uart.Parity = PcdGet8 (PcdUartDefaultParity); + mSerialDevicePath.Uart.StopBits = PcdGet8 (PcdUartDefaultStopBits); + + // + // Make a new handle with Serial IO protocol and its device path on it. + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &mSerialHandle, + &gEfiSerialIoProtocolGuid, &mSerialIoTemplate, + &gEfiDevicePathProtocolGuid, &mSerialDevicePath, + NULL + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} + From 07b3c219af6d777984145de4d7d6faab4b40418b Mon Sep 17 00:00:00 2001 From: Star Zeng Date: Mon, 30 Nov 2015 03:17:57 +0000 Subject: [PATCH 174/525] EmulatorPkg: Use SerialDxe in MdeModulePkg instead of EmbeddedPkg It is also to add GetControl/SetControl/SetAttributes implementation for DxeEmuSerialPortLib. (Sync patch r18967 from main trunk.) Cc: Michael D Kinney Cc: Liming Gao Cc: Jordan Justen Cc: Andrew Fish Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Star Zeng Reviewed-by: Jordan Justen git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19017 6f19259b-4bc3-4df7-8a09-765794883524 --- EmulatorPkg/EmulatorPkg.dsc | 3 +- EmulatorPkg/EmulatorPkg.fdf | 2 +- .../DxeEmuSerialPortLib/DxeEmuSerialPortLib.c | 91 ++++++++++++++++++- 3 files changed, 92 insertions(+), 4 deletions(-) diff --git a/EmulatorPkg/EmulatorPkg.dsc b/EmulatorPkg/EmulatorPkg.dsc index 8eff20edae8d..27a78d55709c 100644 --- a/EmulatorPkg/EmulatorPkg.dsc +++ b/EmulatorPkg/EmulatorPkg.dsc @@ -87,7 +87,6 @@ SecurityManagementLib|MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.inf TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf SerialPortLib|MdePkg/Library/BaseSerialPortLibNull/BaseSerialPortLibNull.inf - SerialPortExtLib|EmbeddedPkg/Library/TemplateSerialPortExtLib/TemplateSerialPortExtLib.inf CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf # # Platform @@ -325,7 +324,7 @@ MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.inf - EmbeddedPkg/SerialDxe/SerialDxe.inf { + MdeModulePkg/Universal/SerialDxe/SerialDxe.inf { DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf SerialPortLib|EmulatorPkg/Library/DxeEmuSerialPortLib/DxeEmuSerialPortLib.inf diff --git a/EmulatorPkg/EmulatorPkg.fdf b/EmulatorPkg/EmulatorPkg.fdf index a0023893bb70..985a78ee2f1f 100644 --- a/EmulatorPkg/EmulatorPkg.fdf +++ b/EmulatorPkg/EmulatorPkg.fdf @@ -161,7 +161,7 @@ INF MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf INF MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf INF MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.inf -INF EmbeddedPkg/SerialDxe/SerialDxe.inf +INF MdeModulePkg/Universal/SerialDxe/SerialDxe.inf INF MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf INF MdeModulePkg/Universal/DevicePathDxe/DevicePathDxe.inf INF MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxe.inf diff --git a/EmulatorPkg/Library/DxeEmuSerialPortLib/DxeEmuSerialPortLib.c b/EmulatorPkg/Library/DxeEmuSerialPortLib/DxeEmuSerialPortLib.c index 792bd62a1c67..2bf5961bf030 100644 --- a/EmulatorPkg/Library/DxeEmuSerialPortLib/DxeEmuSerialPortLib.c +++ b/EmulatorPkg/Library/DxeEmuSerialPortLib/DxeEmuSerialPortLib.c @@ -2,7 +2,7 @@ Serial Port Lib that thunks back to Emulator services to write to StdErr. All read functions are stubed out. - Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
+ Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
Portions copyright (c) 2011, Apple Inc. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License @@ -116,3 +116,92 @@ SerialPortPoll ( return gEmuThunk->PollStdIn (); } +/** + Sets the control bits on a serial device. + + @param 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 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 + ) +{ + *Control = 0; + if (!SerialPortPoll ()) { + *Control = EFI_SERIAL_INPUT_BUFFER_EMPTY; + } + return RETURN_SUCCESS; +} + +/** + Sets the baud rate, receive FIFO depth, transmit/receice time out, parity, + data bits, and stop bits on a serial device. + + @param 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 ReveiveFifoDepth 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 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 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 DataBits The number of data bits to use on the serial device. A DataBits + vaule of 0 will use the device's default data bit setting. + On output, the value actually set. + @param 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; +} + From 051eb0c5f8c3b526af7be6cbcbf4314797d71899 Mon Sep 17 00:00:00 2001 From: Star Zeng Date: Mon, 30 Nov 2015 03:18:40 +0000 Subject: [PATCH 175/525] CorebootPayloadPkg: Use SerialDxe in MdeModulePkg 1. Update fdf and dsc to use SerialDxe in MdeModulePkg. 2. Separate the code that gets SerialRegBase and SerialRegAccessType by CbParseLib from CorebootPayloadPkg/Library/SerialPortLib to PlatformHookLib, and then leverage BaseSerialPortLib16550 in MdeModulePkg. 3. Remove CorebootPayloadPkg/SerialDxe and CorebootPayloadPkg/Library/SerialPortLib. (Sync patch r18968 from main trunk.) Cc: Michael D Kinney Cc: Liming Gao Cc: Maurice Ma Cc: Prince Agyeman Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Star Zeng Reviewed-by: Maurice Ma git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19018 6f19259b-4bc3-4df7-8a09-765794883524 --- CorebootPayloadPkg/CorebootPayloadPkg.fdf | 4 +- CorebootPayloadPkg/CorebootPayloadPkgIa32.dsc | 11 +- .../CorebootPayloadPkgIa32X64.dsc | 11 +- .../Library/PlatformBdsLib/BdsPlatform.h | 5 +- .../Library/PlatformHookLib/PlatformHookLib.c | 56 +++ .../PlatformHookLib.inf} | 36 +- .../Library/SerialPortLib/SerialPortLib.c | 316 -------------- CorebootPayloadPkg/SerialDxe/SerialDxe.inf | 55 --- CorebootPayloadPkg/SerialDxe/SerialIo.c | 392 ------------------ 9 files changed, 92 insertions(+), 794 deletions(-) create mode 100644 CorebootPayloadPkg/Library/PlatformHookLib/PlatformHookLib.c rename CorebootPayloadPkg/Library/{SerialPortLib/SerialPortLib.inf => PlatformHookLib/PlatformHookLib.inf} (54%) delete mode 100644 CorebootPayloadPkg/Library/SerialPortLib/SerialPortLib.c delete mode 100644 CorebootPayloadPkg/SerialDxe/SerialDxe.inf delete mode 100644 CorebootPayloadPkg/SerialDxe/SerialIo.c diff --git a/CorebootPayloadPkg/CorebootPayloadPkg.fdf b/CorebootPayloadPkg/CorebootPayloadPkg.fdf index 810dcb1655e6..c160e4346187 100644 --- a/CorebootPayloadPkg/CorebootPayloadPkg.fdf +++ b/CorebootPayloadPkg/CorebootPayloadPkg.fdf @@ -3,7 +3,7 @@ # # Provides drivers and definitions to create uefi payload for coreboot. # -# Copyright (c) 2014, Intel Corporation. All rights reserved.
+# Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.
# This program and the accompanying materials are licensed and made available under # the terms and conditions of the BSD License that accompanies this distribution. # The full text of the license may be found at @@ -116,7 +116,7 @@ INF DuetPkg/PciBusNoEnumerationDxe/PciBusNoEnumeration.inf # # ISA Support # -INF CorebootPayloadPkg/SerialDxe/SerialDxe.inf +INF MdeModulePkg/Universal/SerialDxe/SerialDxe.inf # # Console Support diff --git a/CorebootPayloadPkg/CorebootPayloadPkgIa32.dsc b/CorebootPayloadPkg/CorebootPayloadPkgIa32.dsc index 00a584234f2f..2c37e443fa78 100644 --- a/CorebootPayloadPkg/CorebootPayloadPkgIa32.dsc +++ b/CorebootPayloadPkg/CorebootPayloadPkgIa32.dsc @@ -3,7 +3,7 @@ # # Provides drivers and definitions to create uefi payload for coreboot. # -# Copyright (c) 2014, Intel Corporation. All rights reserved.
+# Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.
# This program and the accompanying materials are licensed and made available under # the terms and conditions of the BSD License that accompanies this distribution. # The full text of the license may be found at @@ -116,7 +116,8 @@ # TimerLib|CorebootPayloadPkg/Library/AcpiTimerLib/AcpiTimerLib.inf ResetSystemLib|CorebootPayloadPkg/Library/ResetSystemLib/ResetSystemLib.inf - SerialPortLib|CorebootPayloadPkg/Library/SerialPortLib/SerialPortLib.inf + SerialPortLib|MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.inf + PlatformHookLib|CorebootPayloadPkg/Library/PlatformHookLib/PlatformHookLib.inf PlatformBdsLib|CorebootPayloadPkg/Library/PlatformBdsLib/PlatformBdsLib.inf # @@ -214,6 +215,10 @@ gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdDebugLoadImageMethod|0x2 !endif +[PcdsPatchableInModule.common] + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialUseMmio|FALSE + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterBase|0x03F8 + ################################################################################ # # Pcd Dynamic Section - list of all EDK II PCD Entries defined by this Platform @@ -340,7 +345,7 @@ # # ISA Support # - CorebootPayloadPkg/SerialDxe/SerialDxe.inf + MdeModulePkg/Universal/SerialDxe/SerialDxe.inf # # Console Support diff --git a/CorebootPayloadPkg/CorebootPayloadPkgIa32X64.dsc b/CorebootPayloadPkg/CorebootPayloadPkgIa32X64.dsc index ecd12fbf8514..cfaf3048f8de 100644 --- a/CorebootPayloadPkg/CorebootPayloadPkgIa32X64.dsc +++ b/CorebootPayloadPkg/CorebootPayloadPkgIa32X64.dsc @@ -3,7 +3,7 @@ # # Provides drivers and definitions to create uefi payload for coreboot. # -# Copyright (c) 2014, Intel Corporation. All rights reserved.
+# Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.
# This program and the accompanying materials are licensed and made available under # the terms and conditions of the BSD License that accompanies this distribution. # The full text of the license may be found at @@ -116,7 +116,8 @@ # TimerLib|CorebootPayloadPkg/Library/AcpiTimerLib/AcpiTimerLib.inf ResetSystemLib|CorebootPayloadPkg/Library/ResetSystemLib/ResetSystemLib.inf - SerialPortLib|CorebootPayloadPkg/Library/SerialPortLib/SerialPortLib.inf + SerialPortLib|MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.inf + PlatformHookLib|CorebootPayloadPkg/Library/PlatformHookLib/PlatformHookLib.inf PlatformBdsLib|CorebootPayloadPkg/Library/PlatformBdsLib/PlatformBdsLib.inf # @@ -216,6 +217,10 @@ gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdDebugLoadImageMethod|0x2 !endif +[PcdsPatchableInModule.common] + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialUseMmio|FALSE + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterBase|0x03F8 + ################################################################################ # # Pcd Dynamic Section - list of all EDK II PCD Entries defined by this Platform @@ -342,7 +347,7 @@ # # ISA Support # - CorebootPayloadPkg/SerialDxe/SerialDxe.inf + MdeModulePkg/Universal/SerialDxe/SerialDxe.inf # # Console Support diff --git a/CorebootPayloadPkg/Library/PlatformBdsLib/BdsPlatform.h b/CorebootPayloadPkg/Library/PlatformBdsLib/BdsPlatform.h index 975a7718678e..641e1cbf01bc 100644 --- a/CorebootPayloadPkg/Library/PlatformBdsLib/BdsPlatform.h +++ b/CorebootPayloadPkg/Library/PlatformBdsLib/BdsPlatform.h @@ -1,7 +1,7 @@ /** @file Head file for BDS Platform specific code -Copyright (c) 2014, Intel Corporation. All rights reserved.
+Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -29,7 +29,6 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include -#include #include extern BDS_CONSOLE_CONNECT_ENTRY gPlatformConsole[]; @@ -94,7 +93,7 @@ extern VENDOR_DEVICE_PATH gUartDeviceVenderNode; (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8) \ } \ }, \ - EFI_SERIAL_IO_PROTOCOL_GUID \ + {0xD3987D4B, 0x971A, 0x435F, {0x8C, 0xAF, 0x49, 0x67, 0xEB, 0x62, 0x72, 0x41}} \ } #define gUart \ diff --git a/CorebootPayloadPkg/Library/PlatformHookLib/PlatformHookLib.c b/CorebootPayloadPkg/Library/PlatformHookLib/PlatformHookLib.c new file mode 100644 index 000000000000..10fd332fe546 --- /dev/null +++ b/CorebootPayloadPkg/Library/PlatformHookLib/PlatformHookLib.c @@ -0,0 +1,56 @@ +/** @file + Platform Hook Library instance for UART device upon coreboot. + + Copyright (c) 2015, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include +#include + +/** + Performs platform specific initialization required for the CPU to access + the hardware associated with a SerialPortLib instance. This function does + not intiailzie the serial port hardware itself. Instead, it initializes + hardware devices that are required for the CPU to access the serial port + hardware. This function may be called more than once. + + @retval RETURN_SUCCESS The platform specific initialization succeeded. + @retval RETURN_DEVICE_ERROR The platform specific initialization could not be completed. + +**/ +RETURN_STATUS +EFIAPI +PlatformHookSerialPortInitialize ( + VOID + ) +{ + RETURN_STATUS Status; + UINT32 SerialRegBase; + UINT32 SerialRegAccessType; + + Status = CbParseSerialInfo (&SerialRegBase, &SerialRegAccessType, NULL); + if (RETURN_ERROR (Status)) { + return Status; + } + + if (SerialRegAccessType == 2) { //MMIO + PcdSetBoolS (PcdSerialUseMmio, TRUE); + } else { //IO + PcdSetBoolS (PcdSerialUseMmio, FALSE); + } + PcdSet64S (PcdSerialRegisterBase, (UINT64) SerialRegBase); + + return RETURN_SUCCESS; +} + diff --git a/CorebootPayloadPkg/Library/SerialPortLib/SerialPortLib.inf b/CorebootPayloadPkg/Library/PlatformHookLib/PlatformHookLib.inf similarity index 54% rename from CorebootPayloadPkg/Library/SerialPortLib/SerialPortLib.inf rename to CorebootPayloadPkg/Library/PlatformHookLib/PlatformHookLib.inf index c7e48f8bc14d..e5db75fa95b0 100644 --- a/CorebootPayloadPkg/Library/SerialPortLib/SerialPortLib.inf +++ b/CorebootPayloadPkg/Library/PlatformHookLib/PlatformHookLib.inf @@ -1,12 +1,12 @@ ## @file -# SerialPortLib instance for UART device upon coreboot +# Platform Hook Library instance for UART device upon coreboot. +# +# Copyright (c) 2015, Intel Corporation. All rights reserved.
# -# Copyright (c) 2014, Intel Corporation. All rights reserved.
# This program and the accompanying materials # are licensed and made available under the terms and conditions of the BSD License -# which accompanies this distribution. The full text of the license may be found at +# which accompanies this distribution. The full text of the license may be found at # http://opensource.org/licenses/bsd-license.php -# # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. # @@ -14,29 +14,25 @@ [Defines] INF_VERSION = 0x00010005 - BASE_NAME = SerialPortLib + BASE_NAME = PlatformHookLib FILE_GUID = 40A2CBC6-CFB8-447b-A90E-198E88FD345E MODULE_TYPE = BASE VERSION_STRING = 1.0 - LIBRARY_CLASS = SerialPortLib - - CONSTRUCTOR = SerialPortInitialize - + LIBRARY_CLASS = PlatformHookLib + [Sources] - SerialPortLib.c - + PlatformHookLib.c + +[LibraryClasses] + CbParseLib + PcdLib + [Packages] MdePkg/MdePkg.dec MdeModulePkg/MdeModulePkg.dec CorebootModulePkg/CorebootModulePkg.dec -[LibraryClasses] - BaseLib - PcdLib - IoLib - CbParseLib - [Pcd] - gEfiMdeModulePkgTokenSpaceGuid.PcdSerialBaudRate - gEfiMdeModulePkgTokenSpaceGuid.PcdSerialLineControl - gEfiMdeModulePkgTokenSpaceGuid.PcdSerialFifoControl \ No newline at end of file + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialUseMmio ## PRODUCES + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterBase ## PRODUCES + diff --git a/CorebootPayloadPkg/Library/SerialPortLib/SerialPortLib.c b/CorebootPayloadPkg/Library/SerialPortLib/SerialPortLib.c deleted file mode 100644 index 0d87e62b1b06..000000000000 --- a/CorebootPayloadPkg/Library/SerialPortLib/SerialPortLib.c +++ /dev/null @@ -1,316 +0,0 @@ -/** @file - SerialPortLib instance for UART device upon coreboot - - Copyright (c) 2014, Intel Corporation. All rights reserved.
- This program and the accompanying materials - are licensed and made available under the terms and conditions of the BSD License - which accompanies this distribution. The full text of the license may be found at - http://opensource.org/licenses/bsd-license.php - - THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -#include -#include -#include -#include -#include - -// -// 16550 UART register offsets and bitfields -// -#define R_UART_RXBUF 0 -#define R_UART_TXBUF 0 -#define R_UART_BAUD_LOW 0 -#define R_UART_BAUD_HIGH 1 -#define R_UART_FCR 2 -#define B_UART_FCR_FIFOE BIT0 -#define B_UART_FCR_FIFO64 BIT5 -#define R_UART_LCR 3 -#define B_UART_LCR_DLAB BIT7 -#define R_UART_MCR 4 -#define B_UART_MCR_RTS BIT1 -#define R_UART_LSR 5 -#define B_UART_LSR_RXRDY BIT0 -#define B_UART_LSR_TXRDY BIT5 -#define B_UART_LSR_TEMT BIT6 -#define R_UART_MSR 6 -#define B_UART_MSR_CTS BIT4 -#define B_UART_MSR_DSR BIT5 - -UINT32 mSerialRegBase = 0; -UINT32 mSerialRegAccessType = 0; - -/** - Read an 8-bit 16550 register. If PcdSerialUseMmio is TRUE, then the value is read from - MMIO space. If PcdSerialUseMmio is FALSE, then the value is read from I/O space. The - parameter Offset is added to the base address of the 16550 registers that is specified - by PcdSerialRegisterBase. - - @param Offset The offset of the 16550 register to read. - - @return The value read from the 16550 register. - -**/ -UINT8 -SerialPortReadRegister ( - UINTN Offset - ) -{ - if (mSerialRegAccessType == 2) { //MMIO - return MmioRead8 (mSerialRegBase + Offset); - } else { //IO - return IoRead8 ((UINT16)mSerialRegBase + Offset); - } -} - -/** - Write an 8-bit 16550 register. If PcdSerialUseMmio is TRUE, then the value is written to - MMIO space. If PcdSerialUseMmio is FALSE, then the value is written to I/O space. The - parameter Offset is added to the base address of the 16550 registers that is specified - by PcdSerialRegisterBase. - - @param Offset The offset of the 16550 register to write. - @param Value The value to write to the 16550 register specified by Offset. - - @return The value written to the 16550 register. - -**/ -UINT8 -SerialPortWriteRegister ( - UINTN Offset, - UINT8 Value - ) -{ - if (mSerialRegAccessType == 2) { //MMIO - return MmioWrite8 (mSerialRegBase + Offset, Value); - } else {// IO - return IoWrite8 ((UINT16)mSerialRegBase + Offset, Value); - } -} - -/** - 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 - ) -{ - RETURN_STATUS Status; - UINTN Divisor; - BOOLEAN Initialized; - - Status = CbParseSerialInfo (&mSerialRegBase, &mSerialRegAccessType, NULL); - if (RETURN_ERROR (Status)) { - return Status; - } - - // - // See if the serial port is already initialized - // - Initialized = TRUE; - if ((SerialPortReadRegister (R_UART_FCR) & (B_UART_FCR_FIFOE | B_UART_FCR_FIFO64)) != - (PcdGet8 (PcdSerialFifoControl) & (B_UART_FCR_FIFOE | B_UART_FCR_FIFO64)) ) { - Initialized = FALSE; - } - - if ((SerialPortReadRegister (R_UART_LCR) & 0x3F) != (PcdGet8 (PcdSerialLineControl) & 0x3F)) { - Initialized = FALSE; - } - SerialPortWriteRegister (R_UART_LCR, (UINT8)(SerialPortReadRegister (R_UART_LCR) | B_UART_LCR_DLAB)); - Divisor = SerialPortReadRegister (R_UART_BAUD_HIGH) << 8; - Divisor |= SerialPortReadRegister (R_UART_BAUD_LOW); - SerialPortWriteRegister (R_UART_LCR, (UINT8)(SerialPortReadRegister (R_UART_LCR) & ~B_UART_LCR_DLAB)); - if (Divisor != 115200 / PcdGet32 (PcdSerialBaudRate)) { - Initialized = FALSE; - } - if (Initialized) { - return RETURN_SUCCESS; - } - - // - // Configure baud rate - // - Divisor = 115200 / PcdGet32 (PcdSerialBaudRate); - SerialPortWriteRegister (R_UART_LCR, B_UART_LCR_DLAB); - SerialPortWriteRegister (R_UART_BAUD_HIGH, (UINT8) (Divisor >> 8)); - SerialPortWriteRegister (R_UART_BAUD_LOW, (UINT8) (Divisor & 0xff)); - - // - // Clear DLAB and configure Data Bits, Parity, and Stop Bits. - // Strip reserved bits from PcdSerialLineControl - // - SerialPortWriteRegister (R_UART_LCR, (UINT8)(PcdGet8 (PcdSerialLineControl) & 0x3F)); - - // - // Enable and reset FIFOs - // Strip reserved bits from PcdSerialFifoControl - // - SerialPortWriteRegister (R_UART_FCR, (UINT8)(PcdGet8 (PcdSerialFifoControl) & 0x27)); - - // - // Put Modem Control Register(MCR) into its reset state of 0x00. - // - SerialPortWriteRegister (R_UART_MCR, 0x00); - - return RETURN_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 Buffer Pointer to the data buffer to be written. - @param NumberOfBytes 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 Result; - UINTN Index; - UINTN FifoSize; - - if (Buffer == NULL) { - return 0; - } - - if (NumberOfBytes == 0) { - // - // Flush the hardware - // - - // - // Wait for both the transmit FIFO and shift register empty. - // - while ((SerialPortReadRegister (R_UART_LSR) & B_UART_LSR_TEMT) == 0); - - return 0; - } - - // - // Compute the maximum size of the Tx FIFO - // - FifoSize = 1; - if ((PcdGet8 (PcdSerialFifoControl) & B_UART_FCR_FIFOE) != 0) { - if ((PcdGet8 (PcdSerialFifoControl) & B_UART_FCR_FIFO64) == 0) { - FifoSize = 16; - } else { - FifoSize = 64; - } - } - - Result = NumberOfBytes; - while (NumberOfBytes != 0) { - // - // Wait for the serial port to be ready, to make sure both the transmit FIFO - // and shift register empty. - // - while ((SerialPortReadRegister (R_UART_LSR) & B_UART_LSR_TEMT) == 0); - - // - // Fill then entire Tx FIFO - // - for (Index = 0; Index < FifoSize && NumberOfBytes != 0; Index++, NumberOfBytes--, Buffer++) { - - // - // Write byte to the transmit buffer. - // - SerialPortWriteRegister (R_UART_TXBUF, *Buffer); - } - } - return Result; -} - -/** - Reads data from a serial device into a buffer. - - @param Buffer Pointer to the data buffer to store the data read from the serial device. - @param NumberOfBytes Number of bytes to read from the serial device. - - @retval 0 NumberOfBytes is 0. - @retval >0 The number of bytes read from the serial device. - If this value is less than NumberOfBytes, then the read operation failed. - -**/ -UINTN -EFIAPI -SerialPortRead ( - OUT UINT8 *Buffer, - IN UINTN NumberOfBytes -) -{ - UINTN Result; - - if (NULL == Buffer) { - return 0; - } - - for (Result = 0; NumberOfBytes-- != 0; Result++, Buffer++) { - // - // Wait for the serial port to have some data. - // - while ((SerialPortReadRegister (R_UART_LSR) & B_UART_LSR_RXRDY) == 0); - - // - // Read byte from the receive buffer. - // - *Buffer = SerialPortReadRegister (R_UART_RXBUF); - } - - return Result; -} - -/** - Polls a serial device to see if there is any data waiting to be read. - - Polls aserial 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 - ) -{ - // - // Read the serial port status - // - if ((SerialPortReadRegister (R_UART_LSR) & B_UART_LSR_RXRDY) != 0) { - return TRUE; - } - - return FALSE; -} diff --git a/CorebootPayloadPkg/SerialDxe/SerialDxe.inf b/CorebootPayloadPkg/SerialDxe/SerialDxe.inf deleted file mode 100644 index 04d993534e93..000000000000 --- a/CorebootPayloadPkg/SerialDxe/SerialDxe.inf +++ /dev/null @@ -1,55 +0,0 @@ -#/** @file -# -# Convert SerialLib into SerialIo protocol -# -# Copyright (c) 2008 - 2014, Intel Corporation. All rights reserved.
-# This program and the accompanying materials -# are licensed and made available under the terms and conditions of the BSD License -# which accompanies this distribution. The full text of the license may be found at -# http://opensource.org/licenses/bsd-license.php -# -# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -# -#**/ - -[Defines] - INF_VERSION = 0x00010005 - BASE_NAME = SerialDxe - FILE_GUID = D3987D4B-971A-435F-8CAF-4967EB627241 - MODULE_TYPE = DXE_DRIVER - VERSION_STRING = 1.0 - - ENTRY_POINT = SerialDxeInitialize - -[Sources.common] - SerialIo.c - -[Packages] - MdePkg/MdePkg.dec - MdeModulePkg/MdeModulePkg.dec - -[LibraryClasses] - BaseLib - ReportStatusCodeLib - MemoryAllocationLib - UefiLib - UefiBootServicesTableLib - BaseMemoryLib - DebugLib - UefiDriverEntryPoint - SerialPortLib - - -[Protocols] - gEfiSerialIoProtocolGuid - gEfiDevicePathProtocolGuid - -[FixedPcd] - gEfiMdePkgTokenSpaceGuid.PcdUartDefaultBaudRate - gEfiMdePkgTokenSpaceGuid.PcdUartDefaultDataBits - gEfiMdePkgTokenSpaceGuid.PcdUartDefaultParity - gEfiMdePkgTokenSpaceGuid.PcdUartDefaultStopBits - -[Depex] - TRUE diff --git a/CorebootPayloadPkg/SerialDxe/SerialIo.c b/CorebootPayloadPkg/SerialDxe/SerialIo.c deleted file mode 100644 index cdede321669d..000000000000 --- a/CorebootPayloadPkg/SerialDxe/SerialIo.c +++ /dev/null @@ -1,392 +0,0 @@ -/** @file - Serial IO Abstraction for GDB stub. This allows an EFI consoles that shows up on the system - running GDB. One console for error information and another console for user input/output. - - Basic packet format is $packet-data#checksum. So every command has 4 bytes of overhead: $, - #, 0, 0. The 0 and 0 are the ascii characters for the checksum. - - - Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
- Copyright (c) 2013, ARM Ltd. All rights reserved.
- Copyright (c) 2014, Intel Corporation. All rights reserved.
- - This program and the accompanying materials - are licensed and made available under the terms and conditions of the BSD License - which accompanies this distribution. The full text of the license may be found at - http://opensource.org/licenses/bsd-license.php - - THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -#include -#include -#include -#include -#include -#include - -#include - -typedef struct { - VENDOR_DEVICE_PATH Guid; - UART_DEVICE_PATH Uart; - EFI_DEVICE_PATH_PROTOCOL End; -} SIMPLE_TEXT_OUT_DEVICE_PATH; - -SIMPLE_TEXT_OUT_DEVICE_PATH mDevicePath = { - { - { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, { sizeof (VENDOR_DEVICE_PATH), 0} }, - EFI_SERIAL_IO_PROTOCOL_GUID // Use the drivers GUID - }, - { - { MESSAGING_DEVICE_PATH, MSG_UART_DP, { sizeof (UART_DEVICE_PATH), 0} }, - 0, // Reserved - FixedPcdGet64 (PcdUartDefaultBaudRate), // BaudRate - FixedPcdGet8 (PcdUartDefaultDataBits), // DataBits - FixedPcdGet8 (PcdUartDefaultParity), // Parity (N) - FixedPcdGet8 (PcdUartDefaultStopBits) // StopBits - }, - { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 } } -}; - -EFI_HANDLE gHandle = NULL; - -/** - Reset the serial device. - - @param This Protocol instance pointer. - - @retval EFI_SUCCESS The device was reset. - @retval EFI_DEVICE_ERROR The serial device could not be reset. - -**/ -EFI_STATUS -EFIAPI -SerialReset ( - IN EFI_SERIAL_IO_PROTOCOL *This - ) -{ - EFI_STATUS Status; - EFI_TPL Tpl; - - Status = SerialPortInitialize (); - if (EFI_ERROR(Status)) { - return Status; - } - - // - // Set the Serial I/O mode and update the device path - // - - Tpl = gBS->RaiseTPL (TPL_NOTIFY); - - // - // Set the Serial I/O mode - // - This->Mode->ReceiveFifoDepth = 0; - This->Mode->Timeout = 1000000; - This->Mode->BaudRate = PcdGet64 (PcdUartDefaultBaudRate); - This->Mode->DataBits = (UINT32)PcdGet8 (PcdUartDefaultDataBits); - This->Mode->Parity = (UINT32)PcdGet8 (PcdUartDefaultParity); - This->Mode->StopBits = (UINT32)PcdGet8 (PcdUartDefaultStopBits); - - // - // Check if the device path has actually changed - // - if (mDevicePath.Uart.BaudRate == This->Mode->BaudRate && - mDevicePath.Uart.DataBits == (UINT8)This->Mode->DataBits && - mDevicePath.Uart.Parity == (UINT8)This->Mode->Parity && - mDevicePath.Uart.StopBits == (UINT8)This->Mode->StopBits - ) { - gBS->RestoreTPL (Tpl); - return EFI_SUCCESS; - } - - // - // Update the device path - // - mDevicePath.Uart.BaudRate = This->Mode->BaudRate; - mDevicePath.Uart.DataBits = (UINT8)This->Mode->DataBits; - mDevicePath.Uart.Parity = (UINT8)This->Mode->Parity; - mDevicePath.Uart.StopBits = (UINT8)This->Mode->StopBits; - - Status = gBS->ReinstallProtocolInterface ( - gHandle, - &gEfiDevicePathProtocolGuid, - &mDevicePath, - &mDevicePath - ); - - gBS->RestoreTPL (Tpl); - - return Status; -} - - -/** - Sets the baud rate, receive FIFO depth, transmit/receive time out, parity, - data buts, and stop bits on a serial device. - - @param This Protocol instance pointer. - @param BaudRate The requested baud rate. A BaudRate value of 0 will use the the - device's default interface speed. - @param 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. - @param 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. - @param Parity The type of parity to use on this serial device. A Parity value of - DefaultParity will use the device's default parity value. - @param 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. - @param 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. - - @retval EFI_SUCCESS The device was reset. - @retval EFI_DEVICE_ERROR The serial device could not be reset. - -**/ -EFI_STATUS -EFIAPI -SerialSetAttributes ( - IN EFI_SERIAL_IO_PROTOCOL *This, - IN UINT64 BaudRate, - IN UINT32 ReceiveFifoDepth, - IN UINT32 Timeout, - IN EFI_PARITY_TYPE Parity, - IN UINT8 DataBits, - IN EFI_STOP_BITS_TYPE StopBits - ) -{ - EFI_STATUS Status; - EFI_TPL Tpl; - - // - // Set the Serial I/O mode and update the device path - // - - Tpl = gBS->RaiseTPL (TPL_NOTIFY); - - // - // Set the Serial I/O mode - // - This->Mode->BaudRate = BaudRate; - This->Mode->ReceiveFifoDepth = ReceiveFifoDepth; - This->Mode->Timeout = Timeout; - This->Mode->Parity = (UINT32)Parity; - This->Mode->DataBits = (UINT32)DataBits; - This->Mode->StopBits = (UINT32)StopBits; - - // - // Check if the device path has actually changed - // - if (mDevicePath.Uart.BaudRate == BaudRate && - mDevicePath.Uart.Parity == (UINT8)Parity && - mDevicePath.Uart.DataBits == DataBits && - mDevicePath.Uart.StopBits == (UINT8)StopBits - ) { - gBS->RestoreTPL (Tpl); - return EFI_SUCCESS; - } - - // - // Update the device path - // - mDevicePath.Uart.BaudRate = BaudRate; - mDevicePath.Uart.DataBits = DataBits; - mDevicePath.Uart.Parity = (UINT8) Parity; - mDevicePath.Uart.StopBits = (UINT8) StopBits; - - Status = gBS->ReinstallProtocolInterface ( - gHandle, - &gEfiDevicePathProtocolGuid, - &mDevicePath, - &mDevicePath - ); - - gBS->RestoreTPL (Tpl); - - return Status; -} - - -/** - Set the control bits on a serial device - - @param This Protocol instance pointer. - @param Control Set the bits of Control that are settable. - - @retval EFI_SUCCESS The new control bits were set on the serial device. - @retval EFI_UNSUPPORTED The serial device does not support this operation. - @retval EFI_DEVICE_ERROR The serial device is not functioning correctly. - -**/ -EFI_STATUS -EFIAPI -SerialSetControl ( - IN EFI_SERIAL_IO_PROTOCOL *This, - IN UINT32 Control - ) -{ - return EFI_UNSUPPORTED; -} - - -/** - Retrieves the status of the control bits on a serial device - - @param This Protocol instance pointer. - @param Control A pointer to return the current Control signals from the serial device. - - @retval EFI_SUCCESS The control bits were read from the serial device. - @retval EFI_DEVICE_ERROR The serial device is not functioning correctly. - -**/ -EFI_STATUS -EFIAPI -SerialGetControl ( - IN EFI_SERIAL_IO_PROTOCOL *This, - OUT UINT32 *Control - ) -{ - if (SerialPortPoll ()) { - // If a character is pending don't set EFI_SERIAL_INPUT_BUFFER_EMPTY - *Control = EFI_SERIAL_OUTPUT_BUFFER_EMPTY; - } else { - *Control = EFI_SERIAL_INPUT_BUFFER_EMPTY | EFI_SERIAL_OUTPUT_BUFFER_EMPTY; - } - return EFI_SUCCESS; -} - - -/** - Writes data to a serial device. - - @param This Protocol instance pointer. - @param BufferSize On input, the size of the Buffer. On output, the amount of - data actually written. - @param Buffer The buffer of data to write - - @retval EFI_SUCCESS The data was written. - @retval EFI_DEVICE_ERROR The device reported an error. - @retval EFI_TIMEOUT The data write was stopped due to a timeout. - -**/ -EFI_STATUS -EFIAPI -SerialWrite ( - IN EFI_SERIAL_IO_PROTOCOL *This, - IN OUT UINTN *BufferSize, - IN VOID *Buffer - ) -{ - UINTN Count; - - Count = SerialPortWrite (Buffer, *BufferSize); - - if (Count != *BufferSize) { - *BufferSize = Count; - return EFI_TIMEOUT; - } - - return EFI_SUCCESS; -} - -/** - Reads data from a serial device. - - @param This Protocol instance pointer. - @param BufferSize On input, the size of the Buffer. On output, the amount of - data returned in Buffer. - @param Buffer The buffer to return the data into. - - @retval EFI_SUCCESS The data was read. - @retval EFI_DEVICE_ERROR The device reported an error. - @retval EFI_TIMEOUT The data write was stopped due to a timeout. - -**/ - -EFI_STATUS -EFIAPI -SerialRead ( - IN EFI_SERIAL_IO_PROTOCOL *This, - IN OUT UINTN *BufferSize, - OUT VOID *Buffer - ) -{ - UINTN Count = 0; - - if (SerialPortPoll()) { - Count = SerialPortRead (Buffer, *BufferSize); - } - - if (Count != *BufferSize) { - *BufferSize = Count; - return EFI_TIMEOUT; - } - - return EFI_SUCCESS; -} - -// -// Template used to initialize the GDB Serial IO protocols -// -EFI_SERIAL_IO_MODE gSerialIoMode = { - 0, // ControlMask - 0, // Timeout - FixedPcdGet64 (PcdUartDefaultBaudRate), // BaudRate - 1, // ReceiveFifoDepth - FixedPcdGet8 (PcdUartDefaultDataBits), // DataBits - FixedPcdGet8 (PcdUartDefaultParity), // Parity - FixedPcdGet8 (PcdUartDefaultStopBits) // StopBits -}; - - -EFI_SERIAL_IO_PROTOCOL gSerialIoTemplate = { - SERIAL_IO_INTERFACE_REVISION, - SerialReset, - SerialSetAttributes, - SerialSetControl, - SerialGetControl, - SerialWrite, - SerialRead, - &gSerialIoMode -}; - -/** - Initialize the state information for the Serial Io Protocol - - @param ImageHandle of the loaded driver - @param SystemTable Pointer to the System Table - - @retval EFI_SUCCESS Protocol registered - @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure - @retval EFI_DEVICE_ERROR Hardware problems - -**/ -EFI_STATUS -EFIAPI -SerialDxeInitialize ( - IN EFI_HANDLE ImageHandle, - IN EFI_SYSTEM_TABLE *SystemTable - ) -{ - EFI_STATUS Status; - - // Make a new handle with Serial IO protocol and its device path on it. - Status = gBS->InstallMultipleProtocolInterfaces ( - &gHandle, - &gEfiSerialIoProtocolGuid, &gSerialIoTemplate, - &gEfiDevicePathProtocolGuid, &mDevicePath, - NULL - ); - ASSERT_EFI_ERROR (Status); - - return Status; -} - From 39760729116b476ecc2366ae6bfc349f6b23580e Mon Sep 17 00:00:00 2001 From: Star Zeng Date: Mon, 30 Nov 2015 03:19:06 +0000 Subject: [PATCH 176/525] Omap35xxPkg SerialPortLib: Implement Get(Set)Control/SetAttributes (Sync patch r18969 from main trunk.) Cc: Michael D Kinney Cc: Liming Gao Cc: Leif Lindholm Cc: Ard Biesheuvel Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Star Zeng Reviewed-by: Ard Biesheuvel git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19019 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Library/SerialPortLib/SerialPortLib.c | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/Omap35xxPkg/Library/SerialPortLib/SerialPortLib.c b/Omap35xxPkg/Library/SerialPortLib/SerialPortLib.c index 58f70d5512fb..7ac12c729f57 100644 --- a/Omap35xxPkg/Library/SerialPortLib/SerialPortLib.c +++ b/Omap35xxPkg/Library/SerialPortLib/SerialPortLib.c @@ -3,6 +3,7 @@ Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+ Copyright (c) 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License @@ -122,3 +123,92 @@ SerialPortPoll ( } } +/** + 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 + ) +{ + *Control = 0; + if (!SerialPortPoll ()) { + *Control = EFI_SERIAL_INPUT_BUFFER_EMPTY; + } + return RETURN_SUCCESS; +} + +/** + Sets the baud rate, receive FIFO depth, transmit/receice time out, parity, + data bits, and stop bits on a serial device. + + @param 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 ReveiveFifoDepth 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 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 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 DataBits The number of data bits to use on the serial device. A DataBits + vaule of 0 will use the device's default data bit setting. + On output, the value actually set. + @param 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; +} + From ca38bc2a80ade6ae190c40ccd26668b834673ccc Mon Sep 17 00:00:00 2001 From: Star Zeng Date: Mon, 30 Nov 2015 03:19:26 +0000 Subject: [PATCH 177/525] BeagleBoardPkg: Use SerialDxe in MdeModulePkg instead of EmbeddedPkg It is also to remove the reference to TemplateSerialPortExtLib in EmbeddedPkg. (Sync patch r18970 from main trunk.) Cc: Michael D Kinney Cc: Liming Gao Cc: Leif Lindholm Cc: Ard Biesheuvel Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Star Zeng Reviewed-by: Ard Biesheuvel git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19020 6f19259b-4bc3-4df7-8a09-765794883524 --- BeagleBoardPkg/BeagleBoardPkg.dsc | 4 ++-- BeagleBoardPkg/BeagleBoardPkg.fdf | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/BeagleBoardPkg/BeagleBoardPkg.dsc b/BeagleBoardPkg/BeagleBoardPkg.dsc index 533849228aad..b90576ee76d3 100644 --- a/BeagleBoardPkg/BeagleBoardPkg.dsc +++ b/BeagleBoardPkg/BeagleBoardPkg.dsc @@ -2,6 +2,7 @@ # Beagle board package. # # Copyright (c) 2009 - 2010, Apple Inc. All rights reserved.
+# Copyright (c) 2015, Intel Corporation. All rights reserved.
# # This program and the accompanying materials # are licensed and made available under the terms and conditions of the BSD License @@ -87,7 +88,6 @@ PrePiLib|EmbeddedPkg/Library/PrePiLib/PrePiLib.inf SerialPortLib|Omap35xxPkg/Library/SerialPortLib/SerialPortLib.inf - SerialPortExtLib|EmbeddedPkg/Library/TemplateSerialPortExtLib/TemplateSerialPortExtLib.inf SemihostLib|ArmPkg/Library/SemihostLib/SemihostLib.inf RealTimeClockLib|Omap35xxPkg/Library/RealTimeClockLib/RealTimeClockLib.inf @@ -401,7 +401,7 @@ MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.inf - EmbeddedPkg/SerialDxe/SerialDxe.inf + MdeModulePkg/Universal/SerialDxe/SerialDxe.inf MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf # # This version uses semi-hosting console diff --git a/BeagleBoardPkg/BeagleBoardPkg.fdf b/BeagleBoardPkg/BeagleBoardPkg.fdf index fb1dc26de349..b17ad7d0248e 100644 --- a/BeagleBoardPkg/BeagleBoardPkg.fdf +++ b/BeagleBoardPkg/BeagleBoardPkg.fdf @@ -1,6 +1,7 @@ # FLASH layout file for Beagle board. # # Copyright (c) 2009, Apple Inc. All rights reserved.
+# Copyright (c) 2015, Intel Corporation. All rights reserved.
# # This program and the accompanying materials # are licensed and made available under the terms and conditions of the BSD License @@ -110,7 +111,7 @@ FvNameGuid = d0dd3e90-343d-4cb3-8f69-772214989282 INF MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf INF MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf INF MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.inf - INF EmbeddedPkg/SerialDxe/SerialDxe.inf + INF MdeModulePkg/Universal/SerialDxe/SerialDxe.inf INF MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf INF EmbeddedPkg/ResetRuntimeDxe/ResetRuntimeDxe.inf From 9b3a440fdb13a3d6a9328ae2e89ffcb4e2804d16 Mon Sep 17 00:00:00 2001 From: Star Zeng Date: Mon, 30 Nov 2015 03:20:15 +0000 Subject: [PATCH 178/525] ArmPlatformPkg: Use SerialDxe in MdeModulePkg instead of EmbeddedPkg It is also to integrate PL011SerialPortExtLib to PL011SerialPortLib. (Sync patch r18971 from main trunk.) Cc: Michael D Kinney Cc: Liming Gao Cc: Leif Lindholm Cc: Ard Biesheuvel Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Star Zeng Reviewed-by: Ard Biesheuvel git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19021 6f19259b-4bc3-4df7-8a09-765794883524 --- ArmPlatformPkg/ArmJunoPkg/ArmJuno.dsc | 3 +- ArmPlatformPkg/ArmJunoPkg/ArmJuno.fdf | 3 +- .../ArmVExpressPkg/ArmVExpress-CTA15-A7.dsc | 3 +- .../ArmVExpressPkg/ArmVExpress-CTA15-A7.fdf | 3 +- .../ArmVExpress-FVP-AArch64.dsc | 3 +- .../ArmVExpress-FVP-AArch64.fdf | 3 +- .../ArmVExpress-RTSM-A15_MPCore.dsc | 3 +- .../ArmVExpress-RTSM-A15_MPCore.fdf | 3 +- .../ArmVExpressPkg/ArmVExpress.dsc.inc | 1 - .../PL011SerialPortExtLib.c | 137 ------------------ .../PL011SerialPortExtLib.inf | 43 ------ .../PL011SerialPortLib/PL011SerialPortLib.c | 117 ++++++++++++++- 12 files changed, 131 insertions(+), 191 deletions(-) delete mode 100644 ArmPlatformPkg/Library/PL011SerialPortLib/PL011SerialPortExtLib.c delete mode 100644 ArmPlatformPkg/Library/PL011SerialPortLib/PL011SerialPortExtLib.inf diff --git a/ArmPlatformPkg/ArmJunoPkg/ArmJuno.dsc b/ArmPlatformPkg/ArmJunoPkg/ArmJuno.dsc index f5af4267fee6..ba838c706361 100644 --- a/ArmPlatformPkg/ArmJunoPkg/ArmJuno.dsc +++ b/ArmPlatformPkg/ArmJunoPkg/ArmJuno.dsc @@ -1,5 +1,6 @@ # # Copyright (c) 2013-2015, ARM Limited. All rights reserved. +# Copyright (c) 2015, Intel Corporation. All rights reserved.
# # This program and the accompanying materials # are licensed and made available under the terms and conditions of the BSD License @@ -218,7 +219,7 @@ MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.inf MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf - EmbeddedPkg/SerialDxe/SerialDxe.inf + MdeModulePkg/Universal/SerialDxe/SerialDxe.inf MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf { diff --git a/ArmPlatformPkg/ArmJunoPkg/ArmJuno.fdf b/ArmPlatformPkg/ArmJunoPkg/ArmJuno.fdf index c8f5831093a7..51b1180e7a47 100644 --- a/ArmPlatformPkg/ArmJunoPkg/ArmJuno.fdf +++ b/ArmPlatformPkg/ArmJunoPkg/ArmJuno.fdf @@ -1,5 +1,6 @@ # # Copyright (c) 2013-2015, ARM Limited. All rights reserved. +# Copyright (c) 2015, Intel Corporation. All rights reserved.
# # This program and the accompanying materials # are licensed and made available under the terms and conditions of the BSD License @@ -123,7 +124,7 @@ FvNameGuid = B73FE497-B92E-416e-8326-45AD0D270092 INF MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf INF MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.inf INF MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf - INF EmbeddedPkg/SerialDxe/SerialDxe.inf + INF MdeModulePkg/Universal/SerialDxe/SerialDxe.inf INF ArmPkg/Drivers/ArmGic/ArmGicDxe.inf INF ArmPkg/Drivers/TimerDxe/TimerDxe.inf diff --git a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA15-A7.dsc b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA15-A7.dsc index c76d729a0d88..5503bbc30002 100644 --- a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA15-A7.dsc +++ b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA15-A7.dsc @@ -1,5 +1,6 @@ # # Copyright (c) 2012-2015, ARM Limited. All rights reserved. +# Copyright (c) 2015, Intel Corporation. All rights reserved.
# # This program and the accompanying materials # are licensed and made available under the terms and conditions of the BSD License @@ -247,7 +248,7 @@ MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.inf MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf - EmbeddedPkg/SerialDxe/SerialDxe.inf + MdeModulePkg/Universal/SerialDxe/SerialDxe.inf MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf diff --git a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA15-A7.fdf b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA15-A7.fdf index 576b3408e008..5f4f5aaf4998 100644 --- a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA15-A7.fdf +++ b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA15-A7.fdf @@ -1,5 +1,6 @@ # # Copyright (c) 2012-2015, ARM Limited. All rights reserved. +# Copyright (c) 2015, Intel Corporation. All rights reserved.
# # This program and the accompanying materials # are licensed and made available under the terms and conditions of the BSD License @@ -91,7 +92,7 @@ FvNameGuid = 73dcb643-3862-4904-9076-a94af1890243 INF MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf INF MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.inf INF MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf - INF EmbeddedPkg/SerialDxe/SerialDxe.inf + INF MdeModulePkg/Universal/SerialDxe/SerialDxe.inf INF ArmPkg/Drivers/ArmGic/ArmGicDxe.inf INF ArmPkg/Drivers/TimerDxe/TimerDxe.inf diff --git a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-FVP-AArch64.dsc b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-FVP-AArch64.dsc index 3f363064b23f..5751167549b8 100644 --- a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-FVP-AArch64.dsc +++ b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-FVP-AArch64.dsc @@ -1,5 +1,6 @@ # # Copyright (c) 2011-2015, ARM Limited. All rights reserved. +# Copyright (c) 2015, Intel Corporation. All rights reserved.
# # This program and the accompanying materials # are licensed and made available under the terms and conditions of the BSD License @@ -267,7 +268,7 @@ MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.inf MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf - EmbeddedPkg/SerialDxe/SerialDxe.inf + MdeModulePkg/Universal/SerialDxe/SerialDxe.inf MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf diff --git a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-FVP-AArch64.fdf b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-FVP-AArch64.fdf index 1d92d6f34832..d527da0738ca 100644 --- a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-FVP-AArch64.fdf +++ b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-FVP-AArch64.fdf @@ -1,5 +1,6 @@ # # Copyright (c) 2011 - 2015, ARM Limited. All rights reserved. +# Copyright (c) 2015, Intel Corporation. All rights reserved.
# # This program and the accompanying materials # are licensed and made available under the terms and conditions of the BSD License @@ -155,7 +156,7 @@ FvNameGuid = 87940482-fc81-41c3-87e6-399cf85ac8a0 INF MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf INF MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.inf INF MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf - INF EmbeddedPkg/SerialDxe/SerialDxe.inf + INF MdeModulePkg/Universal/SerialDxe/SerialDxe.inf INF ArmPkg/Drivers/ArmGic/ArmGicDxe.inf INF ArmPkg/Drivers/TimerDxe/TimerDxe.inf diff --git a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A15_MPCore.dsc b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A15_MPCore.dsc index 72103e26568c..a8e326902e11 100644 --- a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A15_MPCore.dsc +++ b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A15_MPCore.dsc @@ -1,5 +1,6 @@ # # Copyright (c) 2011-2015, ARM Limited. All rights reserved. +# Copyright (c) 2015, Intel Corporation. All rights reserved.
# # This program and the accompanying materials # are licensed and made available under the terms and conditions of the BSD License @@ -259,7 +260,7 @@ MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.inf MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf - EmbeddedPkg/SerialDxe/SerialDxe.inf + MdeModulePkg/Universal/SerialDxe/SerialDxe.inf MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf diff --git a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A15_MPCore.fdf b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A15_MPCore.fdf index b65dd9d533a8..ee50af2115d5 100644 --- a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A15_MPCore.fdf +++ b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A15_MPCore.fdf @@ -1,5 +1,6 @@ # # Copyright (c) 2011-2015, ARM Limited. All rights reserved. +# Copyright (c) 2015, Intel Corporation. All rights reserved.
# # This program and the accompanying materials # are licensed and made available under the terms and conditions of the BSD License @@ -156,7 +157,7 @@ FvNameGuid = 12c68be9-0996-49d3-8c5b-4957379027ee INF MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf INF MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.inf INF MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf - INF EmbeddedPkg/SerialDxe/SerialDxe.inf + INF MdeModulePkg/Universal/SerialDxe/SerialDxe.inf INF ArmPkg/Drivers/ArmGic/ArmGicDxe.inf INF ArmPkg/Drivers/TimerDxe/TimerDxe.inf diff --git a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress.dsc.inc b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress.dsc.inc index dc69bbbf747c..05cf0badf7c4 100644 --- a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress.dsc.inc +++ b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress.dsc.inc @@ -90,7 +90,6 @@ # ARM PL011 UART Driver PL011UartLib|ArmPlatformPkg/Drivers/PL011Uart/PL011Uart.inf SerialPortLib|ArmPlatformPkg/Library/PL011SerialPortLib/PL011SerialPortLib.inf - SerialPortExtLib|ArmPlatformPkg/Library/PL011SerialPortLib/PL011SerialPortExtLib.inf # ARM SP804 Dual Timer Driver TimerLib|ArmPlatformPkg/Library/SP804TimerLib/SP804TimerLib.inf diff --git a/ArmPlatformPkg/Library/PL011SerialPortLib/PL011SerialPortExtLib.c b/ArmPlatformPkg/Library/PL011SerialPortLib/PL011SerialPortExtLib.c deleted file mode 100644 index 44fe78f4f46b..000000000000 --- a/ArmPlatformPkg/Library/PL011SerialPortLib/PL011SerialPortExtLib.c +++ /dev/null @@ -1,137 +0,0 @@ -/** @file - Serial I/O Port library functions with no library constructor/destructor - - Copyright (c) 2012-2014, ARM Ltd. All rights reserved.
- - This program and the accompanying materials - are licensed and made available under the terms and conditions of the BSD License - which accompanies this distribution. The full text of the license may be found at - http://opensource.org/licenses/bsd-license.php - - THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -#include - -#include -#include -#include - -#include - -/** - Set new attributes to PL011. - - @param BaudRate The baud rate of the serial device. If the baud rate is not supported, - the speed will be reduced down to the nearest supported one and the - variable's value will be updated accordingly. - @param ReceiveFifoDepth The number of characters the device will buffer on input. If the specified - value is not supported, the variable's value will be reduced down to the - nearest supported one. - @param Timeout If applicable, the number of microseconds the device will wait - before timing out a Read or a Write operation. - @param Parity If applicable, this is the EFI_PARITY_TYPE that is computed or checked - as each character is transmitted or received. If the device does not - support parity, the value is the default parity value. - @param DataBits The number of data bits in each character - @param StopBits If applicable, the EFI_STOP_BITS_TYPE number of stop bits per character. - If the device does not support stop bits, the value is the default stop - bit value. - - @retval EFI_SUCCESS All attributes were set correctly on the serial device. - @retval EFI_INVALID_PARAMETERS One or more of the attributes has an unsupported value. - -**/ -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 PL011UartInitializePort ( - (UINTN)PcdGet64 (PcdSerialRegisterBase), - BaudRate, - ReceiveFifoDepth, - Parity, - DataBits, - StopBits); -} - -/** - - Assert or deassert the control signals on a serial port. - The following control signals are set according their bit settings : - . Request to Send - . Data Terminal Ready - - @param[in] Control The following bits are taken into account : - . EFI_SERIAL_REQUEST_TO_SEND : assert/deassert the - "Request To Send" control signal if this bit is - equal to one/zero. - . EFI_SERIAL_DATA_TERMINAL_READY : assert/deassert - the "Data Terminal Ready" control signal if this - bit is equal to one/zero. - . EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE : enable/disable - the hardware loopback if this bit is equal to - one/zero. - . EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE : not supported. - . EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE : enable/ - disable the hardware flow control based on CTS (Clear - To Send) and RTS (Ready To Send) control signals. - - @retval RETURN_SUCCESS The new control bits were set on the serial device. - @retval RETURN_UNSUPPORTED The serial device does not support this operation. - -**/ -RETURN_STATUS -EFIAPI -SerialPortSetControl ( - IN UINT32 Control - ) -{ - return PL011UartSetControl ((UINTN)PcdGet64 (PcdSerialRegisterBase), Control); -} - -/** - - Retrieve the status of the control bits on a serial device. - - @param[out] Control Status of the control bits on a serial device : - - . EFI_SERIAL_DATA_CLEAR_TO_SEND, EFI_SERIAL_DATA_SET_READY, - EFI_SERIAL_RING_INDICATE, EFI_SERIAL_CARRIER_DETECT, - EFI_SERIAL_REQUEST_TO_SEND, EFI_SERIAL_DATA_TERMINAL_READY - are all related to the DTE (Data Terminal Equipment) and - DCE (Data Communication Equipment) modes of operation of - the serial device. - . EFI_SERIAL_INPUT_BUFFER_EMPTY : equal to one if the receive - buffer is empty, 0 otherwise. - . EFI_SERIAL_OUTPUT_BUFFER_EMPTY : equal to one if the transmit - buffer is empty, 0 otherwise. - . EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE : equal to one if the - hardware loopback is enabled (the ouput feeds the receive - buffer), 0 otherwise. - . EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE : equal to one if a - loopback is accomplished by software, 0 otherwise. - . EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE : equal to one if the - hardware flow control based on CTS (Clear To Send) and RTS - (Ready To Send) control signals is enabled, 0 otherwise. - - @retval RETURN_SUCCESS The control bits were read from the serial device. - -**/ -RETURN_STATUS -EFIAPI -SerialPortGetControl ( - OUT UINT32 *Control - ) -{ - return PL011UartGetControl ((UINTN)PcdGet64 (PcdSerialRegisterBase), Control); -} diff --git a/ArmPlatformPkg/Library/PL011SerialPortLib/PL011SerialPortExtLib.inf b/ArmPlatformPkg/Library/PL011SerialPortLib/PL011SerialPortExtLib.inf deleted file mode 100644 index 723cc97d1b06..000000000000 --- a/ArmPlatformPkg/Library/PL011SerialPortLib/PL011SerialPortExtLib.inf +++ /dev/null @@ -1,43 +0,0 @@ -#/** @file -# -# Component description file for PL011SerialPortLib module -# -# Copyright (c) 2011-2012, ARM Ltd. All rights reserved.
-# -# This program and the accompanying materials -# are licensed and made available under the terms and conditions of the BSD License -# which accompanies this distribution. The full text of the license may be found at -# http://opensource.org/licenses/bsd-license.php -# -# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -# -#**/ - -[Defines] - INF_VERSION = 0x00010005 - BASE_NAME = PL011SerialPortExtLib - FILE_GUID = 2be281f1-c506-4558-bd98-d6930e6de9d6 - MODULE_TYPE = BASE - VERSION_STRING = 1.0 - LIBRARY_CLASS = SerialPortExtLib - -[Sources.common] - PL011SerialPortExtLib.c - -[LibraryClasses] - PL011UartLib - PcdLib - -[Packages] - EmbeddedPkg/EmbeddedPkg.dec - MdePkg/MdePkg.dec - MdeModulePkg/MdeModulePkg.dec - ArmPlatformPkg/ArmPlatformPkg.dec - -[Pcd] - gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterBase - gEfiMdePkgTokenSpaceGuid.PcdUartDefaultBaudRate - gEfiMdePkgTokenSpaceGuid.PcdUartDefaultDataBits - gEfiMdePkgTokenSpaceGuid.PcdUartDefaultParity - gEfiMdePkgTokenSpaceGuid.PcdUartDefaultStopBits diff --git a/ArmPlatformPkg/Library/PL011SerialPortLib/PL011SerialPortLib.c b/ArmPlatformPkg/Library/PL011SerialPortLib/PL011SerialPortLib.c index d4f7fc96f6d4..7497b5eb7f19 100644 --- a/ArmPlatformPkg/Library/PL011SerialPortLib/PL011SerialPortLib.c +++ b/ArmPlatformPkg/Library/PL011SerialPortLib/PL011SerialPortLib.c @@ -2,7 +2,8 @@ Serial I/O Port library functions with no library constructor/destructor Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.
- Copyright (c) 2012 - 2013, ARM Ltd. All rights reserved.
+ Copyright (c) 2012 - 2014, ARM Ltd. All rights reserved.
+ Copyright (c) 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License @@ -19,7 +20,6 @@ #include #include #include -#include #include @@ -110,4 +110,117 @@ SerialPortPoll ( { return PL011UartPoll ((UINTN)PcdGet64 (PcdSerialRegisterBase)); } +/** + Set new attributes to PL011. + + @param BaudRate The baud rate of the serial device. If the baud rate is not supported, + the speed will be reduced down to the nearest supported one and the + variable's value will be updated accordingly. + @param ReceiveFifoDepth The number of characters the device will buffer on input. If the specified + value is not supported, the variable's value will be reduced down to the + nearest supported one. + @param Timeout If applicable, the number of microseconds the device will wait + before timing out a Read or a Write operation. + @param Parity If applicable, this is the EFI_PARITY_TYPE that is computed or checked + as each character is transmitted or received. If the device does not + support parity, the value is the default parity value. + @param DataBits The number of data bits in each character + @param StopBits If applicable, the EFI_STOP_BITS_TYPE number of stop bits per character. + If the device does not support stop bits, the value is the default stop + bit value. + + @retval EFI_SUCCESS All attributes were set correctly on the serial device. + @retval EFI_INVALID_PARAMETERS One or more of the attributes has an unsupported value. + +**/ +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 PL011UartInitializePort ( + (UINTN)PcdGet64 (PcdSerialRegisterBase), + BaudRate, + ReceiveFifoDepth, + Parity, + DataBits, + StopBits); +} + +/** + + Assert or deassert the control signals on a serial port. + The following control signals are set according their bit settings : + . Request to Send + . Data Terminal Ready + + @param[in] Control The following bits are taken into account : + . EFI_SERIAL_REQUEST_TO_SEND : assert/deassert the + "Request To Send" control signal if this bit is + equal to one/zero. + . EFI_SERIAL_DATA_TERMINAL_READY : assert/deassert + the "Data Terminal Ready" control signal if this + bit is equal to one/zero. + . EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE : enable/disable + the hardware loopback if this bit is equal to + one/zero. + . EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE : not supported. + . EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE : enable/ + disable the hardware flow control based on CTS (Clear + To Send) and RTS (Ready To Send) control signals. + + @retval RETURN_SUCCESS The new control bits were set on the serial device. + @retval RETURN_UNSUPPORTED The serial device does not support this operation. + +**/ +RETURN_STATUS +EFIAPI +SerialPortSetControl ( + IN UINT32 Control + ) +{ + return PL011UartSetControl ((UINTN)PcdGet64 (PcdSerialRegisterBase), Control); +} + +/** + Retrieve the status of the control bits on a serial device. + + @param[out] Control Status of the control bits on a serial device : + + . EFI_SERIAL_DATA_CLEAR_TO_SEND, EFI_SERIAL_DATA_SET_READY, + EFI_SERIAL_RING_INDICATE, EFI_SERIAL_CARRIER_DETECT, + EFI_SERIAL_REQUEST_TO_SEND, EFI_SERIAL_DATA_TERMINAL_READY + are all related to the DTE (Data Terminal Equipment) and + DCE (Data Communication Equipment) modes of operation of + the serial device. + . EFI_SERIAL_INPUT_BUFFER_EMPTY : equal to one if the receive + buffer is empty, 0 otherwise. + . EFI_SERIAL_OUTPUT_BUFFER_EMPTY : equal to one if the transmit + buffer is empty, 0 otherwise. + . EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE : equal to one if the + hardware loopback is enabled (the output feeds the receive + buffer), 0 otherwise. + . EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE : equal to one if a + loopback is accomplished by software, 0 otherwise. + . EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE : equal to one if the + hardware flow control based on CTS (Clear To Send) and RTS + (Ready To Send) control signals is enabled, 0 otherwise. + + @retval RETURN_SUCCESS The control bits were read from the serial device. + +**/ +RETURN_STATUS +EFIAPI +SerialPortGetControl ( + OUT UINT32 *Control + ) +{ + return PL011UartGetControl ((UINTN)PcdGet64 (PcdSerialRegisterBase), Control); +} From 3ab4039f64099df02026da8952a28c1f6ab42df6 Mon Sep 17 00:00:00 2001 From: Star Zeng Date: Mon, 30 Nov 2015 03:20:39 +0000 Subject: [PATCH 179/525] OvmfPkg XenConsoleSerialPortLib: Implement Get(Set)Control/SetAttributes (Sync patch r18972 from main trunk.) Cc: Michael D Kinney Cc: Liming Gao Cc: Jordan Justen Cc: Laszlo Ersek Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Star Zeng Reviewed-by: Laszlo Ersek git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19022 6f19259b-4bc3-4df7-8a09-765794883524 --- .../XenConsoleSerialPortLib.c | 95 +++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/OvmfPkg/Library/XenConsoleSerialPortLib/XenConsoleSerialPortLib.c b/OvmfPkg/Library/XenConsoleSerialPortLib/XenConsoleSerialPortLib.c index 4ccb38d585fd..295696312413 100644 --- a/OvmfPkg/Library/XenConsoleSerialPortLib/XenConsoleSerialPortLib.c +++ b/OvmfPkg/Library/XenConsoleSerialPortLib/XenConsoleSerialPortLib.c @@ -2,6 +2,7 @@ Xen console SerialPortLib instance Copyright (c) 2015, Linaro Ltd. All rights reserved.
+ Copyright (c) 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License @@ -205,3 +206,97 @@ SerialPortPoll ( return mXenConsoleInterface && mXenConsoleInterface->in_cons != mXenConsoleInterface->in_prod; } + +/** + Sets the control bits on a serial device. + + @param 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 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 + ) +{ + if (!mXenConsoleInterface) { + return RETURN_UNSUPPORTED; + } + + *Control = 0; + if (!SerialPortPoll ()) { + *Control = EFI_SERIAL_INPUT_BUFFER_EMPTY; + } + return RETURN_SUCCESS; +} + +/** + Sets the baud rate, receive FIFO depth, transmit/receice time out, parity, + data bits, and stop bits on a serial device. + + @param 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 ReveiveFifoDepth 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 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 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 DataBits The number of data bits to use on the serial device. A DataBits + vaule of 0 will use the device's default data bit setting. + On output, the value actually set. + @param 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; +} + From 5cfecbc9d59aeb81a2547dfe3e2045d459558270 Mon Sep 17 00:00:00 2001 From: Star Zeng Date: Mon, 30 Nov 2015 03:21:14 +0000 Subject: [PATCH 180/525] ArmVirtPkg: Use SerialDxe in MdeModulePkg instead of EmbeddedPkg Beyond just changing the directly related lines in the FDF and DSC files, we have to adapt the EarlyFdtPL011SerialPortLib and FdtPL011SerialPortLib instances as well, in the same patch. This is because the EmbeddedPkg driver expects the SerialPortSetAttributes(), SerialPortSetControl() and SerialPortGetControl() functions from SerialPortExtLib, while the MdeModulePkg driver expects them from SerialPortLib itself. We cannot implement these functions in ArmVirtPkg's SerialPortLib instances *before* flipping the driver, because it would cause double function definitions in the EmbeddedPkg driver. We also can't implement the functions *after* flipping the driver, because it would cause unresolved function references in the MdeModulePkg driver. Therefore we have to implement the functions simultaneously with the driver replacement. (Sync patch r18973 from main trunk.) Cc: Michael D Kinney Cc: Liming Gao Cc: Laszlo Ersek Cc: Ard Biesheuvel Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Star Zeng Reviewed-by: Laszlo Ersek git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19023 6f19259b-4bc3-4df7-8a09-765794883524 --- ArmVirtPkg/ArmVirt.dsc.inc | 1 - ArmVirtPkg/ArmVirtQemu.dsc | 2 +- ArmVirtPkg/ArmVirtQemu.fdf | 2 +- ArmVirtPkg/ArmVirtXen.dsc | 3 +- ArmVirtPkg/ArmVirtXen.fdf | 3 +- .../EarlyFdtPL011SerialPortLib.c | 88 ++++++++++++++++++- .../FdtPL011SerialPortLib.c | 87 ++++++++++++++++++ 7 files changed, 180 insertions(+), 6 deletions(-) diff --git a/ArmVirtPkg/ArmVirt.dsc.inc b/ArmVirtPkg/ArmVirt.dsc.inc index 8372c5813cb3..72f583ed274e 100644 --- a/ArmVirtPkg/ArmVirt.dsc.inc +++ b/ArmVirtPkg/ArmVirt.dsc.inc @@ -91,7 +91,6 @@ # ARM PL011 UART Driver PL011UartLib|ArmPlatformPkg/Drivers/PL011Uart/PL011Uart.inf SerialPortLib|ArmVirtPkg/Library/FdtPL011SerialPortLib/FdtPL011SerialPortLib.inf - SerialPortExtLib|EmbeddedPkg/Library/SerialPortExtLibNull/SerialPortExtLibNull.inf # # Uncomment (and comment out the next line) For RealView Debugger. The Standard IO window diff --git a/ArmVirtPkg/ArmVirtQemu.dsc b/ArmVirtPkg/ArmVirtQemu.dsc index f1af96827fde..efb4fdd35d44 100644 --- a/ArmVirtPkg/ArmVirtQemu.dsc +++ b/ArmVirtPkg/ArmVirtQemu.dsc @@ -280,7 +280,7 @@ MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.inf MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf - EmbeddedPkg/SerialDxe/SerialDxe.inf + MdeModulePkg/Universal/SerialDxe/SerialDxe.inf MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf diff --git a/ArmVirtPkg/ArmVirtQemu.fdf b/ArmVirtPkg/ArmVirtQemu.fdf index 89a4015e595b..738e3db57045 100644 --- a/ArmVirtPkg/ArmVirtQemu.fdf +++ b/ArmVirtPkg/ArmVirtQemu.fdf @@ -134,7 +134,7 @@ READ_LOCK_STATUS = TRUE INF MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf INF MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.inf INF MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf - INF EmbeddedPkg/SerialDxe/SerialDxe.inf + INF MdeModulePkg/Universal/SerialDxe/SerialDxe.inf INF ArmPkg/Drivers/ArmGic/ArmGicDxe.inf INF ArmPkg/Drivers/TimerDxe/TimerDxe.inf diff --git a/ArmVirtPkg/ArmVirtXen.dsc b/ArmVirtPkg/ArmVirtXen.dsc index 5c19afca30b9..42976dd0164b 100644 --- a/ArmVirtPkg/ArmVirtXen.dsc +++ b/ArmVirtPkg/ArmVirtXen.dsc @@ -1,6 +1,7 @@ # # Copyright (c) 2011-2015, ARM Limited. All rights reserved. # Copyright (c) 2014, Linaro Limited. All rights reserved. +# Copyright (c) 2015, Intel Corporation. All rights reserved.
# # This program and the accompanying materials # are licensed and made available under the terms and conditions of the BSD License @@ -197,7 +198,7 @@ MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf - EmbeddedPkg/SerialDxe/SerialDxe.inf + MdeModulePkg/Universal/SerialDxe/SerialDxe.inf MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf diff --git a/ArmVirtPkg/ArmVirtXen.fdf b/ArmVirtPkg/ArmVirtXen.fdf index 97cab4b058f2..729014753fa1 100644 --- a/ArmVirtPkg/ArmVirtXen.fdf +++ b/ArmVirtPkg/ArmVirtXen.fdf @@ -1,6 +1,7 @@ # # Copyright (c) 2011-2015, ARM Limited. All rights reserved. # Copyright (c) 2014, Linaro Limited. All rights reserved. +# Copyright (c) 2015, Intel Corporation. All rights reserved.
# # This program and the accompanying materials # are licensed and made available under the terms and conditions of the BSD License @@ -134,7 +135,7 @@ READ_LOCK_STATUS = TRUE # INF MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf INF MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf - INF EmbeddedPkg/SerialDxe/SerialDxe.inf + INF MdeModulePkg/Universal/SerialDxe/SerialDxe.inf INF ArmPkg/Drivers/ArmGic/ArmGicDxe.inf INF ArmPkg/Drivers/TimerDxe/TimerDxe.inf diff --git a/ArmVirtPkg/Library/FdtPL011SerialPortLib/EarlyFdtPL011SerialPortLib.c b/ArmVirtPkg/Library/FdtPL011SerialPortLib/EarlyFdtPL011SerialPortLib.c index ba6d277d4571..c8bfb2972eb9 100644 --- a/ArmVirtPkg/Library/FdtPL011SerialPortLib/EarlyFdtPL011SerialPortLib.c +++ b/ArmVirtPkg/Library/FdtPL011SerialPortLib/EarlyFdtPL011SerialPortLib.c @@ -4,6 +4,7 @@ Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.
Copyright (c) 2012 - 2013, ARM Ltd. All rights reserved.
Copyright (c) 2014, Linaro Ltd. All rights reserved.
+ Copyright (c) 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License @@ -19,7 +20,6 @@ #include #include -#include #include #include @@ -183,3 +183,89 @@ SerialPortPoll ( { 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/receice time out, parity, + data bits, and stop bits on a serial device. + + @param 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 ReveiveFifoDepth 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 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 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 DataBits The number of data bits to use on the serial device. A DataBits + vaule of 0 will use the device's default data bit setting. + On output, the value actually set. + @param 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/ArmVirtPkg/Library/FdtPL011SerialPortLib/FdtPL011SerialPortLib.c b/ArmVirtPkg/Library/FdtPL011SerialPortLib/FdtPL011SerialPortLib.c index aced6666a913..b73ab8f48a9d 100644 --- a/ArmVirtPkg/Library/FdtPL011SerialPortLib/FdtPL011SerialPortLib.c +++ b/ArmVirtPkg/Library/FdtPL011SerialPortLib/FdtPL011SerialPortLib.c @@ -5,6 +5,7 @@ Copyright (c) 2012 - 2013, ARM Ltd. All rights reserved.
Copyright (c) 2014, Linaro Ltd. All rights reserved.
Copyright (c) 2014, Red Hat, Inc.
+ Copyright (c) 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License @@ -148,3 +149,89 @@ SerialPortPoll ( } return FALSE; } + +/** + Sets the baud rate, receive FIFO depth, transmit/receice time out, parity, + data bits, and stop bits on a serial device. + + @param 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 ReveiveFifoDepth 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 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 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 DataBits The number of data bits to use on the serial device. A DataBits + vaule of 0 will use the device's default data bit setting. + On output, the value actually set. + @param 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; +} + +/** + Sets the control bits on a serial device. + + @param 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 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; +} + From 7b8985705ba2a0a8e9b5766eb7cb0a70dd41a103 Mon Sep 17 00:00:00 2001 From: Star Zeng Date: Mon, 30 Nov 2015 03:22:01 +0000 Subject: [PATCH 181/525] EmbeddedPkg: Remove SerialDxe and SerialPortExtLib libraries (Sync patch r18974 from main trunk.) Cc: Michael D Kinney Cc: Liming Gao Cc: Leif Lindholm Cc: Ard Biesheuvel Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Star Zeng Reviewed-by: Ard Biesheuvel git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19024 6f19259b-4bc3-4df7-8a09-765794883524 --- EmbeddedPkg/EmbeddedPkg.dsc | 6 +- .../Include/Library/SerialPortExtLib.h | 116 ------ .../SerialPortExtLibNull.c | 48 --- .../SerialPortExtLibNull.inf | 30 -- .../TemplateSerialPortExtLib.c | 79 ---- .../TemplateSerialPortExtLib.inf | 36 -- EmbeddedPkg/SerialDxe/SerialDxe.inf | 55 --- EmbeddedPkg/SerialDxe/SerialIo.c | 391 ------------------ 8 files changed, 1 insertion(+), 760 deletions(-) delete mode 100644 EmbeddedPkg/Include/Library/SerialPortExtLib.h delete mode 100644 EmbeddedPkg/Library/SerialPortExtLibNull/SerialPortExtLibNull.c delete mode 100644 EmbeddedPkg/Library/SerialPortExtLibNull/SerialPortExtLibNull.inf delete mode 100644 EmbeddedPkg/Library/TemplateSerialPortExtLib/TemplateSerialPortExtLib.c delete mode 100644 EmbeddedPkg/Library/TemplateSerialPortExtLib/TemplateSerialPortExtLib.inf delete mode 100644 EmbeddedPkg/SerialDxe/SerialDxe.inf delete mode 100644 EmbeddedPkg/SerialDxe/SerialIo.c diff --git a/EmbeddedPkg/EmbeddedPkg.dsc b/EmbeddedPkg/EmbeddedPkg.dsc index 6719eea37471..a5507ed220d5 100644 --- a/EmbeddedPkg/EmbeddedPkg.dsc +++ b/EmbeddedPkg/EmbeddedPkg.dsc @@ -2,7 +2,7 @@ # Embedded Package # # -# Copyright (c) 2007, Intel Corporation. All rights reserved.
+# Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.
# Copyright (c) 2012-2015, ARM Ltd. All rights reserved.
# # This program and the accompanying materials @@ -68,7 +68,6 @@ PrePiLib|EmbeddedPkg/Library/PrePiLib/PrePiLib.inf SerialPortLib|MdePkg/Library/BaseSerialPortLibNull/BaseSerialPortLibNull.inf - SerialPortExtLib|EmbeddedPkg/Library/TemplateSerialPortExtLib/TemplateSerialPortExtLib.inf RealTimeClockLib|EmbeddedPkg/Library/TemplateRealTimeClockLib/TemplateRealTimeClockLib.inf EfiResetSystemLib|EmbeddedPkg/Library/TemplateResetSystemLib/TemplateResetSystemLib.inf GdbSerialLib|EmbeddedPkg/Library/GdbSerialLib/GdbSerialLib.inf @@ -249,8 +248,6 @@ EmbeddedPkg/Library/GdbSerialLib/GdbSerialLib.inf EmbeddedPkg/Library/PrePiExtractGuidedSectionLib/PrePiExtractGuidedSectionLib.inf EmbeddedPkg/Library/PrePiLib/PrePiLib.inf - MdePkg/Library/BaseSerialPortLibNull/BaseSerialPortLibNull.inf - EmbeddedPkg/Library/SerialPortExtLibNull/SerialPortExtLibNull.inf EmbeddedPkg/Library/TemplateResetSystemLib/TemplateResetSystemLib.inf EmbeddedPkg/Library/TemplateRealTimeClockLib/TemplateRealTimeClockLib.inf EmbeddedPkg/Library/LzmaHobCustomDecompressLib/LzmaHobCustomDecompressLib.inf @@ -261,7 +258,6 @@ EmbeddedPkg/EmbeddedMonotonicCounter/EmbeddedMonotonicCounter.inf EmbeddedPkg/RealTimeClockRuntimeDxe/RealTimeClockRuntimeDxe.inf EmbeddedPkg/ResetRuntimeDxe/ResetRuntimeDxe.inf - EmbeddedPkg/SerialDxe/SerialDxe.inf EmbeddedPkg/SimpleTextInOutSerial/SimpleTextInOutSerial.inf EmbeddedPkg/MetronomeDxe/MetronomeDxe.inf { diff --git a/EmbeddedPkg/Include/Library/SerialPortExtLib.h b/EmbeddedPkg/Include/Library/SerialPortExtLib.h deleted file mode 100644 index 0d0abb35ff54..000000000000 --- a/EmbeddedPkg/Include/Library/SerialPortExtLib.h +++ /dev/null @@ -1,116 +0,0 @@ -/** @file - - Serial I/O port control interface extension. - - This library provides an extension to the library providing common - serial I/O port functions that is defined in MdePkg. The aim is to - provide more control over the functionalities of a serial port. The - extension covers all the needs of the UEFI Serial I/O Protocol. - Though, its use is not restricted to the UEFI Serial I/O Protocol. - It could for example be used in the PEI phase of the boot sequence - as well. - - Copyright (c) 2012 - 2014, ARM Ltd. All rights reserved. - - This program and the accompanying materials - are licensed and made available under the terms and conditions of the BSD License - which accompanies this distribution. The full text of the license may be found at - http://opensource.org/licenses/bsd-license.php - - THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -#ifndef __SERIAL_PORT_EXT_LIB_H__ -#define __SERIAL_PORT_EXT_LIB_H__ - -#include -#include - -/** - - Assert or deassert the control signals on a serial port. - The following control signals are set according their bit settings : - . Request to Send - . Data Terminal Ready - - @param[in] Control The following bits are taken into account : - . EFI_SERIAL_REQUEST_TO_SEND : assert/deassert the - "Request To Send" control signal if this bit is - equal to one/zero. - . EFI_SERIAL_DATA_TERMINAL_READY : assert/deassert - the "Data Terminal Ready" control signal if this - bit is equal to one/zero. - . EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE : enable/disable - the hardware loopback if this bit is equal to - one/zero. - . EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE : not supported. - . EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE : enable/ - disable the hardware flow control based on CTS (Clear - To Send) and RTS (Ready To Send) control signals. - - @retval RETURN_SUCCESS The new control bits were set on the serial device. - @retval RETURN_UNSUPPORTED The serial device does not support this operation. - -**/ -RETURN_STATUS -EFIAPI -SerialPortSetControl ( - IN UINT32 Control - ); - -/** - - Retrieve the status of the control bits on a serial device. - - @param[out] Control Status of the control bits on a serial device : - - . EFI_SERIAL_DATA_CLEAR_TO_SEND, EFI_SERIAL_DATA_SET_READY, - EFI_SERIAL_RING_INDICATE, EFI_SERIAL_CARRIER_DETECT, - EFI_SERIAL_REQUEST_TO_SEND, EFI_SERIAL_DATA_TERMINAL_READY - are all related to the DTE (Data Terminal Equipment) and - DCE (Data Communication Equipment) modes of operation of - the serial device. - . EFI_SERIAL_INPUT_BUFFER_EMPTY : equal to one if the receive - buffer is empty, 0 otherwise. - . EFI_SERIAL_OUTPUT_BUFFER_EMPTY : equal to one if the transmit - buffer is empty, 0 otherwise. - . EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE : equal to one if the - hardware loopback is enabled (the ouput feeds the receive - buffer), 0 otherwise. - . EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE : equal to one if a - loopback is accomplished by software, 0 otherwise. - . EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE : equal to one if the - hardware flow control based on CTS (Clear To Send) and RTS - (Ready To Send) control signals is enabled, 0 otherwise. - - @retval RETURN_SUCCESS The control bits were read from the serial device. - @retval RETURN_DEVICE_ERROR The serial device is not functioning correctly. - -**/ -RETURN_STATUS -EFIAPI -SerialPortGetControl ( - OUT UINT32 *Control - ); - -/** - Set the serial device attributes. - - @return Always return EFI_UNSUPPORTED. - -**/ -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 - ); - -#endif - diff --git a/EmbeddedPkg/Library/SerialPortExtLibNull/SerialPortExtLibNull.c b/EmbeddedPkg/Library/SerialPortExtLibNull/SerialPortExtLibNull.c deleted file mode 100644 index fb7dea54a684..000000000000 --- a/EmbeddedPkg/Library/SerialPortExtLibNull/SerialPortExtLibNull.c +++ /dev/null @@ -1,48 +0,0 @@ -/** @file - - Copyright (c) 2014, Linaro Ltd. All rights reserved.
- - This program and the accompanying materials - are licensed and made available under the terms and conditions of the BSD License - which accompanies this distribution. The full text of the license may be found at - http://opensource.org/licenses/bsd-license.php - - THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -#include - -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_SUCCESS; -} - -RETURN_STATUS -EFIAPI -SerialPortSetControl ( - IN UINT32 Control - ) -{ - return RETURN_SUCCESS; -} - -RETURN_STATUS -EFIAPI -SerialPortGetControl ( - OUT UINT32 *Control - ) -{ - *Control = 0; - return RETURN_SUCCESS; -} diff --git a/EmbeddedPkg/Library/SerialPortExtLibNull/SerialPortExtLibNull.inf b/EmbeddedPkg/Library/SerialPortExtLibNull/SerialPortExtLibNull.inf deleted file mode 100644 index a1ac3febd586..000000000000 --- a/EmbeddedPkg/Library/SerialPortExtLibNull/SerialPortExtLibNull.inf +++ /dev/null @@ -1,30 +0,0 @@ -#/** @file -# -# Component description file for PL011SerialPortLib module -# -# Copyright (c) 2011-2014, ARM Ltd. All rights reserved.
-# -# This program and the accompanying materials -# are licensed and made available under the terms and conditions of the BSD License -# which accompanies this distribution. The full text of the license may be found at -# http://opensource.org/licenses/bsd-license.php -# -# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -# -#**/ - -[Defines] - INF_VERSION = 0x00010005 - BASE_NAME = SerialPortExtLibNull - FILE_GUID = BD396D28-085E-477A-A5DE-A8D91DD1F752 - MODULE_TYPE = BASE - VERSION_STRING = 1.0 - LIBRARY_CLASS = SerialPortExtLib - -[Sources.common] - SerialPortExtLibNull.c - -[Packages] - MdePkg/MdePkg.dec - EmbeddedPkg/EmbeddedPkg.dec diff --git a/EmbeddedPkg/Library/TemplateSerialPortExtLib/TemplateSerialPortExtLib.c b/EmbeddedPkg/Library/TemplateSerialPortExtLib/TemplateSerialPortExtLib.c deleted file mode 100644 index f0f8465cb6d4..000000000000 --- a/EmbeddedPkg/Library/TemplateSerialPortExtLib/TemplateSerialPortExtLib.c +++ /dev/null @@ -1,79 +0,0 @@ -/** @file - Extended Serial I/O Port library functions - - Copyright (c) 2012, ARM Ltd. All rights reserved. - - This program and the accompanying materials - are licensed and made available under the terms and conditions of the BSD License - which accompanies this distribution. The full text of the license may be found at - http://opensource.org/licenses/bsd-license.php - - THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -#include - -#include -#include - -/** - Set the serial device control bits. - - @return Always return RETURN_UNSUPPORTED. - -**/ -RETURN_STATUS -EFIAPI -SerialPortSetControl ( - IN UINT32 Control - ) -{ - return RETURN_UNSUPPORTED; -} - -/** - Get the serial device control bits. - - @param Control Control signals read from the serial device. - - @retval EFI_SUCCESS The control bits were read from the serial device. - @retval EFI_DEVICE_ERROR The serial device is not functioning correctly. - -**/ -RETURN_STATUS -EFIAPI -SerialPortGetControl ( - OUT UINT32 *Control - ) -{ - if (SerialPortPoll ()) { - // If a character is pending don't set EFI_SERIAL_INPUT_BUFFER_EMPTY - *Control = EFI_SERIAL_OUTPUT_BUFFER_EMPTY; - } else { - *Control = EFI_SERIAL_INPUT_BUFFER_EMPTY | EFI_SERIAL_OUTPUT_BUFFER_EMPTY; - } - return RETURN_SUCCESS; -} - -/** - Set the serial device attributes. - - @return Always return RETURN_UNSUPPORTED. - -**/ -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/EmbeddedPkg/Library/TemplateSerialPortExtLib/TemplateSerialPortExtLib.inf b/EmbeddedPkg/Library/TemplateSerialPortExtLib/TemplateSerialPortExtLib.inf deleted file mode 100644 index 2e95405af452..000000000000 --- a/EmbeddedPkg/Library/TemplateSerialPortExtLib/TemplateSerialPortExtLib.inf +++ /dev/null @@ -1,36 +0,0 @@ -#/** @file -# Template for Extended Serial Port Library for UEFI drivers -# -# Copyright (c) 2006, Intel Corporation. All rights reserved.
-# Copyright (c) 2012, ARM Ltd. All rights reserved.
-# -# This program and the accompanying materials -# are licensed and made available under the terms and conditions of the BSD License -# which accompanies this distribution. The full text of the license may be found at -# http://opensource.org/licenses/bsd-license.php -# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -# -# -#**/ - -[Defines] - INF_VERSION = 0x00010005 - BASE_NAME = TemplateSerialPortExtLib - FILE_GUID = 231fe752-40ac-40b0-8d23-4e341309b964 - MODULE_TYPE = BASE - VERSION_STRING = 1.0 - LIBRARY_CLASS = SerialPortExtLib - - -# -# VALID_ARCHITECTURES = ARM IA32 X64 IPF EBC -# - -[Sources.common] - TemplateSerialPortExtLib.c - -[Packages] - MdePkg/MdePkg.dec - EmbeddedPkg/EmbeddedPkg.dec - diff --git a/EmbeddedPkg/SerialDxe/SerialDxe.inf b/EmbeddedPkg/SerialDxe/SerialDxe.inf deleted file mode 100644 index aed458df6385..000000000000 --- a/EmbeddedPkg/SerialDxe/SerialDxe.inf +++ /dev/null @@ -1,55 +0,0 @@ -#/** @file -# -# Convert SerialLib into SerialIo protocol -# -# Copyright (c) 2008, Intel Corporation. All rights reserved.
-# This program and the accompanying materials -# are licensed and made available under the terms and conditions of the BSD License -# which accompanies this distribution. The full text of the license may be found at -# http://opensource.org/licenses/bsd-license.php -# -# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -# -#**/ - -[Defines] - INF_VERSION = 0x00010005 - BASE_NAME = SerialDxe - FILE_GUID = D3987D4B-971A-435F-8CAF-4967EB627241 - MODULE_TYPE = DXE_DRIVER - VERSION_STRING = 1.0 - - ENTRY_POINT = SerialDxeInitialize - -[Sources.common] - SerialIo.c - -[Packages] - MdePkg/MdePkg.dec - EmbeddedPkg/EmbeddedPkg.dec - -[LibraryClasses] - BaseLib - ReportStatusCodeLib - MemoryAllocationLib - UefiLib - UefiBootServicesTableLib - BaseMemoryLib - DebugLib - UefiDriverEntryPoint - SerialPortLib - SerialPortExtLib - -[Protocols] - gEfiSerialIoProtocolGuid - gEfiDevicePathProtocolGuid - -[FixedPcd] - gEfiMdePkgTokenSpaceGuid.PcdUartDefaultBaudRate - gEfiMdePkgTokenSpaceGuid.PcdUartDefaultDataBits - gEfiMdePkgTokenSpaceGuid.PcdUartDefaultParity - gEfiMdePkgTokenSpaceGuid.PcdUartDefaultStopBits - -[Depex] - TRUE diff --git a/EmbeddedPkg/SerialDxe/SerialIo.c b/EmbeddedPkg/SerialDxe/SerialIo.c deleted file mode 100644 index 7a849b7a0139..000000000000 --- a/EmbeddedPkg/SerialDxe/SerialIo.c +++ /dev/null @@ -1,391 +0,0 @@ -/** @file - Serial IO Abstraction for GDB stub. This allows an EFI consoles that shows up on the system - running GDB. One console for error information and another console for user input/output. - - Basic packet format is $packet-data#checksum. So every command has 4 bytes of overhead: $, - #, 0, 0. The 0 and 0 are the ascii characters for the checksum. - - Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
- Copyright (c) 2013-2014, ARM Ltd. All rights reserved.
- - This program and the accompanying materials - are licensed and made available under the terms and conditions of the BSD License - which accompanies this distribution. The full text of the license may be found at - http://opensource.org/licenses/bsd-license.php - - THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -#include -#include -#include -#include -#include -#include -#include - -#include - -typedef struct { - VENDOR_DEVICE_PATH Guid; - UART_DEVICE_PATH Uart; - EFI_DEVICE_PATH_PROTOCOL End; -} SIMPLE_TEXT_OUT_DEVICE_PATH; - -SIMPLE_TEXT_OUT_DEVICE_PATH mDevicePath = { - { - { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, { sizeof (VENDOR_DEVICE_PATH), 0} }, - EFI_CALLER_ID_GUID // Use the drivers GUID - }, - { - { MESSAGING_DEVICE_PATH, MSG_UART_DP, { sizeof (UART_DEVICE_PATH), 0} }, - 0, // Reserved - FixedPcdGet64 (PcdUartDefaultBaudRate), // BaudRate - FixedPcdGet8 (PcdUartDefaultDataBits), // DataBits - FixedPcdGet8 (PcdUartDefaultParity), // Parity (N) - FixedPcdGet8 (PcdUartDefaultStopBits) // StopBits - }, - { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 } } -}; - -EFI_HANDLE gHandle = NULL; - -/** - Reset the serial device. - - @param This Protocol instance pointer. - - @retval EFI_SUCCESS The device was reset. - @retval EFI_DEVICE_ERROR The serial device could not be reset. - -**/ -EFI_STATUS -EFIAPI -SerialReset ( - IN EFI_SERIAL_IO_PROTOCOL *This - ) -{ - EFI_STATUS Status; - EFI_TPL Tpl; - - Status = SerialPortInitialize (); - if (EFI_ERROR(Status)) { - return Status; - } - - // - // Set the Serial I/O mode and update the device path - // - - Tpl = gBS->RaiseTPL (TPL_NOTIFY); - - // - // Set the Serial I/O mode - // - This->Mode->ReceiveFifoDepth = 0; - This->Mode->Timeout = 1000000; - This->Mode->BaudRate = PcdGet64 (PcdUartDefaultBaudRate); - This->Mode->DataBits = (UINT32)PcdGet8 (PcdUartDefaultDataBits); - This->Mode->Parity = (UINT32)PcdGet8 (PcdUartDefaultParity); - This->Mode->StopBits = (UINT32)PcdGet8 (PcdUartDefaultStopBits); - - // - // Check if the device path has actually changed - // - if (mDevicePath.Uart.BaudRate == This->Mode->BaudRate && - mDevicePath.Uart.DataBits == (UINT8)This->Mode->DataBits && - mDevicePath.Uart.Parity == (UINT8)This->Mode->Parity && - mDevicePath.Uart.StopBits == (UINT8)This->Mode->StopBits - ) { - gBS->RestoreTPL (Tpl); - return EFI_SUCCESS; - } - - // - // Update the device path - // - mDevicePath.Uart.BaudRate = This->Mode->BaudRate; - mDevicePath.Uart.DataBits = (UINT8)This->Mode->DataBits; - mDevicePath.Uart.Parity = (UINT8)This->Mode->Parity; - mDevicePath.Uart.StopBits = (UINT8)This->Mode->StopBits; - - Status = gBS->ReinstallProtocolInterface ( - gHandle, - &gEfiDevicePathProtocolGuid, - &mDevicePath, - &mDevicePath - ); - - gBS->RestoreTPL (Tpl); - - return Status; -} - - -/** - Sets the baud rate, receive FIFO depth, transmit/receive time out, parity, - data buts, and stop bits on a serial device. - - @param This Protocol instance pointer. - @param BaudRate The requested baud rate. A BaudRate value of 0 will use the the - device's default interface speed. - @param 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. - @param 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. - @param Parity The type of parity to use on this serial device. A Parity value of - DefaultParity will use the device's default parity value. - @param 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. - @param 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. - - @retval EFI_SUCCESS The device was reset. - @retval EFI_DEVICE_ERROR The serial device could not be reset. - -**/ -EFI_STATUS -EFIAPI -SerialSetAttributes ( - IN EFI_SERIAL_IO_PROTOCOL *This, - IN UINT64 BaudRate, - IN UINT32 ReceiveFifoDepth, - IN UINT32 Timeout, - IN EFI_PARITY_TYPE Parity, - IN UINT8 DataBits, - IN EFI_STOP_BITS_TYPE StopBits - ) -{ - RETURN_STATUS ReturnStatus; - EFI_STATUS Status; - EFI_TPL Tpl; - - ReturnStatus = SerialPortSetAttributes (&BaudRate, &ReceiveFifoDepth, &Timeout, &Parity, &DataBits, &StopBits); - if (RETURN_ERROR (ReturnStatus)) { - return EFI_DEVICE_ERROR; - } - - // - // Set the Serial I/O mode and update the device path - // - - Tpl = gBS->RaiseTPL (TPL_NOTIFY); - - // - // Set the Serial I/O mode - // - This->Mode->BaudRate = BaudRate; - This->Mode->ReceiveFifoDepth = ReceiveFifoDepth; - This->Mode->Timeout = Timeout; - This->Mode->Parity = (UINT32)Parity; - This->Mode->DataBits = (UINT32)DataBits; - This->Mode->StopBits = (UINT32)StopBits; - - // - // Check if the device path has actually changed - // - if (mDevicePath.Uart.BaudRate == BaudRate && - mDevicePath.Uart.Parity == (UINT8)Parity && - mDevicePath.Uart.DataBits == DataBits && - mDevicePath.Uart.StopBits == (UINT8)StopBits - ) { - gBS->RestoreTPL (Tpl); - return EFI_SUCCESS; - } - - // - // Update the device path - // - mDevicePath.Uart.BaudRate = BaudRate; - mDevicePath.Uart.DataBits = DataBits; - mDevicePath.Uart.Parity = (UINT8) Parity; - mDevicePath.Uart.StopBits = (UINT8) StopBits; - - Status = gBS->ReinstallProtocolInterface ( - gHandle, - &gEfiDevicePathProtocolGuid, - &mDevicePath, - &mDevicePath - ); - - gBS->RestoreTPL (Tpl); - - return Status; -} - - -/** - Set the control bits on a serial device - - @param This Protocol instance pointer. - @param Control Set the bits of Control that are settable. - - @retval EFI_SUCCESS The new control bits were set on the serial device. - @retval EFI_UNSUPPORTED The serial device does not support this operation. - @retval EFI_DEVICE_ERROR The serial device is not functioning correctly. - -**/ -EFI_STATUS -EFIAPI -SerialSetControl ( - IN EFI_SERIAL_IO_PROTOCOL *This, - IN UINT32 Control - ) -{ - return SerialPortSetControl(Control); -} - - -/** - Retrieves the status of the control bits on a serial device - - @param This Protocol instance pointer. - @param Control A pointer to return the current Control signals from the serial device. - - @retval EFI_SUCCESS The control bits were read from the serial device. - @retval EFI_DEVICE_ERROR The serial device is not functioning correctly. - -**/ -EFI_STATUS -EFIAPI -SerialGetControl ( - IN EFI_SERIAL_IO_PROTOCOL *This, - OUT UINT32 *Control - ) -{ - return SerialPortGetControl(Control); -} - - -/** - Writes data to a serial device. - - @param This Protocol instance pointer. - @param BufferSize On input, the size of the Buffer. On output, the amount of - data actually written. - @param Buffer The buffer of data to write - - @retval EFI_SUCCESS The data was written. - @retval EFI_DEVICE_ERROR The device reported an error. - @retval EFI_TIMEOUT The data write was stopped due to a timeout. - -**/ -EFI_STATUS -EFIAPI -SerialWrite ( - IN EFI_SERIAL_IO_PROTOCOL *This, - IN OUT UINTN *BufferSize, - IN VOID *Buffer - ) -{ - UINTN Count; - - Count = SerialPortWrite (Buffer, *BufferSize); - - if (Count != *BufferSize) { - *BufferSize = Count; - return EFI_TIMEOUT; - } - - return EFI_SUCCESS; -} - -/** - Reads data from a serial device. - - @param This Protocol instance pointer. - @param BufferSize On input, the size of the Buffer. On output, the amount of - data returned in Buffer. - @param Buffer The buffer to return the data into. - - @retval EFI_SUCCESS The data was read. - @retval EFI_DEVICE_ERROR The device reported an error. - @retval EFI_TIMEOUT The data write was stopped due to a timeout. - -**/ - -EFI_STATUS -EFIAPI -SerialRead ( - IN EFI_SERIAL_IO_PROTOCOL *This, - IN OUT UINTN *BufferSize, - OUT VOID *Buffer - ) -{ - UINTN Count = 0; - - if (SerialPortPoll()) { - Count = SerialPortRead (Buffer, *BufferSize); - } - - if (Count != *BufferSize) { - *BufferSize = Count; - return EFI_TIMEOUT; - } - - return EFI_SUCCESS; -} - -// -// Template used to initialize the GDB Serial IO protocols -// -EFI_SERIAL_IO_MODE gSerialIoMode = { - 0, // ControlMask - 0, // Timeout - FixedPcdGet64 (PcdUartDefaultBaudRate), // BaudRate - 1, // ReceiveFifoDepth - FixedPcdGet8 (PcdUartDefaultDataBits), // DataBits - FixedPcdGet8 (PcdUartDefaultParity), // Parity - FixedPcdGet8 (PcdUartDefaultStopBits) // StopBits -}; - - -EFI_SERIAL_IO_PROTOCOL gSerialIoTemplate = { - SERIAL_IO_INTERFACE_REVISION, - SerialReset, - SerialSetAttributes, - SerialSetControl, - SerialGetControl, - SerialWrite, - SerialRead, - &gSerialIoMode -}; - -/** - Initialize the state information for the Serial Io Protocol - - @param ImageHandle of the loaded driver - @param SystemTable Pointer to the System Table - - @retval EFI_SUCCESS Protocol registered - @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure - @retval EFI_DEVICE_ERROR Hardware problems - -**/ -EFI_STATUS -EFIAPI -SerialDxeInitialize ( - IN EFI_HANDLE ImageHandle, - IN EFI_SYSTEM_TABLE *SystemTable - ) -{ - EFI_STATUS Status; - - // Make a new handle with Serial IO protocol and its device path on it. - Status = gBS->InstallMultipleProtocolInterfaces ( - &gHandle, - &gEfiSerialIoProtocolGuid, &gSerialIoTemplate, - &gEfiDevicePathProtocolGuid, &mDevicePath, - NULL - ); - ASSERT_EFI_ERROR (Status); - - return Status; -} - From d76a00635f5061a96b6d17c1b68de9d2732fce55 Mon Sep 17 00:00:00 2001 From: Zhang Lubo Date: Mon, 30 Nov 2015 03:22:27 +0000 Subject: [PATCH 182/525] NetworkPkg:Fix NULL pointer dereference issues. Revise some errors that some Null pointers may be dereferenced. (Sync patch r18961 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Zhang Lubo Reviewed-by: Fu Siyuan Reviewed-by: Ye Ting Reviewed-by: Wu Jiaxin git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19025 6f19259b-4bc3-4df7-8a09-765794883524 --- NetworkPkg/HttpDxe/HttpImpl.c | 18 ++++++++++-- NetworkPkg/HttpDxe/HttpImpl.h | 1 + NetworkPkg/HttpDxe/HttpProto.c | 52 +++++++++++++++------------------- 3 files changed, 40 insertions(+), 31 deletions(-) diff --git a/NetworkPkg/HttpDxe/HttpImpl.c b/NetworkPkg/HttpDxe/HttpImpl.c index ce28f07efa1f..f26d6f4f3faa 100644 --- a/NetworkPkg/HttpDxe/HttpImpl.c +++ b/NetworkPkg/HttpDxe/HttpImpl.c @@ -39,6 +39,7 @@ EFI_HTTP_PROTOCOL mEfiHttpTemplate = { This is NULL. HttpConfigData is NULL. HttpConfigData->AccessPoint is NULL. + @retval EFI_OUT_OF_RESOURCES Could not allocate enough system resources. @retval EFI_NOT_STARTED The HTTP instance is not configured. **/ @@ -70,6 +71,9 @@ EfiHttpGetModeData ( if (HttpInstance->LocalAddressIsIPv6) { Http6AccessPoint = AllocateZeroPool (sizeof (EFI_HTTPv6_ACCESS_POINT)); + if (Http6AccessPoint == NULL) { + return EFI_OUT_OF_RESOURCES; + } CopyMem ( Http6AccessPoint, &HttpInstance->Ipv6Node, @@ -78,6 +82,9 @@ EfiHttpGetModeData ( HttpConfigData->AccessPoint.IPv6Node = Http6AccessPoint; } else { Http4AccessPoint = AllocateZeroPool (sizeof (EFI_HTTPv4_ACCESS_POINT)); + if (Http4AccessPoint == NULL) { + return EFI_OUT_OF_RESOURCES; + } CopyMem ( Http4AccessPoint, &HttpInstance->IPv4Node, @@ -886,6 +893,8 @@ HttpResponseWorker ( goto Error; } + ASSERT (HttpHeaders != NULL); + // // Cache the part of body. // @@ -1288,14 +1297,19 @@ EfiHttpPoll ( HttpInstance = HTTP_INSTANCE_FROM_PROTOCOL (This); ASSERT (HttpInstance != NULL); - if (HttpInstance->State != HTTP_STATE_TCP_CONNECTED || (HttpInstance->Tcp4 == NULL && - HttpInstance->Tcp6 == NULL)) { + if (HttpInstance->State != HTTP_STATE_TCP_CONNECTED) { return EFI_NOT_STARTED; } if (HttpInstance->LocalAddressIsIPv6) { + if (HttpInstance->Tcp6 == NULL) { + return EFI_NOT_STARTED; + } Status = HttpInstance->Tcp6->Poll (HttpInstance->Tcp6); } else { + if (HttpInstance->Tcp4 == NULL) { + return EFI_NOT_STARTED; + } Status = HttpInstance->Tcp4->Poll (HttpInstance->Tcp4); } diff --git a/NetworkPkg/HttpDxe/HttpImpl.h b/NetworkPkg/HttpDxe/HttpImpl.h index 49c8af1b2100..afbe9822835f 100644 --- a/NetworkPkg/HttpDxe/HttpImpl.h +++ b/NetworkPkg/HttpDxe/HttpImpl.h @@ -44,6 +44,7 @@ This is NULL. HttpConfigData is NULL. HttpConfigData->AccessPoint is NULL. + @retval EFI_OUT_OF_RESOURCES Could not allocate enough system resources. @retval EFI_NOT_STARTED The HTTP instance is not configured. **/ diff --git a/NetworkPkg/HttpDxe/HttpProto.c b/NetworkPkg/HttpDxe/HttpProto.c index 22aed253cb36..d4ab74f0094d 100644 --- a/NetworkPkg/HttpDxe/HttpProto.c +++ b/NetworkPkg/HttpDxe/HttpProto.c @@ -565,15 +565,14 @@ HttpCloseTcpRxEvent ( EFI_TCP4_IO_TOKEN *Rx4Token; EFI_TCP6_IO_TOKEN *Rx6Token; + ASSERT (Wrap != NULL); HttpInstance = Wrap->HttpInstance; Rx4Token = NULL; Rx6Token = NULL; if (HttpInstance->LocalAddressIsIPv6) { - if (Wrap != NULL) { - if (Wrap->TcpWrap.Rx6Token.CompletionToken.Event != NULL) { - gBS->CloseEvent (Wrap->TcpWrap.Rx6Token.CompletionToken.Event); - } + if (Wrap->TcpWrap.Rx6Token.CompletionToken.Event != NULL) { + gBS->CloseEvent (Wrap->TcpWrap.Rx6Token.CompletionToken.Event); } if (HttpInstance->Rx6Token.CompletionToken.Event != NULL) { @@ -581,10 +580,8 @@ HttpCloseTcpRxEvent ( HttpInstance->Rx6Token.CompletionToken.Event = NULL; } } else { - if (Wrap != NULL) { - if (Wrap->TcpWrap.Rx4Token.CompletionToken.Event != NULL) { - gBS->CloseEvent (Wrap->TcpWrap.Rx4Token.CompletionToken.Event); - } + if (Wrap->TcpWrap.Rx4Token.CompletionToken.Event != NULL) { + gBS->CloseEvent (Wrap->TcpWrap.Rx4Token.CompletionToken.Event); } if (HttpInstance->Rx4Token.CompletionToken.Event != NULL) { @@ -1893,23 +1890,22 @@ HttpTcpTokenCleanup ( EFI_TCP4_IO_TOKEN *Rx4Token; EFI_TCP6_IO_TOKEN *Rx6Token; + ASSERT (Wrap != NULL); HttpInstance = Wrap->HttpInstance; Rx4Token = NULL; Rx6Token = NULL; if (HttpInstance->LocalAddressIsIPv6) { - if (Wrap != NULL) { - if (Wrap->TcpWrap.Rx6Token.CompletionToken.Event != NULL) { - gBS->CloseEvent (Wrap->TcpWrap.Rx6Token.CompletionToken.Event); - } + if (Wrap->TcpWrap.Rx6Token.CompletionToken.Event != NULL) { + gBS->CloseEvent (Wrap->TcpWrap.Rx6Token.CompletionToken.Event); + } - Rx6Token = &Wrap->TcpWrap.Rx6Token; - if (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) { - FreePool (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer); - Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL; - } - FreePool (Wrap); + Rx6Token = &Wrap->TcpWrap.Rx6Token; + if (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) { + FreePool (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer); + Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL; } + FreePool (Wrap); if (HttpInstance->Rx6Token.CompletionToken.Event != NULL) { gBS->CloseEvent (HttpInstance->Rx6Token.CompletionToken.Event); @@ -1923,18 +1919,16 @@ HttpTcpTokenCleanup ( } } else { - if (Wrap != NULL) { - if (Wrap->TcpWrap.Rx4Token.CompletionToken.Event != NULL) { - gBS->CloseEvent (Wrap->TcpWrap.Rx4Token.CompletionToken.Event); - } - Rx4Token = &Wrap->TcpWrap.Rx4Token; - if (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) { - FreePool (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer); - Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL; - } - FreePool (Wrap); + if (Wrap->TcpWrap.Rx4Token.CompletionToken.Event != NULL) { + gBS->CloseEvent (Wrap->TcpWrap.Rx4Token.CompletionToken.Event); } - + Rx4Token = &Wrap->TcpWrap.Rx4Token; + if (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) { + FreePool (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer); + Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL; + } + FreePool (Wrap); + if (HttpInstance->Rx4Token.CompletionToken.Event != NULL) { gBS->CloseEvent (HttpInstance->Rx4Token.CompletionToken.Event); HttpInstance->Rx4Token.CompletionToken.Event = NULL; From 988a36669834068d2ba69df9a1598d740513662e Mon Sep 17 00:00:00 2001 From: Ruiyu Ni Date: Tue, 1 Dec 2015 01:56:57 +0000 Subject: [PATCH 183/525] MdeModulePkg/BDS: Do not pass unnecessary option to boot option BDS puts a special GUID in boot option optional data for auto-discovered boot option. But when launching that boot option, the BDS core unconditionally pass the special GUID to the executable. A good written application/OS loader can ignore the unexpected parameters, but BDS core should still avoid passing the unnecessary GUID. (Sync patch r19007 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ruiyu Ni Reviewed-by: Eric Dong git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19072 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Library/UefiBootManagerLib/BmBoot.c | 32 ++++++++++++++++--- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c b/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c index 4afd9c25ff2e..59366885c4b9 100644 --- a/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c +++ b/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c @@ -52,6 +52,28 @@ EfiBootManagerRegisterLegacyBootSupport ( mBmLegacyBoot = LegacyBoot; } +/** + Return TRUE when the boot option is auto-created instead of manually added. + + @param BootOption Pointer to the boot option to check. + + @retval TRUE The boot option is auto-created. + @retval FALSE The boot option is manually added. +**/ +BOOLEAN +BmIsAutoCreateBootOption ( + EFI_BOOT_MANAGER_LOAD_OPTION *BootOption + ) +{ + if ((BootOption->OptionalDataSize == sizeof (EFI_GUID)) && + CompareGuid ((EFI_GUID *) BootOption->OptionalData, &mBmAutoCreateBootOptionGuid) + ) { + return TRUE; + } else { + return FALSE; + } +} + /** For a bootable Device path, return its boot type. @@ -1738,8 +1760,10 @@ EfiBootManagerBoot ( Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo); ASSERT_EFI_ERROR (Status); - ImageInfo->LoadOptionsSize = BootOption->OptionalDataSize; - ImageInfo->LoadOptions = BootOption->OptionalData; + if (!BmIsAutoCreateBootOption (BootOption)) { + ImageInfo->LoadOptionsSize = BootOption->OptionalDataSize; + ImageInfo->LoadOptions = BootOption->OptionalData; + } // // Clean to NULL because the image is loaded directly from the firmwares boot manager. @@ -2155,9 +2179,7 @@ EfiBootManagerRefreshAllBootOption ( for (Index = 0; Index < NvBootOptionCount; Index++) { if (((DevicePathType (NvBootOptions[Index].FilePath) != BBS_DEVICE_PATH) || (DevicePathSubType (NvBootOptions[Index].FilePath) != BBS_BBS_DP) - ) && - (NvBootOptions[Index].OptionalDataSize == sizeof (EFI_GUID)) && - CompareGuid ((EFI_GUID *) NvBootOptions[Index].OptionalData, &mBmAutoCreateBootOptionGuid) + ) && BmIsAutoCreateBootOption (&NvBootOptions[Index]) ) { // // Only check those added by BDS From e55444859f00eca2676aef4f3290571d386dd6be Mon Sep 17 00:00:00 2001 From: Yonghong Zhu Date: Tue, 1 Dec 2015 02:30:17 +0000 Subject: [PATCH 184/525] BaseTools: Fix two warning reported in the make phase. when we make BaseTools, it report warnings about VfrError.cpp and VolInfo, so this patch fix this warning. (Sync patch r18851 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Yonghong Zhu Reviewed-by: Liming Gao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19073 6f19259b-4bc3-4df7-8a09-765794883524 --- BaseTools/Source/C/VfrCompile/VfrError.cpp | 2 +- BaseTools/Source/C/VolInfo/VolInfo.c | 19 +++++++++++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/BaseTools/Source/C/VfrCompile/VfrError.cpp b/BaseTools/Source/C/VfrCompile/VfrError.cpp index 3be2bd84db14..3c506ec20476 100644 --- a/BaseTools/Source/C/VfrCompile/VfrError.cpp +++ b/BaseTools/Source/C/VfrCompile/VfrError.cpp @@ -280,7 +280,7 @@ CVfrErrorHandle::HandleWarning ( GetFileNameLineNum (LineNum, &FileName, &FileLine); if (mWarningAsError) { - Error (FileName, FileLine, 0x2220, "warning treated as error", NULL); + Error (FileName, FileLine, 0x2220, (CHAR8 *) "warning treated as error", NULL); } for (Index = 0; mVfrWarningHandleTable[Index].mWarningCode != VFR_WARNING_CODEUNDEFINED; Index++) { diff --git a/BaseTools/Source/C/VolInfo/VolInfo.c b/BaseTools/Source/C/VolInfo/VolInfo.c index 7e79d753676b..87e78d48a872 100644 --- a/BaseTools/Source/C/VolInfo/VolInfo.c +++ b/BaseTools/Source/C/VolInfo/VolInfo.c @@ -1,7 +1,7 @@ /** @file The tool dumps the contents of a firmware volume -Copyright (c) 1999 - 2014, Intel Corporation. All rights reserved.
+Copyright (c) 1999 - 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -17,6 +17,9 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include #include +#ifdef __GNUC__ +#include +#endif #include #include @@ -1422,9 +1425,21 @@ Routine Description: ); if (ExtractionTool != NULL) { - + #ifndef __GNUC__ ToolInputFile = CloneString (tmpnam (NULL)); ToolOutputFile = CloneString (tmpnam (NULL)); + #else + char tmp1[] = "/tmp/fileXXXXXX"; + char tmp2[] = "/tmp/fileXXXXXX"; + int fd1; + int fd2; + fd1 = mkstemp(tmp1); + fd2 = mkstemp(tmp2); + ToolInputFile = CloneString(tmp1); + ToolOutputFile = CloneString(tmp2); + close(fd1); + close(fd2); + #endif // // Construction 'system' command string From 61b90507206f4368cb102b3014cd46f7d31b2b89 Mon Sep 17 00:00:00 2001 From: Yonghong Zhu Date: Tue, 1 Dec 2015 02:30:36 +0000 Subject: [PATCH 185/525] BaseTools/toolsetup.bat: fixed the error when the path contains space when the path contains space, it will report error for PATH Environment update. (Sync patch r18852 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Yonghong Zhu Reviewed-by: Liming Gao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19074 6f19259b-4bc3-4df7-8a09-765794883524 --- BaseTools/toolsetup.bat | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/BaseTools/toolsetup.bat b/BaseTools/toolsetup.bat index 59874c58392f..310ddd030c07 100755 --- a/BaseTools/toolsetup.bat +++ b/BaseTools/toolsetup.bat @@ -322,13 +322,24 @@ goto end echo !!! WARNING !!! Will not be able to compile Python programs to .exe echo Will setup environment to run Python scripts directly. echo. - set PATH=%BASETOOLS_PYTHON_SOURCE%\Trim;%PATH% - set PATH=%BASETOOLS_PYTHON_SOURCE%\GenFds;%PATH% - set PATH=%BASETOOLS_PYTHON_SOURCE%\build;%PATH% - set PATHEXT=%PATHEXT%;.py + goto UpdatePATH ) + else ( + goto UpdateEnv + ) + ) + else ( + goto UpdateEnv ) - + +:UpdatePATH + set PATH=%BASETOOLS_PYTHON_SOURCE%\Trim;%PATH% + set PATH=%BASETOOLS_PYTHON_SOURCE%\GenFds;%PATH% + set PATH=%BASETOOLS_PYTHON_SOURCE%\build;%PATH% + set PATHEXT=%PATHEXT%;.py + goto UpdateEnv + +:UpdateEnv echo BASE_TOOLS_PATH = %BASE_TOOLS_PATH% echo PYTHON_PATH = %PYTHON_PATH% echo PYTHON_FREEZER_PATH = %PYTHON_FREEZER_PATH% From 61b0bea7d9bbcf22c33cdc729842f9dfd513b56b Mon Sep 17 00:00:00 2001 From: Hess Chen Date: Tue, 1 Dec 2015 02:31:16 +0000 Subject: [PATCH 186/525] BaseTool/UPT: Add supporting of decimal numbers for INF_VERSION and DEC_SPECIFICATION (Sync patch r18868 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Hess Chen Reviewed-by: Yonghong Zhu git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19075 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Source/Python/UPT/Logger/StringTable.py | 2 +- .../Python/UPT/Object/Parser/InfDefineObject.py | 17 +++++++++++------ BaseTools/Source/Python/UPT/Parser/DecParser.py | 4 +++- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/BaseTools/Source/Python/UPT/Logger/StringTable.py b/BaseTools/Source/Python/UPT/Logger/StringTable.py index f15ac7f0bc6b..a481c6785d61 100644 --- a/BaseTools/Source/Python/UPT/Logger/StringTable.py +++ b/BaseTools/Source/Python/UPT/Logger/StringTable.py @@ -656,7 +656,7 @@ ERR_DECPARSE_DEFINE_UNKNOWKEY = \ _("Unknown key [%s] in define section.") ERR_DECPARSE_DEFINE_SPEC = \ -_("Specification value must be HEX numbers.") +_("Specification value must be HEX numbers or decimal numbers.") ERR_DECPARSE_DEFINE_PKGNAME = \ _("Package name must be AlphaNumeric characters.") ERR_DECPARSE_DEFINE_PKGGUID = \ diff --git a/BaseTools/Source/Python/UPT/Object/Parser/InfDefineObject.py b/BaseTools/Source/Python/UPT/Object/Parser/InfDefineObject.py index be9a0e196e39..1d074ee638fd 100644 --- a/BaseTools/Source/Python/UPT/Object/Parser/InfDefineObject.py +++ b/BaseTools/Source/Python/UPT/Object/Parser/InfDefineObject.py @@ -340,16 +340,21 @@ def SetInfVersion(self, InfVersion, Comments): ErrorInInf(ST.ERR_INF_PARSER_NOT_SUPPORT_EDKI_INF, ErrorCode=ToolError.EDK1_INF_ERROR, LineInfo=self.CurrentLine) - - self.InfVersion = InfDefMember() - self.InfVersion.SetValue(InfVersion) - self.InfVersion.Comments = Comments - return True + elif IsValidDecVersionVal(InfVersion): + if (InfVersion < 65541): + ErrorInInf(ST.ERR_INF_PARSER_NOT_SUPPORT_EDKI_INF, + ErrorCode=ToolError.EDK1_INF_ERROR, + LineInfo=self.CurrentLine) else: ErrorInInf(ST.ERR_INF_PARSER_DEFINE_FROMAT_INVALID%(InfVersion), LineInfo=self.CurrentLine) return False + self.InfVersion = InfDefMember() + self.InfVersion.SetValue(InfVersion) + self.InfVersion.Comments = Comments + return True + ## GetInfVersion # def GetInfVersion(self): @@ -1000,4 +1005,4 @@ def SetDefines(self, DefineContent, Arch = None): def GetDefines(self): return self.Defines - \ No newline at end of file + diff --git a/BaseTools/Source/Python/UPT/Parser/DecParser.py b/BaseTools/Source/Python/UPT/Parser/DecParser.py index 25407f9a2d50..23d1ed4dbb23 100644 --- a/BaseTools/Source/Python/UPT/Parser/DecParser.py +++ b/BaseTools/Source/Python/UPT/Parser/DecParser.py @@ -29,6 +29,7 @@ from Library.ParserValidate import IsValidUserId from Library.ParserValidate import IsValidArch from Library.ParserValidate import IsValidWord +from Library.ParserValidate import IsValidDecVersionVal from Parser.DecParserMisc import TOOL_NAME from Parser.DecParserMisc import CleanString from Parser.DecParserMisc import IsValidPcdDatum @@ -452,7 +453,8 @@ def _SetDecSpecification(self, Token): if self.ItemObject.GetPackageSpecification(): self._LoggerError(ST.ERR_DECPARSE_DEFINE_DEFINED % DT.TAB_DEC_DEFINES_DEC_SPECIFICATION) if not IsValidToken('0[xX][0-9a-fA-F]{8}', Token): - self._LoggerError(ST.ERR_DECPARSE_DEFINE_SPEC) + if not IsValidDecVersionVal(Token): + self._LoggerError(ST.ERR_DECPARSE_DEFINE_SPEC) self.ItemObject.SetPackageSpecification(Token) def _SetPackageName(self, Token): From b6274a7a7890953c9906b12755fcee78330a02f2 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Tue, 1 Dec 2015 02:31:39 +0000 Subject: [PATCH 187/525] BaseTools/GenFw ARM: allow R_ARM_REL32 relocations R_ARM_REL32 are relative relocations, so we don't need to do anything special when performing the ELF to PE/COFF conversion, since our memory layout is identical between the two binary formats. So just allow them. (Sync patch r18931 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ard Biesheuvel Reviewed-by: Liming Gao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19076 6f19259b-4bc3-4df7-8a09-765794883524 --- BaseTools/Source/C/GenFw/Elf32Convert.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/BaseTools/Source/C/GenFw/Elf32Convert.c b/BaseTools/Source/C/GenFw/Elf32Convert.c index a7b077873b40..469394540e6a 100644 --- a/BaseTools/Source/C/GenFw/Elf32Convert.c +++ b/BaseTools/Source/C/GenFw/Elf32Convert.c @@ -716,6 +716,7 @@ WriteSections32 ( // break skipped case R_ARM_PC24: + case R_ARM_REL32: case R_ARM_XPC25: case R_ARM_THM_PC22: case R_ARM_THM_JUMP19: @@ -844,6 +845,7 @@ WriteRelocations32 ( // break skipped case R_ARM_PC24: + case R_ARM_REL32: case R_ARM_XPC25: case R_ARM_THM_PC22: case R_ARM_THM_JUMP19: From e07c30da128c51eda38857f29689c5ec07ac6773 Mon Sep 17 00:00:00 2001 From: Yonghong Zhu Date: Tue, 1 Dec 2015 02:32:08 +0000 Subject: [PATCH 188/525] BaseTools: Add a VPD report subsection of FLASH to the Report Build Spec already added a VPD report subsection of FLASH to the Report chapter, it provide a simple way for user to determine where the VPD region and VPD PCDs are located in the fd file. (Sync patch r19026 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Yonghong Zhu Reviewed-by: Liming Gao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19077 6f19259b-4bc3-4df7-8a09-765794883524 --- BaseTools/Source/Python/build/BuildReport.py | 35 ++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/BaseTools/Source/Python/build/BuildReport.py b/BaseTools/Source/Python/build/BuildReport.py index 264607b00360..d64c55d08bc1 100644 --- a/BaseTools/Source/Python/build/BuildReport.py +++ b/BaseTools/Source/Python/build/BuildReport.py @@ -1385,6 +1385,32 @@ def __init__(self, Fd, Wa): self.BaseAddress = Fd.BaseAddress self.Size = Fd.Size self.FdRegionList = [FdRegionReport(FdRegion, Wa) for FdRegion in Fd.RegionList] + self.FvPath = os.path.join(Wa.BuildDir, "FV") + self.VpdFilePath = os.path.join(self.FvPath, "%s.map" % Wa.Platform.VpdToolGuid) + VpdPcdToken = 'gEfiMdeModulePkgTokenSpaceGuid' + VpdPcdName = 'PcdVpdBaseAddress' + self.VPDInfoList = [] + for index, FdRegion in enumerate(Fd.RegionList): + if (VpdPcdName, VpdPcdToken) == FdRegion.PcdOffset: + self.VPDBaseAddress = self.FdRegionList[index].BaseAddress + self.VPDSize = self.FdRegionList[index].Size + break + + if os.path.isfile(self.VpdFilePath): + fd = open(self.VpdFilePath, "r") + Lines = fd.readlines() + for Line in Lines: + Line = Line.strip() + if len(Line) == 0 or Line.startswith("#"): + continue + try: + PcdName, SkuId, Offset, Size, Value = Line.split("#")[0].split("|") + PcdName, SkuId, Offset, Size, Value = PcdName.strip(), SkuId.strip(), Offset.strip(), Size.strip(), Value.strip() + Offset = '0x%08X' % (int(Offset, 16) + self.VPDBaseAddress) + self.VPDInfoList.append("%s | %s | %s | %s | %s" % (PcdName, SkuId, Offset, Size, Value)) + except: + EdkLogger.error("BuildReport", CODE_ERROR, "Fail to parse VPD information file %s" % self.VpdFilePath) + fd.close() ## # Generate report for the firmware device. @@ -1405,6 +1431,15 @@ def GenerateReport(self, File): for FdRegionItem in self.FdRegionList: FdRegionItem.GenerateReport(File) + if len(self.VPDInfoList) > 0: + FileWrite(File, gSubSectionStart) + FileWrite(File, "FD VPD Region") + FileWrite(File, "Base Address: 0x%X" % self.VPDBaseAddress) + FileWrite(File, "Size: 0x%X (%.0fK)" % (self.VPDSize, self.VPDSize / 1024.0)) + FileWrite(File, gSubSectionSep) + for item in self.VPDInfoList: + FileWrite(File, item) + FileWrite(File, gSubSectionEnd) FileWrite(File, gSectionEnd) From f80a15c236a8c433c6dd78f9796794d9f3b36e5c Mon Sep 17 00:00:00 2001 From: Yonghong Zhu Date: Tue, 1 Dec 2015 02:32:33 +0000 Subject: [PATCH 189/525] BaseTools: Add build error detection for Dynamic PCD name conflict when multiple Dynamic PCD have different token space guid but same PCD name, it is difficult for user to check why the generated autogen.c and autogen.h are not consistent. so we add a check before generating autogen.c and report error directly that user can know what happened immediately. (Sync patch r19027 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Yonghong Zhu Reviewed-by: Liming Gao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19078 6f19259b-4bc3-4df7-8a09-765794883524 --- BaseTools/Source/Python/AutoGen/GenC.py | 52 +++++++++++++++++-------- 1 file changed, 36 insertions(+), 16 deletions(-) diff --git a/BaseTools/Source/Python/AutoGen/GenC.py b/BaseTools/Source/Python/AutoGen/GenC.py index 45fb9899f2c2..93be71885097 100644 --- a/BaseTools/Source/Python/AutoGen/GenC.py +++ b/BaseTools/Source/Python/AutoGen/GenC.py @@ -833,7 +833,7 @@ def CreateModulePcdCode(Info, AutoGenC, AutoGenH, Pcd): AutoGenH.Append('// Disabled the macros, as PcdToken and PcdGet/Set are not allowed in the case that more than one DynamicEx Pcds are different Guids but same CName.\n') AutoGenH.Append('// #define %s %s\n' % (PcdTokenName, PcdExTokenName)) AutoGenH.Append('// #define %s LibPcdGetEx%s(&%s, %s)\n' % (GetModeName, DatumSizeLib, Pcd.TokenSpaceGuidCName, PcdTokenName)) - AutoGenH.Append('#define %s LibPcdGetExSize(&%s, %s)\n' % (GetModeSizeName,Pcd.TokenSpaceGuidCName, PcdTokenName)) + AutoGenH.Append('// #define %s LibPcdGetExSize(&%s, %s)\n' % (GetModeSizeName,Pcd.TokenSpaceGuidCName, PcdTokenName)) if Pcd.DatumType == 'VOID*': AutoGenH.Append('// #define %s(SizeOfBuffer, Buffer) LibPcdSetEx%s(&%s, %s, (SizeOfBuffer), (Buffer))\n' % (SetModeName, DatumSizeLib, Pcd.TokenSpaceGuidCName, PcdTokenName)) AutoGenH.Append('// #define %s(SizeOfBuffer, Buffer) LibPcdSetEx%sS(&%s, %s, (SizeOfBuffer), (Buffer))\n' % (SetModeStatusName, DatumSizeLib, Pcd.TokenSpaceGuidCName, PcdTokenName)) @@ -851,14 +851,24 @@ def CreateModulePcdCode(Info, AutoGenC, AutoGenH, Pcd): AutoGenH.Append('#define %s(Value) LibPcdSetEx%s(&%s, %s, (Value))\n' % (SetModeName, DatumSizeLib, Pcd.TokenSpaceGuidCName, PcdTokenName)) AutoGenH.Append('#define %s(Value) LibPcdSetEx%sS(&%s, %s, (Value))\n' % (SetModeStatusName, DatumSizeLib, Pcd.TokenSpaceGuidCName, PcdTokenName)) elif Pcd.Type in gDynamicPcd: - AutoGenH.Append('#define %s LibPcdGet%s(%s)\n' % (GetModeName, DatumSizeLib, PcdTokenName)) - AutoGenH.Append('#define %s LibPcdGetSize(%s)\n' % (GetModeSizeName, PcdTokenName)) - if Pcd.DatumType == 'VOID*': - AutoGenH.Append('#define %s(SizeOfBuffer, Buffer) LibPcdSet%s(%s, (SizeOfBuffer), (Buffer))\n' %(SetModeName, DatumSizeLib, PcdTokenName)) - AutoGenH.Append('#define %s(SizeOfBuffer, Buffer) LibPcdSet%sS(%s, (SizeOfBuffer), (Buffer))\n' % (SetModeStatusName, DatumSizeLib, PcdTokenName)) + PcdList = [] + PcdCNameList = [] + PcdList.extend(Info.LibraryPcdList) + PcdList.extend(Info.ModulePcdList) + for PcdModule in PcdList: + if PcdModule.Type in gDynamicPcd: + PcdCNameList.append(PcdModule.TokenCName) + if PcdCNameList.count(Pcd.TokenCName) > 1: + EdkLogger.error("build", AUTOGEN_ERROR, "More than one Dynamic Pcds [%s] are different Guids but same CName. They need to be changed to DynamicEx type to avoid the confliction.\n" % (Pcd.TokenCName), ExtraData="[%s]" % str(Info.MetaFile.Path)) else: - AutoGenH.Append('#define %s(Value) LibPcdSet%s(%s, (Value))\n' % (SetModeName, DatumSizeLib, PcdTokenName)) - AutoGenH.Append('#define %s(Value) LibPcdSet%sS(%s, (Value))\n' % (SetModeStatusName, DatumSizeLib, PcdTokenName)) + AutoGenH.Append('#define %s LibPcdGet%s(%s)\n' % (GetModeName, DatumSizeLib, PcdTokenName)) + AutoGenH.Append('#define %s LibPcdGetSize(%s)\n' % (GetModeSizeName, PcdTokenName)) + if Pcd.DatumType == 'VOID*': + AutoGenH.Append('#define %s(SizeOfBuffer, Buffer) LibPcdSet%s(%s, (SizeOfBuffer), (Buffer))\n' %(SetModeName, DatumSizeLib, PcdTokenName)) + AutoGenH.Append('#define %s(SizeOfBuffer, Buffer) LibPcdSet%sS(%s, (SizeOfBuffer), (Buffer))\n' % (SetModeStatusName, DatumSizeLib, PcdTokenName)) + else: + AutoGenH.Append('#define %s(Value) LibPcdSet%s(%s, (Value))\n' % (SetModeName, DatumSizeLib, PcdTokenName)) + AutoGenH.Append('#define %s(Value) LibPcdSet%sS(%s, (Value))\n' % (SetModeStatusName, DatumSizeLib, PcdTokenName)) else: PcdVariableName = '_gPcd_' + gItemTypeStringDatabase[Pcd.Type] + '_' + Pcd.TokenCName Const = 'const' @@ -1111,7 +1121,7 @@ def CreateLibraryPcdCode(Info, AutoGenC, AutoGenH, Pcd): AutoGenH.Append('// Disabled the macros, as PcdToken and PcdGet/Set are not allowed in the case that more than one DynamicEx Pcds are different Guids but same CName.\n') AutoGenH.Append('// #define %s %s\n' % (PcdTokenName, PcdExTokenName)) AutoGenH.Append('// #define %s LibPcdGetEx%s(&%s, %s)\n' % (GetModeName, DatumSizeLib, Pcd.TokenSpaceGuidCName, PcdTokenName)) - AutoGenH.Append('// #define %s LibPcdGetExSize(&%s, %s \n' % (GetModeSizeName,Pcd.TokenSpaceGuidCName, PcdTokenName)) + AutoGenH.Append('// #define %s LibPcdGetExSize(&%s, %s \n' % (GetModeSizeName,Pcd.TokenSpaceGuidCName, PcdTokenName)) if Pcd.DatumType == 'VOID*': AutoGenH.Append('// #define %s(SizeOfBuffer, Buffer) LibPcdSetEx%s(&%s, %s, (SizeOfBuffer), (Buffer))\n' % (SetModeName, DatumSizeLib, Pcd.TokenSpaceGuidCName, PcdTokenName)) AutoGenH.Append('// #define %s(SizeOfBuffer, Buffer) LibPcdSetEx%sS(&%s, %s, (SizeOfBuffer), (Buffer))\n' % (SetModeStatusName, DatumSizeLib, Pcd.TokenSpaceGuidCName, PcdTokenName)) @@ -1131,14 +1141,24 @@ def CreateLibraryPcdCode(Info, AutoGenC, AutoGenH, Pcd): else: AutoGenH.Append('#define _PCD_TOKEN_%s %dU\n' % (TokenCName, TokenNumber)) if PcdItemType in gDynamicPcd: - AutoGenH.Append('#define %s LibPcdGet%s(%s)\n' % (GetModeName, DatumSizeLib, PcdTokenName)) - AutoGenH.Append('#define %s LibPcdGetSize(%s)\n' % (GetModeSizeName, PcdTokenName)) - if DatumType == 'VOID*': - AutoGenH.Append('#define %s(SizeOfBuffer, Buffer) LibPcdSet%s(%s, (SizeOfBuffer), (Buffer))\n' %(SetModeName, DatumSizeLib, PcdTokenName)) - AutoGenH.Append('#define %s(SizeOfBuffer, Buffer) LibPcdSet%sS(%s, (SizeOfBuffer), (Buffer))\n' % (SetModeStatusName, DatumSizeLib, PcdTokenName)) + PcdList = [] + PcdCNameList = [] + PcdList.extend(Info.LibraryPcdList) + PcdList.extend(Info.ModulePcdList) + for PcdModule in PcdList: + if PcdModule.Type in gDynamicPcd: + PcdCNameList.append(PcdModule.TokenCName) + if PcdCNameList.count(Pcd.TokenCName) > 1: + EdkLogger.error("build", AUTOGEN_ERROR, "More than one Dynamic Pcds [%s] are different Guids but same CName.They need to be changed to DynamicEx type to avoid the confliction.\n" % (Pcd.TokenCName), ExtraData="[%s]" % str(Info.MetaFile.Path)) else: - AutoGenH.Append('#define %s(Value) LibPcdSet%s(%s, (Value))\n' % (SetModeName, DatumSizeLib, PcdTokenName)) - AutoGenH.Append('#define %s(Value) LibPcdSet%sS(%s, (Value))\n' % (SetModeStatusName, DatumSizeLib, PcdTokenName)) + AutoGenH.Append('#define %s LibPcdGet%s(%s)\n' % (GetModeName, DatumSizeLib, PcdTokenName)) + AutoGenH.Append('#define %s LibPcdGetSize(%s)\n' % (GetModeSizeName, PcdTokenName)) + if DatumType == 'VOID*': + AutoGenH.Append('#define %s(SizeOfBuffer, Buffer) LibPcdSet%s(%s, (SizeOfBuffer), (Buffer))\n' %(SetModeName, DatumSizeLib, PcdTokenName)) + AutoGenH.Append('#define %s(SizeOfBuffer, Buffer) LibPcdSet%sS(%s, (SizeOfBuffer), (Buffer))\n' % (SetModeStatusName, DatumSizeLib, PcdTokenName)) + else: + AutoGenH.Append('#define %s(Value) LibPcdSet%s(%s, (Value))\n' % (SetModeName, DatumSizeLib, PcdTokenName)) + AutoGenH.Append('#define %s(Value) LibPcdSet%sS(%s, (Value))\n' % (SetModeStatusName, DatumSizeLib, PcdTokenName)) if PcdItemType == TAB_PCDS_PATCHABLE_IN_MODULE: PcdVariableName = '_gPcd_' + gItemTypeStringDatabase[TAB_PCDS_PATCHABLE_IN_MODULE] + '_' + TokenCName AutoGenH.Append('extern volatile %s _gPcd_BinaryPatch_%s%s;\n' %(DatumType, TokenCName, Array) ) From 955b2d2e7b446488bb9333910e440c0b0f09f78e Mon Sep 17 00:00:00 2001 From: Jeff Fan Date: Tue, 1 Dec 2015 02:36:56 +0000 Subject: [PATCH 190/525] External link to BaseTools Win binary r107(main trunk r19027) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19079 6f19259b-4bc3-4df7-8a09-765794883524 From 76c092589ed74931ece00e3505979d80042f7b50 Mon Sep 17 00:00:00 2001 From: Jeff Fan Date: Tue, 1 Dec 2015 06:13:41 +0000 Subject: [PATCH 191/525] Sync the files in root dirctory from main trunk r19027. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19081 6f19259b-4bc3-4df7-8a09-765794883524 --- Edk2Setup.bat | 64 ++++++++++++++++++++++++++++++++++++------------- Maintainers.txt | 3 ++- edksetup.bat | 30 +++++++++++++++++++---- edksetup.sh | 19 ++++++++++++--- 4 files changed, 91 insertions(+), 25 deletions(-) diff --git a/Edk2Setup.bat b/Edk2Setup.bat index 0aa786d9ab94..2d132349bc32 100755 --- a/Edk2Setup.bat +++ b/Edk2Setup.bat @@ -62,14 +62,33 @@ @if not defined ORIGINAL_PATH set "ORIGINAL_PATH=%PATH%" @REM Always set the WORKSPACE environment variable to the current directory -@set "WORKSPACE=%CD%" -@if exist "%WORKSPACE%\BaseTools" @set "BASE_TOOLS_PATH=%WORKSPACE%\BaseTools" +@if not defined WORKSPACE ( + @set "WORKSPACE=%CD%" +) +@if not exist "%BASE_TOOLS_PATH%" ( + @if exist "%WORKSPACE%\BaseTools" ( + set "BASE_TOOLS_PATH=%WORKSPACE%\BaseTools" + ) else ( + @if defined PACKAGES_PATH ( + @for %%i IN (%PACKAGES_PATH%) DO ( + @if exist %%~fi\BaseTools ( + @set BASE_TOOLS_PATH=%%~fi\BaseTools + @goto checkBaseTools + ) + ) + ) + ) +) +:checkBaseTools +@if not defined BASE_TOOLS_PATH ( + @echo. + @echo !!! ERROR !!! The BaseTools Package was not found !!! + @echo. + @goto ExitFailure +) @if not exist "%WORKSPACE%\Conf" @mkdir "%WORKSPACE%\Conf" -@@if not defined EDK_TOOLS_PATH @set "EDK_TOOLS_PATH=%WORKSPACE%\BaseTools" -@rem @set "PATH=%WORKSPACE%\BaseTools\Bin\Win32;%PATH%" -@rem @set WORKSPACE_TOOLS_PATH=%WORKSPACE%\BaseTools -@rem ) +@@if not defined EDK_TOOLS_PATH @set "EDK_TOOLS_PATH=%BASE_TOOLS_PATH%" @REM Keep the existing EDK_TOOLS_PATH value, the --reset flag will set it @REM back to WORKSPACE\BaseTools while the --location DIRECTORY flag will @@ -259,7 +278,7 @@ @echo %SCRIPT_NAME% Version: %SCRIPT_VERSION%%SVN_REVISION:~11,-1% @echo Copyright(c) 2014, Intel Corporation. All rights reserved. @set HIDE_PATH=TRUE -@call "%WORKSPACE%\BaseTools\Scripts\ShowEnvironment.bat" +@call "%BASE_TOOLS_PATH%\Scripts\ShowEnvironment.bat" @set HIDE_PATH= @goto ExitSuccess @@ -352,8 +371,8 @@ @REM copied or replaced from the WORKSPACE\BaseTools\Conf directories' template files. :SetConf @if not exist "%EDK_TOOLS_PATH%\Conf" ( - @if exist "%WORKSPACE%\BaseTools\Conf" ( - @set "SRC_CONF=%WORKSPACE%\BaseTools\Conf" + @if exist "%BASE_TOOLS_PATH%\Conf" ( + @set "SRC_CONF=%BASE_TOOLS_PATH%\Conf" ) ) else ( @set "SRC_CONF=%EDK_TOOLS_PATH%\Conf" @@ -365,7 +384,7 @@ @REM The script will test to see if the files exist, and also use the RESET_ENVIRONMENT flag @REM to overwrite the WORKSPACE\Conf *.txt files. -@call "%WORKSPACE%\BaseTools\Scripts\ShowEnvironment.bat" +@call "%BASE_TOOLS_PATH%\Scripts\ShowEnvironment.bat" @if errorlevel 1 ( @echo Unable to copy the template files from "%SRC_CONF%" to "%WORKSPACE%\Conf" @goto ExitFailure @@ -375,22 +394,34 @@ @REM Set up Visual Studio if required to build the Nt32Pkg/Nt32Pkg.dsc emulator @if "%NT32PKG%"=="TRUE" ( @if not defined VSINSTALLDIR @set "PATH=%ORIGINAL_PATH%" - @if not defined NT32_X64 @call "%WORKSPACE%\BaseTools\get_vsvars.bat" - @if defined NT32_X64 call "%WORKSPACE%\BaseTools\Scripts\SetVisualStudio.bat" + @if not defined NT32_X64 @call "%BASE_TOOLS_PATH%\get_vsvars.bat" + @if defined NT32_X64 call "%BASE_TOOLS_PATH%\Scripts\SetVisualStudio.bat" ) @if "%NT32PKG%"=="TRUE" ( @if not defined VS_PATH set "VS_PATH=%PATH%" ) @if defined VS_PATH @set "PATH=%VS_PATH%" @if not defined VS_PATH @set "PATH=%ORIGINAL_PATH%" -@set "PATH=%EDK_TOOLS_PATH%\Bin\Win32;%PATH%" +@if not defined EDK_TOOLS_BIN ( + @if exist %EDK_TOOLS_PATH%\Bin\Win32 ( + @set EDK_TOOLS_BIN=%EDK_TOOLS_PATH%\Bin\Win32 + ) else ( + @echo. + @echo !!! ERROR !!! Cannot find BaseTools Bin Win32!!! + @echo Please check the directory %EDK_TOOLS_PATH%\Bin\Win32 + @echo Or configure EDK_TOOLS_BIN env to point Win32 directory. + @echo. + @goto ExitFailure + ) +) +@set "PATH=%EDK_TOOLS_BIN%;%PATH%" @if "%REBUILD_TOOLS%"=="TRUE" @goto Rebuild @if "%SVN_PULL%"== "TRUE" ( if defined PYTHONHOME ( @REM Use the python script if possible to test is the svn command is available, if it fails, the user may be @REM able to rebuild the Win32 binaries - @call "%WORKSPACE%\BaseTools\Scripts\UpdateBuildVersions.py" --svn-test -v + @call "%BASE_TOOLS_PATH%\Scripts\UpdateBuildVersions.py" --svn-test -v @if errorlevel 1 ( @echo ERROR : The command-line svn tool is not available and the Win32 binaries do not exist @echo Please re-run this script again with the --rebuild option to attempt to build @@ -417,7 +448,6 @@ @REM The following code is used to rebuild the Win32 BaseTools binaries - check that required tools are available :Rebuild -@if not defined BASE_TOOLS_PATH @set "BASE_TOOLS_PATH=%WORKSPACE%\BaseTools" @if not exist "%BASE_TOOLS_PATH%\Source" @goto NoBaseTools @endlocal @if not defined VCINSTALLDIR @goto NoVisualStudio @@ -430,11 +460,11 @@ @if not exist "%PYTHONHOME%\Scripts\cxfreeze.bat" @goto NoCxFreeze @set "PYTHON_FREEZER_PATH=%PYTHONHOME%\Scripts" ) -@call "%WORKSPACE%\BaseTools\Scripts\SetVisualStudio.bat" +@call "%BASE_TOOLS_PATH%\Scripts\SetVisualStudio.bat" @if errorlevel 1 @goto ExitFailure :ShowAndExit -@call "%WORKSPACE%\BaseTools\Scripts\ShowEnvironment.bat" +@call "%BASE_TOOLS_PATH%\Scripts\ShowEnvironment.bat" @REM ######################################################################################### @REM EXIT ROUTINES diff --git a/Maintainers.txt b/Maintainers.txt index 1a073141033a..acb717e03a07 100644 --- a/Maintainers.txt +++ b/Maintainers.txt @@ -68,7 +68,8 @@ M: Ard Biesheuvel BaseTools W: https://github.com/tianocore/tianocore.github.io/wiki/BaseTools -M: Yingke D Liu +M: Yonghong Zhu +M: Liming Gao BeagleBoardPkg W: https://github.com/tianocore/tianocore.github.io/wiki/BeagleBoardPkg diff --git a/edksetup.bat b/edksetup.bat index 25a5a6e8d7e3..b63c29916b06 100755 --- a/edksetup.bat +++ b/edksetup.bat @@ -42,9 +42,11 @@ if %WORKSPACE% == %CD% ( :SetWorkSpace @REM set new workspace @REM clear EFI_SOURCE and EDK_SOURCE for the new workspace -set WORKSPACE=%CD% -set EFI_SOURCE= -set EDK_SOURCE= +if not defined WORKSPACE ( + set WORKSPACE=%CD% + set EFI_SOURCE= + set EDK_SOURCE= +) :ParseArgs if /I "%1"=="-h" goto Usage @@ -92,8 +94,28 @@ if not defined VCINSTALLDIR ( shift :no_nt32 + if /I "%1"=="NewBuild" shift -set EDK_TOOLS_PATH=%WORKSPACE%\BaseTools +if exist %WORKSPACE%\BaseTools ( + set EDK_TOOLS_PATH=%WORKSPACE%\BaseTools +) else ( + if defined PACKAGES_PATH ( + for %%i IN (%PACKAGES_PATH%) DO ( + if exist %%~fi\BaseTools ( + set EDK_TOOLS_PATH=%%~fi\BaseTools + goto checkBaseTools + ) + ) + ) else ( + echo. + echo !!! ERROR !!! Cannot find BaseTools !!! + echo. + goto BadBaseTools + ) +) +if exist %EDK_TOOLS_PATH%\Source set BASE_TOOLS_PATH=%EDK_TOOLS_PATH% + +:checkBaseTools IF NOT EXIST "%EDK_TOOLS_PATH%\toolsetup.bat" goto BadBaseTools call %EDK_TOOLS_PATH%\toolsetup.bat %* if /I "%1"=="Reconfig" shift diff --git a/edksetup.sh b/edksetup.sh index 64795c48d274..57368b56afac 100755 --- a/edksetup.sh +++ b/edksetup.sh @@ -1,5 +1,5 @@ # -# Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
+# Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
# This program and the accompanying materials # are licensed and made available under the terms and conditions of the BSD License # which accompanies this distribution. The full text of the license may be found at @@ -78,10 +78,23 @@ function SetupEnv() elif [ -f "$WORKSPACE/BaseTools/BuildEnv" ] then . $WORKSPACE/BaseTools/BuildEnv $* + elif [ -n "$PACKAGES_PATH" ] + then + PATH_LIST=$PACKAGES_PATH + PATH_LIST=${PATH_LIST//:/ } + for DIR in $PATH_LIST + do + if [ -f "$DIR/BaseTools/BuildEnv" ] + then + export EDK_TOOLS_PATH=$DIR/BaseTools + . $DIR/BaseTools/BuildEnv $* + break + fi + done else echo BaseTools not found in your tree, and EDK_TOOLS_PATH is not set. - echo Please check that WORKSPACE is not set incorrectly in your - echo shell, or point EDK_TOOLS_PATH at the directory that contains + echo Please check that WORKSPACE or PACKAGES_PATH is not set incorrectly + echo in your shell, or point EDK_TOOLS_PATH at the directory that contains echo the EDK2 BuildEnv script. return 1 fi From cbf0366ac7df84a768b173b730526c6282d751c8 Mon Sep 17 00:00:00 2001 From: Jeff Fan Date: Wed, 2 Dec 2015 03:24:17 +0000 Subject: [PATCH 192/525] UefiCpuPkg/CpuMpPei: Exchange whole CPU data in SortApicId() Current implementation only exchanges the APIC ID and BIST, this updating is to exchange all CPU data. (Sync patch r19085 from main trunk.) Cc: Feng Tian Cc: Michael Kinney Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan Reviewed-by: Feng Tian git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19091 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/CpuMpPei/CpuMpPei.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.c b/UefiCpuPkg/CpuMpPei/CpuMpPei.c index c22252220316..ae071ac1f81a 100644 --- a/UefiCpuPkg/CpuMpPei/CpuMpPei.c +++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.c @@ -61,7 +61,7 @@ SortApicId ( UINTN Index2; UINTN Index3; UINT32 ApicId; - EFI_HEALTH_FLAGS Health; + PEI_CPU_DATA CpuData; UINT32 ApCount; ApCount = PeiCpuMpData->CpuCount - 1; @@ -80,11 +80,13 @@ SortApicId ( } } if (Index3 != Index1) { - PeiCpuMpData->CpuData[Index3].ApicId = PeiCpuMpData->CpuData[Index1].ApicId; - PeiCpuMpData->CpuData[Index1].ApicId = ApicId; - Health = PeiCpuMpData->CpuData[Index3].Health; - PeiCpuMpData->CpuData[Index3].Health = PeiCpuMpData->CpuData[Index1].Health; - PeiCpuMpData->CpuData[Index1].Health = Health; + CopyMem (&CpuData, &PeiCpuMpData->CpuData[Index3], sizeof (PEI_CPU_DATA)); + CopyMem ( + &PeiCpuMpData->CpuData[Index3], + &PeiCpuMpData->CpuData[Index1], + sizeof (PEI_CPU_DATA) + ); + CopyMem (&PeiCpuMpData->CpuData[Index1], &CpuData, sizeof (PEI_CPU_DATA)); } } From 3e77391057f37d540254e7a388764d8057cbf9b6 Mon Sep 17 00:00:00 2001 From: Jeff Fan Date: Wed, 2 Dec 2015 03:24:52 +0000 Subject: [PATCH 193/525] UefiCpuPkg/CpuMpPei: Add CPU_VOLATILE_REGISTERS & worker functions Add CPU_VOLATILE_REGISTERS definitions for CRx and DRx required to be restored after APs received INIT IPI. Add worker functions SaveVolatileRegisters()/RestoreVolatileRegisters() used to save/restore CRx and DRx. It also check if Debugging Extensions supported or not. (Sync patch r19086 from main trunk.) Cc: Feng Tian Cc: Michael Kinney Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan Reviewed-by: Feng Tian git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19092 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/CpuMpPei/CpuMpPei.c | 67 ++++++++++++++++++++++++++++++++++ UefiCpuPkg/CpuMpPei/CpuMpPei.h | 13 +++++++ 2 files changed, 80 insertions(+) diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.c b/UefiCpuPkg/CpuMpPei/CpuMpPei.c index ae071ac1f81a..7bedf6421091 100644 --- a/UefiCpuPkg/CpuMpPei/CpuMpPei.c +++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.c @@ -141,6 +141,73 @@ GetMpHobData ( return CpuMpData; } +/** + Save the volatile registers required to be restored following INIT IPI + + @param VolatileRegisters Returns buffer saved the volatile resisters +**/ +VOID +SaveVolatileRegisters ( + OUT CPU_VOLATILE_REGISTERS *VolatileRegisters + ) +{ + UINT32 RegEdx; + + VolatileRegisters->Cr0 = AsmReadCr0 (); + VolatileRegisters->Cr3 = AsmReadCr3 (); + VolatileRegisters->Cr4 = AsmReadCr4 (); + + AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &RegEdx); + if ((RegEdx & BIT2) != 0) { + // + // If processor supports Debugging Extensions feature + // by CPUID.[EAX=01H]:EDX.BIT2 + // + VolatileRegisters->Dr0 = AsmReadDr0 (); + VolatileRegisters->Dr1 = AsmReadDr1 (); + VolatileRegisters->Dr2 = AsmReadDr2 (); + VolatileRegisters->Dr3 = AsmReadDr3 (); + VolatileRegisters->Dr6 = AsmReadDr6 (); + VolatileRegisters->Dr7 = AsmReadDr7 (); + } +} + +/** + Restore the volatile registers following INIT IPI + + @param VolatileRegisters Pointer to volatile resisters + @param IsRestoreDr TRUE: Restore DRx if supported + FALSE: Do not restore DRx +**/ +VOID +RestoreVolatileRegisters ( + IN CPU_VOLATILE_REGISTERS *VolatileRegisters, + IN BOOLEAN IsRestoreDr + ) +{ + UINT32 RegEdx; + + AsmWriteCr0 (VolatileRegisters->Cr0); + AsmWriteCr3 (VolatileRegisters->Cr3); + AsmWriteCr4 (VolatileRegisters->Cr4); + + if (IsRestoreDr) { + AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &RegEdx); + if ((RegEdx & BIT2) != 0) { + // + // If processor supports Debugging Extensions feature + // by CPUID.[EAX=01H]:EDX.BIT2 + // + AsmWriteDr0 (VolatileRegisters->Dr0); + AsmWriteDr1 (VolatileRegisters->Dr1); + AsmWriteDr2 (VolatileRegisters->Dr2); + AsmWriteDr3 (VolatileRegisters->Dr3); + AsmWriteDr6 (VolatileRegisters->Dr6); + AsmWriteDr7 (VolatileRegisters->Dr7); + } + } +} + /** This function will be called from AP reset code if BSP uses WakeUpAP. diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.h b/UefiCpuPkg/CpuMpPei/CpuMpPei.h index de9011329c08..f2286b990ee9 100644 --- a/UefiCpuPkg/CpuMpPei/CpuMpPei.h +++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.h @@ -113,11 +113,24 @@ typedef struct { #pragma pack() +typedef struct { + UINTN Cr0; + UINTN Cr3; + UINTN Cr4; + UINTN Dr0; + UINTN Dr1; + UINTN Dr2; + UINTN Dr3; + UINTN Dr6; + UINTN Dr7; +} CPU_VOLATILE_REGISTERS; + typedef struct { UINT32 ApicId; EFI_HEALTH_FLAGS Health; CPU_STATE State; BOOLEAN CpuHealthy; + CPU_VOLATILE_REGISTERS VolatileRegisters; } PEI_CPU_DATA; // From cfe8be0f32d945a6b3cdc9096bfe11f50bb09447 Mon Sep 17 00:00:00 2001 From: Jeff Fan Date: Wed, 2 Dec 2015 03:25:21 +0000 Subject: [PATCH 194/525] UefiCpuPkg/CpuMpPei: Set AP state to CpuStateIdle after initialization (Sync patch r19087 from main trunk.) Cc: Feng Tian Cc: Michael Kinney Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan Reviewed-by: Feng Tian git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19093 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/CpuMpPei/CpuMpPei.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.c b/UefiCpuPkg/CpuMpPei/CpuMpPei.c index 7bedf6421091..d058d143ced7 100644 --- a/UefiCpuPkg/CpuMpPei/CpuMpPei.c +++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.c @@ -228,13 +228,14 @@ ApCFunction ( PeiCpuMpData = ExchangeInfo->PeiCpuMpData; if (PeiCpuMpData->InitFlag) { + ProcessorNumber = NumApsExecuting; // // This is first time AP wakeup, get BIST information from AP stack // - BistData = *(UINTN *) (PeiCpuMpData->Buffer + NumApsExecuting * PeiCpuMpData->CpuApStackSize - sizeof (UINTN)); - PeiCpuMpData->CpuData[NumApsExecuting].Health.Uint32 = (UINT32) BistData; - PeiCpuMpData->CpuData[NumApsExecuting].ApicId = GetInitialApicId (); - if (PeiCpuMpData->CpuData[NumApsExecuting].ApicId >= 0xFF) { + BistData = *(UINTN *) (PeiCpuMpData->Buffer + ProcessorNumber * PeiCpuMpData->CpuApStackSize - sizeof (UINTN)); + PeiCpuMpData->CpuData[ProcessorNumber].Health.Uint32 = (UINT32) BistData; + PeiCpuMpData->CpuData[ProcessorNumber].ApicId = GetInitialApicId (); + if (PeiCpuMpData->CpuData[ProcessorNumber].ApicId >= 0xFF) { // // Set x2APIC mode if there are any logical processor reporting // an APIC ID of 255 or greater. @@ -248,6 +249,7 @@ ApCFunction ( // MtrrSetAllMtrrs (&PeiCpuMpData->MtrrTable); MicrocodeDetect (); + PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateIdle; } else { // // Execute AP function if AP is not disabled From 5bdb31378999f8a061427a8903b469cf1d02b72e Mon Sep 17 00:00:00 2001 From: Jeff Fan Date: Wed, 2 Dec 2015 03:25:45 +0000 Subject: [PATCH 195/525] UefiCpuPkg/CpuMpPei: Sync BSP's CRx to APs when initialization Save BSP's volatile register and sync CRx register to APs when AP 1st wake up. (Sync patch r19088 from main trunk.) Cc: Feng Tian Cc: Michael Kinney Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan Reviewed-by: Feng Tian git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19094 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/CpuMpPei/CpuMpPei.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.c b/UefiCpuPkg/CpuMpPei/CpuMpPei.c index d058d143ced7..53af9489b2db 100644 --- a/UefiCpuPkg/CpuMpPei/CpuMpPei.c +++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.c @@ -230,6 +230,10 @@ ApCFunction ( if (PeiCpuMpData->InitFlag) { ProcessorNumber = NumApsExecuting; // + // Sync BSP's Control registers to APs + // + RestoreVolatileRegisters (&PeiCpuMpData->CpuData[0].VolatileRegisters, FALSE); + // // This is first time AP wakeup, get BIST information from AP stack // BistData = *(UINTN *) (PeiCpuMpData->Buffer + ProcessorNumber * PeiCpuMpData->CpuApStackSize - sizeof (UINTN)); @@ -560,6 +564,7 @@ PrepareAPStartupVector ( PeiCpuMpData->CpuData[0].Health.Uint32 = 0; PeiCpuMpData->EndOfPeiFlag = FALSE; InitializeSpinLock(&PeiCpuMpData->MpLock); + SaveVolatileRegisters (&PeiCpuMpData->CpuData[0].VolatileRegisters); CopyMem (&PeiCpuMpData->AddressMap, &AddressMap, sizeof (MP_ASSEMBLY_ADDRESS_MAP)); // From 9d564cd5229bd2cd370cce13093e0d8b60cc7003 Mon Sep 17 00:00:00 2001 From: Jeff Fan Date: Wed, 2 Dec 2015 03:26:24 +0000 Subject: [PATCH 196/525] UefiCpuPkg/CpuMpPei: Save/Restore CRx/DRx register for APs waking up PeiStartupAllAPs()/PeiStartupThisAP() will send INIT-SIPI-SIPI to wakeup APs to execute AP function. However, some registers will be reset after APs received INIT IPI. We need to restore some registers (For example, CRx/DRx) manually after APs wakeup. (Sync patch r19089 from main trunk.) Cc: Feng Tian Cc: Michael Kinney Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan Reviewed-by: Feng Tian git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19095 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/CpuMpPei/CpuMpPei.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.c b/UefiCpuPkg/CpuMpPei/CpuMpPei.c index 53af9489b2db..ca486135029a 100644 --- a/UefiCpuPkg/CpuMpPei/CpuMpPei.c +++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.c @@ -259,6 +259,11 @@ ApCFunction ( // Execute AP function if AP is not disabled // GetProcessorNumber (PeiCpuMpData, &ProcessorNumber); + // + // Restore AP's volatile registers saved + // + RestoreVolatileRegisters (&PeiCpuMpData->CpuData[ProcessorNumber].VolatileRegisters, TRUE); + if ((PeiCpuMpData->CpuData[ProcessorNumber].State != CpuStateDisabled) && (PeiCpuMpData->ApFunction != 0)) { PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateBusy; @@ -273,6 +278,11 @@ ApCFunction ( // InterlockedIncrement ((UINT32 *)&PeiCpuMpData->FinishedCount); + // + // Save AP volatile registers + // + SaveVolatileRegisters (&PeiCpuMpData->CpuData[ProcessorNumber].VolatileRegisters); + AsmCliHltLoop (); } From 37c2cf4fb85f7c79a15fc860dc5366f562d5f305 Mon Sep 17 00:00:00 2001 From: Jeff Fan Date: Wed, 2 Dec 2015 03:27:06 +0000 Subject: [PATCH 197/525] UefiCpuPkg/CpuMpPei: Fix typo and add some comments (Sync patch r19090 from main trunk.) Cc: Feng Tian Cc: Michael Kinney Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan Reviewed-by: Feng Tian git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19096 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/CpuMpPei/CpuMpPei.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.c b/UefiCpuPkg/CpuMpPei/CpuMpPei.c index ca486135029a..ab1260d0451b 100644 --- a/UefiCpuPkg/CpuMpPei/CpuMpPei.c +++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.c @@ -212,7 +212,7 @@ RestoreVolatileRegisters ( This function will be called from AP reset code if BSP uses WakeUpAP. @param ExchangeInfo Pointer to the MP exchange info buffer - @param NumApsExecuting Number of curret executing AP + @param NumApsExecuting Number of current executing AP **/ VOID EFIAPI @@ -268,6 +268,9 @@ ApCFunction ( (PeiCpuMpData->ApFunction != 0)) { PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateBusy; Procedure = (EFI_AP_PROCEDURE)(UINTN)PeiCpuMpData->ApFunction; + // + // Invoke AP function here + // Procedure ((VOID *)(UINTN)PeiCpuMpData->ApFunctionArgument); PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateIdle; } @@ -612,7 +615,7 @@ CpuMpEndOfPeiCallback ( EFI_PEI_HOB_POINTERS Hob; EFI_HOB_MEMORY_ALLOCATION *MemoryHob; - DEBUG ((EFI_D_INFO, "CpuMpPei: CpuMpEndOfPeiCallback () invokded\n")); + DEBUG ((EFI_D_INFO, "CpuMpPei: CpuMpEndOfPeiCallback () invoked\n")); Status = PeiServicesGetBootMode (&BootMode); ASSERT_EFI_ERROR (Status); From 183f7faabc138a8d47c6dd387ed2ad175e9f96fe Mon Sep 17 00:00:00 2001 From: Mike Maslenkin Date: Thu, 3 Dec 2015 03:27:13 +0000 Subject: [PATCH 198/525] BaseTools: sync BaseTools from main trunk r18579. This patch fixes incomplete merge of multiple workspaces support. Without this patch build fails with error similar to: ~/sources/edk2> build -p MdePkg/MdePkg.dsc -t GCC48 -a X64 Build environment: Linux-3.16.7-24-desktop-x86_64-with-SuSE-13.2-x86_64 Build start time: 17:15:43, Dec.02 2015 WORKSPACE = /home/user/sources/edk2 ECP_SOURCE = /home/user/sources/edk2/EdkCompatibilityPkg EDK_SOURCE = /home/user/sources/edk2/EdkCompatibilityPkg EFI_SOURCE = /home/user/sources/edk2/EdkCompatibilityPkg EDK_TOOLS_PATH = /home/user/sources/edk2/BaseTools build.py... : error C0DE: Unknown fatal error when processing [/home/user/sources/edk2/MdePkg/Library/BaseCacheMaintenanceLib/BaseCacheMaintenanceLib.inf] (Please send email to edk2-devel@lists.sourceforge.net for help, attaching following call stack trace!) (Python 2.7.8 on linux2) Traceback (most recent call last): File "/home/user/sources/edk2/BaseTools/BinWrappers/PosixLike/../../Source/Python/build/build.py", line 2033, in Main MyBuild.Launch() File "/home/user/sources/edk2/BaseTools/BinWrappers/PosixLike/../../Source/Python/build/build.py", line 1788, in Launch self._MultiThreadBuildPlatform() File "/home/user/sources/edk2/BaseTools/BinWrappers/PosixLike/../../Source/Python/build/build.py", line 1583, in _MultiThreadBuildPlatform self.Progress File "/home/user/sources/edk2/BaseTools/Source/Python/AutoGen/AutoGen.py", line 175, in __new__ if not AutoGenObject._Init(Workspace, MetaFile, Target, Toolchain, Arch, *args, **kwargs): File "/home/user/sources/edk2/BaseTools/Source/Python/AutoGen/AutoGen.py", line 355, in _Init Pkgs = list(PkgSet) + list(PGen.PackageList) File "/home/user/sources/edk2/BaseTools/Source/Python/AutoGen/AutoGen.py", line 1484, in _GetPackageList for La in self.LibraryAutoGenList: File "/home/user/sources/edk2/BaseTools/Source/Python/AutoGen/AutoGen.py", line 1594, in _GetLibraryAutoGenList self._GetAutoGenObjectList() File "/home/user/sources/edk2/BaseTools/Source/Python/AutoGen/AutoGen.py", line 1575, in _GetAutoGenObjectList self.MetaFile File "/home/user/sources/edk2/BaseTools/Source/Python/AutoGen/AutoGen.py", line 175, in __new__ if not AutoGenObject._Init(Workspace, MetaFile, Target, Toolchain, Arch, *args, **kwargs): File "/home/user/sources/edk2/BaseTools/Source/Python/AutoGen/AutoGen.py", line 2199, in _Init self.SourceDir = mws.relpath(self.SourceDir, self.WorkspaceDir) File "/home/user/sources/edk2/BaseTools/Source/Python/Common/MultipleWorkspace.py", line 94, in relpath for Pkg in cls.PACKAGES_PATH: TypeError: 'NoneType' object is not iterable - Failed - Build end time: 17:15:44, Dec.02 2015 Build total time: 00:00:01 Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Mike Maslenkin Cc: Jeff Fan Reviewed-by: Jeff Fan git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19102 6f19259b-4bc3-4df7-8a09-765794883524 --- BaseTools/Source/Python/build/BuildReport.py | 16 ++++--- BaseTools/Source/Python/build/build.py | 46 +++++++++++++------- 2 files changed, 39 insertions(+), 23 deletions(-) diff --git a/BaseTools/Source/Python/build/BuildReport.py b/BaseTools/Source/Python/build/BuildReport.py index d64c55d08bc1..38e55f3e07f6 100644 --- a/BaseTools/Source/Python/build/BuildReport.py +++ b/BaseTools/Source/Python/build/BuildReport.py @@ -41,6 +41,7 @@ from Common.DataType import TAB_BRG_LIBRARY from Common.DataType import TAB_BACK_SLASH from Common.LongFilePathSupport import OpenLongFilePath as open +from Common.MultipleWorkspace import MultipleWorkspace as mws ## Pattern to extract contents in EDK DXS files gDxsDependencyPattern = re.compile(r"DEPENDENCY_START(.+)DEPENDENCY_END", re.DOTALL) @@ -1235,12 +1236,13 @@ def __init__(self, FdRegion, Wa): DecDefaultValue = Package.Pcds[TokenCName, TokenSpaceGuidCName, DecType].DefaultValue PlatformPcds[(TokenCName, TokenSpaceGuidCName)] = DecDefaultValue # - # Collect PCDs defined in DSC common section + # Collect PCDs defined in DSC file # - Platform = Wa.BuildDatabase[Wa.MetaFile, 'COMMON'] - for (TokenCName, TokenSpaceGuidCName) in Platform.Pcds: - DscDefaultValue = Platform.Pcds[(TokenCName, TokenSpaceGuidCName)].DefaultValue - PlatformPcds[(TokenCName, TokenSpaceGuidCName)] = DscDefaultValue + for arch in Wa.ArchList: + Platform = Wa.BuildDatabase[Wa.MetaFile, arch] + for (TokenCName, TokenSpaceGuidCName) in Platform.Pcds: + DscDefaultValue = Platform.Pcds[(TokenCName, TokenSpaceGuidCName)].DefaultValue + PlatformPcds[(TokenCName, TokenSpaceGuidCName)] = DscDefaultValue # # Add PEI and DXE a priori files GUIDs defined in PI specification. @@ -1255,7 +1257,7 @@ def __init__(self, FdRegion, Wa): for Pa in Wa.AutoGenObjectList: for ModuleKey in Pa.Platform.Modules: M = Pa.Platform.Modules[ModuleKey].M - InfPath = os.path.join(Wa.WorkspaceDir, M.MetaFile.File) + InfPath = mws.join(Wa.WorkspaceDir, M.MetaFile.File) self._GuidsDb[M.Guid.upper()] = "%s (%s)" % (M.Module.BaseName, InfPath) # @@ -1277,7 +1279,7 @@ def __init__(self, FdRegion, Wa): Guid = GuidStructureByteArrayToGuidString(GuidValue).upper() for Section in Ffs.SectionList: try: - ModuleSectFile = os.path.join(Wa.WorkspaceDir, Section.SectFileName) + ModuleSectFile = mws.join(Wa.WorkspaceDir, Section.SectFileName) self._GuidsDb[Guid] = ModuleSectFile except AttributeError: pass diff --git a/BaseTools/Source/Python/build/build.py b/BaseTools/Source/Python/build/build.py index 33b45ba26717..6d83ac9701ba 100644 --- a/BaseTools/Source/Python/build/build.py +++ b/BaseTools/Source/Python/build/build.py @@ -41,6 +41,7 @@ from AutoGen.AutoGen import * from Common.BuildToolError import * from Workspace.WorkspaceDatabase import * +from Common.MultipleWorkspace import MultipleWorkspace as mws from BuildReport import BuildReport from GenPatchPcdTable.GenPatchPcdTable import * @@ -104,12 +105,16 @@ def CheckEnvVariable(): EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in WORKSPACE path", ExtraData=WorkspaceDir) os.environ["WORKSPACE"] = WorkspaceDir + + # set multiple workspace + PackagesPath = os.getenv("PACKAGES_PATH") + mws.setWs(WorkspaceDir, PackagesPath) # # Check EFI_SOURCE (Edk build convention). EDK_SOURCE will always point to ECP # if "ECP_SOURCE" not in os.environ: - os.environ["ECP_SOURCE"] = os.path.join(WorkspaceDir, GlobalData.gEdkCompatibilityPkg) + os.environ["ECP_SOURCE"] = mws.join(WorkspaceDir, GlobalData.gEdkCompatibilityPkg) if "EFI_SOURCE" not in os.environ: os.environ["EFI_SOURCE"] = os.environ["ECP_SOURCE"] if "EDK_SOURCE" not in os.environ: @@ -151,16 +156,18 @@ def CheckEnvVariable(): EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in EFI_SOURCE path", ExtraData=EfiSourceDir) - # change absolute path to relative path to WORKSPACE - if EfiSourceDir.upper().find(WorkspaceDir.upper()) != 0: - EdkLogger.error("build", PARAMETER_INVALID, "EFI_SOURCE is not under WORKSPACE", - ExtraData="WORKSPACE = %s\n EFI_SOURCE = %s" % (WorkspaceDir, EfiSourceDir)) - if EdkSourceDir.upper().find(WorkspaceDir.upper()) != 0: - EdkLogger.error("build", PARAMETER_INVALID, "EDK_SOURCE is not under WORKSPACE", - ExtraData="WORKSPACE = %s\n EDK_SOURCE = %s" % (WorkspaceDir, EdkSourceDir)) - if EcpSourceDir.upper().find(WorkspaceDir.upper()) != 0: - EdkLogger.error("build", PARAMETER_INVALID, "ECP_SOURCE is not under WORKSPACE", - ExtraData="WORKSPACE = %s\n ECP_SOURCE = %s" % (WorkspaceDir, EcpSourceDir)) + # check those variables on single workspace case + if not PackagesPath: + # change absolute path to relative path to WORKSPACE + if EfiSourceDir.upper().find(WorkspaceDir.upper()) != 0: + EdkLogger.error("build", PARAMETER_INVALID, "EFI_SOURCE is not under WORKSPACE", + ExtraData="WORKSPACE = %s\n EFI_SOURCE = %s" % (WorkspaceDir, EfiSourceDir)) + if EdkSourceDir.upper().find(WorkspaceDir.upper()) != 0: + EdkLogger.error("build", PARAMETER_INVALID, "EDK_SOURCE is not under WORKSPACE", + ExtraData="WORKSPACE = %s\n EDK_SOURCE = %s" % (WorkspaceDir, EdkSourceDir)) + if EcpSourceDir.upper().find(WorkspaceDir.upper()) != 0: + EdkLogger.error("build", PARAMETER_INVALID, "ECP_SOURCE is not under WORKSPACE", + ExtraData="WORKSPACE = %s\n ECP_SOURCE = %s" % (WorkspaceDir, EcpSourceDir)) # check EDK_TOOLS_PATH if "EDK_TOOLS_PATH" not in os.environ: @@ -182,7 +189,7 @@ def CheckEnvVariable(): GlobalData.gGlobalDefines["EDK_SOURCE"] = EdkSourceDir GlobalData.gGlobalDefines["ECP_SOURCE"] = EcpSourceDir GlobalData.gGlobalDefines["EDK_TOOLS_PATH"] = os.environ["EDK_TOOLS_PATH"] - + ## Get normalized file path # # Convert the path to be local format, and remove the WORKSPACE path at the @@ -198,7 +205,8 @@ def NormFile(FilePath, Workspace): if os.path.isabs(FilePath): FileFullPath = os.path.normpath(FilePath) else: - FileFullPath = os.path.normpath(os.path.join(Workspace, FilePath)) + FileFullPath = os.path.normpath(mws.join(Workspace, FilePath)) + Workspace = mws.getWs(Workspace, FilePath) # check if the file path exists or not if not os.path.isfile(FileFullPath): @@ -748,10 +756,10 @@ def __init__(self, Target, WorkspaceDir, BuildOptions): if not os.path.isabs(ConfDirectoryPath): # Since alternate directory name is not absolute, the alternate directory is located within the WORKSPACE # This also handles someone specifying the Conf directory in the workspace. Using --conf=Conf - ConfDirectoryPath = os.path.join(self.WorkspaceDir, ConfDirectoryPath) + ConfDirectoryPath = mws.join(self.WorkspaceDir, ConfDirectoryPath) else: # Get standard WORKSPACE/Conf use the absolute path to the WORKSPACE/Conf - ConfDirectoryPath = os.path.join(self.WorkspaceDir, 'Conf') + ConfDirectoryPath = mws.join(self.WorkspaceDir, 'Conf') GlobalData.gConfDirectory = ConfDirectoryPath GlobalData.gDatabasePath = os.path.normpath(os.path.join(ConfDirectoryPath, GlobalData.gDatabasePath)) @@ -772,10 +780,16 @@ def __init__(self, Target, WorkspaceDir, BuildOptions): # print current build environment and configuration EdkLogger.quiet("%-16s = %s" % ("WORKSPACE", os.environ["WORKSPACE"])) + if "PACKAGES_PATH" in os.environ: + # WORKSPACE env has been converted before. Print the same path style with WORKSPACE env. + EdkLogger.quiet("%-16s = %s" % ("PACKAGES_PATH", os.path.normcase(os.path.normpath(os.environ["PACKAGES_PATH"])))) EdkLogger.quiet("%-16s = %s" % ("ECP_SOURCE", os.environ["ECP_SOURCE"])) EdkLogger.quiet("%-16s = %s" % ("EDK_SOURCE", os.environ["EDK_SOURCE"])) EdkLogger.quiet("%-16s = %s" % ("EFI_SOURCE", os.environ["EFI_SOURCE"])) EdkLogger.quiet("%-16s = %s" % ("EDK_TOOLS_PATH", os.environ["EDK_TOOLS_PATH"])) + if "EDK_TOOLS_BIN" in os.environ: + # Print the same path style with WORKSPACE env. + EdkLogger.quiet("%-16s = %s" % ("EDK_TOOLS_BIN", os.path.normcase(os.path.normpath(os.environ["EDK_TOOLS_BIN"])))) EdkLogger.info("") @@ -796,7 +810,7 @@ def LoadConfiguration(self): ToolDefinitionFile = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TOOL_CHAIN_CONF] if ToolDefinitionFile == '': ToolDefinitionFile = gToolsDefinition - ToolDefinitionFile = os.path.normpath(os.path.join(self.WorkspaceDir, 'Conf', ToolDefinitionFile)) + ToolDefinitionFile = os.path.normpath(mws.join(self.WorkspaceDir, 'Conf', ToolDefinitionFile)) if os.path.isfile(ToolDefinitionFile) == True: StatusCode = self.ToolDef.LoadToolDefFile(ToolDefinitionFile) else: From 22ad647ffebbd26766a806007ad8eb2a35e3db09 Mon Sep 17 00:00:00 2001 From: Wang Yu Date: Fri, 4 Dec 2015 03:43:12 +0000 Subject: [PATCH 199/525] BaseTools: Add VS2015 tool chain in tools_def.template (Sync patch r19101 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Wang Yu Reviewed-by: Liming Gao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19117 6f19259b-4bc3-4df7-8a09-765794883524 --- BaseTools/Conf/tools_def.template | 519 +++++++++++++++++++++++++++++- edksetup.bat | 38 ++- 2 files changed, 536 insertions(+), 21 deletions(-) diff --git a/BaseTools/Conf/tools_def.template b/BaseTools/Conf/tools_def.template index db08e252d2b9..88d4b4f3b6c9 100644 --- a/BaseTools/Conf/tools_def.template +++ b/BaseTools/Conf/tools_def.template @@ -65,6 +65,14 @@ DEFINE VS2013x86_BIN = C:\Program Files (x86)\Microsoft Visual Studio 12.0\Vc DEFINE VS2013x86_DLL = C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE;DEF(VS2013x86_BIN) DEFINE VS2013x86_BINX64 = DEF(VS2013x86_BIN)\x86_amd64 +DEFINE VS2015_BIN = C:\Program Files\Microsoft Visual Studio 14.0\Vc\bin +DEFINE VS2015_DLL = C:\Program Files\Microsoft Visual Studio 14.0\Common7\IDE;DEF(VS2015_BIN) +DEFINE VS2015_BINX64 = DEF(VS2015_BIN)\x86_amd64 + +DEFINE VS2015x86_BIN = C:\Program Files (x86)\Microsoft Visual Studio 14.0\Vc\bin +DEFINE VS2015x86_DLL = C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE;DEF(VS2015x86_BIN) +DEFINE VS2015x86_BINX64 = DEF(VS2015x86_BIN)\x86_amd64 + DEFINE WINSDK_VERSION = v6.0A DEFINE WINSDK_BIN = c:\Program Files\Microsoft SDKs\Windows\DEF(WINSDK_VERSION)\bin DEFINE WINSDKx86_BIN = c:\Program Files (x86)\Microsoft SDKs\Windows\DEF(WINSDK_VERSION)\bin @@ -81,6 +89,10 @@ DEFINE WINSDK71x86_BIN = c:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\ DEFINE WINSDK8_BIN = c:\Program Files\Windows Kits\8.0\bin\x86\ DEFINE WINSDK8x86_BIN = c:\Program Files (x86)\Windows Kits\8.0\bin\x64 +# Microsoft Visual Studio 2015 Professional Edition +DEFINE WINSDK81_BIN = c:\Program Files\Windows Kits\8.1\bin\x86\ +DEFINE WINSDK81x86_BIN = c:\Program Files (x86)\Windows Kits\8.1\bin\x64 + # These defines are needed for certain Microsoft Visual Studio tools that # are used by other toolchains. An example is that ICC on Windows normally # uses Microsoft's nmake.exe. @@ -293,6 +305,15 @@ DEFINE SOURCERY_CYGWIN_TOOLS = /cygdrive/c/Program Files/CodeSourcery/Sourcery G # Required to build platforms or ACPI tables: # Intel(r) ACPI Compiler (iasl.exe) from # https://acpica.org/downloads +# VS2015 -win32- Requires: +# Microsoft Visual Studio 2015 Professional Edition +# Microsoft Windows Server 2003 Driver Development Kit (Microsoft WINDDK) version 3790.1830 +# Optional: +# Required to build EBC drivers: +# Intel(r) Compiler for Efi Byte Code (Intel(r) EBC Compiler) +# Required to build platforms or ACPI tables: +# Intel(r) ACPI Compiler (iasl.exe) from +# https://acpica.org/downloads # DDK3790 -win32- Requires: # Microsoft Windows Server 2003 Driver Development Kit (Microsoft WINDDK) version 3790.1830 # Optional: @@ -452,6 +473,15 @@ DEFINE SOURCERY_CYGWIN_TOOLS = /cygdrive/c/Program Files/CodeSourcery/Sourcery G # Required to build platforms or ACPI tables: # Microsoft ASL ACPI Compiler (asl.exe) v4.0.0 from # http://download.microsoft.com/download/2/c/1/2c16c7e0-96c1-40f5-81fc-3e4bf7b65496/microsoft_asl_compiler-v4-0-0.msi +# VS2015xASL -win32- Requires: +# Microsoft Visual Studio 2015 Professional Edition +# Microsoft Windows Server 2003 Driver Development Kit (Microsoft WINDDK) version 3790.1830 +# Optional: +# Required to build EBC drivers: +# Intel(r) Compiler for Efi Byte Code (Intel(r) EBC Compiler) +# Required to build platforms or ACPI tables: +# Microsoft ASL ACPI Compiler (asl.exe) v4.0.0 from +# http://download.microsoft.com/download/2/c/1/2c16c7e0-96c1-40f5-81fc-3e4bf7b65496/microsoft_asl_compiler-v4-0-0.msi # DDK3790xASL -win32- Requires: # Microsoft Windows Server 2003 Driver Development Kit (Microsoft WINDDK) version 3790.1830 # Optional: @@ -530,6 +560,13 @@ DEFINE SOURCERY_CYGWIN_TOOLS = /cygdrive/c/Program Files/CodeSourcery/Sourcery G # Required to build platforms or ACPI tables: # Intel(r) ACPI Compiler (iasl.exe) from # https://acpica.org/downloads +# VS2015x86 -win64- Requires: +# Microsoft Visual Studio 2015 (x86) Professional Edition +# Microsoft Windows Server 2003 Driver Development Kit (Microsoft WINDDK) version 3790.1830 +# Optional: +# Required to build platforms or ACPI tables: +# Intel(r) ACPI Compiler (iasl.exe) from +# https://acpica.org/downloads # ICCx86 -win64- Requires: # Intel C Compiler V9.1(x86) # Dependencies: @@ -591,6 +628,13 @@ DEFINE SOURCERY_CYGWIN_TOOLS = /cygdrive/c/Program Files/CodeSourcery/Sourcery G # Required to build platforms or ACPI tables: # Microsoft ASL ACPI Compiler (asl.exe) v4.0.0 from # http://download.microsoft.com/download/2/c/1/2c16c7e0-96c1-40f5-81fc-3e4bf7b65496/microsoft_asl_compiler-v4-0-0.msi +# VS2015x86xASL -win64- Requires: +# Microsoft Visual Studio 2015 (x86) Professional +# Microsoft Windows Server 2003 Driver Development Kit(Microsoft WINDDK) version 3790.1830 +# Optional: +# Required to build platforms or ACPI tables: +# Microsoft ASL ACPI Compiler (asl.exe) v4.0.0 from +# http://download.microsoft.com/download/2/c/1/2c16c7e0-96c1-40f5-81fc-3e4bf7b65496/microsoft_asl_compiler-v4-0-0.msi # ICCx86xASL -win64- Requires: # Intel C Compiler V9.1 (x86) # Dependencies: @@ -2601,7 +2645,7 @@ NOOPT_VS2010x86xASL_IPF_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /LTCG /DLL /OPT:R # VS2012 - Microsoft Visual Studio 2012 Professional Edition with Intel ASL # ASL - Intel ACPI Source Language Compiler #################################################################################### -# VS2012 - Microsoft Visual Studio 2012 Premium Edition +# VS2012 - Microsoft Visual Studio 2012 Professional Edition *_VS2012_*_*_FAMILY = MSFT *_VS2012_*_MAKE_PATH = DEF(VS2012_BIN)\nmake.exe @@ -2719,7 +2763,7 @@ NOOPT_VS2012_X64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT # VS2012 - Microsoft Visual Studio 2012 Professional Edition with Microsoft ASL # ASL - Microsoft ACPI Source Language Compiler (asl.exe) #################################################################################### -# VS2012xASL - Microsoft Visual Studio 2012 Premium Edition +# VS2012xASL - Microsoft Visual Studio 2012 Professional Edition *_VS2012xASL_*_*_FAMILY = MSFT *_VS2012xASL_*_MAKE_PATH = DEF(VS2012_BIN)\nmake.exe @@ -3067,7 +3111,7 @@ NOOPT_VS2012x86xASL_X64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT # VS2013 - Microsoft Visual Studio 2013 Professional Edition with Intel ASL # ASL - Intel ACPI Source Language Compiler #################################################################################### -# VS2013 - Microsoft Visual Studio 2013 Premium Edition +# VS2013 - Microsoft Visual Studio 2013 Professional Edition *_VS2013_*_*_FAMILY = MSFT *_VS2013_*_MAKE_PATH = DEF(VS2013_BIN)\nmake.exe @@ -3185,7 +3229,7 @@ NOOPT_VS2013_X64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT # VS2013 - Microsoft Visual Studio 2013 Professional Edition with Microsoft ASL # ASL - Microsoft ACPI Source Language Compiler (asl.exe) #################################################################################### -# VS2013xASL - Microsoft Visual Studio 2013 Premium Edition +# VS2013xASL - Microsoft Visual Studio 2013 Professional Edition *_VS2013xASL_*_*_FAMILY = MSFT *_VS2013xASL_*_MAKE_PATH = DEF(VS2013_BIN)\nmake.exe @@ -3527,6 +3571,473 @@ NOOPT_VS2013x86xASL_X64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT *_VS2013x86xASL_EBC_DLINK_FLAGS = "C:\Program Files (x86)\Intel\EBC\Lib\EbcLib.lib" /NOLOGO /NODEFAULTLIB /MACHINE:EBC /OPT:REF /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /MAP /ALIGN:32 /DRIVER +#################################################################################### +# +# Microsoft Visual Studio 2015 +# +# VS2015 - Microsoft Visual Studio 2015 Professional Edition with Intel ASL +# ASL - Intel ACPI Source Language Compiler +#################################################################################### +# VS2015 - Microsoft Visual Studio 2015 Professional Edition +*_VS2015_*_*_FAMILY = MSFT + +*_VS2015_*_MAKE_PATH = DEF(VS2015_BIN)\nmake.exe +*_VS2015_*_MAKE_FLAGS = /nologo +*_VS2015_*_RC_PATH = DEF(WINSDK81_BIN)\rc.exe + +*_VS2015_*_SLINK_FLAGS = /NOLOGO /LTCG +*_VS2015_*_APP_FLAGS = /nologo /E /TC +*_VS2015_*_PP_FLAGS = /nologo /E /TC /FIAutoGen.h +*_VS2015_*_VFRPP_FLAGS = /nologo /E /TC /DVFRCOMPILE /FI$(MODULE_NAME)StrDefs.h + +*_VS2015_*_ASM16_PATH = DEF(VS2015_BIN)\ml.exe + +################## +# ASL definitions +################## +*_VS2015_*_ASL_PATH = DEF(DEFAULT_WIN_ASL_BIN) +*_VS2015_*_ASL_FLAGS = DEF(DEFAULT_WIN_ASL_FLAGS) +*_VS2015_*_ASL_OUTFLAGS = DEF(DEFAULT_WIN_ASL_OUTFLAGS) +*_VS2015_*_ASLCC_FLAGS = DEF(MSFT_ASLCC_FLAGS) +*_VS2015_*_ASLPP_FLAGS = DEF(MSFT_ASLPP_FLAGS) +*_VS2015_*_ASLDLINK_FLAGS = DEF(MSFT_ASLDLINK_FLAGS) + +################## +# IA32 definitions +################## +*_VS2015_IA32_*_DLL = DEF(VS2015_DLL) + +*_VS2015_IA32_MAKE_PATH = DEF(VS2015_BIN)\nmake.exe +*_VS2015_IA32_CC_PATH = DEF(VS2015_BIN)\cl.exe +*_VS2015_IA32_VFRPP_PATH = DEF(VS2015_BIN)\cl.exe +*_VS2015_IA32_SLINK_PATH = DEF(VS2015_BIN)\lib.exe +*_VS2015_IA32_DLINK_PATH = DEF(VS2015_BIN)\link.exe +*_VS2015_IA32_APP_PATH = DEF(VS2015_BIN)\cl.exe +*_VS2015_IA32_PP_PATH = DEF(VS2015_BIN)\cl.exe +*_VS2015_IA32_ASM_PATH = DEF(VS2015_BIN)\ml.exe +*_VS2015_IA32_ASLCC_PATH = DEF(VS2015_BIN)\cl.exe +*_VS2015_IA32_ASLPP_PATH = DEF(VS2015_BIN)\cl.exe +*_VS2015_IA32_ASLDLINK_PATH = DEF(VS2015_BIN)\link.exe + + *_VS2015_IA32_MAKE_FLAGS = /nologo + DEBUG_VS2015_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1ib2 /GL /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Zi /Gm +RELEASE_VS2015_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1ib2 /GL /FIAutoGen.h /EHs-c- /GR- /GF +NOOPT_VS2015_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Zi /Gm /Od + + DEBUG_VS2015_IA32_ASM_FLAGS = /nologo /c /WX /W3 /Cx /coff /Zd /Zi +RELEASE_VS2015_IA32_ASM_FLAGS = /nologo /c /WX /W3 /Cx /coff /Zd +NOOPT_VS2015_IA32_ASM_FLAGS = /nologo /c /WX /W3 /Cx /coff /Zd /Zi + + DEBUG_VS2015_IA32_NASM_FLAGS = -Ox -f win32 -g +RELEASE_VS2015_IA32_NASM_FLAGS = -Ox -f win32 +NOOPT_VS2015_IA32_NASM_FLAGS = -O0 -f win32 -g + + DEBUG_VS2015_IA32_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /MACHINE:X86 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /DEBUG +RELEASE_VS2015_IA32_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /IGNORE:4254 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /MACHINE:X86 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /MERGE:.rdata=.data +NOOPT_VS2015_IA32_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /MACHINE:X86 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /DEBUG + +################## +# X64 definitions +################## +*_VS2015_X64_*_DLL = DEF(VS2015_DLL) + +*_VS2015_X64_CC_PATH = DEF(VS2015_BINX64)\cl.exe +*_VS2015_X64_PP_PATH = DEF(VS2015_BINX64)\cl.exe +*_VS2015_X64_APP_PATH = DEF(VS2015_BINX64)\cl.exe +*_VS2015_X64_VFRPP_PATH = DEF(VS2015_BINX64)\cl.exe +*_VS2015_X64_ASM_PATH = DEF(VS2015_BINX64)\ml64.exe +*_VS2015_X64_SLINK_PATH = DEF(VS2015_BINX64)\lib.exe +*_VS2015_X64_DLINK_PATH = DEF(VS2015_BINX64)\link.exe +*_VS2015_X64_ASLCC_PATH = DEF(VS2015_BINX64)\cl.exe +*_VS2015_X64_ASLPP_PATH = DEF(VS2015_BINX64)\cl.exe +*_VS2015_X64_ASLDLINK_PATH = DEF(VS2015_BINX64)\link.exe + + DEBUG_VS2015_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1ib2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Zi /Gm +RELEASE_VS2015_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1ib2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF +NOOPT_VS2015_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Zi /Gm /Od + + DEBUG_VS2015_X64_ASM_FLAGS = /nologo /c /WX /W3 /Cx /Zd /Zi +RELEASE_VS2015_X64_ASM_FLAGS = /nologo /c /WX /W3 /Cx /Zd +NOOPT_VS2015_X64_ASM_FLAGS = /nologo /c /WX /W3 /Cx /Zd /Zi + + DEBUG_VS2015_X64_NASM_FLAGS = -Ox -f win64 -g +RELEASE_VS2015_X64_NASM_FLAGS = -Ox -f win64 +NOOPT_VS2015_X64_NASM_FLAGS = -O0 -f win64 -g + + DEBUG_VS2015_X64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:X64 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /DEBUG +RELEASE_VS2015_X64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /IGNORE:4254 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:X64 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /MERGE:.rdata=.data +NOOPT_VS2015_X64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:X64 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /DEBUG + +################## +# EBC definitions +################## +*_VS2015_EBC_*_FAMILY = INTEL +*_VS2015_EBC_*_DLL = DEF(VS2015_DLL) + +*_VS2015_EBC_MAKE_PATH = DEF(VS2015_BIN)\nmake.exe +*_VS2015_EBC_PP_PATH = DEF(EBC_BIN)\iec.exe +*_VS2015_EBC_VFRPP_PATH = DEF(EBC_BIN)\iec.exe +*_VS2015_EBC_CC_PATH = DEF(EBC_BIN)\iec.exe +*_VS2015_EBC_SLINK_PATH = DEF(VS2015_BIN)\link.exe +*_VS2015_EBC_DLINK_PATH = DEF(VS2015_BIN)\link.exe + +*_VS2015_EBC_MAKE_FLAGS = /nologo +*_VS2015_EBC_PP_FLAGS = /nologo /E /TC /FIAutoGen.h +*_VS2015_EBC_CC_FLAGS = /nologo /c /WX /W3 /FIAutoGen.h /D$(MODULE_ENTRY_POINT)=$(ARCH_ENTRY_POINT) +*_VS2015_EBC_VFRPP_FLAGS = /nologo /E /TC /DVFRCOMPILE /FI$(MODULE_NAME)StrDefs.h +*_VS2015_EBC_SLINK_FLAGS = /lib /NOLOGO /MACHINE:EBC +*_VS2015_EBC_DLINK_FLAGS = "C:\Program Files\Intel\EBC\Lib\EbcLib.lib" /NOLOGO /NODEFAULTLIB /MACHINE:EBC /OPT:REF /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /MAP /ALIGN:32 /DRIVER + + +#################################################################################### +# +# Microsoft Visual Studio 2015 +# +# VS2015 - Microsoft Visual Studio 2015 Professional Edition with Microsoft ASL +# ASL - Microsoft ACPI Source Language Compiler (asl.exe) +#################################################################################### +# VS2015xASL - Microsoft Visual Studio 2015 Professional Edition +*_VS2015xASL_*_*_FAMILY = MSFT + +*_VS2015xASL_*_MAKE_PATH = DEF(VS2015_BIN)\nmake.exe +*_VS2015xASL_*_MAKE_FLAG = /nologo +*_VS2015xASL_*_RC_PATH = DEF(WINSDK81_BIN)\rc.exe + +*_VS2015xASL_*_SLINK_FLAGS = /NOLOGO /LTCG +*_VS2015xASL_*_APP_FLAGS = /nologo /E /TC +*_VS2015xASL_*_PP_FLAGS = /nologo /E /TC /FIAutoGen.h +*_VS2015xASL_*_VFRPP_FLAGS = /nologo /E /TC /DVFRCOMPILE /FI$(MODULE_NAME)StrDefs.h + +*_VS2015xASL_*_ASM16_PATH = DEF(VS2015_BIN)\ml.exe + +################## +# ASL definitions +################## +*_VS2015xASL_*_ASL_PATH = DEF(WIN_ASL_BIN) +*_VS2015xASL_*_ASL_FLAGS = +*_VS2015xASL_*_ASL_OUTFLAGS = DEF(MS_ASL_OUTFLAGS) +*_VS2015xASL_*_ASLCC_FLAGS = DEF(MSFT_ASLCC_FLAGS) +*_VS2015xASL_*_ASLPP_FLAGS = DEF(MSFT_ASLPP_FLAGS) +*_VS2015xASL_*_ASLDLINK_FLAGS = DEF(MSFT_ASLDLINK_FLAGS) + +################## +# IA32 definitions +################## +*_VS2015xASL_IA32_*_DLL = DEF(VS2015_DLL) + +*_VS2015xASL_IA32_MAKE_PATH = DEF(VS2015_BIN)\nmake.exe +*_VS2015xASL_IA32_CC_PATH = DEF(VS2015_BIN)\cl.exe +*_VS2015xASL_IA32_VFRPP_PATH = DEF(VS2015_BIN)\cl.exe +*_VS2015xASL_IA32_SLINK_PATH = DEF(VS2015_BIN)\lib.exe +*_VS2015xASL_IA32_DLINK_PATH = DEF(VS2015_BIN)\link.exe +*_VS2015xASL_IA32_APP_PATH = DEF(VS2015_BIN)\cl.exe +*_VS2015xASL_IA32_PP_PATH = DEF(VS2015_BIN)\cl.exe +*_VS2015xASL_IA32_ASM_PATH = DEF(VS2015_BIN)\ml.exe +*_VS2015xASL_IA32_ASLCC_PATH = DEF(VS2015_BIN)\cl.exe +*_VS2015xASL_IA32_ASLPP_PATH = DEF(VS2015_BIN)\cl.exe +*_VS2015xASL_IA32_ASLDLINK_PATH = DEF(VS2015_BIN)\link.exe + + *_VS2015xASL_IA32_MAKE_FLAGS = /nologo + DEBUG_VS2015xASL_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1ib2 /GL /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Zi /Gm +RELEASE_VS2015xASL_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1ib2 /GL /FIAutoGen.h /EHs-c- /GR- /GF +NOOPT_VS2015xASL_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Zi /Gm /Od + + DEBUG_VS2015xASL_IA32_ASM_FLAGS = /nologo /c /WX /W3 /Cx /coff /Zd /Zi +RELEASE_VS2015xASL_IA32_ASM_FLAGS = /nologo /c /WX /W3 /Cx /coff /Zd +NOOPT_VS2015xASL_IA32_ASM_FLAGS = /nologo /c /WX /W3 /Cx /coff /Zd /Zi + + DEBUG_VS2015xASL_IA32_NASM_FLAGS = -Ox -f win32 -g +RELEASE_VS2015xASL_IA32_NASM_FLAGS = -Ox -f win32 +NOOPT_VS2015xASL_IA32_NASM_FLAGS = -O0 -f win32 -g + + DEBUG_VS2015xASL_IA32_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /MACHINE:X86 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /DEBUG +RELEASE_VS2015xASL_IA32_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /IGNORE:4254 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /MACHINE:X86 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /MERGE:.rdata=.data +NOOPT_VS2015xASL_IA32_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /MACHINE:X86 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /DEBUG + +################## +# X64 definitions +################## +*_VS2015xASL_X64_*_DLL = DEF(VS2015_DLL) + +*_VS2015xASL_X64_CC_PATH = DEF(VS2015_BINX64)\cl.exe +*_VS2015xASL_X64_PP_PATH = DEF(VS2015_BINX64)\cl.exe +*_VS2015xASL_X64_APP_PATH = DEF(VS2015_BINX64)\cl.exe +*_VS2015xASL_X64_VFRPP_PATH = DEF(VS2015_BINX64)\cl.exe +*_VS2015xASL_X64_ASM_PATH = DEF(VS2015_BINX64)\ml64.exe +*_VS2015xASL_X64_SLINK_PATH = DEF(VS2015_BINX64)\lib.exe +*_VS2015xASL_X64_DLINK_PATH = DEF(VS2015_BINX64)\link.exe +*_VS2015xASL_X64_ASLCC_PATH = DEF(VS2015_BINX64)\cl.exe +*_VS2015xASL_X64_ASLPP_PATH = DEF(VS2015_BINX64)\cl.exe +*_VS2015xASL_X64_ASLDLINK_PATH = DEF(VS2015_BINX64)\link.exe + + DEBUG_VS2015xASL_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1ib2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Zi /Gm +RELEASE_VS2015xASL_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1ib2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF +NOOPT_VS2015xASL_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Zi /Gm /Od + + DEBUG_VS2015xASL_X64_ASM_FLAGS = /nologo /c /WX /W3 /Cx /Zd /Zi +RELEASE_VS2015xASL_X64_ASM_FLAGS = /nologo /c /WX /W3 /Cx /Zd +NOOPT_VS2015xASL_X64_ASM_FLAGS = /nologo /c /WX /W3 /Cx /Zd /Zi + + DEBUG_VS2015xASL_X64_NASM_FLAGS = -Ox -f win64 -g +RELEASE_VS2015xASL_X64_NASM_FLAGS = -Ox -f win64 +NOOPT_VS2015xASL_X64_NASM_FLAGS = -O0 -f win64 -g + + DEBUG_VS2015xASL_X64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:X64 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /DEBUG +RELEASE_VS2015xASL_X64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /IGNORE:4254 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:X64 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /MERGE:.rdata=.data +NOOPT_VS2015xASL_X64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:X64 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /DEBUG + +################## +# EBC definitions +################## +*_VS2015xASL_EBC_*_FAMILY = INTEL +*_VS2015xASL_EBC_*_DLL = DEF(VS2015_DLL) + +*_VS2015xASL_EBC_MAKE_PATH = DEF(VS2015_BIN)\nmake.exe +*_VS2015xASL_EBC_PP_PATH = DEF(EBC_BIN)\iec.exe +*_VS2015xASL_EBC_VFRPP_PATH = DEF(EBC_BIN)\iec.exe +*_VS2015xASL_EBC_CC_PATH = DEF(EBC_BIN)\iec.exe +*_VS2015xASL_EBC_SLINK_PATH = DEF(VS2015_BIN)\link.exe +*_VS2015xASL_EBC_DLINK_PATH = DEF(VS2015_BIN)\link.exe + +*_VS2015xASL_EBC_MAKE_FLAGS = /nologo +*_VS2015xASL_EBC_PP_FLAGS = /nologo /E /TC /FIAutoGen.h +*_VS2015xASL_EBC_CC_FLAGS = /nologo /c /WX /W3 /FIAutoGen.h /D$(MODULE_ENTRY_POINT)=$(ARCH_ENTRY_POINT) +*_VS2015xASL_EBC_VFRPP_FLAGS = /nologo /E /TC /DVFRCOMPILE /FI$(MODULE_NAME)StrDefs.h +*_VS2015xASL_EBC_SLINK_FLAGS = /lib /NOLOGO /MACHINE:EBC +*_VS2015xASL_EBC_DLINK_FLAGS = "C:\Program Files\Intel\EBC\Lib\EbcLib.lib" /NOLOGO /NODEFAULTLIB /MACHINE:EBC /OPT:REF /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /MAP /ALIGN:32 /DRIVER + + +#################################################################################### +# VS2015x86 - Microsoft Visual Studio 2015 (x86) professional with Intel ASL +# ASL - Intel ACPI Source Language Compiler (iasl.exe) +#################################################################################### +# VS2015x86 - Microsoft Visual Studio 2015 (x86) professional Edition with Intel ASL +*_VS2015x86_*_*_FAMILY = MSFT + +*_VS2015x86_*_MAKE_PATH = DEF(VS2015x86_BIN)\nmake.exe +*_VS2015x86_*_MAKE_FLAG = /nologo +*_VS2015x86_*_RC_PATH = DEF(WINSDK81x86_BIN)\rc.exe + +*_VS2015x86_*_MAKE_FLAGS = /nologo +*_VS2015x86_*_SLINK_FLAGS = /NOLOGO /LTCG +*_VS2015x86_*_APP_FLAGS = /nologo /E /TC +*_VS2015x86_*_PP_FLAGS = /nologo /E /TC /FIAutoGen.h +*_VS2015x86_*_VFRPP_FLAGS = /nologo /E /TC /DVFRCOMPILE /FI$(MODULE_NAME)StrDefs.h + +*_VS2015x86_*_ASM16_PATH = DEF(VS2015x86_BIN)\ml.exe + +################## +# ASL definitions +################## +*_VS2015x86_*_ASL_PATH = DEF(WIN_IASL_BIN) +*_VS2015x86_*_ASL_FLAGS = DEF(DEFAULT_WIN_ASL_FLAGS) +*_VS2015x86_*_ASL_OUTFLAGS = DEF(DEFAULT_WIN_ASL_OUTFLAGS) +*_VS2015x86_*_ASLCC_FLAGS = DEF(MSFT_ASLCC_FLAGS) +*_VS2015x86_*_ASLPP_FLAGS = DEF(MSFT_ASLPP_FLAGS) +*_VS2015x86_*_ASLDLINK_FLAGS = DEF(MSFT_ASLDLINK_FLAGS) + +################## +# IA32 definitions +################## +*_VS2015x86_IA32_*_DLL = DEF(VS2015x86_DLL) + +*_VS2015x86_IA32_MAKE_PATH = DEF(VS2015x86_BIN)\nmake.exe +*_VS2015x86_IA32_CC_PATH = DEF(VS2015x86_BIN)\cl.exe +*_VS2015x86_IA32_VFRPP_PATH = DEF(VS2015x86_BIN)\cl.exe +*_VS2015x86_IA32_ASLCC_PATH = DEF(VS2015x86_BIN)\cl.exe +*_VS2015x86_IA32_ASLPP_PATH = DEF(VS2015x86_BIN)\cl.exe +*_VS2015x86_IA32_SLINK_PATH = DEF(VS2015x86_BIN)\lib.exe +*_VS2015x86_IA32_DLINK_PATH = DEF(VS2015x86_BIN)\link.exe +*_VS2015x86_IA32_ASLDLINK_PATH= DEF(VS2015x86_BIN)\link.exe +*_VS2015x86_IA32_APP_PATH = DEF(VS2015x86_BIN)\cl.exe +*_VS2015x86_IA32_PP_PATH = DEF(VS2015x86_BIN)\cl.exe +*_VS2015x86_IA32_ASM_PATH = DEF(VS2015x86_BIN)\ml.exe + + *_VS2015x86_IA32_MAKE_FLAGS = /nologo + DEBUG_VS2015x86_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1ib2 /GL /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Zi /Gm +RELEASE_VS2015x86_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1ib2 /GL /FIAutoGen.h /EHs-c- /GR- /GF +NOOPT_VS2015x86_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Zi /Gm /Od + + DEBUG_VS2015x86_IA32_ASM_FLAGS = /nologo /c /WX /W3 /Cx /coff /Zd /Zi +RELEASE_VS2015x86_IA32_ASM_FLAGS = /nologo /c /WX /W3 /Cx /coff /Zd +NOOPT_VS2015x86_IA32_ASM_FLAGS = /nologo /c /WX /W3 /Cx /coff /Zd /Zi + + DEBUG_VS2015x86_IA32_NASM_FLAGS = -Ox -f win32 -g +RELEASE_VS2015x86_IA32_NASM_FLAGS = -Ox -f win32 +NOOPT_VS2015x86_IA32_NASM_FLAGS = -O0 -f win32 -g + + DEBUG_VS2015x86_IA32_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /MACHINE:X86 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /DEBUG +RELEASE_VS2015x86_IA32_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /IGNORE:4254 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /MACHINE:X86 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /MERGE:.rdata=.data +NOOPT_VS2015x86_IA32_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /MACHINE:X86 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /DEBUG + +################## +# X64 definitions +################## +*_VS2015x86_X64_*_DLL = DEF(VS2015x86_DLL) + +*_VS2015x86_X64_CC_PATH = DEF(VS2015x86_BINX64)\cl.exe +*_VS2015x86_X64_PP_PATH = DEF(VS2015x86_BINX64)\cl.exe +*_VS2015x86_X64_APP_PATH = DEF(VS2015x86_BINX64)\cl.exe +*_VS2015x86_X64_VFRPP_PATH = DEF(VS2015x86_BINX64)\cl.exe +*_VS2015x86_X64_ASLCC_PATH = DEF(VS2015x86_BINX64)\cl.exe +*_VS2015x86_X64_ASLPP_PATH = DEF(VS2015x86_BINX64)\cl.exe +*_VS2015x86_X64_ASM_PATH = DEF(VS2015x86_BINX64)\ml64.exe +*_VS2015x86_X64_SLINK_PATH = DEF(VS2015x86_BINX64)\lib.exe +*_VS2015x86_X64_DLINK_PATH = DEF(VS2015x86_BINX64)\link.exe +*_VS2015x86_X64_ASLDLINK_PATH = DEF(VS2015x86_BINX64)\link.exe + + DEBUG_VS2015x86_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1ib2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Zi /Gm +RELEASE_VS2015x86_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1ib2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF +NOOPT_VS2015x86_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Zi /Gm /Od + + DEBUG_VS2015x86_X64_ASM_FLAGS = /nologo /c /WX /W3 /Cx /Zd /Zi +RELEASE_VS2015x86_X64_ASM_FLAGS = /nologo /c /WX /W3 /Cx /Zd +NOOPT_VS2015x86_X64_ASM_FLAGS = /nologo /c /WX /W3 /Cx /Zd /Zi + + DEBUG_VS2015x86_X64_NASM_FLAGS = -Ox -f win64 -g +RELEASE_VS2015x86_X64_NASM_FLAGS = -Ox -f win64 +NOOPT_VS2015x86_X64_NASM_FLAGS = -O0 -f win64 -g + + DEBUG_VS2015x86_X64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:X64 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /DEBUG +RELEASE_VS2015x86_X64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /IGNORE:4254 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:X64 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /MERGE:.rdata=.data +NOOPT_VS2015x86_X64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:X64 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /DEBUG + +################## +# EBC definitions +################## +*_VS2015x86_EBC_*_FAMILY = INTEL +*_VS2015x86_EBC_*_DLL = DEF(VS2015x86_DLL) + +*_VS2015x86_EBC_MAKE_PATH = DEF(VS2015x86_BIN)\nmake.exe +*_VS2015x86_EBC_PP_PATH = DEF(EBC_BINx86)\iec.exe +*_VS2015x86_EBC_VFRPP_PATH = DEF(EBC_BINx86)\iec.exe +*_VS2015x86_EBC_CC_PATH = DEF(EBC_BINx86)\iec.exe +*_VS2015x86_EBC_SLINK_PATH = DEF(VS2015x86_BIN)\link.exe +*_VS2015x86_EBC_DLINK_PATH = DEF(VS2015x86_BIN)\link.exe + +*_VS2015x86_EBC_MAKE_FLAGS = /nologo +*_VS2015x86_EBC_PP_FLAGS = /nologo /E /TC /FIAutoGen.h +*_VS2015x86_EBC_CC_FLAGS = /nologo /c /WX /W3 /FIAutoGen.h /D$(MODULE_ENTRY_POINT)=$(ARCH_ENTRY_POINT) +*_VS2015x86_EBC_VFRPP_FLAGS = /nologo /E /TC /DVFRCOMPILE /FI$(MODULE_NAME)StrDefs.h +*_VS2015x86_EBC_SLINK_FLAGS = /lib /NOLOGO /MACHINE:EBC +*_VS2015x86_EBC_DLINK_FLAGS = "C:\Program Files (x86)\Intel\EBC\Lib\EbcLib.lib" /NOLOGO /NODEFAULTLIB /MACHINE:EBC /OPT:REF /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /MAP /ALIGN:32 /DRIVER + + +#################################################################################### +# VS2015x86xASL - Microsoft Visual Studio 2015 (x86) professional with Microsoft ASL +# ASL - Microsoft ACPI Source Language Compiler (asl.exe) +#################################################################################### +*_VS2015x86xASL_*_*_FAMILY = MSFT + +*_VS2015x86xASL_*_MAKE_PATH = DEF(VS2015x86_BIN)\nmake.exe +*_VS2015x86xASL_*_MAKE_FLAG = /nologo +*_VS2015x86xASL_*_RC_PATH = DEF(WINSDK81x86_BIN)\rc.exe + +*_VS2015x86xASL_*_MAKE_FLAGS = /nologo +*_VS2015x86xASL_*_SLINK_FLAGS = /NOLOGO /LTCG +*_VS2015x86xASL_*_APP_FLAGS = /nologo /E /TC +*_VS2015x86xASL_*_PP_FLAGS = /nologo /E /TC /FIAutoGen.h +*_VS2015x86xASL_*_VFRPP_FLAGS = /nologo /E /TC /DVFRCOMPILE /FI$(MODULE_NAME)StrDefs.h + +*_VS2015x86xASL_*_ASM16_PATH = DEF(VS2015x86_BIN)\ml.exe + +################## +# ASL definitions +################## +*_VS2015x86xASL_*_ASL_PATH = DEF(WIN_ASL_BIN) +*_VS2015x86xASL_*_ASL_FLAGS = DEF(MS_ASL_FLAGS) +*_VS2015x86xASL_*_ASL_OUTFLAGS = DEF(MS_ASL_OUTFLAGS) +*_VS2015x86xASL_*_ASLCC_FLAGS = DEF(MSFT_ASLCC_FLAGS) +*_VS2015x86xASL_*_ASLPP_FLAGS = DEF(MSFT_ASLPP_FLAGS) +*_VS2015x86xASL_*_ASLDLINK_FLAGS = DEF(MSFT_ASLDLINK_FLAGS) + +################## +# IA32 definitions +################## +*_VS2015x86xASL_IA32_*_DLL = DEF(VS2015x86_DLL) + +*_VS2015x86xASL_IA32_MAKE_PATH = DEF(VS2015x86_BIN)\nmake.exe +*_VS2015x86xASL_IA32_CC_PATH = DEF(VS2015x86_BIN)\cl.exe +*_VS2015x86xASL_IA32_VFRPP_PATH = DEF(VS2015x86_BIN)\cl.exe +*_VS2015x86xASL_IA32_ASLCC_PATH = DEF(VS2015x86_BIN)\cl.exe +*_VS2015x86xASL_IA32_ASLPP_PATH = DEF(VS2015x86_BIN)\cl.exe +*_VS2015x86xASL_IA32_SLINK_PATH = DEF(VS2015x86_BIN)\lib.exe +*_VS2015x86xASL_IA32_DLINK_PATH = DEF(VS2015x86_BIN)\link.exe +*_VS2015x86xASL_IA32_ASLDLINK_PATH= DEF(VS2015x86_BIN)\link.exe +*_VS2015x86xASL_IA32_APP_PATH = DEF(VS2015x86_BIN)\cl.exe +*_VS2015x86xASL_IA32_PP_PATH = DEF(VS2015x86_BIN)\cl.exe +*_VS2015x86xASL_IA32_ASM_PATH = DEF(VS2015x86_BIN)\ml.exe + + *_VS2015x86xASL_IA32_MAKE_FLAGS = /nologo + DEBUG_VS2015x86xASL_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1ib2 /GL /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Zi /Gm +RELEASE_VS2015x86xASL_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1ib2 /GL /FIAutoGen.h /EHs-c- /GR- /GF +NOOPT_VS2015x86xASL_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Zi /Gm /Od + + DEBUG_VS2015x86xASL_IA32_ASM_FLAGS = /nologo /c /WX /W3 /Cx /coff /Zd /Zi +RELEASE_VS2015x86xASL_IA32_ASM_FLAGS = /nologo /c /WX /W3 /Cx /coff /Zd +NOOPT_VS2015x86xASL_IA32_ASM_FLAGS = /nologo /c /WX /W3 /Cx /coff /Zd /Zi + + DEBUG_VS2015x86xASL_IA32_NASM_FLAGS = -Ox -f win32 -g +RELEASE_VS2015x86xASL_IA32_NASM_FLAGS = -Ox -f win32 +NOOPT_VS2015x86xASL_IA32_NASM_FLAGS = -O0 -f win32 -g + + DEBUG_VS2015x86xASL_IA32_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /MACHINE:X86 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /DEBUG +RELEASE_VS2015x86xASL_IA32_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /IGNORE:4254 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /MACHINE:X86 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /MERGE:.rdata=.data +NOOPT_VS2015x86xASL_IA32_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /MACHINE:X86 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /DEBUG + +################## +# X64 definitions +################## +*_VS2015x86xASL_X64_*_DLL = DEF(VS2015x86_DLL) + +*_VS2015x86xASL_X64_CC_PATH = DEF(VS2015x86_BINX64)\cl.exe +*_VS2015x86xASL_X64_PP_PATH = DEF(VS2015x86_BINX64)\cl.exe +*_VS2015x86xASL_X64_APP_PATH = DEF(VS2015x86_BINX64)\cl.exe +*_VS2015x86xASL_X64_VFRPP_PATH = DEF(VS2015x86_BINX64)\cl.exe +*_VS2015x86xASL_X64_ASLCC_PATH = DEF(VS2015x86_BINX64)\cl.exe +*_VS2015x86xASL_X64_ASLPP_PATH = DEF(VS2015x86_BINX64)\cl.exe +*_VS2015x86xASL_X64_ASM_PATH = DEF(VS2015x86_BINX64)\ml64.exe +*_VS2015x86xASL_X64_SLINK_PATH = DEF(VS2015x86_BINX64)\lib.exe +*_VS2015x86xASL_X64_DLINK_PATH = DEF(VS2015x86_BINX64)\link.exe +*_VS2015x86xASL_X64_ASLDLINK_PATH = DEF(VS2015x86_BINX64)\link.exe + + DEBUG_VS2015x86xASL_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1ib2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Zi /Gm +RELEASE_VS2015x86xASL_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1ib2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF +NOOPT_VS2015x86xASL_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Zi /Gm /Od + + DEBUG_VS2015x86xASL_X64_ASM_FLAGS = /nologo /c /WX /W3 /Cx /Zd /Zi +RELEASE_VS2015x86xASL_X64_ASM_FLAGS = /nologo /c /WX /W3 /Cx /Zd +NOOPT_VS2015x86xASL_X64_ASM_FLAGS = /nologo /c /WX /W3 /Cx /Zd /Zi + + DEBUG_VS2015x86xASL_X64_NASM_FLAGS = -Ox -f win64 -g +RELEASE_VS2015x86xASL_X64_NASM_FLAGS = -Ox -f win64 +NOOPT_VS2015x86xASL_X64_NASM_FLAGS = -O0 -f win64 -g + + DEBUG_VS2015x86xASL_X64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:X64 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /DEBUG +RELEASE_VS2015x86xASL_X64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /IGNORE:4254 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:X64 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /MERGE:.rdata=.data +NOOPT_VS2015x86xASL_X64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:X64 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /DEBUG + +################## +# EBC definitions +################## +*_VS2015x86xASL_EBC_*_FAMILY = INTEL +*_VS2015x86xASL_EBC_*_DLL = DEF(VS2015x86_DLL) + +*_VS2015x86xASL_EBC_MAKE_PATH = DEF(VS2015x86_BIN)\nmake.exe +*_VS2015x86xASL_EBC_PP_PATH = DEF(EBC_BINx86)\iec.exe +*_VS2015x86xASL_EBC_VFRPP_PATH = DEF(EBC_BINx86)\iec.exe +*_VS2015x86xASL_EBC_CC_PATH = DEF(EBC_BINx86)\iec.exe +*_VS2015x86xASL_EBC_SLINK_PATH = DEF(VS2015x86_BIN)\link.exe +*_VS2015x86xASL_EBC_DLINK_PATH = DEF(VS2015x86_BIN)\link.exe + +*_VS2015x86xASL_EBC_MAKE_FLAGS = /nologo +*_VS2015x86xASL_EBC_PP_FLAGS = /nologo /E /TC /FIAutoGen.h +*_VS2015x86xASL_EBC_CC_FLAGS = /nologo /c /WX /W3 /FIAutoGen.h /D$(MODULE_ENTRY_POINT)=$(ARCH_ENTRY_POINT) +*_VS2015x86xASL_EBC_VFRPP_FLAGS = /nologo /E /TC /DVFRCOMPILE /FI$(MODULE_NAME)StrDefs.h +*_VS2015x86xASL_EBC_SLINK_FLAGS = /lib /NOLOGO /MACHINE:EBC +*_VS2015x86xASL_EBC_DLINK_FLAGS = "C:\Program Files (x86)\Intel\EBC\Lib\EbcLib.lib" /NOLOGO /NODEFAULTLIB /MACHINE:EBC /OPT:REF /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /MAP /ALIGN:32 /DRIVER + + #################################################################################### # # Microsoft Device Driver Kit 3790.1830 (IA-32, X64, Itanium, with Link Time Code Generation) diff --git a/edksetup.bat b/edksetup.bat index b63c29916b06..b69bd26857f5 100755 --- a/edksetup.bat +++ b/edksetup.bat @@ -1,7 +1,7 @@ @REM @file @REM Windows batch file to setup a WORKSPACE environment @REM -@REM Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.
+@REM Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
@REM This program and the accompanying materials @REM are licensed and made available under the terms and conditions of the BSD License @REM which accompanies this distribution. The full text of the license may be found at @@ -63,27 +63,31 @@ if /I not "%1"=="--nt32" goto no_nt32 @REM and headers to interface with Windows. if not defined VCINSTALLDIR ( - if defined VS120COMNTOOLS ( - call "%VS120COMNTOOLS%\vsvars32.bat" + if defined VS140COMNTOOLS ( + call "%VS140COMNTOOLS%\vsvars32.bat" ) else ( - if defined VS110COMNTOOLS ( - call "%VS110COMNTOOLS%\vsvars32.bat" - ) else ( - if defined VS100COMNTOOLS ( - call "%VS100COMNTOOLS%\vsvars32.bat" + if defined VS120COMNTOOLS ( + call "%VS120COMNTOOLS%\vsvars32.bat" + ) else ( + if defined VS110COMNTOOLS ( + call "%VS110COMNTOOLS%\vsvars32.bat" ) else ( - if defined VS90COMNTOOLS ( - call "%VS90COMNTOOLS%\vsvars32.bat" + if defined VS100COMNTOOLS ( + call "%VS100COMNTOOLS%\vsvars32.bat" ) else ( - if defined VS80COMNTOOLS ( - call "%VS80COMNTOOLS%\vsvars32.bat" + if defined VS90COMNTOOLS ( + call "%VS90COMNTOOLS%\vsvars32.bat" ) else ( - if defined VS71COMNTOOLS ( - call "%VS71COMNTOOLS%\vsvars32.bat" + if defined VS80COMNTOOLS ( + call "%VS80COMNTOOLS%\vsvars32.bat" ) else ( - echo. - echo !!! WARNING !!! Cannot find Visual Studio !!! - echo. + if defined VS71COMNTOOLS ( + call "%VS71COMNTOOLS%\vsvars32.bat" + ) else ( + echo. + echo !!! WARNING !!! Cannot find Visual Studio !!! + echo. + ) ) ) ) From ea6947cdfb224d2544cb962f301c4ef0b66b5eb0 Mon Sep 17 00:00:00 2001 From: Liming Gao Date: Fri, 4 Dec 2015 03:44:11 +0000 Subject: [PATCH 200/525] MdePkg: Disable VS2015 warning C4701 & C4703 C4701 & C4703 may cause false positive issues. They have been disabled in VS2013. (Sync patch r19111 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Liming Gao Reviewed-by: Michael Kinney git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19118 6f19259b-4bc3-4df7-8a09-765794883524 --- MdePkg/Include/Ia32/ProcessorBind.h | 6 +++--- MdePkg/Include/X64/ProcessorBind.h | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/MdePkg/Include/Ia32/ProcessorBind.h b/MdePkg/Include/Ia32/ProcessorBind.h index 22f07ca6375e..458f7dd21b93 100644 --- a/MdePkg/Include/Ia32/ProcessorBind.h +++ b/MdePkg/Include/Ia32/ProcessorBind.h @@ -93,7 +93,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. // #pragma warning ( disable : 4206 ) -#if _MSC_VER == 1800 +#if _MSC_VER == 1800 || _MSC_VER == 1900 // // Disable these warnings for VS2013. @@ -101,13 +101,13 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. // // This warning is for potentially uninitialized local variable, and it may cause false -// positive issues in VS2013 build +// positive issues in VS2013 and VS2015 build // #pragma warning ( disable : 4701 ) // // This warning is for potentially uninitialized local pointer variable, and it may cause -// false positive issues in VS2013 build +// false positive issues in VS2013 and VS2015 build // #pragma warning ( disable : 4703 ) diff --git a/MdePkg/Include/X64/ProcessorBind.h b/MdePkg/Include/X64/ProcessorBind.h index 81dbe188ca49..705104af062a 100644 --- a/MdePkg/Include/X64/ProcessorBind.h +++ b/MdePkg/Include/X64/ProcessorBind.h @@ -94,7 +94,7 @@ // #pragma warning ( disable : 4206 ) -#if _MSC_VER == 1800 +#if _MSC_VER == 1800 || _MSC_VER == 1900 // // Disable these warnings for VS2013. @@ -102,13 +102,13 @@ // // This warning is for potentially uninitialized local variable, and it may cause false -// positive issues in VS2013 build +// positive issues in VS2013 and VS2015 build // #pragma warning ( disable : 4701 ) // // This warning is for potentially uninitialized local pointer variable, and it may cause -// false positive issues in VS2013 build +// false positive issues in VS2013 and VS2015 build // #pragma warning ( disable : 4703 ) From 54d3c76fc0e8681c01c9aa546a3b63ccf78bbfa6 Mon Sep 17 00:00:00 2001 From: Liming Gao Date: Fri, 4 Dec 2015 03:44:39 +0000 Subject: [PATCH 201/525] MdeModulePkg: Fix VS2015 warning C4459 in DriverSampleDxe warning C4459: declaration of 'PrivateData' hides global declaration. Update DriverSampleDxe to rename global variable name to be different. (Sync patch r19112 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Liming Gao Reviewed-by: Michael Kinney git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19119 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Universal/DriverSampleDxe/DriverSample.c | 72 +++++++++---------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/MdeModulePkg/Universal/DriverSampleDxe/DriverSample.c b/MdeModulePkg/Universal/DriverSampleDxe/DriverSample.c index 2f77d39e52db..8ec1d4e6e81c 100644 --- a/MdeModulePkg/Universal/DriverSampleDxe/DriverSample.c +++ b/MdeModulePkg/Universal/DriverSampleDxe/DriverSample.c @@ -21,7 +21,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. CHAR16 VariableName[] = L"MyIfrNVData"; CHAR16 MyEfiVar[] = L"MyEfiVar"; EFI_HANDLE DriverHandle[2] = {NULL, NULL}; -DRIVER_SAMPLE_PRIVATE_DATA *PrivateData = NULL; +DRIVER_SAMPLE_PRIVATE_DATA *mPrivateData = NULL; EFI_EVENT mEvent; HII_VENDOR_DEVICE_PATH mHiiVendorDevicePath0 = { @@ -1895,17 +1895,17 @@ DriverSampleInit ( // // Initialize driver private data // - PrivateData = AllocateZeroPool (sizeof (DRIVER_SAMPLE_PRIVATE_DATA)); - if (PrivateData == NULL) { + mPrivateData = AllocateZeroPool (sizeof (DRIVER_SAMPLE_PRIVATE_DATA)); + if (mPrivateData == NULL) { return EFI_OUT_OF_RESOURCES; } - PrivateData->Signature = DRIVER_SAMPLE_PRIVATE_SIGNATURE; + mPrivateData->Signature = DRIVER_SAMPLE_PRIVATE_SIGNATURE; - PrivateData->ConfigAccess.ExtractConfig = ExtractConfig; - PrivateData->ConfigAccess.RouteConfig = RouteConfig; - PrivateData->ConfigAccess.Callback = DriverCallback; - PrivateData->PasswordState = BROWSER_STATE_VALIDATE_PASSWORD; + mPrivateData->ConfigAccess.ExtractConfig = ExtractConfig; + mPrivateData->ConfigAccess.RouteConfig = RouteConfig; + mPrivateData->ConfigAccess.Callback = DriverCallback; + mPrivateData->PasswordState = BROWSER_STATE_VALIDATE_PASSWORD; // // Locate Hii Database protocol @@ -1914,7 +1914,7 @@ DriverSampleInit ( if (EFI_ERROR (Status)) { return Status; } - PrivateData->HiiDatabase = HiiDatabase; + mPrivateData->HiiDatabase = HiiDatabase; // // Locate HiiString protocol @@ -1923,7 +1923,7 @@ DriverSampleInit ( if (EFI_ERROR (Status)) { return Status; } - PrivateData->HiiString = HiiString; + mPrivateData->HiiString = HiiString; // // Locate Formbrowser2 protocol @@ -1932,7 +1932,7 @@ DriverSampleInit ( if (EFI_ERROR (Status)) { return Status; } - PrivateData->FormBrowser2 = FormBrowser2; + mPrivateData->FormBrowser2 = FormBrowser2; // // Locate ConfigRouting protocol @@ -1941,7 +1941,7 @@ DriverSampleInit ( if (EFI_ERROR (Status)) { return Status; } - PrivateData->HiiConfigRouting = HiiConfigRouting; + mPrivateData->HiiConfigRouting = HiiConfigRouting; // // Locate keyword handler protocol @@ -1950,19 +1950,19 @@ DriverSampleInit ( if (EFI_ERROR (Status)) { return Status; } - PrivateData->HiiKeywordHandler = HiiKeywordHandler; + mPrivateData->HiiKeywordHandler = HiiKeywordHandler; Status = gBS->InstallMultipleProtocolInterfaces ( &DriverHandle[0], &gEfiDevicePathProtocolGuid, &mHiiVendorDevicePath0, &gEfiHiiConfigAccessProtocolGuid, - &PrivateData->ConfigAccess, + &mPrivateData->ConfigAccess, NULL ); ASSERT_EFI_ERROR (Status); - PrivateData->DriverHandle[0] = DriverHandle[0]; + mPrivateData->DriverHandle[0] = DriverHandle[0]; // // Publish our HII data @@ -1978,7 +1978,7 @@ DriverSampleInit ( return EFI_OUT_OF_RESOURCES; } - PrivateData->HiiHandle[0] = HiiHandle[0]; + mPrivateData->HiiHandle[0] = HiiHandle[0]; // // Publish another Fromset @@ -1988,12 +1988,12 @@ DriverSampleInit ( &gEfiDevicePathProtocolGuid, &mHiiVendorDevicePath1, &gEfiHiiConfigAccessProtocolGuid, - &PrivateData->ConfigAccess, + &mPrivateData->ConfigAccess, NULL ); ASSERT_EFI_ERROR (Status); - PrivateData->DriverHandle[1] = DriverHandle[1]; + mPrivateData->DriverHandle[1] = DriverHandle[1]; HiiHandle[1] = HiiAddPackages ( &gDriverSampleInventoryGuid, @@ -2007,7 +2007,7 @@ DriverSampleInit ( return EFI_OUT_OF_RESOURCES; } - PrivateData->HiiHandle[1] = HiiHandle[1]; + mPrivateData->HiiHandle[1] = HiiHandle[1]; // // Update the device path string. @@ -2037,14 +2037,14 @@ DriverSampleInit ( // // Initialize Name/Value name String ID // - PrivateData->NameStringId[0] = STR_NAME_VALUE_VAR_NAME0; - PrivateData->NameStringId[1] = STR_NAME_VALUE_VAR_NAME1; - PrivateData->NameStringId[2] = STR_NAME_VALUE_VAR_NAME2; + mPrivateData->NameStringId[0] = STR_NAME_VALUE_VAR_NAME0; + mPrivateData->NameStringId[1] = STR_NAME_VALUE_VAR_NAME1; + mPrivateData->NameStringId[2] = STR_NAME_VALUE_VAR_NAME2; // // Initialize configuration data // - Configuration = &PrivateData->Configuration; + Configuration = &mPrivateData->Configuration; ZeroMem (Configuration, sizeof (DRIVER_SAMPLE_CONFIGURATION)); // @@ -2109,7 +2109,7 @@ DriverSampleInit ( // // Initialize efi varstore configuration data // - VarStoreConfig = &PrivateData->VarStoreConfig; + VarStoreConfig = &mPrivateData->VarStoreConfig; ZeroMem (VarStoreConfig, sizeof (MY_EFI_VARSTORE_DATA)); ConfigRequestHdr = HiiConstructConfigHdr (&gDriverSampleFormSetGuid, MyEfiVar, DriverHandle[0]); @@ -2181,11 +2181,11 @@ DriverSampleInit ( // Register the default HotKey F9 and F10 again. // HotKey.ScanCode = SCAN_F10; - NewString = HiiGetString (PrivateData->HiiHandle[0], STRING_TOKEN (FUNCTION_TEN_STRING), NULL); + NewString = HiiGetString (mPrivateData->HiiHandle[0], STRING_TOKEN (FUNCTION_TEN_STRING), NULL); ASSERT (NewString != NULL); FormBrowserEx->RegisterHotKey (&HotKey, BROWSER_ACTION_SUBMIT, 0, NewString); HotKey.ScanCode = SCAN_F9; - NewString = HiiGetString (PrivateData->HiiHandle[0], STRING_TOKEN (FUNCTION_NINE_STRING), NULL); + NewString = HiiGetString (mPrivateData->HiiHandle[0], STRING_TOKEN (FUNCTION_NINE_STRING), NULL); ASSERT (NewString != NULL); FormBrowserEx->RegisterHotKey (&HotKey, BROWSER_ACTION_DEFAULT, EFI_HII_DEFAULT_CLASS_STANDARD, NewString); } @@ -2237,7 +2237,7 @@ DriverSampleUnload ( { UINTN Index; - ASSERT (PrivateData != NULL); + ASSERT (mPrivateData != NULL); if (DriverHandle[0] != NULL) { gBS->UninstallMultipleProtocolInterfaces ( @@ -2245,7 +2245,7 @@ DriverSampleUnload ( &gEfiDevicePathProtocolGuid, &mHiiVendorDevicePath0, &gEfiHiiConfigAccessProtocolGuid, - &PrivateData->ConfigAccess, + &mPrivateData->ConfigAccess, NULL ); DriverHandle[0] = NULL; @@ -2261,21 +2261,21 @@ DriverSampleUnload ( DriverHandle[1] = NULL; } - if (PrivateData->HiiHandle[0] != NULL) { - HiiRemovePackages (PrivateData->HiiHandle[0]); + if (mPrivateData->HiiHandle[0] != NULL) { + HiiRemovePackages (mPrivateData->HiiHandle[0]); } - if (PrivateData->HiiHandle[1] != NULL) { - HiiRemovePackages (PrivateData->HiiHandle[1]); + if (mPrivateData->HiiHandle[1] != NULL) { + HiiRemovePackages (mPrivateData->HiiHandle[1]); } for (Index = 0; Index < NAME_VALUE_NAME_NUMBER; Index++) { - if (PrivateData->NameValueName[Index] != NULL) { - FreePool (PrivateData->NameValueName[Index]); + if (mPrivateData->NameValueName[Index] != NULL) { + FreePool (mPrivateData->NameValueName[Index]); } } - FreePool (PrivateData); - PrivateData = NULL; + FreePool (mPrivateData); + mPrivateData = NULL; gBS->CloseEvent (mEvent); From 14a68bd79cb3a4d2237c56391a90fdf08ac68c2b Mon Sep 17 00:00:00 2001 From: Liming Gao Date: Fri, 4 Dec 2015 03:45:20 +0000 Subject: [PATCH 202/525] CryptoPkg: Disable VS2015 warning C4311 in OpensslLib Warning C4311: pointer truncation from 'type' to 'type'. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Liming Gao Reviewed-by: Qin Long Reviewed-by: Michael Kinney git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19120 6f19259b-4bc3-4df7-8a09-765794883524 --- CryptoPkg/Library/OpensslLib/OpensslLib.inf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CryptoPkg/Library/OpensslLib/OpensslLib.inf b/CryptoPkg/Library/OpensslLib/OpensslLib.inf index 28d3aec00e2a..aaf0a2982e10 100644 --- a/CryptoPkg/Library/OpensslLib/OpensslLib.inf +++ b/CryptoPkg/Library/OpensslLib/OpensslLib.inf @@ -891,9 +891,10 @@ # C4305: truncation from type1 to type2 of smaller size # C4306: conversion from type1 to type2 of greater size # C4702: Potentially uninitialized local variable name used + # C4311: pointer truncation from 'type' to 'type' # MSFT:*_*_IA32_CC_FLAGS = -U_WIN32 -U_WIN64 -U_MSC_VER $(OPENSSL_FLAGS) $(OPENSSL_EXFLAGS) -DTHIRTY_TWO_BIT /wd4244 /wd4701 /wd4702 /wd4706 - MSFT:*_*_X64_CC_FLAGS = -U_WIN32 -U_WIN64 -U_MSC_VER $(OPENSSL_FLAGS) $(OPENSSL_EXFLAGS) -DSIXTY_FOUR_BIT /wd4133 /wd4244 /wd4245 /wd4267 /wd4701 /wd4305 /wd4306 /wd4702 /wd4706 + MSFT:*_*_X64_CC_FLAGS = -U_WIN32 -U_WIN64 -U_MSC_VER $(OPENSSL_FLAGS) $(OPENSSL_EXFLAGS) -DSIXTY_FOUR_BIT /wd4133 /wd4244 /wd4245 /wd4267 /wd4701 /wd4305 /wd4306 /wd4702 /wd4706 /wd4311 MSFT:*_*_IPF_CC_FLAGS = -U_WIN32 -U_WIN64 -U_MSC_VER $(OPENSSL_FLAGS) $(OPENSSL_EXFLAGS) -DSIXTY_FOUR_BIT /wd4133 /wd4244 /wd4245 /wd4267 /wd4701 /wd4305 /wd4306 /wd4702 /wd4706 INTEL:*_*_IA32_CC_FLAGS = -U_WIN32 -U_WIN64 -U_MSC_VER -U__ICC $(OPENSSL_FLAGS) $(OPENSSL_EXFLAGS) /w -DTHIRTY_TWO_BIT From 174448723f38513b798ea63241de9d4332528c62 Mon Sep 17 00:00:00 2001 From: Liming Gao Date: Fri, 4 Dec 2015 03:46:05 +0000 Subject: [PATCH 203/525] OvmfPkg: Fix VS2015 warning C4459 in XenBusDxe warning C4459: declaration of 'xs' hides global declaration. Update code to rename local variable xs to xsp to be different. (Sync patch r19116 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Liming Gao Reviewed-by: Jordan Justen Acked-by: Michael Kinney git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19121 6f19259b-4bc3-4df7-8a09-765794883524 --- OvmfPkg/XenBusDxe/XenStore.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/OvmfPkg/XenBusDxe/XenStore.c b/OvmfPkg/XenBusDxe/XenStore.c index 9850f1e644fc..61976f91f11b 100644 --- a/OvmfPkg/XenBusDxe/XenStore.c +++ b/OvmfPkg/XenBusDxe/XenStore.c @@ -992,9 +992,9 @@ NotifyEventChannelCheckForEvent ( IN VOID *Context ) { - XENSTORE_PRIVATE *xs; - xs = (XENSTORE_PRIVATE *)Context; - if (TestAndClearBit (xs->EventChannel, xs->Dev->SharedInfo->evtchn_pending)) { + XENSTORE_PRIVATE *xsp; + xsp = (XENSTORE_PRIVATE *)Context; + if (TestAndClearBit (xsp->EventChannel, xsp->Dev->SharedInfo->evtchn_pending)) { gBS->SignalEvent (Event); } } @@ -1007,12 +1007,12 @@ NotifyEventChannelCheckForEvent ( STATIC EFI_STATUS XenStoreInitComms ( - XENSTORE_PRIVATE *xs + XENSTORE_PRIVATE *xsp ) { EFI_STATUS Status; EFI_EVENT TimerEvent; - struct xenstore_domain_interface *XenStore = xs->XenStore; + struct xenstore_domain_interface *XenStore = xsp->XenStore; Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent); Status = gBS->SetTimer (TimerEvent, TimerRelative, @@ -1029,8 +1029,8 @@ XenStoreInitComms ( gBS->CloseEvent (TimerEvent); Status = gBS->CreateEvent (EVT_NOTIFY_WAIT, TPL_NOTIFY, - NotifyEventChannelCheckForEvent, xs, - &xs->EventChannelEvent); + NotifyEventChannelCheckForEvent, xsp, + &xsp->EventChannelEvent); ASSERT_EFI_ERROR (Status); return Status; From a1395ce447423d0d3aa74fce5e790081caebb6c4 Mon Sep 17 00:00:00 2001 From: "Yao, Jiewen" Date: Mon, 7 Dec 2015 02:21:29 +0000 Subject: [PATCH 204/525] Move CommunicationBuffer from stack to global variable. We had put communication buffer to Runtime memory, so that SMI handler can know it is not used by OS. (Sync patch r18949 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: "Yao, Jiewen" Reviewed-by: "Zeng, Star" Reviewed-by: "Kinney, Michael D" git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19126 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Core/PiSmmCore/PiSmmIpl.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.c b/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.c index c534ee37011a..50c3b34dfd34 100644 --- a/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.c +++ b/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.c @@ -246,6 +246,8 @@ BOOLEAN mSmmLocked = FALSE; EFI_PHYSICAL_ADDRESS mSmramCacheBase; UINT64 mSmramCacheSize; +EFI_SMM_COMMUNICATE_HEADER mCommunicateHeader; + // // Table of Protocol notification and GUIDed Event notifications that the SMM IPL requires // @@ -538,21 +540,20 @@ SmmIplGuidedEventNotify ( IN VOID *Context ) { - EFI_SMM_COMMUNICATE_HEADER CommunicateHeader; UINTN Size; // // Use Guid to initialize EFI_SMM_COMMUNICATE_HEADER structure // - CopyGuid (&CommunicateHeader.HeaderGuid, (EFI_GUID *)Context); - CommunicateHeader.MessageLength = 1; - CommunicateHeader.Data[0] = 0; + CopyGuid (&mCommunicateHeader.HeaderGuid, (EFI_GUID *)Context); + mCommunicateHeader.MessageLength = 1; + mCommunicateHeader.Data[0] = 0; // // Generate the Software SMI and return the result // - Size = sizeof (CommunicateHeader); - SmmCommunicationCommunicate (&mSmmCommunication, &CommunicateHeader, &Size); + Size = sizeof (mCommunicateHeader); + SmmCommunicationCommunicate (&mSmmCommunication, &mCommunicateHeader, &Size); } /** @@ -569,7 +570,6 @@ SmmIplDxeDispatchEventNotify ( IN VOID *Context ) { - EFI_SMM_COMMUNICATE_HEADER CommunicateHeader; UINTN Size; EFI_STATUS Status; @@ -582,20 +582,20 @@ SmmIplDxeDispatchEventNotify ( // Clear the buffer passed into the Software SMI. This buffer will return // the status of the SMM Core Dispatcher. // - CopyGuid (&CommunicateHeader.HeaderGuid, (EFI_GUID *)Context); - CommunicateHeader.MessageLength = 1; - CommunicateHeader.Data[0] = 0; + CopyGuid (&mCommunicateHeader.HeaderGuid, (EFI_GUID *)Context); + mCommunicateHeader.MessageLength = 1; + mCommunicateHeader.Data[0] = 0; // // Generate the Software SMI and return the result // - Size = sizeof (CommunicateHeader); - SmmCommunicationCommunicate (&mSmmCommunication, &CommunicateHeader, &Size); + Size = sizeof (mCommunicateHeader); + SmmCommunicationCommunicate (&mSmmCommunication, &mCommunicateHeader, &Size); // // Return if there is no request to restart the SMM Core Dispatcher // - if (CommunicateHeader.Data[0] != COMM_BUFFER_SMM_DISPATCH_RESTART) { + if (mCommunicateHeader.Data[0] != COMM_BUFFER_SMM_DISPATCH_RESTART) { return; } From cc08065caea36f373f513f60cd800464e1955b5f Mon Sep 17 00:00:00 2001 From: Jeff Fan Date: Tue, 8 Dec 2015 08:39:21 +0000 Subject: [PATCH 205/525] UefiCpuPkg/CpuMpPei: Add missing point at function header (Sync patch r19165 from main trunk.) Cc: Qiu Shumin Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan Reviewed-by: Qiu Shumin git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19167 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/CpuMpPei/CpuMpPei.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.c b/UefiCpuPkg/CpuMpPei/CpuMpPei.c index ab1260d0451b..2e6e7611a261 100644 --- a/UefiCpuPkg/CpuMpPei/CpuMpPei.c +++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.c @@ -142,7 +142,7 @@ GetMpHobData ( } /** - Save the volatile registers required to be restored following INIT IPI + Save the volatile registers required to be restored following INIT IPI. @param VolatileRegisters Returns buffer saved the volatile resisters **/ @@ -173,7 +173,7 @@ SaveVolatileRegisters ( } /** - Restore the volatile registers following INIT IPI + Restore the volatile registers following INIT IPI. @param VolatileRegisters Pointer to volatile resisters @param IsRestoreDr TRUE: Restore DRx if supported From e5ece6913432c3dfdb842035021d4521ecd1836c Mon Sep 17 00:00:00 2001 From: Qin Long Date: Thu, 10 Dec 2015 07:15:21 +0000 Subject: [PATCH 206/525] CryptoPkg: Add one new API (Pkcs7GetCertificatesList) for certs retrieving. Adding one new API (Pkcs7GetCertificatesList) to retrieve and sort all embedded certificates from Pkcs7 signedData. This new API will provide the support for UEFI 2.5 Secure-Boot AuditMode feature. (Sync patch r18729 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Qin Long Reviewed-by: Chao Zhang Reviewed-by: Ting Ye git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19184 6f19259b-4bc3-4df7-8a09-765794883524 --- CryptoPkg/Include/Library/BaseCryptLib.h | 30 ++ .../BaseCryptLib/Pk/CryptPkcs7Verify.c | 288 ++++++++++++++++++ .../BaseCryptLib/Pk/CryptPkcs7VerifyNull.c | 34 +++ .../Pk/CryptPkcs7VerifyNull.c | 34 +++ 4 files changed, 386 insertions(+) diff --git a/CryptoPkg/Include/Library/BaseCryptLib.h b/CryptoPkg/Include/Library/BaseCryptLib.h index 95b75c92b8f5..390e302f98c8 100644 --- a/CryptoPkg/Include/Library/BaseCryptLib.h +++ b/CryptoPkg/Include/Library/BaseCryptLib.h @@ -1984,6 +1984,36 @@ Pkcs7FreeSigners ( IN UINT8 *Certs ); +/** + Retrieves all embedded certificates from PKCS#7 signed data as described in "PKCS #7: + Cryptographic Message Syntax Standard", and outputs two certificate lists chained and + unchained to the signer's certificates. + The input signed data could be wrapped in a ContentInfo structure. + + @param[in] P7Data Pointer to the PKCS#7 message. + @param[in] P7Length Length of the PKCS#7 message in bytes. + @param[out] SingerChainCerts Pointer to the certificates list chained to signer's + certificate. It's caller's responsiblity to free the buffer. + @param[out] ChainLength Length of the chained certificates list buffer in bytes. + @param[out] UnchainCerts Pointer to the unchained certificates lists. It's caller's + responsiblity to free the buffer. + @param[out] UnchainLength Length of the unchained certificates list buffer in bytes. + + @retval TRUE The operation is finished successfully. + @retval FALSE Error occurs during the operation. + +**/ +BOOLEAN +EFIAPI +Pkcs7GetCertificatesList ( + IN CONST UINT8 *P7Data, + IN UINTN P7Length, + OUT UINT8 **SignerChainCerts, + OUT UINTN *ChainLength, + OUT UINT8 **UnchainCerts, + OUT UINTN *UnchainLength + ); + /** Creates a PKCS#7 signedData as described in "PKCS #7: Cryptographic Message Syntax Standard, version 1.5". This interface is only intended to be used for diff --git a/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7Verify.c b/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7Verify.c index d0b0c838b83a..6c91dea58151 100644 --- a/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7Verify.c +++ b/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7Verify.c @@ -508,6 +508,294 @@ Pkcs7FreeSigners ( free (Certs); } +/** + Retrieves all embedded certificates from PKCS#7 signed data as described in "PKCS #7: + Cryptographic Message Syntax Standard", and outputs two certificate lists chained and + unchained to the signer's certificates. + The input signed data could be wrapped in a ContentInfo structure. + + @param[in] P7Data Pointer to the PKCS#7 message. + @param[in] P7Length Length of the PKCS#7 message in bytes. + @param[out] SingerChainCerts Pointer to the certificates list chained to signer's + certificate. It's caller's responsiblity to free the buffer. + @param[out] ChainLength Length of the chained certificates list buffer in bytes. + @param[out] UnchainCerts Pointer to the unchained certificates lists. It's caller's + responsiblity to free the buffer. + @param[out] UnchainLength Length of the unchained certificates list buffer in bytes. + + @retval TRUE The operation is finished successfully. + @retval FALSE Error occurs during the operation. + +**/ +BOOLEAN +EFIAPI +Pkcs7GetCertificatesList ( + IN CONST UINT8 *P7Data, + IN UINTN P7Length, + OUT UINT8 **SignerChainCerts, + OUT UINTN *ChainLength, + OUT UINT8 **UnchainCerts, + OUT UINTN *UnchainLength + ) +{ + BOOLEAN Status; + UINT8 *NewP7Data; + UINTN NewP7Length; + BOOLEAN Wrapped; + UINT8 Index; + PKCS7 *Pkcs7; + X509_STORE_CTX CertCtx; + STACK_OF(X509) *Signers; + X509 *Signer; + X509 *Cert; + X509 *TempCert; + X509 *Issuer; + UINT8 *CertBuf; + UINT8 *OldBuf; + UINTN BufferSize; + UINTN OldSize; + UINT8 *SingleCert; + UINTN CertSize; + + // + // Initializations + // + Status = FALSE; + NewP7Data = NULL; + Pkcs7 = NULL; + Cert = NULL; + TempCert = NULL; + SingleCert = NULL; + CertBuf = NULL; + OldBuf = NULL; + Signers = NULL; + + // + // Parameter Checking + // + if ((P7Data == NULL) || (SignerChainCerts == NULL) || (ChainLength == NULL) || + (UnchainCerts == NULL) || (UnchainLength == NULL) || (P7Length > INT_MAX)) { + return Status; + } + + *SignerChainCerts = NULL; + *ChainLength = 0; + *UnchainCerts = NULL; + *UnchainLength = 0; + + // + // Construct a new PKCS#7 data wrapping with ContentInfo structure if needed. + // + Status = WrapPkcs7Data (P7Data, P7Length, &Wrapped, &NewP7Data, &NewP7Length); + if (!Status || (NewP7Length > INT_MAX)) { + goto _Error; + } + + // + // Decodes PKCS#7 SignedData + // + Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **) &NewP7Data, (int) NewP7Length); + if ((Pkcs7 == NULL) || (!PKCS7_type_is_signed (Pkcs7))) { + goto _Error; + } + + // + // Obtains Signer's Certificate from PKCS#7 data + // NOTE: Only one signer case will be handled in this function, which means SignerInfos + // should include only one singer's certificate. + // + Signers = PKCS7_get0_signers (Pkcs7, NULL, PKCS7_BINARY); + if ((Signers == NULL) || (sk_X509_num (Signers) != 1)) { + goto _Error; + } + Signer = sk_X509_value (Signers, 0); + + if (!X509_STORE_CTX_init (&CertCtx, NULL, Signer, Pkcs7->d.sign->cert)) { + goto _Error; + } + // + // Initialize Chained & Untrusted stack + // + if (CertCtx.chain == NULL) { + if (((CertCtx.chain = sk_X509_new_null ()) == NULL) || + (!sk_X509_push (CertCtx.chain, CertCtx.cert))) { + goto _Error; + } + } + sk_X509_delete_ptr (CertCtx.untrusted, Signer); + + // + // Build certificates stack chained from Signer's certificate. + // + Cert = Signer; + for (; ;) { + // + // Self-Issue checking + // + if (CertCtx.check_issued (&CertCtx, Cert, Cert)) { + break; + } + + // + // Found the issuer of the current certificate + // + if (CertCtx.untrusted != NULL) { + Issuer = NULL; + for (Index = 0; Index < sk_X509_num (CertCtx.untrusted); Index++) { + TempCert = sk_X509_value (CertCtx.untrusted, Index); + if (CertCtx.check_issued (&CertCtx, Cert, TempCert)) { + Issuer = TempCert; + break; + } + } + if (Issuer != NULL) { + if (!sk_X509_push (CertCtx.chain, Issuer)) { + goto _Error; + } + sk_X509_delete_ptr (CertCtx.untrusted, Issuer); + + Cert = Issuer; + continue; + } + } + + break; + } + + // + // Converts Chained and Untrusted Certificate to Certificate Buffer in following format: + // UINT8 CertNumber; + // UINT32 Cert1Length; + // UINT8 Cert1[]; + // UINT32 Cert2Length; + // UINT8 Cert2[]; + // ... + // UINT32 CertnLength; + // UINT8 Certn[]; + // + + if (CertCtx.chain != NULL) { + BufferSize = sizeof (UINT8); + OldSize = BufferSize; + CertBuf = NULL; + + for (Index = 0; ; Index++) { + Status = X509PopCertificate (CertCtx.chain, &SingleCert, &CertSize); + if (!Status) { + break; + } + + OldSize = BufferSize; + OldBuf = CertBuf; + BufferSize = OldSize + CertSize + sizeof (UINT32); + CertBuf = malloc (BufferSize); + + if (CertBuf == NULL) { + Status = FALSE; + goto _Error; + } + if (OldBuf != NULL) { + CopyMem (CertBuf, OldBuf, OldSize); + free (OldBuf); + OldBuf = NULL; + } + + WriteUnaligned32 ((UINT32 *) (CertBuf + OldSize), (UINT32) CertSize); + CopyMem (CertBuf + OldSize + sizeof (UINT32), SingleCert, CertSize); + + free (SingleCert); + SingleCert = NULL; + } + + if (CertBuf != NULL) { + // + // Update CertNumber. + // + CertBuf[0] = Index; + + *SignerChainCerts = CertBuf; + *ChainLength = BufferSize; + } + } + + if (CertCtx.untrusted != NULL) { + BufferSize = sizeof (UINT8); + OldSize = BufferSize; + CertBuf = NULL; + + for (Index = 0; ; Index++) { + Status = X509PopCertificate (CertCtx.untrusted, &SingleCert, &CertSize); + if (!Status) { + break; + } + + OldSize = BufferSize; + OldBuf = CertBuf; + BufferSize = OldSize + CertSize + sizeof (UINT32); + CertBuf = malloc (BufferSize); + + if (CertBuf == NULL) { + Status = FALSE; + goto _Error; + } + if (OldBuf != NULL) { + CopyMem (CertBuf, OldBuf, OldSize); + free (OldBuf); + OldBuf = NULL; + } + + WriteUnaligned32 ((UINT32 *) (CertBuf + OldSize), (UINT32) CertSize); + CopyMem (CertBuf + OldSize + sizeof (UINT32), SingleCert, CertSize); + + free (SingleCert); + SingleCert = NULL; + } + + if (CertBuf != NULL) { + // + // Update CertNumber. + // + CertBuf[0] = Index; + + *UnchainCerts = CertBuf; + *UnchainLength = BufferSize; + } + } + + Status = TRUE; + +_Error: + // + // Release Resources. + // + if (!Wrapped && (NewP7Data != NULL)) { + free (NewP7Data); + } + + if (Pkcs7 != NULL) { + PKCS7_free (Pkcs7); + } + sk_X509_free (Signers); + + X509_STORE_CTX_cleanup (&CertCtx); + + if (SingleCert != NULL) { + free (SingleCert); + } + + if (OldBuf != NULL) { + free (OldBuf); + } + + if (!Status && (CertBuf != NULL)) { + free (CertBuf); + *SignerChainCerts = NULL; + *UnchainCerts = NULL; + } + + return Status; +} + /** Verifies the validility of a PKCS#7 signed data as described in "PKCS #7: Cryptographic Message Syntax Standard". The input signed data could be wrapped diff --git a/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyNull.c b/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyNull.c index 09b92c7f159b..b9affe427503 100644 --- a/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyNull.c +++ b/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyNull.c @@ -66,6 +66,40 @@ Pkcs7FreeSigners ( ASSERT (FALSE); } +/** + Retrieves all embedded certificates from PKCS#7 signed data as described in "PKCS #7: + Cryptographic Message Syntax Standard", and outputs two certificate lists chained and + unchained to the signer's certificates. + The input signed data could be wrapped in a ContentInfo structure. + + @param[in] P7Data Pointer to the PKCS#7 message. + @param[in] P7Length Length of the PKCS#7 message in bytes. + @param[out] SingerChainCerts Pointer to the certificates list chained to signer's + certificate. It's caller's responsiblity to free the buffer. + @param[out] ChainLength Length of the chained certificates list buffer in bytes. + @param[out] UnchainCerts Pointer to the unchained certificates lists. It's caller's + responsiblity to free the buffer. + @param[out] UnchainLength Length of the unchained certificates list buffer in bytes. + + @retval TRUE The operation is finished successfully. + @retval FALSE Error occurs during the operation. + +**/ +BOOLEAN +EFIAPI +Pkcs7GetCertificatesList ( + IN CONST UINT8 *P7Data, + IN UINTN P7Length, + OUT UINT8 **SignerChainCerts, + OUT UINTN *ChainLength, + OUT UINT8 **UnchainCerts, + OUT UINTN *UnchainLength + ) +{ + ASSERT (FALSE); + return FALSE; +} + /** Verifies the validility of a PKCS#7 signed data as described in "PKCS #7: Cryptographic Message Syntax Standard". The input signed data could be wrapped diff --git a/CryptoPkg/Library/BaseCryptLibRuntimeCryptProtocol/Pk/CryptPkcs7VerifyNull.c b/CryptoPkg/Library/BaseCryptLibRuntimeCryptProtocol/Pk/CryptPkcs7VerifyNull.c index 09b92c7f159b..b9affe427503 100644 --- a/CryptoPkg/Library/BaseCryptLibRuntimeCryptProtocol/Pk/CryptPkcs7VerifyNull.c +++ b/CryptoPkg/Library/BaseCryptLibRuntimeCryptProtocol/Pk/CryptPkcs7VerifyNull.c @@ -66,6 +66,40 @@ Pkcs7FreeSigners ( ASSERT (FALSE); } +/** + Retrieves all embedded certificates from PKCS#7 signed data as described in "PKCS #7: + Cryptographic Message Syntax Standard", and outputs two certificate lists chained and + unchained to the signer's certificates. + The input signed data could be wrapped in a ContentInfo structure. + + @param[in] P7Data Pointer to the PKCS#7 message. + @param[in] P7Length Length of the PKCS#7 message in bytes. + @param[out] SingerChainCerts Pointer to the certificates list chained to signer's + certificate. It's caller's responsiblity to free the buffer. + @param[out] ChainLength Length of the chained certificates list buffer in bytes. + @param[out] UnchainCerts Pointer to the unchained certificates lists. It's caller's + responsiblity to free the buffer. + @param[out] UnchainLength Length of the unchained certificates list buffer in bytes. + + @retval TRUE The operation is finished successfully. + @retval FALSE Error occurs during the operation. + +**/ +BOOLEAN +EFIAPI +Pkcs7GetCertificatesList ( + IN CONST UINT8 *P7Data, + IN UINTN P7Length, + OUT UINT8 **SignerChainCerts, + OUT UINTN *ChainLength, + OUT UINT8 **UnchainCerts, + OUT UINTN *UnchainLength + ) +{ + ASSERT (FALSE); + return FALSE; +} + /** Verifies the validility of a PKCS#7 signed data as described in "PKCS #7: Cryptographic Message Syntax Standard". The input signed data could be wrapped From 93b745fa60c3f188eeaa93f120ad33d1469a648b Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Thu, 10 Dec 2015 07:15:53 +0000 Subject: [PATCH 207/525] CryptoPkg: fix AARCH64 build under CLANG35 The OpenSSL function sk_X509_delete_ptr() resolves through preprocessor substitution to '(X509 *)sk_delete_ptr()', in which the cast causes the call to be interpreted as an expression (whose value is not used) rather than a statement, resulting in the following error under Clang: ...: error: expression result unused [-Werror,-Wunused-value] Add (VOID) casts to silence the error. (Sync patch r18730 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ard Biesheuvel Reviewed-by: Qin Long git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19185 6f19259b-4bc3-4df7-8a09-765794883524 --- CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7Verify.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7Verify.c b/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7Verify.c index 6c91dea58151..d49fbb7afded 100644 --- a/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7Verify.c +++ b/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7Verify.c @@ -622,7 +622,7 @@ Pkcs7GetCertificatesList ( goto _Error; } } - sk_X509_delete_ptr (CertCtx.untrusted, Signer); + (VOID)sk_X509_delete_ptr (CertCtx.untrusted, Signer); // // Build certificates stack chained from Signer's certificate. @@ -652,7 +652,7 @@ Pkcs7GetCertificatesList ( if (!sk_X509_push (CertCtx.chain, Issuer)) { goto _Error; } - sk_X509_delete_ptr (CertCtx.untrusted, Issuer); + (VOID)sk_X509_delete_ptr (CertCtx.untrusted, Issuer); Cert = Issuer; continue; From b2a59c532279fff7ed980e5ff2222adcd59c8a84 Mon Sep 17 00:00:00 2001 From: Chao Zhang Date: Thu, 10 Dec 2015 07:16:34 +0000 Subject: [PATCH 208/525] MdePkg: Add AuditMode/DeployedMode name definition Add AuditMode/DeployedMode definition from Enable Secure Boot feature defined in UEFI2.5 Mantis 1263. https://mantis.uefi.org/mantis/view.php?id=1263 (Sync patch r19130 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Chao Zhang Reviewed-by: Zeng Star Reviewed-by: Long Qin git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19186 6f19259b-4bc3-4df7-8a09-765794883524 --- MdePkg/Include/Guid/GlobalVariable.h | 14 ++++++++++++++ MdePkg/Include/Guid/ImageAuthentication.h | 9 ++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/MdePkg/Include/Guid/GlobalVariable.h b/MdePkg/Include/Guid/GlobalVariable.h index 1e4fbc822718..e58f7a1e8c01 100644 --- a/MdePkg/Include/Guid/GlobalVariable.h +++ b/MdePkg/Include/Guid/GlobalVariable.h @@ -126,6 +126,20 @@ extern EFI_GUID gEfiGlobalVariableGuid; /// #define EFI_SETUP_MODE_NAME L"SetupMode" /// +/// Whether the system is operating in audit mode (1) or not (0). +/// All other values are reserved. Should be treated as read-only except when DeployedMode is 0. +/// Always becomes read-only after ExitBootServices() is called. +/// Its attribute is BS+RT. +/// +#define EFI_AUDIT_MODE_NAME L"AuditMode" +/// +/// Whether the system is operating in deployed mode (1) or not (0). +/// All other values are reserved. Should be treated as read-only when its value is 1. +/// Always becomes read-only after ExitBootServices() is called. +/// Its attribute is BS+RT. +/// +#define EFI_DEPLOYED_MODE_NAME L"DeployedMode" +/// /// The Key Exchange Key Signature Database. /// Its attribute is NV+BS+RT+AT. /// diff --git a/MdePkg/Include/Guid/ImageAuthentication.h b/MdePkg/Include/Guid/ImageAuthentication.h index 4f4296086d75..2f51935c0c76 100644 --- a/MdePkg/Include/Guid/ImageAuthentication.h +++ b/MdePkg/Include/Guid/ImageAuthentication.h @@ -43,9 +43,12 @@ #define SECURE_BOOT_MODE_ENABLE 1 #define SECURE_BOOT_MODE_DISABLE 0 -#define SETUP_MODE 1 -#define USER_MODE 0 - +#define SETUP_MODE_ENABLE 1 +#define SETUP_MODE_DISABLE 0 +#define DEPLOYED_MODE_ENABLE 1 +#define DEPLOYED_MODE_DISABLE 0 +#define AUDIT_MODE_ENABLE 1 +#define AUDIT_MODE_DISABLE 0 //*********************************************************************** // Signature Database From 54707a6bc7a627660f742c1111763d9e093184a6 Mon Sep 17 00:00:00 2001 From: Chao Zhang Date: Thu, 10 Dec 2015 07:17:12 +0000 Subject: [PATCH 209/525] MdeModulePkg: VarCheckUefiLib: Add DeployedMode/AuditMode var check logic DeployedMode & AuditMode are UINT8 Global variable according to Enable Secure Boot feature defined in UEFI2.5 Mantis 1263. Add them to var check list. https://mantis.uefi.org/mantis/view.php?id=1263 (Sync patch r19131 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Chao Zhang Reviewed-by: Zeng Star Reviewed-by: Long Qin git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19187 6f19259b-4bc3-4df7-8a09-765794883524 --- .../VarCheckUefiLibNullClass.c | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLibNullClass.c b/MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLibNullClass.c index 15144bd4c0a9..a4268ae113a9 100644 --- a/MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLibNullClass.c +++ b/MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLibNullClass.c @@ -425,6 +425,28 @@ UEFI_DEFINED_VARIABLE_ENTRY mGlobalVariableList[] = { }, NULL }, + { + EFI_AUDIT_MODE_NAME, + { + VAR_CHECK_VARIABLE_PROPERTY_REVISION, + 0, + VARIABLE_ATTRIBUTE_BS_RT, + sizeof (UINT8), + sizeof (UINT8) + }, + NULL + }, + { + EFI_DEPLOYED_MODE_NAME, + { + VAR_CHECK_VARIABLE_PROPERTY_REVISION, + 0, + VARIABLE_ATTRIBUTE_BS_RT, + sizeof (UINT8), + sizeof (UINT8) + }, + NULL + }, { EFI_KEY_EXCHANGE_KEY_NAME, { From 3d5dca0b88f2e1034553a9aa72930c6e7eb58bb3 Mon Sep 17 00:00:00 2001 From: Chao Zhang Date: Thu, 10 Dec 2015 07:17:41 +0000 Subject: [PATCH 210/525] SecurityPkg: Add gEdkiiSecureBootModeGuid definition Add gEdkiiSecureBootModeGuid definition for Enable Secure Boot feature defined in UEFI2.5 Mantis 1263. It is a private variable GUID. https://mantis.uefi.org/mantis/view.php?id=1263 (Sync patch r19132 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Chao Zhang Reviewed-by: Zeng Star Reviewed-by: Long Qin git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19188 6f19259b-4bc3-4df7-8a09-765794883524 --- SecurityPkg/Include/Guid/AuthenticatedVariableFormat.h | 1 + SecurityPkg/SecurityPkg.dec | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/SecurityPkg/Include/Guid/AuthenticatedVariableFormat.h b/SecurityPkg/Include/Guid/AuthenticatedVariableFormat.h index 1f007cfc73e2..7094d523b524 100644 --- a/SecurityPkg/Include/Guid/AuthenticatedVariableFormat.h +++ b/SecurityPkg/Include/Guid/AuthenticatedVariableFormat.h @@ -28,6 +28,7 @@ extern EFI_GUID gEfiSecureBootEnableDisableGuid; extern EFI_GUID gEfiCertDbGuid; extern EFI_GUID gEfiCustomModeEnableGuid; extern EFI_GUID gEfiVendorKeysNvGuid; +extern EFI_GUID gEdkiiSecureBootModeGuid; /// /// "SecureBootEnable" variable for the Secure Boot feature enable/disable. diff --git a/SecurityPkg/SecurityPkg.dec b/SecurityPkg/SecurityPkg.dec index 959acf06b4c2..d568b4757a0b 100644 --- a/SecurityPkg/SecurityPkg.dec +++ b/SecurityPkg/SecurityPkg.dec @@ -109,7 +109,11 @@ ## GUID used to "certdb" variable to store the signer's certificates for common variables with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute. # Include/Guid/AuthenticatedVariableFormat.h gEfiCertDbGuid = { 0xd9bee56e, 0x75dc, 0x49d9, { 0xb4, 0xd7, 0xb5, 0x34, 0x21, 0xf, 0x63, 0x7a } } - + + ## GUID used to "SecureBootMode" variable to save platform secure boot mode + # Include/Guid/AuthenticatedVariableFormat.h + gEdkiiSecureBootModeGuid = { 0xc573b77, 0xeb93, 0x4d3d, { 0xaf, 0xfc, 0x5f, 0xeb, 0xca, 0xfb, 0x65, 0xb0 } } + ## Hob GUID used to pass a TCG_PCR_EVENT from a TPM PEIM to a TPM DXE Driver. # Include/Guid/TcgEventHob.h gTcgEventEntryHobGuid = { 0x2b9ffb52, 0x1b13, 0x416f, { 0xa8, 0x7b, 0xbc, 0x93, 0xd, 0xef, 0x92, 0xa8 }} From 277a82548ac1a6d72be2c869cbd4a2b365f8d7c3 Mon Sep 17 00:00:00 2001 From: Chao Zhang Date: Thu, 10 Dec 2015 07:18:35 +0000 Subject: [PATCH 211/525] SecurityPkg: AuthVariableLib: Customized SecureBoot Mode transition. Implement Customized SecureBoot Mode transition logic according to Mantis 1263, including AuditMode/DeployedMode/PK update management. Also implement image verification logic in AuditMode. Image Certificate & Hash are recorded to EFI Image Execution Table. https://mantis.uefi.org/mantis/view.php?id=1263 (Sync patch r19133 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Chao Zhang Reviewed-by: Zeng Star Reviewed-by: Long Qin git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19189 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Library/AuthVariableLib/AuthService.c | 1414 ++++++++++++++--- .../AuthVariableLib/AuthServiceInternal.h | 93 ++ .../Library/AuthVariableLib/AuthVariableLib.c | 109 +- .../AuthVariableLib/AuthVariableLib.inf | 4 + .../DxeImageVerificationLib.c | 670 +++++++- 5 files changed, 1967 insertions(+), 323 deletions(-) diff --git a/SecurityPkg/Library/AuthVariableLib/AuthService.c b/SecurityPkg/Library/AuthVariableLib/AuthService.c index 1f9ba15384f2..5546c2e5c906 100644 --- a/SecurityPkg/Library/AuthVariableLib/AuthService.c +++ b/SecurityPkg/Library/AuthVariableLib/AuthService.c @@ -56,6 +56,54 @@ EFI_SIGNATURE_ITEM mSupportSigItem[] = { {EFI_CERT_X509_SHA512_GUID, 0, 80 } }; +// +// Secure Boot Mode state machine +// +SECURE_BOOT_MODE mSecureBootState[SecureBootModeTypeMax] = { + // USER MODE + { + AUDIT_MODE_DISABLE, // AuditMode + FALSE, // IsAuditModeRO, AuditMode is RW + DEPLOYED_MODE_DISABLE, // DeployedMode + FALSE, // IsDeployedModeRO, DeployedMode is RW + SETUP_MODE_DISABLE, // SetupMode + // SetupMode is always RO + SECURE_BOOT_MODE_ENABLE // SecureBoot + }, + // SETUP MODE + { + AUDIT_MODE_DISABLE, // AuditMode + FALSE, // IsAuditModeRO, AuditMode is RW + DEPLOYED_MODE_DISABLE, // DeployedMode + TRUE, // IsDeployedModeRO, DeployedMode is RO + SETUP_MODE_ENABLE, // SetupMode + // SetupMode is always RO + SECURE_BOOT_MODE_DISABLE // SecureBoot + }, + // AUDIT MODE + { + AUDIT_MODE_ENABLE, // AuditMode + TRUE, // AuditModeValAttr RO, AuditMode is RO + DEPLOYED_MODE_DISABLE, // DeployedMode + TRUE, // DeployedModeValAttr RO, DeployedMode is RO + SETUP_MODE_ENABLE, // SetupMode + // SetupMode is always RO + SECURE_BOOT_MODE_DISABLE // SecureBoot + }, + // DEPLOYED MODE + { + AUDIT_MODE_DISABLE, // AuditMode, AuditMode is RO + TRUE, // AuditModeValAttr RO + DEPLOYED_MODE_ENABLE, // DeployedMode + TRUE, // DeployedModeValAttr RO, DeployedMode is RO + SETUP_MODE_DISABLE, // SetupMode + // SetupMode is always RO + SECURE_BOOT_MODE_ENABLE // SecureBoot + } +}; + +SECURE_BOOT_MODE_TYPE mSecureBootMode; + /** Finds variable in storage blocks of volatile and non-volatile storage areas. @@ -179,74 +227,982 @@ AuthServiceInternalUpdateVariableWithMonotonicCount ( } /** - Update the variable region with Variable information. + Update the variable region with Variable information. + + @param[in] VariableName Name of variable. + @param[in] VendorGuid Guid of variable. + @param[in] Data Data pointer. + @param[in] DataSize Size of Data. + @param[in] Attributes Attribute value of the variable. + @param[in] TimeStamp Value of associated TimeStamp. + + @retval EFI_SUCCESS The update operation is success. + @retval EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_WRITE_PROTECTED Variable is write-protected. + @retval EFI_OUT_OF_RESOURCES There is not enough resource. + +**/ +EFI_STATUS +AuthServiceInternalUpdateVariableWithTimeStamp ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN VOID *Data, + IN UINTN DataSize, + IN UINT32 Attributes, + IN EFI_TIME *TimeStamp + ) +{ + EFI_STATUS FindStatus; + VOID *OrgData; + UINTN OrgDataSize; + AUTH_VARIABLE_INFO AuthVariableInfo; + + FindStatus = AuthServiceInternalFindVariable ( + VariableName, + VendorGuid, + &OrgData, + &OrgDataSize + ); + + // + // EFI_VARIABLE_APPEND_WRITE attribute only effects for existing variable + // + if (!EFI_ERROR (FindStatus) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0)) { + if ((CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) && + ((StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0) || (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0) || + (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) == 0))) || + (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0))) { + // + // For variables with formatted as EFI_SIGNATURE_LIST, the driver shall not perform an append of + // EFI_SIGNATURE_DATA values that are already part of the existing variable value. + // + FilterSignatureList ( + OrgData, + OrgDataSize, + Data, + &DataSize + ); + } + } + + ZeroMem (&AuthVariableInfo, sizeof (AuthVariableInfo)); + AuthVariableInfo.VariableName = VariableName; + AuthVariableInfo.VendorGuid = VendorGuid; + AuthVariableInfo.Data = Data; + AuthVariableInfo.DataSize = DataSize; + AuthVariableInfo.Attributes = Attributes; + AuthVariableInfo.TimeStamp = TimeStamp; + return mAuthVarLibContextIn->UpdateVariable ( + &AuthVariableInfo + ); +} + +/** + Initialize Secure Boot variables. + + @retval EFI_SUCCESS The initialization operation is successful. + @retval EFI_OUT_OF_RESOURCES There is not enough resource. + +**/ +EFI_STATUS +InitSecureBootVariables ( + VOID + ) +{ + EFI_STATUS Status; + UINT8 *Data; + UINTN DataSize; + UINT32 SecureBoot; + UINT8 SecureBootEnable; + SECURE_BOOT_MODE_TYPE SecureBootMode; + BOOLEAN IsPkPresent; + + // + // Find "PK" variable + // + Status = AuthServiceInternalFindVariable (EFI_PLATFORM_KEY_NAME, &gEfiGlobalVariableGuid, (VOID **) &Data, &DataSize); + if (EFI_ERROR (Status)) { + IsPkPresent = FALSE; + DEBUG ((EFI_D_INFO, "Variable %s does not exist.\n", EFI_PLATFORM_KEY_NAME)); + } else { + IsPkPresent = TRUE; + DEBUG ((EFI_D_INFO, "Variable %s exists.\n", EFI_PLATFORM_KEY_NAME)); + } + + // + // Init "SecureBootMode" variable. + // Initial case + // SecureBootMode doesn't exist. Init it with PK state + // 3 inconsistency cases need to sync + // 1.1 Add PK -> system break -> update SecureBootMode Var + // 1.2 Delete PK -> system break -> update SecureBootMode Var + // 1.3 Set AuditMode ->Delete PK -> system break -> Update SecureBootMode Var + // + Status = AuthServiceInternalFindVariable (EDKII_SECURE_BOOT_MODE_NAME, &gEdkiiSecureBootModeGuid, (VOID **)&Data, &DataSize); + if (EFI_ERROR(Status)) { + // + // Variable driver Initial Case + // + if (IsPkPresent) { + SecureBootMode = SecureBootModeTypeUserMode; + } else { + SecureBootMode = SecureBootModeTypeSetupMode; + } + } else { + // + // 3 inconsistency cases need to sync + // + SecureBootMode = (SECURE_BOOT_MODE_TYPE)*Data; + ASSERT(SecureBootMode < SecureBootModeTypeMax); + + if (IsPkPresent) { + // + // 3.1 Add PK -> system break -> update SecureBootMode Var + // + if (SecureBootMode == SecureBootModeTypeSetupMode) { + SecureBootMode = SecureBootModeTypeUserMode; + } else if (SecureBootMode == SecureBootModeTypeAuditMode) { + SecureBootMode = SecureBootModeTypeDeployedMode; + } + } else { + // + // 3.2 Delete PK -> system break -> update SecureBootMode Var + // 3.3 Set AuditMode ->Delete PK -> system break -> Update SecureBootMode Var. Reinit to be SetupMode + // + if ((SecureBootMode == SecureBootModeTypeUserMode) || (SecureBootMode == SecureBootModeTypeDeployedMode)) { + SecureBootMode = SecureBootModeTypeSetupMode; + } + } + } + + if (EFI_ERROR(Status) || (SecureBootMode != (SECURE_BOOT_MODE_TYPE)*Data)) { + // + // Update SecureBootMode Var + // + Status = AuthServiceInternalUpdateVariable ( + EDKII_SECURE_BOOT_MODE_NAME, + &gEdkiiSecureBootModeGuid, + &SecureBootMode, + sizeof (UINT8), + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS + ); + if (EFI_ERROR(Status)) { + return Status; + } + } + + // + // Init "AuditMode" + // + Status = AuthServiceInternalUpdateVariable ( + EFI_AUDIT_MODE_NAME, + &gEfiGlobalVariableGuid, + &mSecureBootState[SecureBootMode].AuditMode, + sizeof(UINT8), + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS + ); + if (EFI_ERROR(Status)) { + return Status; + } + + // + // Init "DeployedMode" + // + Status = AuthServiceInternalUpdateVariable ( + EFI_DEPLOYED_MODE_NAME, + &gEfiGlobalVariableGuid, + &mSecureBootState[SecureBootMode].DeployedMode, + sizeof(UINT8), + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS + ); + if (EFI_ERROR(Status)) { + return Status; + } + + // + // Init "SetupMode" + // + Status = AuthServiceInternalUpdateVariable ( + EFI_SETUP_MODE_NAME, + &gEfiGlobalVariableGuid, + &mSecureBootState[SecureBootMode].SetupMode, + sizeof(UINT8), + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS + ); + if (EFI_ERROR(Status)) { + return Status; + } + + // + // If "SecureBootEnable" variable exists, then update "SecureBoot" variable. + // If "SecureBootEnable" variable is SECURE_BOOT_ENABLE and in User Mode or Deployed Mode, Set "SecureBoot" variable to SECURE_BOOT_MODE_ENABLE. + // If "SecureBootEnable" variable is SECURE_BOOT_DISABLE, Set "SecureBoot" variable to SECURE_BOOT_MODE_DISABLE. + // + SecureBootEnable = SECURE_BOOT_DISABLE; + Status = AuthServiceInternalFindVariable (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid, (VOID **)&Data, &DataSize); + if (!EFI_ERROR(Status)) { + if (!IsPkPresent) { + // + // PK is cleared in runtime. "SecureBootMode" is not updated before reboot + // Delete "SecureBootMode" + // + Status = AuthServiceInternalUpdateVariable ( + EFI_SECURE_BOOT_ENABLE_NAME, + &gEfiSecureBootEnableDisableGuid, + &SecureBootEnable, + 0, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS + ); + } else { + SecureBootEnable = *Data; + } + } else if ((SecureBootMode == SecureBootModeTypeUserMode) || (SecureBootMode == SecureBootModeTypeDeployedMode)) { + // + // "SecureBootEnable" not exist, initialize it in User Mode or Deployed Mode. + // + SecureBootEnable = SECURE_BOOT_ENABLE; + Status = AuthServiceInternalUpdateVariable ( + EFI_SECURE_BOOT_ENABLE_NAME, + &gEfiSecureBootEnableDisableGuid, + &SecureBootEnable, + sizeof (UINT8), + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS + ); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // Create "SecureBoot" variable with BS+RT attribute set. + // + if ((SecureBootEnable == SECURE_BOOT_ENABLE) + && ((SecureBootMode == SecureBootModeTypeUserMode) || (SecureBootMode == SecureBootModeTypeDeployedMode))) { + SecureBoot = SECURE_BOOT_MODE_ENABLE; + } else { + SecureBoot = SECURE_BOOT_MODE_DISABLE; + } + Status = AuthServiceInternalUpdateVariable ( + EFI_SECURE_BOOT_MODE_NAME, + &gEfiGlobalVariableGuid, + &SecureBoot, + sizeof (UINT8), + EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS + ); + + DEBUG ((EFI_D_INFO, "SecureBootMode is %x\n", SecureBootMode)); + DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SECURE_BOOT_MODE_NAME, SecureBoot)); + DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SECURE_BOOT_ENABLE_NAME, SecureBootEnable)); + + // + // Save SecureBootMode in global space + // + mSecureBootMode = SecureBootMode; + + return Status; +} + +/** + Update SecureBootMode variable. + + @param[in] NewMode New Secure Boot Mode. + + @retval EFI_SUCCESS The initialization operation is successful. + @retval EFI_OUT_OF_RESOURCES There is not enough resource. + +**/ +EFI_STATUS +UpdateSecureBootMode( + IN SECURE_BOOT_MODE_TYPE NewMode + ) +{ + EFI_STATUS Status; + + // + // Update "SecureBootMode" variable to new Secure Boot Mode + // + Status = AuthServiceInternalUpdateVariable ( + EDKII_SECURE_BOOT_MODE_NAME, + &gEdkiiSecureBootModeGuid, + &NewMode, + sizeof (UINT8), + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS + ); + + if (!EFI_ERROR(Status)) { + DEBUG((EFI_D_INFO, "SecureBootMode Update to %x\n", NewMode)); + mSecureBootMode = NewMode; + } else { + DEBUG((EFI_D_ERROR, "SecureBootMode Update failure %x\n", Status)); + } + + return Status; +} + +/** + Current secure boot mode is AuditMode. This function performs secure boot mode transition + to a new mode. + + @param[in] NewMode New Secure Boot Mode. + + @retval EFI_SUCCESS The initialization operation is successful. + @retval EFI_OUT_OF_RESOURCES There is not enough resource. + +**/ +EFI_STATUS +TransitionFromAuditMode( + IN SECURE_BOOT_MODE_TYPE NewMode + ) +{ + EFI_STATUS Status; + UINT8 *AuditVarData; + UINT8 *DeployedVarData; + UINT8 *SetupVarData; + UINT8 *SecureBootVarData; + UINT8 SecureBootEnable; + UINTN DataSize; + + // + // AuditMode/DeployedMode/SetupMode/SecureBoot are all NON_NV variable maintained by Variable driver + // they can be RW. but can't be deleted. so they can always be found. + // + Status = AuthServiceInternalFindVariable ( + EFI_AUDIT_MODE_NAME, + &gEfiGlobalVariableGuid, + &AuditVarData, + &DataSize + ); + if (EFI_ERROR (Status)) { + ASSERT(FALSE); + } + + Status = AuthServiceInternalFindVariable ( + EFI_DEPLOYED_MODE_NAME, + &gEfiGlobalVariableGuid, + &DeployedVarData, + &DataSize + ); + if (EFI_ERROR (Status)) { + ASSERT(FALSE); + } + + Status = AuthServiceInternalFindVariable ( + EFI_SETUP_MODE_NAME, + &gEfiGlobalVariableGuid, + &SetupVarData, + &DataSize + ); + if (EFI_ERROR (Status)) { + ASSERT(FALSE); + } + + Status = AuthServiceInternalFindVariable ( + EFI_SECURE_BOOT_MODE_NAME, + &gEfiGlobalVariableGuid, + &SecureBootVarData, + &DataSize + ); + if (EFI_ERROR (Status)) { + ASSERT(FALSE); + } + + // + // Make Secure Boot Mode transition ATOMIC + // Update Private NV SecureBootMode Variable first, because it may fail due to NV range overflow. + // other tranisition logic are all memory operations. + // + Status = UpdateSecureBootMode(NewMode); + if (EFI_ERROR(Status)) { + DEBUG((EFI_D_ERROR, "Update SecureBootMode Variable fail %x\n", Status)); + } + + if (NewMode == SecureBootModeTypeDeployedMode) { + // + // Since PK is enrolled, can't rollback, always update SecureBootMode in memory + // + mSecureBootMode = NewMode; + Status = EFI_SUCCESS; + + // + // AuditMode ----> DeployedMode + // Side Effects + // AuditMode =: 0 / DeployedMode := 1 / SetupMode := 0 + // + // Update the value of AuditMode variable by a simple mem copy, this could avoid possible + // variable storage reclaim at runtime. + // + CopyMem (AuditVarData, &mSecureBootState[NewMode].AuditMode, sizeof(UINT8)); + // + // Update the value of DeployedMode variable by a simple mem copy, this could avoid possible + // variable storage reclaim at runtime. + // + CopyMem (DeployedVarData, &mSecureBootState[NewMode].DeployedMode, sizeof(UINT8)); + // + // Update the value of SetupMode variable by a simple mem copy, this could avoid possible + // variable storage reclaim at runtime. + // + CopyMem (SetupVarData, &mSecureBootState[NewMode].SetupMode, sizeof(UINT8)); + + if (mAuthVarLibContextIn->AtRuntime ()) { + // + // SecureBoot Variable indicates whether the platform firmware is operating + // in Secure boot mode (1) or not (0), so we should not change SecureBoot + // Variable in runtime. + // + return Status; + } + + // + // Update the value of SecureBoot variable by a simple mem copy, this could avoid possible + // variable storage reclaim at runtime. + // + CopyMem (SecureBootVarData, &mSecureBootState[NewMode].SecureBoot, sizeof(UINT8)); + + // + // Create "SecureBootEnable" variable as secure boot is enabled. + // + SecureBootEnable = SECURE_BOOT_ENABLE; + AuthServiceInternalUpdateVariable ( + EFI_SECURE_BOOT_ENABLE_NAME, + &gEfiSecureBootEnableDisableGuid, + &SecureBootEnable, + sizeof (SecureBootEnable), + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS + ); + } else { + DEBUG((EFI_D_ERROR, "Invalid state tranition from %x to %x\n", SecureBootModeTypeAuditMode, NewMode)); + ASSERT(FALSE); + } + + return Status; +} + +/** + Current secure boot mode is DeployedMode. This function performs secure boot mode transition + to a new mode. + + @param[in] NewMode New Secure Boot Mode. + + @retval EFI_SUCCESS The initialization operation is successful. + @retval EFI_OUT_OF_RESOURCES There is not enough resource. + +**/ +EFI_STATUS +TransitionFromDeployedMode( + IN SECURE_BOOT_MODE_TYPE NewMode + ) +{ + EFI_STATUS Status; + UINT8 *DeployedVarData; + UINT8 *SetupVarData; + UINT8 *SecureBootVarData; + UINT8 SecureBootEnable; + UINTN DataSize; + + // + // AuditMode/DeployedMode/SetupMode/SecureBoot are all NON_NV variable maintained by Variable driver + // they can be RW. but can't be deleted. so they can always be found. + // + Status = AuthServiceInternalFindVariable ( + EFI_DEPLOYED_MODE_NAME, + &gEfiGlobalVariableGuid, + &DeployedVarData, + &DataSize + ); + if (EFI_ERROR (Status)) { + ASSERT(FALSE); + } + + Status = AuthServiceInternalFindVariable ( + EFI_SETUP_MODE_NAME, + &gEfiGlobalVariableGuid, + &SetupVarData, + &DataSize + ); + if (EFI_ERROR (Status)) { + ASSERT(FALSE); + } + + Status = AuthServiceInternalFindVariable ( + EFI_SECURE_BOOT_MODE_NAME, + &gEfiGlobalVariableGuid, + &SecureBootVarData, + &DataSize + ); + if (EFI_ERROR (Status)) { + ASSERT(FALSE); + } + + // + // Make Secure Boot Mode transition ATOMIC + // Update Private NV SecureBootMode Variable first, because it may fail due to NV range overflow. + // other tranisition logic are all memory operations. + // + Status = UpdateSecureBootMode(NewMode); + if (EFI_ERROR(Status)) { + DEBUG((EFI_D_ERROR, "Update SecureBootMode Variable fail %x\n", Status)); + } + + switch(NewMode) { + case SecureBootModeTypeUserMode: + // + // DeployedMode ----> UserMode + // Side Effects + // DeployedMode := 0 + // + // Platform Specific DeployedMode clear. UpdateSecureBootMode fails and no other variables are updated before. rollback this transition + // + if (EFI_ERROR(Status)) { + return Status; + } + CopyMem (DeployedVarData, &mSecureBootState[NewMode].DeployedMode, sizeof(UINT8)); + + break; + + case SecureBootModeTypeSetupMode: + // + // Since PK is processed before, can't rollback, still update SecureBootMode in memory + // + mSecureBootMode = NewMode; + Status = EFI_SUCCESS; + + // + // DeployedMode ----> SetupMode + // + // Platform Specific PKpub clear or Delete Pkpub + // Side Effects + // DeployedMode := 0 / SetupMode := 1 / SecureBoot := 0 + // + // Update the value of DeployedMode variable by a simple mem copy, this could avoid possible + // variable storage reclaim at runtime. + // + CopyMem (DeployedVarData, &mSecureBootState[NewMode].DeployedMode, sizeof(UINT8)); + // + // Update the value of SetupMode variable by a simple mem copy, this could avoid possible + // variable storage reclaim at runtime. + // + CopyMem (SetupVarData, &mSecureBootState[NewMode].SetupMode, sizeof(UINT8)); + + if (mAuthVarLibContextIn->AtRuntime ()) { + // + // SecureBoot Variable indicates whether the platform firmware is operating + // in Secure boot mode (1) or not (0), so we should not change SecureBoot + // Variable in runtime. + // + return Status; + } + + // + // Update the value of SecureBoot variable by a simple mem copy, this could avoid possible + // variable storage reclaim at runtime. + // + CopyMem (SecureBootVarData, &mSecureBootState[NewMode].SecureBoot, sizeof(UINT8)); + + // + // Delete the "SecureBootEnable" variable as secure boot is Disabled. + // + SecureBootEnable = SECURE_BOOT_DISABLE; + AuthServiceInternalUpdateVariable ( + EFI_SECURE_BOOT_ENABLE_NAME, + &gEfiSecureBootEnableDisableGuid, + &SecureBootEnable, + 0, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS + ); + break; + + default: + DEBUG((EFI_D_ERROR, "Invalid state tranition from %x to %x\n", SecureBootModeTypeDeployedMode, NewMode)); + ASSERT(FALSE); + } + + return Status; +} + +/** + Current secure boot mode is UserMode. This function performs secure boot mode transition + to a new mode. + + @param[in] NewMode New Secure Boot Mode. + + @retval EFI_SUCCESS The initialization operation is successful. + @retval EFI_OUT_OF_RESOURCES There is not enough resource. + +**/ +EFI_STATUS +TransitionFromUserMode( + IN SECURE_BOOT_MODE_TYPE NewMode + ) +{ + EFI_STATUS Status; + UINT8 *AuditVarData; + UINT8 *DeployedVarData; + UINT8 *SetupVarData; + UINT8 *PkVarData; + UINT8 *SecureBootVarData; + UINT8 SecureBootEnable; + UINTN DataSize; + VARIABLE_ENTRY_CONSISTENCY VariableEntry; + + // + // AuditMode/DeployedMode/SetupMode/SecureBoot are all NON_NV variable maintained by Variable driver + // they can be RW. but can't be deleted. so they can always be found. + // + Status = AuthServiceInternalFindVariable ( + EFI_AUDIT_MODE_NAME, + &gEfiGlobalVariableGuid, + &AuditVarData, + &DataSize + ); + if (EFI_ERROR (Status)) { + ASSERT(FALSE); + } + + Status = AuthServiceInternalFindVariable ( + EFI_DEPLOYED_MODE_NAME, + &gEfiGlobalVariableGuid, + &DeployedVarData, + &DataSize + ); + if (EFI_ERROR (Status)) { + ASSERT(FALSE); + } + + Status = AuthServiceInternalFindVariable ( + EFI_SETUP_MODE_NAME, + &gEfiGlobalVariableGuid, + &SetupVarData, + &DataSize + ); + if (EFI_ERROR (Status)) { + ASSERT(FALSE); + } + + Status = AuthServiceInternalFindVariable ( + EFI_SECURE_BOOT_MODE_NAME, + &gEfiGlobalVariableGuid, + &SecureBootVarData, + &DataSize + ); + if (EFI_ERROR (Status)) { + ASSERT(FALSE); + } + + // + // Make Secure Boot Mode transition ATOMIC + // Update Private NV SecureBootMode Variable first, because it may fail due to NV range overflow. + // Other tranisition logic are all memory operations and PK delete is assumed to be always successful. + // + if (NewMode != SecureBootModeTypeAuditMode) { + Status = UpdateSecureBootMode(NewMode); + if (EFI_ERROR(Status)) { + DEBUG((EFI_D_ERROR, "Update SecureBootMode Variable fail %x\n", Status)); + } + } else { + // + // UserMode -----> AuditMode. Check RemainingSpace for SecureBootMode var first. + // Will update SecureBootMode after DeletePK logic + // + VariableEntry.VariableSize = sizeof(UINT8); + VariableEntry.Guid = &gEdkiiSecureBootModeGuid; + VariableEntry.Name = EDKII_SECURE_BOOT_MODE_NAME; + if (!mAuthVarLibContextIn->CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT, &VariableEntry, NULL)) { + return EFI_OUT_OF_RESOURCES; + } + } + + switch(NewMode) { + case SecureBootModeTypeDeployedMode: + // + // UpdateSecureBootMode fails and no other variables are updated before. rollback this transition + // + if (EFI_ERROR(Status)) { + return Status; + } + + // + // UserMode ----> DeployedMode + // Side Effects + // DeployedMode := 1 + // + CopyMem (DeployedVarData, &mSecureBootState[NewMode].DeployedMode, sizeof(UINT8)); + break; + + case SecureBootModeTypeAuditMode: + // + // UserMode ----> AuditMode + // Side Effects + // Delete PKpub / SetupMode := 1 / SecureBoot := 0 + // + // Delete PKpub without verification. Should always succeed. + // + PkVarData = NULL; + Status = AuthServiceInternalUpdateVariable ( + EFI_PLATFORM_KEY_NAME, + &gEfiGlobalVariableGuid, + PkVarData, + 0, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS + ); + if (EFI_ERROR(Status)) { + DEBUG((EFI_D_ERROR, "UserMode -> AuditMode. Delete PK fail %x\n", Status)); + ASSERT(FALSE); + } + + // + // Update Private NV SecureBootMode Variable + // + Status = UpdateSecureBootMode(NewMode); + if (EFI_ERROR(Status)) { + // + // Since PK is deleted successfully, Doesn't break, continue to update other variable. + // + DEBUG((EFI_D_ERROR, "Update SecureBootMode Variable fail %x\n", Status)); + } + CopyMem (AuditVarData, &mSecureBootState[NewMode].AuditMode, sizeof(UINT8)); + + // + // Fall into SetupMode logic + // + case SecureBootModeTypeSetupMode: + // + // Since PK is deleted before , can't rollback, still update SecureBootMode in memory + // + mSecureBootMode = NewMode; + Status = EFI_SUCCESS; + + // + // UserMode ----> SetupMode + // Side Effects + // DeployedMode :=0 / SetupMode :=1 / SecureBoot :=0 + // + // Update the value of SetupMode variable by a simple mem copy, this could avoid possible + // variable storage reclaim at runtime. + // + CopyMem (SetupVarData, &mSecureBootState[NewMode].SetupMode, sizeof(UINT8)); + + if (mAuthVarLibContextIn->AtRuntime ()) { + // + // SecureBoot Variable indicates whether the platform firmware is operating + // in Secure boot mode (1) or not (0), so we should not change SecureBoot + // Variable in runtime. + // + return Status; + } + + // + // Update the value of SecureBoot variable by a simple mem copy, this could avoid possible + // variable storage reclaim at runtime. + // + CopyMem (SecureBootVarData, &mSecureBootState[NewMode].SecureBoot, sizeof(UINT8)); + + // + // Delete the "SecureBootEnable" variable as secure boot is Disabled. + // + SecureBootEnable = SECURE_BOOT_DISABLE; + AuthServiceInternalUpdateVariable ( + EFI_SECURE_BOOT_ENABLE_NAME, + &gEfiSecureBootEnableDisableGuid, + &SecureBootEnable, + 0, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS + ); + + break; + + default: + DEBUG((EFI_D_ERROR, "Invalid state tranition from %x to %x\n", SecureBootModeTypeUserMode, NewMode)); + ASSERT(FALSE); + } + + return Status; +} + +/** + Current secure boot mode is SetupMode. This function performs secure boot mode transition + to a new mode. + + @param[in] NewMode New Secure Boot Mode. + + @retval EFI_SUCCESS The initialization operation is successful. + @retval EFI_OUT_OF_RESOURCES There is not enough resource. + +**/ +EFI_STATUS +TransitionFromSetupMode( + IN SECURE_BOOT_MODE_TYPE NewMode + ) +{ + EFI_STATUS Status; + UINT8 *AuditVarData; + UINT8 *SetupVarData; + UINT8 *SecureBootVarData; + UINT8 SecureBootEnable; + UINTN DataSize; + + // + // AuditMode/DeployedMode/SetupMode/SecureBoot are all NON_NV variable maintained by Variable driver + // they can be RW. but can't be deleted. so they can always be found. + // + Status = AuthServiceInternalFindVariable ( + EFI_AUDIT_MODE_NAME, + &gEfiGlobalVariableGuid, + &AuditVarData, + &DataSize + ); + if (EFI_ERROR (Status)) { + ASSERT(FALSE); + } + + Status = AuthServiceInternalFindVariable ( + EFI_SETUP_MODE_NAME, + &gEfiGlobalVariableGuid, + &SetupVarData, + &DataSize + ); + if (EFI_ERROR (Status)) { + ASSERT(FALSE); + } + + Status = AuthServiceInternalFindVariable ( + EFI_SECURE_BOOT_MODE_NAME, + &gEfiGlobalVariableGuid, + &SecureBootVarData, + &DataSize + ); + if (EFI_ERROR (Status)) { + ASSERT(FALSE); + } + + // + // Make Secure Boot Mode transition ATOMIC + // Update Private NV SecureBootMode Variable first, because it may fail due to NV range overflow. + // Other tranisition logic are all memory operations and PK delete is assumed to be always successful. + // + Status = UpdateSecureBootMode(NewMode); + if (EFI_ERROR(Status)) { + DEBUG((EFI_D_ERROR, "Update SecureBootMode Variable fail %x\n", Status)); + } + + switch(NewMode) { + case SecureBootModeTypeAuditMode: + // + // UpdateSecureBootMode fails and no other variables are updated before. rollback this transition + // + if (EFI_ERROR(Status)) { + return Status; + } + + // + // SetupMode ----> AuditMode + // Side Effects + // AuditMode := 1 + // + // Update the value of AuditMode variable by a simple mem copy, this could avoid possible + // variable storage reclaim at runtime. + // + CopyMem (AuditVarData, &mSecureBootState[NewMode].AuditMode, sizeof(UINT8)); + break; + + case SecureBootModeTypeUserMode: + // + // Since PK is enrolled before, can't rollback, still update SecureBootMode in memory + // + mSecureBootMode = NewMode; + Status = EFI_SUCCESS; + + // + // SetupMode ----> UserMode + // Side Effects + // SetupMode := 0 / SecureBoot := 1 + // + // Update the value of AuditMode variable by a simple mem copy, this could avoid possible + // variable storage reclaim at runtime. + // + CopyMem (SetupVarData, &mSecureBootState[NewMode].SetupMode, sizeof(UINT8)); + + if (mAuthVarLibContextIn->AtRuntime ()) { + // + // SecureBoot Variable indicates whether the platform firmware is operating + // in Secure boot mode (1) or not (0), so we should not change SecureBoot + // Variable in runtime. + // + return Status; + } + + // + // Update the value of SecureBoot variable by a simple mem copy, this could avoid possible + // variable storage reclaim at runtime. + // + CopyMem (SecureBootVarData, &mSecureBootState[NewMode].SecureBoot, sizeof(UINT8)); + + // + // Create the "SecureBootEnable" variable as secure boot is enabled. + // + SecureBootEnable = SECURE_BOOT_ENABLE; + AuthServiceInternalUpdateVariable ( + EFI_SECURE_BOOT_ENABLE_NAME, + &gEfiSecureBootEnableDisableGuid, + &SecureBootEnable, + sizeof (SecureBootEnable), + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS + ); + break; + + default: + DEBUG((EFI_D_ERROR, "Invalid state tranition from %x to %x\n", SecureBootModeTypeSetupMode, NewMode)); + ASSERT(FALSE); + } + + return Status; +} + +/** + This function performs main secure boot mode transition logic. - @param[in] VariableName Name of variable. - @param[in] VendorGuid Guid of variable. - @param[in] Data Data pointer. - @param[in] DataSize Size of Data. - @param[in] Attributes Attribute value of the variable. - @param[in] TimeStamp Value of associated TimeStamp. + @param[in] CurMode Current Secure Boot Mode. + @param[in] NewMode New Secure Boot Mode. - @retval EFI_SUCCESS The update operation is success. - @retval EFI_INVALID_PARAMETER Invalid parameter. - @retval EFI_WRITE_PROTECTED Variable is write-protected. + @retval EFI_SUCCESS The initialization operation is successful. @retval EFI_OUT_OF_RESOURCES There is not enough resource. + @retval EFI_INVALID_PARAMETER The Current Secure Boot Mode is wrong. **/ EFI_STATUS -AuthServiceInternalUpdateVariableWithTimeStamp ( - IN CHAR16 *VariableName, - IN EFI_GUID *VendorGuid, - IN VOID *Data, - IN UINTN DataSize, - IN UINT32 Attributes, - IN EFI_TIME *TimeStamp +SecureBootModeTransition( + IN SECURE_BOOT_MODE_TYPE CurMode, + IN SECURE_BOOT_MODE_TYPE NewMode ) { - EFI_STATUS FindStatus; - VOID *OrgData; - UINTN OrgDataSize; - AUTH_VARIABLE_INFO AuthVariableInfo; - - FindStatus = AuthServiceInternalFindVariable ( - VariableName, - VendorGuid, - &OrgData, - &OrgDataSize - ); + EFI_STATUS Status; // - // EFI_VARIABLE_APPEND_WRITE attribute only effects for existing variable + // SecureBootMode transition // - if (!EFI_ERROR (FindStatus) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0)) { - if ((CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) && - ((StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0) || (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0) || - (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) == 0))) || - (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0))) { - // - // For variables with formatted as EFI_SIGNATURE_LIST, the driver shall not perform an append of - // EFI_SIGNATURE_DATA values that are already part of the existing variable value. - // - FilterSignatureList ( - OrgData, - OrgDataSize, - Data, - &DataSize - ); - } + switch (CurMode) { + case SecureBootModeTypeUserMode: + Status = TransitionFromUserMode(NewMode); + break; + + case SecureBootModeTypeSetupMode: + Status = TransitionFromSetupMode(NewMode); + break; + + case SecureBootModeTypeAuditMode: + Status = TransitionFromAuditMode(NewMode); + break; + + case SecureBootModeTypeDeployedMode: + Status = TransitionFromDeployedMode(NewMode); + break; + + default: + Status = EFI_INVALID_PARAMETER; + ASSERT(FALSE); } - ZeroMem (&AuthVariableInfo, sizeof (AuthVariableInfo)); - AuthVariableInfo.VariableName = VariableName; - AuthVariableInfo.VendorGuid = VendorGuid; - AuthVariableInfo.Data = Data; - AuthVariableInfo.DataSize = DataSize; - AuthVariableInfo.Attributes = Attributes; - AuthVariableInfo.TimeStamp = TimeStamp; - return mAuthVarLibContextIn->UpdateVariable ( - &AuthVariableInfo - ); + return Status; + } /** @@ -597,129 +1553,6 @@ VerifyCounterBasedPayload ( } } -/** - Update platform mode. - - @param[in] Mode SETUP_MODE or USER_MODE. - - @return EFI_INVALID_PARAMETER Invalid parameter. - @return EFI_SUCCESS Update platform mode successfully. - -**/ -EFI_STATUS -UpdatePlatformMode ( - IN UINT32 Mode - ) -{ - EFI_STATUS Status; - VOID *Data; - UINTN DataSize; - UINT8 SecureBootMode; - UINT8 SecureBootEnable; - UINTN VariableDataSize; - - Status = AuthServiceInternalFindVariable ( - EFI_SETUP_MODE_NAME, - &gEfiGlobalVariableGuid, - &Data, - &DataSize - ); - if (EFI_ERROR (Status)) { - return Status; - } - - // - // Update the value of SetupMode variable by a simple mem copy, this could avoid possible - // variable storage reclaim at runtime. - // - mPlatformMode = (UINT8) Mode; - CopyMem (Data, &mPlatformMode, sizeof(UINT8)); - - if (mAuthVarLibContextIn->AtRuntime ()) { - // - // SecureBoot Variable indicates whether the platform firmware is operating - // in Secure boot mode (1) or not (0), so we should not change SecureBoot - // Variable in runtime. - // - return Status; - } - - // - // Check "SecureBoot" variable's existence. - // If it doesn't exist, firmware has no capability to perform driver signing verification, - // then set "SecureBoot" to 0. - // - Status = AuthServiceInternalFindVariable ( - EFI_SECURE_BOOT_MODE_NAME, - &gEfiGlobalVariableGuid, - &Data, - &DataSize - ); - // - // If "SecureBoot" variable exists, then check "SetupMode" variable update. - // If "SetupMode" variable is USER_MODE, "SecureBoot" variable is set to 1. - // If "SetupMode" variable is SETUP_MODE, "SecureBoot" variable is set to 0. - // - if (EFI_ERROR (Status)) { - SecureBootMode = SECURE_BOOT_MODE_DISABLE; - } else { - if (mPlatformMode == USER_MODE) { - SecureBootMode = SECURE_BOOT_MODE_ENABLE; - } else if (mPlatformMode == SETUP_MODE) { - SecureBootMode = SECURE_BOOT_MODE_DISABLE; - } else { - return EFI_NOT_FOUND; - } - } - - Status = AuthServiceInternalUpdateVariable ( - EFI_SECURE_BOOT_MODE_NAME, - &gEfiGlobalVariableGuid, - &SecureBootMode, - sizeof(UINT8), - EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS - ); - if (EFI_ERROR (Status)) { - return Status; - } - - // - // Check "SecureBootEnable" variable's existence. It can enable/disable secure boot feature. - // - Status = AuthServiceInternalFindVariable ( - EFI_SECURE_BOOT_ENABLE_NAME, - &gEfiSecureBootEnableDisableGuid, - &Data, - &DataSize - ); - - if (SecureBootMode == SECURE_BOOT_MODE_ENABLE) { - // - // Create the "SecureBootEnable" variable as secure boot is enabled. - // - SecureBootEnable = SECURE_BOOT_ENABLE; - VariableDataSize = sizeof (SecureBootEnable); - } else { - // - // Delete the "SecureBootEnable" variable if this variable exist as "SecureBoot" - // variable is not in secure boot state. - // - if (EFI_ERROR (Status)) { - return EFI_SUCCESS; - } - SecureBootEnable = SECURE_BOOT_DISABLE; - VariableDataSize = 0; - } - - Status = AuthServiceInternalUpdateVariable ( - EFI_SECURE_BOOT_ENABLE_NAME, - &gEfiSecureBootEnableDisableGuid, - &SecureBootEnable, - VariableDataSize, - EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS - ); - return Status; -} /** Check input data form to make sure it is a valid EFI_SIGNATURE_LIST for PK/KEK/db/dbx/dbt variable. @@ -879,6 +1712,121 @@ VendorKeyIsModified ( ); } +/** + Process Secure Boot Mode variable. + + Caution: This function may receive untrusted input. + This function may be invoked in SMM mode, and datasize and data are external input. + This function will do basic validation, before parse the data. + This function will parse the authentication carefully to avoid security issues, like + buffer overflow, integer overflow. + This function will check attribute carefully to avoid authentication bypass. + + @param[in] VariableName Name of Variable to be found. + @param[in] VendorGuid Variable vendor GUID. + @param[in] Data Data pointer. + @param[in] DataSize Size of Data found. If size is less than the + data, this value contains the required size. + @param[in] Attributes Attribute value of the variable + + @return EFI_INVALID_PARAMETER Invalid parameter + @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation + check carried out by the firmware. + @return EFI_WRITE_PROTECTED Variable is Read-Only. + @return EFI_SUCCESS Variable passed validation successfully. + +**/ +EFI_STATUS +ProcessSecureBootModeVar ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN VOID *Data, + IN UINTN DataSize, + IN UINT32 Attributes OPTIONAL + ) +{ + EFI_STATUS Status; + UINT8 *VarData; + UINTN VarDataSize; + + // + // Check "AuditMode", "DeployedMode" Variable ReadWrite Attributes + // if in Runtime, Always RO + // if in Boottime, Depends on current Secure Boot Mode + // + if (mAuthVarLibContextIn->AtRuntime()) { + return EFI_WRITE_PROTECTED; + } + + // + // Delete not OK + // + if ((DataSize != sizeof(UINT8)) || (Attributes == 0)) { + return EFI_INVALID_PARAMETER; + } + + if (StrCmp (VariableName, EFI_AUDIT_MODE_NAME) == 0) { + if(mSecureBootState[mSecureBootMode].IsAuditModeRO) { + return EFI_WRITE_PROTECTED; + } + } else { + // + // Platform specific deployedMode clear. Set DeployedMode = RW + // + if (!InCustomMode() || !UserPhysicalPresent() || mSecureBootMode != SecureBootModeTypeDeployedMode) { + if(mSecureBootState[mSecureBootMode].IsDeployedModeRO) { + return EFI_WRITE_PROTECTED; + } + } + } + + if (*(UINT8 *)Data != 0 && *(UINT8 *)Data != 1) { + return EFI_INVALID_PARAMETER; + } + + // + // AuditMode/DeployedMode/SetupMode/SecureBoot are all NON_NV variable maintained by Variable driver + // they can be RW. but can't be deleted. so they can always be found. + // + Status = AuthServiceInternalFindVariable ( + VariableName, + VendorGuid, + &VarData, + &VarDataSize + ); + if (EFI_ERROR(Status)) { + ASSERT(FALSE); + } + + // + // If AuditMode/DeployedMode is assigned same value. Simply return EFI_SUCCESS + // + if (*VarData == *(UINT8 *)Data) { + return EFI_SUCCESS; + } + + // + // Perform SecureBootMode transition + // + if (StrCmp (VariableName, EFI_AUDIT_MODE_NAME) == 0) { + DEBUG((EFI_D_INFO, "Current SecureBootMode %x Transfer to SecureBootMode %x\n", mSecureBootMode, SecureBootModeTypeAuditMode)); + return SecureBootModeTransition(mSecureBootMode, SecureBootModeTypeAuditMode); + } else if (StrCmp (VariableName, EFI_DEPLOYED_MODE_NAME) == 0) { + if (mSecureBootMode == SecureBootModeTypeDeployedMode) { + // + // Platform specific DeployedMode clear. InCustomMode() && UserPhysicalPresent() is checked before + // + DEBUG((EFI_D_INFO, "Current SecureBootMode %x. Transfer to SecureBootMode %x\n", mSecureBootMode, SecureBootModeTypeUserMode)); + return SecureBootModeTransition(mSecureBootMode, SecureBootModeTypeUserMode); + } else { + DEBUG((EFI_D_INFO, "Current SecureBootMode %x. Transfer to SecureBootMode %x\n", mSecureBootMode, SecureBootModeTypeDeployedMode)); + return SecureBootModeTransition(mSecureBootMode, SecureBootModeTypeDeployedMode); + } + } + + return EFI_INVALID_PARAMETER; +} + /** Process variable with platform key for verification. @@ -917,6 +1865,7 @@ ProcessVarWithPk ( BOOLEAN Del; UINT8 *Payload; UINTN PayloadSize; + VARIABLE_ENTRY_CONSISTENCY VariableEntry[2]; if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0 || (Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == 0) { @@ -927,19 +1876,55 @@ ProcessVarWithPk ( return EFI_INVALID_PARAMETER; } + // + // Init state of Del. State may change due to secure check + // Del = FALSE; - if ((InCustomMode() && UserPhysicalPresent()) || (mPlatformMode == SETUP_MODE && !IsPk)) { - Payload = (UINT8 *) Data + AUTHINFO2_SIZE (Data); - PayloadSize = DataSize - AUTHINFO2_SIZE (Data); - if (PayloadSize == 0) { - Del = TRUE; - } + Payload = (UINT8 *) Data + AUTHINFO2_SIZE (Data); + PayloadSize = DataSize - AUTHINFO2_SIZE (Data); + if (PayloadSize == 0) { + Del = TRUE; + } + + // + // Check the variable space for both PKpub and SecureBootMode variable. + // + VariableEntry[0].VariableSize = PayloadSize; + VariableEntry[0].Guid = &gEfiGlobalVariableGuid; + VariableEntry[0].Name = EFI_PLATFORM_KEY_NAME; + + VariableEntry[1].VariableSize = sizeof(UINT8); + VariableEntry[1].Guid = &gEdkiiSecureBootModeGuid; + VariableEntry[1].Name = EDKII_SECURE_BOOT_MODE_NAME; + + if ((InCustomMode() && UserPhysicalPresent()) || + (((mSecureBootMode == SecureBootModeTypeSetupMode) || (mSecureBootMode == SecureBootModeTypeAuditMode)) && !IsPk)) { Status = CheckSignatureListFormat(VariableName, VendorGuid, Payload, PayloadSize); if (EFI_ERROR (Status)) { return Status; } + // + // If delete PKpub, only check for "SecureBootMode" only + // if update / add PKpub, check both NewPKpub & "SecureBootMode" + // + if (IsPk) { + // + // Delete PKpub + // + if (Del && ((mSecureBootMode == SecureBootModeTypeUserMode) || (mSecureBootMode == SecureBootModeTypeDeployedMode)) + && !mAuthVarLibContextIn->CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT, &VariableEntry[1], NULL)){ + return EFI_OUT_OF_RESOURCES; + // + // Add PKpub + // + } else if (!Del && ((mSecureBootMode == SecureBootModeTypeSetupMode) || (mSecureBootMode == SecureBootModeTypeAuditMode)) + && !mAuthVarLibContextIn->CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT, &VariableEntry[0], &VariableEntry[1], NULL)) { + return EFI_OUT_OF_RESOURCES; + } + } + Status = AuthServiceInternalUpdateVariableWithTimeStamp ( VariableName, VendorGuid, @@ -952,10 +1937,17 @@ ProcessVarWithPk ( return Status; } - if ((mPlatformMode != SETUP_MODE) || IsPk) { + if (((mSecureBootMode != SecureBootModeTypeSetupMode) && (mSecureBootMode != SecureBootModeTypeAuditMode)) || IsPk) { Status = VendorKeyIsModified (); } - } else if (mPlatformMode == USER_MODE) { + } else if (mSecureBootMode == SecureBootModeTypeUserMode || mSecureBootMode == SecureBootModeTypeDeployedMode) { + // + // If delete PKpub, check "SecureBootMode" only + // + if (IsPk && Del && !mAuthVarLibContextIn->CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT, &VariableEntry[1], NULL)){ + return EFI_OUT_OF_RESOURCES; + } + // // Verify against X509 Cert in PK database. // @@ -970,8 +1962,19 @@ ProcessVarWithPk ( ); } else { // + // SetupMode or AuditMode to add PK // Verify against the certificate in data payload. // + // + // Check PKpub & SecureBootMode variable space consistency + // + if (!mAuthVarLibContextIn->CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT, &VariableEntry[0], &VariableEntry[1], NULL)) { + // + // No enough variable space to set PK successfully. + // + return EFI_OUT_OF_RESOURCES; + } + Status = VerifyTimeBasedPayloadAndUpdate ( VariableName, VendorGuid, @@ -984,16 +1987,30 @@ ProcessVarWithPk ( } if (!EFI_ERROR(Status) && IsPk) { - if (mPlatformMode == SETUP_MODE && !Del) { - // - // If enroll PK in setup mode, need change to user mode. - // - Status = UpdatePlatformMode (USER_MODE); - } else if (mPlatformMode == USER_MODE && Del){ - // - // If delete PK in user mode, need change to setup mode. - // - Status = UpdatePlatformMode (SETUP_MODE); + // + // Delete or Enroll PK causes SecureBootMode change + // + if (!Del) { + if (mSecureBootMode == SecureBootModeTypeSetupMode) { + // + // If enroll PK in setup mode, change to user mode. + // + Status = SecureBootModeTransition (mSecureBootMode, SecureBootModeTypeUserMode); + } else if (mSecureBootMode == SecureBootModeTypeAuditMode) { + // + // If enroll PK in Audit mode, change to Deployed mode. + // + Status = SecureBootModeTransition (mSecureBootMode, SecureBootModeTypeDeployedMode); + } else { + DEBUG((EFI_D_INFO, "PK is updated in %x mode. No SecureBootMode change.\n", mSecureBootMode)); + } + } else { + if ((mSecureBootMode == SecureBootModeTypeUserMode) || (mSecureBootMode == SecureBootModeTypeDeployedMode)) { + // + // If delete PK in User Mode or DeployedMode, change to Setup Mode. + // + Status = SecureBootModeTransition (mSecureBootMode, SecureBootModeTypeSetupMode); + } } } @@ -1046,7 +2063,8 @@ ProcessVarWithKek ( } Status = EFI_SUCCESS; - if (mPlatformMode == USER_MODE && !(InCustomMode() && UserPhysicalPresent())) { + if ((mSecureBootMode == SecureBootModeTypeUserMode || mSecureBootMode == SecureBootModeTypeDeployedMode) + && !(InCustomMode() && UserPhysicalPresent())) { // // Time-based, verify against X509 Cert KEK. // @@ -1083,7 +2101,7 @@ ProcessVarWithKek ( return Status; } - if (mPlatformMode != SETUP_MODE) { + if ((mSecureBootMode != SecureBootModeTypeSetupMode) && (mSecureBootMode != SecureBootModeTypeAuditMode)) { Status = VendorKeyIsModified (); } } diff --git a/SecurityPkg/Library/AuthVariableLib/AuthServiceInternal.h b/SecurityPkg/Library/AuthVariableLib/AuthServiceInternal.h index add05c21cce4..ec4b3d97f59f 100644 --- a/SecurityPkg/Library/AuthVariableLib/AuthServiceInternal.h +++ b/SecurityPkg/Library/AuthVariableLib/AuthServiceInternal.h @@ -117,6 +117,54 @@ typedef struct { } AUTH_CERT_DB_DATA; #pragma pack() +/// +/// "SecureBootMode" variable stores current secure boot mode. +/// The value type is SECURE_BOOT_MODE_TYPE. +/// +#define EDKII_SECURE_BOOT_MODE_NAME L"SecureBootMode" + +typedef enum { + SecureBootModeTypeUserMode, + SecureBootModeTypeSetupMode, + SecureBootModeTypeAuditMode, + SecureBootModeTypeDeployedMode, + SecureBootModeTypeMax +} SECURE_BOOT_MODE_TYPE; + +// +// Record status info of Customized Secure Boot Mode. +// +typedef struct { + /// + /// AuditMode variable value + /// + UINT8 AuditMode; + /// + /// AuditMode variable RW + /// + BOOLEAN IsAuditModeRO; + /// + /// DeployedMode variable value + /// + UINT8 DeployedMode; + /// + /// AuditMode variable RW + /// + BOOLEAN IsDeployedModeRO; + /// + /// SetupMode variable value + /// + UINT8 SetupMode; + /// + /// SetupMode is always RO. Skip IsSetupModeRO; + /// + + /// + /// SecureBoot variable value + /// + UINT8 SecureBoot; +} SECURE_BOOT_MODE; + extern UINT8 *mPubKeyStore; extern UINT32 mPubKeyNumber; extern UINT32 mMaxKeyNumber; @@ -130,6 +178,18 @@ extern VOID *mHashCtx; extern AUTH_VAR_LIB_CONTEXT_IN *mAuthVarLibContextIn; +/** + Initialize Secure Boot variables. + + @retval EFI_SUCCESS The initialization operation is successful. + @retval EFI_OUT_OF_RESOURCES There is not enough resource. + +**/ +EFI_STATUS +InitSecureBootVariables ( + VOID + ); + /** Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set @@ -219,6 +279,39 @@ FilterSignatureList ( IN OUT UINTN *NewDataSize ); +/** + Process Secure Boot Mode variable. + + Caution: This function may receive untrusted input. + This function may be invoked in SMM mode, and datasize and data are external input. + This function will do basic validation, before parse the data. + This function will parse the authentication carefully to avoid security issues, like + buffer overflow, integer overflow. + This function will check attribute carefully to avoid authentication bypass. + + @param[in] VariableName Name of Variable to be found. + @param[in] VendorGuid Variable vendor GUID. + @param[in] Data Data pointer. + @param[in] DataSize Size of Data found. If size is less than the + data, this value contains the required size. + @param[in] Attributes Attribute value of the variable + + @return EFI_INVALID_PARAMETER Invalid parameter + @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation + check carried out by the firmware. + @return EFI_WRITE_PROTECTED Variable is Read-Only. + @return EFI_SUCCESS Variable passed validation successfully. + +**/ +EFI_STATUS +ProcessSecureBootModeVar ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN VOID *Data, + IN UINTN DataSize, + IN UINT32 Attributes OPTIONAL + ); + /** Process variable with platform key for verification. diff --git a/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.c b/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.c index a54eaaa066bb..dee5e1dd9d85 100644 --- a/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.c +++ b/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.c @@ -33,7 +33,6 @@ UINT32 mMaxKeyNumber; UINT32 mMaxKeyDbSize; UINT8 *mCertDbStore; UINT32 mMaxCertDbSize; -UINT32 mPlatformMode; UINT8 mVendorKeyState; EFI_GUID mSignatureSupport[] = {EFI_CERT_SHA1_GUID, EFI_CERT_SHA256_GUID, EFI_CERT_RSA2048_GUID, EFI_CERT_X509_GUID}; @@ -99,6 +98,17 @@ VARIABLE_ENTRY_PROPERTY mAuthVarEntry[] = { MAX_UINTN } }, + { + &gEdkiiSecureBootModeGuid, + L"SecureBootMode", + { + VAR_CHECK_VARIABLE_PROPERTY_REVISION, + VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY, + VARIABLE_ATTRIBUTE_NV_BS_RT, + sizeof (UINT8), + sizeof (UINT8) + } + } }; VOID **mAuthVarAddressPointer[10]; @@ -132,8 +142,6 @@ AuthVariableLibInitialize ( UINT8 *Data; UINTN DataSize; UINTN CtxSize; - UINT8 SecureBootMode; - UINT8 SecureBootEnable; UINT8 CustomMode; UINT32 ListSize; @@ -208,31 +216,11 @@ AuthVariableLibInitialize ( mPubKeyNumber = (UINT32) (DataSize / sizeof (AUTHVAR_KEY_DB_DATA)); } - Status = AuthServiceInternalFindVariable (EFI_PLATFORM_KEY_NAME, &gEfiGlobalVariableGuid, (VOID **) &Data, &DataSize); - if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_INFO, "Variable %s does not exist.\n", EFI_PLATFORM_KEY_NAME)); - } else { - DEBUG ((EFI_D_INFO, "Variable %s exists.\n", EFI_PLATFORM_KEY_NAME)); - } - // - // Create "SetupMode" variable with BS+RT attribute set. + // Init Secure Boot variables // - if (EFI_ERROR (Status)) { - mPlatformMode = SETUP_MODE; - } else { - mPlatformMode = USER_MODE; - } - Status = AuthServiceInternalUpdateVariable ( - EFI_SETUP_MODE_NAME, - &gEfiGlobalVariableGuid, - &mPlatformMode, - sizeof(UINT8), - EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS - ); - if (EFI_ERROR (Status)) { - return Status; - } + Status = InitSecureBootVariables (); + // // Create "SignatureSupport" variable with BS+RT attribute set. @@ -248,69 +236,6 @@ AuthVariableLibInitialize ( return Status; } - // - // If "SecureBootEnable" variable exists, then update "SecureBoot" variable. - // If "SecureBootEnable" variable is SECURE_BOOT_ENABLE and in USER_MODE, Set "SecureBoot" variable to SECURE_BOOT_MODE_ENABLE. - // If "SecureBootEnable" variable is SECURE_BOOT_DISABLE, Set "SecureBoot" variable to SECURE_BOOT_MODE_DISABLE. - // - SecureBootEnable = SECURE_BOOT_DISABLE; - Status = AuthServiceInternalFindVariable (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid, (VOID **) &Data, &DataSize); - if (!EFI_ERROR (Status)) { - if (mPlatformMode == SETUP_MODE){ - // - // PK is cleared in runtime. "SecureBootMode" is not updated before reboot - // Delete "SecureBootMode" in SetupMode - // - Status = AuthServiceInternalUpdateVariable ( - EFI_SECURE_BOOT_ENABLE_NAME, - &gEfiSecureBootEnableDisableGuid, - &SecureBootEnable, - 0, - EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS - ); - } else { - SecureBootEnable = *(UINT8 *) Data; - } - } else if (mPlatformMode == USER_MODE) { - // - // "SecureBootEnable" not exist, initialize it in USER_MODE. - // - SecureBootEnable = SECURE_BOOT_ENABLE; - Status = AuthServiceInternalUpdateVariable ( - EFI_SECURE_BOOT_ENABLE_NAME, - &gEfiSecureBootEnableDisableGuid, - &SecureBootEnable, - sizeof (UINT8), - EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS - ); - if (EFI_ERROR (Status)) { - return Status; - } - } - - // - // Create "SecureBoot" variable with BS+RT attribute set. - // - if (SecureBootEnable == SECURE_BOOT_ENABLE && mPlatformMode == USER_MODE) { - SecureBootMode = SECURE_BOOT_MODE_ENABLE; - } else { - SecureBootMode = SECURE_BOOT_MODE_DISABLE; - } - Status = AuthServiceInternalUpdateVariable ( - EFI_SECURE_BOOT_MODE_NAME, - &gEfiGlobalVariableGuid, - &SecureBootMode, - sizeof (UINT8), - EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS - ); - if (EFI_ERROR (Status)) { - return Status; - } - - DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SETUP_MODE_NAME, mPlatformMode)); - DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SECURE_BOOT_MODE_NAME, SecureBootMode)); - DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SECURE_BOOT_ENABLE_NAME, SecureBootEnable)); - // // Initialize "CustomMode" in STANDARD_SECURE_BOOT_MODE state. // @@ -455,10 +380,16 @@ AuthVariableLibProcessVariable ( { EFI_STATUS Status; + // + // Process PK, KEK, Sigdb, AuditMode, DeployedMode separately. + // if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_PLATFORM_KEY_NAME) == 0)){ Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, Attributes, TRUE); } else if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0)) { Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, Attributes, FALSE); + } else if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) + && (StrCmp (VariableName, EFI_AUDIT_MODE_NAME) == 0 || StrCmp (VariableName, EFI_DEPLOYED_MODE_NAME) == 0)) { + Status = ProcessSecureBootModeVar(VariableName, VendorGuid, Data, DataSize, Attributes); } else if (CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) && ((StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0) || (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0) || diff --git a/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.inf b/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.inf index 3709f7baae0b..07a3ed541932 100644 --- a/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.inf +++ b/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.inf @@ -85,6 +85,10 @@ ## PRODUCES ## Variable:L"AuthVarKeyDatabase" gEfiAuthenticatedVariableGuid + ## CONSUMES ## Variable:L"SecureBootMode" + ## PRODUCES ## Variable:L"SecureBootMode" + gEdkiiSecureBootModeGuid + gEfiCertTypeRsa2048Sha256Guid ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the certificate. gEfiCertPkcs7Guid ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the certificate. gEfiCertX509Guid ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the signature. diff --git a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c index 5cb9f8144e2a..4b4d3bf77de5 100644 --- a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c +++ b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c @@ -711,6 +711,58 @@ GetImageExeInfoTableSize ( return TotalSize; } +/** + Create signature list based on input signature data and certificate type GUID. Caller is reposible + to free new created SignatureList. + + @param[in] SignatureData Signature data in SignatureList. + @param[in] SignatureDataSize Signature data size. + @param[in] CertType Certificate Type. + @param[out] SignatureList Created SignatureList. + @param[out] SignatureListSize Created SignatureListSize. + + @return EFI_OUT_OF_RESOURCES The operation is failed due to lack of resources. + @retval EFI_SUCCESS Successfully create signature list. + +**/ +EFI_STATUS +CreateSignatureList( + IN UINT8 *SignatureData, + IN UINTN SignatureDataSize, + IN EFI_GUID *CertType, + OUT EFI_SIGNATURE_LIST **SignatureList, + OUT UINTN *SignatureListSize + ) +{ + EFI_SIGNATURE_LIST *SignList; + UINTN SignListSize; + EFI_SIGNATURE_DATA *Signature; + + SignList = NULL; + *SignatureList = NULL; + + SignListSize = sizeof (EFI_SIGNATURE_LIST) + sizeof (EFI_SIGNATURE_DATA) - 1 + SignatureDataSize; + SignList = (EFI_SIGNATURE_LIST *) AllocateZeroPool (SignListSize); + if (SignList == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + SignList->SignatureHeaderSize = 0; + SignList->SignatureListSize = (UINT32) SignListSize; + SignList->SignatureSize = (UINT32) SignatureDataSize + sizeof (EFI_SIGNATURE_DATA) - 1; + CopyMem (&SignList->SignatureType, CertType, sizeof (EFI_GUID)); + + DEBUG((EFI_D_INFO, "SignatureDataSize %x\n", SignatureDataSize)); + Signature = (EFI_SIGNATURE_DATA *) ((UINT8 *) SignList + sizeof (EFI_SIGNATURE_LIST)); + CopyMem (Signature->SignatureData, SignatureData, SignatureDataSize); + + *SignatureList = SignList; + *SignatureListSize = SignListSize; + + return EFI_SUCCESS; + +} + /** Create an Image Execution Information Table entry and add it to system configuration table. @@ -737,11 +789,13 @@ AddImageExeInfo ( UINTN NewImageExeInfoEntrySize; UINTN NameStringLen; UINTN DevicePathSize; + CHAR16 *NameStr; ImageExeInfoTable = NULL; NewImageExeInfoTable = NULL; ImageExeInfoEntry = NULL; NameStringLen = 0; + NameStr = NULL; if (DevicePath == NULL) { return ; @@ -769,7 +823,12 @@ AddImageExeInfo ( } DevicePathSize = GetDevicePathSize (DevicePath); - NewImageExeInfoEntrySize = sizeof (EFI_IMAGE_EXECUTION_INFO) + NameStringLen + DevicePathSize + SignatureSize; + + // + // Signature size can be odd. Pad after signature to ensure next EXECUTION_INFO entry align + // + NewImageExeInfoEntrySize = sizeof (EFI_IMAGE_EXECUTION_INFO) + NameStringLen + DevicePathSize + SignatureSize; + NewImageExeInfoTable = (EFI_IMAGE_EXECUTION_INFO_TABLE *) AllocateRuntimePool (ImageExeInfoTableSize + NewImageExeInfoEntrySize); if (NewImageExeInfoTable == NULL) { return ; @@ -788,19 +847,21 @@ AddImageExeInfo ( WriteUnaligned32 ((UINT32 *) ImageExeInfoEntry, Action); WriteUnaligned32 ((UINT32 *) ((UINT8 *) ImageExeInfoEntry + sizeof (EFI_IMAGE_EXECUTION_ACTION)), (UINT32) NewImageExeInfoEntrySize); + NameStr = (CHAR16 *)(ImageExeInfoEntry + 1); if (Name != NULL) { - CopyMem ((UINT8 *) ImageExeInfoEntry + sizeof (EFI_IMAGE_EXECUTION_ACTION) + sizeof (UINT32), Name, NameStringLen); + CopyMem ((UINT8 *) NameStr, Name, NameStringLen); } else { - ZeroMem ((UINT8 *) ImageExeInfoEntry + sizeof (EFI_IMAGE_EXECUTION_ACTION) + sizeof (UINT32), sizeof (CHAR16)); + ZeroMem ((UINT8 *) NameStr, sizeof (CHAR16)); } + CopyMem ( - (UINT8 *) ImageExeInfoEntry + sizeof (EFI_IMAGE_EXECUTION_ACTION) + sizeof (UINT32) + NameStringLen, + (UINT8 *) NameStr + NameStringLen, DevicePath, DevicePathSize ); if (Signature != NULL) { CopyMem ( - (UINT8 *) ImageExeInfoEntry + sizeof (EFI_IMAGE_EXECUTION_ACTION) + sizeof (UINT32) + NameStringLen + DevicePathSize, + (UINT8 *) NameStr + NameStringLen + DevicePathSize, Signature, SignatureSize ); @@ -1087,6 +1148,53 @@ IsTimeZero ( return FALSE; } +/** + Record multiple certificate list & verification state of a verified image to + IMAGE_EXECUTION_TABLE. + + @param[in] CertBuf Certificate list buffer. + @param[in] CertBufLength Certificate list buffer. + @param[in] Action Certificate list action to be record. + @param[in] ImageName Image name. + @param[in] ImageDevicePath Image device path. + +**/ +VOID +RecordCertListToImageExeuctionTable( + IN UINT8 *CertBuf, + IN UINTN CertBufLength, + IN EFI_IMAGE_EXECUTION_ACTION Action, + IN CHAR16 *ImageName OPTIONAL, + IN CONST EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath OPTIONAL + ) +{ + UINT8 CertNumber; + UINT8 *CertPtr; + UINTN Index; + UINT8 *Cert; + UINTN CertSize; + EFI_STATUS Status; + EFI_SIGNATURE_LIST *SignatureList; + UINTN SignatureListSize; + + CertNumber = (UINT8) (*CertBuf); + CertPtr = CertBuf + 1; + for (Index = 0; Index < CertNumber; Index++) { + CertSize = (UINTN) ReadUnaligned32 ((UINT32 *)CertPtr); + Cert = (UINT8 *)CertPtr + sizeof (UINT32); + + // + // Record all cert in cert chain to be passed + // + Status = CreateSignatureList(Cert, CertSize, &gEfiCertX509Guid, &SignatureList, &SignatureListSize); + if (!EFI_ERROR(Status)) { + AddImageExeInfo (Action, ImageName, ImageDevicePath, SignatureList, SignatureListSize); + FreePool (SignatureList); + } + } +} + + /** Check whether the timestamp signature is valid and the signing time is also earlier than the revocation time. @@ -1197,8 +1305,11 @@ PassTimestampCheck ( Check whether the image signature is forbidden by the forbidden database (dbx). The image is forbidden to load if any certificates for signing are revoked before signing time. - @param[in] AuthData Pointer to the Authenticode signature retrieved from the signed image. - @param[in] AuthDataSize Size of the Authenticode signature in bytes. + @param[in] AuthData Pointer to the Authenticode signature retrieved from the signed image. + @param[in] AuthDataSize Size of the Authenticode signature in bytes. + @param[in] IsAuditMode Whether system Secure Boot Mode is in AuditMode. + @param[in] ImageName Name of the image to verify. + @param[in] ImageDevicePath DevicePath of the image to verify. @retval TRUE Image is forbidden by dbx. @retval FALSE Image is not forbidden by dbx. @@ -1206,8 +1317,11 @@ PassTimestampCheck ( **/ BOOLEAN IsForbiddenByDbx ( - IN UINT8 *AuthData, - IN UINTN AuthDataSize + IN UINT8 *AuthData, + IN UINTN AuthDataSize, + IN BOOLEAN IsAuditMode, + IN CHAR16 *ImageName OPTIONAL, + IN CONST EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath OPTIONAL ) { EFI_STATUS Status; @@ -1230,7 +1344,10 @@ IsForbiddenByDbx ( UINT8 *Cert; UINTN CertSize; EFI_TIME RevocationTime; - + UINT8 *SignerCert; + UINTN SignerCertLength; + UINT8 *UnchainCert; + UINTN UnchainCertLength; // // Variable Initialization // @@ -1245,6 +1362,10 @@ IsForbiddenByDbx ( BufferLength = 0; TrustedCert = NULL; TrustedCertLength = 0; + SignerCert = NULL; + SignerCertLength = 0; + UnchainCert = NULL; + UnchainCertLength = 0; // // The image will not be forbidden if dbx can't be got. @@ -1352,21 +1473,54 @@ IsForbiddenByDbx ( } Done: + if (IsForbidden && IsAuditMode) { + Pkcs7GetCertificatesList(AuthData, AuthDataSize, &SignerCert, &SignerCertLength, &UnchainCert, &UnchainCertLength); + + // + // Record all certs in image to be failed + // + if ((SignerCertLength != 0) && (SignerCert != NULL)) { + RecordCertListToImageExeuctionTable( + SignerCert, + SignerCertLength, + EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED | EFI_IMAGE_EXECUTION_INITIALIZED, + ImageName, + ImageDevicePath + ); + } + + if ((UnchainCertLength != 0) && (UnchainCert != NULL)) { + RecordCertListToImageExeuctionTable( + UnchainCert, + UnchainCertLength, + EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED | EFI_IMAGE_EXECUTION_INITIALIZED, + ImageName, + ImageDevicePath + ); + } + } + if (Data != NULL) { FreePool (Data); } Pkcs7FreeSigners (CertBuffer); Pkcs7FreeSigners (TrustedCert); + Pkcs7FreeSigners (SignerCert); + Pkcs7FreeSigners (UnchainCert); return IsForbidden; } + /** Check whether the image signature can be verified by the trusted certificates in DB database. - @param[in] AuthData Pointer to the Authenticode signature retrieved from signed image. - @param[in] AuthDataSize Size of the Authenticode signature in bytes. + @param[in] AuthData Pointer to the Authenticode signature retrieved from signed image. + @param[in] AuthDataSize Size of the Authenticode signature in bytes. + @param[in] IsAuditMode Whether system Secure Boot Mode is in AuditMode. + @param[in] ImageName Name of the image to verify. + @param[in] ImageDevicePath DevicePath of the image to verify. @retval TRUE Image passed verification using certificate in db. @retval FALSE Image didn't pass verification using certificate in db. @@ -1374,14 +1528,17 @@ IsForbiddenByDbx ( **/ BOOLEAN IsAllowedByDb ( - IN UINT8 *AuthData, - IN UINTN AuthDataSize + IN UINT8 *AuthData, + IN UINTN AuthDataSize, + IN BOOLEAN IsAuditMode, + IN CHAR16 *ImageName OPTIONAL, + IN CONST EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath OPTIONAL ) { EFI_STATUS Status; BOOLEAN VerifyStatus; EFI_SIGNATURE_LIST *CertList; - EFI_SIGNATURE_DATA *Cert; + EFI_SIGNATURE_DATA *CertData; UINTN DataSize; UINT8 *Data; UINT8 *RootCert; @@ -1391,14 +1548,22 @@ IsAllowedByDb ( UINTN DbxDataSize; UINT8 *DbxData; EFI_TIME RevocationTime; + UINT8 *SignerCert; + UINTN SignerCertLength; + UINT8 *UnchainCert; + UINTN UnchainCertLength; - Data = NULL; - CertList = NULL; - Cert = NULL; - RootCert = NULL; - DbxData = NULL; - RootCertSize = 0; - VerifyStatus = FALSE; + Data = NULL; + CertList = NULL; + CertData = NULL; + RootCert = NULL; + DbxData = NULL; + RootCertSize = 0; + VerifyStatus = FALSE; + SignerCert = NULL; + SignerCertLength = 0; + UnchainCert = NULL; + UnchainCertLength = 0; DataSize = 0; Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL); @@ -1419,14 +1584,14 @@ IsAllowedByDb ( CertList = (EFI_SIGNATURE_LIST *) Data; while ((DataSize > 0) && (DataSize >= CertList->SignatureListSize)) { if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) { - Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize); - CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize; + CertData = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize); + CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize; for (Index = 0; Index < CertCount; Index++) { // // Iterate each Signature Data Node within this CertList for verify. // - RootCert = Cert->SignatureData; + RootCert = CertData->SignatureData; RootCertSize = CertList->SignatureSize - sizeof (EFI_GUID); // @@ -1468,7 +1633,7 @@ IsAllowedByDb ( goto Done; } - Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize); + CertData = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertData + CertList->SignatureSize); } } @@ -1478,10 +1643,67 @@ IsAllowedByDb ( } Done: + if (VerifyStatus) { - SecureBootHook (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, CertList->SignatureSize, Cert); + SecureBootHook (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, CertList->SignatureSize, CertData); + } + + if (IsAuditMode) { + + Pkcs7GetCertificatesList(AuthData, AuthDataSize, &SignerCert, &SignerCertLength, &UnchainCert, &UnchainCertLength); + if (VerifyStatus) { + if ((SignerCertLength != 0) && (SignerCert != NULL)) { + // + // Record all cert in signer's cert chain to be passed + // + RecordCertListToImageExeuctionTable( + SignerCert, + SignerCertLength, + EFI_IMAGE_EXECUTION_AUTH_SIG_PASSED | EFI_IMAGE_EXECUTION_INITIALIZED, + ImageName, + ImageDevicePath + ); + } + + if ((UnchainCertLength != 0) && (UnchainCert != NULL)) { + // + // Record all certs in unchained certificates lists to be failed + // + RecordCertListToImageExeuctionTable( + UnchainCert, + UnchainCertLength, + EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED | EFI_IMAGE_EXECUTION_INITIALIZED, + ImageName, + ImageDevicePath + ); + } + } else { + // + // Record all certs in image to be failed + // + if ((SignerCertLength != 0) && (SignerCert != NULL)) { + RecordCertListToImageExeuctionTable( + SignerCert, + SignerCertLength, + EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED | EFI_IMAGE_EXECUTION_INITIALIZED, + ImageName, + ImageDevicePath + ); + } + + if ((UnchainCertLength != 0) && (UnchainCert != NULL)) { + RecordCertListToImageExeuctionTable( + UnchainCert, + UnchainCertLength, + EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED | EFI_IMAGE_EXECUTION_INITIALIZED, + ImageName, + ImageDevicePath + ); + } + } } + if (Data != NULL) { FreePool (Data); } @@ -1489,9 +1711,369 @@ IsAllowedByDb ( FreePool (DbxData); } + Pkcs7FreeSigners (SignerCert); + Pkcs7FreeSigners (UnchainCert); + return VerifyStatus; } +/** + Provide verification service for signed images in AuditMode, which include both signature validation + and platform policy control. For signature types, both UEFI WIN_CERTIFICATE_UEFI_GUID and + MSFT Authenticode type signatures are supported. + + In this implementation, only verify external executables when in AuditMode. + Executables from FV is bypass, so pass in AuthenticationStatus is ignored. Other authentication status + are record into IMAGE_EXECUTION_TABLE. + + The image verification policy is: + If the image is signed, + At least one valid signature or at least one hash value of the image must match a record + in the security database "db", and no valid signature nor any hash value of the image may + be reflected in the security database "dbx". + Otherwise, the image is not signed, + The SHA256 hash value of the image must match a record in the security database "db", and + not be reflected in the security data base "dbx". + + Caution: This function may receive untrusted input. + PE/COFF image is external input, so this function will validate its data structure + within this image buffer before use. + + @param[in] AuthenticationStatus + This is the authentication status returned from the security + measurement services for the input file. + @param[in] File This is a pointer to the device path of the file that is + being dispatched. This will optionally be used for logging. + @param[in] FileBuffer File buffer matches the input file device path. + @param[in] FileSize Size of File buffer matches the input file device path. + @param[in] BootPolicy A boot policy that was used to call LoadImage() UEFI service. + + @retval EFI_SUCCESS The authenticate info is sucessfully stored for the file + specified by DevicePath and non-NULL FileBuffer + @retval EFI_ACCESS_DENIED The file specified by File and FileBuffer did not + authenticate, and the platform policy dictates that the DXE + Foundation many not use File. + +**/ +EFI_STATUS +EFIAPI +ImageVerificationInAuditMode ( + IN UINT32 AuthenticationStatus, + IN CONST EFI_DEVICE_PATH_PROTOCOL *File, + IN VOID *FileBuffer, + IN UINTN FileSize, + IN BOOLEAN BootPolicy + ) +{ + EFI_STATUS Status; + UINT16 Magic; + EFI_IMAGE_DOS_HEADER *DosHdr; + EFI_SIGNATURE_LIST *SignatureList; + EFI_IMAGE_EXECUTION_ACTION Action; + WIN_CERTIFICATE *WinCertificate; + UINT32 Policy; + PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + UINT32 NumberOfRvaAndSizes; + WIN_CERTIFICATE_EFI_PKCS *PkcsCertData; + WIN_CERTIFICATE_UEFI_GUID *WinCertUefiGuid; + UINT8 *AuthData; + UINTN AuthDataSize; + EFI_IMAGE_DATA_DIRECTORY *SecDataDir; + UINT32 OffSet; + CHAR16 *FilePathStr; + UINTN SignatureListSize; + + SignatureList = NULL; + WinCertificate = NULL; + SecDataDir = NULL; + PkcsCertData = NULL; + FilePathStr = NULL; + Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED | EFI_IMAGE_EXECUTION_INITIALIZED; + Status = EFI_ACCESS_DENIED; + + + // + // Check the image type and get policy setting. + // + switch (GetImageType (File)) { + + case IMAGE_FROM_FV: + Policy = ALWAYS_EXECUTE; + break; + + case IMAGE_FROM_OPTION_ROM: + Policy = PcdGet32 (PcdOptionRomImageVerificationPolicy); + break; + + case IMAGE_FROM_REMOVABLE_MEDIA: + Policy = PcdGet32 (PcdRemovableMediaImageVerificationPolicy); + break; + + case IMAGE_FROM_FIXED_MEDIA: + Policy = PcdGet32 (PcdFixedMediaImageVerificationPolicy); + break; + + default: + Policy = DENY_EXECUTE_ON_SECURITY_VIOLATION; + break; + } + + // + // If policy is always/never execute, return directly. + // + if (Policy == ALWAYS_EXECUTE) { + return EFI_SUCCESS; + } + + // + // Get Image Device Path Str + // + FilePathStr = ConvertDevicePathToText (File, FALSE, TRUE); + + // + // Authentication failed because of (unspecified) firmware security policy + // + if (Policy == NEVER_EXECUTE) { + // + // No signature, record FilePath/FilePathStr only + // + AddImageExeInfo (EFI_IMAGE_EXECUTION_POLICY_FAILED | EFI_IMAGE_EXECUTION_INITIALIZED, FilePathStr, File, NULL, 0); + goto END; + } + + // + // The policy QUERY_USER_ON_SECURITY_VIOLATION and ALLOW_EXECUTE_ON_SECURITY_VIOLATION + // violates the UEFI spec and has been removed. + // + ASSERT (Policy != QUERY_USER_ON_SECURITY_VIOLATION && Policy != ALLOW_EXECUTE_ON_SECURITY_VIOLATION); + if (Policy == QUERY_USER_ON_SECURITY_VIOLATION || Policy == ALLOW_EXECUTE_ON_SECURITY_VIOLATION) { + CpuDeadLoop (); + } + + // + // Read the Dos header. + // + if (FileBuffer == NULL) { + Status = EFI_INVALID_PARAMETER; + goto END; + } + + mImageBase = (UINT8 *) FileBuffer; + mImageSize = FileSize; + + ZeroMem (&ImageContext, sizeof (ImageContext)); + ImageContext.Handle = (VOID *) FileBuffer; + ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) DxeImageVerificationLibImageRead; + + // + // Get information about the image being loaded + // + Status = PeCoffLoaderGetImageInfo (&ImageContext); + if (EFI_ERROR (Status)) { + // + // The information can't be got from the invalid PeImage + // + goto END; + } + + + DosHdr = (EFI_IMAGE_DOS_HEADER *) mImageBase; + if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) { + // + // DOS image header is present, + // so read the PE header after the DOS image header. + // + mPeCoffHeaderOffset = DosHdr->e_lfanew; + } else { + mPeCoffHeaderOffset = 0; + } + + // + // Check PE/COFF image. + // + mNtHeader.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) (mImageBase + mPeCoffHeaderOffset); + if (mNtHeader.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) { + // + // It is not a valid Pe/Coff file. + // + Status = EFI_ACCESS_DENIED; + goto END; + } + + if (mNtHeader.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value + // in the PE/COFF Header. If the MachineType is Itanium(IA64) and the + // Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC + // then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC + // + Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC; + } else { + // + // Get the magic value from the PE/COFF Optional Header + // + Magic = mNtHeader.Pe32->OptionalHeader.Magic; + } + + if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Use PE32 offset. + // + NumberOfRvaAndSizes = mNtHeader.Pe32->OptionalHeader.NumberOfRvaAndSizes; + if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) { + SecDataDir = (EFI_IMAGE_DATA_DIRECTORY *) &mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]; + } + } else { + // + // Use PE32+ offset. + // + NumberOfRvaAndSizes = mNtHeader.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes; + if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) { + SecDataDir = (EFI_IMAGE_DATA_DIRECTORY *) &mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]; + } + } + + // + // Start Image Validation. + // + if (SecDataDir == NULL || SecDataDir->Size == 0) { + // + // This image is not signed. The SHA256 hash value of the image must match a record in the security database "db", + // and not be reflected in the security data base "dbx". + // + if (!HashPeImage (HASHALG_SHA256)) { + Status = EFI_ACCESS_DENIED; + goto END; + } + + // + // Image Hash is in forbidden database (DBX). + // + if (!IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, mImageDigest, &mCertType, mImageDigestSize)) { + // + // Image Hash is in allowed database (DB). + // + if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE, mImageDigest, &mCertType, mImageDigestSize)) { + Action = EFI_IMAGE_EXECUTION_AUTH_SIG_PASSED | EFI_IMAGE_EXECUTION_INITIALIZED; + } + } + + // + // Add HASH digest for image without signature + // + Status = CreateSignatureList(mImageDigest, mImageDigestSize, &mCertType, &SignatureList, &SignatureListSize); + if (!EFI_ERROR(Status)) { + AddImageExeInfo (Action, FilePathStr, File, SignatureList, SignatureListSize); + FreePool (SignatureList); + } + goto END; + } + + // + // Verify the signature of the image, multiple signatures are allowed as per PE/COFF Section 4.7 + // "Attribute Certificate Table". + // The first certificate starts at offset (SecDataDir->VirtualAddress) from the start of the file. + // + for (OffSet = SecDataDir->VirtualAddress; + OffSet < (SecDataDir->VirtualAddress + SecDataDir->Size); + OffSet += (WinCertificate->dwLength + ALIGN_SIZE (WinCertificate->dwLength))) { + WinCertificate = (WIN_CERTIFICATE *) (mImageBase + OffSet); + if ((SecDataDir->VirtualAddress + SecDataDir->Size - OffSet) <= sizeof (WIN_CERTIFICATE) || + (SecDataDir->VirtualAddress + SecDataDir->Size - OffSet) < WinCertificate->dwLength) { + break; + } + + // + // Verify the image's Authenticode signature, only DER-encoded PKCS#7 signed data is supported. + // + if (WinCertificate->wCertificateType == WIN_CERT_TYPE_PKCS_SIGNED_DATA) { + // + // The certificate is formatted as WIN_CERTIFICATE_EFI_PKCS which is described in the + // Authenticode specification. + // + PkcsCertData = (WIN_CERTIFICATE_EFI_PKCS *) WinCertificate; + if (PkcsCertData->Hdr.dwLength <= sizeof (PkcsCertData->Hdr)) { + break; + } + AuthData = PkcsCertData->CertData; + AuthDataSize = PkcsCertData->Hdr.dwLength - sizeof(PkcsCertData->Hdr); + } else if (WinCertificate->wCertificateType == WIN_CERT_TYPE_EFI_GUID) { + // + // The certificate is formatted as WIN_CERTIFICATE_UEFI_GUID which is described in UEFI Spec. + // + WinCertUefiGuid = (WIN_CERTIFICATE_UEFI_GUID *) WinCertificate; + if (WinCertUefiGuid->Hdr.dwLength <= OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData)) { + break; + } + if (!CompareGuid (&WinCertUefiGuid->CertType, &gEfiCertPkcs7Guid)) { + continue; + } + AuthData = WinCertUefiGuid->CertData; + AuthDataSize = WinCertUefiGuid->Hdr.dwLength - OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData); + } else { + if (WinCertificate->dwLength < sizeof (WIN_CERTIFICATE)) { + break; + } + continue; + } + + Status = HashPeImageByType (AuthData, AuthDataSize); + if (EFI_ERROR (Status)) { + continue; + } + + Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED | EFI_IMAGE_EXECUTION_INITIALIZED; + + // + // Check the digital signature against the revoked certificate in forbidden database (dbx). + // Check the digital signature against the valid certificate in allowed database (db). + // + if (!IsForbiddenByDbx (AuthData, AuthDataSize, TRUE, FilePathStr, File)) { + IsAllowedByDb (AuthData, AuthDataSize, TRUE, FilePathStr, File); + } + + // + // Check the image's hash value. + // + if (!IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, mImageDigest, &mCertType, mImageDigestSize)) { + if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE, mImageDigest, &mCertType, mImageDigestSize)) { + Action = EFI_IMAGE_EXECUTION_AUTH_SIG_PASSED | EFI_IMAGE_EXECUTION_INITIALIZED; + } + } + + // + // Add HASH digest for image with signature + // + Status = CreateSignatureList(mImageDigest, mImageDigestSize, &mCertType, &SignatureList, &SignatureListSize); + + if (!EFI_ERROR(Status)) { + AddImageExeInfo (Action, FilePathStr, File, SignatureList, SignatureListSize); + FreePool (SignatureList); + } else { + goto END; + } + } + + + if (OffSet != (SecDataDir->VirtualAddress + SecDataDir->Size)) { + // + // The Size in Certificate Table or the attribute certicate table is corrupted. + // + Status = EFI_ACCESS_DENIED; + } else { + Status = EFI_SUCCESS; + } + +END: + + if (FilePathStr != NULL) { + FreePool(FilePathStr); + FilePathStr = NULL; + } + + return Status; +} + /** Provide verification service for signed images, which include both signature validation and platform policy control. For signature types, both UEFI WIN_CERTIFICATE_UEFI_GUID and @@ -1559,7 +2141,9 @@ DxeImageVerificationHandler ( EFI_IMAGE_EXECUTION_ACTION Action; WIN_CERTIFICATE *WinCertificate; UINT32 Policy; - UINT8 *SecureBoot; + UINT8 *VarData; + UINT8 SecureBoot; + UINT8 AuditMode; PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; UINT32 NumberOfRvaAndSizes; WIN_CERTIFICATE_EFI_PKCS *PkcsCertData; @@ -1579,6 +2163,20 @@ DxeImageVerificationHandler ( Status = EFI_ACCESS_DENIED; VerifyStatus = EFI_ACCESS_DENIED; + GetEfiGlobalVariable2 (EFI_AUDIT_MODE_NAME, (VOID**)&VarData, NULL); + // + // Skip verification if AuditMode variable doesn't exist. AuditMode should always exist + // + if (VarData == NULL) { + return EFI_SUCCESS; + } + AuditMode = *VarData; + FreePool(VarData); + + if (AuditMode == AUDIT_MODE_ENABLE) { + return ImageVerificationInAuditMode(AuthenticationStatus, File, FileBuffer, FileSize, BootPolicy); + } + // // Check the image type and get policy setting. // @@ -1622,22 +2220,22 @@ DxeImageVerificationHandler ( CpuDeadLoop (); } - GetEfiGlobalVariable2 (EFI_SECURE_BOOT_MODE_NAME, (VOID**)&SecureBoot, NULL); + GetEfiGlobalVariable2 (EFI_SECURE_BOOT_MODE_NAME, (VOID**)&VarData, NULL); // // Skip verification if SecureBoot variable doesn't exist. // - if (SecureBoot == NULL) { + if (VarData == NULL) { return EFI_SUCCESS; } + SecureBoot = *VarData; + FreePool(VarData); // - // Skip verification if SecureBoot is disabled. + // Skip verification if SecureBoot is disabled but not AuditMode // - if (*SecureBoot == SECURE_BOOT_MODE_DISABLE) { - FreePool (SecureBoot); + if (SecureBoot == SECURE_BOOT_MODE_DISABLE) { return EFI_SUCCESS; } - FreePool (SecureBoot); // // Read the Dos header. @@ -1808,7 +2406,7 @@ DxeImageVerificationHandler ( // // Check the digital signature against the revoked certificate in forbidden database (dbx). // - if (IsForbiddenByDbx (AuthData, AuthDataSize)) { + if (IsForbiddenByDbx (AuthData, AuthDataSize, FALSE, NULL, NULL)) { Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED; VerifyStatus = EFI_ACCESS_DENIED; break; @@ -1818,7 +2416,7 @@ DxeImageVerificationHandler ( // Check the digital signature against the valid certificate in allowed database (db). // if (EFI_ERROR (VerifyStatus)) { - if (IsAllowedByDb (AuthData, AuthDataSize)) { + if (IsAllowedByDb (AuthData, AuthDataSize, FALSE, NULL, NULL)) { VerifyStatus = EFI_SUCCESS; } } From f8d51f2e2705229aaceae1e53f4eb8fb993fc0d4 Mon Sep 17 00:00:00 2001 From: Chao Zhang Date: Thu, 10 Dec 2015 07:19:10 +0000 Subject: [PATCH 212/525] SecurityPkg: SecureBootConfigDxe: SecureBoot UI for Customized SecureBoot Mode Add SecureBoot UI support for Customized SecureBoot Mode transition according to Mantis 1263. User can do secure boot mode transition through UI. https://mantis.uefi.org/mantis/view.php?id=1263 (Sync patch r19134 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Chao Zhang Reviewed-by: Zeng Star Reviewed-by: Long Qin git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19190 6f19259b-4bc3-4df7-8a09-765794883524 --- .../SecureBootConfigDxe/SecureBootConfig.vfr | 77 +++- .../SecureBootConfigImpl.c | 432 ++++++++++++++++-- .../SecureBootConfigNvData.h | 13 +- .../SecureBootConfigStrings.uni | Bin 13086 -> 14876 bytes 4 files changed, 465 insertions(+), 57 deletions(-) diff --git a/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfig.vfr b/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfig.vfr index 3c994317f74b..1eb3599279d8 100644 --- a/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfig.vfr +++ b/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfig.vfr @@ -1,7 +1,7 @@ /** @file VFR file used by the SecureBoot configuration component. -Copyright (c) 2011 - 2014, Intel Corporation. All rights reserved.
+Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -33,6 +33,14 @@ formset subtitle text = STRING_TOKEN(STR_NULL); + // + // Display current secure boot mode(one of SetupMode/AuditMode/UserMode/DeployedMode) + // + text + help = STRING_TOKEN(STR_CUR_SECURE_BOOT_MODE_HELP), + text = STRING_TOKEN(STR_CUR_SECURE_BOOT_MODE_PROMPT), + text = STRING_TOKEN(STR_CUR_SECURE_BOOT_MODE_CONTENT); + text help = STRING_TOKEN(STR_SECURE_BOOT_STATE_HELP), text = STRING_TOKEN(STR_SECURE_BOOT_STATE_PROMPT), @@ -84,18 +92,18 @@ formset endoneof; // - // - // Display of 'Current Secure Boot Mode' + // Display PK include page // suppressif questionref(SecureBootMode) == SECURE_BOOT_MODE_STANDARD; - grayoutif NOT ideqval SECUREBOOT_CONFIGURATION.PhysicalPresent == 1; - goto FORMID_SECURE_BOOT_OPTION_FORM, - prompt = STRING_TOKEN(STR_SECURE_BOOT_OPTION), - help = STRING_TOKEN(STR_SECURE_BOOT_OPTION_HELP), - flags = INTERACTIVE, - key = KEY_SECURE_BOOT_OPTION; - endif; + grayoutif NOT ideqval SECUREBOOT_CONFIGURATION.PhysicalPresent == 1; + goto FORMID_SECURE_BOOT_OPTION_FORM, + prompt = STRING_TOKEN(STR_SECURE_BOOT_OPTION), + help = STRING_TOKEN(STR_SECURE_BOOT_OPTION_HELP), + flags = INTERACTIVE, + key = KEY_SECURE_BOOT_OPTION; + endif; endif; + endform; // @@ -106,6 +114,55 @@ formset subtitle text = STRING_TOKEN(STR_NULL); + // + // Display of SetupMode/UserMode/AuditMode/DeployedMode transition + // + disableif TRUE; + oneof varid = SECUREBOOT_CONFIGURATION.TransSecureBootMode, + prompt = STRING_TOKEN(STR_TRANS_SECURE_BOOT_MODE_PROMPT), + help = STRING_TOKEN(STR_TRANS_SECURE_BOOT_MODE_HELP), + flags = INTERACTIVE, + suppressif ideqval SECUREBOOT_CONFIGURATION.CurSecureBootMode == SECURE_BOOT_MODE_AUDIT_MODE + OR (ideqval SECUREBOOT_CONFIGURATION.CurSecureBootMode == SECURE_BOOT_MODE_DEPLOYED_MODE AND + ideqval SECUREBOOT_CONFIGURATION.PhysicalPresent == 0); + option text = STRING_TOKEN(STR_USER_MODE), value = SECURE_BOOT_MODE_USER_MODE, flags = 0; + endif + suppressif ideqval SECUREBOOT_CONFIGURATION.CurSecureBootMode == SECURE_BOOT_MODE_AUDIT_MODE; + option text = STRING_TOKEN(STR_SETUP_MODE), value = SECURE_BOOT_MODE_SETUP_MODE, flags = 0; + endif + suppressif ideqval SECUREBOOT_CONFIGURATION.CurSecureBootMode == SECURE_BOOT_MODE_DEPLOYED_MODE; + option text = STRING_TOKEN(STR_AUDIT_MODE), value = SECURE_BOOT_MODE_AUDIT_MODE, flags = 0; + endif + suppressif ideqval SECUREBOOT_CONFIGURATION.CurSecureBootMode == SECURE_BOOT_MODE_SETUP_MODE; + option text = STRING_TOKEN(STR_DEPLOYED_MODE), value = SECURE_BOOT_MODE_DEPLOYED_MODE, flags = 0; + endif + option text = STRING_TOKEN(STR_DEPLOYED_MODE), value = 4, flags = 0; + endoneof; + endif; + oneof name = TransSecureBootMode, + questionid = KEY_TRANS_SECURE_BOOT_MODE, + prompt = STRING_TOKEN(STR_TRANS_SECURE_BOOT_MODE_PROMPT), + help = STRING_TOKEN(STR_TRANS_SECURE_BOOT_MODE_HELP), + flags = INTERACTIVE | NUMERIC_SIZE_1, + suppressif ideqval SECUREBOOT_CONFIGURATION.CurSecureBootMode == SECURE_BOOT_MODE_AUDIT_MODE + OR (ideqval SECUREBOOT_CONFIGURATION.CurSecureBootMode == SECURE_BOOT_MODE_DEPLOYED_MODE AND + ideqval SECUREBOOT_CONFIGURATION.PhysicalPresent == 0); + option text = STRING_TOKEN(STR_USER_MODE), value = SECURE_BOOT_MODE_USER_MODE, flags = 0; + endif + suppressif ideqval SECUREBOOT_CONFIGURATION.CurSecureBootMode == SECURE_BOOT_MODE_AUDIT_MODE; + option text = STRING_TOKEN(STR_SETUP_MODE), value = SECURE_BOOT_MODE_SETUP_MODE, flags = 0; + endif + suppressif ideqval SECUREBOOT_CONFIGURATION.CurSecureBootMode == SECURE_BOOT_MODE_DEPLOYED_MODE; + option text = STRING_TOKEN(STR_AUDIT_MODE), value = SECURE_BOOT_MODE_AUDIT_MODE, flags = 0; + endif + suppressif ideqval SECUREBOOT_CONFIGURATION.CurSecureBootMode == SECURE_BOOT_MODE_SETUP_MODE; + option text = STRING_TOKEN(STR_DEPLOYED_MODE), value = SECURE_BOOT_MODE_DEPLOYED_MODE, flags = 0; + endif + + endoneof; + + subtitle text = STRING_TOKEN(STR_NULL); + goto FORMID_SECURE_BOOT_PK_OPTION_FORM, prompt = STRING_TOKEN(STR_SECURE_BOOT_PK_OPTION), help = STRING_TOKEN(STR_SECURE_BOOT_PK_OPTION_HELP), diff --git a/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigImpl.c b/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigImpl.c index e43c6e0ee7e2..a685b409e238 100644 --- a/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigImpl.c +++ b/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigImpl.c @@ -49,6 +49,8 @@ HII_VENDOR_DEVICE_PATH mSecureBootHiiVendorDevicePath = { BOOLEAN mIsEnterSecureBootForm = FALSE; +BOOLEAN mIsSelectedSecureBootModeForm = FALSE; +BOOLEAN mIsSecureBootModeChanged = FALSE; // // OID ASN.1 Value for Hash Algorithms @@ -2808,6 +2810,256 @@ DeleteSignature ( ); } +/** + Perform secure boot mode transition from User Mode by setting AuditMode + or DeployedMode variable. + + @param[in] NewMode New secure boot mode. + + @retval EFI_SUCCESS Secure Boot mode transition is successful. +**/ +EFI_STATUS +TransitionFromUserMode( + IN UINT8 NewMode + ) +{ + UINT8 Data; + EFI_STATUS Status; + + if (NewMode == SECURE_BOOT_MODE_AUDIT_MODE) { + Data = 1; + Status = gRT->SetVariable( + EFI_AUDIT_MODE_NAME, + &gEfiGlobalVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + sizeof(UINT8), + &Data + ); + return Status; + } else if (NewMode == SECURE_BOOT_MODE_DEPLOYED_MODE) { + Data = 1; + Status = gRT->SetVariable( + EFI_DEPLOYED_MODE_NAME, + &gEfiGlobalVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + sizeof(UINT8), + &Data + ); + return Status; + } + + // + // Other case do nothing here. May Goto enroll PK page. + // + return EFI_SUCCESS; +} + +/** + Perform secure boot mode transition from Setup Mode by setting AuditMode + variable. + + @param[in] NewMode New secure boot mode. + + @retval EFI_SUCCESS Secure Boot mode transition is successful. +**/ +EFI_STATUS +TransitionFromSetupMode( + IN UINT8 NewMode + ) +{ + UINT8 Data; + EFI_STATUS Status; + + Status = EFI_INVALID_PARAMETER; + + if (NewMode == SECURE_BOOT_MODE_AUDIT_MODE) { + Data = 1; + Status = gRT->SetVariable( + EFI_AUDIT_MODE_NAME, + &gEfiGlobalVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + sizeof(UINT8), + &Data + ); + return Status; + } + + // + // Other case do nothing here. May Goto enroll PK page. + // + return EFI_SUCCESS; +} + +/** + Perform secure boot mode transition from Audit Mode. Nothing is done here, + should goto enroll PK page. + + @param[in] NewMode New secure boot mode. + + @retval EFI_SUCCESS Secure Boot mode transition is successful. +**/ +EFI_STATUS +TransitionFromAuditMode( + IN UINT8 NewMode + ) +{ + // + // Other case do nothing here. Should Goto enroll PK page. + // + return EFI_SUCCESS; +} + +/** + Perform secure boot mode transition from Deployed Mode by setting Deployed Mode + variable to 0. + + @param[in] NewMode New secure boot mode. + + @retval EFI_SUCCESS Secure Boot mode transition is successful. +**/ +EFI_STATUS +TransitionFromDeployedMode( + IN UINT8 NewMode + ) +{ + UINT8 Data; + EFI_STATUS Status; + + // + // Platform specific logic. when physical presence, Allow to set DeployedMode =:0 + // to switch back to UserMode + // + if (NewMode == SECURE_BOOT_MODE_USER_MODE) { + Data = 0; + Status = gRT->SetVariable( + EFI_DEPLOYED_MODE_NAME, + &gEfiGlobalVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + sizeof(UINT8), + &Data + ); + DEBUG((EFI_D_INFO, "DeployedMode Status %x\n", Status)); + return Status; + } + return EFI_SUCCESS; +} + +/** + Perform main secure boot mode transition. + + @param[in] CurMode New secure boot mode. + @param[in] NewMode New secure boot mode. + + @retval EFI_SUCCESS Secure Boot mode transition is successful. +**/ +EFI_STATUS +SecureBootModeTransition( + IN UINT8 CurMode, + IN UINT8 NewMode + ) +{ + EFI_STATUS Status; + + // + // Set platform to be customized mode to ensure platform specific mode switch sucess + // + Status = SetSecureBootMode(CUSTOM_SECURE_BOOT_MODE); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // SecureBootMode transition + // + switch (CurMode) { + case SECURE_BOOT_MODE_USER_MODE: + Status = TransitionFromUserMode(NewMode); + break; + + case SECURE_BOOT_MODE_SETUP_MODE: + Status = TransitionFromSetupMode(NewMode); + break; + + case SECURE_BOOT_MODE_AUDIT_MODE: + Status = TransitionFromAuditMode(NewMode); + break; + + case SECURE_BOOT_MODE_DEPLOYED_MODE: + Status = TransitionFromDeployedMode(NewMode); + break; + + default: + Status = EFI_INVALID_PARAMETER; + ASSERT(FALSE); + } + + return Status; +} + +/** + Get current secure boot mode by retrieve data from SetupMode/AuditMode/DeployedMode. + + @param[out] SecureBootMode Current secure boot mode. + +**/ +VOID +ExtractSecureBootModeFromVariable( + OUT UINT8 *SecureBootMode + ) +{ + UINT8 *SetupMode; + UINT8 *AuditMode; + UINT8 *DeployedMode; + + SetupMode = NULL; + AuditMode = NULL; + DeployedMode = NULL; + + // + // Get AuditMode/DeployedMode from variable + // + GetVariable2 (EFI_SETUP_MODE_NAME, &gEfiGlobalVariableGuid, (VOID**)&SetupMode, NULL); + GetVariable2 (EFI_AUDIT_MODE_NAME, &gEfiGlobalVariableGuid, (VOID**)&AuditMode, NULL); + GetVariable2 (EFI_DEPLOYED_MODE_NAME, &gEfiGlobalVariableGuid, (VOID**)&DeployedMode, NULL); + if (SetupMode != NULL && AuditMode != NULL && DeployedMode != NULL) { + if (*SetupMode == 0 && *AuditMode == 0 && *DeployedMode == 0) { + // + // User Mode + // + *SecureBootMode = SECURE_BOOT_MODE_USER_MODE; + } else if (*SetupMode == 1 && *AuditMode == 0 && *DeployedMode == 0) { + // + // Setup Mode + // + *SecureBootMode = SECURE_BOOT_MODE_SETUP_MODE; + } else if (*SetupMode == 1 && *AuditMode == 1 && *DeployedMode == 0) { + // + // Audit Mode + // + *SecureBootMode = SECURE_BOOT_MODE_AUDIT_MODE; + } else if (*SetupMode == 0 && *AuditMode == 0 && *DeployedMode == 1) { + // + // Deployed Mode + // + *SecureBootMode = SECURE_BOOT_MODE_DEPLOYED_MODE; + } else { + ASSERT(FALSE); + } + }else { + ASSERT(FALSE); + } + + if (SetupMode != NULL) { + FreePool (SetupMode); + } + if (DeployedMode != NULL) { + FreePool (DeployedMode); + } + if (AuditMode != NULL) { + FreePool (AuditMode); + } +} + /** This function extracts configuration from variable. @@ -2820,12 +3072,10 @@ SecureBootExtractConfigFromVariable ( ) { UINT8 *SecureBootEnable; - UINT8 *SetupMode; UINT8 *SecureBootMode; EFI_TIME CurrTime; SecureBootEnable = NULL; - SetupMode = NULL; SecureBootMode = NULL; // @@ -2865,16 +3115,6 @@ SecureBootExtractConfigFromVariable ( ConfigData->PhysicalPresent = FALSE; } - // - // If there is no PK then the Delete Pk button will be gray. - // - GetVariable2 (EFI_SETUP_MODE_NAME, &gEfiGlobalVariableGuid, (VOID**)&SetupMode, NULL); - if (SetupMode == NULL || (*SetupMode) == SETUP_MODE) { - ConfigData->HasPk = FALSE; - } else { - ConfigData->HasPk = TRUE; - } - // // Get the SecureBootMode from CustomMode variable. // @@ -2885,12 +3125,24 @@ SecureBootExtractConfigFromVariable ( ConfigData->SecureBootMode = *(SecureBootMode); } + // + // Extact current Secure Boot Mode + // + ExtractSecureBootModeFromVariable(&ConfigData->CurSecureBootMode); + + // + // If there is no PK then the Delete Pk button will be gray. + // + if (ConfigData->CurSecureBootMode == SECURE_BOOT_MODE_SETUP_MODE || ConfigData->CurSecureBootMode == SECURE_BOOT_MODE_AUDIT_MODE) { + ConfigData->HasPk = FALSE; + } else { + ConfigData->HasPk = TRUE; + } + if (SecureBootEnable != NULL) { FreePool (SecureBootEnable); } - if (SetupMode != NULL) { - FreePool (SetupMode); - } + if (SecureBootMode != NULL) { FreePool (SecureBootMode); } @@ -2965,16 +3217,28 @@ SecureBootExtractConfig ( SecureBootExtractConfigFromVariable (&Configuration); // - // Update current secure boot state. + // Get current secure boot state. // GetVariable2 (EFI_SECURE_BOOT_MODE_NAME, &gEfiGlobalVariableGuid, (VOID**)&SecureBoot, NULL); + if (SecureBoot != NULL && *SecureBoot == SECURE_BOOT_MODE_ENABLE) { HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_SECURE_BOOT_STATE_CONTENT), L"Enabled", NULL); } else { HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_SECURE_BOOT_STATE_CONTENT), L"Disabled", NULL); } - if (SecureBoot != NULL) { - FreePool (SecureBoot); + + // + // Get current secure boot mode + // + DEBUG((EFI_D_INFO, "Configuration.CurSecureBootMode %d\n", Configuration.CurSecureBootMode)); + if (Configuration.CurSecureBootMode == SECURE_BOOT_MODE_USER_MODE) { + HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_CUR_SECURE_BOOT_MODE_CONTENT), L"UserMode", NULL); + } else if (Configuration.CurSecureBootMode == SECURE_BOOT_MODE_SETUP_MODE) { + HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_CUR_SECURE_BOOT_MODE_CONTENT), L"SetupMode", NULL); + } else if (Configuration.CurSecureBootMode == SECURE_BOOT_MODE_AUDIT_MODE) { + HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_CUR_SECURE_BOOT_MODE_CONTENT), L"AuditMode", NULL); + } else if (Configuration.CurSecureBootMode == SECURE_BOOT_MODE_DEPLOYED_MODE) { + HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_CUR_SECURE_BOOT_MODE_CONTENT), L"DeployedMode", NULL); } BufferSize = sizeof (SECUREBOOT_CONFIGURATION); @@ -3021,6 +3285,10 @@ SecureBootExtractConfig ( *Progress = Request + StrLen (Request); } + if (SecureBoot != NULL) { + FreePool (SecureBoot); + } + return Status; } @@ -3142,23 +3410,41 @@ SecureBootCallback ( UINT16 LabelId; UINT8 *SecureBootEnable; UINT8 *SecureBootMode; - UINT8 *SetupMode; CHAR16 PromptString[100]; + UINT8 CurSecureBootMode; + Status = EFI_SUCCESS; SecureBootEnable = NULL; SecureBootMode = NULL; - SetupMode = NULL; if ((This == NULL) || (Value == NULL) || (ActionRequest == NULL)) { return EFI_INVALID_PARAMETER; } + Private = SECUREBOOT_CONFIG_PRIVATE_FROM_THIS (This); + + // + // Retrieve uncommitted data from Browser + // + BufferSize = sizeof (SECUREBOOT_CONFIGURATION); + IfrNvData = AllocateZeroPool (BufferSize); + if (IfrNvData == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + HiiGetBrowserData (&gSecureBootConfigFormSetGuid, mSecureBootStorageName, BufferSize, (UINT8 *) IfrNvData); if (Action == EFI_BROWSER_ACTION_FORM_OPEN) { if (QuestionId == KEY_SECURE_BOOT_MODE) { mIsEnterSecureBootForm = TRUE; + } else if (QuestionId == KEY_TRANS_SECURE_BOOT_MODE){ + // + // Secure Boot Policy variable changes after tranistion. Re-sync CurSecureBootMode + // + ExtractSecureBootModeFromVariable(&IfrNvData->CurSecureBootMode); + mIsSelectedSecureBootModeForm = TRUE; + mIsSecureBootModeChanged = FALSE; } - - return EFI_SUCCESS; + goto EXIT; } if (Action == EFI_BROWSER_ACTION_RETRIEVE) { @@ -3168,32 +3454,23 @@ SecureBootCallback ( Value->u8 = SECURE_BOOT_MODE_STANDARD; Status = EFI_SUCCESS; } + } else if (QuestionId == KEY_TRANS_SECURE_BOOT_MODE) { + if (mIsSelectedSecureBootModeForm) { + Value->u8 = IfrNvData->CurSecureBootMode; + Status = EFI_SUCCESS; + } } - return Status; + goto EXIT; } if ((Action != EFI_BROWSER_ACTION_CHANGED) && (Action != EFI_BROWSER_ACTION_CHANGING) && (Action != EFI_BROWSER_ACTION_FORM_CLOSE) && (Action != EFI_BROWSER_ACTION_DEFAULT_STANDARD)) { - return EFI_UNSUPPORTED; - } - - Private = SECUREBOOT_CONFIG_PRIVATE_FROM_THIS (This); - - // - // Retrieve uncommitted data from Browser - // - BufferSize = sizeof (SECUREBOOT_CONFIGURATION); - IfrNvData = AllocateZeroPool (BufferSize); - if (IfrNvData == NULL) { - return EFI_OUT_OF_RESOURCES; + Status = EFI_UNSUPPORTED; + goto EXIT; } - Status = EFI_SUCCESS; - - HiiGetBrowserData (&gSecureBootConfigFormSetGuid, mSecureBootStorageName, BufferSize, (UINT8 *) IfrNvData); - if (Action == EFI_BROWSER_ACTION_CHANGING) { switch (QuestionId) { @@ -3419,6 +3696,66 @@ SecureBootCallback ( ); } break; + case KEY_TRANS_SECURE_BOOT_MODE: + // + // Pop up to alert user want to change secure boot mode + // + if ((IfrNvData->CurSecureBootMode == SECURE_BOOT_MODE_USER_MODE && + (Value->u8 == SECURE_BOOT_MODE_AUDIT_MODE || Value->u8 == SECURE_BOOT_MODE_DEPLOYED_MODE)) + ||(IfrNvData->CurSecureBootMode == SECURE_BOOT_MODE_SETUP_MODE && + Value->u8 == SECURE_BOOT_MODE_AUDIT_MODE) + ||(IfrNvData->CurSecureBootMode == SECURE_BOOT_MODE_DEPLOYED_MODE && + Value->u8 == SECURE_BOOT_MODE_USER_MODE && IfrNvData->PhysicalPresent == 1)){ + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Are you sure you want to switch secure boot mode?", + L"Press 'Y' to switch secure boot mode, 'N' to discard change and return", + NULL + ); + if (Key.UnicodeChar != 'y' && Key.UnicodeChar != 'Y') { + // + // If not 'Y'/''y' restore to defualt secure boot mode + // + Value->u8 = IfrNvData->CurSecureBootMode; + goto EXIT; + } + } else if ((IfrNvData->CurSecureBootMode == SECURE_BOOT_MODE_SETUP_MODE && Value->u8 == SECURE_BOOT_MODE_USER_MODE) + ||(IfrNvData->CurSecureBootMode == SECURE_BOOT_MODE_USER_MODE && Value->u8 == SECURE_BOOT_MODE_SETUP_MODE) + ||(IfrNvData->CurSecureBootMode == SECURE_BOOT_MODE_AUDIT_MODE && Value->u8 == SECURE_BOOT_MODE_DEPLOYED_MODE) + ||(IfrNvData->CurSecureBootMode == SECURE_BOOT_MODE_DEPLOYED_MODE && Value->u8 == SECURE_BOOT_MODE_SETUP_MODE)) { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Secure boot mode tranistion requires PK change", + L"Please go to link below to update PK", + NULL + ); + } else { + Status = EFI_INVALID_PARAMETER; + goto EXIT; + } + + Status = SecureBootModeTransition(IfrNvData->CurSecureBootMode, Value->u8); + // + // Secure Boot Policy variable may change after tranistion. Re-sync CurSecureBootMode + // + ExtractSecureBootModeFromVariable(&CurSecureBootMode); + if (IfrNvData->CurSecureBootMode != CurSecureBootMode) { + IfrNvData->CurSecureBootMode = CurSecureBootMode; + mIsSecureBootModeChanged = TRUE; + + if (IfrNvData->CurSecureBootMode == SECURE_BOOT_MODE_USER_MODE) { + HiiSetString (Private->HiiHandle, STRING_TOKEN (STR_CUR_SECURE_BOOT_MODE_CONTENT), L"UserMode", NULL); + } else if (IfrNvData->CurSecureBootMode == SECURE_BOOT_MODE_SETUP_MODE) { + HiiSetString (Private->HiiHandle, STRING_TOKEN (STR_CUR_SECURE_BOOT_MODE_CONTENT), L"SetupMode", NULL); + } else if (IfrNvData->CurSecureBootMode == SECURE_BOOT_MODE_AUDIT_MODE) { + HiiSetString (Private->HiiHandle, STRING_TOKEN (STR_CUR_SECURE_BOOT_MODE_CONTENT), L"AuditMode", NULL); + } else if (IfrNvData->CurSecureBootMode == SECURE_BOOT_MODE_DEPLOYED_MODE) { + HiiSetString (Private->HiiHandle, STRING_TOKEN (STR_CUR_SECURE_BOOT_MODE_CONTENT), L"DeployedMode", NULL); + } + } + break; default: if (QuestionId >= FILE_OPTION_GOTO_OFFSET) { @@ -3509,7 +3846,13 @@ SecureBootCallback ( case KEY_SECURE_BOOT_MODE: mIsEnterSecureBootForm = FALSE; break; - + case KEY_TRANS_SECURE_BOOT_MODE: + mIsSelectedSecureBootModeForm = FALSE; + if (mIsSecureBootModeChanged) { + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_RESET; + } + mIsSecureBootModeChanged = FALSE; + break; case KEY_SECURE_BOOT_KEK_GUID: case KEY_SECURE_BOOT_SIGNATURE_GUID_DB: case KEY_SECURE_BOOT_SIGNATURE_GUID_DBX: @@ -3528,8 +3871,7 @@ SecureBootCallback ( break; case KEY_SECURE_BOOT_DELETE_PK: - GetVariable2 (EFI_SETUP_MODE_NAME, &gEfiGlobalVariableGuid, (VOID**)&SetupMode, NULL); - if (SetupMode == NULL || (*SetupMode) == SETUP_MODE) { + if (IfrNvData->CurSecureBootMode == SECURE_BOOT_MODE_USER_MODE || IfrNvData->CurSecureBootMode == SECURE_BOOT_MODE_DEPLOYED_MODE) { IfrNvData->DeletePk = TRUE; IfrNvData->HasPk = FALSE; *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT; @@ -3538,9 +3880,6 @@ SecureBootCallback ( IfrNvData->HasPk = TRUE; *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY; } - if (SetupMode != NULL) { - FreePool (SetupMode); - } break; default: if (QuestionId >= FILE_OPTION_OFFSET && QuestionId < FILE_OPTION_GOTO_OFFSET) { @@ -3575,10 +3914,13 @@ SecureBootCallback ( } } +EXIT: + if (!EFI_ERROR (Status)) { BufferSize = sizeof (SECUREBOOT_CONFIGURATION); HiiSetBrowserData (&gSecureBootConfigFormSetGuid, mSecureBootStorageName, BufferSize, (UINT8*) IfrNvData, NULL); } + FreePool (IfrNvData); return EFI_SUCCESS; diff --git a/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigNvData.h b/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigNvData.h index b628bcb1f532..7195e94a2fc7 100644 --- a/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigNvData.h +++ b/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigNvData.h @@ -1,7 +1,7 @@ /** @file Header file for NV data structure definition. -Copyright (c) 2011 - 2014, Intel Corporation. All rights reserved.
+Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -84,6 +84,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #define LABEL_DBT_DELETE 0x1203 #define LABEL_END 0xffff +#define KEY_TRANS_SECURE_BOOT_MODE 0x2000 + #define SECURE_BOOT_MAX_ATTEMPTS_NUM 255 #define CONFIG_OPTION_OFFSET 0x2000 @@ -116,6 +118,11 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #define SECURE_BOOT_GUID_SIZE 36 #define SECURE_BOOT_GUID_STORAGE_SIZE 37 +#define SECURE_BOOT_MODE_USER_MODE 0 +#define SECURE_BOOT_MODE_SETUP_MODE 1 +#define SECURE_BOOT_MODE_AUDIT_MODE 2 +#define SECURE_BOOT_MODE_DEPLOYED_MODE 3 + // // Nv Data structure referenced by IFR // @@ -125,6 +132,8 @@ typedef struct { CHAR16 SignatureGuid[SECURE_BOOT_GUID_STORAGE_SIZE]; BOOLEAN PhysicalPresent; // If a Physical Present User UINT8 SecureBootMode; // Secure Boot Mode: Standard Or Custom + UINT8 CurSecureBootMode; // Current SecureBoot Mode SetupMode/UserMode/AuditMode/DeployedMode + UINT8 TransSecureBootMode; // Trans Next SecureBoot Mode BOOLEAN DeletePk; BOOLEAN HasPk; // If Pk is existed it is true BOOLEAN AlwaysRevocation; // If the certificate is always revoked. Revocation time is hidden @@ -133,4 +142,4 @@ typedef struct { EFI_HII_TIME RevocationTime; // The revocation time of the certificate } SECUREBOOT_CONFIGURATION; -#endif \ No newline at end of file +#endif diff --git a/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigStrings.uni b/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigStrings.uni index 063a10d44d125cda13a2b62d56dc4cbed528f01c..263811b05216b72148392d968fc12c65fd8591ff 100644 GIT binary patch delta 801 zcmZ`%K~EDw7<~rY*%|^~h%CF{*wiMai3Jlc#7n~(H7QVGo9Mxq(iYjIwuKgrUep^W zqWP}I_!A(#crx-&^Sw9k&71wc&wHPGAHH9@b9VkdDL>V8zoar# zQ|qY6d2&%6yGyd{XJuK<8&bZy*+1NX+=-Kxtnv-_bOUYF(ZCuscDVL%gbre~fFkQU zBH|;gf-X-Ujv)c-4x03O&0Rfaq~P3$Z%%Ar3xTv9SJvjza_ZdeA77cDm6AW5i0}pt zDW%g zmuQ0;O~!a>A`M%$S?y8roSui)N#m7$@;<$ec#EdOtovkJT#b9xu12d_n{Ulz@(GWJ z(yTi1Q8{yN%D07<+;)~E^qOiIT^=po?_c$2u1O}TQz5qb+c&Wz2g+kJvvR63^2OD2 z8X*&!^pSmiMDv!cI@c#OgOR2-(sb>ctmeP%{=2pR8i0v*%g2Shs&IVnVOySgtMV?F zW^IQ=@?K8L&gDdi3d&>)@?#~VhJ$9_0#sWU? Date: Thu, 10 Dec 2015 07:19:44 +0000 Subject: [PATCH 213/525] SecurityPkg: AuthVariableLib: Fix GCC compile error (Sync patch r19140 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ard Biesheuvel Reviewed-by: Chao Zhang git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19191 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Library/AuthVariableLib/AuthService.c | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/SecurityPkg/Library/AuthVariableLib/AuthService.c b/SecurityPkg/Library/AuthVariableLib/AuthService.c index 5546c2e5c906..9a09eaed609a 100644 --- a/SecurityPkg/Library/AuthVariableLib/AuthService.c +++ b/SecurityPkg/Library/AuthVariableLib/AuthService.c @@ -555,10 +555,10 @@ TransitionFromAuditMode( ) { EFI_STATUS Status; - UINT8 *AuditVarData; - UINT8 *DeployedVarData; - UINT8 *SetupVarData; - UINT8 *SecureBootVarData; + VOID *AuditVarData; + VOID *DeployedVarData; + VOID *SetupVarData; + VOID *SecureBootVarData; UINT8 SecureBootEnable; UINTN DataSize; @@ -693,9 +693,9 @@ TransitionFromDeployedMode( ) { EFI_STATUS Status; - UINT8 *DeployedVarData; - UINT8 *SetupVarData; - UINT8 *SecureBootVarData; + VOID *DeployedVarData; + VOID *SetupVarData; + VOID *SecureBootVarData; UINT8 SecureBootEnable; UINTN DataSize; @@ -835,11 +835,11 @@ TransitionFromUserMode( ) { EFI_STATUS Status; - UINT8 *AuditVarData; - UINT8 *DeployedVarData; - UINT8 *SetupVarData; - UINT8 *PkVarData; - UINT8 *SecureBootVarData; + VOID *AuditVarData; + VOID *DeployedVarData; + VOID *SetupVarData; + VOID *PkVarData; + VOID *SecureBootVarData; UINT8 SecureBootEnable; UINTN DataSize; VARIABLE_ENTRY_CONSISTENCY VariableEntry; @@ -1034,9 +1034,9 @@ TransitionFromSetupMode( ) { EFI_STATUS Status; - UINT8 *AuditVarData; - UINT8 *SetupVarData; - UINT8 *SecureBootVarData; + VOID *AuditVarData; + VOID *SetupVarData; + VOID *SecureBootVarData; UINT8 SecureBootEnable; UINTN DataSize; @@ -1746,7 +1746,7 @@ ProcessSecureBootModeVar ( ) { EFI_STATUS Status; - UINT8 *VarData; + VOID *VarData; UINTN VarDataSize; // @@ -1801,7 +1801,7 @@ ProcessSecureBootModeVar ( // // If AuditMode/DeployedMode is assigned same value. Simply return EFI_SUCCESS // - if (*VarData == *(UINT8 *)Data) { + if (*(UINT8 *)VarData == *(UINT8 *)Data) { return EFI_SUCCESS; } From 8012b6588f3070027ecfcf4c6a9fc840b13c026b Mon Sep 17 00:00:00 2001 From: Chao Zhang Date: Thu, 10 Dec 2015 07:20:16 +0000 Subject: [PATCH 214/525] MdePkg: Restore SetupMode macro definition Restore SetupMode macro definition to keep backward compatibility. No current module is referencing them now. (Sync patch r19175 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Chao Zhang Reviewed-by: Star Zeng git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19192 6f19259b-4bc3-4df7-8a09-765794883524 --- MdePkg/Include/Guid/ImageAuthentication.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/MdePkg/Include/Guid/ImageAuthentication.h b/MdePkg/Include/Guid/ImageAuthentication.h index 2f51935c0c76..c7336439981b 100644 --- a/MdePkg/Include/Guid/ImageAuthentication.h +++ b/MdePkg/Include/Guid/ImageAuthentication.h @@ -43,6 +43,14 @@ #define SECURE_BOOT_MODE_ENABLE 1 #define SECURE_BOOT_MODE_DISABLE 0 +/// +/// Depricated value definition for SetupMode variable +/// +#define SETUP_MODE 1 +#define USER_MODE 0 +/// +/// Value definition for SetupMode/DeployedMode/AuditMode variable +/// #define SETUP_MODE_ENABLE 1 #define SETUP_MODE_DISABLE 0 #define DEPLOYED_MODE_ENABLE 1 From d839b9c0f0c80161b932f2c4d153c555b1322610 Mon Sep 17 00:00:00 2001 From: Jiaxin Wu Date: Thu, 10 Dec 2015 07:20:43 +0000 Subject: [PATCH 215/525] ShellPkg: Fix wrong return status for Ifconfig.c The Ifconfig command handler tries to return an EFI_STATUS when the return type should be SHELL_STATUS. (Sync patch r19110 from main trunk.) Cc: Cohen Eugene Cc: Carsey Jaben Cc: Ye Ting Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiaxin Wu Reviewed-by: Jaben Carsey Reviewed-by: Ye Ting Reviewed-by: Ard Biesheuvel git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19193 6f19259b-4bc3-4df7-8a09-765794883524 --- .../UefiShellNetwork1CommandsLib/Ifconfig.c | 102 ++++++++++++------ 1 file changed, 69 insertions(+), 33 deletions(-) diff --git a/ShellPkg/Library/UefiShellNetwork1CommandsLib/Ifconfig.c b/ShellPkg/Library/UefiShellNetwork1CommandsLib/Ifconfig.c index e16d46a8ec4d..fb6f57518422 100644 --- a/ShellPkg/Library/UefiShellNetwork1CommandsLib/Ifconfig.c +++ b/ShellPkg/Library/UefiShellNetwork1CommandsLib/Ifconfig.c @@ -423,7 +423,7 @@ IfConfigGetInterfaceInfo ( &HandleBuffer ); if (EFI_ERROR (Status) || (HandleNum == 0)) { - return EFI_ABORTED; + return Status; } // @@ -587,11 +587,11 @@ IfConfigGetInterfaceInfo ( @param[in] IfList The pointer of IfList(interface list). - @retval EFI_SUCCESS The ifconfig command list processed successfully. + @retval SHELL_SUCCESS The ifconfig command list processed successfully. @retval others The ifconfig command list process failed. **/ -EFI_STATUS +SHELL_STATUS IfConfigShowInterfaceInfo ( IN LIST_ENTRY *IfList ) @@ -783,7 +783,7 @@ IfConfigShowInterfaceInfo ( ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_BREAK), gShellNetwork1HiiHandle); - return EFI_SUCCESS; + return SHELL_SUCCESS; } /** @@ -791,16 +791,17 @@ IfConfigShowInterfaceInfo ( @param[in] IfList The pointer of IfList(interface list). - @retval EFI_SUCCESS The ifconfig command clean processed successfully. + @retval SHELL_SUCCESS The ifconfig command clean processed successfully. @retval others The ifconfig command clean process failed. **/ -EFI_STATUS +SHELL_STATUS IfConfigClearInterfaceInfo ( IN LIST_ENTRY *IfList ) { - EFI_STATUS Status; + EFI_STATUS Status; + SHELL_STATUS ShellStatus; LIST_ENTRY *Entry; LIST_ENTRY *Next; IFCONFIG_INTERFACE_CB *IfCb; @@ -808,6 +809,7 @@ IfConfigClearInterfaceInfo ( Policy = Ip4Config2PolicyDhcp; Status = EFI_SUCCESS; + ShellStatus = SHELL_SUCCESS; if (IsListEmpty (IfList)) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INVALID_INTERFACE), gShellNetwork1HiiHandle); @@ -825,13 +827,13 @@ IfConfigClearInterfaceInfo ( sizeof (EFI_IP4_CONFIG2_POLICY), &Policy ); - if (EFI_ERROR (Status)) { + ShellStatus = SHELL_ACCESS_DENIED; break; } } - return Status; + return ShellStatus; } /** @@ -840,18 +842,18 @@ IfConfigClearInterfaceInfo ( @param[in] IfList The pointer of IfList(interface list). @param[in] VarArg The pointer of ARG_LIST(Args with "-s" option). - @retval EFI_SUCCESS The ifconfig command set processed successfully. + @retval SHELL_SUCCESS The ifconfig command set processed successfully. @retval others The ifconfig command set process failed. **/ -EFI_STATUS +SHELL_STATUS IfConfigSetInterfaceInfo ( IN LIST_ENTRY *IfList, IN ARG_LIST *VarArg ) { - EFI_STATUS Status; + SHELL_STATUS ShellStatus; IFCONFIG_INTERFACE_CB *IfCb; VAR_CHECK_CODE CheckCode; EFI_EVENT TimeOutEvt; @@ -872,7 +874,7 @@ IfConfigSetInterfaceInfo ( if (IsListEmpty (IfList)) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INVALID_INTERFACE), gShellNetwork1HiiHandle); - return EFI_INVALID_PARAMETER; + return SHELL_INVALID_PARAMETER; } // @@ -880,6 +882,7 @@ IfConfigSetInterfaceInfo ( // IfCb = NET_LIST_USER_STRUCT (IfList->ForwardLink, IFCONFIG_INTERFACE_CB, Link); Status = EFI_SUCCESS; + ShellStatus = SHELL_SUCCESS; // // Initialize check list mechanism. @@ -901,6 +904,7 @@ IfConfigSetInterfaceInfo ( &TimeOutEvt ); if (EFI_ERROR (Status)) { + ShellStatus = SHELL_ACCESS_DENIED; goto ON_EXIT; } @@ -912,6 +916,7 @@ IfConfigSetInterfaceInfo ( &MappedEvt ); if (EFI_ERROR (Status)) { + ShellStatus = SHELL_ACCESS_DENIED; goto ON_EXIT; } @@ -969,6 +974,7 @@ IfConfigSetInterfaceInfo ( if (IfCb->Policy == Ip4Config2PolicyDhcp) { Status = IfConfigStartIp4 (IfCb->NicHandle, gImageHandle); if (EFI_ERROR(Status)) { + ShellStatus = SHELL_ACCESS_DENIED; goto ON_EXIT; } } else { @@ -983,6 +989,7 @@ IfConfigSetInterfaceInfo ( &Policy ); if (EFI_ERROR(Status)) { + ShellStatus = SHELL_ACCESS_DENIED; goto ON_EXIT; } } @@ -1000,8 +1007,8 @@ IfConfigSetInterfaceInfo ( sizeof (EFI_IP4_CONFIG2_POLICY), &Policy ); - if (EFI_ERROR(Status)) { + ShellStatus = SHELL_ACCESS_DENIED; goto ON_EXIT; } @@ -1014,6 +1021,7 @@ IfConfigSetInterfaceInfo ( // Status = NetLibStrToIp4 (VarArg->Arg, &ManualAddress.Address); if (EFI_ERROR(Status)) { + ShellStatus = SHELL_INVALID_PARAMETER; goto ON_EXIT; } @@ -1023,6 +1031,7 @@ IfConfigSetInterfaceInfo ( VarArg = VarArg->Next; Status = NetLibStrToIp4 (VarArg->Arg, &ManualAddress.SubnetMask); if (EFI_ERROR(Status)) { + ShellStatus = SHELL_INVALID_PARAMETER; goto ON_EXIT; } @@ -1032,6 +1041,7 @@ IfConfigSetInterfaceInfo ( VarArg = VarArg->Next; Status = NetLibStrToIp4 (VarArg->Arg, &Gateway); if (EFI_ERROR(Status)) { + ShellStatus = SHELL_INVALID_PARAMETER; goto ON_EXIT; } @@ -1043,6 +1053,7 @@ IfConfigSetInterfaceInfo ( MappedEvt ); if (EFI_ERROR (Status)) { + ShellStatus = SHELL_ACCESS_DENIED; goto ON_EXIT; } @@ -1071,9 +1082,10 @@ IfConfigSetInterfaceInfo ( Ip4Config2DataTypeManualAddress, MappedEvt ); - + if (EFI_ERROR (Status)) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_SET_ADDR_FAILED), gShellNetwork1HiiHandle, Status); + ShellStatus = SHELL_ACCESS_DENIED; goto ON_EXIT; } @@ -1088,6 +1100,11 @@ IfConfigSetInterfaceInfo ( DataSize, &Gateway ); + if (EFI_ERROR (Status)) { + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + VarArg = VarArg->Next; } else if (StrCmp (VarArg->Arg, L"dns") == 0) { @@ -1109,6 +1126,7 @@ IfConfigSetInterfaceInfo ( while (Tmp != NULL) { Status = NetLibStrToIp4 (Tmp->Arg, Dns + Index); if (EFI_ERROR(Status)) { + ShellStatus = SHELL_INVALID_PARAMETER; goto ON_EXIT; } Index ++; @@ -1128,6 +1146,10 @@ IfConfigSetInterfaceInfo ( DataSize, Dns ); + if (EFI_ERROR (Status)) { + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } } } @@ -1136,7 +1158,7 @@ IfConfigSetInterfaceInfo ( FreePool (Dns); } - return Status; + return ShellStatus; } @@ -1145,16 +1167,19 @@ IfConfigSetInterfaceInfo ( @param[in] Private The pointer of IFCONFIG_PRIVATE_DATA. - @retval EFI_SUCCESS ifconfig command processed successfully. + @retval SHELL_SUCCESS ifconfig command processed successfully. @retval others The ifconfig command process failed. **/ -EFI_STATUS +SHELL_STATUS IfConfig ( IN IFCONFIG_PRIVATE_DATA *Private ) { EFI_STATUS Status; + SHELL_STATUS ShellStatus; + + ShellStatus = SHELL_SUCCESS; // // Get configure information of all interfaces. @@ -1163,31 +1188,30 @@ IfConfig ( Private->IfName, &Private->IfList ); - if (EFI_ERROR (Status)) { + ShellStatus = SHELL_NOT_FOUND; goto ON_EXIT; } switch (Private->OpCode) { case IfConfigOpList: - Status = IfConfigShowInterfaceInfo (&Private->IfList); + ShellStatus = IfConfigShowInterfaceInfo (&Private->IfList); break; case IfConfigOpClear: - Status = IfConfigClearInterfaceInfo (&Private->IfList); + ShellStatus = IfConfigClearInterfaceInfo (&Private->IfList); break; case IfConfigOpSet: - Status = IfConfigSetInterfaceInfo (&Private->IfList, Private->VarArg); + ShellStatus = IfConfigSetInterfaceInfo (&Private->IfList, Private->VarArg); break; default: - Status = EFI_ABORTED; + ShellStatus = SHELL_UNSUPPORTED; } ON_EXIT: - - return Status; + return ShellStatus; } /** @@ -1267,16 +1291,26 @@ ShellCommandRunIfconfig ( EFI_STATUS Status; IFCONFIG_PRIVATE_DATA *Private; LIST_ENTRY *ParamPackage; + SHELL_STATUS ShellStatus; CONST CHAR16 *ValueStr; ARG_LIST *ArgList; CHAR16 *ProblemParam; CHAR16 *Str; - + + Status = EFI_INVALID_PARAMETER; Private = NULL; + ShellStatus = SHELL_SUCCESS; Status = ShellCommandLineParseEx (mIfConfigCheckList, &ParamPackage, &ProblemParam, TRUE, FALSE); if (EFI_ERROR (Status)) { - ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellNetwork1HiiHandle, L"ifconfig", ProblemParam); + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellNetwork1HiiHandle, L"ifconfig", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + goto ON_EXIT; } @@ -1285,6 +1319,7 @@ ShellCommandRunIfconfig ( // if (ShellCommandLineGetFlag (ParamPackage, L"-c")) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_UNSUPPORTED_OPTION), gShellNetwork1HiiHandle,L"-c"); + ShellStatus = SHELL_INVALID_PARAMETER; goto ON_EXIT; } @@ -1294,6 +1329,7 @@ ShellCommandRunIfconfig ( if (!ShellCommandLineGetFlag (ParamPackage, L"-r") && !ShellCommandLineGetFlag (ParamPackage, L"-s") && !ShellCommandLineGetFlag (ParamPackage, L"-l")) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_LACK_OPTION), gShellNetwork1HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; goto ON_EXIT; } @@ -1304,15 +1340,13 @@ ShellCommandRunIfconfig ( ((ShellCommandLineGetFlag (ParamPackage, L"-r")) && (ShellCommandLineGetFlag (ParamPackage, L"-l"))) || ((ShellCommandLineGetFlag (ParamPackage, L"-s")) && (ShellCommandLineGetFlag (ParamPackage, L"-l")))) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_CON), gShellNetwork1HiiHandle, L"ifconfig"); + ShellStatus = SHELL_INVALID_PARAMETER; goto ON_EXIT; } - Status = EFI_INVALID_PARAMETER; - Private = AllocateZeroPool (sizeof (IFCONFIG_PRIVATE_DATA)); - if (Private == NULL) { - Status = EFI_OUT_OF_RESOURCES; + ShellStatus = SHELL_OUT_OF_RESOURCES; goto ON_EXIT; } @@ -1351,6 +1385,7 @@ ShellCommandRunIfconfig ( ValueStr = ShellCommandLineGetValue (ParamPackage, L"-s"); if (ValueStr == NULL) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_LACK_INTERFACE), gShellNetwork1HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; goto ON_EXIT; } @@ -1367,6 +1402,7 @@ ShellCommandRunIfconfig ( if (Private->IfName == NULL || Private->VarArg == NULL) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_LACK_COMMAND), gShellNetwork1HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; goto ON_EXIT; } } @@ -1374,7 +1410,7 @@ ShellCommandRunIfconfig ( // // Main process of ifconfig. // - Status = IfConfig (Private); + ShellStatus = IfConfig (Private); ON_EXIT: @@ -1384,5 +1420,5 @@ ShellCommandRunIfconfig ( IfConfigCleanup (Private); } - return Status; + return ShellStatus; } From b0fdb34d967435c34f28a3da3b09398ff600f145 Mon Sep 17 00:00:00 2001 From: Qiu Shumin Date: Thu, 10 Dec 2015 07:21:12 +0000 Subject: [PATCH 216/525] ShellPkg: Refine the code to reduce time cost of 'map -r' In some platform 'map -r' may cost more than 1 min. This patch filter the target handles by BlockIO and SimpleFileSystem protocol to reduce the time cost. (Sync patch r19149 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Qiu Shumin Reviewed-by: Jaben Carsey git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19194 6f19259b-4bc3-4df7-8a09-765794883524 --- .../UefiShellCommandLib/ConsistMapping.c | 40 ++++++++++++++----- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/ShellPkg/Library/UefiShellCommandLib/ConsistMapping.c b/ShellPkg/Library/UefiShellCommandLib/ConsistMapping.c index 9bd7b2cedd25..86e8dc59a895 100644 --- a/ShellPkg/Library/UefiShellCommandLib/ConsistMapping.c +++ b/ShellPkg/Library/UefiShellCommandLib/ConsistMapping.c @@ -16,6 +16,10 @@ #include #include #include +#include +#include + + typedef enum { MTDTypeUnknown, @@ -1349,20 +1353,22 @@ ShellCommandConsistMappingInitialize ( OUT EFI_DEVICE_PATH_PROTOCOL ***Table ) { - EFI_HANDLE *HandleBuffer; - UINTN HandleNum; - UINTN HandleLoop; - EFI_DEVICE_PATH_PROTOCOL **TempTable; - EFI_DEVICE_PATH_PROTOCOL *DevicePath; - EFI_DEVICE_PATH_PROTOCOL *HIDevicePath; - UINTN Index; - EFI_STATUS Status; + EFI_HANDLE *HandleBuffer; + UINTN HandleNum; + UINTN HandleLoop; + EFI_DEVICE_PATH_PROTOCOL **TempTable; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_DEVICE_PATH_PROTOCOL *HIDevicePath; + EFI_BLOCK_IO_PROTOCOL *BlockIo; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFileSystem; + UINTN Index; + EFI_STATUS Status; HandleBuffer = NULL; Status = gBS->LocateHandleBuffer ( - AllHandles, - NULL, + ByProtocol, + &gEfiDevicePathProtocolGuid, NULL, &HandleNum, &HandleBuffer @@ -1385,6 +1391,20 @@ ShellCommandConsistMappingInitialize ( continue; } + Status = gBS->HandleProtocol( HandleBuffer[HandleLoop], + &gEfiBlockIoProtocolGuid, + (VOID **)&BlockIo + ); + if (EFI_ERROR(Status)) { + Status = gBS->HandleProtocol( HandleBuffer[HandleLoop], + &gEfiSimpleFileSystemProtocolGuid, + (VOID **)&SimpleFileSystem + ); + if (EFI_ERROR(Status)) { + continue; + } + } + for (Index = 0; TempTable[Index] != NULL; Index++) { if (DevicePathCompare (&TempTable[Index], &HIDevicePath) == 0) { FreePool (HIDevicePath); From 53c6f25007d394164df6669506e643ed73c08577 Mon Sep 17 00:00:00 2001 From: Jeff Fan Date: Thu, 10 Dec 2015 07:21:55 +0000 Subject: [PATCH 217/525] UefiCpuPkg/MtrrLib: Add PCD PcdCpuNumberOfReservedVariableMtrrs Current MtrrLib reserves 2 variable MTRRs for some legacy OS boot (CSM boots) may require some MTRRs to be reserved for OS use. But UEFI OS boot will not use MTRRs. Per Scott's suggestion in link: http://article.gmane.org/gmane.comp.bios.edk2.devel/4099 Add one PCD PcdCpuNumberOfReservedVariableMtrrs to specify the number of variable MTRRs reserved for OS use. Setting its default value to 2 is for back-compatibility. (Sync patch r19151 from main trunk.) Cc: Scott Duplichan Cc: Feng Tian Cc: Michael Kinney Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan Suggested-by: Scott Duplichan Reviewed-by: Feng Tian git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19195 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/Include/Library/MtrrLib.h | 3 ++- UefiCpuPkg/Library/MtrrLib/MtrrLib.c | 6 ++++-- UefiCpuPkg/Library/MtrrLib/MtrrLib.inf | 5 ++++- UefiCpuPkg/UefiCpuPkg.dec | 5 +++++ 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/UefiCpuPkg/Include/Library/MtrrLib.h b/UefiCpuPkg/Include/Library/MtrrLib.h index e06fff7f0178..f9002e7cbfc7 100644 --- a/UefiCpuPkg/Include/Library/MtrrLib.h +++ b/UefiCpuPkg/Include/Library/MtrrLib.h @@ -1,7 +1,7 @@ /** @file MTRR setting library - Copyright (c) 2008 - 2011, Intel Corporation. All rights reserved.
+ Copyright (c) 2008 - 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -26,6 +26,7 @@ #define MTRR_NUMBER_OF_VARIABLE_MTRR 32 // // Firmware need reserve 2 MTRR for OS +// Note: It is replaced by PCD PcdCpuNumberOfReservedVariableMtrrs // #define RESERVED_FIRMWARE_VARIABLE_MTRR_NUMBER 2 diff --git a/UefiCpuPkg/Library/MtrrLib/MtrrLib.c b/UefiCpuPkg/Library/MtrrLib/MtrrLib.c index a65560542c88..82223379e773 100644 --- a/UefiCpuPkg/Library/MtrrLib/MtrrLib.c +++ b/UefiCpuPkg/Library/MtrrLib/MtrrLib.c @@ -140,13 +140,15 @@ GetFirmwareVariableMtrrCount ( ) { UINT32 VariableMtrrCount; + UINT32 ReservedMtrrNumber; VariableMtrrCount = GetVariableMtrrCount (); - if (VariableMtrrCount < RESERVED_FIRMWARE_VARIABLE_MTRR_NUMBER) { + ReservedMtrrNumber = PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs); + if (VariableMtrrCount < ReservedMtrrNumber) { return 0; } - return VariableMtrrCount - RESERVED_FIRMWARE_VARIABLE_MTRR_NUMBER; + return VariableMtrrCount - ReservedMtrrNumber; } /** diff --git a/UefiCpuPkg/Library/MtrrLib/MtrrLib.inf b/UefiCpuPkg/Library/MtrrLib/MtrrLib.inf index 64ec9bd0b0fa..01a4d84da0ed 100644 --- a/UefiCpuPkg/Library/MtrrLib/MtrrLib.inf +++ b/UefiCpuPkg/Library/MtrrLib/MtrrLib.inf @@ -1,7 +1,7 @@ ## @file # MTRR library provides APIs for MTRR operation. # -# Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.
+# Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
# This program and the accompanying materials # are licensed and made available under the terms and conditions of the BSD License # which accompanies this distribution. The full text of the license may be found at @@ -41,3 +41,6 @@ CpuLib DebugLib +[Pcd] + gUefiCpuPkgTokenSpaceGuid.PcdCpuNumberOfReservedVariableMtrrs ## SOMETIMES_CONSUMES + diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec index e783a7b53616..a6941466891e 100644 --- a/UefiCpuPkg/UefiCpuPkg.dec +++ b/UefiCpuPkg/UefiCpuPkg.dec @@ -167,6 +167,11 @@ # @Prompt SMM CPU Synchronization Method. gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmSyncMode|0x00|UINT8|0x60000014 + ## Specifies the number of variable MTRRs reserved for OS use. The default number of + # MTRRs reserved for OS use is 2. + # @Prompt Number of reserved variable MTRRs. + gUefiCpuPkgTokenSpaceGuid.PcdCpuNumberOfReservedVariableMtrrs|0x2|UINT32|0x00000015 + [PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx] ## Specifies timeout value in microseconds for the BSP to detect all APs for the first time. # @Prompt Timeout for the BSP to detect all APs for the first time. From e7409a1e259fb56c6a1927398aff5b251fbb444d Mon Sep 17 00:00:00 2001 From: Michael Kinney Date: Thu, 10 Dec 2015 07:22:31 +0000 Subject: [PATCH 218/525] UefiCpuPkg/MtrrLib: Fix some typo and clean up code format Fixed some typo. Removed some trailing spaces and TAB key. Clean up code format. (Sync patch r19152 from main trunk.) Cc: Feng Tian Cc: Michael Kinney Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Michael Kinney Signed-off-by: Jeff Fan Reviewed-by: Feng Tian git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19196 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/Include/Library/MtrrLib.h | 70 +++++++----- UefiCpuPkg/Library/MtrrLib/MtrrLib.c | 162 ++++++++++++++------------- 2 files changed, 121 insertions(+), 111 deletions(-) diff --git a/UefiCpuPkg/Include/Library/MtrrLib.h b/UefiCpuPkg/Include/Library/MtrrLib.h index f9002e7cbfc7..884c7bb6996c 100644 --- a/UefiCpuPkg/Include/Library/MtrrLib.h +++ b/UefiCpuPkg/Include/Library/MtrrLib.h @@ -84,8 +84,8 @@ typedef struct { // Structure to hold base and mask pair for variable MTRR register // typedef struct _MTRR_VARIABLE_SETTING_ { - UINT64 Base; - UINT64 Mask; + UINT64 Base; + UINT64 Mask; } MTRR_VARIABLE_SETTING; // @@ -115,11 +115,11 @@ typedef struct _MTRR_SETTINGS_ { // Memory cache types // typedef enum { - CacheUncacheable = 0, - CacheWriteCombining = 1, - CacheWriteThrough = 4, - CacheWriteProtected = 5, - CacheWriteBack = 6 + CacheUncacheable = 0, + CacheWriteCombining = 1, + CacheWriteThrough = 4, + CacheWriteProtected = 5, + CacheWriteBack = 6 } MTRR_MEMORY_CACHE_TYPE; #define MTRR_CACHE_UNCACHEABLE 0 @@ -156,20 +156,27 @@ GetFirmwareVariableMtrrCount ( /** This function attempts to set the attributes for a memory range. - @param BaseAddress The physical address that is the start address of a memory region. - @param Length The size in bytes of the memory region. - @param Attributes The bit mask of attributes to set for the memory region. + @param[in] BaseAddress The physical address that is the start + address of a memory region. + @param[in] Length The size in bytes of the memory region. + @param[in] Attribute The bit mask of attributes to set for the + memory region. - @retval RETURN_SUCCESS The attributes were set for the memory region. + @retval RETURN_SUCCESS The attributes were set for the memory + region. @retval RETURN_INVALID_PARAMETER Length is zero. - @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the - memory resource range specified by BaseAddress and Length. - @retval RETURN_UNSUPPORTED The bit mask of attributes is not support for the memory resource - range specified by BaseAddress and Length. - @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by - BaseAddress and Length cannot be modified. - @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of - the memory resource range. + @retval RETURN_UNSUPPORTED The processor does not support one or + more bytes of the memory resource range + specified by BaseAddress and Length. + @retval RETURN_UNSUPPORTED The bit mask of attributes is not support + for the memory resource range specified + by BaseAddress and Length. + @retval RETURN_ACCESS_DENIED The attributes for the memory resource + range specified by BaseAddress and Length + cannot be modified. + @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to + modify the attributes of the memory + resource range. **/ RETURN_STATUS @@ -185,7 +192,7 @@ MtrrSetMemoryAttribute ( This function will get the memory cache type of the specific address. This function is mainly for debugging purposes. - @param Address The specific address + @param[in] Address The specific address @return The memory cache type of the specific address @@ -200,7 +207,7 @@ MtrrGetMemoryAttribute ( /** This function will get the raw value in variable MTRRs - @param VariableSettings A buffer to hold variable MTRRs content. + @param[out] VariableSettings A buffer to hold variable MTRRs content. @return The buffer point to MTRR_VARIABLE_SETTINGS in which holds the content of the variable mtrr @@ -215,7 +222,7 @@ MtrrGetVariableMtrr ( /** This function sets fixed MTRRs - @param VariableSettings A buffer to hold variable MTRRs content. + @param[in] VariableSettings A buffer to hold variable MTRRs content. @return The pointer of VariableSettings @@ -230,7 +237,7 @@ MtrrSetVariableMtrr ( /** This function gets the content in fixed MTRRs - @param FixedSettings A buffer to hold fixed MTRRs content. + @param[out] FixedSettings A buffer to hold fixed MTRRs content. @return The pointer of FixedSettings @@ -245,7 +252,7 @@ MtrrGetFixedMtrr ( /** This function sets fixed MTRRs - @param FixedSettings A buffer holding fixed MTRRs content. + @param[in] FixedSettings A buffer holding fixed MTRRs content. @return The pointer of FixedSettings @@ -260,7 +267,7 @@ MtrrSetFixedMtrr ( /** This function gets the content in all MTRRs (variable and fixed) - @param MtrrSetting A buffer to hold all MTRRs content. + @param[out] MtrrSetting A buffer to hold all MTRRs content. @return The pointer of MtrrSetting @@ -275,7 +282,7 @@ MtrrGetAllMtrrs ( /** This function sets all MTRRs (variable and fixed) - @param MtrrSetting A buffer to hold all MTRRs content. + @param[in] MtrrSetting A buffer to hold all MTRRs content. @return The pointer of MtrrSetting @@ -293,11 +300,12 @@ MtrrSetAllMtrrs ( This function shadows the content of variable MTRRs into an internal array: VariableMtrr - @param MtrrValidBitsMask The mask for the valid bit of the MTRR - @param MtrrValidAddressMask The valid address mask for MTRR since the base address in - MTRR must align to 4K, so valid address mask equal to - MtrrValidBitsMask & 0xfffffffffffff000ULL - @param VariableMtrr The array to shadow variable MTRRs content + @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR + @param[in] MtrrValidAddressMask The valid address mask for MTRR since the base address in + MTRR must align to 4K, so valid address mask equal to + MtrrValidBitsMask & 0xfffffffffffff000ULL + @param[out] VariableMtrr The array to shadow variable MTRRs content + @return The ruturn value of this paramter indicates the number of MTRRs which has been used. **/ diff --git a/UefiCpuPkg/Library/MtrrLib/MtrrLib.c b/UefiCpuPkg/Library/MtrrLib/MtrrLib.c index 82223379e773..1584ae23d9ce 100644 --- a/UefiCpuPkg/Library/MtrrLib/MtrrLib.c +++ b/UefiCpuPkg/Library/MtrrLib/MtrrLib.c @@ -86,7 +86,7 @@ CONST FIXED_MTRR mMtrrLibFixedMtrrTable[] = { MTRR_LIB_IA32_MTRR_FIX4K_F8000, 0xF8000, SIZE_4KB - }, + } }; // @@ -188,7 +188,7 @@ PreMtrrChange ( // Disable interrupts and save current interrupt state // MtrrContext->InterruptState = SaveAndDisableInterrupts(); - + // // Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29) // @@ -206,7 +206,7 @@ PreMtrrChange ( CpuFlushTlb (); // - // Disable Mtrrs + // Disable MTRRs // AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, 10, 11, 0); } @@ -226,7 +226,7 @@ PostMtrrChangeEnableCache ( ) { // - // Flush all TLBs + // Flush all TLBs // CpuFlushTlb (); @@ -239,7 +239,7 @@ PostMtrrChangeEnableCache ( // Restore original CR4 value // AsmWriteCr4 (MtrrContext->Cr4); - + // // Restore original interrupt state // @@ -272,9 +272,9 @@ PostMtrrChange ( /** Programs fixed MTRRs registers. - @param MemoryCacheType The memory type to set. - @param Base The base address of memory range. - @param Length The length of memory range. + @param[in] MemoryCacheType The memory type to set. + @param[in, out] Base The base address of memory range. + @param[in, out] Length The length of memory range. @retval RETURN_SUCCESS The cache type was updated successfully @retval RETURN_UNSUPPORTED The requested range or cache type was invalid @@ -356,14 +356,14 @@ ProgramFixedMtrr ( /** - Get the attribute of variable MTRRs. + Gets the attribute of variable MTRRs. This function shadows the content of variable MTRRs into an internal array: VariableMtrr. - @param MtrrValidBitsMask The mask for the valid bit of the MTRR - @param MtrrValidAddressMask The valid address mask for MTRR - @param VariableMtrr The array to shadow variable MTRRs content + @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR + @param[in] MtrrValidAddressMask The valid address mask for MTRR + @param[out] VariableMtrr The array to shadow variable MTRRs content @return The return value of this paramter indicates the number of MTRRs which has been used. @@ -423,9 +423,9 @@ MtrrGetMemoryAttributeInVariableMtrr ( /** Checks overlap between given memory range and MTRRs. - @param Start The start address of memory range. - @param End The end address of memory range. - @param VariableMtrr The array to shadow variable MTRRs content + @param[in] Start The start address of memory range. + @param[in] End The end address of memory range. + @param[in] VariableMtrr The array to shadow variable MTRRs content @retval TRUE Overlap exists. @retval FALSE No overlap. @@ -461,9 +461,9 @@ CheckMemoryAttributeOverlap ( /** Marks a variable MTRR as non-valid. - @param Index The index of the array VariableMtrr to be invalidated - @param VariableMtrr The array to shadow variable MTRRs content - @param UsedMtrr The number of MTRRs which has already been used + @param[in] Index The index of the array VariableMtrr to be invalidated + @param[in] VariableMtrr The array to shadow variable MTRRs content + @param[out] UsedMtrr The number of MTRRs which has already been used **/ VOID @@ -479,16 +479,16 @@ InvalidateShadowMtrr ( /** - Combine memory attributes. + Combines memory attributes. If overlap exists between given memory range and MTRRs, try to combine them. - @param Attributes The memory type to set. - @param Base The base address of memory range. - @param Length The length of memory range. - @param VariableMtrr The array to shadow variable MTRRs content - @param UsedMtrr The number of MTRRs which has already been used - @param OverwriteExistingMtrr Returns whether an existing MTRR was used + @param[in] Attributes The memory type to set. + @param[in, out] Base The base address of memory range. + @param[in, out] Length The length of memory range. + @param[in] VariableMtrr The array to shadow variable MTRRs content + @param[in, out] UsedMtrr The number of MTRRs which has already been used + @param[out] OverwriteExistingMtrr Returns whether an existing MTRR was used @retval EFI_SUCCESS Memory region successfully combined. @retval EFI_ACCESS_DENIED Memory region cannot be combined. @@ -536,7 +536,7 @@ CombineMemoryAttribute ( // if (Attributes == VariableMtrr[Index].Type) { // - // if the Mtrr range contain the request range, set a flag, then continue to + // if the MTRR range contain the request range, set a flag, then continue to // invalidate any MTRR of the same request range with higher priority cache type. // if (VariableMtrr[Index].BaseAddress <= *Base && MtrrEnd >= EndAddress) { @@ -597,9 +597,10 @@ CombineMemoryAttribute ( /** - Calculate the maximum value which is a power of 2, but less the MemoryLength. + Calculates the maximum value which is a power of 2, but less the MemoryLength. + + @param[in] MemoryLength The number to pass in. - @param MemoryLength The number to pass in. @return The maximum value which is align to power of 2 and less the MemoryLength **/ @@ -626,21 +627,22 @@ Power2MaxMemory ( /** - Determine the MTRR numbers used to program a memory range. + Determines the MTRR numbers used to program a memory range. - This function first checks the alignment of the base address. If the alignment of the base address <= Length, - cover the memory range (BaseAddress, alignment) by a MTRR, then BaseAddress += alignment and Length -= alignment. - Repeat the step until alignment > Length. + This function first checks the alignment of the base address. + If the alignment of the base address <= Length, cover the memory range + (BaseAddress, alignment) by a MTRR, then BaseAddress += alignment and + Length -= alignment. Repeat the step until alignment > Length. - Then this function determines which direction of programming the variable MTRRs for the remaining length - will use fewer MTRRs. + Then this function determines which direction of programming the variable + MTRRs for the remaining length will use fewer MTRRs. - @param BaseAddress Length of Memory to program MTRR - @param Length Length of Memory to program MTRR - @param MtrrNumber Pointer to the number of necessary MTRRs + @param[in] BaseAddress Length of Memory to program MTRR + @param[in] Length Length of Memory to program MTRR + @param[in] MtrrNumber Pointer to the number of necessary MTRRs @retval TRUE Positive direction is better. - FALSE Negtive direction is better. + FALSE Negative direction is better. **/ BOOLEAN @@ -709,13 +711,13 @@ GetMtrrNumberAndDirection ( This function programs MTRRs according to the values specified in the shadow array. - @param VariableMtrr The array to shadow variable MTRRs content + @param[in, out] VariableMtrr Shadow of variable MTRR contents **/ VOID InvalidateMtrr ( - IN VARIABLE_MTRR *VariableMtrr - ) + IN OUT VARIABLE_MTRR *VariableMtrr + ) { UINTN Index; UINTN VariableMtrrCount; @@ -741,11 +743,11 @@ InvalidateMtrr ( This function programs variable MTRRs - @param MtrrNumber Index of MTRR to program. - @param BaseAddress Base address of memory region. - @param Length Length of memory region. - @param MemoryCacheType Memory type to set. - @param MtrrValidAddressMask The valid address mask for MTRR + @param[in] MtrrNumber Index of MTRR to program. + @param[in] BaseAddress Base address of memory region. + @param[in] Length Length of memory region. + @param[in] MemoryCacheType Memory type to set. + @param[in] MtrrValidAddressMask The valid address mask for MTRR **/ VOID @@ -782,9 +784,9 @@ ProgramVariableMtrr ( /** - Convert the Memory attibute value to MTRR_MEMORY_CACHE_TYPE. + Converts the Memory attribute value to MTRR_MEMORY_CACHE_TYPE. - @param MtrrType MTRR memory type + @param[in] MtrrType MTRR memory type @return The enum item in MTRR_MEMORY_CACHE_TYPE @@ -808,7 +810,7 @@ GetMemoryCacheTypeFromMtrrType ( default: // // MtrrType is MTRR_CACHE_INVALID_TYPE, that means - // no mtrr covers the range + // no MTRR covers the range // return MtrrGetDefaultMemoryType (); } @@ -819,8 +821,8 @@ GetMemoryCacheTypeFromMtrrType ( This function initializes the valid bits mask and valid address mask for MTRRs. - @param MtrrValidBitsMask The mask for the valid bit of the MTRR - @param MtrrValidAddressMask The valid address mask for the MTRR + @param[out] MtrrValidBitsMask The mask for the valid bit of the MTRR + @param[out] MtrrValidAddressMask The valid address mask for the MTRR **/ VOID @@ -849,21 +851,21 @@ MtrrLibInitializeMtrrMask ( /** - Determing the real attribute of a memory range. + Determines the real attribute of a memory range. This function is to arbitrate the real attribute of the memory when - there are 2 MTRR covers the same memory range. For further details, + there are 2 MTRRs covers the same memory range. For further details, please refer the IA32 Software Developer's Manual, Volume 3, Section 10.11.4.1. - @param MtrrType1 the first kind of Memory type - @param MtrrType2 the second kind of memory type + @param[in] MtrrType1 The first kind of Memory type + @param[in] MtrrType2 The second kind of memory type **/ UINT64 MtrrPrecedence ( - UINT64 MtrrType1, - UINT64 MtrrType2 + IN UINT64 MtrrType1, + IN UINT64 MtrrType2 ) { UINT64 MtrrType; @@ -923,11 +925,11 @@ MtrrPrecedence ( /** This function attempts to set the attributes for a memory range. - @param BaseAddress The physical address that is the start - address of a memory region. - @param Length The size in bytes of the memory region. - @param Attributes The bit mask of attributes to set for the - memory region. + @param[in] BaseAddress The physical address that is the start + address of a memory region. + @param[in] Length The size in bytes of the memory region. + @param[in] Attribute The bit mask of attributes to set for the + memory region. @retval RETURN_SUCCESS The attributes were set for the memory region. @@ -1198,9 +1200,9 @@ MtrrSetMemoryAttribute ( This function is mainly for debug purpose. - @param Address The specific address + @param[in] Address The specific address - @return Memory cache type of the sepcific address + @return Memory cache type of the specific address **/ MTRR_MEMORY_CACHE_TYPE @@ -1290,7 +1292,7 @@ MtrrGetMemoryAttribute ( /** This function will get the raw value in variable MTRRs - @param VariableSettings A buffer to hold variable MTRRs content. + @param[out] FixedSettings A buffer to hold fixed MTRRs content. @return The VariableSettings input pointer @@ -1325,7 +1327,7 @@ MtrrGetVariableMtrr ( /** Worker function setting variable MTRRs - @param VariableSettings A buffer to hold variable MTRRs content. + @param[in] VariableSettings A buffer to hold variable MTRRs content. **/ VOID @@ -1355,7 +1357,7 @@ MtrrSetVariableMtrrWorker ( /** This function sets variable MTRRs - @param VariableSettings A buffer to hold variable MTRRs content. + @param[in] VariableSettings A buffer to hold variable MTRRs content. @return The pointer of VariableSettings @@ -1382,7 +1384,7 @@ MtrrSetVariableMtrr ( /** This function gets the content in fixed MTRRs - @param FixedSettings A buffer to hold fixed Mtrrs content. + @param[out] FixedSettings A buffer to hold fixed Mtrrs content. @retval The pointer of FixedSettings @@ -1410,7 +1412,7 @@ MtrrGetFixedMtrr ( /** Worker function setting fixed MTRRs - @param FixedSettings A buffer to hold fixed Mtrrs content. + @param[in] FixedSettings A buffer to hold fixed Mtrrs content. **/ VOID @@ -1432,7 +1434,7 @@ MtrrSetFixedMtrrWorker ( /** This function sets fixed MTRRs - @param FixedSettings A buffer to hold fixed Mtrrs content. + @param[in] FixedSettings A buffer to hold fixed Mtrrs content. @retval The pointer of FixedSettings @@ -1460,7 +1462,7 @@ MtrrSetFixedMtrr ( /** This function gets the content in all MTRRs (variable and fixed) - @param MtrrSetting A buffer to hold all Mtrrs content. + @param[out] MtrrSetting A buffer to hold all Mtrrs content. @retval the pointer of MtrrSetting @@ -1497,7 +1499,7 @@ MtrrGetAllMtrrs ( /** This function sets all MTRRs (variable and fixed) - @param MtrrSetting A buffer holding all MTRRs content. + @param[in] MtrrSetting A buffer holding all MTRRs content. @retval The pointer of MtrrSetting @@ -1569,7 +1571,7 @@ MtrrDebugPrintAllMtrrs ( DEBUG((DEBUG_CACHE, "MTRR Settings\n")); DEBUG((DEBUG_CACHE, "=============\n")); - + MtrrGetAllMtrrs (&MtrrSettings); DEBUG((DEBUG_CACHE, "MTRR Default Type: %016lx\n", MtrrSettings.MtrrDefType)); for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) { @@ -1596,7 +1598,7 @@ MtrrDebugPrintAllMtrrs ( MemoryType = (UINTN)(RShiftU64 (MtrrSettings.Fixed.Mtrr[Index], Index1 * 8) & 0xff); if (MemoryType > CacheWriteBack) { MemoryType = MTRR_CACHE_INVALID_TYPE; - } + } if (MemoryType != PreviousMemoryType) { if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) { DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1)); @@ -1632,12 +1634,12 @@ MtrrDebugPrintAllMtrrs ( PreviousMemoryType = MemoryType; DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base)); } - - RangeBase = BASE_1MB; + + RangeBase = BASE_1MB; NoRangeBase = BASE_1MB; RangeLimit = Limit; NoRangeLimit = Limit; - + for (Index = 0, Found = FALSE; Index < VariableMtrrCount; Index++) { if ((MtrrSettings.Variables.Mtrr[Index].Mask & BIT11) == 0) { // @@ -1651,7 +1653,7 @@ MtrrDebugPrintAllMtrrs ( if (Base >= MtrrBase && Base < MtrrLimit) { Found = TRUE; } - + if (Base >= MtrrBase && MtrrBase > RangeBase) { RangeBase = MtrrBase; } @@ -1664,7 +1666,7 @@ MtrrDebugPrintAllMtrrs ( if (Base < MtrrLimit && MtrrLimit <= RangeLimit) { RangeLimit = MtrrLimit; } - + if (Base > MtrrLimit && NoRangeBase < MtrrLimit) { NoRangeBase = MtrrLimit + 1; } @@ -1672,7 +1674,7 @@ MtrrDebugPrintAllMtrrs ( NoRangeLimit = MtrrBase - 1; } } - + if (Found) { Base = RangeLimit + 1; } else { From 09e97e00725749440b9c6a968537dac09a11d34c Mon Sep 17 00:00:00 2001 From: Michael Kinney Date: Thu, 10 Dec 2015 07:22:58 +0000 Subject: [PATCH 219/525] UefiCpuPkg/MtrrLib: Add worker functions not invoke IsMtrrSupported() Abstract some worker functions not to invoke IsMtrrSupported(). They could be used by other functions to reduce the number of invoking times on IsMtrrSupported(). (Sync patch r19153 from main trunk.) Cc: Feng Tian Cc: Michael Kinney Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Michael Kinney Signed-off-by: Jeff Fan Reviewed-by: Feng Tian git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19197 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/Library/MtrrLib/MtrrLib.c | 139 +++++++++++++++++++++------ 1 file changed, 108 insertions(+), 31 deletions(-) diff --git a/UefiCpuPkg/Library/MtrrLib/MtrrLib.c b/UefiCpuPkg/Library/MtrrLib/MtrrLib.c index 1584ae23d9ce..b1c12aa32e01 100644 --- a/UefiCpuPkg/Library/MtrrLib/MtrrLib.c +++ b/UefiCpuPkg/Library/MtrrLib/MtrrLib.c @@ -103,6 +103,24 @@ GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mMtrrMemoryCacheTypeShortName[] = { "R*" // Invalid }; +/** + Worker function returns the variable MTRR count for the CPU. + + @return Variable MTRR count + +**/ +UINT32 +GetVariableMtrrCountWorker ( + VOID + ) +{ + UINT32 VariableMtrrCount; + + VariableMtrrCount = (UINT32)(AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP) & MTRR_LIB_IA32_MTRR_CAP_VCNT_MASK); + ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR); + return VariableMtrrCount; +} + /** Returns the variable MTRR count for the CPU. @@ -115,34 +133,27 @@ GetVariableMtrrCount ( VOID ) { - UINT32 VariableMtrrCount; - if (!IsMtrrSupported ()) { return 0; } - - VariableMtrrCount = (UINT32)(AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP) & MTRR_LIB_IA32_MTRR_CAP_VCNT_MASK); - ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR); - - return VariableMtrrCount; + return GetVariableMtrrCountWorker (); } /** - Returns the firmware usable variable MTRR count for the CPU. + Worker function returns the firmware usable variable MTRR count for the CPU. @return Firmware usable variable MTRR count **/ UINT32 -EFIAPI -GetFirmwareVariableMtrrCount ( +GetFirmwareVariableMtrrCountWorker ( VOID ) { UINT32 VariableMtrrCount; UINT32 ReservedMtrrNumber; - VariableMtrrCount = GetVariableMtrrCount (); + VariableMtrrCount = GetVariableMtrrCountWorker (); ReservedMtrrNumber = PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs); if (VariableMtrrCount < ReservedMtrrNumber) { return 0; @@ -151,6 +162,39 @@ GetFirmwareVariableMtrrCount ( return VariableMtrrCount - ReservedMtrrNumber; } +/** + Returns the firmware usable variable MTRR count for the CPU. + + @return Firmware usable variable MTRR count + +**/ +UINT32 +EFIAPI +GetFirmwareVariableMtrrCount ( + VOID + ) +{ + if (!IsMtrrSupported ()) { + return 0; + } + return GetFirmwareVariableMtrrCountWorker (); +} + +/** + Worker function returns the default MTRR cache type for the system. + + @return The default MTRR cache type. + +**/ +MTRR_MEMORY_CACHE_TYPE +MtrrGetDefaultMemoryTypeWorker ( + VOID + ) +{ + return (MTRR_MEMORY_CACHE_TYPE) (AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE) & 0x7); +} + + /** Returns the default MTRR cache type for the system. @@ -166,8 +210,7 @@ MtrrGetDefaultMemoryType ( if (!IsMtrrSupported ()) { return CacheUncacheable; } - - return (MTRR_MEMORY_CACHE_TYPE) (AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE) & 0x7); + return MtrrGetDefaultMemoryTypeWorker (); } /** @@ -1290,26 +1333,21 @@ MtrrGetMemoryAttribute ( /** - This function will get the raw value in variable MTRRs + Worker function will get the raw value in variable MTRRs - @param[out] FixedSettings A buffer to hold fixed MTRRs content. + @param[out] VariableSettings A buffer to hold variable MTRRs content. @return The VariableSettings input pointer **/ MTRR_VARIABLE_SETTINGS* -EFIAPI -MtrrGetVariableMtrr ( - OUT MTRR_VARIABLE_SETTINGS *VariableSettings +MtrrGetVariableMtrrWorker ( + OUT MTRR_VARIABLE_SETTINGS *VariableSettings ) { UINT32 Index; UINT32 VariableMtrrCount; - if (!IsMtrrSupported ()) { - return VariableSettings; - } - VariableMtrrCount = GetVariableMtrrCount (); ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR); @@ -1323,6 +1361,29 @@ MtrrGetVariableMtrr ( return VariableSettings; } +/** + This function will get the raw value in variable MTRRs + + @param[out] VariableSettings A buffer to hold variable MTRRs content. + + @return The VariableSettings input pointer + +**/ +MTRR_VARIABLE_SETTINGS* +EFIAPI +MtrrGetVariableMtrr ( + OUT MTRR_VARIABLE_SETTINGS *VariableSettings + ) +{ + if (!IsMtrrSupported ()) { + return VariableSettings; + } + + return MtrrGetVariableMtrrWorker ( + VariableSettings + ); +} + /** Worker function setting variable MTRRs @@ -1380,11 +1441,34 @@ MtrrSetVariableMtrr ( return VariableSettings; } +/** + Worker function gets the content in fixed MTRRs + + @param[out] FixedSettings A buffer to hold fixed MTRRs content. + + @retval The pointer of FixedSettings + +**/ +MTRR_FIXED_SETTINGS* +MtrrGetFixedMtrrWorker ( + OUT MTRR_FIXED_SETTINGS *FixedSettings + ) +{ + UINT32 Index; + + for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) { + FixedSettings->Mtrr[Index] = + AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr); + } + + return FixedSettings; +} + /** This function gets the content in fixed MTRRs - @param[out] FixedSettings A buffer to hold fixed Mtrrs content. + @param[out] FixedSettings A buffer to hold fixed MTRRs content. @retval The pointer of FixedSettings @@ -1395,18 +1479,11 @@ MtrrGetFixedMtrr ( OUT MTRR_FIXED_SETTINGS *FixedSettings ) { - UINT32 Index; - if (!IsMtrrSupported ()) { return FixedSettings; } - for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) { - FixedSettings->Mtrr[Index] = - AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr); - }; - - return FixedSettings; + return MtrrGetFixedMtrrWorker (FixedSettings); } /** From d9b7d84100be975a07b0cda0962c898ab970e614 Mon Sep 17 00:00:00 2001 From: Michael Kinney Date: Thu, 10 Dec 2015 07:23:27 +0000 Subject: [PATCH 220/525] UefiCpuPkg/MtrrLib: Adjust functions order Only adjust functions order and there is no any real functionality impact. (Sync patch r19154 from main trunk.) Cc: Feng Tian Cc: Michael Kinney Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Michael Kinney Signed-off-by: Jeff Fan Reviewed-by: Feng Tian git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19198 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/Library/MtrrLib/MtrrLib.c | 956 +++++++++++++-------------- 1 file changed, 477 insertions(+), 479 deletions(-) diff --git a/UefiCpuPkg/Library/MtrrLib/MtrrLib.c b/UefiCpuPkg/Library/MtrrLib/MtrrLib.c index b1c12aa32e01..ea2b211e0580 100644 --- a/UefiCpuPkg/Library/MtrrLib/MtrrLib.c +++ b/UefiCpuPkg/Library/MtrrLib/MtrrLib.c @@ -311,6 +311,103 @@ PostMtrrChange ( PostMtrrChangeEnableCache (MtrrContext); } +/** + Worker function gets the content in fixed MTRRs + + @param[out] FixedSettings A buffer to hold fixed MTRRs content. + + @retval The pointer of FixedSettings + +**/ +MTRR_FIXED_SETTINGS* +MtrrGetFixedMtrrWorker ( + OUT MTRR_FIXED_SETTINGS *FixedSettings + ) +{ + UINT32 Index; + + for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) { + FixedSettings->Mtrr[Index] = + AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr); + } + + return FixedSettings; +} + + +/** + This function gets the content in fixed MTRRs + + @param[out] FixedSettings A buffer to hold fixed MTRRs content. + + @retval The pointer of FixedSettings + +**/ +MTRR_FIXED_SETTINGS* +EFIAPI +MtrrGetFixedMtrr ( + OUT MTRR_FIXED_SETTINGS *FixedSettings + ) +{ + if (!IsMtrrSupported ()) { + return FixedSettings; + } + + return MtrrGetFixedMtrrWorker (FixedSettings); +} + + +/** + Worker function will get the raw value in variable MTRRs + + @param[out] VariableSettings A buffer to hold variable MTRRs content. + + @return The VariableSettings input pointer + +**/ +MTRR_VARIABLE_SETTINGS* +MtrrGetVariableMtrrWorker ( + OUT MTRR_VARIABLE_SETTINGS *VariableSettings + ) +{ + UINT32 Index; + UINT32 VariableMtrrCount; + + VariableMtrrCount = GetVariableMtrrCount (); + ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR); + + for (Index = 0; Index < VariableMtrrCount; Index++) { + VariableSettings->Mtrr[Index].Base = + AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1)); + VariableSettings->Mtrr[Index].Mask = + AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1); + } + + return VariableSettings; +} + +/** + This function will get the raw value in variable MTRRs + + @param[out] VariableSettings A buffer to hold variable MTRRs content. + + @return The VariableSettings input pointer + +**/ +MTRR_VARIABLE_SETTINGS* +EFIAPI +MtrrGetVariableMtrr ( + OUT MTRR_VARIABLE_SETTINGS *VariableSettings + ) +{ + if (!IsMtrrSupported ()) { + return VariableSettings; + } + + return MtrrGetVariableMtrrWorker ( + VariableSettings + ); +} /** Programs fixed MTRRs registers. @@ -965,126 +1062,368 @@ MtrrPrecedence ( } + /** - This function attempts to set the attributes for a memory range. + This function will get the memory cache type of the specific address. - @param[in] BaseAddress The physical address that is the start - address of a memory region. - @param[in] Length The size in bytes of the memory region. - @param[in] Attribute The bit mask of attributes to set for the - memory region. + This function is mainly for debug purpose. - @retval RETURN_SUCCESS The attributes were set for the memory - region. - @retval RETURN_INVALID_PARAMETER Length is zero. - @retval RETURN_UNSUPPORTED The processor does not support one or - more bytes of the memory resource range - specified by BaseAddress and Length. - @retval RETURN_UNSUPPORTED The bit mask of attributes is not support - for the memory resource range specified - by BaseAddress and Length. - @retval RETURN_ACCESS_DENIED The attributes for the memory resource - range specified by BaseAddress and Length - cannot be modified. - @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to - modify the attributes of the memory - resource range. + @param[in] Address The specific address + + @return Memory cache type of the specific address **/ -RETURN_STATUS +MTRR_MEMORY_CACHE_TYPE EFIAPI -MtrrSetMemoryAttribute ( - IN PHYSICAL_ADDRESS BaseAddress, - IN UINT64 Length, - IN MTRR_MEMORY_CACHE_TYPE Attribute +MtrrGetMemoryAttribute ( + IN PHYSICAL_ADDRESS Address ) { - UINT64 TempQword; - RETURN_STATUS Status; - UINT64 MemoryType; - UINT64 Alignment; - BOOLEAN OverLap; - BOOLEAN Positive; - UINT32 MsrNum; - UINTN MtrrNumber; - VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR]; - UINT32 UsedMtrr; - UINT64 MtrrValidBitsMask; - UINT64 MtrrValidAddressMask; - BOOLEAN OverwriteExistingMtrr; - UINT32 FirmwareVariableMtrrCount; - UINT32 VariableMtrrEnd; - MTRR_CONTEXT MtrrContext; - - DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttribute() %a:%016lx-%016lx\n", mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, Length)); + UINT64 TempQword; + UINTN Index; + UINTN SubIndex; + UINT64 MtrrType; + UINT64 TempMtrrType; + MTRR_MEMORY_CACHE_TYPE CacheType; + VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR]; + UINT64 MtrrValidBitsMask; + UINT64 MtrrValidAddressMask; + UINTN VariableMtrrCount; if (!IsMtrrSupported ()) { - Status = RETURN_UNSUPPORTED; - goto Done; + return CacheUncacheable; } - FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount (); - VariableMtrrEnd = MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (2 * GetVariableMtrrCount ()) - 1; - - MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask); - - TempQword = 0; - MemoryType = (UINT64)Attribute; - OverwriteExistingMtrr = FALSE; - // - // Check for an invalid parameter + // Check if MTRR is enabled, if not, return UC as attribute // - if (Length == 0) { - Status = RETURN_INVALID_PARAMETER; - goto Done; - } + TempQword = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE); + MtrrType = MTRR_CACHE_INVALID_TYPE; - if ( - (BaseAddress & ~MtrrValidAddressMask) != 0 || - (Length & ~MtrrValidAddressMask) != 0 - ) { - Status = RETURN_UNSUPPORTED; - goto Done; + if ((TempQword & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) { + return CacheUncacheable; } // - // Check if Fixed MTRR + // If address is less than 1M, then try to go through the fixed MTRR // - Status = RETURN_SUCCESS; - while ((BaseAddress < BASE_1MB) && (Length > 0) && Status == RETURN_SUCCESS) { - PreMtrrChange (&MtrrContext); - Status = ProgramFixedMtrr (MemoryType, &BaseAddress, &Length); - PostMtrrChange (&MtrrContext); - if (RETURN_ERROR (Status)) { - goto Done; + if (Address < BASE_1MB) { + if ((TempQword & MTRR_LIB_CACHE_FIXED_MTRR_ENABLED) != 0) { + // + // Go through the fixed MTRR + // + for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) { + if (Address >= mMtrrLibFixedMtrrTable[Index].BaseAddress && + Address < ( + mMtrrLibFixedMtrrTable[Index].BaseAddress + + (mMtrrLibFixedMtrrTable[Index].Length * 8) + ) + ) { + SubIndex = + ((UINTN)Address - mMtrrLibFixedMtrrTable[Index].BaseAddress) / + mMtrrLibFixedMtrrTable[Index].Length; + TempQword = AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr); + MtrrType = RShiftU64 (TempQword, SubIndex * 8) & 0xFF; + return GetMemoryCacheTypeFromMtrrType (MtrrType); + } + } } } - - if (Length == 0) { - // - // A Length of 0 can only make sense for fixed MTTR ranges. - // Since we just handled the fixed MTRRs, we can skip the - // variable MTRR section. - // - goto Done; - } + MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask); + MtrrGetMemoryAttributeInVariableMtrr( + MtrrValidBitsMask, + MtrrValidAddressMask, + VariableMtrr + ); // - // Since memory ranges below 1MB will be overridden by the fixed MTRRs, - // we can set the base to 0 to save variable MTRRs. + // Go through the variable MTRR // - if (BaseAddress == BASE_1MB) { - BaseAddress = 0; - Length += SIZE_1MB; + VariableMtrrCount = GetVariableMtrrCount (); + ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR); + + for (Index = 0; Index < VariableMtrrCount; Index++) { + if (VariableMtrr[Index].Valid) { + if (Address >= VariableMtrr[Index].BaseAddress && + Address < VariableMtrr[Index].BaseAddress+VariableMtrr[Index].Length) { + TempMtrrType = VariableMtrr[Index].Type; + MtrrType = MtrrPrecedence (MtrrType, TempMtrrType); + } + } } + CacheType = GetMemoryCacheTypeFromMtrrType (MtrrType); - // - // Check for overlap - // - UsedMtrr = MtrrGetMemoryAttributeInVariableMtrr (MtrrValidBitsMask, MtrrValidAddressMask, VariableMtrr); - OverLap = CheckMemoryAttributeOverlap (BaseAddress, BaseAddress + Length - 1, VariableMtrr); - if (OverLap) { + return CacheType; +} + + + +/** + This function prints all MTRRs for debugging. +**/ +VOID +EFIAPI +MtrrDebugPrintAllMtrrs ( + VOID + ) +{ + DEBUG_CODE ( + MTRR_SETTINGS MtrrSettings; + UINTN Index; + UINTN Index1; + UINTN VariableMtrrCount; + UINT64 Base; + UINT64 Limit; + UINT64 MtrrBase; + UINT64 MtrrLimit; + UINT64 RangeBase; + UINT64 RangeLimit; + UINT64 NoRangeBase; + UINT64 NoRangeLimit; + UINT32 RegEax; + UINTN MemoryType; + UINTN PreviousMemoryType; + BOOLEAN Found; + + if (!IsMtrrSupported ()) { + return; + } + + DEBUG((DEBUG_CACHE, "MTRR Settings\n")); + DEBUG((DEBUG_CACHE, "=============\n")); + + MtrrGetAllMtrrs (&MtrrSettings); + DEBUG((DEBUG_CACHE, "MTRR Default Type: %016lx\n", MtrrSettings.MtrrDefType)); + for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) { + DEBUG((DEBUG_CACHE, "Fixed MTRR[%02d] : %016lx\n", Index, MtrrSettings.Fixed.Mtrr[Index])); + } + + VariableMtrrCount = GetVariableMtrrCount (); + for (Index = 0; Index < VariableMtrrCount; Index++) { + DEBUG((DEBUG_CACHE, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n", + Index, + MtrrSettings.Variables.Mtrr[Index].Base, + MtrrSettings.Variables.Mtrr[Index].Mask + )); + } + DEBUG((DEBUG_CACHE, "\n")); + DEBUG((DEBUG_CACHE, "MTRR Ranges\n")); + DEBUG((DEBUG_CACHE, "====================================\n")); + + Base = 0; + PreviousMemoryType = MTRR_CACHE_INVALID_TYPE; + for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) { + Base = mMtrrLibFixedMtrrTable[Index].BaseAddress; + for (Index1 = 0; Index1 < 8; Index1++) { + MemoryType = (UINTN)(RShiftU64 (MtrrSettings.Fixed.Mtrr[Index], Index1 * 8) & 0xff); + if (MemoryType > CacheWriteBack) { + MemoryType = MTRR_CACHE_INVALID_TYPE; + } + if (MemoryType != PreviousMemoryType) { + if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) { + DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1)); + } + PreviousMemoryType = MemoryType; + DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base)); + } + Base += mMtrrLibFixedMtrrTable[Index].Length; + } + } + DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1)); + + VariableMtrrCount = GetVariableMtrrCount (); + + Limit = BIT36 - 1; + AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL); + if (RegEax >= 0x80000008) { + AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL); + Limit = LShiftU64 (1, RegEax & 0xff) - 1; + } + Base = BASE_1MB; + PreviousMemoryType = MTRR_CACHE_INVALID_TYPE; + do { + MemoryType = MtrrGetMemoryAttribute (Base); + if (MemoryType > CacheWriteBack) { + MemoryType = MTRR_CACHE_INVALID_TYPE; + } + + if (MemoryType != PreviousMemoryType) { + if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) { + DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1)); + } + PreviousMemoryType = MemoryType; + DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base)); + } + + RangeBase = BASE_1MB; + NoRangeBase = BASE_1MB; + RangeLimit = Limit; + NoRangeLimit = Limit; + + for (Index = 0, Found = FALSE; Index < VariableMtrrCount; Index++) { + if ((MtrrSettings.Variables.Mtrr[Index].Mask & BIT11) == 0) { + // + // If mask is not valid, then do not display range + // + continue; + } + MtrrBase = (MtrrSettings.Variables.Mtrr[Index].Base & (~(SIZE_4KB - 1))); + MtrrLimit = MtrrBase + ((~(MtrrSettings.Variables.Mtrr[Index].Mask & (~(SIZE_4KB - 1)))) & Limit); + + if (Base >= MtrrBase && Base < MtrrLimit) { + Found = TRUE; + } + + if (Base >= MtrrBase && MtrrBase > RangeBase) { + RangeBase = MtrrBase; + } + if (Base > MtrrLimit && MtrrLimit > RangeBase) { + RangeBase = MtrrLimit + 1; + } + if (Base < MtrrBase && MtrrBase < RangeLimit) { + RangeLimit = MtrrBase - 1; + } + if (Base < MtrrLimit && MtrrLimit <= RangeLimit) { + RangeLimit = MtrrLimit; + } + + if (Base > MtrrLimit && NoRangeBase < MtrrLimit) { + NoRangeBase = MtrrLimit + 1; + } + if (Base < MtrrBase && NoRangeLimit > MtrrBase) { + NoRangeLimit = MtrrBase - 1; + } + } + + if (Found) { + Base = RangeLimit + 1; + } else { + Base = NoRangeLimit + 1; + } + } while (Base < Limit); + DEBUG((DEBUG_CACHE, "%016lx\n\n", Base - 1)); + ); +} +/** + This function attempts to set the attributes for a memory range. + + @param[in] BaseAddress The physical address that is the start + address of a memory region. + @param[in] Length The size in bytes of the memory region. + @param[in] Attribute The bit mask of attributes to set for the + memory region. + + @retval RETURN_SUCCESS The attributes were set for the memory + region. + @retval RETURN_INVALID_PARAMETER Length is zero. + @retval RETURN_UNSUPPORTED The processor does not support one or + more bytes of the memory resource range + specified by BaseAddress and Length. + @retval RETURN_UNSUPPORTED The bit mask of attributes is not support + for the memory resource range specified + by BaseAddress and Length. + @retval RETURN_ACCESS_DENIED The attributes for the memory resource + range specified by BaseAddress and Length + cannot be modified. + @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to + modify the attributes of the memory + resource range. + +**/ +RETURN_STATUS +EFIAPI +MtrrSetMemoryAttribute ( + IN PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN MTRR_MEMORY_CACHE_TYPE Attribute + ) +{ + UINT64 TempQword; + RETURN_STATUS Status; + UINT64 MemoryType; + UINT64 Alignment; + BOOLEAN OverLap; + BOOLEAN Positive; + UINT32 MsrNum; + UINTN MtrrNumber; + VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR]; + UINT32 UsedMtrr; + UINT64 MtrrValidBitsMask; + UINT64 MtrrValidAddressMask; + BOOLEAN OverwriteExistingMtrr; + UINT32 FirmwareVariableMtrrCount; + UINT32 VariableMtrrEnd; + MTRR_CONTEXT MtrrContext; + + DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttribute() %a:%016lx-%016lx\n", mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, Length)); + + if (!IsMtrrSupported ()) { + Status = RETURN_UNSUPPORTED; + goto Done; + } + + FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount (); + VariableMtrrEnd = MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (2 * GetVariableMtrrCount ()) - 1; + + MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask); + + TempQword = 0; + MemoryType = (UINT64)Attribute; + OverwriteExistingMtrr = FALSE; + + // + // Check for an invalid parameter + // + if (Length == 0) { + Status = RETURN_INVALID_PARAMETER; + goto Done; + } + + if ( + (BaseAddress & ~MtrrValidAddressMask) != 0 || + (Length & ~MtrrValidAddressMask) != 0 + ) { + Status = RETURN_UNSUPPORTED; + goto Done; + } + + // + // Check if Fixed MTRR + // + Status = RETURN_SUCCESS; + while ((BaseAddress < BASE_1MB) && (Length > 0) && Status == RETURN_SUCCESS) { + PreMtrrChange (&MtrrContext); + Status = ProgramFixedMtrr (MemoryType, &BaseAddress, &Length); + PostMtrrChange (&MtrrContext); + if (RETURN_ERROR (Status)) { + goto Done; + } + } + + if (Length == 0) { + // + // A Length of 0 can only make sense for fixed MTTR ranges. + // Since we just handled the fixed MTRRs, we can skip the + // variable MTRR section. + // + goto Done; + } + + // + // Since memory ranges below 1MB will be overridden by the fixed MTRRs, + // we can set the base to 0 to save variable MTRRs. + // + if (BaseAddress == BASE_1MB) { + BaseAddress = 0; + Length += SIZE_1MB; + } + + // + // Check for overlap + // + UsedMtrr = MtrrGetMemoryAttributeInVariableMtrr (MtrrValidBitsMask, MtrrValidAddressMask, VariableMtrr); + OverLap = CheckMemoryAttributeOverlap (BaseAddress, BaseAddress + Length - 1, VariableMtrr); + if (OverLap) { Status = CombineMemoryAttribute (MemoryType, &BaseAddress, &Length, VariableMtrr, &UsedMtrr, &OverwriteExistingMtrr); if (RETURN_ERROR (Status)) { goto Done; @@ -1183,208 +1522,59 @@ MtrrSetMemoryAttribute ( for (; MsrNum < VariableMtrrEnd; MsrNum += 2) { if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) { break; - } - } - - ProgramVariableMtrr ( - MsrNum, - BaseAddress, - Length, - MemoryType, - MtrrValidAddressMask - ); - BaseAddress += Length; - TempQword = Length - TempQword; - MemoryType = MTRR_CACHE_UNCACHEABLE; - } - - do { - // - // Find unused MTRR - // - for (; MsrNum < VariableMtrrEnd; MsrNum += 2) { - if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) { - break; - } - } - - Length = Power2MaxMemory (TempQword); - if (!Positive) { - BaseAddress -= Length; - } - - ProgramVariableMtrr ( - MsrNum, - BaseAddress, - Length, - MemoryType, - MtrrValidAddressMask - ); - - if (Positive) { - BaseAddress += Length; - } - TempQword -= Length; - - } while (TempQword > 0); - -Done: - DEBUG((DEBUG_CACHE, " Status = %r\n", Status)); - if (!RETURN_ERROR (Status)) { - MtrrDebugPrintAllMtrrs (); - } - - return Status; -} - - -/** - This function will get the memory cache type of the specific address. - - This function is mainly for debug purpose. - - @param[in] Address The specific address - - @return Memory cache type of the specific address - -**/ -MTRR_MEMORY_CACHE_TYPE -EFIAPI -MtrrGetMemoryAttribute ( - IN PHYSICAL_ADDRESS Address - ) -{ - UINT64 TempQword; - UINTN Index; - UINTN SubIndex; - UINT64 MtrrType; - UINT64 TempMtrrType; - MTRR_MEMORY_CACHE_TYPE CacheType; - VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR]; - UINT64 MtrrValidBitsMask; - UINT64 MtrrValidAddressMask; - UINTN VariableMtrrCount; - - if (!IsMtrrSupported ()) { - return CacheUncacheable; - } - - // - // Check if MTRR is enabled, if not, return UC as attribute - // - TempQword = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE); - MtrrType = MTRR_CACHE_INVALID_TYPE; - - if ((TempQword & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) { - return CacheUncacheable; - } - - // - // If address is less than 1M, then try to go through the fixed MTRR - // - if (Address < BASE_1MB) { - if ((TempQword & MTRR_LIB_CACHE_FIXED_MTRR_ENABLED) != 0) { - // - // Go through the fixed MTRR - // - for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) { - if (Address >= mMtrrLibFixedMtrrTable[Index].BaseAddress && - Address < ( - mMtrrLibFixedMtrrTable[Index].BaseAddress + - (mMtrrLibFixedMtrrTable[Index].Length * 8) - ) - ) { - SubIndex = - ((UINTN)Address - mMtrrLibFixedMtrrTable[Index].BaseAddress) / - mMtrrLibFixedMtrrTable[Index].Length; - TempQword = AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr); - MtrrType = RShiftU64 (TempQword, SubIndex * 8) & 0xFF; - return GetMemoryCacheTypeFromMtrrType (MtrrType); - } - } - } - } - MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask); - MtrrGetMemoryAttributeInVariableMtrr( - MtrrValidBitsMask, - MtrrValidAddressMask, - VariableMtrr - ); - - // - // Go through the variable MTRR - // - VariableMtrrCount = GetVariableMtrrCount (); - ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR); - - for (Index = 0; Index < VariableMtrrCount; Index++) { - if (VariableMtrr[Index].Valid) { - if (Address >= VariableMtrr[Index].BaseAddress && - Address < VariableMtrr[Index].BaseAddress+VariableMtrr[Index].Length) { - TempMtrrType = VariableMtrr[Index].Type; - MtrrType = MtrrPrecedence (MtrrType, TempMtrrType); - } - } - } - CacheType = GetMemoryCacheTypeFromMtrrType (MtrrType); - - return CacheType; -} - - -/** - Worker function will get the raw value in variable MTRRs - - @param[out] VariableSettings A buffer to hold variable MTRRs content. - - @return The VariableSettings input pointer - -**/ -MTRR_VARIABLE_SETTINGS* -MtrrGetVariableMtrrWorker ( - OUT MTRR_VARIABLE_SETTINGS *VariableSettings - ) -{ - UINT32 Index; - UINT32 VariableMtrrCount; - - VariableMtrrCount = GetVariableMtrrCount (); - ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR); - - for (Index = 0; Index < VariableMtrrCount; Index++) { - VariableSettings->Mtrr[Index].Base = - AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1)); - VariableSettings->Mtrr[Index].Mask = - AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1); + } + } + + ProgramVariableMtrr ( + MsrNum, + BaseAddress, + Length, + MemoryType, + MtrrValidAddressMask + ); + BaseAddress += Length; + TempQword = Length - TempQword; + MemoryType = MTRR_CACHE_UNCACHEABLE; } - return VariableSettings; -} + do { + // + // Find unused MTRR + // + for (; MsrNum < VariableMtrrEnd; MsrNum += 2) { + if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) { + break; + } + } -/** - This function will get the raw value in variable MTRRs + Length = Power2MaxMemory (TempQword); + if (!Positive) { + BaseAddress -= Length; + } - @param[out] VariableSettings A buffer to hold variable MTRRs content. + ProgramVariableMtrr ( + MsrNum, + BaseAddress, + Length, + MemoryType, + MtrrValidAddressMask + ); - @return The VariableSettings input pointer + if (Positive) { + BaseAddress += Length; + } + TempQword -= Length; -**/ -MTRR_VARIABLE_SETTINGS* -EFIAPI -MtrrGetVariableMtrr ( - OUT MTRR_VARIABLE_SETTINGS *VariableSettings - ) -{ - if (!IsMtrrSupported ()) { - return VariableSettings; + } while (TempQword > 0); + +Done: + DEBUG((DEBUG_CACHE, " Status = %r\n", Status)); + if (!RETURN_ERROR (Status)) { + MtrrDebugPrintAllMtrrs (); } - return MtrrGetVariableMtrrWorker ( - VariableSettings - ); + return Status; } - - /** Worker function setting variable MTRRs @@ -1441,51 +1631,6 @@ MtrrSetVariableMtrr ( return VariableSettings; } -/** - Worker function gets the content in fixed MTRRs - - @param[out] FixedSettings A buffer to hold fixed MTRRs content. - - @retval The pointer of FixedSettings - -**/ -MTRR_FIXED_SETTINGS* -MtrrGetFixedMtrrWorker ( - OUT MTRR_FIXED_SETTINGS *FixedSettings - ) -{ - UINT32 Index; - - for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) { - FixedSettings->Mtrr[Index] = - AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr); - } - - return FixedSettings; -} - - -/** - This function gets the content in fixed MTRRs - - @param[out] FixedSettings A buffer to hold fixed MTRRs content. - - @retval The pointer of FixedSettings - -**/ -MTRR_FIXED_SETTINGS* -EFIAPI -MtrrGetFixedMtrr ( - OUT MTRR_FIXED_SETTINGS *FixedSettings - ) -{ - if (!IsMtrrSupported ()) { - return FixedSettings; - } - - return MtrrGetFixedMtrrWorker (FixedSettings); -} - /** Worker function setting fixed MTRRs @@ -1615,153 +1760,6 @@ MtrrSetAllMtrrs ( return MtrrSetting; } -/** - This function prints all MTRRs for debugging. -**/ -VOID -EFIAPI -MtrrDebugPrintAllMtrrs ( - VOID - ) -{ - DEBUG_CODE ( - MTRR_SETTINGS MtrrSettings; - UINTN Index; - UINTN Index1; - UINTN VariableMtrrCount; - UINT64 Base; - UINT64 Limit; - UINT64 MtrrBase; - UINT64 MtrrLimit; - UINT64 RangeBase; - UINT64 RangeLimit; - UINT64 NoRangeBase; - UINT64 NoRangeLimit; - UINT32 RegEax; - UINTN MemoryType; - UINTN PreviousMemoryType; - BOOLEAN Found; - - if (!IsMtrrSupported ()) { - return; - } - - DEBUG((DEBUG_CACHE, "MTRR Settings\n")); - DEBUG((DEBUG_CACHE, "=============\n")); - - MtrrGetAllMtrrs (&MtrrSettings); - DEBUG((DEBUG_CACHE, "MTRR Default Type: %016lx\n", MtrrSettings.MtrrDefType)); - for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) { - DEBUG((DEBUG_CACHE, "Fixed MTRR[%02d] : %016lx\n", Index, MtrrSettings.Fixed.Mtrr[Index])); - } - - VariableMtrrCount = GetVariableMtrrCount (); - for (Index = 0; Index < VariableMtrrCount; Index++) { - DEBUG((DEBUG_CACHE, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n", - Index, - MtrrSettings.Variables.Mtrr[Index].Base, - MtrrSettings.Variables.Mtrr[Index].Mask - )); - } - DEBUG((DEBUG_CACHE, "\n")); - DEBUG((DEBUG_CACHE, "MTRR Ranges\n")); - DEBUG((DEBUG_CACHE, "====================================\n")); - - Base = 0; - PreviousMemoryType = MTRR_CACHE_INVALID_TYPE; - for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) { - Base = mMtrrLibFixedMtrrTable[Index].BaseAddress; - for (Index1 = 0; Index1 < 8; Index1++) { - MemoryType = (UINTN)(RShiftU64 (MtrrSettings.Fixed.Mtrr[Index], Index1 * 8) & 0xff); - if (MemoryType > CacheWriteBack) { - MemoryType = MTRR_CACHE_INVALID_TYPE; - } - if (MemoryType != PreviousMemoryType) { - if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) { - DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1)); - } - PreviousMemoryType = MemoryType; - DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base)); - } - Base += mMtrrLibFixedMtrrTable[Index].Length; - } - } - DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1)); - - VariableMtrrCount = GetVariableMtrrCount (); - - Limit = BIT36 - 1; - AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL); - if (RegEax >= 0x80000008) { - AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL); - Limit = LShiftU64 (1, RegEax & 0xff) - 1; - } - Base = BASE_1MB; - PreviousMemoryType = MTRR_CACHE_INVALID_TYPE; - do { - MemoryType = MtrrGetMemoryAttribute (Base); - if (MemoryType > CacheWriteBack) { - MemoryType = MTRR_CACHE_INVALID_TYPE; - } - - if (MemoryType != PreviousMemoryType) { - if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) { - DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1)); - } - PreviousMemoryType = MemoryType; - DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base)); - } - - RangeBase = BASE_1MB; - NoRangeBase = BASE_1MB; - RangeLimit = Limit; - NoRangeLimit = Limit; - - for (Index = 0, Found = FALSE; Index < VariableMtrrCount; Index++) { - if ((MtrrSettings.Variables.Mtrr[Index].Mask & BIT11) == 0) { - // - // If mask is not valid, then do not display range - // - continue; - } - MtrrBase = (MtrrSettings.Variables.Mtrr[Index].Base & (~(SIZE_4KB - 1))); - MtrrLimit = MtrrBase + ((~(MtrrSettings.Variables.Mtrr[Index].Mask & (~(SIZE_4KB - 1)))) & Limit); - - if (Base >= MtrrBase && Base < MtrrLimit) { - Found = TRUE; - } - - if (Base >= MtrrBase && MtrrBase > RangeBase) { - RangeBase = MtrrBase; - } - if (Base > MtrrLimit && MtrrLimit > RangeBase) { - RangeBase = MtrrLimit + 1; - } - if (Base < MtrrBase && MtrrBase < RangeLimit) { - RangeLimit = MtrrBase - 1; - } - if (Base < MtrrLimit && MtrrLimit <= RangeLimit) { - RangeLimit = MtrrLimit; - } - - if (Base > MtrrLimit && NoRangeBase < MtrrLimit) { - NoRangeBase = MtrrLimit + 1; - } - if (Base < MtrrBase && NoRangeLimit > MtrrBase) { - NoRangeLimit = MtrrBase - 1; - } - } - - if (Found) { - Base = RangeLimit + 1; - } else { - Base = NoRangeLimit + 1; - } - } while (Base < Limit); - DEBUG((DEBUG_CACHE, "%016lx\n\n", Base - 1)); - ); -} - /** Checks if MTRR is supported. From de8926accb5d751ab88a73252c377be0b42ef3e7 Mon Sep 17 00:00:00 2001 From: Michael Kinney Date: Thu, 10 Dec 2015 07:23:53 +0000 Subject: [PATCH 221/525] UefiCpuPkg/MtrrLib: Make use of worker functions to get MTRRs count Try to make use of worker functions to get MTRRs count. It could avoid invoking IsMtrrSupported() for many times. (Sync patch r19155 from main trunk.) Cc: Feng Tian Cc: Michael Kinney Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Michael Kinney Signed-off-by: Jeff Fan Reviewed-by: Feng Tian git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19199 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/Library/MtrrLib/MtrrLib.c | 76 +++++++++++++++++++--------- 1 file changed, 51 insertions(+), 25 deletions(-) diff --git a/UefiCpuPkg/Library/MtrrLib/MtrrLib.c b/UefiCpuPkg/Library/MtrrLib/MtrrLib.c index ea2b211e0580..0358fffb28a2 100644 --- a/UefiCpuPkg/Library/MtrrLib/MtrrLib.c +++ b/UefiCpuPkg/Library/MtrrLib/MtrrLib.c @@ -367,13 +367,12 @@ MtrrGetFixedMtrr ( **/ MTRR_VARIABLE_SETTINGS* MtrrGetVariableMtrrWorker ( + IN UINT32 VariableMtrrCount, OUT MTRR_VARIABLE_SETTINGS *VariableSettings ) { UINT32 Index; - UINT32 VariableMtrrCount; - VariableMtrrCount = GetVariableMtrrCount (); ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR); for (Index = 0; Index < VariableMtrrCount; Index++) { @@ -405,6 +404,7 @@ MtrrGetVariableMtrr ( } return MtrrGetVariableMtrrWorker ( + GetVariableMtrrCountWorker (), VariableSettings ); } @@ -527,7 +527,7 @@ MtrrGetMemoryAttributeInVariableMtrr ( return 0; } - FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount (); + FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCountWorker (); VariableMtrrEnd = MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (2 * GetVariableMtrrCount ()) - 1; ZeroMem (VariableMtrr, sizeof (VARIABLE_MTRR) * MTRR_NUMBER_OF_VARIABLE_MTRR); @@ -563,6 +563,8 @@ MtrrGetMemoryAttributeInVariableMtrr ( /** Checks overlap between given memory range and MTRRs. + @param[in] FirmwareVariableMtrrCount The number of variable MTRRs available + to firmware. @param[in] Start The start address of memory range. @param[in] End The end address of memory range. @param[in] VariableMtrr The array to shadow variable MTRRs content @@ -573,14 +575,15 @@ MtrrGetMemoryAttributeInVariableMtrr ( **/ BOOLEAN CheckMemoryAttributeOverlap ( - IN PHYSICAL_ADDRESS Start, - IN PHYSICAL_ADDRESS End, - IN VARIABLE_MTRR *VariableMtrr + IN UINTN FirmwareVariableMtrrCount, + IN PHYSICAL_ADDRESS Start, + IN PHYSICAL_ADDRESS End, + IN VARIABLE_MTRR *VariableMtrr ) { UINT32 Index; - for (Index = 0; Index < 6; Index++) { + for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) { if ( VariableMtrr[Index].Valid && !( @@ -623,6 +626,8 @@ InvalidateShadowMtrr ( If overlap exists between given memory range and MTRRs, try to combine them. + @param[in] FirmwareVariableMtrrCount The number of variable MTRRs + available to firmware. @param[in] Attributes The memory type to set. @param[in, out] Base The base address of memory range. @param[in, out] Length The length of memory range. @@ -636,6 +641,7 @@ InvalidateShadowMtrr ( **/ RETURN_STATUS CombineMemoryAttribute ( + IN UINT32 FirmwareVariableMtrrCount, IN UINT64 Attributes, IN OUT UINT64 *Base, IN OUT UINT64 *Length, @@ -649,11 +655,8 @@ CombineMemoryAttribute ( UINT64 CombineEnd; UINT64 MtrrEnd; UINT64 EndAddress; - UINT32 FirmwareVariableMtrrCount; BOOLEAN CoveredByExistingMtrr; - FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount (); - *OverwriteExistingMtrr = FALSE; CoveredByExistingMtrr = FALSE; EndAddress = *Base +*Length - 1; @@ -851,21 +854,21 @@ GetMtrrNumberAndDirection ( This function programs MTRRs according to the values specified in the shadow array. + @param[in] VariableMtrrCount Number of variable MTRRs @param[in, out] VariableMtrr Shadow of variable MTRR contents **/ VOID InvalidateMtrr ( + IN UINTN VariableMtrrCount, IN OUT VARIABLE_MTRR *VariableMtrr ) { UINTN Index; - UINTN VariableMtrrCount; MTRR_CONTEXT MtrrContext; PreMtrrChange (&MtrrContext); Index = 0; - VariableMtrrCount = GetVariableMtrrCount (); while (Index < VariableMtrrCount) { if (!VariableMtrr[Index].Valid && VariableMtrr[Index].Used) { AsmWriteMsr64 (VariableMtrr[Index].Msr, 0); @@ -1139,7 +1142,7 @@ MtrrGetMemoryAttribute ( // // Go through the variable MTRR // - VariableMtrrCount = GetVariableMtrrCount (); + VariableMtrrCount = GetVariableMtrrCountWorker (); ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR); for (Index = 0; Index < VariableMtrrCount; Index++) { @@ -1354,6 +1357,7 @@ MtrrSetMemoryAttribute ( UINT32 FirmwareVariableMtrrCount; UINT32 VariableMtrrEnd; MTRR_CONTEXT MtrrContext; + UINT32 VariableMtrrCount; DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttribute() %a:%016lx-%016lx\n", mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, Length)); @@ -1362,7 +1366,7 @@ MtrrSetMemoryAttribute ( goto Done; } - FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount (); + FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCountWorker (); VariableMtrrEnd = MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (2 * GetVariableMtrrCount ()) - 1; MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask); @@ -1418,13 +1422,32 @@ MtrrSetMemoryAttribute ( Length += SIZE_1MB; } + // + // Read all variable MTRRs + // + VariableMtrrCount = GetVariableMtrrCountWorker (); + // // Check for overlap // UsedMtrr = MtrrGetMemoryAttributeInVariableMtrr (MtrrValidBitsMask, MtrrValidAddressMask, VariableMtrr); - OverLap = CheckMemoryAttributeOverlap (BaseAddress, BaseAddress + Length - 1, VariableMtrr); + OverLap = CheckMemoryAttributeOverlap ( + FirmwareVariableMtrrCount, + BaseAddress, + BaseAddress + Length - 1, + VariableMtrr + ); + if (OverLap) { - Status = CombineMemoryAttribute (MemoryType, &BaseAddress, &Length, VariableMtrr, &UsedMtrr, &OverwriteExistingMtrr); + Status = CombineMemoryAttribute ( + FirmwareVariableMtrrCount, + MemoryType, + &BaseAddress, + &Length, + VariableMtrr, + &UsedMtrr, + &OverwriteExistingMtrr + ); if (RETURN_ERROR (Status)) { goto Done; } @@ -1433,7 +1456,7 @@ MtrrSetMemoryAttribute ( // // Combined successfully, invalidate the now-unused MTRRs // - InvalidateMtrr(VariableMtrr); + InvalidateMtrr(VariableMtrrCount, VariableMtrr); Status = RETURN_SUCCESS; goto Done; } @@ -1447,7 +1470,7 @@ MtrrSetMemoryAttribute ( // // Invalidate the now-unused MTRRs // - InvalidateMtrr(VariableMtrr); + InvalidateMtrr(VariableMtrrCount, VariableMtrr); goto Done; } @@ -1461,7 +1484,7 @@ MtrrSetMemoryAttribute ( // // Invalidate the now-unused MTRRs // - InvalidateMtrr(VariableMtrr); + InvalidateMtrr(VariableMtrrCount, VariableMtrr); // // Find first unused MTRR @@ -1589,7 +1612,7 @@ MtrrSetVariableMtrrWorker ( UINT32 Index; UINT32 VariableMtrrCount; - VariableMtrrCount = GetVariableMtrrCount (); + VariableMtrrCount = GetVariableMtrrCountWorker (); ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR); for (Index = 0; Index < VariableMtrrCount; Index++) { @@ -1634,7 +1657,7 @@ MtrrSetVariableMtrr ( /** Worker function setting fixed MTRRs - @param[in] FixedSettings A buffer to hold fixed Mtrrs content. + @param[in] FixedSettings A buffer to hold fixed MTRRs content. **/ VOID @@ -1656,7 +1679,7 @@ MtrrSetFixedMtrrWorker ( /** This function sets fixed MTRRs - @param[in] FixedSettings A buffer to hold fixed Mtrrs content. + @param[in] FixedSettings A buffer to hold fixed MTRRs content. @retval The pointer of FixedSettings @@ -1684,7 +1707,7 @@ MtrrSetFixedMtrr ( /** This function gets the content in all MTRRs (variable and fixed) - @param[out] MtrrSetting A buffer to hold all Mtrrs content. + @param[out] MtrrSetting A buffer to hold all MTRRs content. @retval the pointer of MtrrSetting @@ -1702,12 +1725,15 @@ MtrrGetAllMtrrs ( // // Get fixed MTRRs // - MtrrGetFixedMtrr (&MtrrSetting->Fixed); + MtrrGetFixedMtrrWorker (&MtrrSetting->Fixed); // // Get variable MTRRs // - MtrrGetVariableMtrr (&MtrrSetting->Variables); + MtrrGetVariableMtrrWorker ( + GetVariableMtrrCountWorker (), + &MtrrSetting->Variables + ); // // Get MTRR_DEF_TYPE value From 58672619a3f1cf4c022d4c0c3c1cca071f70fc85 Mon Sep 17 00:00:00 2001 From: Michael Kinney Date: Thu, 10 Dec 2015 07:24:19 +0000 Subject: [PATCH 222/525] UefiCpuPkg/MtrrLib: Add MtrrGetMemoryAttributeInVariableMtrrWorker () Add function to shadow the content of variable MTRRs into an internal array: VariableMtrr. And used MtrrGetMemoryAttributeInVariableMtrrWorker() in other functions. (Sync patch r19156 from main trunk.) Cc: Feng Tian Cc: Michael Kinney Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Michael Kinney Signed-off-by: Jeff Fan Reviewed-by: Feng Tian git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19200 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/Library/MtrrLib/MtrrLib.c | 121 ++++++++++++++++++--------- 1 file changed, 82 insertions(+), 39 deletions(-) diff --git a/UefiCpuPkg/Library/MtrrLib/MtrrLib.c b/UefiCpuPkg/Library/MtrrLib/MtrrLib.c index 0358fffb28a2..697dc4352f61 100644 --- a/UefiCpuPkg/Library/MtrrLib/MtrrLib.c +++ b/UefiCpuPkg/Library/MtrrLib/MtrrLib.c @@ -495,6 +495,50 @@ ProgramFixedMtrr ( } +/** + Worker function gets the attribute of variable MTRRs. + + This function shadows the content of variable MTRRs into an + internal array: VariableMtrr. + + @param[in] VariableSettings The variable MTRR values to shadow + @param[in] FirmwareVariableMtrrCount The number of variable MTRRs available to firmware + @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR + @param[in] MtrrValidAddressMask The valid address mask for MTRR + @param[out] VariableMtrr The array to shadow variable MTRRs content + + @return The return value of this parameter indicates the + number of MTRRs which has been used. + +**/ +UINT32 +MtrrGetMemoryAttributeInVariableMtrrWorker ( + IN MTRR_VARIABLE_SETTINGS *VariableSettings, + IN UINTN FirmwareVariableMtrrCount, + IN UINT64 MtrrValidBitsMask, + IN UINT64 MtrrValidAddressMask, + OUT VARIABLE_MTRR *VariableMtrr + ) +{ + UINTN Index; + UINT32 UsedMtrr; + + ZeroMem (VariableMtrr, sizeof (VARIABLE_MTRR) * MTRR_NUMBER_OF_VARIABLE_MTRR); + for (Index = 0, UsedMtrr = 0; Index < FirmwareVariableMtrrCount; Index++) { + if ((VariableSettings->Mtrr[Index].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) != 0) { + VariableMtrr[Index].Msr = (UINT32)Index; + VariableMtrr[Index].BaseAddress = (VariableSettings->Mtrr[Index].Base & MtrrValidAddressMask); + VariableMtrr[Index].Length = ((~(VariableSettings->Mtrr[Index].Mask & MtrrValidAddressMask)) & MtrrValidBitsMask) + 1; + VariableMtrr[Index].Type = (VariableSettings->Mtrr[Index].Base & 0x0ff); + VariableMtrr[Index].Valid = TRUE; + VariableMtrr[Index].Used = TRUE; + UsedMtrr++; + } + } + return UsedMtrr; +} + + /** Gets the attribute of variable MTRRs. @@ -517,46 +561,24 @@ MtrrGetMemoryAttributeInVariableMtrr ( OUT VARIABLE_MTRR *VariableMtrr ) { - UINTN Index; - UINT32 MsrNum; - UINT32 UsedMtrr; - UINT32 FirmwareVariableMtrrCount; - UINT32 VariableMtrrEnd; + MTRR_VARIABLE_SETTINGS VariableSettings; if (!IsMtrrSupported ()) { return 0; } - FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCountWorker (); - VariableMtrrEnd = MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (2 * GetVariableMtrrCount ()) - 1; - - ZeroMem (VariableMtrr, sizeof (VARIABLE_MTRR) * MTRR_NUMBER_OF_VARIABLE_MTRR); - UsedMtrr = 0; + MtrrGetVariableMtrrWorker ( + GetVariableMtrrCountWorker (), + &VariableSettings + ); - for (MsrNum = MTRR_LIB_IA32_VARIABLE_MTRR_BASE, Index = 0; - ( - (MsrNum < VariableMtrrEnd) && - (Index < FirmwareVariableMtrrCount) - ); - MsrNum += 2 - ) { - if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) != 0) { - VariableMtrr[Index].Msr = MsrNum; - VariableMtrr[Index].BaseAddress = (AsmReadMsr64 (MsrNum) & - MtrrValidAddressMask); - VariableMtrr[Index].Length = ((~(AsmReadMsr64 (MsrNum + 1) & - MtrrValidAddressMask) - ) & - MtrrValidBitsMask - ) + 1; - VariableMtrr[Index].Type = (AsmReadMsr64 (MsrNum) & 0x0ff); - VariableMtrr[Index].Valid = TRUE; - VariableMtrr[Index].Used = TRUE; - UsedMtrr = UsedMtrr + 1; - Index++; - } - } - return UsedMtrr; + return MtrrGetMemoryAttributeInVariableMtrrWorker ( + &VariableSettings, + GetFirmwareVariableMtrrCountWorker (), + MtrrValidBitsMask, + MtrrValidAddressMask, + VariableMtrr + ); } @@ -1092,6 +1114,7 @@ MtrrGetMemoryAttribute ( UINT64 MtrrValidBitsMask; UINT64 MtrrValidAddressMask; UINTN VariableMtrrCount; + MTRR_VARIABLE_SETTINGS VariableSettings; if (!IsMtrrSupported ()) { return CacheUncacheable; @@ -1133,12 +1156,20 @@ MtrrGetMemoryAttribute ( } } MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask); - MtrrGetMemoryAttributeInVariableMtrr( - MtrrValidBitsMask, - MtrrValidAddressMask, - VariableMtrr + + MtrrGetVariableMtrrWorker ( + GetVariableMtrrCountWorker (), + &VariableSettings ); + MtrrGetMemoryAttributeInVariableMtrrWorker ( + &VariableSettings, + GetFirmwareVariableMtrrCountWorker (), + MtrrValidBitsMask, + MtrrValidAddressMask, + VariableMtrr + ); + // // Go through the variable MTRR // @@ -1358,6 +1389,9 @@ MtrrSetMemoryAttribute ( UINT32 VariableMtrrEnd; MTRR_CONTEXT MtrrContext; UINT32 VariableMtrrCount; + MTRR_VARIABLE_SETTINGS OriginalVariableSettings; + MTRR_VARIABLE_SETTINGS WorkingVariableSettings; + MTRR_VARIABLE_SETTINGS *VariableSettings; DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttribute() %a:%016lx-%016lx\n", mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, Length)); @@ -1426,11 +1460,20 @@ MtrrSetMemoryAttribute ( // Read all variable MTRRs // VariableMtrrCount = GetVariableMtrrCountWorker (); + MtrrGetVariableMtrrWorker (VariableMtrrCount, &OriginalVariableSettings); + CopyMem (&WorkingVariableSettings, &OriginalVariableSettings, sizeof (WorkingVariableSettings)); + VariableSettings = &WorkingVariableSettings; // // Check for overlap // - UsedMtrr = MtrrGetMemoryAttributeInVariableMtrr (MtrrValidBitsMask, MtrrValidAddressMask, VariableMtrr); + UsedMtrr = MtrrGetMemoryAttributeInVariableMtrrWorker ( + VariableSettings, + FirmwareVariableMtrrCount, + MtrrValidBitsMask, + MtrrValidAddressMask, + VariableMtrr + ); OverLap = CheckMemoryAttributeOverlap ( FirmwareVariableMtrrCount, BaseAddress, From d4ac50dfffbccd5fe608de084be489c7b45d93eb Mon Sep 17 00:00:00 2001 From: Michael Kinney Date: Thu, 10 Dec 2015 07:24:56 +0000 Subject: [PATCH 223/525] UefiCpuPkg/MtrrLib: Reduce hardware init when program fixed MTRRs When MtrrSetMemoryAttribute() programs fixed MTRRs, it may disable/enable cache and disable/enable MTRRs several times. This updating tries to do operation in local variable and does the hardware initialization one time only. (Sync patch r19157 from main trunk.) Cc: Feng Tian Cc: Michael Kinney Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Michael Kinney Signed-off-by: Jeff Fan Reviewed-by: Feng Tian git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19201 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/Library/MtrrLib/MtrrLib.c | 90 +++++++++++++++++++++------- 1 file changed, 70 insertions(+), 20 deletions(-) diff --git a/UefiCpuPkg/Library/MtrrLib/MtrrLib.c b/UefiCpuPkg/Library/MtrrLib/MtrrLib.c index 697dc4352f61..322f47b0976c 100644 --- a/UefiCpuPkg/Library/MtrrLib/MtrrLib.c +++ b/UefiCpuPkg/Library/MtrrLib/MtrrLib.c @@ -415,6 +415,9 @@ MtrrGetVariableMtrr ( @param[in] MemoryCacheType The memory type to set. @param[in, out] Base The base address of memory range. @param[in, out] Length The length of memory range. + @param[out] ReturnMsrNum The index of the fixed MTRR MSR to program. + @param[out] ReturnClearMask The bits to clear in the fixed MTRR MSR. + @param[out] ReturnOrMask The bits to set in the fixed MTRR MSR. @retval RETURN_SUCCESS The cache type was updated successfully @retval RETURN_UNSUPPORTED The requested range or cache type was invalid @@ -423,9 +426,12 @@ MtrrGetVariableMtrr ( **/ RETURN_STATUS ProgramFixedMtrr ( - IN UINT64 MemoryCacheType, - IN OUT UINT64 *Base, - IN OUT UINT64 *Length + IN UINT64 MemoryCacheType, + IN OUT UINT64 *Base, + IN OUT UINT64 *Length, + OUT UINT32 *ReturnMsrNum, + OUT UINT64 *ReturnClearMask, + OUT UINT64 *ReturnOrMask ) { UINT32 MsrNum; @@ -488,9 +494,10 @@ ProgramFixedMtrr ( return RETURN_UNSUPPORTED; } - TempQword = - (AsmReadMsr64 (mMtrrLibFixedMtrrTable[MsrNum].Msr) & ~ClearMask) | OrMask; - AsmWriteMsr64 (mMtrrLibFixedMtrrTable[MsrNum].Msr, TempQword); + *ReturnMsrNum = MsrNum; + *ReturnClearMask = ClearMask; + *ReturnOrMask = OrMask; + return RETURN_SUCCESS; } @@ -1388,12 +1395,25 @@ MtrrSetMemoryAttribute ( UINT32 FirmwareVariableMtrrCount; UINT32 VariableMtrrEnd; MTRR_CONTEXT MtrrContext; + BOOLEAN MtrrContextValid; + BOOLEAN FixedSettingsValid[MTRR_NUMBER_OF_FIXED_MTRR]; + BOOLEAN FixedSettingsModified[MTRR_NUMBER_OF_FIXED_MTRR]; + MTRR_FIXED_SETTINGS WorkingFixedSettings; UINT32 VariableMtrrCount; MTRR_VARIABLE_SETTINGS OriginalVariableSettings; MTRR_VARIABLE_SETTINGS WorkingVariableSettings; + UINT32 Index; + UINT64 ClearMask; + UINT64 OrMask; + UINT64 NewValue; MTRR_VARIABLE_SETTINGS *VariableSettings; DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttribute() %a:%016lx-%016lx\n", mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, Length)); + MtrrContextValid = FALSE; + for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) { + FixedSettingsValid[Index] = FALSE; + FixedSettingsModified[Index] = FALSE; + } if (!IsMtrrSupported ()) { Status = RETURN_UNSUPPORTED; @@ -1429,22 +1449,31 @@ MtrrSetMemoryAttribute ( // Check if Fixed MTRR // Status = RETURN_SUCCESS; - while ((BaseAddress < BASE_1MB) && (Length > 0) && Status == RETURN_SUCCESS) { - PreMtrrChange (&MtrrContext); - Status = ProgramFixedMtrr (MemoryType, &BaseAddress, &Length); - PostMtrrChange (&MtrrContext); - if (RETURN_ERROR (Status)) { - goto Done; + if (BaseAddress < BASE_1MB) { + while ((BaseAddress < BASE_1MB) && (Length > 0) && Status == RETURN_SUCCESS) { + Status = ProgramFixedMtrr (MemoryType, &BaseAddress, &Length, &MsrNum, &ClearMask, &OrMask); + if (RETURN_ERROR (Status)) { + goto Done; + } + if (!FixedSettingsValid[MsrNum]) { + WorkingFixedSettings.Mtrr[MsrNum] = AsmReadMsr64 (mMtrrLibFixedMtrrTable[MsrNum].Msr); + FixedSettingsValid[MsrNum] = TRUE; + } + NewValue = (WorkingFixedSettings.Mtrr[MsrNum] & ~ClearMask) | OrMask; + if (WorkingFixedSettings.Mtrr[MsrNum] != NewValue) { + WorkingFixedSettings.Mtrr[MsrNum] = NewValue; + FixedSettingsModified[MsrNum] = TRUE; + } } - } - if (Length == 0) { - // - // A Length of 0 can only make sense for fixed MTTR ranges. - // Since we just handled the fixed MTRRs, we can skip the - // variable MTRR section. - // - goto Done; + if (Length == 0) { + // + // A Length of 0 can only make sense for fixed MTTR ranges. + // Since we just handled the fixed MTRRs, we can skip the + // variable MTRR section. + // + goto Done; + } } // @@ -1634,6 +1663,27 @@ MtrrSetMemoryAttribute ( } while (TempQword > 0); Done: + + // + // Write fixed MTRRs that have been modified + // + for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) { + if (FixedSettingsModified[Index]) { + if (!MtrrContextValid) { + PreMtrrChange (&MtrrContext); + MtrrContextValid = TRUE; + } + AsmWriteMsr64 ( + mMtrrLibFixedMtrrTable[Index].Msr, + WorkingFixedSettings.Mtrr[Index] + ); + } + } + + if (MtrrContextValid) { + PostMtrrChange (&MtrrContext); + } + DEBUG((DEBUG_CACHE, " Status = %r\n", Status)); if (!RETURN_ERROR (Status)) { MtrrDebugPrintAllMtrrs (); From bf4f151df461b4b840600d7ea75736a065618be0 Mon Sep 17 00:00:00 2001 From: Michael Kinney Date: Thu, 10 Dec 2015 07:25:24 +0000 Subject: [PATCH 224/525] UefiCpuPkg/MtrrLib: Reduce hardware init when program variable MTRRs When MtrrSetMemoryAttribute() programs variable MTRRs, it may disable/enable cache and disable/enable MTRRs several times. This updating tries to do operation in local variable and does the hardware initialization one time only. (Sync patch r19158 from main trunk.) Cc: Feng Tian Cc: Michael Kinney Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Michael Kinney Signed-off-by: Jeff Fan Reviewed-by: Feng Tian git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19202 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/Library/MtrrLib/MtrrLib.c | 98 ++++++++++++++++------------ 1 file changed, 55 insertions(+), 43 deletions(-) diff --git a/UefiCpuPkg/Library/MtrrLib/MtrrLib.c b/UefiCpuPkg/Library/MtrrLib/MtrrLib.c index 322f47b0976c..0e76e2f92ad5 100644 --- a/UefiCpuPkg/Library/MtrrLib/MtrrLib.c +++ b/UefiCpuPkg/Library/MtrrLib/MtrrLib.c @@ -883,30 +883,27 @@ GetMtrrNumberAndDirection ( This function programs MTRRs according to the values specified in the shadow array. + @param[in, out] VariableSettings Variable MTRR settings @param[in] VariableMtrrCount Number of variable MTRRs @param[in, out] VariableMtrr Shadow of variable MTRR contents **/ VOID InvalidateMtrr ( + IN OUT MTRR_VARIABLE_SETTINGS *VariableSettings, IN UINTN VariableMtrrCount, IN OUT VARIABLE_MTRR *VariableMtrr ) { UINTN Index; - MTRR_CONTEXT MtrrContext; - PreMtrrChange (&MtrrContext); - Index = 0; - while (Index < VariableMtrrCount) { + for (Index = 0; Index < VariableMtrrCount; Index++) { if (!VariableMtrr[Index].Valid && VariableMtrr[Index].Used) { - AsmWriteMsr64 (VariableMtrr[Index].Msr, 0); - AsmWriteMsr64 (VariableMtrr[Index].Msr + 1, 0); + VariableSettings->Mtrr[Index].Base = 0; + VariableSettings->Mtrr[Index].Mask = 0; VariableMtrr[Index].Used = FALSE; } - Index ++; } - PostMtrrChange (&MtrrContext); } @@ -915,6 +912,7 @@ InvalidateMtrr ( This function programs variable MTRRs + @param[in, out] VariableSettings Variable MTRR settings. @param[in] MtrrNumber Index of MTRR to program. @param[in] BaseAddress Base address of memory region. @param[in] Length Length of memory region. @@ -924,34 +922,27 @@ InvalidateMtrr ( **/ VOID ProgramVariableMtrr ( - IN UINTN MtrrNumber, - IN PHYSICAL_ADDRESS BaseAddress, - IN UINT64 Length, - IN UINT64 MemoryCacheType, - IN UINT64 MtrrValidAddressMask + IN OUT MTRR_VARIABLE_SETTINGS *VariableSettings, + IN UINTN MtrrNumber, + IN PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN UINT64 MemoryCacheType, + IN UINT64 MtrrValidAddressMask ) { UINT64 TempQword; - MTRR_CONTEXT MtrrContext; - - PreMtrrChange (&MtrrContext); // // MTRR Physical Base // TempQword = (BaseAddress & MtrrValidAddressMask) | MemoryCacheType; - AsmWriteMsr64 ((UINT32) MtrrNumber, TempQword); + VariableSettings->Mtrr[MtrrNumber].Base = TempQword; // // MTRR Physical Mask // TempQword = ~(Length - 1); - AsmWriteMsr64 ( - (UINT32) (MtrrNumber + 1), - (TempQword & MtrrValidAddressMask) | MTRR_LIB_CACHE_MTRR_ENABLED - ); - - PostMtrrChange (&MtrrContext); + VariableSettings->Mtrr[MtrrNumber].Mask = (TempQword & MtrrValidAddressMask) | MTRR_LIB_CACHE_MTRR_ENABLED; } @@ -1393,7 +1384,6 @@ MtrrSetMemoryAttribute ( UINT64 MtrrValidAddressMask; BOOLEAN OverwriteExistingMtrr; UINT32 FirmwareVariableMtrrCount; - UINT32 VariableMtrrEnd; MTRR_CONTEXT MtrrContext; BOOLEAN MtrrContextValid; BOOLEAN FixedSettingsValid[MTRR_NUMBER_OF_FIXED_MTRR]; @@ -1401,6 +1391,7 @@ MtrrSetMemoryAttribute ( MTRR_FIXED_SETTINGS WorkingFixedSettings; UINT32 VariableMtrrCount; MTRR_VARIABLE_SETTINGS OriginalVariableSettings; + BOOLEAN ProgramVariableSettings; MTRR_VARIABLE_SETTINGS WorkingVariableSettings; UINT32 Index; UINT64 ClearMask; @@ -1414,16 +1405,14 @@ MtrrSetMemoryAttribute ( FixedSettingsValid[Index] = FALSE; FixedSettingsModified[Index] = FALSE; } + ProgramVariableSettings = FALSE; if (!IsMtrrSupported ()) { Status = RETURN_UNSUPPORTED; goto Done; } - FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCountWorker (); - VariableMtrrEnd = MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (2 * GetVariableMtrrCount ()) - 1; - - MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask); + MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask); TempQword = 0; MemoryType = (UINT64)Attribute; @@ -1489,8 +1478,10 @@ MtrrSetMemoryAttribute ( // Read all variable MTRRs // VariableMtrrCount = GetVariableMtrrCountWorker (); + FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCountWorker (); MtrrGetVariableMtrrWorker (VariableMtrrCount, &OriginalVariableSettings); CopyMem (&WorkingVariableSettings, &OriginalVariableSettings, sizeof (WorkingVariableSettings)); + ProgramVariableSettings = TRUE; VariableSettings = &WorkingVariableSettings; // @@ -1509,7 +1500,6 @@ MtrrSetMemoryAttribute ( BaseAddress + Length - 1, VariableMtrr ); - if (OverLap) { Status = CombineMemoryAttribute ( FirmwareVariableMtrrCount, @@ -1528,7 +1518,7 @@ MtrrSetMemoryAttribute ( // // Combined successfully, invalidate the now-unused MTRRs // - InvalidateMtrr(VariableMtrrCount, VariableMtrr); + InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr); Status = RETURN_SUCCESS; goto Done; } @@ -1542,7 +1532,7 @@ MtrrSetMemoryAttribute ( // // Invalidate the now-unused MTRRs // - InvalidateMtrr(VariableMtrrCount, VariableMtrr); + InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr); goto Done; } @@ -1556,16 +1546,13 @@ MtrrSetMemoryAttribute ( // // Invalidate the now-unused MTRRs // - InvalidateMtrr(VariableMtrrCount, VariableMtrr); + InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr); // // Find first unused MTRR // - for (MsrNum = MTRR_LIB_IA32_VARIABLE_MTRR_BASE; - MsrNum < VariableMtrrEnd; - MsrNum += 2 - ) { - if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) { + for (MsrNum = 0; MsrNum < VariableMtrrCount; MsrNum++) { + if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) { break; } } @@ -1584,13 +1571,14 @@ MtrrSetMemoryAttribute ( // // Find unused MTRR // - for (; MsrNum < VariableMtrrEnd; MsrNum += 2) { - if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) { + for (; MsrNum < VariableMtrrCount; MsrNum++) { + if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) { break; } } ProgramVariableMtrr ( + VariableSettings, MsrNum, BaseAddress, Alignment, @@ -1614,13 +1602,14 @@ MtrrSetMemoryAttribute ( // // Find unused MTRR // - for (; MsrNum < VariableMtrrEnd; MsrNum += 2) { - if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) { + for (; MsrNum < VariableMtrrCount; MsrNum++) { + if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) { break; } } ProgramVariableMtrr ( + VariableSettings, MsrNum, BaseAddress, Length, @@ -1636,8 +1625,8 @@ MtrrSetMemoryAttribute ( // // Find unused MTRR // - for (; MsrNum < VariableMtrrEnd; MsrNum += 2) { - if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) { + for (; MsrNum < VariableMtrrCount; MsrNum++) { + if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) { break; } } @@ -1648,6 +1637,7 @@ MtrrSetMemoryAttribute ( } ProgramVariableMtrr ( + VariableSettings, MsrNum, BaseAddress, Length, @@ -1680,6 +1670,28 @@ MtrrSetMemoryAttribute ( } } + // + // Write variable MTRRs + // + if (ProgramVariableSettings) { + for (Index = 0; Index < VariableMtrrCount; Index++) { + if (WorkingVariableSettings.Mtrr[Index].Base != OriginalVariableSettings.Mtrr[Index].Base || + WorkingVariableSettings.Mtrr[Index].Mask != OriginalVariableSettings.Mtrr[Index].Mask ) { + if (!MtrrContextValid) { + PreMtrrChange (&MtrrContext); + MtrrContextValid = TRUE; + } + AsmWriteMsr64 ( + MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1), + WorkingVariableSettings.Mtrr[Index].Base + ); + AsmWriteMsr64 ( + MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1, + WorkingVariableSettings.Mtrr[Index].Mask + ); + } + } + } if (MtrrContextValid) { PostMtrrChange (&MtrrContext); } From 1a66807b216a6f17e4f206c121c998008c2460d6 Mon Sep 17 00:00:00 2001 From: Michael Kinney Date: Thu, 10 Dec 2015 07:25:55 +0000 Subject: [PATCH 225/525] UefiCpuPkg/MtrrLib: Print MTRR settings when set fixed/variable MTRRs (Sync patch r19159 from main trunk.) Cc: Feng Tian Cc: Michael Kinney Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Michael Kinney Signed-off-by: Jeff Fan Reviewed-by: Feng Tian git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19203 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/Library/MtrrLib/MtrrLib.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/UefiCpuPkg/Library/MtrrLib/MtrrLib.c b/UefiCpuPkg/Library/MtrrLib/MtrrLib.c index 0e76e2f92ad5..d29aca2bdcfb 100644 --- a/UefiCpuPkg/Library/MtrrLib/MtrrLib.c +++ b/UefiCpuPkg/Library/MtrrLib/MtrrLib.c @@ -1756,6 +1756,8 @@ MtrrSetVariableMtrr ( PreMtrrChange (&MtrrContext); MtrrSetVariableMtrrWorker (VariableSettings); PostMtrrChange (&MtrrContext); + MtrrDebugPrintAllMtrrs (); + return VariableSettings; } @@ -1804,6 +1806,7 @@ MtrrSetFixedMtrr ( PreMtrrChange (&MtrrContext); MtrrSetFixedMtrrWorker (FixedSettings); PostMtrrChange (&MtrrContext); + MtrrDebugPrintAllMtrrs (); return FixedSettings; } @@ -1888,9 +1891,12 @@ MtrrSetAllMtrrs ( PostMtrrChangeEnableCache (&MtrrContext); + MtrrDebugPrintAllMtrrs (); + return MtrrSetting; } + /** Checks if MTRR is supported. From 9975f897f84f0e6baff716b1b778bb9cd893b526 Mon Sep 17 00:00:00 2001 From: Michael Kinney Date: Thu, 10 Dec 2015 07:26:28 +0000 Subject: [PATCH 226/525] UefiCpuPkg/MtrrLib: Add worker functions to access MTRRs or variable Add worker functions that could access MTRRs or MTRR settings in input buffer. (Sync patch r19160 from main trunk.) Cc: Feng Tian Cc: Michael Kinney Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Michael Kinney Signed-off-by: Jeff Fan Reviewed-by: Feng Tian git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19204 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/Library/MtrrLib/MtrrLib.c | 106 +++++++++++++++++++++------ 1 file changed, 83 insertions(+), 23 deletions(-) diff --git a/UefiCpuPkg/Library/MtrrLib/MtrrLib.c b/UefiCpuPkg/Library/MtrrLib/MtrrLib.c index d29aca2bdcfb..4c76abf9eb38 100644 --- a/UefiCpuPkg/Library/MtrrLib/MtrrLib.c +++ b/UefiCpuPkg/Library/MtrrLib/MtrrLib.c @@ -183,15 +183,25 @@ GetFirmwareVariableMtrrCount ( /** Worker function returns the default MTRR cache type for the system. + If MtrrSetting is not NULL, returns the default MTRR cache type from input + MTRR settings buffer. + If MtrrSetting is NULL, returns the default MTRR cache type from MSR. + + @param[in] MtrrSetting A buffer holding all MTRRs content. + @return The default MTRR cache type. **/ MTRR_MEMORY_CACHE_TYPE MtrrGetDefaultMemoryTypeWorker ( - VOID + IN MTRR_SETTINGS *MtrrSetting ) { - return (MTRR_MEMORY_CACHE_TYPE) (AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE) & 0x7); + if (MtrrSetting == NULL) { + return (MTRR_MEMORY_CACHE_TYPE) (AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE) & 0x7); + } else { + return (MTRR_MEMORY_CACHE_TYPE) (MtrrSetting->MtrrDefType & 0x7); + } } @@ -210,7 +220,7 @@ MtrrGetDefaultMemoryType ( if (!IsMtrrSupported ()) { return CacheUncacheable; } - return MtrrGetDefaultMemoryTypeWorker (); + return MtrrGetDefaultMemoryTypeWorker (NULL); } /** @@ -360,6 +370,12 @@ MtrrGetFixedMtrr ( /** Worker function will get the raw value in variable MTRRs + If MtrrSetting is not NULL, gets the variable MTRRs raw value from input + MTRR settings buffer. + If MtrrSetting is NULL, gets the variable MTRRs raw value from MTRRs. + + @param[in] MtrrSetting A buffer holding all MTRRs content. + @param[in] VariableMtrrCount Number of variable MTRRs. @param[out] VariableSettings A buffer to hold variable MTRRs content. @return The VariableSettings input pointer @@ -367,6 +383,7 @@ MtrrGetFixedMtrr ( **/ MTRR_VARIABLE_SETTINGS* MtrrGetVariableMtrrWorker ( + IN MTRR_SETTINGS *MtrrSetting, IN UINT32 VariableMtrrCount, OUT MTRR_VARIABLE_SETTINGS *VariableSettings ) @@ -376,10 +393,15 @@ MtrrGetVariableMtrrWorker ( ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR); for (Index = 0; Index < VariableMtrrCount; Index++) { - VariableSettings->Mtrr[Index].Base = - AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1)); - VariableSettings->Mtrr[Index].Mask = - AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1); + if (MtrrSetting == NULL) { + VariableSettings->Mtrr[Index].Base = + AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1)); + VariableSettings->Mtrr[Index].Mask = + AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1); + } else { + VariableSettings->Mtrr[Index].Base = MtrrSetting->Variables.Mtrr[Index].Base; + VariableSettings->Mtrr[Index].Mask = MtrrSetting->Variables.Mtrr[Index].Mask; + } } return VariableSettings; @@ -404,6 +426,7 @@ MtrrGetVariableMtrr ( } return MtrrGetVariableMtrrWorker ( + NULL, GetVariableMtrrCountWorker (), VariableSettings ); @@ -575,6 +598,7 @@ MtrrGetMemoryAttributeInVariableMtrr ( } MtrrGetVariableMtrrWorker ( + NULL, GetVariableMtrrCountWorker (), &VariableSettings ); @@ -949,6 +973,11 @@ ProgramVariableMtrr ( /** Converts the Memory attribute value to MTRR_MEMORY_CACHE_TYPE. + If MtrrSetting is not NULL, gets the default memory attribute from input + MTRR settings buffer. + If MtrrSetting is NULL, gets the default memory attribute from MSR. + + @param[in] MtrrSetting A buffer holding all MTRRs content. @param[in] MtrrType MTRR memory type @return The enum item in MTRR_MEMORY_CACHE_TYPE @@ -956,6 +985,7 @@ ProgramVariableMtrr ( **/ MTRR_MEMORY_CACHE_TYPE GetMemoryCacheTypeFromMtrrType ( + IN MTRR_SETTINGS *MtrrSetting, IN UINT64 MtrrType ) { @@ -975,7 +1005,7 @@ GetMemoryCacheTypeFromMtrrType ( // MtrrType is MTRR_CACHE_INVALID_TYPE, that means // no MTRR covers the range // - return MtrrGetDefaultMemoryType (); + return MtrrGetDefaultMemoryTypeWorker (MtrrSetting); } } @@ -1084,21 +1114,22 @@ MtrrPrecedence ( return MtrrType; } - - /** - This function will get the memory cache type of the specific address. + Worker function will get the memory cache type of the specific address. - This function is mainly for debug purpose. + If MtrrSetting is not NULL, gets the memory cache type from input + MTRR settings buffer. + If MtrrSetting is NULL, gets the memory cache type from MTRRs. + @param[in] MtrrSetting A buffer holding all MTRRs content. @param[in] Address The specific address @return Memory cache type of the specific address **/ MTRR_MEMORY_CACHE_TYPE -EFIAPI -MtrrGetMemoryAttribute ( +MtrrGetMemoryAttributeByAddressWorker ( + IN MTRR_SETTINGS *MtrrSetting, IN PHYSICAL_ADDRESS Address ) { @@ -1114,14 +1145,14 @@ MtrrGetMemoryAttribute ( UINTN VariableMtrrCount; MTRR_VARIABLE_SETTINGS VariableSettings; - if (!IsMtrrSupported ()) { - return CacheUncacheable; - } - // // Check if MTRR is enabled, if not, return UC as attribute // - TempQword = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE); + if (MtrrSetting == NULL) { + TempQword = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE); + } else { + TempQword = MtrrSetting->MtrrDefType; + } MtrrType = MTRR_CACHE_INVALID_TYPE; if ((TempQword & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) { @@ -1146,9 +1177,13 @@ MtrrGetMemoryAttribute ( SubIndex = ((UINTN)Address - mMtrrLibFixedMtrrTable[Index].BaseAddress) / mMtrrLibFixedMtrrTable[Index].Length; - TempQword = AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr); + if (MtrrSetting == NULL) { + TempQword = AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr); + } else { + TempQword = MtrrSetting->Fixed.Mtrr[Index]; + } MtrrType = RShiftU64 (TempQword, SubIndex * 8) & 0xFF; - return GetMemoryCacheTypeFromMtrrType (MtrrType); + return GetMemoryCacheTypeFromMtrrType (MtrrSetting, MtrrType); } } } @@ -1156,6 +1191,7 @@ MtrrGetMemoryAttribute ( MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask); MtrrGetVariableMtrrWorker ( + MtrrSetting, GetVariableMtrrCountWorker (), &VariableSettings ); @@ -1183,12 +1219,35 @@ MtrrGetMemoryAttribute ( } } } - CacheType = GetMemoryCacheTypeFromMtrrType (MtrrType); + CacheType = GetMemoryCacheTypeFromMtrrType (MtrrSetting, MtrrType); return CacheType; } +/** + This function will get the memory cache type of the specific address. + + This function is mainly for debug purpose. + + @param[in] Address The specific address + + @return Memory cache type of the specific address + +**/ +MTRR_MEMORY_CACHE_TYPE +EFIAPI +MtrrGetMemoryAttribute ( + IN PHYSICAL_ADDRESS Address + ) +{ + if (!IsMtrrSupported ()) { + return CacheUncacheable; + } + + return MtrrGetMemoryAttributeByAddressWorker (NULL, Address); +} + /** This function prints all MTRRs for debugging. @@ -1479,7 +1538,7 @@ MtrrSetMemoryAttribute ( // VariableMtrrCount = GetVariableMtrrCountWorker (); FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCountWorker (); - MtrrGetVariableMtrrWorker (VariableMtrrCount, &OriginalVariableSettings); + MtrrGetVariableMtrrWorker (NULL, VariableMtrrCount, &OriginalVariableSettings); CopyMem (&WorkingVariableSettings, &OriginalVariableSettings, sizeof (WorkingVariableSettings)); ProgramVariableSettings = TRUE; VariableSettings = &WorkingVariableSettings; @@ -1839,6 +1898,7 @@ MtrrGetAllMtrrs ( // Get variable MTRRs // MtrrGetVariableMtrrWorker ( + NULL, GetVariableMtrrCountWorker (), &MtrrSetting->Variables ); From cefdb9e78a5c24e34d66214b659f2b5f5b42f875 Mon Sep 17 00:00:00 2001 From: Michael Kinney Date: Thu, 10 Dec 2015 07:26:56 +0000 Subject: [PATCH 227/525] UefiCpuPkg/MtrrLib: Add MtrrDebugPrintAllMtrrsWorker() MtrrDebugPrintAllMtrrsWorker() provides the capability to dump the MTRR setting from MTRRs or the input MTRR settings buffer. (Sync patch r19161 from main trunk.) Cc: Feng Tian Cc: Michael Kinney Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Michael Kinney Signed-off-by: Jeff Fan Reviewed-by: Feng Tian git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19205 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/Library/MtrrLib/MtrrLib.c | 60 ++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 17 deletions(-) diff --git a/UefiCpuPkg/Library/MtrrLib/MtrrLib.c b/UefiCpuPkg/Library/MtrrLib/MtrrLib.c index 4c76abf9eb38..a5bfa8801615 100644 --- a/UefiCpuPkg/Library/MtrrLib/MtrrLib.c +++ b/UefiCpuPkg/Library/MtrrLib/MtrrLib.c @@ -1248,18 +1248,23 @@ MtrrGetMemoryAttribute ( return MtrrGetMemoryAttributeByAddressWorker (NULL, Address); } - /** - This function prints all MTRRs for debugging. + Worker function prints all MTRRs for debugging. + + If MtrrSetting is not NULL, print MTRR settings from from input MTRR + settings buffer. + If MtrrSetting is NULL, print MTRR settings from MTRRs. + + @param MtrrSetting A buffer holding all MTRRs content. **/ VOID -EFIAPI -MtrrDebugPrintAllMtrrs ( - VOID +MtrrDebugPrintAllMtrrsWorker ( + IN MTRR_SETTINGS *MtrrSetting ) { DEBUG_CODE ( - MTRR_SETTINGS MtrrSettings; + MTRR_SETTINGS LocalMtrrs; + MTRR_SETTINGS *Mtrrs; UINTN Index; UINTN Index1; UINTN VariableMtrrCount; @@ -1283,18 +1288,24 @@ MtrrDebugPrintAllMtrrs ( DEBUG((DEBUG_CACHE, "MTRR Settings\n")); DEBUG((DEBUG_CACHE, "=============\n")); - MtrrGetAllMtrrs (&MtrrSettings); - DEBUG((DEBUG_CACHE, "MTRR Default Type: %016lx\n", MtrrSettings.MtrrDefType)); + if (MtrrSetting != NULL) { + Mtrrs = MtrrSetting; + } else { + MtrrGetAllMtrrs (&LocalMtrrs); + Mtrrs = &LocalMtrrs; + } + + DEBUG((DEBUG_CACHE, "MTRR Default Type: %016lx\n", Mtrrs->MtrrDefType)); for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) { - DEBUG((DEBUG_CACHE, "Fixed MTRR[%02d] : %016lx\n", Index, MtrrSettings.Fixed.Mtrr[Index])); + DEBUG((DEBUG_CACHE, "Fixed MTRR[%02d] : %016lx\n", Index, Mtrrs->Fixed.Mtrr[Index])); } VariableMtrrCount = GetVariableMtrrCount (); for (Index = 0; Index < VariableMtrrCount; Index++) { DEBUG((DEBUG_CACHE, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n", Index, - MtrrSettings.Variables.Mtrr[Index].Base, - MtrrSettings.Variables.Mtrr[Index].Mask + Mtrrs->Variables.Mtrr[Index].Base, + Mtrrs->Variables.Mtrr[Index].Mask )); } DEBUG((DEBUG_CACHE, "\n")); @@ -1306,7 +1317,7 @@ MtrrDebugPrintAllMtrrs ( for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) { Base = mMtrrLibFixedMtrrTable[Index].BaseAddress; for (Index1 = 0; Index1 < 8; Index1++) { - MemoryType = (UINTN)(RShiftU64 (MtrrSettings.Fixed.Mtrr[Index], Index1 * 8) & 0xff); + MemoryType = (UINTN)(RShiftU64 (Mtrrs->Fixed.Mtrr[Index], Index1 * 8) & 0xff); if (MemoryType > CacheWriteBack) { MemoryType = MTRR_CACHE_INVALID_TYPE; } @@ -1333,7 +1344,7 @@ MtrrDebugPrintAllMtrrs ( Base = BASE_1MB; PreviousMemoryType = MTRR_CACHE_INVALID_TYPE; do { - MemoryType = MtrrGetMemoryAttribute (Base); + MemoryType = MtrrGetMemoryAttributeByAddressWorker (Mtrrs, Base); if (MemoryType > CacheWriteBack) { MemoryType = MTRR_CACHE_INVALID_TYPE; } @@ -1352,14 +1363,14 @@ MtrrDebugPrintAllMtrrs ( NoRangeLimit = Limit; for (Index = 0, Found = FALSE; Index < VariableMtrrCount; Index++) { - if ((MtrrSettings.Variables.Mtrr[Index].Mask & BIT11) == 0) { + if ((Mtrrs->Variables.Mtrr[Index].Mask & BIT11) == 0) { // // If mask is not valid, then do not display range // continue; } - MtrrBase = (MtrrSettings.Variables.Mtrr[Index].Base & (~(SIZE_4KB - 1))); - MtrrLimit = MtrrBase + ((~(MtrrSettings.Variables.Mtrr[Index].Mask & (~(SIZE_4KB - 1)))) & Limit); + MtrrBase = (Mtrrs->Variables.Mtrr[Index].Base & (~(SIZE_4KB - 1))); + MtrrLimit = MtrrBase + ((~(Mtrrs->Variables.Mtrr[Index].Mask & (~(SIZE_4KB - 1)))) & Limit); if (Base >= MtrrBase && Base < MtrrLimit) { Found = TRUE; @@ -1395,8 +1406,23 @@ MtrrDebugPrintAllMtrrs ( DEBUG((DEBUG_CACHE, "%016lx\n\n", Base - 1)); ); } + + +/** + This function prints all MTRRs for debugging. +**/ +VOID +EFIAPI +MtrrDebugPrintAllMtrrs ( + VOID + ) +{ + MtrrDebugPrintAllMtrrsWorker (NULL); +} + + /** - This function attempts to set the attributes for a memory range. + Worker function attempts to set the attributes for a memory range. @param[in] BaseAddress The physical address that is the start address of a memory region. From 8e01b4c503c12a00c328cd96d5fbaca818e47980 Mon Sep 17 00:00:00 2001 From: Michael Kinney Date: Thu, 10 Dec 2015 07:27:38 +0000 Subject: [PATCH 228/525] UefiCpuPkg/MtrrLib: Add MtrrSetMemoryAttributeInMtrrSettings() Add new API MtrrSetMemoryAttributeInMtrrSettings() in MtrrLib. Platform could use this API to set MTRR setting into local MTRR settings buffer instead of MTRRs. At last, platform could use MtrrSetAllMtrrs() to set the MTRR settings into MTRRs totally. It could improve MTRRs programming performance obviously, specially when platform is going to program a set of MTRRs. (Sync patch r19162 from main trunk.) Cc: Feng Tian Cc: Michael Kinney Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Michael Kinney Signed-off-by: Jeff Fan Reviewed-by: Feng Tian git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19206 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/Include/Library/MtrrLib.h | 31 ++++++ UefiCpuPkg/Library/MtrrLib/MtrrLib.c | 140 +++++++++++++++++++++++---- 2 files changed, 151 insertions(+), 20 deletions(-) diff --git a/UefiCpuPkg/Include/Library/MtrrLib.h b/UefiCpuPkg/Include/Library/MtrrLib.h index 884c7bb6996c..36cd2cd6d574 100644 --- a/UefiCpuPkg/Include/Library/MtrrLib.h +++ b/UefiCpuPkg/Include/Library/MtrrLib.h @@ -352,4 +352,35 @@ MtrrGetDefaultMemoryType ( VOID ); +/** + This function attempts to set the attributes into MTRR setting buffer for a memory range. + + @param[in, out] MtrrSetting MTRR setting buffer to be set. + @param[in] BaseAddress The physical address that is the start address + of a memory region. + @param[in] Length The size in bytes of the memory region. + @param[in] Attribute The bit mask of attributes to set for the + memory region. + + @retval RETURN_SUCCESS The attributes were set for the memory region. + @retval RETURN_INVALID_PARAMETER Length is zero. + @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the + memory resource range specified by BaseAddress and Length. + @retval RETURN_UNSUPPORTED The bit mask of attributes is not support for the memory resource + range specified by BaseAddress and Length. + @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by + BaseAddress and Length cannot be modified. + @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of + the memory resource range. + +**/ +RETURN_STATUS +EFIAPI +MtrrSetMemoryAttributeInMtrrSettings ( + IN OUT MTRR_SETTINGS *MtrrSetting, + IN PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN MTRR_MEMORY_CACHE_TYPE Attribute + ); + #endif // _MTRR_LIB_H_ diff --git a/UefiCpuPkg/Library/MtrrLib/MtrrLib.c b/UefiCpuPkg/Library/MtrrLib/MtrrLib.c index a5bfa8801615..f5b3460f1316 100644 --- a/UefiCpuPkg/Library/MtrrLib/MtrrLib.c +++ b/UefiCpuPkg/Library/MtrrLib/MtrrLib.c @@ -1424,6 +1424,11 @@ MtrrDebugPrintAllMtrrs ( /** Worker function attempts to set the attributes for a memory range. + If MtrrSettings is not NULL, set the attributes into the input MTRR + settings buffer. + If MtrrSettings is NULL, set the attributes into MTRRs registers. + + @param[in, out] MtrrSetting A buffer holding all MTRRs content. @param[in] BaseAddress The physical address that is the start address of a memory region. @param[in] Length The size in bytes of the memory region. @@ -1448,11 +1453,11 @@ MtrrDebugPrintAllMtrrs ( **/ RETURN_STATUS -EFIAPI -MtrrSetMemoryAttribute ( - IN PHYSICAL_ADDRESS BaseAddress, - IN UINT64 Length, - IN MTRR_MEMORY_CACHE_TYPE Attribute +MtrrSetMemoryAttributeWorker ( + IN OUT MTRR_SETTINGS *MtrrSetting, + IN PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN MTRR_MEMORY_CACHE_TYPE Attribute ) { UINT64 TempQword; @@ -1484,7 +1489,6 @@ MtrrSetMemoryAttribute ( UINT64 NewValue; MTRR_VARIABLE_SETTINGS *VariableSettings; - DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttribute() %a:%016lx-%016lx\n", mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, Length)); MtrrContextValid = FALSE; for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) { FixedSettingsValid[Index] = FALSE; @@ -1529,14 +1533,19 @@ MtrrSetMemoryAttribute ( if (RETURN_ERROR (Status)) { goto Done; } - if (!FixedSettingsValid[MsrNum]) { - WorkingFixedSettings.Mtrr[MsrNum] = AsmReadMsr64 (mMtrrLibFixedMtrrTable[MsrNum].Msr); - FixedSettingsValid[MsrNum] = TRUE; - } - NewValue = (WorkingFixedSettings.Mtrr[MsrNum] & ~ClearMask) | OrMask; - if (WorkingFixedSettings.Mtrr[MsrNum] != NewValue) { - WorkingFixedSettings.Mtrr[MsrNum] = NewValue; - FixedSettingsModified[MsrNum] = TRUE; + if (MtrrSetting != NULL) { + MtrrSetting->Fixed.Mtrr[MsrNum] = (MtrrSetting->Fixed.Mtrr[MsrNum] & ~ClearMask) | OrMask; + MtrrSetting->MtrrDefType |= MTRR_LIB_CACHE_FIXED_MTRR_ENABLED; + } else { + if (!FixedSettingsValid[MsrNum]) { + WorkingFixedSettings.Mtrr[MsrNum] = AsmReadMsr64 (mMtrrLibFixedMtrrTable[MsrNum].Msr); + FixedSettingsValid[MsrNum] = TRUE; + } + NewValue = (WorkingFixedSettings.Mtrr[MsrNum] & ~ClearMask) | OrMask; + if (WorkingFixedSettings.Mtrr[MsrNum] != NewValue) { + WorkingFixedSettings.Mtrr[MsrNum] = NewValue; + FixedSettingsModified[MsrNum] = TRUE; + } } } @@ -1564,10 +1573,14 @@ MtrrSetMemoryAttribute ( // VariableMtrrCount = GetVariableMtrrCountWorker (); FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCountWorker (); - MtrrGetVariableMtrrWorker (NULL, VariableMtrrCount, &OriginalVariableSettings); - CopyMem (&WorkingVariableSettings, &OriginalVariableSettings, sizeof (WorkingVariableSettings)); - ProgramVariableSettings = TRUE; - VariableSettings = &WorkingVariableSettings; + if (MtrrSetting != NULL) { + VariableSettings = &MtrrSetting->Variables; + } else { + MtrrGetVariableMtrrWorker (NULL, VariableMtrrCount, &OriginalVariableSettings); + CopyMem (&WorkingVariableSettings, &OriginalVariableSettings, sizeof (WorkingVariableSettings)); + ProgramVariableSettings = TRUE; + VariableSettings = &WorkingVariableSettings; + } // // Check for overlap @@ -1613,7 +1626,7 @@ MtrrSetMemoryAttribute ( // The memory type is the same with the type specified by // MTRR_LIB_IA32_MTRR_DEF_TYPE. // - if ((!OverwriteExistingMtrr) && (Attribute == MtrrGetDefaultMemoryType ())) { + if ((!OverwriteExistingMtrr) && (Attribute == MtrrGetDefaultMemoryTypeWorker (MtrrSetting))) { // // Invalidate the now-unused MTRRs // @@ -1783,11 +1796,98 @@ MtrrSetMemoryAttribute ( DEBUG((DEBUG_CACHE, " Status = %r\n", Status)); if (!RETURN_ERROR (Status)) { - MtrrDebugPrintAllMtrrs (); + if (MtrrSetting != NULL) { + MtrrSetting->MtrrDefType |= MTRR_LIB_CACHE_MTRR_ENABLED; + } + MtrrDebugPrintAllMtrrsWorker (MtrrSetting); } return Status; } + +/** + This function attempts to set the attributes for a memory range. + + @param[in] BaseAddress The physical address that is the start + address of a memory region. + @param[in] Length The size in bytes of the memory region. + @param[in] Attributes The bit mask of attributes to set for the + memory region. + + @retval RETURN_SUCCESS The attributes were set for the memory + region. + @retval RETURN_INVALID_PARAMETER Length is zero. + @retval RETURN_UNSUPPORTED The processor does not support one or + more bytes of the memory resource range + specified by BaseAddress and Length. + @retval RETURN_UNSUPPORTED The bit mask of attributes is not support + for the memory resource range specified + by BaseAddress and Length. + @retval RETURN_ACCESS_DENIED The attributes for the memory resource + range specified by BaseAddress and Length + cannot be modified. + @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to + modify the attributes of the memory + resource range. + +**/ +RETURN_STATUS +EFIAPI +MtrrSetMemoryAttribute ( + IN PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN MTRR_MEMORY_CACHE_TYPE Attribute + ) +{ + DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttribute() %a:%016lx-%016lx\n", mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, Length)); + return MtrrSetMemoryAttributeWorker ( + NULL, + BaseAddress, + Length, + Attribute + ); +} + +/** + This function attempts to set the attributes into MTRR setting buffer for a memory range. + + @param[in, out] MtrrSetting MTRR setting buffer to be set. + @param[in] BaseAddress The physical address that is the start address + of a memory region. + @param[in] Length The size in bytes of the memory region. + @param[in] Attribute The bit mask of attributes to set for the + memory region. + + @retval RETURN_SUCCESS The attributes were set for the memory region. + @retval RETURN_INVALID_PARAMETER Length is zero. + @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the + memory resource range specified by BaseAddress and Length. + @retval RETURN_UNSUPPORTED The bit mask of attributes is not support for the memory resource + range specified by BaseAddress and Length. + @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by + BaseAddress and Length cannot be modified. + @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of + the memory resource range. + +**/ +RETURN_STATUS +EFIAPI +MtrrSetMemoryAttributeInMtrrSettings ( + IN OUT MTRR_SETTINGS *MtrrSetting, + IN PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN MTRR_MEMORY_CACHE_TYPE Attribute + ) +{ + DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttributeMtrrSettings(%p) %a:%016lx-%016lx\n", MtrrSetting, mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, Length)); + return MtrrSetMemoryAttributeWorker ( + MtrrSetting, + BaseAddress, + Length, + Attribute + ); +} + /** Worker function setting variable MTRRs From f7993e868c8b7947401ec94e50667d870b4ddfe0 Mon Sep 17 00:00:00 2001 From: Ruiyu Ni Date: Thu, 10 Dec 2015 07:28:33 +0000 Subject: [PATCH 229/525] MdeModulePkg: Add PciSioSerialDxe driver PciSioSerialDxe driver can manages UARTs on a SIO chip or a PCI/PCIE card. It manages the SIO instance whose last device path node is a ACPI device path and the HID in the ACPI device path node equals to EISA_PNP_ID (0x501). It also manages the PCI IO instance whose class code is 7/0/2 (16550 UART). But when proper value is set to PcdPciSerialParameters, the driver can also manage non-standard PCI serial cards by matching the Vendor ID and Device ID specified in PcdPciSerialParameters. The PCI BAR index, IO/MMIO offset, register stride, clock rate can also be specified through the same PCD. (Sync patch r19179 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ruiyu Ni Reviewed-by: Feng Tian Reviewed-by: Michael Kinney git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19207 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Bus/Pci/PciSioSerialDxe/ComponentName.c | 288 ++++ .../Pci/PciSioSerialDxe/PciSioSerialDxe.inf | 81 + .../Pci/PciSioSerialDxe/PciSioSerialDxe.uni | Bin 0 -> 1936 bytes .../PciSioSerialDxe/PciSioSerialDxeExtra.uni | Bin 0 -> 1372 bytes MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.c | 1242 ++++++++++++++++ MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.h | 789 ++++++++++ .../Bus/Pci/PciSioSerialDxe/SerialIo.c | 1320 +++++++++++++++++ MdeModulePkg/MdeModulePkg.dec | 38 + MdeModulePkg/MdeModulePkg.dsc | 1 + 9 files changed, 3759 insertions(+) create mode 100644 MdeModulePkg/Bus/Pci/PciSioSerialDxe/ComponentName.c create mode 100644 MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxe.inf create mode 100644 MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxe.uni create mode 100644 MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxeExtra.uni create mode 100644 MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.c create mode 100644 MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.h create mode 100644 MdeModulePkg/Bus/Pci/PciSioSerialDxe/SerialIo.c diff --git a/MdeModulePkg/Bus/Pci/PciSioSerialDxe/ComponentName.c b/MdeModulePkg/Bus/Pci/PciSioSerialDxe/ComponentName.c new file mode 100644 index 000000000000..994dc847c9d1 --- /dev/null +++ b/MdeModulePkg/Bus/Pci/PciSioSerialDxe/ComponentName.c @@ -0,0 +1,288 @@ +/** @file + UEFI Component Name and Name2 protocol for Isa serial driver. + +Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "Serial.h" + +// +// EFI Component Name Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gPciSioSerialComponentName = { + SerialComponentNameGetDriverName, + SerialComponentNameGetControllerName, + "eng" +}; + +// +// EFI Component Name 2 Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gPciSioSerialComponentName2 = { + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) SerialComponentNameGetDriverName, + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) SerialComponentNameGetControllerName, + "en" +}; + + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mSerialDriverNameTable[] = { + { + "eng;en", + L"PCI SIO Serial Driver" + }, + { + NULL, + NULL + } +}; + +GLOBAL_REMOVE_IF_UNREFERENCED CHAR16 mSioSerialPortName[] = L"SIO Serial Port #%d"; +GLOBAL_REMOVE_IF_UNREFERENCED CHAR16 mPciSerialPortName[] = L"PCI Serial Port #%d"; + +/** + Retrieves a Unicode string that is the user readable name of the driver. + + This function retrieves the user readable name of a driver in the form of a + Unicode string. If the driver specified by This has a user readable name in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified + in RFC 4646 or ISO 639-2 language code format. + + @param DriverName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by + This and the language specified by Language was + returned in DriverName. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER DriverName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +SerialComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +{ + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + mSerialDriverNameTable, + DriverName, + (BOOLEAN)(This == &gPciSioSerialComponentName) + ); +} + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by a driver. + + This function retrieves the user readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param ControllerHandle[in] The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + + @param ChildHandle[in] The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 4646 or ISO 639-2 language code format. + + @param ControllerName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + + @retval EFI_INVALID_PARAMETER ControllerHandle is NULL. + + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +SerialComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +{ + EFI_STATUS Status; + EFI_SERIAL_IO_PROTOCOL *SerialIo; + SERIAL_DEV *SerialDevice; + EFI_UNICODE_STRING_TABLE *ControllerNameTable; + EFI_GUID *IoProtocolGuid; + + // + // Make sure this driver is currently managing ControllerHandle + // + IoProtocolGuid = &gEfiSioProtocolGuid; + Status = EfiTestManagedDevice ( + ControllerHandle, + gSerialControllerDriver.DriverBindingHandle, + IoProtocolGuid + ); + if (EFI_ERROR (Status)) { + IoProtocolGuid = &gEfiPciIoProtocolGuid; + Status = EfiTestManagedDevice ( + ControllerHandle, + gSerialControllerDriver.DriverBindingHandle, + IoProtocolGuid + ); + } + + if (EFI_ERROR (Status)) { + return Status; + } + + ControllerNameTable = NULL; + if (ChildHandle != NULL) { + Status = EfiTestChildHandle ( + ControllerHandle, + ChildHandle, + IoProtocolGuid + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Get the Serial I/O Protocol from the child handle + // + Status = gBS->OpenProtocol ( + ChildHandle, + &gEfiSerialIoProtocolGuid, + (VOID **) &SerialIo, + gSerialControllerDriver.DriverBindingHandle, + ChildHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Get the Serial Controller's Device structure + // + SerialDevice = SERIAL_DEV_FROM_THIS (SerialIo); + ControllerNameTable = SerialDevice->ControllerNameTable; + } + + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + ControllerNameTable, + ControllerName, + (BOOLEAN)(This == &gPciSioSerialComponentName) + ); +} + +/** + Add the ISO639-2 and RFC4646 component name both for the Serial IO device + + @param SerialDevice A pointer to the SERIAL_DEV instance. + @param Instance Instance ID for the serial device. +**/ +VOID +AddName ( + IN SERIAL_DEV *SerialDevice, + IN UINT32 Instance + ) +{ + CHAR16 SerialPortName[SERIAL_PORT_NAME_LEN]; + UnicodeSPrint ( + SerialPortName, + sizeof (SerialPortName), + (SerialDevice->PciDeviceInfo != NULL) ? PCI_SERIAL_PORT_NAME : SIO_SERIAL_PORT_NAME, + Instance + ); + AddUnicodeString2 ( + "eng", + gPciSioSerialComponentName.SupportedLanguages, + &SerialDevice->ControllerNameTable, + SerialPortName, + TRUE + ); + AddUnicodeString2 ( + "en", + gPciSioSerialComponentName2.SupportedLanguages, + &SerialDevice->ControllerNameTable, + SerialPortName, + FALSE + ); + +} diff --git a/MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxe.inf b/MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxe.inf new file mode 100644 index 000000000000..03fddfe75e8a --- /dev/null +++ b/MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxe.inf @@ -0,0 +1,81 @@ +## @file +# Serial driver for standard UARTS on a SIO chip or PCI/PCIE card. +# +# Produces the Serial I/O protocol for standard UARTS using Super I/O or PCI I/O. +# +# Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PciSioSerialDxe + MODULE_UNI_FILE = PciSioSerialDxe.uni + FILE_GUID = E2775B47-D453-4EE3-ADA7-391A1B05AC17 + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = InitializePciSioSerial + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# +# DRIVER_BINDING = gSerialControllerDriver +# COMPONENT_NAME = gPciSioSerialComponentName +# COMPONENT_NAME2 = gPciSioSerialComponentName2 +# + +[Sources] + ComponentName.c + SerialIo.c + Serial.h + Serial.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + PcdLib + ReportStatusCodeLib + UefiBootServicesTableLib + MemoryAllocationLib + BaseMemoryLib + DevicePathLib + UefiLib + UefiDriverEntryPoint + DebugLib + IoLib + +[Guids] + gEfiUartDevicePathGuid ## SOMETIMES_CONSUMES ## GUID + +[Protocols] + gEfiSioProtocolGuid ## TO_START + gEfiDevicePathProtocolGuid ## TO_START + gEfiPciIoProtocolGuid ## TO_START + gEfiSerialIoProtocolGuid ## BY_START + gEfiDevicePathProtocolGuid ## BY_START + +[FeaturePcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialUseHalfHandshake|FALSE ## CONSUMES + +[Pcd] + gEfiMdePkgTokenSpaceGuid.PcdUartDefaultBaudRate|115200 ## CONSUMES + gEfiMdePkgTokenSpaceGuid.PcdUartDefaultDataBits|8 ## CONSUMES + gEfiMdePkgTokenSpaceGuid.PcdUartDefaultParity|1 ## CONSUMES + gEfiMdePkgTokenSpaceGuid.PcdUartDefaultStopBits|1 ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialClockRate|1843200 ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdPciSerialParameters ## CONSUMES + +[UserExtensions.TianoCore."ExtraFiles"] + PciSioSerialDxeExtra.uni diff --git a/MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxe.uni b/MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxe.uni new file mode 100644 index 0000000000000000000000000000000000000000..617f583b35ad6654d838b1a174253a71862606db GIT binary patch literal 1936 zcmd6oTaOY!5QXd6#Q)G?U)1b^nivyfj9f;Ys0-ne)h9D7EKIV%W`NcG^XhkMURac)neX4r+^|NL*3$!Qvg1xmXOYPdm_Rt<+)n1QPhBd(+Y~=G>w*|Zxtb;9W z#r~Y#g!Kr^!0OhuKBogdbNYnVv)I~Uzn9F;Hmhg$!cLjTL|ze5e1(vKp+3QyGMihKojUvSD6yqS=DLWj zGBv{UwKd4cnooBgGuC-VOLY@COTihQ+Pf>%nK`SnPL@R+p@>a@Wy z=a$Z?#MkMO`y}v9@VllT((Bxs6WW#X+dNB`3?5>=WhrLzObdOqyCB!)xds*3V*P24 zOIcapT?trckoruqRQb|=2+!TTNL8`F!k%YHoPXeR$Z21fz^xLL4It*{ z7aIk{XtkrO>S#qKUimv!h2`4HKXaw4+&-h?Y6sdcu?%58qUQFaS3#N5N=3?9-#%Cb zuMTz8w)gaP`^-A_H{SBGk2R*!2E6>pl^)nRV}w0m%Mr>f#8h^KN6(Sl%v90pD~!Dj zdWEs!YsEUj}45~2N9=*#-++|bDKECo%)ZFVGzKZ^p@gqB8 zu9p~XqU5)T>`Q@DqQ_{_p{^9O#e3W8wjG0iVQX%eP3@$pp6xeA`h5eb4aNYph*h1t z_h2f$n~dR)zZ0^l*D#?15_;8-YT^tmF|E*-Z}eY$%PYnG?{{}qPLErwsyaosjw$f> MyZ_(+8o4sR0T-w!M*si- literal 0 HcmV?d00001 diff --git a/MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxeExtra.uni b/MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxeExtra.uni new file mode 100644 index 0000000000000000000000000000000000000000..935bdba93e0322aa2412b9d02bd7cba7623bceb2 GIT binary patch literal 1372 zcmZXUTW`}q5QXO%iT|()FM!&Fi+Di@ku(M@N*(1Q;3;x0O)ce8ISDlUc;GwZ*lvm< z@9fUboH=`THh=%LtYv}kIlo{Z?AkJ0+T0%7BfQ${*%aS^Z^JmZoLNdt*X~#ayTm_r zPiDXI%W`cG_@Og!mWOVwS^Y%a_|v=ian;*0H|5uN0`+4Plh| zd2Wf{fT9{JP|EY|h>#{JoTo&rV4}SPdD0@_5vy9oZB<8EViRDQku8nHOnR31%AR>l z3g48tCF6uqd3!Rnn=>z&6tz|-w;*PU%qo4P#D=@C^E%vNm-Xcdms*QouEmt`|I=o0 z5TZB~da2fywX~nW^Zva^Rk6RuU)+#5-x2eW)2S|nmItCH$NbGv0WsR$(^Y-6<0jsE zN2|jMZ55xp(oIgEb3d&I+HdhpU_PVgPOCRTx#24nDQ&Q!eYOZzJ-R5dPmFE*$~s2T zfTprTyfJ+?Vivj1BfG*z_-lmv4r2N`B4Xgk2{ZMx#s*fnLTz9>zSioj;uh>1`{I>& zMXlRZ603@<6KyC{(KR)n(0 xF1%;d2j|3#pJE!|UcgQNU^;PNPf88lQ@>j2y!RgOa!OU`dT;ALBnL%U{{R8l(_R1o literal 0 HcmV?d00001 diff --git a/MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.c b/MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.c new file mode 100644 index 000000000000..86e75a43f719 --- /dev/null +++ b/MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.c @@ -0,0 +1,1242 @@ +/** @file + Serial driver for PCI or SIO UARTS. + +Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "Serial.h" + +// +// ISA Serial Driver Global Variables +// + +EFI_DRIVER_BINDING_PROTOCOL gSerialControllerDriver = { + SerialControllerDriverSupported, + SerialControllerDriverStart, + SerialControllerDriverStop, + 0xa, + NULL, + NULL +}; + +CONTROLLER_DEVICE_PATH mControllerDevicePathTemplate = { + { + HARDWARE_DEVICE_PATH, + HW_CONTROLLER_DP, + sizeof (CONTROLLER_DEVICE_PATH), + 0 + }, + 0 +}; + +SERIAL_DEV gSerialDevTemplate = { + SERIAL_DEV_SIGNATURE, + NULL, + { + SERIAL_IO_INTERFACE_REVISION, + SerialReset, + SerialSetAttributes, + SerialSetControl, + SerialGetControl, + SerialWrite, + SerialRead, + NULL + }, // SerialIo + { + SERIAL_PORT_SUPPORT_CONTROL_MASK, + SERIAL_PORT_DEFAULT_TIMEOUT, + 0, + 16, + 0, + 0, + 0 + }, // SerialMode + NULL, // DevicePath + NULL, // ParentDevicePath + { + { + MESSAGING_DEVICE_PATH, + MSG_UART_DP, + { + (UINT8) (sizeof (UART_DEVICE_PATH)), + (UINT8) ((sizeof (UART_DEVICE_PATH)) >> 8) + } + }, + 0, 0, 0, 0, 0 + }, // UartDevicePath + 0, // BaseAddress + FALSE, // MmioAccess + 1, // RegisterStride + 0, // ClockRate + 16, // ReceiveFifoDepth + { 0, 0 }, // Receive; + 16, // TransmitFifoDepth + { 0, 0 }, // Transmit; + FALSE, // SoftwareLoopbackEnable; + FALSE, // HardwareFlowControl; + NULL, // *ControllerNameTable; + FALSE, // ContainsControllerNode; + 0, // Instance; + NULL // *PciDeviceInfo; +}; + +/** + Check the device path node whether it's the Flow Control node or not. + + @param[in] FlowControl The device path node to be checked. + + @retval TRUE It's the Flow Control node. + @retval FALSE It's not. + +**/ +BOOLEAN +IsUartFlowControlDevicePathNode ( + IN UART_FLOW_CONTROL_DEVICE_PATH *FlowControl + ) +{ + return (BOOLEAN) ( + (DevicePathType (FlowControl) == MESSAGING_DEVICE_PATH) && + (DevicePathSubType (FlowControl) == MSG_VENDOR_DP) && + (CompareGuid (&FlowControl->Guid, &gEfiUartDevicePathGuid)) + ); +} + +/** + The user Entry Point for module PciSioSerial. The user code starts with this function. + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + @retval other Some error occurs when executing this entry point. + +**/ +EFI_STATUS +EFIAPI +InitializePciSioSerial ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + // + // Install driver model protocol(s). + // + Status = EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, + SystemTable, + &gSerialControllerDriver, + ImageHandle, + &gPciSioSerialComponentName, + &gPciSioSerialComponentName2 + ); + ASSERT_EFI_ERROR (Status); + + // + // Initialize UART default setting in gSerialDevTempate + // + gSerialDevTemplate.SerialMode.BaudRate = PcdGet64 (PcdUartDefaultBaudRate); + gSerialDevTemplate.SerialMode.DataBits = PcdGet8 (PcdUartDefaultDataBits); + gSerialDevTemplate.SerialMode.Parity = PcdGet8 (PcdUartDefaultParity); + gSerialDevTemplate.SerialMode.StopBits = PcdGet8 (PcdUartDefaultStopBits); + gSerialDevTemplate.UartDevicePath.BaudRate = PcdGet64 (PcdUartDefaultBaudRate); + gSerialDevTemplate.UartDevicePath.DataBits = PcdGet8 (PcdUartDefaultDataBits); + gSerialDevTemplate.UartDevicePath.Parity = PcdGet8 (PcdUartDefaultParity); + gSerialDevTemplate.UartDevicePath.StopBits = PcdGet8 (PcdUartDefaultStopBits); + gSerialDevTemplate.ClockRate = PcdGet32 (PcdSerialClockRate); + + return Status; +} + +/** + Return whether the controller is a SIO serial controller. + + @param Controller The controller handle. + + @retval EFI_SUCCESS The controller is a SIO serial controller. + @retval others The controller is not a SIO serial controller. +**/ +EFI_STATUS +IsSioSerialController ( + EFI_HANDLE Controller + ) +{ + EFI_STATUS Status; + EFI_SIO_PROTOCOL *Sio; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + ACPI_HID_DEVICE_PATH *Acpi; + + // + // Open the IO Abstraction(s) needed to perform the supported test + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiSioProtocolGuid, + (VOID **) &Sio, + gSerialControllerDriver.DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (Status == EFI_ALREADY_STARTED) { + return EFI_SUCCESS; + } + + if (!EFI_ERROR (Status)) { + // + // Close the I/O Abstraction(s) used to perform the supported test + // + gBS->CloseProtocol ( + Controller, + &gEfiSioProtocolGuid, + gSerialControllerDriver.DriverBindingHandle, + Controller + ); + + Status = gBS->OpenProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + (VOID **) &DevicePath, + gSerialControllerDriver.DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + ASSERT (Status != EFI_ALREADY_STARTED); + + if (!EFI_ERROR (Status)) { + do { + Acpi = (ACPI_HID_DEVICE_PATH *) DevicePath; + DevicePath = NextDevicePathNode (DevicePath); + } while (!IsDevicePathEnd (DevicePath)); + + if (DevicePathType (Acpi) != ACPI_DEVICE_PATH || + (DevicePathSubType (Acpi) != ACPI_DP && DevicePathSubType (Acpi) != ACPI_EXTENDED_DP) || + Acpi->HID != EISA_PNP_ID (0x501) + ) { + Status = EFI_UNSUPPORTED; + } + } + + // + // Close protocol, don't use device path protocol in the Support() function + // + gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + gSerialControllerDriver.DriverBindingHandle, + Controller + ); + } + return Status; +} + +/** + Return whether the controller is a PCI serial controller. + + @param Controller The controller handle. + + @retval EFI_SUCCESS The controller is a PCI serial controller. + @retval others The controller is not a PCI serial controller. +**/ +EFI_STATUS +IsPciSerialController ( + EFI_HANDLE Controller + ) +{ + EFI_STATUS Status; + EFI_PCI_IO_PROTOCOL *PciIo; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + PCI_TYPE00 Pci; + PCI_SERIAL_PARAMETER *PciSerialParameter; + + // + // Open the IO Abstraction(s) needed to perform the supported test + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo, + gSerialControllerDriver.DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (Status == EFI_ALREADY_STARTED) { + return EFI_SUCCESS; + } + + if (!EFI_ERROR (Status)) { + Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0, sizeof (Pci), &Pci); + if (!EFI_ERROR (Status)) { + if (!IS_PCI_16550_SERIAL (&Pci)) { + for (PciSerialParameter = (PCI_SERIAL_PARAMETER *) PcdGetPtr (PcdPciSerialParameters) + ; PciSerialParameter->VendorId != 0xFFFF + ; PciSerialParameter++ + ) { + if ((Pci.Hdr.VendorId == PciSerialParameter->VendorId) && + (Pci.Hdr.DeviceId == PciSerialParameter->DeviceId) + ) { + break; + } + } + if (PciSerialParameter->VendorId == 0xFFFF) { + Status = EFI_UNSUPPORTED; + } else { + Status = EFI_SUCCESS; + } + } + } + + // + // Close the I/O Abstraction(s) used to perform the supported test + // + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + gSerialControllerDriver.DriverBindingHandle, + Controller + ); + } + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Open the EFI Device Path protocol needed to perform the supported test + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + (VOID **) &DevicePath, + gSerialControllerDriver.DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + ASSERT (Status != EFI_ALREADY_STARTED); + + // + // Close protocol, don't use device path protocol in the Support() function + // + gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + gSerialControllerDriver.DriverBindingHandle, + Controller + ); + + return Status; +} + +/** + Check to see if this driver supports the given controller + + @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param Controller The handle of the controller to test. + @param RemainingDevicePath A pointer to the remaining portion of a device path. + + @return EFI_SUCCESS This driver can support the given controller + +**/ +EFI_STATUS +EFIAPI +SerialControllerDriverSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) + +{ + EFI_STATUS Status; + UART_DEVICE_PATH *Uart; + UART_FLOW_CONTROL_DEVICE_PATH *FlowControl; + + // + // Test RemainingDevicePath + // + if ((RemainingDevicePath != NULL) && !IsDevicePathEnd (RemainingDevicePath)) { + Status = EFI_UNSUPPORTED; + + Uart = SkipControllerDevicePathNode (RemainingDevicePath, NULL, NULL); + if (DevicePathType (Uart) != MESSAGING_DEVICE_PATH || + DevicePathSubType (Uart) != MSG_UART_DP || + DevicePathNodeLength (Uart) != sizeof (UART_DEVICE_PATH) + ) { + return EFI_UNSUPPORTED; + } + + // + // Do a rough check because Clock Rate is unknown until DriverBindingStart() + // + if (!VerifyUartParameters (0, Uart->BaudRate, Uart->DataBits, Uart->Parity, Uart->StopBits, NULL, NULL)) { + return EFI_UNSUPPORTED; + } + + FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (Uart); + if (IsUartFlowControlDevicePathNode (FlowControl)) { + // + // If the second node is Flow Control Node, + // return error when it request other than hardware flow control. + // + if ((ReadUnaligned32 (&FlowControl->FlowControlMap) & ~UART_FLOW_CONTROL_HARDWARE) != 0) { + return EFI_UNSUPPORTED; + } + } + } + + Status = IsSioSerialController (Controller); + if (EFI_ERROR (Status)) { + Status = IsPciSerialController (Controller); + } + return Status; +} + +/** + Create the child serial device instance. + + @param Controller The parent controller handle. + @param Uart Pointer to the UART device path node in RemainingDevicePath, + or NULL if RemainingDevicePath is NULL. + @param ParentDevicePath Pointer to the parent device path. + @param CreateControllerNode TRUE to create the controller node. + @param Instance Instance number of the serial device. + The value will be set to the controller node + if CreateControllerNode is TRUE. + @param ParentIo A union type pointer to either Sio or PciIo. + @param PciSerialParameter The PCI serial parameter to be used by current serial device. + NULL for SIO serial device. + @param PciDeviceInfo The PCI device info for the current serial device. + NULL for SIO serial device. + + @retval EFI_SUCCESS The serial device was created successfully. + @retval others The serial device wasn't created. +**/ +EFI_STATUS +CreateSerialDevice ( + IN EFI_HANDLE Controller, + IN UART_DEVICE_PATH *Uart, + IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath, + IN BOOLEAN CreateControllerNode, + IN UINT32 Instance, + IN PARENT_IO_PROTOCOL_PTR ParentIo, + IN PCI_SERIAL_PARAMETER *PciSerialParameter, OPTIONAL + IN PCI_DEVICE_INFO *PciDeviceInfo OPTIONAL + ) +{ + EFI_STATUS Status; + SERIAL_DEV *SerialDevice; + UINT8 BarIndex; + UINT64 Offset; + UART_FLOW_CONTROL_DEVICE_PATH *FlowControl; + UINT32 FlowControlMap; + ACPI_RESOURCE_HEADER_PTR Resources; + EFI_ACPI_IO_PORT_DESCRIPTOR *Io; + EFI_ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR *FixedIo; + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *AddressSpace; + EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; + + BarIndex = 0; + Offset = 0; + FlowControl = NULL; + FlowControlMap = 0; + + // + // Initialize the serial device instance + // + SerialDevice = AllocateCopyPool (sizeof (SERIAL_DEV), &gSerialDevTemplate); + ASSERT (SerialDevice != NULL); + + SerialDevice->SerialIo.Mode = &(SerialDevice->SerialMode); + SerialDevice->ParentDevicePath = ParentDevicePath; + SerialDevice->PciDeviceInfo = PciDeviceInfo; + SerialDevice->Instance = Instance; + + if (Uart != NULL) { + CopyMem (&SerialDevice->UartDevicePath, Uart, sizeof (UART_DEVICE_PATH)); + FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (Uart); + if (IsUartFlowControlDevicePathNode (FlowControl)) { + FlowControlMap = ReadUnaligned32 (&FlowControl->FlowControlMap); + } else { + FlowControl = NULL; + } + } + + // + // For PCI serial device, use the information from PCD + // + if (PciSerialParameter != NULL) { + BarIndex = (PciSerialParameter->BarIndex == PCI_BAR_ALL) ? 0 : PciSerialParameter->BarIndex; + Offset = PciSerialParameter->Offset; + if (PciSerialParameter->RegisterStride != 0) { + SerialDevice->RegisterStride = PciSerialParameter->RegisterStride; + } + if (PciSerialParameter->ClockRate != 0) { + SerialDevice->ClockRate = PciSerialParameter->ClockRate; + } + if (PciSerialParameter->ReceiveFifoDepth != 0) { + SerialDevice->ReceiveFifoDepth = PciSerialParameter->ReceiveFifoDepth; + } + if (PciSerialParameter->TransmitFifoDepth != 0) { + SerialDevice->TransmitFifoDepth = PciSerialParameter->TransmitFifoDepth; + } + } + + // + // Pass NULL ActualBaudRate to VerifyUartParameters to disallow baudrate degrade. + // DriverBindingStart() shouldn't create a handle with different UART device path. + // + if (!VerifyUartParameters (SerialDevice->ClockRate, SerialDevice->UartDevicePath.BaudRate, SerialDevice->UartDevicePath.DataBits, + SerialDevice->UartDevicePath.Parity, SerialDevice->UartDevicePath.StopBits, NULL, NULL + )) { + Status = EFI_INVALID_PARAMETER; + goto CreateError; + } + + if (PciSerialParameter == NULL) { + Status = ParentIo.Sio->GetResources (ParentIo.Sio, &Resources); + } else { + Status = ParentIo.PciIo->GetBarAttributes (ParentIo.PciIo, BarIndex, NULL, (VOID **) &Resources); + } + + if (!EFI_ERROR (Status)) { + // + // Get the base address information from ACPI resource descriptor. + // ACPI_IO_PORT_DESCRIPTOR and ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR are returned from Sio; + // ACPI_ADDRESS_SPACE_DESCRIPTOR is returned from PciIo. + // + while ((Resources.SmallHeader->Byte != ACPI_END_TAG_DESCRIPTOR) && (SerialDevice->BaseAddress == 0)) { + switch (Resources.SmallHeader->Byte) { + case ACPI_IO_PORT_DESCRIPTOR: + Io = (EFI_ACPI_IO_PORT_DESCRIPTOR *) Resources.SmallHeader; + if (Io->Length != 0) { + SerialDevice->BaseAddress = Io->BaseAddressMin; + } + break; + + case ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR: + FixedIo = (EFI_ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR *) Resources.SmallHeader; + if (FixedIo->Length != 0) { + SerialDevice->BaseAddress = FixedIo->BaseAddress; + } + break; + + case ACPI_ADDRESS_SPACE_DESCRIPTOR: + AddressSpace = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Resources.SmallHeader; + if (AddressSpace->AddrLen != 0) { + if (AddressSpace->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) { + SerialDevice->MmioAccess = TRUE; + } + SerialDevice->BaseAddress = AddressSpace->AddrRangeMin + Offset; + } + break; + } + + if (Resources.SmallHeader->Bits.Type == 0) { + Resources.SmallHeader = (ACPI_SMALL_RESOURCE_HEADER *) ((UINT8 *) Resources.SmallHeader + + Resources.SmallHeader->Bits.Length + + sizeof (*Resources.SmallHeader)); + } else { + Resources.LargeHeader = (ACPI_LARGE_RESOURCE_HEADER *) ((UINT8 *) Resources.LargeHeader + + Resources.LargeHeader->Length + + sizeof (*Resources.LargeHeader)); + } + } + } + + if (SerialDevice->BaseAddress == 0) { + Status = EFI_INVALID_PARAMETER; + goto CreateError; + } + + SerialDevice->HardwareFlowControl = (BOOLEAN) (FlowControlMap == UART_FLOW_CONTROL_HARDWARE); + + // + // Report status code the serial present + // + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_PROGRESS_CODE, + EFI_P_PC_PRESENCE_DETECT | EFI_PERIPHERAL_SERIAL_PORT, + SerialDevice->ParentDevicePath + ); + + if (!SerialPresent (SerialDevice)) { + Status = EFI_DEVICE_ERROR; + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_ERROR_CODE, + EFI_P_EC_NOT_DETECTED | EFI_PERIPHERAL_SERIAL_PORT, + SerialDevice->ParentDevicePath + ); + goto CreateError; + } + + // + // 1. Append Controller device path node. + // + if (CreateControllerNode) { + mControllerDevicePathTemplate.ControllerNumber = SerialDevice->Instance; + SerialDevice->DevicePath = AppendDevicePathNode ( + SerialDevice->ParentDevicePath, + (EFI_DEVICE_PATH_PROTOCOL *) &mControllerDevicePathTemplate + ); + SerialDevice->ContainsControllerNode = TRUE; + } + + // + // 2. Append UART device path node. + // The Uart setings are zero here. + // SetAttribute() will update them to match the default setings. + // + TempDevicePath = SerialDevice->DevicePath; + if (TempDevicePath != NULL) { + SerialDevice->DevicePath = AppendDevicePathNode ( + TempDevicePath, + (EFI_DEVICE_PATH_PROTOCOL *) &SerialDevice->UartDevicePath + ); + FreePool (TempDevicePath); + } else { + SerialDevice->DevicePath = AppendDevicePathNode ( + SerialDevice->ParentDevicePath, + (EFI_DEVICE_PATH_PROTOCOL *) &SerialDevice->UartDevicePath + ); + } + // + // 3. Append the Flow Control device path node. + // Only produce the Flow Control node when remaining device path has it + // + if (FlowControl != NULL) { + TempDevicePath = SerialDevice->DevicePath; + if (TempDevicePath != NULL) { + SerialDevice->DevicePath = AppendDevicePathNode ( + TempDevicePath, + (EFI_DEVICE_PATH_PROTOCOL *) FlowControl + ); + FreePool (TempDevicePath); + } + } + ASSERT (SerialDevice->DevicePath != NULL); + + // + // Fill in Serial I/O Mode structure based on either the RemainingDevicePath or defaults. + // + SerialDevice->SerialMode.BaudRate = SerialDevice->UartDevicePath.BaudRate; + SerialDevice->SerialMode.DataBits = SerialDevice->UartDevicePath.DataBits; + SerialDevice->SerialMode.Parity = SerialDevice->UartDevicePath.Parity; + SerialDevice->SerialMode.StopBits = SerialDevice->UartDevicePath.StopBits; + + // + // Issue a reset to initialize the COM port + // + Status = SerialDevice->SerialIo.Reset (&SerialDevice->SerialIo); + if (EFI_ERROR (Status)) { + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_ERROR_CODE, + EFI_P_EC_CONTROLLER_ERROR | EFI_PERIPHERAL_SERIAL_PORT, + SerialDevice->DevicePath + ); + goto CreateError; + } + + AddName (SerialDevice, Instance); + // + // Install protocol interfaces for the serial device. + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &SerialDevice->Handle, + &gEfiDevicePathProtocolGuid, SerialDevice->DevicePath, + &gEfiSerialIoProtocolGuid, &SerialDevice->SerialIo, + NULL + ); + if (EFI_ERROR (Status)) { + goto CreateError; + } + // + // Open For Child Device + // + Status = gBS->OpenProtocol ( + Controller, + PciSerialParameter != NULL ? &gEfiPciIoProtocolGuid : &gEfiSioProtocolGuid, + (VOID **) &ParentIo, + gSerialControllerDriver.DriverBindingHandle, + SerialDevice->Handle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + + if (EFI_ERROR (Status)) { + gBS->UninstallMultipleProtocolInterfaces ( + &SerialDevice->Handle, + &gEfiDevicePathProtocolGuid, SerialDevice->DevicePath, + &gEfiSerialIoProtocolGuid, &SerialDevice->SerialIo, + NULL + ); + } + +CreateError: + if (EFI_ERROR (Status)) { + if (SerialDevice->DevicePath != NULL) { + FreePool (SerialDevice->DevicePath); + } + if (SerialDevice->ControllerNameTable != NULL) { + FreeUnicodeStringTable (SerialDevice->ControllerNameTable); + } + FreePool (SerialDevice); + } + return Status; +} + +/** + Returns an array of pointers containing all the child serial device pointers. + + @param Controller The parent controller handle. + @param IoProtocolGuid The protocol GUID, either equals to gEfiSioProtocolGuid + or equals to gEfiPciIoProtocolGuid. + @param Count Count of the serial devices. + + @return An array of pointers containing all the child serial device pointers. +**/ +SERIAL_DEV ** +GetChildSerialDevices ( + IN EFI_HANDLE Controller, + IN EFI_GUID *IoProtocolGuid, + OUT UINTN *Count + ) +{ + EFI_STATUS Status; + UINTN Index; + EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer; + UINTN EntryCount; + SERIAL_DEV **SerialDevices; + EFI_SERIAL_IO_PROTOCOL *SerialIo; + BOOLEAN OpenByDriver; + + *Count = 0; + // + // If the SerialIo instance specified by RemainingDevicePath is already created, + // update the attributes/control. + // + Status = gBS->OpenProtocolInformation ( + Controller, + IoProtocolGuid, + &OpenInfoBuffer, + &EntryCount + ); + if (EFI_ERROR (Status)) { + return NULL; + } + + SerialDevices = AllocatePool (EntryCount * sizeof (SERIAL_DEV *)); + ASSERT (SerialDevices != NULL); + + *Count = 0; + OpenByDriver = FALSE; + for (Index = 0; Index < EntryCount; Index++) { + if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) { + Status = gBS->OpenProtocol ( + OpenInfoBuffer[Index].ControllerHandle, + &gEfiSerialIoProtocolGuid, + (VOID **) &SerialIo, + gSerialControllerDriver.DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + SerialDevices[(*Count)++] = SERIAL_DEV_FROM_THIS (SerialIo); + } + } + + + if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) { + ASSERT (OpenInfoBuffer[Index].AgentHandle == gSerialControllerDriver.DriverBindingHandle); + OpenByDriver = TRUE; + } + } + if (OpenInfoBuffer != NULL) { + FreePool (OpenInfoBuffer); + } + + ASSERT ((*Count == 0) || (OpenByDriver)); + + return SerialDevices; +} + +/** + Start to management the controller passed in + + @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param Controller The handle of the controller to test. + @param RemainingDevicePath A pointer to the remaining portion of a device path. + + @return EFI_SUCCESS Driver is started successfully +**/ +EFI_STATUS +EFIAPI +SerialControllerDriverStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + EFI_STATUS Status; + UINTN Index; + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; + EFI_DEVICE_PATH_PROTOCOL *Node; + EFI_SERIAL_IO_PROTOCOL *SerialIo; + UINT32 ControllerNumber; + UART_DEVICE_PATH *Uart; + UART_FLOW_CONTROL_DEVICE_PATH *FlowControl; + UINT32 Control; + PARENT_IO_PROTOCOL_PTR ParentIo; + ACPI_HID_DEVICE_PATH *Acpi; + EFI_GUID *IoProtocolGuid; + PCI_SERIAL_PARAMETER *PciSerialParameter; + PCI_SERIAL_PARAMETER DefaultPciSerialParameter; + PCI_TYPE00 Pci; + UINT32 PciSerialCount; + SERIAL_DEV **SerialDevices; + UINTN SerialDeviceCount; + PCI_DEVICE_INFO *PciDeviceInfo; + UINT64 Supports; + BOOLEAN ContainsControllerNode; + + // + // Get the Parent Device Path + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + (VOID **) &ParentDevicePath, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) { + return Status; + } + // + // Report status code enable the serial + // + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_PROGRESS_CODE, + EFI_P_PC_ENABLE | EFI_PERIPHERAL_SERIAL_PORT, + ParentDevicePath + ); + + // + // Grab the IO abstraction we need to get any work done + // + IoProtocolGuid = &gEfiSioProtocolGuid; + Status = gBS->OpenProtocol ( + Controller, + IoProtocolGuid, + (VOID **) &ParentIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) { + IoProtocolGuid = &gEfiPciIoProtocolGuid; + Status = gBS->OpenProtocol ( + Controller, + IoProtocolGuid, + (VOID **) &ParentIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + } + ASSERT (!EFI_ERROR (Status) || Status == EFI_ALREADY_STARTED); + + // + // Do nothing for END device path node + // + if ((RemainingDevicePath != NULL) && IsDevicePathEnd (RemainingDevicePath)) { + return EFI_SUCCESS; + } + + + SerialDevices = GetChildSerialDevices (Controller, IoProtocolGuid, &SerialDeviceCount); + // + // If the SerialIo instance specified by RemainingDevicePath is already created, + // update the attributes/control. + // + if ((SerialDeviceCount != 0) && (RemainingDevicePath != NULL)) { + Uart = (UART_DEVICE_PATH *) SkipControllerDevicePathNode (RemainingDevicePath, &ContainsControllerNode, &ControllerNumber); + for (Index = 0; Index < SerialDeviceCount; Index++) { + if ((!SerialDevices[Index]->ContainsControllerNode && !ContainsControllerNode) || + (SerialDevices[Index]->ContainsControllerNode && ContainsControllerNode && SerialDevices[Index]->Instance == ControllerNumber) + ) { + Status = EFI_INVALID_PARAMETER; + // + // Pass NULL ActualBaudRate to VerifyUartParameters to disallow baudrate degrade. + // DriverBindingStart() shouldn't create a handle with different UART device path. + // + if (VerifyUartParameters (SerialDevices[Index]->ClockRate, Uart->BaudRate, Uart->DataBits, + (EFI_PARITY_TYPE) Uart->Parity, (EFI_STOP_BITS_TYPE) Uart->StopBits, NULL, NULL)) { + SerialIo = &SerialDevices[Index]->SerialIo; + Status = SerialIo->SetAttributes ( + SerialIo, + Uart->BaudRate, + SerialIo->Mode->ReceiveFifoDepth, + SerialIo->Mode->Timeout, + (EFI_PARITY_TYPE) Uart->Parity, + Uart->DataBits, + (EFI_STOP_BITS_TYPE) Uart->StopBits + ); + } + FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (Uart); + if (!EFI_ERROR (Status) && IsUartFlowControlDevicePathNode (FlowControl)) { + Status = SerialIo->GetControl (SerialIo, &Control); + if (!EFI_ERROR (Status)) { + if (ReadUnaligned32 (&FlowControl->FlowControlMap) == UART_FLOW_CONTROL_HARDWARE) { + Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE; + } else { + Control &= ~EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE; + } + // + // Clear the bits that are not allowed to pass to SetControl + // + Control &= (EFI_SERIAL_REQUEST_TO_SEND | EFI_SERIAL_DATA_TERMINAL_READY | + EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE | EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE | + EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE); + Status = SerialIo->SetControl (SerialIo, Control); + } + } + break; + } + } + if (Index != SerialDeviceCount) { + // + // Directly return if the SerialIo instance specified by RemainingDevicePath is found and updated. + // Otherwise continue to create the instance specified by RemainingDevicePath. + // + if (SerialDevices != NULL) { + FreePool (SerialDevices); + } + return Status; + } + } + + if (RemainingDevicePath != NULL) { + Uart = (UART_DEVICE_PATH *) SkipControllerDevicePathNode (RemainingDevicePath, &ContainsControllerNode, &ControllerNumber); + } else { + Uart = NULL; + } + + PciDeviceInfo = NULL; + if (IoProtocolGuid == &gEfiSioProtocolGuid) { + Status = EFI_NOT_FOUND; + if (RemainingDevicePath == NULL || !ContainsControllerNode) { + Node = ParentDevicePath; + do { + Acpi = (ACPI_HID_DEVICE_PATH *) Node; + Node = NextDevicePathNode (Node); + } while (!IsDevicePathEnd (Node)); + Status = CreateSerialDevice (Controller, Uart, ParentDevicePath, FALSE, Acpi->UID, ParentIo, NULL, NULL); + DEBUG ((EFI_D_INFO, "PciSioSerial: Create SIO child serial device - %r\n", Status)); + } + } else { + Status = ParentIo.PciIo->Pci.Read (ParentIo.PciIo, EfiPciIoWidthUint8, 0, sizeof (Pci), &Pci); + if (!EFI_ERROR (Status)) { + // + // PcdPciSerialParameters takes the higher priority. + // + PciSerialCount = 0; + for (PciSerialParameter = PcdGetPtr (PcdPciSerialParameters); PciSerialParameter->VendorId != 0xFFFF; PciSerialParameter++) { + if ((PciSerialParameter->VendorId == Pci.Hdr.VendorId) && + (PciSerialParameter->DeviceId == Pci.Hdr.DeviceId) + ) { + PciSerialCount++; + } + } + + if (SerialDeviceCount == 0) { + // + // Enable the IO & MEM decoding when creating the first child. + // Restore the PCI attributes when all children is destroyed (PciDeviceInfo->ChildCount == 0). + // + PciDeviceInfo = AllocatePool (sizeof (PCI_DEVICE_INFO)); + PciDeviceInfo->ChildCount = 0; + PciDeviceInfo->PciIo = ParentIo.PciIo; + Status = ParentIo.PciIo->Attributes ( + ParentIo.PciIo, + EfiPciIoAttributeOperationGet, + 0, + &PciDeviceInfo->PciAttributes + ); + + if (!EFI_ERROR (Status)) { + Status = ParentIo.PciIo->Attributes ( + ParentIo.PciIo, + EfiPciIoAttributeOperationSupported, + 0, + &Supports + ); + if (!EFI_ERROR (Status)) { + Supports &= EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_MEMORY; + Status = ParentIo.PciIo->Attributes ( + ParentIo.PciIo, + EfiPciIoAttributeOperationEnable, + Supports, + NULL + ); + } + } + } else { + // + // Re-use the PciDeviceInfo stored in existing children. + // + PciDeviceInfo = SerialDevices[0]->PciDeviceInfo; + ASSERT (PciDeviceInfo != NULL); + } + + Status = EFI_NOT_FOUND; + if (PciSerialCount <= 1) { + // + // PCI serial device contains only one UART + // + if (RemainingDevicePath == NULL || !ContainsControllerNode) { + // + // This PCI serial device is matched by class code in Supported() + // + if (PciSerialCount == 0) { + DefaultPciSerialParameter.VendorId = Pci.Hdr.VendorId; + DefaultPciSerialParameter.DeviceId = Pci.Hdr.DeviceId; + DefaultPciSerialParameter.BarIndex = 0; + DefaultPciSerialParameter.Offset = 0; + DefaultPciSerialParameter.RegisterStride = 0; + DefaultPciSerialParameter.ClockRate = 0; + PciSerialParameter = &DefaultPciSerialParameter; + } else if (PciSerialCount == 1) { + PciSerialParameter = PcdGetPtr (PcdPciSerialParameters); + } + + Status = CreateSerialDevice (Controller, Uart, ParentDevicePath, FALSE, 0, ParentIo, PciSerialParameter, PciDeviceInfo); + DEBUG ((EFI_D_INFO, "PciSioSerial: Create PCI child serial device (single) - %r\n", Status)); + if (!EFI_ERROR (Status)) { + PciDeviceInfo->ChildCount++; + } + } + } else { + // + // PCI serial device contains multiple UARTs + // + if (RemainingDevicePath == NULL || ContainsControllerNode) { + PciSerialCount = 0; + for (PciSerialParameter = PcdGetPtr (PcdPciSerialParameters); PciSerialParameter->VendorId != 0xFFFF; PciSerialParameter++) { + if ((PciSerialParameter->VendorId == Pci.Hdr.VendorId) && + (PciSerialParameter->DeviceId == Pci.Hdr.DeviceId) && + ((RemainingDevicePath == NULL) || (ControllerNumber == PciSerialCount)) + ) { + // + // Create controller node when PCI serial device contains multiple UARTs + // + Status = CreateSerialDevice (Controller, Uart, ParentDevicePath, TRUE, PciSerialCount, ParentIo, PciSerialParameter, PciDeviceInfo); + PciSerialCount++; + DEBUG ((EFI_D_INFO, "PciSioSerial: Create PCI child serial device (multiple) - %r\n", Status)); + if (!EFI_ERROR (Status)) { + PciDeviceInfo->ChildCount++; + } + } + } + } + } + } + } + + if (SerialDevices != NULL) { + FreePool (SerialDevices); + } + + // + // For multiple PCI serial devices, set Status to SUCCESS if one child is created successfully + // + if ((PciDeviceInfo != NULL) && (PciDeviceInfo->ChildCount != 0)) { + Status = EFI_SUCCESS; + } + + if (EFI_ERROR (Status) && (SerialDeviceCount == 0)) { + if (PciDeviceInfo != NULL) { + Status = ParentIo.PciIo->Attributes ( + ParentIo.PciIo, + EfiPciIoAttributeOperationSet, + PciDeviceInfo->PciAttributes, + NULL + ); + ASSERT_EFI_ERROR (Status); + FreePool (PciDeviceInfo); + } + gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller + ); + gBS->CloseProtocol ( + Controller, + IoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + } + + return Status; +} + +/** + Disconnect this driver with the controller, uninstall related protocol instance + + @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param Controller The handle of the controller to test. + @param NumberOfChildren Number of child device. + @param ChildHandleBuffer A pointer to the remaining portion of a device path. + + @retval EFI_SUCCESS Operation successfully + @retval EFI_DEVICE_ERROR Cannot stop the driver successfully + +**/ +EFI_STATUS +EFIAPI +SerialControllerDriverStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) + +{ + EFI_STATUS Status; + UINTN Index; + BOOLEAN AllChildrenStopped; + EFI_SERIAL_IO_PROTOCOL *SerialIo; + SERIAL_DEV *SerialDevice; + VOID *IoProtocol; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + PCI_DEVICE_INFO *PciDeviceInfo; + + PciDeviceInfo = NULL; + + Status = gBS->HandleProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + (VOID **) &DevicePath + ); + + // + // Report the status code disable the serial + // + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_PROGRESS_CODE, + EFI_P_PC_DISABLE | EFI_PERIPHERAL_SERIAL_PORT, + DevicePath + ); + + if (NumberOfChildren == 0) { + // + // Close the bus driver + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + &IoProtocol, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + gBS->CloseProtocol ( + Controller, + !EFI_ERROR (Status) ? &gEfiPciIoProtocolGuid : &gEfiSioProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller + ); + return EFI_SUCCESS; + } + + AllChildrenStopped = TRUE; + + for (Index = 0; Index < NumberOfChildren; Index++) { + + Status = gBS->OpenProtocol ( + ChildHandleBuffer[Index], + &gEfiSerialIoProtocolGuid, + (VOID **) &SerialIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + + SerialDevice = SERIAL_DEV_FROM_THIS (SerialIo); + ASSERT ((PciDeviceInfo == NULL) || (PciDeviceInfo == SerialDevice->PciDeviceInfo)); + PciDeviceInfo = SerialDevice->PciDeviceInfo; + + Status = gBS->CloseProtocol ( + Controller, + PciDeviceInfo != NULL ? &gEfiPciIoProtocolGuid : &gEfiSioProtocolGuid, + This->DriverBindingHandle, + ChildHandleBuffer[Index] + ); + + Status = gBS->UninstallMultipleProtocolInterfaces ( + ChildHandleBuffer[Index], + &gEfiDevicePathProtocolGuid, SerialDevice->DevicePath, + &gEfiSerialIoProtocolGuid, &SerialDevice->SerialIo, + NULL + ); + if (EFI_ERROR (Status)) { + gBS->OpenProtocol ( + Controller, + PciDeviceInfo != NULL ? &gEfiPciIoProtocolGuid : &gEfiSioProtocolGuid, + &IoProtocol, + This->DriverBindingHandle, + ChildHandleBuffer[Index], + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + } else { + FreePool (SerialDevice->DevicePath); + FreeUnicodeStringTable (SerialDevice->ControllerNameTable); + FreePool (SerialDevice); + + if (PciDeviceInfo != NULL) { + ASSERT (PciDeviceInfo->ChildCount != 0); + PciDeviceInfo->ChildCount--; + } + } + } + + if (EFI_ERROR (Status)) { + AllChildrenStopped = FALSE; + } + } + + if (!AllChildrenStopped) { + return EFI_DEVICE_ERROR; + } else { + // + // If all children are destroyed, restore the PCI attributes. + // + if ((PciDeviceInfo != NULL) && (PciDeviceInfo->ChildCount == 0)) { + ASSERT (PciDeviceInfo->PciIo != NULL); + Status = PciDeviceInfo->PciIo->Attributes ( + PciDeviceInfo->PciIo, + EfiPciIoAttributeOperationSet, + PciDeviceInfo->PciAttributes, + NULL + ); + ASSERT_EFI_ERROR (Status); + FreePool (PciDeviceInfo); + } + return EFI_SUCCESS; + } +} diff --git a/MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.h b/MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.h new file mode 100644 index 000000000000..f147e6904462 --- /dev/null +++ b/MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.h @@ -0,0 +1,789 @@ +/** @file + Header file for PciSioSerial Driver + +Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _SERIAL_H_ +#define _SERIAL_H_ + + +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// +// Driver Binding Externs +// +extern EFI_DRIVER_BINDING_PROTOCOL gSerialControllerDriver; +extern EFI_COMPONENT_NAME_PROTOCOL gPciSioSerialComponentName; +extern EFI_COMPONENT_NAME2_PROTOCOL gPciSioSerialComponentName2; + +#define SIO_SERIAL_PORT_NAME L"SIO Serial Port #%d" +#define PCI_SERIAL_PORT_NAME L"PCI Serial Port #%d" +#define SERIAL_PORT_NAME_LEN (sizeof (SIO_SERIAL_PORT_NAME) / sizeof (CHAR16) + MAXIMUM_VALUE_CHARACTERS) + +// +// Internal Data Structures +// +#define TIMEOUT_STALL_INTERVAL 10 + +#pragma pack(1) +/// +/// PcdPciSerialParameters contains zero or more instances of the below structure. +/// If a PCI device contains multiple UARTs, PcdPciSerialParameters needs to contain +/// two instances of the below structure, with the VendorId and DeviceId equals to the +/// device ID and vendor ID of the device. If the PCI device uses the first two BARs +/// to support multiple UARTs, BarIndex of first instance equals to 0 and BarIndex of +/// second one equals to 1; if the PCI device uses the first BAR to support multiple +/// UARTs, BarIndex of both instance equals to 0 and Offset of first instance equals +/// to 0 while Offset of second one equals to some value bigger or equal to 8. +/// For certain UART whose register needs to be accessed in DWORD aligned address, +/// RegisterStride equals to 4. +/// +typedef struct { + UINT16 VendorId; ///< Vendor ID to match the PCI device. The value 0xFFFF terminates the list of entries. + UINT16 DeviceId; ///< Device ID to match the PCI device + UINT32 ClockRate; ///< UART clock rate. Set to 0 for default clock rate of 1843200 Hz + UINT64 Offset; ///< The byte offset into to the BAR + UINT8 BarIndex; ///< Which BAR to get the UART base address + UINT8 RegisterStride; ///< UART register stride in bytes. Set to 0 for default register stride of 1 byte. + UINT16 ReceiveFifoDepth; ///< UART receive FIFO depth in bytes. Set to 0 for a default FIFO depth of 16 bytes. + UINT16 TransmitFifoDepth; ///< UART transmit FIFO depth in bytes. Set to 0 for a default FIFO depth of 16 bytes. + UINT8 Reserved[2]; +} PCI_SERIAL_PARAMETER; +#pragma pack() + +#define SERIAL_MAX_FIFO_SIZE 17 ///< Actual FIFO size is 16. FIFO based on circular wastes one unit. +typedef struct { + UINT16 Head; ///< Head pointer of the FIFO. Empty when (Head == Tail). + UINT16 Tail; ///< Tail pointer of the FIFO. Full when ((Tail + 1) % SERIAL_MAX_FIFO_SIZE == Head). + UINT8 Data[SERIAL_MAX_FIFO_SIZE]; ///< Store the FIFO data. +} SERIAL_DEV_FIFO; + +typedef union { + EFI_PCI_IO_PROTOCOL *PciIo; + EFI_SIO_PROTOCOL *Sio; +} PARENT_IO_PROTOCOL_PTR; + +typedef struct { + EFI_PCI_IO_PROTOCOL *PciIo; // Pointer to parent PciIo instance. + UINTN ChildCount; // Count of child SerialIo instance. + UINT64 PciAttributes; // Original PCI attributes. +} PCI_DEVICE_INFO; + +typedef struct { + UINT32 Signature; + EFI_HANDLE Handle; + EFI_SERIAL_IO_PROTOCOL SerialIo; + EFI_SERIAL_IO_MODE SerialMode; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; + UART_DEVICE_PATH UartDevicePath; + + EFI_PHYSICAL_ADDRESS BaseAddress; ///< UART base address + BOOLEAN MmioAccess; ///< TRUE for MMIO, FALSE for IO + UINT8 RegisterStride; ///< UART Register Stride + UINT32 ClockRate; ///< UART clock rate + + UINT16 ReceiveFifoDepth; ///< UART receive FIFO depth in bytes. + SERIAL_DEV_FIFO Receive; ///< The FIFO used to store received data + + UINT16 TransmitFifoDepth; ///< UART transmit FIFO depth in bytes. + SERIAL_DEV_FIFO Transmit; ///< The FIFO used to store to-transmit data + + BOOLEAN SoftwareLoopbackEnable; + BOOLEAN HardwareFlowControl; + EFI_UNICODE_STRING_TABLE *ControllerNameTable; + BOOLEAN ContainsControllerNode; ///< TRUE if the device produced contains Controller node + UINT32 Instance; + PCI_DEVICE_INFO *PciDeviceInfo; +} SERIAL_DEV; + +#define SERIAL_DEV_SIGNATURE SIGNATURE_32 ('s', 'e', 'r', 'd') +#define SERIAL_DEV_FROM_THIS(a) CR (a, SERIAL_DEV, SerialIo, SERIAL_DEV_SIGNATURE) + +// +// Serial Driver Defaults +// +#define SERIAL_PORT_DEFAULT_TIMEOUT 1000000 +#define SERIAL_PORT_SUPPORT_CONTROL_MASK (EFI_SERIAL_CLEAR_TO_SEND | \ + EFI_SERIAL_DATA_SET_READY | \ + EFI_SERIAL_RING_INDICATE | \ + EFI_SERIAL_CARRIER_DETECT | \ + EFI_SERIAL_REQUEST_TO_SEND | \ + EFI_SERIAL_DATA_TERMINAL_READY | \ + EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE | \ + EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE | \ + EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE | \ + EFI_SERIAL_OUTPUT_BUFFER_EMPTY | \ + EFI_SERIAL_INPUT_BUFFER_EMPTY) + +#define SERIAL_PORT_MIN_TIMEOUT 1 // 1 uS +#define SERIAL_PORT_MAX_TIMEOUT 100000000 // 100 seconds +// +// UART Registers +// +#define SERIAL_REGISTER_THR 0 ///< WO Transmit Holding Register +#define SERIAL_REGISTER_RBR 0 ///< RO Receive Buffer Register +#define SERIAL_REGISTER_DLL 0 ///< R/W Divisor Latch LSB +#define SERIAL_REGISTER_DLM 1 ///< R/W Divisor Latch MSB +#define SERIAL_REGISTER_IER 1 ///< R/W Interrupt Enable Register +#define SERIAL_REGISTER_IIR 2 ///< RO Interrupt Identification Register +#define SERIAL_REGISTER_FCR 2 ///< WO FIFO Cotrol Register +#define SERIAL_REGISTER_LCR 3 ///< R/W Line Control Register +#define SERIAL_REGISTER_MCR 4 ///< R/W Modem Control Register +#define SERIAL_REGISTER_LSR 5 ///< R/W Line Status Register +#define SERIAL_REGISTER_MSR 6 ///< R/W Modem Status Register +#define SERIAL_REGISTER_SCR 7 ///< R/W Scratch Pad Register +#pragma pack(1) + +/// +/// Interrupt Enable Register +/// +typedef union { + struct { + UINT8 Ravie : 1; ///< Receiver Data Available Interrupt Enable + UINT8 Theie : 1; ///< Transmistter Holding Register Empty Interrupt Enable + UINT8 Rie : 1; ///< Receiver Interrupt Enable + UINT8 Mie : 1; ///< Modem Interrupt Enable + UINT8 Reserved : 4; + } Bits; + UINT8 Data; +} SERIAL_PORT_IER; + +/// +/// FIFO Control Register +/// +typedef union { + struct { + UINT8 TrFIFOE : 1; ///< Transmit and Receive FIFO Enable + UINT8 ResetRF : 1; ///< Reset Reciever FIFO + UINT8 ResetTF : 1; ///< Reset Transmistter FIFO + UINT8 Dms : 1; ///< DMA Mode Select + UINT8 Reserved : 1; + UINT8 TrFIFO64 : 1; ///< Enable 64 byte FIFO + UINT8 Rtb : 2; ///< Receive Trigger Bits + } Bits; + UINT8 Data; +} SERIAL_PORT_FCR; + +/// +/// Line Control Register +/// +typedef union { + struct { + UINT8 SerialDB : 2; ///< Number of Serial Data Bits + UINT8 StopB : 1; ///< Number of Stop Bits + UINT8 ParEn : 1; ///< Parity Enable + UINT8 EvenPar : 1; ///< Even Parity Select + UINT8 SticPar : 1; ///< Sticky Parity + UINT8 BrCon : 1; ///< Break Control + UINT8 DLab : 1; ///< Divisor Latch Access Bit + } Bits; + UINT8 Data; +} SERIAL_PORT_LCR; + +/// +/// Modem Control Register +/// +typedef union { + struct { + UINT8 DtrC : 1; ///< Data Terminal Ready Control + UINT8 Rts : 1; ///< Request To Send Control + UINT8 Out1 : 1; ///< Output1 + UINT8 Out2 : 1; ///< Output2, used to disable interrupt + UINT8 Lme : 1; ///< Loopback Mode Enable + UINT8 Reserved : 3; + } Bits; + UINT8 Data; +} SERIAL_PORT_MCR; + +/// +/// Line Status Register +/// +typedef union { + struct { + UINT8 Dr : 1; ///< Receiver Data Ready Status + UINT8 Oe : 1; ///< Overrun Error Status + UINT8 Pe : 1; ///< Parity Error Status + UINT8 Fe : 1; ///< Framing Error Status + UINT8 Bi : 1; ///< Break Interrupt Status + UINT8 Thre : 1; ///< Transmistter Holding Register Status + UINT8 Temt : 1; ///< Transmitter Empty Status + UINT8 FIFOe : 1; ///< FIFO Error Status + } Bits; + UINT8 Data; +} SERIAL_PORT_LSR; + +/// +/// Modem Status Register +/// +typedef union { + struct { + UINT8 DeltaCTS : 1; ///< Delta Clear To Send Status + UINT8 DeltaDSR : 1; ///< Delta Data Set Ready Status + UINT8 TrailingEdgeRI : 1; ///< Trailing Edge of Ring Indicator Status + UINT8 DeltaDCD : 1; ///< Delta Data Carrier Detect Status + UINT8 Cts : 1; ///< Clear To Send Status + UINT8 Dsr : 1; ///< Data Set Ready Status + UINT8 Ri : 1; ///< Ring Indicator Status + UINT8 Dcd : 1; ///< Data Carrier Detect Status + } Bits; + UINT8 Data; +} SERIAL_PORT_MSR; + +#pragma pack() +// +// Define serial register I/O macros +// +#define READ_RBR(S) SerialReadRegister (S, SERIAL_REGISTER_RBR) +#define READ_DLL(S) SerialReadRegister (S, SERIAL_REGISTER_DLL) +#define READ_DLM(S) SerialReadRegister (S, SERIAL_REGISTER_DLM) +#define READ_IER(S) SerialReadRegister (S, SERIAL_REGISTER_IER) +#define READ_IIR(S) SerialReadRegister (S, SERIAL_REGISTER_IIR) +#define READ_LCR(S) SerialReadRegister (S, SERIAL_REGISTER_LCR) +#define READ_MCR(S) SerialReadRegister (S, SERIAL_REGISTER_MCR) +#define READ_LSR(S) SerialReadRegister (S, SERIAL_REGISTER_LSR) +#define READ_MSR(S) SerialReadRegister (S, SERIAL_REGISTER_MSR) +#define READ_SCR(S) SerialReadRegister (S, SERIAL_REGISTER_SCR) + +#define WRITE_THR(S, D) SerialWriteRegister (S, SERIAL_REGISTER_THR, D) +#define WRITE_DLL(S, D) SerialWriteRegister (S, SERIAL_REGISTER_DLL, D) +#define WRITE_DLM(S, D) SerialWriteRegister (S, SERIAL_REGISTER_DLM, D) +#define WRITE_IER(S, D) SerialWriteRegister (S, SERIAL_REGISTER_IER, D) +#define WRITE_FCR(S, D) SerialWriteRegister (S, SERIAL_REGISTER_FCR, D) +#define WRITE_LCR(S, D) SerialWriteRegister (S, SERIAL_REGISTER_LCR, D) +#define WRITE_MCR(S, D) SerialWriteRegister (S, SERIAL_REGISTER_MCR, D) +#define WRITE_LSR(S, D) SerialWriteRegister (S, SERIAL_REGISTER_LSR, D) +#define WRITE_MSR(S, D) SerialWriteRegister (S, SERIAL_REGISTER_MSR, D) +#define WRITE_SCR(S, D) SerialWriteRegister (S, SERIAL_REGISTER_SCR, D) + +// +// Prototypes +// Driver model protocol interface +// +/** + Check to see if this driver supports the given controller + + @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param Controller The handle of the controller to test. + @param RemainingDevicePath A pointer to the remaining portion of a device path. + + @return EFI_SUCCESS This driver can support the given controller + +**/ +EFI_STATUS +EFIAPI +SerialControllerDriverSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +/** + Start to management the controller passed in + + @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param Controller The handle of the controller to test. + @param RemainingDevicePath A pointer to the remaining portion of a device path. + + @return EFI_SUCCESS Driver is started successfully +**/ +EFI_STATUS +EFIAPI +SerialControllerDriverStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +/** + Disconnect this driver with the controller, uninstall related protocol instance + + @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param Controller The handle of the controller to test. + @param NumberOfChildren Number of child device. + @param ChildHandleBuffer A pointer to the remaining portion of a device path. + + @retval EFI_SUCCESS Operation successfully + @retval EFI_DEVICE_ERROR Cannot stop the driver successfully + +**/ +EFI_STATUS +EFIAPI +SerialControllerDriverStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +// +// Serial I/O Protocol Interface +// +/** + Reset serial device. + + @param This Pointer to EFI_SERIAL_IO_PROTOCOL + + @retval EFI_SUCCESS Reset successfully + @retval EFI_DEVICE_ERROR Failed to reset + +**/ +EFI_STATUS +EFIAPI +SerialReset ( + IN EFI_SERIAL_IO_PROTOCOL *This + ); + +/** + Set new attributes to a serial device. + + @param This Pointer to EFI_SERIAL_IO_PROTOCOL + @param BaudRate The baudrate of the serial device + @param ReceiveFifoDepth The depth of receive FIFO buffer + @param Timeout The request timeout for a single char + @param Parity The type of parity used in serial device + @param DataBits Number of databits used in serial device + @param StopBits Number of stopbits used in serial device + + @retval EFI_SUCCESS The new attributes were set + @retval EFI_INVALID_PARAMETERS One or more attributes have an unsupported value + @retval EFI_UNSUPPORTED Data Bits can not set to 5 or 6 + @retval EFI_DEVICE_ERROR The serial device is not functioning correctly (no return) + +**/ +EFI_STATUS +EFIAPI +SerialSetAttributes ( + IN EFI_SERIAL_IO_PROTOCOL *This, + IN UINT64 BaudRate, + IN UINT32 ReceiveFifoDepth, + IN UINT32 Timeout, + IN EFI_PARITY_TYPE Parity, + IN UINT8 DataBits, + IN EFI_STOP_BITS_TYPE StopBits + ); + +/** + Set Control Bits. + + @param This Pointer to EFI_SERIAL_IO_PROTOCOL + @param Control Control bits that can be settable + + @retval EFI_SUCCESS New Control bits were set successfully + @retval EFI_UNSUPPORTED The Control bits wanted to set are not supported + +**/ +EFI_STATUS +EFIAPI +SerialSetControl ( + IN EFI_SERIAL_IO_PROTOCOL *This, + IN UINT32 Control + ); + +/** + Get ControlBits. + + @param This Pointer to EFI_SERIAL_IO_PROTOCOL + @param Control Control signals of the serial device + + @retval EFI_SUCCESS Get Control signals successfully + +**/ +EFI_STATUS +EFIAPI +SerialGetControl ( + IN EFI_SERIAL_IO_PROTOCOL *This, + OUT UINT32 *Control + ); + +/** + Write the specified number of bytes to serial device. + + @param This Pointer to EFI_SERIAL_IO_PROTOCOL + @param BufferSize On input the size of Buffer, on output the amount of + data actually written + @param Buffer The buffer of data to write + + @retval EFI_SUCCESS The data were written successfully + @retval EFI_DEVICE_ERROR The device reported an error + @retval EFI_TIMEOUT The write operation was stopped due to timeout + +**/ +EFI_STATUS +EFIAPI +SerialWrite ( + IN EFI_SERIAL_IO_PROTOCOL *This, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + ); + +/** + Read the specified number of bytes from serial device. + + @param This Pointer to EFI_SERIAL_IO_PROTOCOL + @param BufferSize On input the size of Buffer, on output the amount of + data returned in buffer + @param Buffer The buffer to return the data into + + @retval EFI_SUCCESS The data were read successfully + @retval EFI_DEVICE_ERROR The device reported an error + @retval EFI_TIMEOUT The read operation was stopped due to timeout + +**/ +EFI_STATUS +EFIAPI +SerialRead ( + IN EFI_SERIAL_IO_PROTOCOL *This, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ); + +// +// Internal Functions +// +/** + Use scratchpad register to test if this serial port is present. + + @param SerialDevice Pointer to serial device structure + + @return if this serial port is present +**/ +BOOLEAN +SerialPresent ( + IN SERIAL_DEV *SerialDevice + ); + +/** + Detect whether specific FIFO is full or not. + + @param Fifo A pointer to the Data Structure SERIAL_DEV_FIFO + + @return whether specific FIFO is full or not + +**/ +BOOLEAN +SerialFifoFull ( + IN SERIAL_DEV_FIFO *Fifo + ); + +/** + Detect whether specific FIFO is empty or not. + + @param Fifo A pointer to the Data Structure SERIAL_DEV_FIFO + + @return whether specific FIFO is empty or not + +**/ +BOOLEAN +SerialFifoEmpty ( + IN SERIAL_DEV_FIFO *Fifo + ); + +/** + Add data to specific FIFO. + + @param Fifo A pointer to the Data Structure SERIAL_DEV_FIFO + @param Data the data added to FIFO + + @retval EFI_SUCCESS Add data to specific FIFO successfully + @retval EFI_OUT_OF_RESOURCE Failed to add data because FIFO is already full + +**/ +EFI_STATUS +SerialFifoAdd ( + IN SERIAL_DEV_FIFO *Fifo, + IN UINT8 Data + ); + +/** + Remove data from specific FIFO. + + @param Fifo A pointer to the Data Structure SERIAL_DEV_FIFO + @param Data the data removed from FIFO + + @retval EFI_SUCCESS Remove data from specific FIFO successfully + @retval EFI_OUT_OF_RESOURCE Failed to remove data because FIFO is empty + +**/ +EFI_STATUS +SerialFifoRemove ( + IN SERIAL_DEV_FIFO *Fifo, + OUT UINT8 *Data + ); + +/** + Reads and writes all avaliable data. + + @param SerialDevice The device to flush + + @retval EFI_SUCCESS Data was read/written successfully. + @retval EFI_OUT_OF_RESOURCE Failed because software receive FIFO is full. Note, when + this happens, pending writes are not done. + +**/ +EFI_STATUS +SerialReceiveTransmit ( + IN SERIAL_DEV *SerialDevice + ); + +/** + Read serial port. + + @param SerialDev Pointer to serial device + @param Offset Offset in register group + + @return Data read from serial port +**/ +UINT8 +SerialReadRegister ( + IN SERIAL_DEV *SerialDev, + IN UINT32 Offset + ); + +/** + Write serial port. + + @param SerialDev Pointer to serial device + @param Offset Offset in register group + @param Data data which is to be written to some serial port register +**/ +VOID +SerialWriteRegister ( + IN SERIAL_DEV *SerialDev, + IN UINT32 Offset, + IN UINT8 Data + ); + + +// +// EFI Component Name Functions +// +/** + Retrieves a Unicode string that is the user readable name of the driver. + + This function retrieves the user readable name of a driver in the form of a + Unicode string. If the driver specified by This has a user readable name in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified + in RFC 4646 or ISO 639-2 language code format. + + @param DriverName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by + This and the language specified by Language was + returned in DriverName. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER DriverName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +SerialComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by a driver. + + This function retrieves the user readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param ControllerHandle[in] The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + + @param ChildHandle[in] The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 4646 or ISO 639-2 language code format. + + @param ControllerName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + + @retval EFI_INVALID_PARAMETER ControllerHandle is NULL. + + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +SerialComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + +/** + Add the component name for the serial io device + + @param SerialDevice A pointer to the SERIAL_DEV instance. + @param Uid Unique ID for the serial device. +**/ +VOID +AddName ( + IN SERIAL_DEV *SerialDevice, + IN UINT32 Uid + ); + +/** + Checks whether the UART parameters are valid and computes the Divisor. + + @param ClockRate The clock rate of the serial device used to verify + the BaudRate. Do not verify the BaudRate if it's 0. + @param BaudRate The requested baudrate of the serial device. + @param DataBits Number of databits used in serial device. + @param Parity The type of parity used in serial device. + @param StopBits Number of stopbits used in serial device. + @param Divisor Return the divisor if ClockRate is not 0. + @param ActualBaudRate Return the actual supported baudrate without + exceeding BaudRate. NULL means baudrate degradation + is not allowed. + If the requested BaudRate is not supported, the routine + returns TRUE and the Actual Baud Rate when ActualBaudRate + is not NULL, returns FALSE when ActualBaudRate is NULL. + + @retval TRUE The UART parameters are valid. + @retval FALSE The UART parameters are not valid. +**/ +BOOLEAN +VerifyUartParameters ( + IN UINT32 ClockRate, + IN UINT64 BaudRate, + IN UINT8 DataBits, + IN EFI_PARITY_TYPE Parity, + IN EFI_STOP_BITS_TYPE StopBits, + OUT UINT64 *Divisor, + OUT UINT64 *ActualBaudRate + ); + +/** + Skip the optional Controller device path node and return the + pointer to the next device path node. + + @param DevicePath Pointer to the device path. + @param ContainsControllerNode Returns TRUE if the Controller device path exists. + @param ControllerNumber Returns the Controller Number if Controller device path exists. + + @return Pointer to the next device path node. +**/ +UART_DEVICE_PATH * +SkipControllerDevicePathNode ( + EFI_DEVICE_PATH_PROTOCOL *DevicePath, + BOOLEAN *ContainsControllerNode, + UINT32 *ControllerNumber + ); + +/** + Check the device path node whether it's the Flow Control node or not. + + @param[in] FlowControl The device path node to be checked. + + @retval TRUE It's the Flow Control node. + @retval FALSE It's not. + +**/ +BOOLEAN +IsUartFlowControlDevicePathNode ( + IN UART_FLOW_CONTROL_DEVICE_PATH *FlowControl + ); +#endif diff --git a/MdeModulePkg/Bus/Pci/PciSioSerialDxe/SerialIo.c b/MdeModulePkg/Bus/Pci/PciSioSerialDxe/SerialIo.c new file mode 100644 index 000000000000..f1870f3a1bed --- /dev/null +++ b/MdeModulePkg/Bus/Pci/PciSioSerialDxe/SerialIo.c @@ -0,0 +1,1320 @@ +/** @file + SerialIo implementation for PCI or SIO UARTs. + +Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "Serial.h" + +/** + Skip the optional Controller device path node and return the + pointer to the next device path node. + + @param DevicePath Pointer to the device path. + @param ContainsControllerNode Returns TRUE if the Controller device path exists. + @param ControllerNumber Returns the Controller Number if Controller device path exists. + + @return Pointer to the next device path node. +**/ +UART_DEVICE_PATH * +SkipControllerDevicePathNode ( + EFI_DEVICE_PATH_PROTOCOL *DevicePath, + BOOLEAN *ContainsControllerNode, + UINT32 *ControllerNumber + ) +{ + if ((DevicePathType (DevicePath) == HARDWARE_DEVICE_PATH) && + (DevicePathSubType (DevicePath) == HW_CONTROLLER_DP) + ) { + if (ContainsControllerNode != NULL) { + *ContainsControllerNode = TRUE; + } + if (ControllerNumber != NULL) { + *ControllerNumber = ((CONTROLLER_DEVICE_PATH *) DevicePath)->ControllerNumber; + } + DevicePath = NextDevicePathNode (DevicePath); + } else { + if (ContainsControllerNode != NULL) { + *ContainsControllerNode = FALSE; + } + } + return (UART_DEVICE_PATH *) DevicePath; +} + +/** + Checks whether the UART parameters are valid and computes the Divisor. + + @param ClockRate The clock rate of the serial device used to verify + the BaudRate. Do not verify the BaudRate if it's 0. + @param BaudRate The requested baudrate of the serial device. + @param DataBits Number of databits used in serial device. + @param Parity The type of parity used in serial device. + @param StopBits Number of stopbits used in serial device. + @param Divisor Return the divisor if ClockRate is not 0. + @param ActualBaudRate Return the actual supported baudrate without + exceeding BaudRate. NULL means baudrate degradation + is not allowed. + If the requested BaudRate is not supported, the routine + returns TRUE and the Actual Baud Rate when ActualBaudRate + is not NULL, returns FALSE when ActualBaudRate is NULL. + + @retval TRUE The UART parameters are valid. + @retval FALSE The UART parameters are not valid. +**/ +BOOLEAN +VerifyUartParameters ( + IN UINT32 ClockRate, + IN UINT64 BaudRate, + IN UINT8 DataBits, + IN EFI_PARITY_TYPE Parity, + IN EFI_STOP_BITS_TYPE StopBits, + OUT UINT64 *Divisor, + OUT UINT64 *ActualBaudRate + ) +{ + UINT64 Remainder; + UINT32 ComputedBaudRate; + UINT64 ComputedDivisor; + UINT64 Percent; + + if ((DataBits < 5) || (DataBits > 8) || + (Parity < NoParity) || (Parity > SpaceParity) || + (StopBits < OneStopBit) || (StopBits > TwoStopBits) || + ((DataBits == 5) && (StopBits == TwoStopBits)) || + ((DataBits >= 6) && (DataBits <= 8) && (StopBits == OneFiveStopBits)) + ) { + return FALSE; + } + + // + // Do not verify the baud rate if clock rate is unknown (0). + // + if (ClockRate == 0) { + return TRUE; + } + + // + // Compute divisor use to program the baud rate using a round determination + // Divisor = ClockRate / 16 / BaudRate = ClockRate / (16 * BaudRate) + // = ClockRate / (BaudRate << 4) + // + ComputedDivisor = DivU64x64Remainder (ClockRate, LShiftU64 (BaudRate, 4), &Remainder); + // + // Round Divisor up by 1 if the Remainder is more than half (16 * BaudRate) + // BaudRate * 16 / 2 = BaudRate * 8 = (BaudRate << 3) + // + if (Remainder >= LShiftU64 (BaudRate, 3)) { + ComputedDivisor++; + } + // + // If the computed divisor is larger than the maximum value that can be programmed + // into the UART, then the requested baud rate can not be supported. + // + if (ComputedDivisor > MAX_UINT16) { + return FALSE; + } + + // + // If the computed divisor is 0, then use a computed divisor of 1, which will select + // the maximum supported baud rate. + // + if (ComputedDivisor == 0) { + ComputedDivisor = 1; + } + + // + // Actual baud rate that the serial port will be programmed for + // should be with in 4% of requested one. + // + ComputedBaudRate = ClockRate / ((UINT16) ComputedDivisor << 4); + if (ComputedBaudRate == 0) { + return FALSE; + } + + Percent = DivU64x32 (MultU64x32 (BaudRate, 100), ComputedBaudRate); + DEBUG ((EFI_D_INFO, "ClockRate = %d\n", ClockRate)); + DEBUG ((EFI_D_INFO, "Divisor = %ld\n", ComputedDivisor)); + DEBUG ((EFI_D_INFO, "BaudRate/Actual (%ld/%d) = %d%%\n", BaudRate, ComputedBaudRate, Percent)); + + // + // If the requested BaudRate is not supported: + // Returns TRUE and the Actual Baud Rate when ActualBaudRate is not NULL; + // Returns FALSE when ActualBaudRate is NULL. + // + if ((Percent >= 96) && (Percent <= 104)) { + if (ActualBaudRate != NULL) { + *ActualBaudRate = BaudRate; + } + if (Divisor != NULL) { + *Divisor = ComputedDivisor; + } + return TRUE; + } + if (ComputedBaudRate < BaudRate) { + if (ActualBaudRate != NULL) { + *ActualBaudRate = ComputedBaudRate; + } + if (Divisor != NULL) { + *Divisor = ComputedDivisor; + } + return TRUE; + } + + // + // ActualBaudRate is higher than requested baud rate and more than 4% + // higher than the requested value. Increment Divisor if it is less + // than MAX_UINT16 and computed baud rate with new divisor. + // + if (ComputedDivisor == MAX_UINT16) { + return FALSE; + } + ComputedDivisor++; + ComputedBaudRate = ClockRate / ((UINT16) ComputedDivisor << 4); + if (ComputedBaudRate == 0) { + return FALSE; + } + + DEBUG ((EFI_D_INFO, "ClockRate = %d\n", ClockRate)); + DEBUG ((EFI_D_INFO, "Divisor = %ld\n", ComputedDivisor)); + DEBUG ((EFI_D_INFO, "BaudRate/Actual (%ld/%d) = %d%%\n", BaudRate, ComputedBaudRate, Percent)); + + if (ActualBaudRate != NULL) { + *ActualBaudRate = ComputedBaudRate; + } + if (Divisor != NULL) { + *Divisor = ComputedDivisor; + } + return TRUE; +} + +/** + Detect whether specific FIFO is full or not. + + @param Fifo A pointer to the Data Structure SERIAL_DEV_FIFO + + @return whether specific FIFO is full or not +**/ +BOOLEAN +SerialFifoFull ( + IN SERIAL_DEV_FIFO *Fifo + ) +{ + return (BOOLEAN) (((Fifo->Tail + 1) % SERIAL_MAX_FIFO_SIZE) == Fifo->Head); +} + +/** + Detect whether specific FIFO is empty or not. + + @param Fifo A pointer to the Data Structure SERIAL_DEV_FIFO + + @return whether specific FIFO is empty or not +**/ +BOOLEAN +SerialFifoEmpty ( + IN SERIAL_DEV_FIFO *Fifo + ) + +{ + return (BOOLEAN) (Fifo->Head == Fifo->Tail); +} + +/** + Add data to specific FIFO. + + @param Fifo A pointer to the Data Structure SERIAL_DEV_FIFO + @param Data the data added to FIFO + + @retval EFI_SUCCESS Add data to specific FIFO successfully + @retval EFI_OUT_OF_RESOURCE Failed to add data because FIFO is already full +**/ +EFI_STATUS +SerialFifoAdd ( + IN OUT SERIAL_DEV_FIFO *Fifo, + IN UINT8 Data + ) +{ + // + // if FIFO full can not add data + // + if (SerialFifoFull (Fifo)) { + return EFI_OUT_OF_RESOURCES; + } + // + // FIFO is not full can add data + // + Fifo->Data[Fifo->Tail] = Data; + Fifo->Tail = (Fifo->Tail + 1) % SERIAL_MAX_FIFO_SIZE; + return EFI_SUCCESS; +} + +/** + Remove data from specific FIFO. + + @param Fifo A pointer to the Data Structure SERIAL_DEV_FIFO + @param Data the data removed from FIFO + + @retval EFI_SUCCESS Remove data from specific FIFO successfully + @retval EFI_OUT_OF_RESOURCE Failed to remove data because FIFO is empty + +**/ +EFI_STATUS +SerialFifoRemove ( + IN OUT SERIAL_DEV_FIFO *Fifo, + OUT UINT8 *Data + ) +{ + // + // if FIFO is empty, no data can remove + // + if (SerialFifoEmpty (Fifo)) { + return EFI_OUT_OF_RESOURCES; + } + // + // FIFO is not empty, can remove data + // + *Data = Fifo->Data[Fifo->Head]; + Fifo->Head = (Fifo->Head + 1) % SERIAL_MAX_FIFO_SIZE; + return EFI_SUCCESS; +} + +/** + Reads and writes all avaliable data. + + @param SerialDevice The device to transmit. + + @retval EFI_SUCCESS Data was read/written successfully. + @retval EFI_OUT_OF_RESOURCE Failed because software receive FIFO is full. Note, when + this happens, pending writes are not done. + +**/ +EFI_STATUS +SerialReceiveTransmit ( + IN SERIAL_DEV *SerialDevice + ) + +{ + SERIAL_PORT_LSR Lsr; + UINT8 Data; + BOOLEAN ReceiveFifoFull; + SERIAL_PORT_MSR Msr; + SERIAL_PORT_MCR Mcr; + UINTN TimeOut; + + Data = 0; + + // + // Begin the read or write + // + if (SerialDevice->SoftwareLoopbackEnable) { + do { + ReceiveFifoFull = SerialFifoFull (&SerialDevice->Receive); + if (!SerialFifoEmpty (&SerialDevice->Transmit)) { + SerialFifoRemove (&SerialDevice->Transmit, &Data); + if (ReceiveFifoFull) { + return EFI_OUT_OF_RESOURCES; + } + + SerialFifoAdd (&SerialDevice->Receive, Data); + } + } while (!SerialFifoEmpty (&SerialDevice->Transmit)); + } else { + ReceiveFifoFull = SerialFifoFull (&SerialDevice->Receive); + // + // For full handshake flow control, tell the peer to send data + // if receive buffer is available. + // + if (SerialDevice->HardwareFlowControl && + !FeaturePcdGet(PcdSerialUseHalfHandshake)&& + !ReceiveFifoFull + ) { + Mcr.Data = READ_MCR (SerialDevice); + Mcr.Bits.Rts = 1; + WRITE_MCR (SerialDevice, Mcr.Data); + } + do { + Lsr.Data = READ_LSR (SerialDevice); + + // + // Flush incomming data to prevent a an overrun during a long write + // + if ((Lsr.Bits.Dr == 1) && !ReceiveFifoFull) { + ReceiveFifoFull = SerialFifoFull (&SerialDevice->Receive); + if (!ReceiveFifoFull) { + if (Lsr.Bits.FIFOe == 1 || Lsr.Bits.Oe == 1 || Lsr.Bits.Pe == 1 || Lsr.Bits.Fe == 1 || Lsr.Bits.Bi == 1) { + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_ERROR_CODE, + EFI_P_EC_INPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT, + SerialDevice->DevicePath + ); + if (Lsr.Bits.FIFOe == 1 || Lsr.Bits.Pe == 1|| Lsr.Bits.Fe == 1 || Lsr.Bits.Bi == 1) { + Data = READ_RBR (SerialDevice); + continue; + } + } + + Data = READ_RBR (SerialDevice); + + SerialFifoAdd (&SerialDevice->Receive, Data); + + // + // For full handshake flow control, if receive buffer full + // tell the peer to stop sending data. + // + if (SerialDevice->HardwareFlowControl && + !FeaturePcdGet(PcdSerialUseHalfHandshake) && + SerialFifoFull (&SerialDevice->Receive) + ) { + Mcr.Data = READ_MCR (SerialDevice); + Mcr.Bits.Rts = 0; + WRITE_MCR (SerialDevice, Mcr.Data); + } + + + continue; + } else { + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_PROGRESS_CODE, + EFI_P_SERIAL_PORT_PC_CLEAR_BUFFER | EFI_PERIPHERAL_SERIAL_PORT, + SerialDevice->DevicePath + ); + } + } + // + // Do the write + // + if (Lsr.Bits.Thre == 1 && !SerialFifoEmpty (&SerialDevice->Transmit)) { + // + // Make sure the transmit data will not be missed + // + if (SerialDevice->HardwareFlowControl) { + // + // For half handshake flow control assert RTS before sending. + // + if (FeaturePcdGet(PcdSerialUseHalfHandshake)) { + Mcr.Data = READ_MCR (SerialDevice); + Mcr.Bits.Rts= 0; + WRITE_MCR (SerialDevice, Mcr.Data); + } + // + // Wait for CTS + // + TimeOut = 0; + Msr.Data = READ_MSR (SerialDevice); + while ((Msr.Bits.Dcd == 1) && ((Msr.Bits.Cts == 0) ^ FeaturePcdGet(PcdSerialUseHalfHandshake))) { + gBS->Stall (TIMEOUT_STALL_INTERVAL); + TimeOut++; + if (TimeOut > 5) { + break; + } + + Msr.Data = READ_MSR (SerialDevice); + } + + if ((Msr.Bits.Dcd == 0) || ((Msr.Bits.Cts == 1) ^ FeaturePcdGet(PcdSerialUseHalfHandshake))) { + SerialFifoRemove (&SerialDevice->Transmit, &Data); + WRITE_THR (SerialDevice, Data); + } + + // + // For half handshake flow control, tell DCE we are done. + // + if (FeaturePcdGet(PcdSerialUseHalfHandshake)) { + Mcr.Data = READ_MCR (SerialDevice); + Mcr.Bits.Rts = 1; + WRITE_MCR (SerialDevice, Mcr.Data); + } + } else { + SerialFifoRemove (&SerialDevice->Transmit, &Data); + WRITE_THR (SerialDevice, Data); + } + } + } while (Lsr.Bits.Thre == 1 && !SerialFifoEmpty (&SerialDevice->Transmit)); + } + + return EFI_SUCCESS; +} + +/** + Flush the serial hardware transmit FIFO and shift register. + + @param SerialDevice The device to flush. +**/ +VOID +SerialFlushTransmitFifo ( + SERIAL_DEV *SerialDevice + ) +{ + SERIAL_PORT_LSR Lsr; + + // + // Wait for the serial port to be ready, to make sure both the transmit FIFO + // and shift register empty. + // + do { + Lsr.Data = READ_LSR (SerialDevice); + } while (Lsr.Bits.Temt == 0); +} + +// +// Interface Functions +// +/** + Reset serial device. + + @param This Pointer to EFI_SERIAL_IO_PROTOCOL + + @retval EFI_SUCCESS Reset successfully + @retval EFI_DEVICE_ERROR Failed to reset + +**/ +EFI_STATUS +EFIAPI +SerialReset ( + IN EFI_SERIAL_IO_PROTOCOL *This + ) +{ + EFI_STATUS Status; + SERIAL_DEV *SerialDevice; + SERIAL_PORT_LCR Lcr; + SERIAL_PORT_IER Ier; + SERIAL_PORT_MCR Mcr; + SERIAL_PORT_FCR Fcr; + EFI_TPL Tpl; + UINT32 Control; + + SerialDevice = SERIAL_DEV_FROM_THIS (This); + + // + // Report the status code reset the serial + // + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_PROGRESS_CODE, + EFI_P_PC_RESET | EFI_PERIPHERAL_SERIAL_PORT, + SerialDevice->DevicePath + ); + + Tpl = gBS->RaiseTPL (TPL_NOTIFY); + + SerialFlushTransmitFifo (SerialDevice); + + // + // Make sure DLAB is 0. + // + Lcr.Data = READ_LCR (SerialDevice); + Lcr.Bits.DLab = 0; + WRITE_LCR (SerialDevice, Lcr.Data); + + // + // Turn off all interrupts + // + Ier.Data = READ_IER (SerialDevice); + Ier.Bits.Ravie = 0; + Ier.Bits.Theie = 0; + Ier.Bits.Rie = 0; + Ier.Bits.Mie = 0; + WRITE_IER (SerialDevice, Ier.Data); + + // + // Reset the FIFO + // + Fcr.Data = 0; + Fcr.Bits.TrFIFOE = 0; + WRITE_FCR (SerialDevice, Fcr.Data); + + // + // Turn off loopback and disable device interrupt. + // + Mcr.Data = READ_MCR (SerialDevice); + Mcr.Bits.Out1 = 0; + Mcr.Bits.Out2 = 0; + Mcr.Bits.Lme = 0; + WRITE_MCR (SerialDevice, Mcr.Data); + + // + // Clear the scratch pad register + // + WRITE_SCR (SerialDevice, 0); + + // + // Enable FIFO + // + Fcr.Bits.TrFIFOE = 1; + if (SerialDevice->ReceiveFifoDepth > 16) { + Fcr.Bits.TrFIFO64 = 1; + } + Fcr.Bits.ResetRF = 1; + Fcr.Bits.ResetTF = 1; + WRITE_FCR (SerialDevice, Fcr.Data); + + // + // Go set the current attributes + // + Status = This->SetAttributes ( + This, + This->Mode->BaudRate, + This->Mode->ReceiveFifoDepth, + This->Mode->Timeout, + (EFI_PARITY_TYPE) This->Mode->Parity, + (UINT8) This->Mode->DataBits, + (EFI_STOP_BITS_TYPE) This->Mode->StopBits + ); + + if (EFI_ERROR (Status)) { + gBS->RestoreTPL (Tpl); + return EFI_DEVICE_ERROR; + } + // + // Go set the current control bits + // + Control = 0; + if (SerialDevice->HardwareFlowControl) { + Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE; + } + if (SerialDevice->SoftwareLoopbackEnable) { + Control |= EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE; + } + Status = This->SetControl ( + This, + Control + ); + + if (EFI_ERROR (Status)) { + gBS->RestoreTPL (Tpl); + return EFI_DEVICE_ERROR; + } + + // + // Reset the software FIFO + // + SerialDevice->Receive.Head = SerialDevice->Receive.Tail = 0; + SerialDevice->Transmit.Head = SerialDevice->Transmit.Tail = 0; + gBS->RestoreTPL (Tpl); + + // + // Device reset is complete + // + return EFI_SUCCESS; +} + +/** + Set new attributes to a serial device. + + @param This Pointer to EFI_SERIAL_IO_PROTOCOL + @param BaudRate The baudrate of the serial device + @param ReceiveFifoDepth The depth of receive FIFO buffer + @param Timeout The request timeout for a single char + @param Parity The type of parity used in serial device + @param DataBits Number of databits used in serial device + @param StopBits Number of stopbits used in serial device + + @retval EFI_SUCCESS The new attributes were set + @retval EFI_INVALID_PARAMETERS One or more attributes have an unsupported value + @retval EFI_UNSUPPORTED Data Bits can not set to 5 or 6 + @retval EFI_DEVICE_ERROR The serial device is not functioning correctly (no return) + +**/ +EFI_STATUS +EFIAPI +SerialSetAttributes ( + IN EFI_SERIAL_IO_PROTOCOL *This, + IN UINT64 BaudRate, + IN UINT32 ReceiveFifoDepth, + IN UINT32 Timeout, + IN EFI_PARITY_TYPE Parity, + IN UINT8 DataBits, + IN EFI_STOP_BITS_TYPE StopBits + ) +{ + EFI_STATUS Status; + SERIAL_DEV *SerialDevice; + UINT64 Divisor; + SERIAL_PORT_LCR Lcr; + UART_DEVICE_PATH *Uart; + EFI_TPL Tpl; + + SerialDevice = SERIAL_DEV_FROM_THIS (This); + + // + // Check for default settings and fill in actual values. + // + if (BaudRate == 0) { + BaudRate = PcdGet64 (PcdUartDefaultBaudRate); + } + + if (ReceiveFifoDepth == 0) { + ReceiveFifoDepth = SerialDevice->ReceiveFifoDepth; + } + + if (Timeout == 0) { + Timeout = SERIAL_PORT_DEFAULT_TIMEOUT; + } + + if (Parity == DefaultParity) { + Parity = (EFI_PARITY_TYPE) PcdGet8 (PcdUartDefaultParity); + } + + if (DataBits == 0) { + DataBits = PcdGet8 (PcdUartDefaultDataBits); + } + + if (StopBits == DefaultStopBits) { + StopBits = (EFI_STOP_BITS_TYPE) PcdGet8 (PcdUartDefaultStopBits); + } + + if (!VerifyUartParameters (SerialDevice->ClockRate, BaudRate, DataBits, Parity, StopBits, &Divisor, &BaudRate)) { + return EFI_INVALID_PARAMETER; + } + + if ((ReceiveFifoDepth == 0) || (ReceiveFifoDepth > SerialDevice->ReceiveFifoDepth)) { + return EFI_INVALID_PARAMETER; + } + + if ((Timeout < SERIAL_PORT_MIN_TIMEOUT) || (Timeout > SERIAL_PORT_MAX_TIMEOUT)) { + return EFI_INVALID_PARAMETER; + } + + Tpl = gBS->RaiseTPL (TPL_NOTIFY); + + SerialFlushTransmitFifo (SerialDevice); + + // + // Put serial port on Divisor Latch Mode + // + Lcr.Data = READ_LCR (SerialDevice); + Lcr.Bits.DLab = 1; + WRITE_LCR (SerialDevice, Lcr.Data); + + // + // Write the divisor to the serial port + // + WRITE_DLL (SerialDevice, (UINT8) Divisor); + WRITE_DLM (SerialDevice, (UINT8) ((UINT16) Divisor >> 8)); + + // + // Put serial port back in normal mode and set remaining attributes. + // + Lcr.Bits.DLab = 0; + + switch (Parity) { + case NoParity: + Lcr.Bits.ParEn = 0; + Lcr.Bits.EvenPar = 0; + Lcr.Bits.SticPar = 0; + break; + + case EvenParity: + Lcr.Bits.ParEn = 1; + Lcr.Bits.EvenPar = 1; + Lcr.Bits.SticPar = 0; + break; + + case OddParity: + Lcr.Bits.ParEn = 1; + Lcr.Bits.EvenPar = 0; + Lcr.Bits.SticPar = 0; + break; + + case SpaceParity: + Lcr.Bits.ParEn = 1; + Lcr.Bits.EvenPar = 1; + Lcr.Bits.SticPar = 1; + break; + + case MarkParity: + Lcr.Bits.ParEn = 1; + Lcr.Bits.EvenPar = 0; + Lcr.Bits.SticPar = 1; + break; + + default: + break; + } + + switch (StopBits) { + case OneStopBit: + Lcr.Bits.StopB = 0; + break; + + case OneFiveStopBits: + case TwoStopBits: + Lcr.Bits.StopB = 1; + break; + + default: + break; + } + // + // DataBits + // + Lcr.Bits.SerialDB = (UINT8) ((DataBits - 5) & 0x03); + WRITE_LCR (SerialDevice, Lcr.Data); + + // + // Set the Serial I/O mode + // + This->Mode->BaudRate = BaudRate; + This->Mode->ReceiveFifoDepth = ReceiveFifoDepth; + This->Mode->Timeout = Timeout; + This->Mode->Parity = Parity; + This->Mode->DataBits = DataBits; + This->Mode->StopBits = StopBits; + + // + // See if Device Path Node has actually changed + // + if (SerialDevice->UartDevicePath.BaudRate == BaudRate && + SerialDevice->UartDevicePath.DataBits == DataBits && + SerialDevice->UartDevicePath.Parity == Parity && + SerialDevice->UartDevicePath.StopBits == StopBits + ) { + gBS->RestoreTPL (Tpl); + return EFI_SUCCESS; + } + // + // Update the device path + // + SerialDevice->UartDevicePath.BaudRate = BaudRate; + SerialDevice->UartDevicePath.DataBits = DataBits; + SerialDevice->UartDevicePath.Parity = (UINT8) Parity; + SerialDevice->UartDevicePath.StopBits = (UINT8) StopBits; + + Status = EFI_SUCCESS; + if (SerialDevice->Handle != NULL) { + + // + // Skip the optional Controller device path node + // + Uart = SkipControllerDevicePathNode ( + (EFI_DEVICE_PATH_PROTOCOL *) ( + (UINT8 *) SerialDevice->DevicePath + GetDevicePathSize (SerialDevice->ParentDevicePath) - END_DEVICE_PATH_LENGTH + ), + NULL, + NULL + ); + CopyMem (Uart, &SerialDevice->UartDevicePath, sizeof (UART_DEVICE_PATH)); + Status = gBS->ReinstallProtocolInterface ( + SerialDevice->Handle, + &gEfiDevicePathProtocolGuid, + SerialDevice->DevicePath, + SerialDevice->DevicePath + ); + } + + gBS->RestoreTPL (Tpl); + + return Status; +} + +/** + Set Control Bits. + + @param This Pointer to EFI_SERIAL_IO_PROTOCOL + @param Control Control bits that can be settable + + @retval EFI_SUCCESS New Control bits were set successfully + @retval EFI_UNSUPPORTED The Control bits wanted to set are not supported + +**/ +EFI_STATUS +EFIAPI +SerialSetControl ( + IN EFI_SERIAL_IO_PROTOCOL *This, + IN UINT32 Control + ) +{ + SERIAL_DEV *SerialDevice; + SERIAL_PORT_MCR Mcr; + EFI_TPL Tpl; + UART_FLOW_CONTROL_DEVICE_PATH *FlowControl; + EFI_STATUS Status; + + // + // The control bits that can be set are : + // EFI_SERIAL_DATA_TERMINAL_READY: 0x0001 // WO + // EFI_SERIAL_REQUEST_TO_SEND: 0x0002 // WO + // EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE: 0x1000 // RW + // EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE: 0x2000 // RW + // EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE: 0x4000 // RW + // + SerialDevice = SERIAL_DEV_FROM_THIS (This); + + // + // first determine the parameter is invalid + // + if ((Control & (~(EFI_SERIAL_REQUEST_TO_SEND | EFI_SERIAL_DATA_TERMINAL_READY | + EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE | EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE | + EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE))) != 0) { + return EFI_UNSUPPORTED; + } + + Tpl = gBS->RaiseTPL (TPL_NOTIFY); + + Mcr.Data = READ_MCR (SerialDevice); + Mcr.Bits.DtrC = 0; + Mcr.Bits.Rts = 0; + Mcr.Bits.Lme = 0; + SerialDevice->SoftwareLoopbackEnable = FALSE; + SerialDevice->HardwareFlowControl = FALSE; + + if ((Control & EFI_SERIAL_DATA_TERMINAL_READY) == EFI_SERIAL_DATA_TERMINAL_READY) { + Mcr.Bits.DtrC = 1; + } + + if ((Control & EFI_SERIAL_REQUEST_TO_SEND) == EFI_SERIAL_REQUEST_TO_SEND) { + Mcr.Bits.Rts = 1; + } + + if ((Control & EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) == EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) { + Mcr.Bits.Lme = 1; + } + + if ((Control & EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) == EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) { + SerialDevice->HardwareFlowControl = TRUE; + } + + WRITE_MCR (SerialDevice, Mcr.Data); + + if ((Control & EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) == EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) { + SerialDevice->SoftwareLoopbackEnable = TRUE; + } + + Status = EFI_SUCCESS; + if (SerialDevice->Handle != NULL) { + FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) ( + (UINTN) SerialDevice->DevicePath + + GetDevicePathSize (SerialDevice->ParentDevicePath) + - END_DEVICE_PATH_LENGTH + + sizeof (UART_DEVICE_PATH) + ); + if (IsUartFlowControlDevicePathNode (FlowControl) && + ((BOOLEAN) (ReadUnaligned32 (&FlowControl->FlowControlMap) == UART_FLOW_CONTROL_HARDWARE) != SerialDevice->HardwareFlowControl)) { + // + // Flow Control setting is changed, need to reinstall device path protocol + // + WriteUnaligned32 (&FlowControl->FlowControlMap, SerialDevice->HardwareFlowControl ? UART_FLOW_CONTROL_HARDWARE : 0); + Status = gBS->ReinstallProtocolInterface ( + SerialDevice->Handle, + &gEfiDevicePathProtocolGuid, + SerialDevice->DevicePath, + SerialDevice->DevicePath + ); + } + } + + gBS->RestoreTPL (Tpl); + + return Status; +} + +/** + Get ControlBits. + + @param This Pointer to EFI_SERIAL_IO_PROTOCOL + @param Control Control signals of the serial device + + @retval EFI_SUCCESS Get Control signals successfully + +**/ +EFI_STATUS +EFIAPI +SerialGetControl ( + IN EFI_SERIAL_IO_PROTOCOL *This, + OUT UINT32 *Control + ) +{ + SERIAL_DEV *SerialDevice; + SERIAL_PORT_MSR Msr; + SERIAL_PORT_MCR Mcr; + EFI_TPL Tpl; + + Tpl = gBS->RaiseTPL (TPL_NOTIFY); + + SerialDevice = SERIAL_DEV_FROM_THIS (This); + + *Control = 0; + + // + // Read the Modem Status Register + // + Msr.Data = READ_MSR (SerialDevice); + + if (Msr.Bits.Cts == 1) { + *Control |= EFI_SERIAL_CLEAR_TO_SEND; + } + + if (Msr.Bits.Dsr == 1) { + *Control |= EFI_SERIAL_DATA_SET_READY; + } + + if (Msr.Bits.Ri == 1) { + *Control |= EFI_SERIAL_RING_INDICATE; + } + + if (Msr.Bits.Dcd == 1) { + *Control |= EFI_SERIAL_CARRIER_DETECT; + } + // + // Read the Modem Control Register + // + Mcr.Data = READ_MCR (SerialDevice); + + if (Mcr.Bits.DtrC == 1) { + *Control |= EFI_SERIAL_DATA_TERMINAL_READY; + } + + if (Mcr.Bits.Rts == 1) { + *Control |= EFI_SERIAL_REQUEST_TO_SEND; + } + + if (Mcr.Bits.Lme == 1) { + *Control |= EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE; + } + + if (SerialDevice->HardwareFlowControl) { + *Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE; + } + // + // Update FIFO status + // + SerialReceiveTransmit (SerialDevice); + + // + // See if the Transmit FIFO is empty + // + if (SerialFifoEmpty (&SerialDevice->Transmit)) { + *Control |= EFI_SERIAL_OUTPUT_BUFFER_EMPTY; + } + + // + // See if the Receive FIFO is empty. + // + if (SerialFifoEmpty (&SerialDevice->Receive)) { + *Control |= EFI_SERIAL_INPUT_BUFFER_EMPTY; + } + + if (SerialDevice->SoftwareLoopbackEnable) { + *Control |= EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE; + } + + gBS->RestoreTPL (Tpl); + + return EFI_SUCCESS; +} + +/** + Write the specified number of bytes to serial device. + + @param This Pointer to EFI_SERIAL_IO_PROTOCOL + @param BufferSize On input the size of Buffer, on output the amount of + data actually written + @param Buffer The buffer of data to write + + @retval EFI_SUCCESS The data were written successfully + @retval EFI_DEVICE_ERROR The device reported an error + @retval EFI_TIMEOUT The write operation was stopped due to timeout + +**/ +EFI_STATUS +EFIAPI +SerialWrite ( + IN EFI_SERIAL_IO_PROTOCOL *This, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + ) +{ + SERIAL_DEV *SerialDevice; + UINT8 *CharBuffer; + UINT32 Index; + UINTN Elapsed; + UINTN ActualWrite; + EFI_TPL Tpl; + UINTN Timeout; + UINTN BitsPerCharacter; + + SerialDevice = SERIAL_DEV_FROM_THIS (This); + Elapsed = 0; + ActualWrite = 0; + + if (*BufferSize == 0) { + return EFI_SUCCESS; + } + + if (Buffer == NULL) { + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_ERROR_CODE, + EFI_P_EC_OUTPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT, + SerialDevice->DevicePath + ); + + return EFI_DEVICE_ERROR; + } + + Tpl = gBS->RaiseTPL (TPL_NOTIFY); + + CharBuffer = (UINT8 *) Buffer; + + // + // Compute the number of bits in a single character. This is a start bit, + // followed by the number of data bits, followed by the number of stop bits. + // The number of stop bits is specified by an enumeration that includes + // support for 1.5 stop bits. Treat 1.5 stop bits as 2 stop bits. + // + BitsPerCharacter = + 1 + + This->Mode->DataBits + + ((This->Mode->StopBits == TwoStopBits) ? 2 : This->Mode->StopBits); + + // + // Compute the timeout in microseconds to wait for a single byte to be + // transmitted. The Mode structure contans a Timeout field that is the + // maximum time to transmit or receive a character. However, many UARTs + // have a FIFO for transmits, so the time required to add one new character + // to the transmit FIFO may be the time required to flush a full FIFO. If + // the Timeout in the Mode structure is smaller than the time required to + // flush a full FIFO at the current baud rate, then use a timeout value that + // is required to flush a full transmit FIFO. + // + Timeout = MAX ( + This->Mode->Timeout, + (UINTN)DivU64x64Remainder ( + BitsPerCharacter * (SerialDevice->TransmitFifoDepth + 1) * 1000000, + This->Mode->BaudRate, + NULL + ) + ); + + for (Index = 0; Index < *BufferSize; Index++) { + SerialFifoAdd (&SerialDevice->Transmit, CharBuffer[Index]); + + while (SerialReceiveTransmit (SerialDevice) != EFI_SUCCESS || !SerialFifoEmpty (&SerialDevice->Transmit)) { + // + // Unsuccessful write so check if timeout has expired, if not, + // stall for a bit, increment time elapsed, and try again + // + if (Elapsed >= Timeout) { + *BufferSize = ActualWrite; + gBS->RestoreTPL (Tpl); + return EFI_TIMEOUT; + } + + gBS->Stall (TIMEOUT_STALL_INTERVAL); + + Elapsed += TIMEOUT_STALL_INTERVAL; + } + + ActualWrite++; + // + // Successful write so reset timeout + // + Elapsed = 0; + } + + gBS->RestoreTPL (Tpl); + + return EFI_SUCCESS; +} + +/** + Read the specified number of bytes from serial device. + + @param This Pointer to EFI_SERIAL_IO_PROTOCOL + @param BufferSize On input the size of Buffer, on output the amount of + data returned in buffer + @param Buffer The buffer to return the data into + + @retval EFI_SUCCESS The data were read successfully + @retval EFI_DEVICE_ERROR The device reported an error + @retval EFI_TIMEOUT The read operation was stopped due to timeout + +**/ +EFI_STATUS +EFIAPI +SerialRead ( + IN EFI_SERIAL_IO_PROTOCOL *This, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +{ + SERIAL_DEV *SerialDevice; + UINT32 Index; + UINT8 *CharBuffer; + UINTN Elapsed; + EFI_STATUS Status; + EFI_TPL Tpl; + + SerialDevice = SERIAL_DEV_FROM_THIS (This); + Elapsed = 0; + + if (*BufferSize == 0) { + return EFI_SUCCESS; + } + + if (Buffer == NULL) { + return EFI_DEVICE_ERROR; + } + + Tpl = gBS->RaiseTPL (TPL_NOTIFY); + + Status = SerialReceiveTransmit (SerialDevice); + + if (EFI_ERROR (Status)) { + *BufferSize = 0; + + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_ERROR_CODE, + EFI_P_EC_INPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT, + SerialDevice->DevicePath + ); + + gBS->RestoreTPL (Tpl); + + return EFI_DEVICE_ERROR; + } + + CharBuffer = (UINT8 *) Buffer; + for (Index = 0; Index < *BufferSize; Index++) { + while (SerialFifoRemove (&SerialDevice->Receive, &(CharBuffer[Index])) != EFI_SUCCESS) { + // + // Unsuccessful read so check if timeout has expired, if not, + // stall for a bit, increment time elapsed, and try again + // Need this time out to get conspliter to work. + // + if (Elapsed >= This->Mode->Timeout) { + *BufferSize = Index; + gBS->RestoreTPL (Tpl); + return EFI_TIMEOUT; + } + + gBS->Stall (TIMEOUT_STALL_INTERVAL); + Elapsed += TIMEOUT_STALL_INTERVAL; + + Status = SerialReceiveTransmit (SerialDevice); + if (Status == EFI_DEVICE_ERROR) { + *BufferSize = Index; + gBS->RestoreTPL (Tpl); + return EFI_DEVICE_ERROR; + } + } + // + // Successful read so reset timeout + // + Elapsed = 0; + } + + SerialReceiveTransmit (SerialDevice); + + gBS->RestoreTPL (Tpl); + + return EFI_SUCCESS; +} + +/** + Use scratchpad register to test if this serial port is present. + + @param SerialDevice Pointer to serial device structure + + @return if this serial port is present +**/ +BOOLEAN +SerialPresent ( + IN SERIAL_DEV *SerialDevice + ) + +{ + UINT8 Temp; + BOOLEAN Status; + + Status = TRUE; + + // + // Save SCR reg + // + Temp = READ_SCR (SerialDevice); + WRITE_SCR (SerialDevice, 0xAA); + + if (READ_SCR (SerialDevice) != 0xAA) { + Status = FALSE; + } + + WRITE_SCR (SerialDevice, 0x55); + + if (READ_SCR (SerialDevice) != 0x55) { + Status = FALSE; + } + // + // Restore SCR + // + WRITE_SCR (SerialDevice, Temp); + return Status; +} + +/** + Read serial port. + + @param SerialDev Pointer to serial device + @param Offset Offset in register group + + @return Data read from serial port + +**/ +UINT8 +SerialReadRegister ( + IN SERIAL_DEV *SerialDev, + IN UINT32 Offset + ) +{ + UINT8 Data; + EFI_STATUS Status; + + if (SerialDev->PciDeviceInfo == NULL) { + return IoRead8 ((UINTN) SerialDev->BaseAddress + Offset * SerialDev->RegisterStride); + } else { + if (SerialDev->MmioAccess) { + Status = SerialDev->PciDeviceInfo->PciIo->Mem.Read (SerialDev->PciDeviceInfo->PciIo, EfiPciIoWidthUint8, EFI_PCI_IO_PASS_THROUGH_BAR, + SerialDev->BaseAddress + Offset * SerialDev->RegisterStride, 1, &Data); + } else { + Status = SerialDev->PciDeviceInfo->PciIo->Io.Read (SerialDev->PciDeviceInfo->PciIo, EfiPciIoWidthUint8, EFI_PCI_IO_PASS_THROUGH_BAR, + SerialDev->BaseAddress + Offset * SerialDev->RegisterStride, 1, &Data); + } + ASSERT_EFI_ERROR (Status); + return Data; + } +} + +/** + Write serial port. + + @param SerialDev Pointer to serial device + @param Offset Offset in register group + @param Data data which is to be written to some serial port register +**/ +VOID +SerialWriteRegister ( + IN SERIAL_DEV *SerialDev, + IN UINT32 Offset, + IN UINT8 Data + ) +{ + EFI_STATUS Status; + + if (SerialDev->PciDeviceInfo == NULL) { + IoWrite8 ((UINTN) SerialDev->BaseAddress + Offset * SerialDev->RegisterStride, Data); + } else { + if (SerialDev->MmioAccess) { + Status = SerialDev->PciDeviceInfo->PciIo->Mem.Write (SerialDev->PciDeviceInfo->PciIo, EfiPciIoWidthUint8, EFI_PCI_IO_PASS_THROUGH_BAR, + SerialDev->BaseAddress + Offset * SerialDev->RegisterStride, 1, &Data); + } else { + Status = SerialDev->PciDeviceInfo->PciIo->Io.Write (SerialDev->PciDeviceInfo->PciIo, EfiPciIoWidthUint8, EFI_PCI_IO_PASS_THROUGH_BAR, + SerialDev->BaseAddress + Offset * SerialDev->RegisterStride, 1, &Data); + } + ASSERT_EFI_ERROR (Status); + } +} diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec index 3dfcd6a77f64..38eac142ac79 100644 --- a/MdeModulePkg/MdeModulePkg.dec +++ b/MdeModulePkg/MdeModulePkg.dec @@ -665,6 +665,12 @@ # @Prompt Enable S3 performance data support. gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwarePerformanceDataTableS3Support|TRUE|BOOLEAN|0x00010064 + ## Indicates if Serial device uses half hand shake.

+ # TRUE - Serial device uses half hand shake.
+ # FALSE - Serial device doesn't use half hand shake.
+ # @Prompt Enable Serial device Half Hand Shake + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialUseHalfHandshake|FALSE|BOOLEAN|0x00010073 + [PcdsFeatureFlag.IA32, PcdsFeatureFlag.X64] ## Indicates if DxeIpl should switch to long mode to enter DXE phase. # It is assumed that 64-bit DxeCore is built in firmware if it is true; otherwise 32-bit DxeCore @@ -950,6 +956,38 @@ # @Prompt Pci Serial Device Info gEfiMdeModulePkgTokenSpaceGuid.PcdSerialPciDeviceInfo|{0xFF}|VOID*|0x00010067 + ## PCI Serial Parameters. It is an array of VendorID, DeviceID, ClockRate, Offset, + # BarIndex, RegisterStride, ReceiveFifoDepth, TransmitFifoDepth information that + # describes the parameters of special PCI serial devices. + # Each array entry is 24-byte in length. The array is terminated + # by an array entry with a PCI Vendor ID of 0xFFFF. If a platform only contains a + # standard 16550 PCI serial device whose class code is 7/0/2, the value is 0xFFFF. + # The C style structure is defined as below: + # typedef struct { + # UINT16 VendorId; ///< Vendor ID to match the PCI device. The value 0xFFFF terminates the list of entries. + # UINT16 DeviceId; ///< Device ID to match the PCI device + # UINT32 ClockRate; ///< UART clock rate. Set to 0 for default clock rate of 1843200 Hz + # UINT64 Offset; ///< The byte offset into to the BAR + # UINT8 BarIndex; ///< Which BAR to get the UART base address + # UINT8 RegisterStride; ///< UART register stride in bytes. Set to 0 for default register stride of 1 byte. + # UINT16 ReceiveFifoDepth; ///< UART receive FIFO depth in bytes. Set to 0 for a default FIFO depth of 16 bytes. + # UINT16 TransmitFifoDepth; ///< UART transmit FIFO depth in bytes. Set to 0 for a default FIFO depth of 16 bytes. + # UINT8 Reserved[2]; + # } PCI_SERIAL_PARAMETER; + # It contains zero or more instances of the above structure. + # For example, if a PCI device contains two UARTs, PcdPciSerialParameters needs + # to contain two instances of the above structure, with the VendorId and DeviceId + # equals to the Device ID and Vendor ID of the device; If the PCI device uses the + # first two BARs to support two UARTs, BarIndex of first instance equals to 0 and + # BarIndex of second one equals to 1; If the PCI device uses the first BAR to + # support both UARTs, BarIndex of both instance equals to 0, Offset of first + # instance equals to 0 and Offset of second one equals to a value bigger than or + # equal to 8. + # For certain UART whose register needs to be accessed in DWORD aligned address, + # RegisterStride equals to 4. + # @Prompt Pci Serial Parameters + gEfiMdeModulePkgTokenSpaceGuid.PcdPciSerialParameters|{0xFF, 0xFF}|VOID*|0x00010071 + ## Serial Port Extended Transmit FIFO Size. The default is 64 bytes. # @Prompt Serial Port Extended Transmit FIFO Size in Bytes gEfiMdeModulePkgTokenSpaceGuid.PcdSerialExtendedTxFifoSize|64|UINT32|0x00010068 diff --git a/MdeModulePkg/MdeModulePkg.dsc b/MdeModulePkg/MdeModulePkg.dsc index 602b4bba818f..d8d8885f167d 100644 --- a/MdeModulePkg/MdeModulePkg.dsc +++ b/MdeModulePkg/MdeModulePkg.dsc @@ -206,6 +206,7 @@ MdeModulePkg/Application/HelloWorld/HelloWorld.inf MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.inf + MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxe.inf MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf MdeModulePkg/Bus/Pci/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupportDxe.inf MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDxe.inf From 09281aceec8e7eb24dab0421134f11fbf8bf9af9 Mon Sep 17 00:00:00 2001 From: Ruiyu Ni Date: Thu, 10 Dec 2015 07:29:10 +0000 Subject: [PATCH 230/525] ShellPkg/mm: Fix the help message to align to implementation and spec The implementation is already aligned to spec. (Sync patch r19180 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ruiyu Ni Reviewed-by: Jaben Carsey git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19208 6f19259b-4bc3-4df7-8a09-765794883524 --- .../UefiShellDebug1CommandsLib.uni | Bin 140676 -> 139694 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.uni b/ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.uni index e16175a6174fbd08275d14d88eaa385e42ae4781..48ea1e07a369920006a5381c03e0235dff10e42a 100644 GIT binary patch delta 70 zcmZoU&9Uw<$3&(_jHZoGw?1Y38qHh7punKZ;K|?*q-&<9$1)aAS4d?%vi(*pqZ9k| ag!znV+wY|_3h_>VV9HpvU9FrkZXE!W5*c6s delta 569 zcmb`EO-n*S6o$_cQ;9OM4?_}WB?K0zwKOCsFpz{GB2!Abno!s9BM90A{eZ&YK$}3? zCT&7DMU)WKrv5?ZLRWDKYMGsTEfAtsF)(*#?#wgKd8c?|+PgRDnjibmIJR3mui;zR z7lts*fdmPNfPhKJK}H+x@N5JEFw5Ux_t4`jPURJ0rp6L((o+caB@x95BZcg!r-cYs zj4imJ<2nx0-31Pj;zbjkB+)XSh7`9fUlD^eBw>{`B%Z~2HLVE*A^0V+0y6(+seE(M zMrToGZ257JmM^iB3UzdL#8i2zdeQb@^gdF27%x>Mw02X-jRuDsM%f|2hJt-k+_xeV zsxeh>v6l{IuJNV8e&rrrm*cM*bL945Kg|?yfXSXVc8cliu+4mRBoS_KRmv$E=txE@ zT_sTOjdOC+kDR`fQ=iVo=d-Y;WvY3$amoj1rulcY8wF_Dw(QN<=pu`g?H{HwR`O?1 GE`9<%caSCk From 5b2f873d3d5d0d2c65f3ffa6cd459822e9b06619 Mon Sep 17 00:00:00 2001 From: Ruiyu Ni Date: Thu, 10 Dec 2015 07:30:02 +0000 Subject: [PATCH 231/525] ShellPkg/mm: Fix mm to support multiple root bridge platform In multiple root bridge platforms, different root bridges may share the same segment but occupy different range of buses, or may occupy different segments. The fix is to find the correct root bridge IO instance by comparing not only the segment but also the bus ranges. It tries to access the MMIO and IO in the following order: PciRootBridgeIo, CpuIo and direct IO. (Sync patch r19181 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ruiyu Ni Reviewed-by: Michael Kinney git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19209 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Library/UefiShellDebug1CommandsLib/Mm.c | 917 +++++++++--------- .../UefiShellDebug1CommandsLib.h | 3 +- .../UefiShellDebug1CommandsLib.inf | 4 +- .../UefiShellDebug1CommandsLib.uni | Bin 139694 -> 139228 bytes ShellPkg/ShellPkg.dsc | 1 + 5 files changed, 464 insertions(+), 461 deletions(-) diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/Mm.c b/ShellPkg/Library/UefiShellDebug1CommandsLib/Mm.c index ca64f2c5b022..3f08cc84dc24 100644 --- a/ShellPkg/Library/UefiShellDebug1CommandsLib/Mm.c +++ b/ShellPkg/Library/UefiShellDebug1CommandsLib/Mm.c @@ -2,7 +2,7 @@ Main file for Mm shell Debug1 function. (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
- Copyright (c) 2005 - 2014, Intel Corporation. All rights reserved.
+ Copyright (c) 2005 - 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -15,16 +15,25 @@ #include "UefiShellDebug1CommandsLib.h" #include +#include #include #include typedef enum { - EfiMemory, - EFIMemoryMappedIo, - EfiIo, - EfiPciConfig, - EfiPciEConfig -} EFI_ACCESS_TYPE; + ShellMmMemory, + ShellMmMemoryMappedIo, + ShellMmIo, + ShellMmPci, + ShellMmPciExpress +} SHELL_MM_ACCESS_TYPE; + +CONST UINT16 mShellMmAccessTypeStr[] = { + STRING_TOKEN (STR_MM_MEM), + STRING_TOKEN (STR_MM_MMIO), + STRING_TOKEN (STR_MM_IO), + STRING_TOKEN (STR_MM_PCI), + STRING_TOKEN (STR_MM_PCIE) +}; STATIC CONST SHELL_PARAM_ITEM ParamList[] = { {L"-mmio", TypeFlag}, @@ -37,161 +46,341 @@ STATIC CONST SHELL_PARAM_ITEM ParamList[] = { {NULL, TypeMax} }; -STATIC CONST UINT64 MaxNum[9] = { 0xff, 0xffff, 0xffffffff, 0xffffffffffffffffULL }; +CONST UINT64 mShellMmMaxNumber[] = { + 0, MAX_UINT8, MAX_UINT16, 0, MAX_UINT32, 0, 0, 0, MAX_UINT64 +}; +CONST EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH mShellMmRootBridgeIoWidth[] = { + 0, EfiPciWidthUint8, EfiPciWidthUint16, 0, EfiPciWidthUint32, 0, 0, 0, EfiPciWidthUint64 +}; +CONST EFI_CPU_IO_PROTOCOL_WIDTH mShellMmCpuIoWidth[] = { + 0, EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, 0, EfiCpuIoWidthUint32, 0, 0, 0, EfiCpuIoWidthUint64 +}; /** - Read some data into a buffer from memory. - - @param[in] Width The width of each read. - @param[in] Addresss The memory location to start reading at. - @param[in] Size The size of Buffer in Width sized units. - @param[out] Buffer The buffer to read into. + Extract the PCI segment, bus, device, function, register from + from a SHELL_MM_PCI or SHELL_MM_PCIE format of address.. + + @param[in] PciFormat Whether the address is of PCI format of PCIE format. + @param[in] Address SHELL_MM_PCI or SHELL_MM_PCIE address. + @param[out] Segment PCI segment number. + @param[out] Bus PCI bus number. + @param[out] Device PCI device number. + @param[out] Function PCI function number. + @param[out] Register PCI register offset. **/ VOID EFIAPI -ReadMem ( - IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, - IN UINT64 Address, - IN UINTN Size, - OUT VOID *Buffer +ShellMmDecodePciAddress ( + IN BOOLEAN PciFormat, + IN UINT64 Address, + OUT UINT32 *Segment, + OUT UINT8 *Bus, + OUT UINT8 *Device, OPTIONAL + OUT UINT8 *Function, OPTIONAL + OUT UINT32 *Register OPTIONAL ) { - // - // This function is defective. This ASSERT prevents the defect from affecting anything. - // - ASSERT(Size == 1); - do { - if (Width == EfiPciWidthUint8) { - *(UINT8 *) Buffer = *(UINT8 *) (UINTN) Address; - Address -= 1; - } else if (Width == EfiPciWidthUint16) { - *(UINT16 *) Buffer = *(UINT16 *) (UINTN) Address; - Address -= 2; - } else if (Width == EfiPciWidthUint32) { - *(UINT32 *) Buffer = *(UINT32 *) (UINTN) Address; - Address -= 4; - } else if (Width == EfiPciWidthUint64) { - *(UINT64 *) Buffer = *(UINT64 *) (UINTN) Address; - Address -= 8; - } else { - ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MM_READ_ERROR), gShellDebug1HiiHandle, L"mm"); - break; + if (PciFormat) { + // + // PCI Configuration Space.The address will have the format 0x000000ssbbddffrr, + // where ss = Segment, bb = Bus, dd = Device, ff = Function and rr = Register. + // + *Segment = (UINT32) (RShiftU64 (Address, 32) & 0xFF); + *Bus = (UINT8) (((UINT32) Address) >> 24); + + if (Device != NULL) { + *Device = (UINT8) (((UINT32) Address) >> 16); + } + if (Function != NULL) { + *Function = (UINT8) (((UINT32) Address) >> 8); } - Size--; - } while (Size > 0); + if (Register != NULL) { + *Register = (UINT8) Address; + } + } else { + // + // PCI Express Configuration Space.The address will have the format 0x0000000ssbbddffrrr, + // where ss = Segment, bb = Bus, dd = Device, ff = Function and rrr = Register. + // + *Segment = (UINT32) (RShiftU64 (Address, 36) & 0xFF); + *Bus = (UINT8) RShiftU64 (Address, 28); + if (Device != NULL) { + *Device = (UINT8) (((UINT32) Address) >> 20); + } + if (Function != NULL) { + *Function = (UINT8) (((UINT32) Address) >> 12); + } + if (Register != NULL) { + *Register = (UINT32) (Address & 0xFFF); + } + } } /** - Write some data to memory. - - @param[in] Width The width of each write. - @param[in] Addresss The memory location to start writing at. - @param[in] Size The size of Buffer in Width sized units. - @param[in] Buffer The buffer to write from. + Read or write some data from or into the Address. + + @param[in] AccessType Access type. + @param[in] PciRootBridgeIo PciRootBridgeIo instance. + @param[in] CpuIo CpuIo instance. + @param[in] Read TRUE for read, FALSE for write. + @param[in] Addresss The memory location to access. + @param[in] Size The size of Buffer in Width sized units. + @param[in, out] Buffer The buffer to read into or write from. **/ VOID -EFIAPI -WriteMem ( - IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, - IN UINT64 Address, - IN UINTN Size, - IN VOID *Buffer +ShellMmAccess ( + IN SHELL_MM_ACCESS_TYPE AccessType, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, + IN EFI_CPU_IO2_PROTOCOL *CpuIo, + IN BOOLEAN Read, + IN UINT64 Address, + IN UINTN Size, + IN OUT VOID *Buffer ) { - // - // This function is defective. This ASSERT prevents the defect from affecting anything. - // - ASSERT(Size == 1); - do { - if (Width == EfiPciWidthUint8) { - *(UINT8 *) (UINTN) Address = *(UINT8 *) Buffer; - Address += 1; - } else if (Width == EfiPciWidthUint16) { - *(UINT16 *) (UINTN) Address = *(UINT16 *) Buffer; - Address += 2; - } else if (Width == EfiPciWidthUint32) { - *(UINT32 *) (UINTN) Address = *(UINT32 *) Buffer; - Address += 4; - } else if (Width == EfiPciWidthUint64) { - *(UINT64 *) (UINTN) Address = *(UINT64 *) Buffer; - Address += 8; + EFI_STATUS Status; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_IO_MEM RootBridgeIoMem; + EFI_CPU_IO_PROTOCOL_IO_MEM CpuIoMem; + UINT32 Segment; + UINT8 Bus; + UINT8 Device; + UINT8 Function; + UINT32 Register; + + if (AccessType == ShellMmMemory) { + if (Read) { + CopyMem (Buffer, (VOID *) (UINTN) Address, Size); } else { + CopyMem ((VOID *) (UINTN) Address, Buffer, Size); + } + } else { + RootBridgeIoMem = NULL; + CpuIoMem = NULL; + switch (AccessType) { + case ShellMmPci: + case ShellMmPciExpress: + ASSERT (PciRootBridgeIo != NULL); + ShellMmDecodePciAddress ((BOOLEAN) (AccessType == ShellMmPci), Address, &Segment, &Bus, &Device, &Function, &Register); + if (Read) { + Status = PciRootBridgeIo->Pci.Read ( + PciRootBridgeIo, mShellMmRootBridgeIoWidth[Size], + EFI_PCI_ADDRESS (Bus, Device, Function, Register), + 1, Buffer + ); + } else { + Status = PciRootBridgeIo->Pci.Write ( + PciRootBridgeIo, mShellMmRootBridgeIoWidth[Size], + EFI_PCI_ADDRESS (Bus, Device, Function, Register), + 1, Buffer + ); + } + ASSERT_EFI_ERROR (Status); + return; + + case ShellMmMemoryMappedIo: + if (PciRootBridgeIo != NULL) { + RootBridgeIoMem = Read ? PciRootBridgeIo->Mem.Read : PciRootBridgeIo->Mem.Write; + } + if (CpuIo != NULL) { + CpuIoMem = Read ? CpuIo->Mem.Read : CpuIo->Mem.Write; + } + break; + + case ShellMmIo: + if (PciRootBridgeIo != NULL) { + RootBridgeIoMem = Read ? PciRootBridgeIo->Io.Read : PciRootBridgeIo->Io.Write; + } + if (CpuIo != NULL) { + CpuIoMem = Read ? CpuIo->Io.Read : CpuIo->Io.Write; + } + break; + default: ASSERT (FALSE); + break; } - // - // - // - Size--; - } while (Size > 0); + + Status = EFI_UNSUPPORTED; + if (RootBridgeIoMem != NULL) { + Status = RootBridgeIoMem (PciRootBridgeIo, mShellMmRootBridgeIoWidth[Size], Address, 1, Buffer); + } + if (EFI_ERROR (Status) && (CpuIoMem != NULL)) { + Status = CpuIoMem (CpuIo, mShellMmCpuIoWidth[Size], Address, 1, Buffer); + } + + if (EFI_ERROR (Status)) { + if (AccessType == ShellMmIo) { + switch (Size) { + case 1: + if (Read) { + *(UINT8 *) Buffer = IoRead8 ((UINTN) Address); + } else { + IoWrite8 ((UINTN) Address, *(UINT8 *) Buffer); + } + break; + case 2: + if (Read) { + *(UINT16 *) Buffer = IoRead16 ((UINTN) Address); + } else { + IoWrite16 ((UINTN) Address, *(UINT16 *) Buffer); + } + break; + case 4: + if (Read) { + *(UINT32 *) Buffer = IoRead32 ((UINTN) Address); + } else { + IoWrite32 ((UINTN) Address, *(UINT32 *) Buffer); + } + break; + case 8: + if (Read) { + *(UINT64 *) Buffer = IoRead64 ((UINTN) Address); + } else { + IoWrite64 ((UINTN) Address, *(UINT64 *) Buffer); + } + break; + default: + ASSERT (FALSE); + break; + } + } else { + switch (Size) { + case 1: + if (Read) { + *(UINT8 *) Buffer = MmioRead8 ((UINTN) Address); + } else { + MmioWrite8 ((UINTN) Address, *(UINT8 *) Buffer); + } + break; + case 2: + if (Read) { + *(UINT16 *) Buffer = MmioRead16 ((UINTN) Address); + } else { + MmioWrite16 ((UINTN) Address, *(UINT16 *) Buffer); + } + break; + case 4: + if (Read) { + *(UINT32 *) Buffer = MmioRead32 ((UINTN) Address); + } else { + MmioWrite32 ((UINTN) Address, *(UINT32 *) Buffer); + } + break; + case 8: + if (Read) { + *(UINT64 *) Buffer = MmioRead64 ((UINTN) Address); + } else { + MmioWrite64 ((UINTN) Address, *(UINT64 *) Buffer); + } + break; + default: + ASSERT (FALSE); + break; + } + } + } + } } /** - Convert a string to it's hex data. + Find the CpuIo instance and PciRootBridgeIo instance in the platform. + If there are multiple PciRootBridgeIo instances, the instance which manages + the Address is returned. - @param[in] str The pointer to the string of hex data. - @param[out] data The pointer to the buffer to fill. Valid upon a TRUE return. + @param[in] AccessType Access type. + @param[in] Address Address to access. + @param[out] CpuIo Return the CpuIo instance. + @param[out] PciRootBridgeIo Return the proper PciRootBridgeIo instance. - @retval TRUE The conversion was successful. - @retval FALSE The conversion failed. + @retval TRUE There are PciRootBridgeIo instances in the platform. + @retval FALSE There isn't PciRootBridgeIo instance in the platform. **/ BOOLEAN -EFIAPI -GetHex ( - IN UINT16 *str, - OUT UINT64 *data +ShellMmLocateIoProtocol ( + IN SHELL_MM_ACCESS_TYPE AccessType, + IN UINT64 Address, + OUT EFI_CPU_IO2_PROTOCOL **CpuIo, + OUT EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL **PciRootBridgeIo ) { - UINTN TempUint; - CHAR16 TempChar; - BOOLEAN Find; + EFI_STATUS Status; + UINTN Index; + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *Io; + UINT32 Segment; + UINT8 Bus; + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors; + + Status = gBS->LocateProtocol (&gEfiCpuIo2ProtocolGuid, NULL, (VOID **) CpuIo); + if (EFI_ERROR (Status)) { + *CpuIo = NULL; + } + + *PciRootBridgeIo = NULL; + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiPciRootBridgeIoProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer + ); + if (EFI_ERROR (Status) || (HandleCount == 0)) { + return FALSE; + } + + if ((AccessType == ShellMmPci) || (AccessType == ShellMmPciExpress)) { + ShellMmDecodePciAddress ((BOOLEAN) (AccessType == ShellMmPci), Address, &Segment, &Bus, NULL, NULL, NULL); + } - Find = FALSE; // - // convert hex digits + // Find the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL of the specified segment & bus number // - TempUint = 0; - TempChar = *(str++); - while (TempChar != CHAR_NULL) { - if (TempChar >= 'a' && TempChar <= 'f') { - TempChar -= 'a' - 'A'; - } - - if (TempChar == ' ') { - break; + for (Index = 0; (Index < HandleCount) && (*PciRootBridgeIo == NULL); Index++) { + Status = gBS->HandleProtocol ( + HandleBuffer[Index], + &gEfiPciRootBridgeIoProtocolGuid, + (VOID *) &Io + ); + if (EFI_ERROR (Status)) { + continue; } - if ((TempChar >= '0' && TempChar <= '9') || (TempChar >= 'A' && TempChar <= 'F')) { - TempUint = (TempUint << 4) | (TempChar - (TempChar >= 'A' ? 'A' - 10 : '0')); - - Find = TRUE; - } else { - return FALSE; + if ((((AccessType == ShellMmPci) || (AccessType == ShellMmPciExpress)) && (Io->SegmentNumber == Segment)) || + ((AccessType == ShellMmIo) || (AccessType == ShellMmMemoryMappedIo)) + ) { + Status = Io->Configuration (Io, (VOID **) &Descriptors); + if (!EFI_ERROR (Status)) { + while (Descriptors->Desc != ACPI_END_TAG_DESCRIPTOR) { + // + // Compare the segment and bus range for PCI/PCIE access + // + if ((Descriptors->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) && + ((AccessType == ShellMmPci) || (AccessType == ShellMmPciExpress)) && + ((Bus >= Descriptors->AddrRangeMin) && (Bus <= Descriptors->AddrRangeMax)) + ) { + *PciRootBridgeIo = Io; + break; + + // + // Compare the address range for MMIO/IO access + // + } else if ((((Descriptors->ResType == ACPI_ADDRESS_SPACE_TYPE_IO) && (AccessType == ShellMmIo)) || + ((Descriptors->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) && (AccessType == ShellMmMemoryMappedIo)) + ) && ((Address >= Descriptors->AddrRangeMin) && (Address <= Descriptors->AddrRangeMax)) + ) { + *PciRootBridgeIo = Io; + break; + } + Descriptors++; + } + } } - - TempChar = *(str++); + } + if (HandleBuffer != NULL) { + FreePool (HandleBuffer); } - *data = TempUint; - return Find; -} - -/** - Get the PCI-E Address from a PCI address format 0x0000ssbbddffrrr - where ss is SEGMENT, bb is BUS, dd is DEVICE, ff is FUNCTION - and rrr is REGISTER (extension format for PCI-E). - - @param[in] InputAddress PCI address format on input. - @param[out]PciEAddress PCI-E address extention format. -**/ -VOID -EFIAPI -GetPciEAddressFromInputAddress ( - IN UINT64 InputAddress, - OUT UINT64 *PciEAddress - ) -{ - *PciEAddress = RShiftU64(InputAddress & ~(UINT64) 0xFFF, 4); - *PciEAddress += LShiftU64((UINT16) InputAddress & 0x0FFF, 32); + return TRUE; } /** @@ -207,438 +396,248 @@ ShellCommandRunMm ( IN EFI_SYSTEM_TABLE *SystemTable ) { - EFI_STATUS Status; - EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev; - UINT64 Address; - UINT64 PciEAddress; - UINT64 Value; - UINT32 SegmentNumber; - EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width; - EFI_ACCESS_TYPE AccessType; - UINT64 Buffer; - UINTN Index; - UINTN Size; -// CHAR16 *ValueStr; - BOOLEAN Complete; - CHAR16 *InputStr; - BOOLEAN Interactive; - EFI_HANDLE *HandleBuffer; - UINTN BufferSize; - UINTN ItemValue; - LIST_ENTRY *Package; - CHAR16 *ProblemParam; - SHELL_STATUS ShellStatus; - CONST CHAR16 *Temp; - - Value = 0; - Address = 0; - PciEAddress = 0; - IoDev = NULL; - HandleBuffer = NULL; - BufferSize = 0; - SegmentNumber = 0; - ShellStatus = SHELL_SUCCESS; - InputStr = NULL; + EFI_STATUS Status; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo; + EFI_CPU_IO2_PROTOCOL *CpuIo; + UINT64 Address; + UINT64 Value; + SHELL_MM_ACCESS_TYPE AccessType; + UINT64 Buffer; + UINTN Index; + UINTN Size; + BOOLEAN Complete; + CHAR16 *InputStr; + BOOLEAN Interactive; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + CONST CHAR16 *Temp; + BOOLEAN HasPciRootBridgeIo; + + Value = 0; + Address = 0; + ShellStatus = SHELL_SUCCESS; + InputStr = NULL; + Size = 1; + AccessType = ShellMmMemory; // // Parse arguments // - Width = EfiPciWidthUint8; - Size = 1; - AccessType = EfiMemory; -// ValueStr = NULL; - Interactive = TRUE; - Package = NULL; - Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE); - if (EFI_ERROR(Status)) { + if (EFI_ERROR (Status)) { if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { - ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDebug1HiiHandle, L"mm", ProblemParam); - FreePool(ProblemParam); + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDebug1HiiHandle, L"mm", ProblemParam); + FreePool (ProblemParam); ShellStatus = SHELL_INVALID_PARAMETER; goto Done; } else { - ASSERT(FALSE); + ASSERT (FALSE); } } else { - if (ShellCommandLineGetCount(Package) < 2) { - ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellDebug1HiiHandle, L"mm"); + if (ShellCommandLineGetCount (Package) < 2) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellDebug1HiiHandle, L"mm"); ShellStatus = SHELL_INVALID_PARAMETER; goto Done; - } else if (ShellCommandLineGetCount(Package) > 3) { - ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle, L"mm"); + } else if (ShellCommandLineGetCount (Package) > 3) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle, L"mm"); ShellStatus = SHELL_INVALID_PARAMETER; goto Done; - } else if (ShellCommandLineGetFlag(Package, L"-w") && ShellCommandLineGetValue(Package, L"-w") == NULL) { - ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellDebug1HiiHandle, L"mm", L"-w"); + } else if (ShellCommandLineGetFlag (Package, L"-w") && ShellCommandLineGetValue (Package, L"-w") == NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellDebug1HiiHandle, L"mm", L"-w"); ShellStatus = SHELL_INVALID_PARAMETER; goto Done; } else { - if (ShellCommandLineGetFlag(Package, L"-mmio")) { - AccessType = EFIMemoryMappedIo; - if (ShellCommandLineGetFlag(Package, L"-mem") - ||ShellCommandLineGetFlag(Package, L"-io") - ||ShellCommandLineGetFlag(Package, L"-pci") - ||ShellCommandLineGetFlag(Package, L"-pcie") - ){ - ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle, L"mm"); + if (ShellCommandLineGetFlag (Package, L"-mmio")) { + AccessType = ShellMmMemoryMappedIo; + if (ShellCommandLineGetFlag (Package, L"-mem") + || ShellCommandLineGetFlag (Package, L"-io") + || ShellCommandLineGetFlag (Package, L"-pci") + || ShellCommandLineGetFlag (Package, L"-pcie") + ) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle, L"mm"); ShellStatus = SHELL_INVALID_PARAMETER; goto Done; } - } else if (ShellCommandLineGetFlag(Package, L"-mem")) { - AccessType = EfiMemory; - if (ShellCommandLineGetFlag(Package, L"-io") - ||ShellCommandLineGetFlag(Package, L"-pci") - ||ShellCommandLineGetFlag(Package, L"-pcie") - ){ - ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle, L"mm"); + } else if (ShellCommandLineGetFlag (Package, L"-mem")) { + AccessType = ShellMmMemory; + if (ShellCommandLineGetFlag (Package, L"-io") + || ShellCommandLineGetFlag (Package, L"-pci") + || ShellCommandLineGetFlag (Package, L"-pcie") + ) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle, L"mm"); ShellStatus = SHELL_INVALID_PARAMETER; goto Done; } - } else if (ShellCommandLineGetFlag(Package, L"-io")) { - AccessType = EfiIo; - if (ShellCommandLineGetFlag(Package, L"-pci") - ||ShellCommandLineGetFlag(Package, L"-pcie") - ){ - ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle, L"mm"); + } else if (ShellCommandLineGetFlag (Package, L"-io")) { + AccessType = ShellMmIo; + if (ShellCommandLineGetFlag (Package, L"-pci") + || ShellCommandLineGetFlag (Package, L"-pcie") + ) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle, L"mm"); ShellStatus = SHELL_INVALID_PARAMETER; goto Done; } - } else if (ShellCommandLineGetFlag(Package, L"-pci")) { - AccessType = EfiPciConfig; - if (ShellCommandLineGetFlag(Package, L"-pcie") - ){ - ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle, L"mm"); + } else if (ShellCommandLineGetFlag (Package, L"-pci")) { + AccessType = ShellMmPci; + if (ShellCommandLineGetFlag (Package, L"-pcie") + ) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle, L"mm"); ShellStatus = SHELL_INVALID_PARAMETER; goto Done; } - } else if (ShellCommandLineGetFlag(Package, L"-pcie")) { - AccessType = EfiPciEConfig; + } else if (ShellCommandLineGetFlag (Package, L"-pcie")) { + AccessType = ShellMmPciExpress; } } // // Non interactive for a script file or for the specific parameter // - if (gEfiShellProtocol->BatchIsActive() || ShellCommandLineGetFlag (Package, L"-n")) { + Interactive = TRUE; + if (gEfiShellProtocol->BatchIsActive () || ShellCommandLineGetFlag (Package, L"-n")) { Interactive = FALSE; } - Temp = ShellCommandLineGetValue(Package, L"-w"); + Temp = ShellCommandLineGetValue (Package, L"-w"); if (Temp != NULL) { - ItemValue = ShellStrToUintn (Temp); - - switch (ItemValue) { - case 1: - Width = EfiPciWidthUint8; - Size = 1; - break; - - case 2: - Width = EfiPciWidthUint16; - Size = 2; - break; - - case 4: - Width = EfiPciWidthUint32; - Size = 4; - break; - - case 8: - Width = EfiPciWidthUint64; - Size = 8; - break; - - default: - ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM_VAL), gShellDebug1HiiHandle, L"mm", Temp, L"-w"); - ShellStatus = SHELL_INVALID_PARAMETER; - goto Done; - } + Size = ShellStrToUintn (Temp); } - - Temp = ShellCommandLineGetRawValue(Package, 1); - if (!ShellIsHexOrDecimalNumber(Temp, TRUE, FALSE) || EFI_ERROR(ShellConvertStringToUint64(Temp, (UINT64*)&Address, TRUE, FALSE))) { - ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"mm", Temp); + if ((Size != 1) && (Size != 2) && (Size != 4) && (Size != 8)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM_VAL), gShellDebug1HiiHandle, L"mm", Temp, L"-w"); ShellStatus = SHELL_INVALID_PARAMETER; goto Done; } - Temp = ShellCommandLineGetRawValue(Package, 2); - if (Temp != NULL) { - // - // Per spec if value is specified, then -n is assumed. - // - Interactive = FALSE; - - if (!ShellIsHexOrDecimalNumber(Temp, TRUE, FALSE) || EFI_ERROR(ShellConvertStringToUint64(Temp, &Value, TRUE, FALSE))) { - ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"mm", Temp); - ShellStatus = SHELL_INVALID_PARAMETER; - goto Done; - } - switch (Size) { - case 1: - if (Value > 0xFF) { - ShellStatus = SHELL_INVALID_PARAMETER; - } - break; - - case 2: - if (Value > 0xFFFF) { - ShellStatus = SHELL_INVALID_PARAMETER; - } - break; - - case 4: - if (Value > 0xFFFFFFFF) { - ShellStatus = SHELL_INVALID_PARAMETER; - } - break; - - default: - break; - } - - if (ShellStatus != SHELL_SUCCESS) { - ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"mm", Temp); - ShellStatus = SHELL_INVALID_PARAMETER; - goto Done; - } + Temp = ShellCommandLineGetRawValue (Package, 1); + Status = ShellConvertStringToUint64 (Temp, &Address, TRUE, FALSE); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"mm", Temp); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; } if ((Address & (Size - 1)) != 0) { - ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MM_NOT_ALIGNED), gShellDebug1HiiHandle, L"mm", Address); + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_MM_NOT_ALIGNED), gShellDebug1HiiHandle, L"mm", Address); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } + + if ((AccessType == ShellMmIo) && (Address + Size > MAX_UINT16 + 1)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_MM_IO_ADDRESS_RANGE), gShellDebug1HiiHandle, L"mm"); ShellStatus = SHELL_INVALID_PARAMETER; goto Done; } + // - // locate DeviceIO protocol interface + // locate IO protocol interface // - if (AccessType != EfiMemory) { - Status = gBS->LocateHandleBuffer ( - ByProtocol, - &gEfiPciRootBridgeIoProtocolGuid, - NULL, - &BufferSize, - &HandleBuffer - ); - if (EFI_ERROR (Status)) { - ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PCIRBIO_NF), gShellDebug1HiiHandle, L"mm"); + HasPciRootBridgeIo = ShellMmLocateIoProtocol (AccessType, Address, &CpuIo, &PciRootBridgeIo); + if ((AccessType == ShellMmPci) || (AccessType == ShellMmPciExpress)) { + if (!HasPciRootBridgeIo) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PCIRBIO_NF), gShellDebug1HiiHandle, L"mm"); ShellStatus = SHELL_NOT_FOUND; goto Done; } - // - // In the case of PCI or PCIE - // Get segment number and mask the segment bits in Address - // - if (AccessType == EfiPciEConfig) { - SegmentNumber = (UINT32) RShiftU64 (Address, 36) & 0xff; - Address &= 0xfffffffffULL; - } else { - if (AccessType == EfiPciConfig) { - SegmentNumber = (UINT32) RShiftU64 (Address, 32) & 0xff; - Address &= 0xffffffff; - } - } - // - // Find the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL of the specified segment number - // - for (Index = 0; Index < BufferSize; Index++) { - Status = gBS->HandleProtocol ( - HandleBuffer[Index], - &gEfiPciRootBridgeIoProtocolGuid, - (VOID *) &IoDev - ); - if (EFI_ERROR (Status)) { - continue; - } - if (IoDev->SegmentNumber != SegmentNumber) { - IoDev = NULL; - } - } - if (IoDev == NULL) { - ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MM_SEGMENT_NOT_FOUND), gShellDebug1HiiHandle, L"mm", SegmentNumber); + if (PciRootBridgeIo == NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_MM_PCIE_ADDRESS_RANGE), gShellDebug1HiiHandle, L"mm", Address); ShellStatus = SHELL_INVALID_PARAMETER; goto Done; } } - if (AccessType == EfiIo && Address + Size > 0x10000) { - ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MM_ADDRESS_RANGE), gShellDebug1HiiHandle, L"mm"); - ShellStatus = SHELL_INVALID_PARAMETER; - goto Done; - } - - if (AccessType == EfiPciEConfig) { - GetPciEAddressFromInputAddress (Address, &PciEAddress); - } - // - // Set value + // Mode 1: Directly set a value // - if (ShellCommandLineGetRawValue(Package, 2) != NULL) { - if (AccessType == EFIMemoryMappedIo) { - IoDev->Mem.Write (IoDev, Width, Address, 1, &Value); - } else if (AccessType == EfiIo) { - IoDev->Io.Write (IoDev, Width, Address, 1, &Value); - } else if (AccessType == EfiPciConfig) { - IoDev->Pci.Write (IoDev, Width, Address, 1, &Value); - } else if (AccessType == EfiPciEConfig) { - IoDev->Pci.Write (IoDev, Width, PciEAddress, 1, &Value); - } else { - WriteMem (Width, Address, 1, &Value); + Temp = ShellCommandLineGetRawValue (Package, 2); + if (Temp != NULL) { + Status = ShellConvertStringToUint64 (Temp, &Value, TRUE, FALSE); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"mm", Temp); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } + + if (Value > mShellMmMaxNumber[Size]) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"mm", Temp); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; } - ASSERT(ShellStatus == SHELL_SUCCESS); + ShellMmAccess (AccessType, PciRootBridgeIo, CpuIo, FALSE, Address, Size, &Value); goto Done; } - // - // non-interactive mode + // Mode 2: Directly show a value // if (!Interactive) { - Buffer = 0; - if (AccessType == EFIMemoryMappedIo) { - if (!gEfiShellProtocol->BatchIsActive()) { - ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MM_MMIO), gShellDebug1HiiHandle); - } - IoDev->Mem.Read (IoDev, Width, Address, 1, &Buffer); - } else if (AccessType == EfiIo) { - if (!gEfiShellProtocol->BatchIsActive()) { - ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MM_IO), gShellDebug1HiiHandle); - } - IoDev->Io.Read (IoDev, Width, Address, 1, &Buffer); - } else if (AccessType == EfiPciConfig) { - if (!gEfiShellProtocol->BatchIsActive()) { - ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MM_PCI), gShellDebug1HiiHandle); - } - IoDev->Pci.Read (IoDev, Width, Address, 1, &Buffer); - } else if (AccessType == EfiPciEConfig) { - if (!gEfiShellProtocol->BatchIsActive()) { - ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MM_PCIE), gShellDebug1HiiHandle); - } - IoDev->Pci.Read (IoDev, Width, PciEAddress, 1, &Buffer); - } else { - if (!gEfiShellProtocol->BatchIsActive()) { - ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MM_MEM), gShellDebug1HiiHandle); - } - ReadMem (Width, Address, 1, &Buffer); - } - if (!gEfiShellProtocol->BatchIsActive()) { - ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MM_ADDRESS), gShellDebug1HiiHandle, Address); - } - if (Size == 1) { - ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MM_BUF2), gShellDebug1HiiHandle, (UINTN)Buffer); - } else if (Size == 2) { - ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MM_BUF4), gShellDebug1HiiHandle, (UINTN)Buffer); - } else if (Size == 4) { - ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MM_BUF8), gShellDebug1HiiHandle, (UINTN)Buffer); - } else if (Size == 8) { - ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MM_BUF16), gShellDebug1HiiHandle, Buffer); + if (!gEfiShellProtocol->BatchIsActive ()) { + ShellPrintHiiEx (-1, -1, NULL, mShellMmAccessTypeStr[AccessType], gShellDebug1HiiHandle); } + ShellMmAccess (AccessType, PciRootBridgeIo, CpuIo, TRUE, Address, Size, &Buffer); - ShellPrintEx(-1, -1, L"\r\n"); - - ASSERT(ShellStatus == SHELL_SUCCESS); + if (!gEfiShellProtocol->BatchIsActive ()) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_MM_ADDRESS), gShellDebug1HiiHandle, Address); + } + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_MM_BUF), gShellDebug1HiiHandle, Size * 2, Buffer & mShellMmMaxNumber[Size]); + ShellPrintEx (-1, -1, L"\r\n"); goto Done; } + // - // interactive mode + // Mode 3: Show or set values in interactive mode // Complete = FALSE; do { - if (AccessType == EfiIo && Address + Size > 0x10000) { - ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MM_ADDRESS_RANGE2), gShellDebug1HiiHandle, L"mm"); + if ((AccessType == ShellMmIo) && (Address + Size > MAX_UINT16 + 1)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_MM_ADDRESS_RANGE2), gShellDebug1HiiHandle, L"mm"); break; } - Buffer = 0; - if (AccessType == EFIMemoryMappedIo) { - ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MM_MMIO), gShellDebug1HiiHandle); - IoDev->Mem.Read (IoDev, Width, Address, 1, &Buffer); - } else if (AccessType == EfiIo) { - ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MM_IO), gShellDebug1HiiHandle); - IoDev->Io.Read (IoDev, Width, Address, 1, &Buffer); - } else if (AccessType == EfiPciConfig) { - ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MM_PCI), gShellDebug1HiiHandle); - IoDev->Pci.Read (IoDev, Width, Address, 1, &Buffer); - } else if (AccessType == EfiPciEConfig) { - ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MM_PCIE), gShellDebug1HiiHandle); - IoDev->Pci.Read (IoDev, Width, PciEAddress, 1, &Buffer); - } else { - ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MM_MEM), gShellDebug1HiiHandle); - ReadMem (Width, Address, 1, &Buffer); - } - - ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MM_ADDRESS), gShellDebug1HiiHandle, Address); - - if (Size == 1) { - ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MM_BUF2), gShellDebug1HiiHandle, (UINTN)Buffer); - } else if (Size == 2) { - ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MM_BUF4), gShellDebug1HiiHandle, (UINTN)Buffer); - } else if (Size == 4) { - ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MM_BUF8), gShellDebug1HiiHandle, (UINTN)Buffer); - } else if (Size == 8) { - ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MM_BUF16), gShellDebug1HiiHandle, Buffer); - } - ShellPrintEx(-1, -1, L" > "); + ShellMmAccess (AccessType, PciRootBridgeIo, CpuIo, TRUE, Address, Size, &Buffer); + ShellPrintHiiEx (-1, -1, NULL, mShellMmAccessTypeStr[AccessType], gShellDebug1HiiHandle); + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_MM_ADDRESS), gShellDebug1HiiHandle, Address); + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_MM_BUF), gShellDebug1HiiHandle, Size * 2, Buffer & mShellMmMaxNumber[Size]); + ShellPrintEx (-1, -1, L" > "); // // wait user input to modify // if (InputStr != NULL) { - FreePool(InputStr); + FreePool (InputStr); InputStr = NULL; } - ShellPromptForResponse(ShellPromptResponseTypeFreeform, NULL, (VOID**)&InputStr); + ShellPromptForResponse (ShellPromptResponseTypeFreeform, NULL, (VOID**) &InputStr); - // - // skip space characters - // - for (Index = 0; InputStr != NULL && InputStr[Index] == ' '; Index++); - - // - // parse input string - // - if (InputStr != NULL && (InputStr[Index] == '.' || InputStr[Index] == 'q' || InputStr[Index] == 'Q')) { - Complete = TRUE; - } else if (InputStr == NULL || InputStr[Index] == CHAR_NULL) { + if (InputStr != NULL) { // - // Continue to next address + // skip space characters // - } else if (GetHex (InputStr + Index, &Buffer) && Buffer <= MaxNum[Width]) { - if (AccessType == EFIMemoryMappedIo) { - IoDev->Mem.Write (IoDev, Width, Address, 1, &Buffer); - } else if (AccessType == EfiIo) { - IoDev->Io.Write (IoDev, Width, Address, 1, &Buffer); - } else if (AccessType == EfiPciConfig) { - IoDev->Pci.Write (IoDev, Width, Address, 1, &Buffer); - } else if (AccessType == EfiPciEConfig) { - IoDev->Pci.Write (IoDev, Width, PciEAddress, 1, &Buffer); + for (Index = 0; InputStr[Index] == ' '; Index++); + } + + if ((InputStr != NULL) && (InputStr[Index] != CHAR_NULL)) { + if ((InputStr[Index] == '.') || (InputStr[Index] == 'q') || (InputStr[Index] == 'Q')) { + Complete = TRUE; + } else if (!EFI_ERROR (ShellConvertStringToUint64 (InputStr + Index, &Buffer, TRUE, TRUE)) && + (Buffer <= mShellMmMaxNumber[Size]) + ) { + ShellMmAccess (AccessType, PciRootBridgeIo, CpuIo, FALSE, Address, Size, &Buffer); } else { - WriteMem (Width, Address, 1, &Buffer); + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_MM_ERROR), gShellDebug1HiiHandle, L"mm"); + continue; } - } else { - ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MM_ERROR), gShellDebug1HiiHandle, L"mm"); - continue; - // PrintToken (STRING_TOKEN (STR_IOMOD_ERROR), HiiHandle); } Address += Size; - if (AccessType == EfiPciEConfig) { - GetPciEAddressFromInputAddress (Address, &PciEAddress); - } - ShellPrintEx(-1, -1, L"\r\n"); - // Print (L"\n"); + ShellPrintEx (-1, -1, L"\r\n"); } while (!Complete); } - ASSERT(ShellStatus == SHELL_SUCCESS); -Done: + ASSERT (ShellStatus == SHELL_SUCCESS); +Done: if (InputStr != NULL) { - FreePool(InputStr); - } - if (HandleBuffer != NULL) { - FreePool (HandleBuffer); + FreePool (InputStr); } if (Package != NULL) { ShellCommandLineFreeVarList (Package); diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.h b/ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.h index d8755bfefce3..ec15155a0793 100644 --- a/ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.h +++ b/ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.h @@ -1,7 +1,7 @@ /** @file Main file for NULL named library for Profile1 shell command functions. - Copyright (c) 2010 - 2013, Intel Corporation. All rights reserved.
+ Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -38,6 +38,7 @@ #include #include #include +#include #include #include diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.inf b/ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.inf index 55371eb37194..cfbf001bcb25 100644 --- a/ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.inf +++ b/ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.inf @@ -17,7 +17,7 @@ BASE_NAME = UefiShellDebug1CommandsLib FILE_GUID = 90330D51-A99B-4cc8-A2EB-AE22542A3F45 MODULE_TYPE = UEFI_APPLICATION - VERSION_STRING = 1.0 + VERSION_STRING = 1.1 LIBRARY_CLASS = NULL|UEFI_APPLICATION UEFI_DRIVER CONSTRUCTOR = UefiShellDebug1CommandsLibConstructor DESTRUCTOR = UefiShellDebug1CommandsLibDestructor @@ -106,6 +106,7 @@ MemoryAllocationLib BaseLib BaseMemoryLib + IoLib DebugLib ShellCommandLib ShellLib @@ -125,6 +126,7 @@ gEfiPciRootBridgeIoProtocolGuid ## CONSUMES gEfiBlockIoProtocolGuid ## CONSUMES gEfiSimplePointerProtocolGuid ## CONSUMES + gEfiCpuIo2ProtocolGuid ## CONSUMES [Guids] gEfiGlobalVariableGuid ## SOMETIMES_CONSUMES ## GUID diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.uni b/ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.uni index 48ea1e07a369920006a5381c03e0235dff10e42a..2d9bed75c60e9689aab39654f005c2b95690fbb0 100644 GIT binary patch delta 111 zcmV-#0FeK#!wB5J2(V;Slg?HK0Y#G!RUeaN3^J4GQ$h_O0CoUj0Bith0Av6lmjhe@ zA(y0G0T7Zk8k1mD1OrI`Pm>Q-Ba;e6B9ri1KC_rrG6R$1ARv>#2qKdVSqK3tvwvE3 R0h3@b9D~4Ix4>Kh?!@`vC7A#K delta 235 zcmcb!pJUx&jtwaxyul2v4DJlRK+=yPWcqw1M#;%+97e*y453X_AP940@A)Y<$X)QEYq&=iHq2RM|t4Hznb3Jn;H7%C=z3{z!y zVhCk$V=$S#aE~K1P;N5sLiNc4;cQTG3y?Tmj|D^zCq$1SgV|)m$@XwrAb)dgWGUk$ zQ>n=bAuOyxK=(RM?q4lGd4jvz_tGQCNiW<-|x#PKRLlbrukje_IFW??~VWf DV&+0w diff --git a/ShellPkg/ShellPkg.dsc b/ShellPkg/ShellPkg.dsc index c2ce4f9ab365..c9ed0f8fbafc 100644 --- a/ShellPkg/ShellPkg.dsc +++ b/ShellPkg/ShellPkg.dsc @@ -49,6 +49,7 @@ PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf BcfgCommandLib|ShellPkg/Library/UefiShellBcfgCommandLib/UefiShellBcfgCommandLib.inf + IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf [LibraryClasses.ARM] # From e01bbd9f84666a8d0f1d364e7301b99e72ce8f44 Mon Sep 17 00:00:00 2001 From: Jeff Fan Date: Thu, 10 Dec 2015 07:31:17 +0000 Subject: [PATCH 232/525] UefiCpuPkg/UefiCpuPkg.uni: Add PcdCpuNumberOfReservedVariableMtrrs (Sync patch r19182 from main trunk.) Cc: Shumin Qiu Cc: Michael Kinney Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan Reviewed-by: Shumin Qiu git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19210 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/UefiCpuPkg.uni | Bin 21898 -> 22498 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/UefiCpuPkg/UefiCpuPkg.uni b/UefiCpuPkg/UefiCpuPkg.uni index f7ab84c5a246356d85cba9e5c88b15bd7c5e80fe..542b1cd961caa039fb3bee7125f299a86f67ea72 100644 GIT binary patch delta 316 zcmeBL&G=|N2dBvTl|7!rXpnLsj$ zAqObp%TNO37fs$6Y;KRNSAiiPs9OOjhpJzJp$yFg1)v!rKzo8F3-X1#>M;Z`Bm?bn zW+(u<1ldGVT=P-PKP3;zCotFGv>WJ0Y;H{h`l1LZ Date: Thu, 10 Dec 2015 07:31:51 +0000 Subject: [PATCH 233/525] UefiCpuPkg/MtrrLib:Initialize local variables before use them (Sync patch r19183 from main trunk.) Cc: Shumin Qiu Cc: Michael Kinney Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan Reviewed-by: Shumin Qiu git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19211 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/Library/MtrrLib/MtrrLib.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/UefiCpuPkg/Library/MtrrLib/MtrrLib.c b/UefiCpuPkg/Library/MtrrLib/MtrrLib.c index f5b3460f1316..199e165d466a 100644 --- a/UefiCpuPkg/Library/MtrrLib/MtrrLib.c +++ b/UefiCpuPkg/Library/MtrrLib/MtrrLib.c @@ -1489,7 +1489,9 @@ MtrrSetMemoryAttributeWorker ( UINT64 NewValue; MTRR_VARIABLE_SETTINGS *VariableSettings; - MtrrContextValid = FALSE; + MtrrContextValid = FALSE; + VariableMtrrCount = 0; + ZeroMem (&WorkingFixedSettings, sizeof (WorkingFixedSettings)); for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) { FixedSettingsValid[Index] = FALSE; FixedSettingsModified[Index] = FALSE; From 754840385799645d6be1b589d8e3933471f7cb8a Mon Sep 17 00:00:00 2001 From: Jiaxin Wu Date: Fri, 11 Dec 2015 07:32:28 +0000 Subject: [PATCH 234/525] NetworkPkg: Fix the potential NULL pointer dereferenced issue This patch is used to fix the potential NULL pointer dereferenced in function 'ParseDnsResponse'. (Sync patch r19178 from main trunk.) Cc: Fu Siyuan Cc: Zhang Lubo Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiaxin Wu Reviewed-by: Zhang Lubo Reviewed-by: Fu Siyuan git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19220 6f19259b-4bc3-4df7-8a09-765794883524 --- NetworkPkg/DnsDxe/DnsImpl.c | 59 ++++++++++++++++++++++++++----------- 1 file changed, 41 insertions(+), 18 deletions(-) diff --git a/NetworkPkg/DnsDxe/DnsImpl.c b/NetworkPkg/DnsDxe/DnsImpl.c index 42d51f0ed7a2..4f7320e403bf 100644 --- a/NetworkPkg/DnsDxe/DnsImpl.c +++ b/NetworkPkg/DnsDxe/DnsImpl.c @@ -1199,19 +1199,28 @@ ParseDnsResponse ( // // Check the Query type, do some buffer allocations. // - if (QuerySection->Type == DNS_TYPE_A) { - Dns4TokenEntry->Token->RspData.H2AData = AllocatePool (sizeof (DNS_HOST_TO_ADDR_DATA)); - ASSERT (Dns4TokenEntry->Token->RspData.H2AData != NULL); - Dns4TokenEntry->Token->RspData.H2AData->IpList = AllocatePool (DnsHeader->AnswersNum * sizeof (EFI_IPv4_ADDRESS)); - ASSERT (Dns4TokenEntry->Token->RspData.H2AData->IpList != NULL); - } else if (QuerySection->Type == DNS_TYPE_AAAA) { - Dns6TokenEntry->Token->RspData.H2AData = AllocatePool (sizeof (DNS6_HOST_TO_ADDR_DATA)); - ASSERT (Dns6TokenEntry->Token->RspData.H2AData != NULL); - Dns6TokenEntry->Token->RspData.H2AData->IpList = AllocatePool (DnsHeader->AnswersNum * sizeof (EFI_IPv6_ADDRESS)); - ASSERT (Dns6TokenEntry->Token->RspData.H2AData->IpList != NULL); + if (Instance->Service->IpVersion == IP_VERSION_4) { + ASSERT (Dns4TokenEntry != NULL); + if (QuerySection->Type == DNS_TYPE_A) { + Dns4TokenEntry->Token->RspData.H2AData = AllocatePool (sizeof (DNS_HOST_TO_ADDR_DATA)); + ASSERT (Dns4TokenEntry->Token->RspData.H2AData != NULL); + Dns4TokenEntry->Token->RspData.H2AData->IpList = AllocatePool (DnsHeader->AnswersNum * sizeof (EFI_IPv4_ADDRESS)); + ASSERT (Dns4TokenEntry->Token->RspData.H2AData->IpList != NULL); + } else { + Status = EFI_UNSUPPORTED; + goto ON_EXIT; + } } else { - Status = EFI_UNSUPPORTED; - goto ON_EXIT; + ASSERT (Dns6TokenEntry != NULL); + if (QuerySection->Type == DNS_TYPE_AAAA) { + Dns6TokenEntry->Token->RspData.H2AData = AllocatePool (sizeof (DNS6_HOST_TO_ADDR_DATA)); + ASSERT (Dns6TokenEntry->Token->RspData.H2AData != NULL); + Dns6TokenEntry->Token->RspData.H2AData->IpList = AllocatePool (DnsHeader->AnswersNum * sizeof (EFI_IPv6_ADDRESS)); + ASSERT (Dns6TokenEntry->Token->RspData.H2AData->IpList != NULL); + } else { + Status = EFI_UNSUPPORTED; + goto ON_EXIT; + } } // @@ -1240,7 +1249,7 @@ ParseDnsResponse ( // // This is address entry, get Data. // - ASSERT (AnswerSection->DataLength == 4); + ASSERT (Dns4TokenEntry != NULL && AnswerSection->DataLength == 4); HostAddr4 = Dns4TokenEntry->Token->RspData.H2AData->IpList; AnswerData = (UINT8 *) AnswerSection + sizeof (*AnswerSection); @@ -1282,7 +1291,7 @@ ParseDnsResponse ( // // This is address entry, get Data. // - ASSERT (AnswerSection->DataLength == 16); + ASSERT (Dns6TokenEntry != NULL && AnswerSection->DataLength == 16); HostAddr6 = Dns6TokenEntry->Token->RspData.H2AData->IpList; AnswerData = (UINT8 *) AnswerSection + sizeof (*AnswerSection); @@ -1333,16 +1342,29 @@ ParseDnsResponse ( AnswerSectionNum ++; } - if (QuerySection->Type == DNS_TYPE_A) { - Dns4TokenEntry->Token->RspData.H2AData->IpCount = IpCount; - } else if (QuerySection->Type == DNS_TYPE_AAAA) { - Dns6TokenEntry->Token->RspData.H2AData->IpCount = IpCount; + if (Instance->Service->IpVersion == IP_VERSION_4) { + ASSERT (Dns4TokenEntry != NULL); + if (QuerySection->Type == DNS_TYPE_A) { + Dns4TokenEntry->Token->RspData.H2AData->IpCount = IpCount; + } else { + Status = EFI_UNSUPPORTED; + goto ON_EXIT; + } + } else { + ASSERT (Dns6TokenEntry != NULL); + if (QuerySection->Type == DNS_TYPE_AAAA) { + Dns6TokenEntry->Token->RspData.H2AData->IpCount = IpCount; + } else { + Status = EFI_UNSUPPORTED; + goto ON_EXIT; + } } // // Parsing is complete, SignalEvent here. // if (Instance->Service->IpVersion == IP_VERSION_4) { + ASSERT (Dns4TokenEntry != NULL); Dns4RemoveTokenEntry (&Instance->Dns4TxTokens, Dns4TokenEntry); Dns4TokenEntry->Token->Status = EFI_SUCCESS; if (Dns4TokenEntry->Token->Event != NULL) { @@ -1350,6 +1372,7 @@ ParseDnsResponse ( DispatchDpc (); } } else { + ASSERT (Dns6TokenEntry != NULL); Dns6RemoveTokenEntry (&Instance->Dns6TxTokens, Dns6TokenEntry); Dns6TokenEntry->Token->Status = EFI_SUCCESS; if (Dns6TokenEntry->Token->Event != NULL) { From 540afa672ba3f0236835f8ef7e2030d61e56039e Mon Sep 17 00:00:00 2001 From: Hao Wu Date: Fri, 11 Dec 2015 07:33:24 +0000 Subject: [PATCH 235/525] MdePkg UefiScsiLib: Add non-blocking support for SCSI Read/Write command Four new functions are added to UefiScsiLib: ScsiRead10CommandEx ScsiWrite10CommandEx ScsiRead16CommandEx ScsiWrite16CommandEx They support both blocking and non-blocking SCSI Read/Write operation depending on the optional parameter 'Event' passed to those APIs. When 'Event' is NULL, these four functions will call the non-EX version couterparts to execute blocking SCSI I/O. When 'Event' is not NULL, non-blocking I/O operation is executed. (Sync patch r19214 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Hao Wu Reviewed-by: Feng Tian git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19221 6f19259b-4bc3-4df7-8a09-765794883524 --- MdePkg/Include/Library/UefiScsiLib.h | 360 ++++++++++ MdePkg/Library/UefiScsiLib/UefiScsiLib.c | 776 +++++++++++++++++++++ MdePkg/Library/UefiScsiLib/UefiScsiLib.inf | 4 +- 3 files changed, 1139 insertions(+), 1 deletion(-) diff --git a/MdePkg/Include/Library/UefiScsiLib.h b/MdePkg/Include/Library/UefiScsiLib.h index 26e4aa4e0f02..067acfdb4347 100644 --- a/MdePkg/Include/Library/UefiScsiLib.h +++ b/MdePkg/Include/Library/UefiScsiLib.h @@ -818,4 +818,364 @@ ScsiWrite16Command ( IN UINT32 SectorSize ); + +/** + Execute blocking/non-blocking Read(10) SCSI command on a specific SCSI + target. + + Executes the SCSI Read(10) command on the SCSI target specified by ScsiIo. + When Event is NULL, blocking command will be executed. Otherwise non-blocking + command will be executed. + For blocking I/O, if Timeout is zero, this function will wait indefinitely + for the command to complete. If Timeout is greater than zero, then the + command is executed and will timeout after Timeout 100 ns units. + For non-blocking I/O, if Timeout is zero, Event will be signaled only after + the command to completes. If Timeout is greater than zero, Event will also be + signaled after Timeout 100 ns units. + The StartLba and SectorSize parameters are used to construct the CDB for this + SCSI command. + + If ScsiIo is NULL, then ASSERT(). + If SenseDataLength is NULL, then ASSERT(). + If HostAdapterStatus is NULL, then ASSERT(). + If TargetStatus is NULL, then ASSERT(). + If DataLength is NULL, then ASSERT(). + + If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet + buffer alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise + EFI_INVALID_PARAMETER gets returned. + + If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet + buffer alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise + EFI_INVALID_PARAMETER gets returned. + + @param[in] ScsiIo A pointer to SCSI IO protocol. + @param[in] Timeout The length of timeout period. + @param[in, out] SenseData A pointer to output sense data. + @param[in, out] SenseDataLength The length of output sense data. + @param[out] HostAdapterStatus The status of Host Adapter. + @param[out] TargetStatus The status of the target. + @param[in, out] DataBuffer Read 16 command data. + @param[in, out] DataLength The length of data buffer. + @param[in] StartLba The start address of LBA. + @param[in] SectorSize The number of contiguous logical blocks + of data that shall be transferred. + @param[in] Event If the SCSI target does not support + non-blocking I/O, then Event is ignored, + and blocking I/O is performed. If Event + is NULL, then blocking I/O is performed. + If Event is not NULL and non-blocking + I/O is supported, then non-blocking I/O + is performed, and Event will be signaled + when the SCSI Read(10) command + completes. + + @retval EFI_SUCCESS Command is executed successfully. + @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, + but the entire DataBuffer could not be + transferred. The actual number of bytes + transferred is returned in DataLength. + @retval EFI_NOT_READY The SCSI Request Packet could not be + sent because there are too many SCSI + Command Packets already queued. + @retval EFI_DEVICE_ERROR A device error occurred while attempting + to send SCSI Request Packet. + @retval EFI_UNSUPPORTED The command described by the SCSI + Request Packet is not supported by the + SCSI initiator(i.e., SCSI Host + Controller) + @retval EFI_TIMEOUT A timeout occurred while waiting for the + SCSI Request Packet to execute. + @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet + are invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due + to a lack of resources. + +**/ +EFI_STATUS +EFIAPI +ScsiRead10CommandEx ( + IN EFI_SCSI_IO_PROTOCOL *ScsiIo, + IN UINT64 Timeout, + IN OUT VOID *SenseData, OPTIONAL + IN OUT UINT8 *SenseDataLength, + OUT UINT8 *HostAdapterStatus, + OUT UINT8 *TargetStatus, + IN OUT VOID *DataBuffer, OPTIONAL + IN OUT UINT32 *DataLength, + IN UINT32 StartLba, + IN UINT32 SectorSize, + IN EFI_EVENT Event OPTIONAL + ); + + +/** + Execute blocking/non-blocking Write(10) SCSI command on a specific SCSI + target. + + Executes the SCSI Write(10) command on the SCSI target specified by ScsiIo. + When Event is NULL, blocking command will be executed. Otherwise non-blocking + command will be executed. + For blocking I/O, if Timeout is zero, this function will wait indefinitely + for the command to complete. If Timeout is greater than zero, then the + command is executed and will timeout after Timeout 100 ns units. + For non-blocking I/O, if Timeout is zero, Event will be signaled only after + the command to completes. If Timeout is greater than zero, Event will also be + signaled after Timeout 100 ns units. + The StartLba and SectorSize parameters are used to construct the CDB for this + SCSI command. + + If ScsiIo is NULL, then ASSERT(). + If SenseDataLength is NULL, then ASSERT(). + If HostAdapterStatus is NULL, then ASSERT(). + If TargetStatus is NULL, then ASSERT(). + If DataLength is NULL, then ASSERT(). + + If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet + buffer alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise + EFI_INVALID_PARAMETER gets returned. + + If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet + buffer alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise + EFI_INVALID_PARAMETER gets returned. + + @param[in] ScsiIo SCSI IO Protocol to use + @param[in] Timeout The length of timeout period. + @param[in, out] SenseData A pointer to output sense data. + @param[in, out] SenseDataLength The length of output sense data. + @param[out] HostAdapterStatus The status of Host Adapter. + @param[out] TargetStatus The status of the target. + @param[in, out] DataBuffer A pointer to a data buffer. + @param[in, out] DataLength The length of data buffer. + @param[in] StartLba The start address of LBA. + @param[in] SectorSize The number of contiguous logical blocks + of data that shall be transferred. + @param[in] Event If the SCSI target does not support + non-blocking I/O, then Event is ignored, + and blocking I/O is performed. If Event + is NULL, then blocking I/O is performed. + If Event is not NULL and non-blocking + I/O is supported, then non-blocking I/O + is performed, and Event will be signaled + when the SCSI Write(10) command + completes. + + @retval EFI_SUCCESS Command is executed successfully. + @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, + but the entire DataBuffer could not be + transferred. The actual number of bytes + transferred is returned in DataLength. + @retval EFI_NOT_READY The SCSI Request Packet could not be + sent because there are too many SCSI + Command Packets already queued. + @retval EFI_DEVICE_ERROR A device error occurred while attempting + to send SCSI Request Packet. + @retval EFI_UNSUPPORTED The command described by the SCSI + Request Packet is not supported by the + SCSI initiator(i.e., SCSI Host + Controller) + @retval EFI_TIMEOUT A timeout occurred while waiting for the + SCSI Request Packet to execute. + @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet + are invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due + to a lack of resources. + +**/ +EFI_STATUS +EFIAPI +ScsiWrite10CommandEx ( + IN EFI_SCSI_IO_PROTOCOL *ScsiIo, + IN UINT64 Timeout, + IN OUT VOID *SenseData, OPTIONAL + IN OUT UINT8 *SenseDataLength, + OUT UINT8 *HostAdapterStatus, + OUT UINT8 *TargetStatus, + IN OUT VOID *DataBuffer, OPTIONAL + IN OUT UINT32 *DataLength, + IN UINT32 StartLba, + IN UINT32 SectorSize, + IN EFI_EVENT Event OPTIONAL + ); + + +/** + Execute blocking/non-blocking Read(16) SCSI command on a specific SCSI + target. + + Executes the SCSI Read(16) command on the SCSI target specified by ScsiIo. + When Event is NULL, blocking command will be executed. Otherwise non-blocking + command will be executed. + For blocking I/O, if Timeout is zero, this function will wait indefinitely + for the command to complete. If Timeout is greater than zero, then the + command is executed and will timeout after Timeout 100 ns units. + For non-blocking I/O, if Timeout is zero, Event will be signaled only after + the command to completes. If Timeout is greater than zero, Event will also be + signaled after Timeout 100 ns units. + The StartLba and SectorSize parameters are used to construct the CDB for this + SCSI command. + + If ScsiIo is NULL, then ASSERT(). + If SenseDataLength is NULL, then ASSERT(). + If HostAdapterStatus is NULL, then ASSERT(). + If TargetStatus is NULL, then ASSERT(). + If DataLength is NULL, then ASSERT(). + + If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet + buffer alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise + EFI_INVALID_PARAMETER gets returned. + + If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet + buffer alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise + EFI_INVALID_PARAMETER gets returned. + + @param[in] ScsiIo A pointer to SCSI IO protocol. + @param[in] Timeout The length of timeout period. + @param[in, out] SenseData A pointer to output sense data. + @param[in, out] SenseDataLength The length of output sense data. + @param[out] HostAdapterStatus The status of Host Adapter. + @param[out] TargetStatus The status of the target. + @param[in, out] DataBuffer Read 16 command data. + @param[in, out] DataLength The length of data buffer. + @param[in] StartLba The start address of LBA. + @param[in] SectorSize The number of contiguous logical blocks + of data that shall be transferred. + @param[in] Event If the SCSI target does not support + non-blocking I/O, then Event is ignored, + and blocking I/O is performed. If Event + is NULL, then blocking I/O is performed. + If Event is not NULL and non-blocking + I/O is supported, then non-blocking I/O + is performed, and Event will be signaled + when the SCSI Read(16) command + completes. + + @retval EFI_SUCCESS Command is executed successfully. + @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, + but the entire DataBuffer could not be + transferred. The actual number of bytes + transferred is returned in DataLength. + @retval EFI_NOT_READY The SCSI Request Packet could not be + sent because there are too many SCSI + Command Packets already queued. + @retval EFI_DEVICE_ERROR A device error occurred while attempting + to send SCSI Request Packet. + @retval EFI_UNSUPPORTED The command described by the SCSI + Request Packet is not supported by the + SCSI initiator(i.e., SCSI Host + Controller) + @retval EFI_TIMEOUT A timeout occurred while waiting for the + SCSI Request Packet to execute. + @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet + are invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due + to a lack of resources. + +**/ +EFI_STATUS +EFIAPI +ScsiRead16CommandEx ( + IN EFI_SCSI_IO_PROTOCOL *ScsiIo, + IN UINT64 Timeout, + IN OUT VOID *SenseData, OPTIONAL + IN OUT UINT8 *SenseDataLength, + OUT UINT8 *HostAdapterStatus, + OUT UINT8 *TargetStatus, + IN OUT VOID *DataBuffer, OPTIONAL + IN OUT UINT32 *DataLength, + IN UINT64 StartLba, + IN UINT32 SectorSize, + IN EFI_EVENT Event OPTIONAL + ); + + +/** + Execute blocking/non-blocking Write(16) SCSI command on a specific SCSI + target. + + Executes the SCSI Write(16) command on the SCSI target specified by ScsiIo. + When Event is NULL, blocking command will be executed. Otherwise non-blocking + command will be executed. + For blocking I/O, if Timeout is zero, this function will wait indefinitely + for the command to complete. If Timeout is greater than zero, then the + command is executed and will timeout after Timeout 100 ns units. + For non-blocking I/O, if Timeout is zero, Event will be signaled only after + the command to completes. If Timeout is greater than zero, Event will also be + signaled after Timeout 100 ns units. + The StartLba and SectorSize parameters are used to construct the CDB for this + SCSI command. + + If ScsiIo is NULL, then ASSERT(). + If SenseDataLength is NULL, then ASSERT(). + If HostAdapterStatus is NULL, then ASSERT(). + If TargetStatus is NULL, then ASSERT(). + If DataLength is NULL, then ASSERT(). + + If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet + buffer alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise + EFI_INVALID_PARAMETER gets returned. + + If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet + buffer alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise + EFI_INVALID_PARAMETER gets returned. + + @param[in] ScsiIo SCSI IO Protocol to use + @param[in] Timeout The length of timeout period. + @param[in, out] SenseData A pointer to output sense data. + @param[in, out] SenseDataLength The length of output sense data. + @param[out] HostAdapterStatus The status of Host Adapter. + @param[out] TargetStatus The status of the target. + @param[in, out] DataBuffer A pointer to a data buffer. + @param[in, out] DataLength The length of data buffer. + @param[in] StartLba The start address of LBA. + @param[in] SectorSize The number of contiguous logical blocks + of data that shall be transferred. + @param[in] Event If the SCSI target does not support + non-blocking I/O, then Event is ignored, + and blocking I/O is performed. If Event + is NULL, then blocking I/O is performed. + If Event is not NULL and non-blocking + I/O is supported, then non-blocking I/O + is performed, and Event will be signaled + when the SCSI Write(16) command + completes. + + @retval EFI_SUCCESS Command is executed successfully. + @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, + but the entire DataBuffer could not be + transferred. The actual number of bytes + transferred is returned in DataLength. + @retval EFI_NOT_READY The SCSI Request Packet could not be + sent because there are too many SCSI + Command Packets already queued. + @retval EFI_DEVICE_ERROR A device error occurred while attempting + to send SCSI Request Packet. + @retval EFI_UNSUPPORTED The command described by the SCSI + Request Packet is not supported by the + SCSI initiator(i.e., SCSI Host + Controller) + @retval EFI_TIMEOUT A timeout occurred while waiting for the + SCSI Request Packet to execute. + @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet + are invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due + to a lack of resources. + +**/ +EFI_STATUS +EFIAPI +ScsiWrite16CommandEx ( + IN EFI_SCSI_IO_PROTOCOL *ScsiIo, + IN UINT64 Timeout, + IN OUT VOID *SenseData, OPTIONAL + IN OUT UINT8 *SenseDataLength, + OUT UINT8 *HostAdapterStatus, + OUT UINT8 *TargetStatus, + IN OUT VOID *DataBuffer, OPTIONAL + IN OUT UINT32 *DataLength, + IN UINT64 StartLba, + IN UINT32 SectorSize, + IN EFI_EVENT Event OPTIONAL + ); + #endif diff --git a/MdePkg/Library/UefiScsiLib/UefiScsiLib.c b/MdePkg/Library/UefiScsiLib/UefiScsiLib.c index 89f261777bb6..d8babcee406a 100644 --- a/MdePkg/Library/UefiScsiLib/UefiScsiLib.c +++ b/MdePkg/Library/UefiScsiLib/UefiScsiLib.c @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include @@ -29,6 +31,39 @@ #define EFI_SCSI_OP_LENGTH_TEN 0xa #define EFI_SCSI_OP_LENGTH_SIXTEEN 0x10 +// +// The context structure used when non-blocking SCSI read/write operation +// completes. +// +typedef struct { + /// + /// The SCSI request packet to send to the SCSI controller specified by + /// the device handle. + /// + EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket; + /// + /// The length of the output sense data. + /// + UINT8 *SenseDataLength; + /// + /// The status of the SCSI host adapter. + /// + UINT8 *HostAdapterStatus; + /// + /// The status of the target SCSI device. + /// + UINT8 *TargetStatus; + /// + /// The length of the data buffer for the SCSI read/write command. + /// + UINT32 *DataLength; + /// + /// The caller event to be signaled when the SCSI read/write command + /// completes. + /// + EFI_EVENT CallerEvent; +} EFI_SCSI_LIB_ASYNC_CONTEXT; + /** @@ -1249,3 +1284,744 @@ ScsiWrite16Command ( return Status; } + + +/** + Internal helper notify function in which update the result of the + non-blocking SCSI Read/Write commands and signal caller event. + + @param Event The instance of EFI_EVENT. + @param Context The parameter passed in. + +**/ +VOID +EFIAPI +ScsiLibNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_SCSI_LIB_ASYNC_CONTEXT *LibContext; + EFI_SCSI_IO_SCSI_REQUEST_PACKET *CommandPacket; + EFI_EVENT CallerEvent; + + LibContext = (EFI_SCSI_LIB_ASYNC_CONTEXT *) Context; + CommandPacket = &LibContext->CommandPacket; + CallerEvent = LibContext->CallerEvent; + + // + // Update SCSI Read/Write operation results + // + *LibContext->SenseDataLength = CommandPacket->SenseDataLength; + *LibContext->HostAdapterStatus = CommandPacket->HostAdapterStatus; + *LibContext->TargetStatus = CommandPacket->TargetStatus; + if (CommandPacket->InDataBuffer != NULL) { + *LibContext->DataLength = CommandPacket->InTransferLength; + } else { + *LibContext->DataLength = CommandPacket->OutTransferLength; + } + + if (CommandPacket->Cdb != NULL) { + FreePool (CommandPacket->Cdb); + } + FreePool (Context); + + gBS->CloseEvent (Event); + gBS->SignalEvent (CallerEvent); +} + + +/** + Execute blocking/non-blocking Read(10) SCSI command on a specific SCSI + target. + + Executes the SCSI Read(10) command on the SCSI target specified by ScsiIo. + When Event is NULL, blocking command will be executed. Otherwise non-blocking + command will be executed. + For blocking I/O, if Timeout is zero, this function will wait indefinitely + for the command to complete. If Timeout is greater than zero, then the + command is executed and will timeout after Timeout 100 ns units. + For non-blocking I/O, if Timeout is zero, Event will be signaled only after + the command to completes. If Timeout is greater than zero, Event will also be + signaled after Timeout 100 ns units. + The StartLba and SectorSize parameters are used to construct the CDB for this + SCSI command. + + If ScsiIo is NULL, then ASSERT(). + If SenseDataLength is NULL, then ASSERT(). + If HostAdapterStatus is NULL, then ASSERT(). + If TargetStatus is NULL, then ASSERT(). + If DataLength is NULL, then ASSERT(). + + If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet + buffer alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise + EFI_INVALID_PARAMETER gets returned. + + If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet + buffer alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise + EFI_INVALID_PARAMETER gets returned. + + @param[in] ScsiIo A pointer to SCSI IO protocol. + @param[in] Timeout The length of timeout period. + @param[in, out] SenseData A pointer to output sense data. + @param[in, out] SenseDataLength The length of output sense data. + @param[out] HostAdapterStatus The status of Host Adapter. + @param[out] TargetStatus The status of the target. + @param[in, out] DataBuffer Read 16 command data. + @param[in, out] DataLength The length of data buffer. + @param[in] StartLba The start address of LBA. + @param[in] SectorSize The number of contiguous logical blocks + of data that shall be transferred. + @param[in] Event If the SCSI target does not support + non-blocking I/O, then Event is ignored, + and blocking I/O is performed. If Event + is NULL, then blocking I/O is performed. + If Event is not NULL and non-blocking + I/O is supported, then non-blocking I/O + is performed, and Event will be signaled + when the SCSI Read(10) command + completes. + + @retval EFI_SUCCESS Command is executed successfully. + @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, + but the entire DataBuffer could not be + transferred. The actual number of bytes + transferred is returned in DataLength. + @retval EFI_NOT_READY The SCSI Request Packet could not be + sent because there are too many SCSI + Command Packets already queued. + @retval EFI_DEVICE_ERROR A device error occurred while attempting + to send SCSI Request Packet. + @retval EFI_UNSUPPORTED The command described by the SCSI + Request Packet is not supported by the + SCSI initiator(i.e., SCSI Host + Controller) + @retval EFI_TIMEOUT A timeout occurred while waiting for the + SCSI Request Packet to execute. + @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet + are invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due + to a lack of resources. + +**/ +EFI_STATUS +EFIAPI +ScsiRead10CommandEx ( + IN EFI_SCSI_IO_PROTOCOL *ScsiIo, + IN UINT64 Timeout, + IN OUT VOID *SenseData, OPTIONAL + IN OUT UINT8 *SenseDataLength, + OUT UINT8 *HostAdapterStatus, + OUT UINT8 *TargetStatus, + IN OUT VOID *DataBuffer, OPTIONAL + IN OUT UINT32 *DataLength, + IN UINT32 StartLba, + IN UINT32 SectorSize, + IN EFI_EVENT Event OPTIONAL + ) +{ + EFI_SCSI_LIB_ASYNC_CONTEXT *Context; + EFI_SCSI_IO_SCSI_REQUEST_PACKET *CommandPacket; + EFI_STATUS Status; + UINT8 *Cdb; + EFI_EVENT SelfEvent; + + if (Event == NULL) { + return ScsiRead10Command ( + ScsiIo, + Timeout, + SenseData, + SenseDataLength, + HostAdapterStatus, + TargetStatus, + DataBuffer, + DataLength, + StartLba, + SectorSize + ); + } + + ASSERT (SenseDataLength != NULL); + ASSERT (HostAdapterStatus != NULL); + ASSERT (TargetStatus != NULL); + ASSERT (DataLength != NULL); + ASSERT (ScsiIo != NULL); + + Context = AllocateZeroPool (sizeof (EFI_SCSI_LIB_ASYNC_CONTEXT)); + if (Context == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Cdb = AllocateZeroPool (EFI_SCSI_OP_LENGTH_TEN); + if (Cdb == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ErrorExit; + } + + Context->SenseDataLength = SenseDataLength; + Context->HostAdapterStatus = HostAdapterStatus; + Context->TargetStatus = TargetStatus; + Context->CallerEvent = Event; + + CommandPacket = &Context->CommandPacket; + CommandPacket->Timeout = Timeout; + CommandPacket->InDataBuffer = DataBuffer; + CommandPacket->SenseData = SenseData; + CommandPacket->InTransferLength = *DataLength; + CommandPacket->Cdb = Cdb; + // + // Fill Cdb for Read (10) Command + // + Cdb[0] = EFI_SCSI_OP_READ10; + WriteUnaligned32 ((UINT32 *)&Cdb[2], SwapBytes32 (StartLba)); + WriteUnaligned16 ((UINT16 *)&Cdb[7], SwapBytes16 ((UINT16) SectorSize)); + + CommandPacket->CdbLength = EFI_SCSI_OP_LENGTH_TEN; + CommandPacket->DataDirection = EFI_SCSI_DATA_IN; + CommandPacket->SenseDataLength = *SenseDataLength; + + // + // Create Event + // + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + ScsiLibNotify, + Context, + &SelfEvent + ); + if (EFI_ERROR(Status)) { + goto ErrorExit; + } + + return ScsiIo->ExecuteScsiCommand (ScsiIo, CommandPacket, SelfEvent); + +ErrorExit: + if (Context != NULL) { + FreePool (Context); + } + + return Status; +} + + +/** + Execute blocking/non-blocking Write(10) SCSI command on a specific SCSI + target. + + Executes the SCSI Write(10) command on the SCSI target specified by ScsiIo. + When Event is NULL, blocking command will be executed. Otherwise non-blocking + command will be executed. + For blocking I/O, if Timeout is zero, this function will wait indefinitely + for the command to complete. If Timeout is greater than zero, then the + command is executed and will timeout after Timeout 100 ns units. + For non-blocking I/O, if Timeout is zero, Event will be signaled only after + the command to completes. If Timeout is greater than zero, Event will also be + signaled after Timeout 100 ns units. + The StartLba and SectorSize parameters are used to construct the CDB for this + SCSI command. + + If ScsiIo is NULL, then ASSERT(). + If SenseDataLength is NULL, then ASSERT(). + If HostAdapterStatus is NULL, then ASSERT(). + If TargetStatus is NULL, then ASSERT(). + If DataLength is NULL, then ASSERT(). + + If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet + buffer alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise + EFI_INVALID_PARAMETER gets returned. + + If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet + buffer alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise + EFI_INVALID_PARAMETER gets returned. + + @param[in] ScsiIo SCSI IO Protocol to use + @param[in] Timeout The length of timeout period. + @param[in, out] SenseData A pointer to output sense data. + @param[in, out] SenseDataLength The length of output sense data. + @param[out] HostAdapterStatus The status of Host Adapter. + @param[out] TargetStatus The status of the target. + @param[in, out] DataBuffer A pointer to a data buffer. + @param[in, out] DataLength The length of data buffer. + @param[in] StartLba The start address of LBA. + @param[in] SectorSize The number of contiguous logical blocks + of data that shall be transferred. + @param[in] Event If the SCSI target does not support + non-blocking I/O, then Event is ignored, + and blocking I/O is performed. If Event + is NULL, then blocking I/O is performed. + If Event is not NULL and non-blocking + I/O is supported, then non-blocking I/O + is performed, and Event will be signaled + when the SCSI Write(10) command + completes. + + @retval EFI_SUCCESS Command is executed successfully. + @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, + but the entire DataBuffer could not be + transferred. The actual number of bytes + transferred is returned in DataLength. + @retval EFI_NOT_READY The SCSI Request Packet could not be + sent because there are too many SCSI + Command Packets already queued. + @retval EFI_DEVICE_ERROR A device error occurred while attempting + to send SCSI Request Packet. + @retval EFI_UNSUPPORTED The command described by the SCSI + Request Packet is not supported by the + SCSI initiator(i.e., SCSI Host + Controller) + @retval EFI_TIMEOUT A timeout occurred while waiting for the + SCSI Request Packet to execute. + @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet + are invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due + to a lack of resources. + +**/ +EFI_STATUS +EFIAPI +ScsiWrite10CommandEx ( + IN EFI_SCSI_IO_PROTOCOL *ScsiIo, + IN UINT64 Timeout, + IN OUT VOID *SenseData, OPTIONAL + IN OUT UINT8 *SenseDataLength, + OUT UINT8 *HostAdapterStatus, + OUT UINT8 *TargetStatus, + IN OUT VOID *DataBuffer, OPTIONAL + IN OUT UINT32 *DataLength, + IN UINT32 StartLba, + IN UINT32 SectorSize, + IN EFI_EVENT Event OPTIONAL + ) +{ + EFI_SCSI_LIB_ASYNC_CONTEXT *Context; + EFI_SCSI_IO_SCSI_REQUEST_PACKET *CommandPacket; + EFI_STATUS Status; + UINT8 *Cdb; + EFI_EVENT SelfEvent; + + if (Event == NULL) { + return ScsiWrite10Command ( + ScsiIo, + Timeout, + SenseData, + SenseDataLength, + HostAdapterStatus, + TargetStatus, + DataBuffer, + DataLength, + StartLba, + SectorSize + ); + } + + ASSERT (SenseDataLength != NULL); + ASSERT (HostAdapterStatus != NULL); + ASSERT (TargetStatus != NULL); + ASSERT (DataLength != NULL); + ASSERT (ScsiIo != NULL); + + Context = AllocateZeroPool (sizeof (EFI_SCSI_LIB_ASYNC_CONTEXT)); + if (Context == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Cdb = AllocateZeroPool (EFI_SCSI_OP_LENGTH_TEN); + if (Cdb == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ErrorExit; + } + + Context->SenseDataLength = SenseDataLength; + Context->HostAdapterStatus = HostAdapterStatus; + Context->TargetStatus = TargetStatus; + Context->CallerEvent = Event; + + CommandPacket = &Context->CommandPacket; + CommandPacket->Timeout = Timeout; + CommandPacket->OutDataBuffer = DataBuffer; + CommandPacket->SenseData = SenseData; + CommandPacket->OutTransferLength = *DataLength; + CommandPacket->Cdb = Cdb; + // + // Fill Cdb for Write (10) Command + // + Cdb[0] = EFI_SCSI_OP_WRITE10; + WriteUnaligned32 ((UINT32 *)&Cdb[2], SwapBytes32 (StartLba)); + WriteUnaligned16 ((UINT16 *)&Cdb[7], SwapBytes16 ((UINT16) SectorSize)); + + CommandPacket->CdbLength = EFI_SCSI_OP_LENGTH_TEN; + CommandPacket->DataDirection = EFI_SCSI_DATA_OUT; + CommandPacket->SenseDataLength = *SenseDataLength; + + // + // Create Event + // + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + ScsiLibNotify, + Context, + &SelfEvent + ); + if (EFI_ERROR(Status)) { + goto ErrorExit; + } + + return ScsiIo->ExecuteScsiCommand (ScsiIo, CommandPacket, Event); + +ErrorExit: + if (Context != NULL) { + FreePool (Context); + } + + return Status; +} + + +/** + Execute blocking/non-blocking Read(16) SCSI command on a specific SCSI + target. + + Executes the SCSI Read(16) command on the SCSI target specified by ScsiIo. + When Event is NULL, blocking command will be executed. Otherwise non-blocking + command will be executed. + For blocking I/O, if Timeout is zero, this function will wait indefinitely + for the command to complete. If Timeout is greater than zero, then the + command is executed and will timeout after Timeout 100 ns units. + For non-blocking I/O, if Timeout is zero, Event will be signaled only after + the command to completes. If Timeout is greater than zero, Event will also be + signaled after Timeout 100 ns units. + The StartLba and SectorSize parameters are used to construct the CDB for this + SCSI command. + + If ScsiIo is NULL, then ASSERT(). + If SenseDataLength is NULL, then ASSERT(). + If HostAdapterStatus is NULL, then ASSERT(). + If TargetStatus is NULL, then ASSERT(). + If DataLength is NULL, then ASSERT(). + + If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet + buffer alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise + EFI_INVALID_PARAMETER gets returned. + + If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet + buffer alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise + EFI_INVALID_PARAMETER gets returned. + + @param[in] ScsiIo A pointer to SCSI IO protocol. + @param[in] Timeout The length of timeout period. + @param[in, out] SenseData A pointer to output sense data. + @param[in, out] SenseDataLength The length of output sense data. + @param[out] HostAdapterStatus The status of Host Adapter. + @param[out] TargetStatus The status of the target. + @param[in, out] DataBuffer Read 16 command data. + @param[in, out] DataLength The length of data buffer. + @param[in] StartLba The start address of LBA. + @param[in] SectorSize The number of contiguous logical blocks + of data that shall be transferred. + @param[in] Event If the SCSI target does not support + non-blocking I/O, then Event is ignored, + and blocking I/O is performed. If Event + is NULL, then blocking I/O is performed. + If Event is not NULL and non-blocking + I/O is supported, then non-blocking I/O + is performed, and Event will be signaled + when the SCSI Read(16) command + completes. + + @retval EFI_SUCCESS Command is executed successfully. + @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, + but the entire DataBuffer could not be + transferred. The actual number of bytes + transferred is returned in DataLength. + @retval EFI_NOT_READY The SCSI Request Packet could not be + sent because there are too many SCSI + Command Packets already queued. + @retval EFI_DEVICE_ERROR A device error occurred while attempting + to send SCSI Request Packet. + @retval EFI_UNSUPPORTED The command described by the SCSI + Request Packet is not supported by the + SCSI initiator(i.e., SCSI Host + Controller) + @retval EFI_TIMEOUT A timeout occurred while waiting for the + SCSI Request Packet to execute. + @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet + are invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due + to a lack of resources. + +**/ +EFI_STATUS +EFIAPI +ScsiRead16CommandEx ( + IN EFI_SCSI_IO_PROTOCOL *ScsiIo, + IN UINT64 Timeout, + IN OUT VOID *SenseData, OPTIONAL + IN OUT UINT8 *SenseDataLength, + OUT UINT8 *HostAdapterStatus, + OUT UINT8 *TargetStatus, + IN OUT VOID *DataBuffer, OPTIONAL + IN OUT UINT32 *DataLength, + IN UINT64 StartLba, + IN UINT32 SectorSize, + IN EFI_EVENT Event OPTIONAL + ) +{ + EFI_SCSI_LIB_ASYNC_CONTEXT *Context; + EFI_SCSI_IO_SCSI_REQUEST_PACKET *CommandPacket; + EFI_STATUS Status; + UINT8 *Cdb; + EFI_EVENT SelfEvent; + + if (Event == NULL) { + return ScsiRead16Command ( + ScsiIo, + Timeout, + SenseData, + SenseDataLength, + HostAdapterStatus, + TargetStatus, + DataBuffer, + DataLength, + StartLba, + SectorSize + ); + } + + ASSERT (SenseDataLength != NULL); + ASSERT (HostAdapterStatus != NULL); + ASSERT (TargetStatus != NULL); + ASSERT (DataLength != NULL); + ASSERT (ScsiIo != NULL); + + Context = AllocateZeroPool (sizeof (EFI_SCSI_LIB_ASYNC_CONTEXT)); + if (Context == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Cdb = AllocateZeroPool (EFI_SCSI_OP_LENGTH_SIXTEEN); + if (Cdb == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ErrorExit; + } + + Context->SenseDataLength = SenseDataLength; + Context->HostAdapterStatus = HostAdapterStatus; + Context->TargetStatus = TargetStatus; + Context->CallerEvent = Event; + + CommandPacket = &Context->CommandPacket; + CommandPacket->Timeout = Timeout; + CommandPacket->InDataBuffer = DataBuffer; + CommandPacket->SenseData = SenseData; + CommandPacket->InTransferLength = *DataLength; + CommandPacket->Cdb = Cdb; + // + // Fill Cdb for Read (16) Command + // + Cdb[0] = EFI_SCSI_OP_READ16; + WriteUnaligned64 ((UINT64 *)&Cdb[2], SwapBytes64 (StartLba)); + WriteUnaligned32 ((UINT32 *)&Cdb[10], SwapBytes32 (SectorSize)); + + CommandPacket->CdbLength = EFI_SCSI_OP_LENGTH_SIXTEEN; + CommandPacket->DataDirection = EFI_SCSI_DATA_IN; + CommandPacket->SenseDataLength = *SenseDataLength; + + // + // Create Event + // + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + ScsiLibNotify, + Context, + &SelfEvent + ); + if (EFI_ERROR(Status)) { + goto ErrorExit; + } + + return ScsiIo->ExecuteScsiCommand (ScsiIo, CommandPacket, Event); + +ErrorExit: + if (Context != NULL) { + FreePool (Context); + } + + return Status; +} + + +/** + Execute blocking/non-blocking Write(16) SCSI command on a specific SCSI + target. + + Executes the SCSI Write(16) command on the SCSI target specified by ScsiIo. + When Event is NULL, blocking command will be executed. Otherwise non-blocking + command will be executed. + For blocking I/O, if Timeout is zero, this function will wait indefinitely + for the command to complete. If Timeout is greater than zero, then the + command is executed and will timeout after Timeout 100 ns units. + For non-blocking I/O, if Timeout is zero, Event will be signaled only after + the command to completes. If Timeout is greater than zero, Event will also be + signaled after Timeout 100 ns units. + The StartLba and SectorSize parameters are used to construct the CDB for this + SCSI command. + + If ScsiIo is NULL, then ASSERT(). + If SenseDataLength is NULL, then ASSERT(). + If HostAdapterStatus is NULL, then ASSERT(). + If TargetStatus is NULL, then ASSERT(). + If DataLength is NULL, then ASSERT(). + + If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet + buffer alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise + EFI_INVALID_PARAMETER gets returned. + + If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet + buffer alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise + EFI_INVALID_PARAMETER gets returned. + + @param[in] ScsiIo SCSI IO Protocol to use + @param[in] Timeout The length of timeout period. + @param[in, out] SenseData A pointer to output sense data. + @param[in, out] SenseDataLength The length of output sense data. + @param[out] HostAdapterStatus The status of Host Adapter. + @param[out] TargetStatus The status of the target. + @param[in, out] DataBuffer A pointer to a data buffer. + @param[in, out] DataLength The length of data buffer. + @param[in] StartLba The start address of LBA. + @param[in] SectorSize The number of contiguous logical blocks + of data that shall be transferred. + @param[in] Event If the SCSI target does not support + non-blocking I/O, then Event is ignored, + and blocking I/O is performed. If Event + is NULL, then blocking I/O is performed. + If Event is not NULL and non-blocking + I/O is supported, then non-blocking I/O + is performed, and Event will be signaled + when the SCSI Write(16) command + completes. + + @retval EFI_SUCCESS Command is executed successfully. + @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, + but the entire DataBuffer could not be + transferred. The actual number of bytes + transferred is returned in DataLength. + @retval EFI_NOT_READY The SCSI Request Packet could not be + sent because there are too many SCSI + Command Packets already queued. + @retval EFI_DEVICE_ERROR A device error occurred while attempting + to send SCSI Request Packet. + @retval EFI_UNSUPPORTED The command described by the SCSI + Request Packet is not supported by the + SCSI initiator(i.e., SCSI Host + Controller) + @retval EFI_TIMEOUT A timeout occurred while waiting for the + SCSI Request Packet to execute. + @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet + are invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due + to a lack of resources. + +**/ +EFI_STATUS +EFIAPI +ScsiWrite16CommandEx ( + IN EFI_SCSI_IO_PROTOCOL *ScsiIo, + IN UINT64 Timeout, + IN OUT VOID *SenseData, OPTIONAL + IN OUT UINT8 *SenseDataLength, + OUT UINT8 *HostAdapterStatus, + OUT UINT8 *TargetStatus, + IN OUT VOID *DataBuffer, OPTIONAL + IN OUT UINT32 *DataLength, + IN UINT64 StartLba, + IN UINT32 SectorSize, + IN EFI_EVENT Event OPTIONAL + ) +{ + EFI_SCSI_LIB_ASYNC_CONTEXT *Context; + EFI_SCSI_IO_SCSI_REQUEST_PACKET *CommandPacket; + EFI_STATUS Status; + UINT8 *Cdb; + EFI_EVENT SelfEvent; + + if (Event == NULL) { + return ScsiWrite16Command ( + ScsiIo, + Timeout, + SenseData, + SenseDataLength, + HostAdapterStatus, + TargetStatus, + DataBuffer, + DataLength, + StartLba, + SectorSize + ); + } + + ASSERT (SenseDataLength != NULL); + ASSERT (HostAdapterStatus != NULL); + ASSERT (TargetStatus != NULL); + ASSERT (DataLength != NULL); + ASSERT (ScsiIo != NULL); + + Context = AllocateZeroPool (sizeof (EFI_SCSI_LIB_ASYNC_CONTEXT)); + if (Context == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Cdb = AllocateZeroPool (EFI_SCSI_OP_LENGTH_SIXTEEN); + if (Cdb == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ErrorExit; + } + + Context->SenseDataLength = SenseDataLength; + Context->HostAdapterStatus = HostAdapterStatus; + Context->TargetStatus = TargetStatus; + Context->CallerEvent = Event; + + CommandPacket = &Context->CommandPacket; + CommandPacket->Timeout = Timeout; + CommandPacket->OutDataBuffer = DataBuffer; + CommandPacket->SenseData = SenseData; + CommandPacket->OutTransferLength = *DataLength; + CommandPacket->Cdb = Cdb; + // + // Fill Cdb for Write (16) Command + // + Cdb[0] = EFI_SCSI_OP_WRITE16; + WriteUnaligned64 ((UINT64 *)&Cdb[2], SwapBytes64 (StartLba)); + WriteUnaligned32 ((UINT32 *)&Cdb[10], SwapBytes32 (SectorSize)); + + CommandPacket->CdbLength = EFI_SCSI_OP_LENGTH_SIXTEEN; + CommandPacket->DataDirection = EFI_SCSI_DATA_OUT; + CommandPacket->SenseDataLength = *SenseDataLength; + + // + // Create Event + // + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + ScsiLibNotify, + Context, + &SelfEvent + ); + if (EFI_ERROR(Status)) { + goto ErrorExit; + } + + return ScsiIo->ExecuteScsiCommand (ScsiIo, CommandPacket, Event); + +ErrorExit: + if (Context != NULL) { + FreePool (Context); + } + + return Status; +} diff --git a/MdePkg/Library/UefiScsiLib/UefiScsiLib.inf b/MdePkg/Library/UefiScsiLib/UefiScsiLib.inf index 1eb90765af42..cd0c5c1ec803 100644 --- a/MdePkg/Library/UefiScsiLib/UefiScsiLib.inf +++ b/MdePkg/Library/UefiScsiLib/UefiScsiLib.inf @@ -4,7 +4,7 @@ # This libarary provides the functions to submit Scsi commands defined # in SCSI-2 specification for scsi device. # -# Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.
+# Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
# # This program and the accompanying materials # are licensed and made available under the terms and conditions of the BSD License @@ -42,4 +42,6 @@ BaseMemoryLib DebugLib BaseLib + MemoryAllocationLib + UefiBootServicesTableLib From 6a14da57ac9737d268ee6abe156008b862146ef9 Mon Sep 17 00:00:00 2001 From: Hao Wu Date: Fri, 11 Dec 2015 07:34:34 +0000 Subject: [PATCH 236/525] MdeModulePkg ScsiDiskDxe: Add BlockIO2 Support Together with EFI_BLOCK_IO_PROTOCOL, EFI_BLOCK_IO2_PROTOCOL is installed as well in ScsiDiskDxe. Block I/O 2 functions are implemented: Reset ReadBlocksEx WriteBlocksEx FlushBlocksEx (Sync patch r19215 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Hao Wu Reviewed-by: Feng Tian git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19222 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Bus/Scsi/ScsiDiskDxe/ComponentName.c | 4 +- MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c | 1436 ++++++++++++++++- MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.h | 335 +++- .../Bus/Scsi/ScsiDiskDxe/ScsiDiskDxe.inf | 6 +- 4 files changed, 1767 insertions(+), 14 deletions(-) diff --git a/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ComponentName.c b/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ComponentName.c index 17908258029c..08b71d08f36b 100644 --- a/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ComponentName.c +++ b/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ComponentName.c @@ -1,7 +1,7 @@ /** @file UEFI Component Name(2) protocol implementation for SCSI disk driver. -Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.
+Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -211,7 +211,7 @@ ScsiDiskComponentNameGetControllerName ( return Status; } - ScsiDiskDevice = SCSI_DISK_DEV_FROM_THIS (BlockIo); + ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO (BlockIo); return LookupUnicodeString2 ( Language, diff --git a/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c b/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c index e7abe544df58..d83fa24a4fe0 100644 --- a/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c +++ b/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c @@ -239,7 +239,13 @@ ScsiDiskDriverBindingStart ( ScsiDiskDevice->BlkIo.ReadBlocks = ScsiDiskReadBlocks; ScsiDiskDevice->BlkIo.WriteBlocks = ScsiDiskWriteBlocks; ScsiDiskDevice->BlkIo.FlushBlocks = ScsiDiskFlushBlocks; + ScsiDiskDevice->BlkIo2.Media = &ScsiDiskDevice->BlkIoMedia; + ScsiDiskDevice->BlkIo2.Reset = ScsiDiskResetEx; + ScsiDiskDevice->BlkIo2.ReadBlocksEx = ScsiDiskReadBlocksEx; + ScsiDiskDevice->BlkIo2.WriteBlocksEx = ScsiDiskWriteBlocksEx; + ScsiDiskDevice->BlkIo2.FlushBlocksEx = ScsiDiskFlushBlocksEx; ScsiDiskDevice->Handle = Controller; + InitializeListHead (&ScsiDiskDevice->BlkIo2Queue); ScsiIo->GetDeviceType (ScsiIo, &(ScsiDiskDevice->DeviceType)); switch (ScsiDiskDevice->DeviceType) { @@ -300,7 +306,8 @@ ScsiDiskDriverBindingStart ( Status = ScsiDiskDetectMedia (ScsiDiskDevice, MustReadCapacity, &Temp); if (!EFI_ERROR (Status)) { // - // Determine if Block IO should be produced on this controller handle + // Determine if Block IO & Block IO2 should be produced on this controller + // handle // if (DetermineInstallBlockIo(Controller)) { InitializeInstallDiskInfo(ScsiDiskDevice, Controller); @@ -308,6 +315,8 @@ ScsiDiskDriverBindingStart ( &Controller, &gEfiBlockIoProtocolGuid, &ScsiDiskDevice->BlkIo, + &gEfiBlockIo2ProtocolGuid, + &ScsiDiskDevice->BlkIo2, &gEfiDiskInfoProtocolGuid, &ScsiDiskDevice->DiskInfo, NULL @@ -390,11 +399,19 @@ ScsiDiskDriverBindingStop ( return Status; } - ScsiDiskDevice = SCSI_DISK_DEV_FROM_THIS (BlkIo); + ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO (BlkIo); + + // + // Wait for the BlockIo2 requests queue to become empty + // + while (!IsListEmpty (&ScsiDiskDevice->BlkIo2Queue)); + Status = gBS->UninstallMultipleProtocolInterfaces ( Controller, &gEfiBlockIoProtocolGuid, &ScsiDiskDevice->BlkIo, + &gEfiBlockIo2ProtocolGuid, + &ScsiDiskDevice->BlkIo2, &gEfiDiskInfoProtocolGuid, &ScsiDiskDevice->DiskInfo, NULL @@ -443,7 +460,7 @@ ScsiDiskReset ( OldTpl = gBS->RaiseTPL (TPL_CALLBACK); - ScsiDiskDevice = SCSI_DISK_DEV_FROM_THIS (This); + ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO (This); Status = ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo); @@ -505,7 +522,7 @@ ScsiDiskReadBlocks ( MediaChange = FALSE; OldTpl = gBS->RaiseTPL (TPL_CALLBACK); - ScsiDiskDevice = SCSI_DISK_DEV_FROM_THIS (This); + ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO (This); if (!IS_DEVICE_FIXED(ScsiDiskDevice)) { @@ -522,6 +539,12 @@ ScsiDiskReadBlocks ( &ScsiDiskDevice->BlkIo, &ScsiDiskDevice->BlkIo ); + gBS->ReinstallProtocolInterface ( + ScsiDiskDevice->Handle, + &gEfiBlockIo2ProtocolGuid, + &ScsiDiskDevice->BlkIo2, + &ScsiDiskDevice->BlkIo2 + ); Status = EFI_MEDIA_CHANGED; goto Done; } @@ -623,7 +646,7 @@ ScsiDiskWriteBlocks ( MediaChange = FALSE; OldTpl = gBS->RaiseTPL (TPL_CALLBACK); - ScsiDiskDevice = SCSI_DISK_DEV_FROM_THIS (This); + ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO (This); if (!IS_DEVICE_FIXED(ScsiDiskDevice)) { @@ -640,6 +663,12 @@ ScsiDiskWriteBlocks ( &ScsiDiskDevice->BlkIo, &ScsiDiskDevice->BlkIo ); + gBS->ReinstallProtocolInterface ( + ScsiDiskDevice->Handle, + &gEfiBlockIo2ProtocolGuid, + &ScsiDiskDevice->BlkIo2, + &ScsiDiskDevice->BlkIo2 + ); Status = EFI_MEDIA_CHANGED; goto Done; } @@ -725,6 +754,392 @@ ScsiDiskFlushBlocks ( } +/** + Reset SCSI Disk. + + @param This The pointer of EFI_BLOCK_IO2_PROTOCOL. + @param ExtendedVerification The flag about if extend verificate. + + @retval EFI_SUCCESS The device was reset. + @retval EFI_DEVICE_ERROR The device is not functioning properly and could + not be reset. + @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice(). + +**/ +EFI_STATUS +EFIAPI +ScsiDiskResetEx ( + IN EFI_BLOCK_IO2_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +{ + EFI_TPL OldTpl; + SCSI_DISK_DEV *ScsiDiskDevice; + EFI_STATUS Status; + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + + ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO2 (This); + + Status = ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo); + + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + goto Done; + } + + if (!ExtendedVerification) { + goto Done; + } + + Status = ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo); + + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + goto Done; + } + +Done: + gBS->RestoreTPL (OldTpl); + return Status; +} + +/** + The function is to Read Block from SCSI Disk. + + @param This The pointer of EFI_BLOCK_IO_PROTOCOL. + @param MediaId The Id of Media detected. + @param Lba The logic block address. + @param Token A pointer to the token associated with the transaction. + @param BufferSize The size of Buffer. + @param Buffer The buffer to fill the read out data. + + @retval EFI_SUCCESS The read request was queued if Token-> Event is + not NULL. The data was read correctly from the + device if theToken-> Event is NULL. + @retval EFI_DEVICE_ERROR The device reported an error while attempting + to perform the read operation. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_MEDIA_CHANGED The MediaId is not for the current media. + @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of + the intrinsic block size of the device. + @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not + valid, or the buffer is not on proper + alignment. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a + lack of resources. + +**/ +EFI_STATUS +EFIAPI +ScsiDiskReadBlocksEx ( + IN EFI_BLOCK_IO2_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN OUT EFI_BLOCK_IO2_TOKEN *Token, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +{ + SCSI_DISK_DEV *ScsiDiskDevice; + EFI_BLOCK_IO_MEDIA *Media; + EFI_STATUS Status; + UINTN BlockSize; + UINTN NumberOfBlocks; + BOOLEAN MediaChange; + EFI_TPL OldTpl; + + MediaChange = FALSE; + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO2 (This); + + if (!IS_DEVICE_FIXED(ScsiDiskDevice)) { + + Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange); + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + goto Done; + } + + if (MediaChange) { + gBS->ReinstallProtocolInterface ( + ScsiDiskDevice->Handle, + &gEfiBlockIoProtocolGuid, + &ScsiDiskDevice->BlkIo, + &ScsiDiskDevice->BlkIo + ); + gBS->ReinstallProtocolInterface ( + ScsiDiskDevice->Handle, + &gEfiBlockIo2ProtocolGuid, + &ScsiDiskDevice->BlkIo2, + &ScsiDiskDevice->BlkIo2 + ); + Status = EFI_MEDIA_CHANGED; + goto Done; + } + } + // + // Get the intrinsic block size + // + Media = ScsiDiskDevice->BlkIo2.Media; + BlockSize = Media->BlockSize; + + NumberOfBlocks = BufferSize / BlockSize; + + if (!(Media->MediaPresent)) { + Status = EFI_NO_MEDIA; + goto Done; + } + + if (MediaId != Media->MediaId) { + Status = EFI_MEDIA_CHANGED; + goto Done; + } + + if (Buffer == NULL) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + if (BufferSize == 0) { + if ((Token != NULL) && (Token->Event != NULL)) { + Token->TransactionStatus = EFI_SUCCESS; + gBS->SignalEvent (Token->Event); + } + + Status = EFI_SUCCESS; + goto Done; + } + + if (BufferSize % BlockSize != 0) { + Status = EFI_BAD_BUFFER_SIZE; + goto Done; + } + + if (Lba > Media->LastBlock) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + // + // If all the parameters are valid, then perform read sectors command + // to transfer data from device to host. + // + if ((Token != NULL) && (Token->Event != NULL)) { + Token->TransactionStatus = EFI_SUCCESS; + Status = ScsiDiskAsyncReadSectors ( + ScsiDiskDevice, + Buffer, + Lba, + NumberOfBlocks, + Token + ); + } else { + Status = ScsiDiskReadSectors ( + ScsiDiskDevice, + Buffer, + Lba, + NumberOfBlocks + ); + } + +Done: + gBS->RestoreTPL (OldTpl); + return Status; +} + +/** + The function is to Write Block to SCSI Disk. + + @param This The pointer of EFI_BLOCK_IO_PROTOCOL. + @param MediaId The Id of Media detected. + @param Lba The logic block address. + @param Token A pointer to the token associated with the transaction. + @param BufferSize The size of Buffer. + @param Buffer The buffer to fill the read out data. + + @retval EFI_SUCCESS The data were written correctly to the device. + @retval EFI_WRITE_PROTECTED The device cannot be written to. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_MEDIA_CHANGED The MediaId is not for the current media. + @retval EFI_DEVICE_ERROR The device reported an error while attempting + to perform the write operation. + @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of + the intrinsic block size of the device. + @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not + valid, or the buffer is not on proper + alignment. + +**/ +EFI_STATUS +EFIAPI +ScsiDiskWriteBlocksEx ( + IN EFI_BLOCK_IO2_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN OUT EFI_BLOCK_IO2_TOKEN *Token, + IN UINTN BufferSize, + IN VOID *Buffer + ) +{ + SCSI_DISK_DEV *ScsiDiskDevice; + EFI_BLOCK_IO_MEDIA *Media; + EFI_STATUS Status; + UINTN BlockSize; + UINTN NumberOfBlocks; + BOOLEAN MediaChange; + EFI_TPL OldTpl; + + MediaChange = FALSE; + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO2 (This); + + if (!IS_DEVICE_FIXED(ScsiDiskDevice)) { + + Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange); + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + goto Done; + } + + if (MediaChange) { + gBS->ReinstallProtocolInterface ( + ScsiDiskDevice->Handle, + &gEfiBlockIoProtocolGuid, + &ScsiDiskDevice->BlkIo, + &ScsiDiskDevice->BlkIo + ); + gBS->ReinstallProtocolInterface ( + ScsiDiskDevice->Handle, + &gEfiBlockIo2ProtocolGuid, + &ScsiDiskDevice->BlkIo2, + &ScsiDiskDevice->BlkIo2 + ); + Status = EFI_MEDIA_CHANGED; + goto Done; + } + } + // + // Get the intrinsic block size + // + Media = ScsiDiskDevice->BlkIo2.Media; + BlockSize = Media->BlockSize; + + NumberOfBlocks = BufferSize / BlockSize; + + if (!(Media->MediaPresent)) { + Status = EFI_NO_MEDIA; + goto Done; + } + + if (MediaId != Media->MediaId) { + Status = EFI_MEDIA_CHANGED; + goto Done; + } + + if (BufferSize == 0) { + if ((Token != NULL) && (Token->Event != NULL)) { + Token->TransactionStatus = EFI_SUCCESS; + gBS->SignalEvent (Token->Event); + } + + Status = EFI_SUCCESS; + goto Done; + } + + if (Buffer == NULL) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + if (BufferSize % BlockSize != 0) { + Status = EFI_BAD_BUFFER_SIZE; + goto Done; + } + + if (Lba > Media->LastBlock) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + // + // if all the parameters are valid, then perform write sectors command + // to transfer data from device to host. + // + if ((Token != NULL) && (Token->Event != NULL)) { + Token->TransactionStatus = EFI_SUCCESS; + Status = ScsiDiskAsyncWriteSectors ( + ScsiDiskDevice, + Buffer, + Lba, + NumberOfBlocks, + Token + ); + } else { + Status = ScsiDiskWriteSectors ( + ScsiDiskDevice, + Buffer, + Lba, + NumberOfBlocks + ); + } + +Done: + gBS->RestoreTPL (OldTpl); + return Status; +} + +/** + Flush the Block Device. + + @param This Indicates a pointer to the calling context. + @param Token A pointer to the token associated with the transaction. + + @retval EFI_SUCCESS All outstanding data was written to the device. + @retval EFI_DEVICE_ERROR The device reported an error while writing back the + data. + @retval EFI_NO_MEDIA There is no media in the device. + +**/ +EFI_STATUS +EFIAPI +ScsiDiskFlushBlocksEx ( + IN EFI_BLOCK_IO2_PROTOCOL *This, + IN OUT EFI_BLOCK_IO2_TOKEN *Token + ) +{ + // + // Signal event and return directly. + // + if ((Token != NULL) && (Token->Event != NULL)) { + Token->TransactionStatus = EFI_SUCCESS; + gBS->SignalEvent (Token->Event); + } + + return EFI_SUCCESS; +} + + /** Detect Device and read out capacity ,if error occurs, parse the sense key. @@ -2050,6 +2465,328 @@ ScsiDiskWriteSectors ( return EFI_SUCCESS; } +/** + Asynchronously read sector from SCSI Disk. + + @param ScsiDiskDevice The pointer of SCSI_DISK_DEV. + @param Buffer The buffer to fill in the read out data. + @param Lba Logic block address. + @param NumberOfBlocks The number of blocks to read. + @param Token A pointer to the token associated with the + non-blocking read request. + + @retval EFI_INVALID_PARAMETER Token is NULL or Token->Event is NULL. + @retval EFI_DEVICE_ERROR Indicates a device error. + @retval EFI_SUCCESS Operation is successful. + +**/ +EFI_STATUS +ScsiDiskAsyncReadSectors ( + IN SCSI_DISK_DEV *ScsiDiskDevice, + OUT VOID *Buffer, + IN EFI_LBA Lba, + IN UINTN NumberOfBlocks, + IN EFI_BLOCK_IO2_TOKEN *Token + ) +{ + UINTN BlocksRemaining; + UINT8 *PtrBuffer; + UINT32 BlockSize; + UINT32 ByteCount; + UINT32 MaxBlock; + UINT32 SectorCount; + UINT64 Timeout; + SCSI_BLKIO2_REQUEST *BlkIo2Req; + EFI_STATUS Status; + + if ((Token == NULL) || (Token->Event == NULL)) { + return EFI_INVALID_PARAMETER; + } + + BlkIo2Req = AllocateZeroPool (sizeof (SCSI_BLKIO2_REQUEST)); + if (BlkIo2Req == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + BlkIo2Req->Token = Token; + InsertTailList (&ScsiDiskDevice->BlkIo2Queue, &BlkIo2Req->Link); + InitializeListHead (&BlkIo2Req->ScsiRWQueue); + + Status = EFI_SUCCESS; + + BlocksRemaining = NumberOfBlocks; + BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize; + + // + // Limit the data bytes that can be transferred by one Read(10) or Read(16) + // Command + // + if (!ScsiDiskDevice->Cdb16Byte) { + MaxBlock = 0xFFFF; + } else { + MaxBlock = 0xFFFFFFFF; + } + + PtrBuffer = Buffer; + + while (BlocksRemaining > 0) { + + if (BlocksRemaining <= MaxBlock) { + if (!ScsiDiskDevice->Cdb16Byte) { + SectorCount = (UINT16) BlocksRemaining; + } else { + SectorCount = (UINT32) BlocksRemaining; + } + } else { + SectorCount = MaxBlock; + } + + ByteCount = SectorCount * BlockSize; + // + // |------------------------|-----------------|------------------|-----------------| + // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate | + // |------------------------|-----------------|------------------|-----------------| + // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec | + // |------------------------|-----------------|------------------|-----------------| + // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec | + // |------------------------|-----------------|------------------|-----------------| + // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec | + // |------------------------|-----------------|------------------|-----------------| + // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec | + // |------------------------|-----------------|------------------|-----------------| + // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec | + // |------------------------|-----------------|------------------|-----------------| + // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec | + // |------------------------|-----------------|------------------|-----------------| + // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec | + // |------------------------|-----------------|------------------|-----------------| + // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec | + // |------------------------|-----------------|------------------|-----------------| + // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec | + // |------------------------|-----------------|------------------|-----------------| + // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec | + // |------------------------|-----------------|------------------|-----------------| + // + // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, + // we have to use the lowest transfer rate to calculate the possible + // maximum timeout value for each operation. + // From the above table, we could know 2.1Mbytes per second is lowest one. + // The timout value is rounded up to nearest integar and here an additional + // 30s is added to follow ATA spec in which it mentioned that the device + // may take up to 30s to respond commands in the Standby/Idle mode. + // + Timeout = EFI_TIMER_PERIOD_SECONDS (ByteCount / 2100000 + 31); + + if (!ScsiDiskDevice->Cdb16Byte) { + Status = ScsiDiskAsyncRead10 ( + ScsiDiskDevice, + Timeout, + PtrBuffer, + ByteCount, + (UINT32) Lba, + SectorCount, + BlkIo2Req, + Token + ); + } else { + Status = ScsiDiskAsyncRead16 ( + ScsiDiskDevice, + Timeout, + PtrBuffer, + ByteCount, + Lba, + SectorCount, + BlkIo2Req, + Token + ); + } + if (EFI_ERROR (Status)) { + // + // Free the SCSI_BLKIO2_REQUEST structure only when the first SCSI + // command fails. Otherwise, it will be freed in the callback function + // ScsiDiskNotify(). + // + if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) { + RemoveEntryList (&BlkIo2Req->Link); + FreePool (BlkIo2Req); + } + return EFI_DEVICE_ERROR; + } + + // + // Sectors submitted for transfer + // + SectorCount = ByteCount / BlockSize; + + Lba += SectorCount; + PtrBuffer = PtrBuffer + SectorCount * BlockSize; + BlocksRemaining -= SectorCount; + } + + return EFI_SUCCESS; +} + +/** + Asynchronously write sector to SCSI Disk. + + @param ScsiDiskDevice The pointer of SCSI_DISK_DEV. + @param Buffer The buffer of data to be written into SCSI Disk. + @param Lba Logic block address. + @param NumberOfBlocks The number of blocks to read. + @param Token A pointer to the token associated with the + non-blocking read request. + + @retval EFI_INVALID_PARAMETER Token is NULL or Token->Event is NULL + @retval EFI_DEVICE_ERROR Indicates a device error. + @retval EFI_SUCCESS Operation is successful. + +**/ +EFI_STATUS +ScsiDiskAsyncWriteSectors ( + IN SCSI_DISK_DEV *ScsiDiskDevice, + IN VOID *Buffer, + IN EFI_LBA Lba, + IN UINTN NumberOfBlocks, + IN EFI_BLOCK_IO2_TOKEN *Token + ) +{ + UINTN BlocksRemaining; + UINT8 *PtrBuffer; + UINT32 BlockSize; + UINT32 ByteCount; + UINT32 MaxBlock; + UINT32 SectorCount; + UINT64 Timeout; + SCSI_BLKIO2_REQUEST *BlkIo2Req; + EFI_STATUS Status; + + if ((Token == NULL) || (Token->Event == NULL)) { + return EFI_INVALID_PARAMETER; + } + + BlkIo2Req = AllocateZeroPool (sizeof (SCSI_BLKIO2_REQUEST)); + if (BlkIo2Req == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + BlkIo2Req->Token = Token; + InsertTailList (&ScsiDiskDevice->BlkIo2Queue, &BlkIo2Req->Link); + InitializeListHead (&BlkIo2Req->ScsiRWQueue); + + Status = EFI_SUCCESS; + + BlocksRemaining = NumberOfBlocks; + BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize; + + // + // Limit the data bytes that can be transferred by one Read(10) or Read(16) + // Command + // + if (!ScsiDiskDevice->Cdb16Byte) { + MaxBlock = 0xFFFF; + } else { + MaxBlock = 0xFFFFFFFF; + } + + PtrBuffer = Buffer; + + while (BlocksRemaining > 0) { + + if (BlocksRemaining <= MaxBlock) { + if (!ScsiDiskDevice->Cdb16Byte) { + SectorCount = (UINT16) BlocksRemaining; + } else { + SectorCount = (UINT32) BlocksRemaining; + } + } else { + SectorCount = MaxBlock; + } + + ByteCount = SectorCount * BlockSize; + // + // |------------------------|-----------------|------------------|-----------------| + // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate | + // |------------------------|-----------------|------------------|-----------------| + // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec | + // |------------------------|-----------------|------------------|-----------------| + // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec | + // |------------------------|-----------------|------------------|-----------------| + // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec | + // |------------------------|-----------------|------------------|-----------------| + // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec | + // |------------------------|-----------------|------------------|-----------------| + // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec | + // |------------------------|-----------------|------------------|-----------------| + // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec | + // |------------------------|-----------------|------------------|-----------------| + // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec | + // |------------------------|-----------------|------------------|-----------------| + // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec | + // |------------------------|-----------------|------------------|-----------------| + // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec | + // |------------------------|-----------------|------------------|-----------------| + // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec | + // |------------------------|-----------------|------------------|-----------------| + // + // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, + // we have to use the lowest transfer rate to calculate the possible + // maximum timeout value for each operation. + // From the above table, we could know 2.1Mbytes per second is lowest one. + // The timout value is rounded up to nearest integar and here an additional + // 30s is added to follow ATA spec in which it mentioned that the device + // may take up to 30s to respond commands in the Standby/Idle mode. + // + Timeout = EFI_TIMER_PERIOD_SECONDS (ByteCount / 2100000 + 31); + + if (!ScsiDiskDevice->Cdb16Byte) { + Status = ScsiDiskAsyncWrite10 ( + ScsiDiskDevice, + Timeout, + PtrBuffer, + ByteCount, + (UINT32) Lba, + SectorCount, + BlkIo2Req, + Token + ); + } else { + Status = ScsiDiskAsyncWrite16 ( + ScsiDiskDevice, + Timeout, + PtrBuffer, + ByteCount, + Lba, + SectorCount, + BlkIo2Req, + Token + ); + } + if (EFI_ERROR (Status)) { + // + // Free the SCSI_BLKIO2_REQUEST structure only when the first SCSI + // command fails. Otherwise, it will be freed in the callback function + // ScsiDiskNotify(). + // + if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) { + RemoveEntryList (&BlkIo2Req->Link); + FreePool (BlkIo2Req); + } + return EFI_DEVICE_ERROR; + } + + // + // Sectors submitted for transfer + // + SectorCount = ByteCount / BlockSize; + + Lba += SectorCount; + PtrBuffer = PtrBuffer + SectorCount * BlockSize; + BlocksRemaining -= SectorCount; + } + + return EFI_SUCCESS; +} + /** Submit Read(10) command. @@ -2546,6 +3283,689 @@ ScsiDiskWrite16 ( } +/** + Internal helper notify function in which determine whether retry of a SCSI + Read/Write command is needed and signal the event passed from Block I/O(2) if + the SCSI I/O operation completes. + + @param Event The instance of EFI_EVENT. + @param Context The parameter passed in. + +**/ +VOID +EFIAPI +ScsiDiskNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + SCSI_ASYNC_RW_REQUEST *Request; + SCSI_DISK_DEV *ScsiDiskDevice; + EFI_BLOCK_IO2_TOKEN *Token; + UINTN Action; + UINT32 OldDataLength; + UINT32 OldSectorCount; + UINT8 MaxRetry; + + gBS->CloseEvent (Event); + + Request = (SCSI_ASYNC_RW_REQUEST *) Context; + ScsiDiskDevice = Request->ScsiDiskDevice; + Token = Request->BlkIo2Req->Token; + OldDataLength = Request->DataLength; + OldSectorCount = Request->SectorCount; + MaxRetry = 2; + + // + // If previous sub-tasks already fails, no need to process this sub-task. + // + if (Token->TransactionStatus != EFI_SUCCESS) { + goto Exit; + } + + // + // Check HostAdapterStatus and TargetStatus + // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL) + // + Status = CheckHostAdapterStatus (Request->HostAdapterStatus); + if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) { + if (++Request->TimesRetry > MaxRetry) { + Token->TransactionStatus = EFI_DEVICE_ERROR; + goto Exit; + } else { + goto Retry; + } + } else if (Status == EFI_DEVICE_ERROR) { + // + // reset the scsi channel + // + ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo); + Token->TransactionStatus = EFI_DEVICE_ERROR; + goto Exit; + } + + Status = CheckTargetStatus (Request->TargetStatus); + if (Status == EFI_NOT_READY) { + // + // reset the scsi device + // + ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo); + if (++Request->TimesRetry > MaxRetry) { + Token->TransactionStatus = EFI_DEVICE_ERROR; + goto Exit; + } else { + goto Retry; + } + } else if (Status == EFI_DEVICE_ERROR) { + Token->TransactionStatus = EFI_DEVICE_ERROR; + goto Exit; + } + + if (Request->TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) { + DEBUG ((EFI_D_ERROR, "ScsiDiskNotify: Check Condition happened!\n")); + + Status = DetectMediaParsingSenseKeys ( + ScsiDiskDevice, + Request->SenseData, + Request->SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), + &Action + ); + if (Action == ACTION_RETRY_COMMAND_LATER) { + if (++Request->TimesRetry > MaxRetry) { + Token->TransactionStatus = EFI_DEVICE_ERROR; + goto Exit; + } else { + goto Retry; + } + } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) { + if (Request->SectorCount <= 1) { + // + // Jump out if the operation still fails with one sector transfer + // length. + // + Token->TransactionStatus = EFI_DEVICE_ERROR; + goto Exit; + } + // + // Try again with two half length request if the sense data shows we need + // to retry. + // + Request->SectorCount >>= 1; + Request->DataLength = Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize; + Request->TimesRetry = 0; + + goto Retry; + } else { + Token->TransactionStatus = EFI_DEVICE_ERROR; + goto Exit; + } + } + + // + // This sub-task succeeds, no need to retry. + // + goto Exit; + +Retry: + if (Request->InBuffer != NULL) { + // + // SCSI read command + // + if (!ScsiDiskDevice->Cdb16Byte) { + Status = ScsiDiskAsyncRead10 ( + ScsiDiskDevice, + Request->Timeout, + Request->InBuffer, + Request->DataLength, + (UINT32) Request->StartLba, + Request->SectorCount, + Request->BlkIo2Req, + Token + ); + } else { + Status = ScsiDiskAsyncRead16 ( + ScsiDiskDevice, + Request->Timeout, + Request->InBuffer, + Request->DataLength, + Request->StartLba, + Request->SectorCount, + Request->BlkIo2Req, + Token + ); + } + + if (EFI_ERROR (Status)) { + Token->TransactionStatus = EFI_DEVICE_ERROR; + goto Exit; + } else if (OldSectorCount != Request->SectorCount) { + // + // Original sub-task will be split into two new sub-tasks with smaller + // DataLength + // + if (!ScsiDiskDevice->Cdb16Byte) { + Status = ScsiDiskAsyncRead10 ( + ScsiDiskDevice, + Request->Timeout, + Request->InBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize, + OldDataLength - Request->DataLength, + (UINT32) Request->StartLba + Request->SectorCount, + OldSectorCount - Request->SectorCount, + Request->BlkIo2Req, + Token + ); + } else { + Status = ScsiDiskAsyncRead16 ( + ScsiDiskDevice, + Request->Timeout, + Request->InBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize, + OldDataLength - Request->DataLength, + Request->StartLba + Request->SectorCount, + OldSectorCount - Request->SectorCount, + Request->BlkIo2Req, + Token + ); + } + if (EFI_ERROR (Status)) { + Token->TransactionStatus = EFI_DEVICE_ERROR; + goto Exit; + } + } + } else { + // + // SCSI write command + // + if (!ScsiDiskDevice->Cdb16Byte) { + Status = ScsiDiskAsyncWrite10 ( + ScsiDiskDevice, + Request->Timeout, + Request->OutBuffer, + Request->DataLength, + (UINT32) Request->StartLba, + Request->SectorCount, + Request->BlkIo2Req, + Token + ); + } else { + Status = ScsiDiskAsyncWrite16 ( + ScsiDiskDevice, + Request->Timeout, + Request->OutBuffer, + Request->DataLength, + Request->StartLba, + Request->SectorCount, + Request->BlkIo2Req, + Token + ); + } + + if (EFI_ERROR (Status)) { + Token->TransactionStatus = EFI_DEVICE_ERROR; + goto Exit; + } else if (OldSectorCount != Request->SectorCount) { + // + // Original sub-task will be split into two new sub-tasks with smaller + // DataLength + // + if (!ScsiDiskDevice->Cdb16Byte) { + Status = ScsiDiskAsyncWrite10 ( + ScsiDiskDevice, + Request->Timeout, + Request->OutBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize, + OldDataLength - Request->DataLength, + (UINT32) Request->StartLba + Request->SectorCount, + OldSectorCount - Request->SectorCount, + Request->BlkIo2Req, + Token + ); + } else { + Status = ScsiDiskAsyncWrite16 ( + ScsiDiskDevice, + Request->Timeout, + Request->OutBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize, + OldDataLength - Request->DataLength, + Request->StartLba + Request->SectorCount, + OldSectorCount - Request->SectorCount, + Request->BlkIo2Req, + Token + ); + } + if (EFI_ERROR (Status)) { + Token->TransactionStatus = EFI_DEVICE_ERROR; + goto Exit; + } + } + } + +Exit: + RemoveEntryList (&Request->Link); + if (IsListEmpty (&Request->BlkIo2Req->ScsiRWQueue)) { + // + // The last SCSI R/W command of a BlockIo2 request completes + // + RemoveEntryList (&Request->BlkIo2Req->Link); + FreePool (Request->BlkIo2Req); // Should be freed only once + gBS->SignalEvent (Token->Event); + } + + FreePool (Request->SenseData); + FreePool (Request); +} + + +/** + Submit Async Read(10) command. + + @param ScsiDiskDevice The pointer of ScsiDiskDevice. + @param Timeout The time to complete the command. + @param DataBuffer The buffer to fill with the read out data. + @param DataLength The length of buffer. + @param StartLba The start logic block address. + @param SectorCount The number of blocks to read. + @param BlkIo2Req The upstream BlockIo2 request. + @param Token The pointer to the token associated with the + non-blocking read request. + + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a + lack of resources. + @return others Status returned by calling + ScsiRead10CommandEx(). + +**/ +EFI_STATUS +ScsiDiskAsyncRead10 ( + IN SCSI_DISK_DEV *ScsiDiskDevice, + IN UINT64 Timeout, + OUT UINT8 *DataBuffer, + IN UINT32 DataLength, + IN UINT32 StartLba, + IN UINT32 SectorCount, + IN OUT SCSI_BLKIO2_REQUEST *BlkIo2Req, + IN EFI_BLOCK_IO2_TOKEN *Token + ) +{ + EFI_STATUS Status; + SCSI_ASYNC_RW_REQUEST *Request; + EFI_EVENT AsyncIoEvent; + + Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST)); + if (Request == NULL) { + return EFI_OUT_OF_RESOURCES; + } + InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link); + + Request->SenseDataLength = (UINT8) (6 * sizeof (EFI_SCSI_SENSE_DATA)); + Request->SenseData = AllocateZeroPool (Request->SenseDataLength); + if (Request->SenseData == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ErrorExit; + } + + Request->ScsiDiskDevice = ScsiDiskDevice; + Request->Timeout = Timeout; + Request->InBuffer = DataBuffer; + Request->DataLength = DataLength; + Request->StartLba = StartLba; + Request->SectorCount = SectorCount; + Request->BlkIo2Req = BlkIo2Req; + + // + // Create Event + // + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + ScsiDiskNotify, + Request, + &AsyncIoEvent + ); + if (EFI_ERROR(Status)) { + goto ErrorExit; + } + + Status = ScsiRead10CommandEx ( + ScsiDiskDevice->ScsiIo, + Request->Timeout, + Request->SenseData, + &Request->SenseDataLength, + &Request->HostAdapterStatus, + &Request->TargetStatus, + Request->InBuffer, + &Request->DataLength, + (UINT32) Request->StartLba, + Request->SectorCount, + AsyncIoEvent + ); + if (EFI_ERROR(Status)) { + goto ErrorExit; + } + + return EFI_SUCCESS; + +ErrorExit: + if (Request != NULL) { + if (Request->SenseData != NULL) { + FreePool (Request->SenseData); + } + + RemoveEntryList (&Request->Link); + FreePool (Request); + } + + return Status; +} + + +/** + Submit Async Write(10) command. + + @param ScsiDiskDevice The pointer of ScsiDiskDevice. + @param Timeout The time to complete the command. + @param DataBuffer The buffer contains the data to write. + @param DataLength The length of buffer. + @param StartLba The start logic block address. + @param SectorCount The number of blocks to write. + @param BlkIo2Req The upstream BlockIo2 request. + @param Token The pointer to the token associated with the + non-blocking read request. + + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a + lack of resources. + @return others Status returned by calling + ScsiWrite10CommandEx(). + +**/ +EFI_STATUS +ScsiDiskAsyncWrite10 ( + IN SCSI_DISK_DEV *ScsiDiskDevice, + IN UINT64 Timeout, + IN UINT8 *DataBuffer, + IN UINT32 DataLength, + IN UINT32 StartLba, + IN UINT32 SectorCount, + IN OUT SCSI_BLKIO2_REQUEST *BlkIo2Req, + IN EFI_BLOCK_IO2_TOKEN *Token + ) +{ + EFI_STATUS Status; + SCSI_ASYNC_RW_REQUEST *Request; + EFI_EVENT AsyncIoEvent; + + Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST)); + if (Request == NULL) { + return EFI_OUT_OF_RESOURCES; + } + InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link); + + Request->SenseDataLength = (UINT8) (6 * sizeof (EFI_SCSI_SENSE_DATA)); + Request->SenseData = AllocateZeroPool (Request->SenseDataLength); + if (Request->SenseData == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ErrorExit; + } + + Request->ScsiDiskDevice = ScsiDiskDevice; + Request->Timeout = Timeout; + Request->OutBuffer = DataBuffer; + Request->DataLength = DataLength; + Request->StartLba = StartLba; + Request->SectorCount = SectorCount; + Request->BlkIo2Req = BlkIo2Req; + + // + // Create Event + // + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + ScsiDiskNotify, + Request, + &AsyncIoEvent + ); + if (EFI_ERROR(Status)) { + goto ErrorExit; + } + + Status = ScsiWrite10CommandEx ( + ScsiDiskDevice->ScsiIo, + Request->Timeout, + Request->SenseData, + &Request->SenseDataLength, + &Request->HostAdapterStatus, + &Request->TargetStatus, + Request->OutBuffer, + &Request->DataLength, + (UINT32) Request->StartLba, + Request->SectorCount, + AsyncIoEvent + ); + if (EFI_ERROR(Status)) { + goto ErrorExit; + } + + return EFI_SUCCESS; + +ErrorExit: + if (Request != NULL) { + if (Request->SenseData != NULL) { + FreePool (Request->SenseData); + } + + RemoveEntryList (&Request->Link); + FreePool (Request); + } + + return Status; +} + + +/** + Submit Async Read(16) command. + + @param ScsiDiskDevice The pointer of ScsiDiskDevice. + @param Timeout The time to complete the command. + @param DataBuffer The buffer to fill with the read out data. + @param DataLength The length of buffer. + @param StartLba The start logic block address. + @param SectorCount The number of blocks to read. + @param BlkIo2Req The upstream BlockIo2 request. + @param Token The pointer to the token associated with the + non-blocking read request. + + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a + lack of resources. + @return others Status returned by calling + ScsiRead16CommandEx(). + +**/ +EFI_STATUS +ScsiDiskAsyncRead16 ( + IN SCSI_DISK_DEV *ScsiDiskDevice, + IN UINT64 Timeout, + OUT UINT8 *DataBuffer, + IN UINT32 DataLength, + IN UINT64 StartLba, + IN UINT32 SectorCount, + IN OUT SCSI_BLKIO2_REQUEST *BlkIo2Req, + IN EFI_BLOCK_IO2_TOKEN *Token + ) +{ + EFI_STATUS Status; + SCSI_ASYNC_RW_REQUEST *Request; + EFI_EVENT AsyncIoEvent; + + Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST)); + if (Request == NULL) { + return EFI_OUT_OF_RESOURCES; + } + InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link); + + Request->SenseDataLength = (UINT8) (6 * sizeof (EFI_SCSI_SENSE_DATA)); + Request->SenseData = AllocateZeroPool (Request->SenseDataLength); + if (Request->SenseData == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ErrorExit; + } + + Request->ScsiDiskDevice = ScsiDiskDevice; + Request->Timeout = Timeout; + Request->InBuffer = DataBuffer; + Request->DataLength = DataLength; + Request->StartLba = StartLba; + Request->SectorCount = SectorCount; + Request->BlkIo2Req = BlkIo2Req; + + // + // Create Event + // + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + ScsiDiskNotify, + Request, + &AsyncIoEvent + ); + if (EFI_ERROR(Status)) { + goto ErrorExit; + } + + Status = ScsiRead16CommandEx ( + ScsiDiskDevice->ScsiIo, + Request->Timeout, + Request->SenseData, + &Request->SenseDataLength, + &Request->HostAdapterStatus, + &Request->TargetStatus, + Request->InBuffer, + &Request->DataLength, + Request->StartLba, + Request->SectorCount, + AsyncIoEvent + ); + if (EFI_ERROR(Status)) { + goto ErrorExit; + } + + return EFI_SUCCESS; + +ErrorExit: + if (Request != NULL) { + if (Request->SenseData != NULL) { + FreePool (Request->SenseData); + } + + RemoveEntryList (&Request->Link); + FreePool (Request); + } + + return Status; +} + + +/** + Submit Async Write(16) command. + + @param ScsiDiskDevice The pointer of ScsiDiskDevice. + @param Timeout The time to complete the command. + @param DataBuffer The buffer contains the data to write. + @param DataLength The length of buffer. + @param StartLba The start logic block address. + @param SectorCount The number of blocks to write. + @param BlkIo2Req The upstream BlockIo2 request. + @param Token The pointer to the token associated with the + non-blocking read request. + + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a + lack of resources. + @return others Status returned by calling + ScsiWrite16CommandEx(). + +**/ +EFI_STATUS +ScsiDiskAsyncWrite16 ( + IN SCSI_DISK_DEV *ScsiDiskDevice, + IN UINT64 Timeout, + IN UINT8 *DataBuffer, + IN UINT32 DataLength, + IN UINT64 StartLba, + IN UINT32 SectorCount, + IN OUT SCSI_BLKIO2_REQUEST *BlkIo2Req, + IN EFI_BLOCK_IO2_TOKEN *Token + ) +{ + EFI_STATUS Status; + SCSI_ASYNC_RW_REQUEST *Request; + EFI_EVENT AsyncIoEvent; + + Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST)); + if (Request == NULL) { + return EFI_OUT_OF_RESOURCES; + } + InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link); + + Request->SenseDataLength = (UINT8) (6 * sizeof (EFI_SCSI_SENSE_DATA)); + Request->SenseData = AllocateZeroPool (Request->SenseDataLength); + if (Request->SenseData == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ErrorExit; + } + + Request->ScsiDiskDevice = ScsiDiskDevice; + Request->Timeout = Timeout; + Request->OutBuffer = DataBuffer; + Request->DataLength = DataLength; + Request->StartLba = StartLba; + Request->SectorCount = SectorCount; + Request->BlkIo2Req = BlkIo2Req; + + // + // Create Event + // + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + ScsiDiskNotify, + Request, + &AsyncIoEvent + ); + if (EFI_ERROR(Status)) { + goto ErrorExit; + } + + Status = ScsiWrite16CommandEx ( + ScsiDiskDevice->ScsiIo, + Request->Timeout, + Request->SenseData, + &Request->SenseDataLength, + &Request->HostAdapterStatus, + &Request->TargetStatus, + Request->OutBuffer, + &Request->DataLength, + Request->StartLba, + Request->SectorCount, + AsyncIoEvent + ); + if (EFI_ERROR(Status)) { + goto ErrorExit; + } + + return EFI_SUCCESS; + +ErrorExit: + if (Request != NULL) { + if (Request->SenseData != NULL) { + FreePool (Request->SenseData); + } + + RemoveEntryList (&Request->Link); + FreePool (Request); + } + + return Status; +} + + /** Check sense key to find if media presents. @@ -2932,13 +4352,13 @@ ReleaseScsiDiskDeviceResources ( } /** - Determine if Block Io should be produced. + Determine if Block Io & Block Io2 should be produced. @param ChildHandle Child Handle to retrieve Parent information. - @retval TRUE Should produce Block Io. - @retval FALSE Should not produce Block Io. + @retval TRUE Should produce Block Io & Block Io2. + @retval FALSE Should not produce Block Io & Block Io2. **/ BOOLEAN diff --git a/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.h b/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.h index 407763665f7c..836e7caeeda1 100644 --- a/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.h +++ b/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.h @@ -1,7 +1,7 @@ /** @file Header file for SCSI Disk Driver. -Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.
+Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -22,6 +22,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include #include +#include #include #include #include @@ -50,6 +51,7 @@ typedef struct { EFI_HANDLE Handle; EFI_BLOCK_IO_PROTOCOL BlkIo; + EFI_BLOCK_IO2_PROTOCOL BlkIo2; EFI_BLOCK_IO_MEDIA BlkIoMedia; EFI_SCSI_IO_PROTOCOL *ScsiIo; UINT8 DeviceType; @@ -75,12 +77,59 @@ typedef struct { // The flag indicates if 16-byte command can be used // BOOLEAN Cdb16Byte; + + // + // The queue for BlockIo2 requests + // + LIST_ENTRY BlkIo2Queue; } SCSI_DISK_DEV; -#define SCSI_DISK_DEV_FROM_THIS(a) CR (a, SCSI_DISK_DEV, BlkIo, SCSI_DISK_DEV_SIGNATURE) +#define SCSI_DISK_DEV_FROM_BLKIO(a) CR (a, SCSI_DISK_DEV, BlkIo, SCSI_DISK_DEV_SIGNATURE) +#define SCSI_DISK_DEV_FROM_BLKIO2(a) CR (a, SCSI_DISK_DEV, BlkIo2, SCSI_DISK_DEV_SIGNATURE) #define SCSI_DISK_DEV_FROM_DISKINFO(a) CR (a, SCSI_DISK_DEV, DiskInfo, SCSI_DISK_DEV_SIGNATURE) +// +// Asynchronous I/O request +// +// +// Private data structure for a BlockIo2 request +// +typedef struct { + EFI_BLOCK_IO2_TOKEN *Token; + // + // The queue for Scsi Read/Write requests of a BlockIo2 + // + LIST_ENTRY ScsiRWQueue; + + LIST_ENTRY Link; +} SCSI_BLKIO2_REQUEST; + +// +// Private data structure for a SCSI Read/Write request +// +typedef struct { + SCSI_DISK_DEV *ScsiDiskDevice; + UINT64 Timeout; + EFI_SCSI_SENSE_DATA *SenseData; + UINT8 SenseDataLength; + UINT8 HostAdapterStatus; + UINT8 TargetStatus; + UINT8 *InBuffer; + UINT8 *OutBuffer; + UINT32 DataLength; + UINT64 StartLba; + UINT32 SectorCount; + UINT8 TimesRetry; + + // + // The BlockIo2 request this SCSI command belongs to + // + SCSI_BLKIO2_REQUEST *BlkIo2Req; + + LIST_ENTRY Link; +} SCSI_ASYNC_RW_REQUEST; + // // Global Variables // @@ -410,6 +459,116 @@ ScsiDiskFlushBlocks ( ); +/** + Reset SCSI Disk. + + @param This The pointer of EFI_BLOCK_IO2_PROTOCOL. + @param ExtendedVerification The flag about if extend verificate. + + @retval EFI_SUCCESS The device was reset. + @retval EFI_DEVICE_ERROR The device is not functioning properly and could + not be reset. + @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice(). + +**/ +EFI_STATUS +EFIAPI +ScsiDiskResetEx ( + IN EFI_BLOCK_IO2_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ); + +/** + The function is to Read Block from SCSI Disk. + + @param This The pointer of EFI_BLOCK_IO_PROTOCOL. + @param MediaId The Id of Media detected. + @param Lba The logic block address. + @param Token A pointer to the token associated with the transaction. + @param BufferSize The size of Buffer. + @param Buffer The buffer to fill the read out data. + + @retval EFI_SUCCESS The read request was queued if Token-> Event is + not NULL. The data was read correctly from the + device if theToken-> Event is NULL. + @retval EFI_DEVICE_ERROR The device reported an error while attempting + to perform the read operation. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_MEDIA_CHANGED The MediaId is not for the current media. + @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of + the intrinsic block size of the device. + @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not + valid, or the buffer is not on proper + alignment. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a + lack of resources. + +**/ +EFI_STATUS +EFIAPI +ScsiDiskReadBlocksEx ( + IN EFI_BLOCK_IO2_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN OUT EFI_BLOCK_IO2_TOKEN *Token, + IN UINTN BufferSize, + OUT VOID *Buffer + ); + +/** + The function is to Write Block to SCSI Disk. + + @param This The pointer of EFI_BLOCK_IO_PROTOCOL. + @param MediaId The Id of Media detected. + @param Lba The logic block address. + @param Token A pointer to the token associated with the transaction. + @param BufferSize The size of Buffer. + @param Buffer The buffer to fill the read out data. + + @retval EFI_SUCCESS The data were written correctly to the device. + @retval EFI_WRITE_PROTECTED The device cannot be written to. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_MEDIA_CHANGED The MediaId is not for the current media. + @retval EFI_DEVICE_ERROR The device reported an error while attempting + to perform the write operation. + @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of + the intrinsic block size of the device. + @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not + valid, or the buffer is not on proper + alignment. + +**/ +EFI_STATUS +EFIAPI +ScsiDiskWriteBlocksEx ( + IN EFI_BLOCK_IO2_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN OUT EFI_BLOCK_IO2_TOKEN *Token, + IN UINTN BufferSize, + IN VOID *Buffer + ); + +/** + Flush the Block Device. + + @param This Indicates a pointer to the calling context. + @param Token A pointer to the token associated with the transaction. + + @retval EFI_SUCCESS All outstanding data was written to the device. + @retval EFI_DEVICE_ERROR The device reported an error while writing back the + data. + @retval EFI_NO_MEDIA There is no media in the device. + +**/ +EFI_STATUS +EFIAPI +ScsiDiskFlushBlocksEx ( + IN EFI_BLOCK_IO2_PROTOCOL *This, + IN OUT EFI_BLOCK_IO2_TOKEN *Token + ); + + /** Provides inquiry information for the controller type. @@ -717,6 +876,54 @@ ScsiDiskWriteSectors ( IN UINTN NumberOfBlocks ); +/** + Asynchronously read sector from SCSI Disk. + + @param ScsiDiskDevice The pointer of SCSI_DISK_DEV. + @param Buffer The buffer to fill in the read out data. + @param Lba Logic block address. + @param NumberOfBlocks The number of blocks to read. + @param Token A pointer to the token associated with the + non-blocking read request. + + @retval EFI_INVALID_PARAMETER Token is NULL or Token->Event is NULL. + @retval EFI_DEVICE_ERROR Indicates a device error. + @retval EFI_SUCCESS Operation is successful. + +**/ +EFI_STATUS +ScsiDiskAsyncReadSectors ( + IN SCSI_DISK_DEV *ScsiDiskDevice, + OUT VOID *Buffer, + IN EFI_LBA Lba, + IN UINTN NumberOfBlocks, + IN EFI_BLOCK_IO2_TOKEN *Token + ); + +/** + Asynchronously write sector to SCSI Disk. + + @param ScsiDiskDevice The pointer of SCSI_DISK_DEV. + @param Buffer The buffer of data to be written into SCSI Disk. + @param Lba Logic block address. + @param NumberOfBlocks The number of blocks to read. + @param Token A pointer to the token associated with the + non-blocking read request. + + @retval EFI_INVALID_PARAMETER Token is NULL or Token->Event is NULL + @retval EFI_DEVICE_ERROR Indicates a device error. + @retval EFI_SUCCESS Operation is successful. + +**/ +EFI_STATUS +ScsiDiskAsyncWriteSectors ( + IN SCSI_DISK_DEV *ScsiDiskDevice, + IN VOID *Buffer, + IN EFI_LBA Lba, + IN UINTN NumberOfBlocks, + IN EFI_BLOCK_IO2_TOKEN *Token + ); + /** Submit Read(10) command. @@ -815,6 +1022,130 @@ ScsiDiskWrite16 ( IN UINT32 SectorCount ); +/** + Submit Async Read(10) command. + + @param ScsiDiskDevice The pointer of ScsiDiskDevice. + @param Timeout The time to complete the command. + @param DataBuffer The buffer to fill with the read out data. + @param DataLength The length of buffer. + @param StartLba The start logic block address. + @param SectorCount The number of blocks to read. + @param BlkIo2Req The upstream BlockIo2 request. + @param Token The pointer to the token associated with the + non-blocking read request. + + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a + lack of resources. + @return others Status returned by calling + ScsiRead10CommandEx(). + +**/ +EFI_STATUS +ScsiDiskAsyncRead10 ( + IN SCSI_DISK_DEV *ScsiDiskDevice, + IN UINT64 Timeout, + OUT UINT8 *DataBuffer, + IN UINT32 DataLength, + IN UINT32 StartLba, + IN UINT32 SectorCount, + IN OUT SCSI_BLKIO2_REQUEST *BlkIo2Req, + IN EFI_BLOCK_IO2_TOKEN *Token + ); + +/** + Submit Async Write(10) command. + + @param ScsiDiskDevice The pointer of ScsiDiskDevice. + @param Timeout The time to complete the command. + @param DataBuffer The buffer contains the data to write. + @param DataLength The length of buffer. + @param StartLba The start logic block address. + @param SectorCount The number of blocks to write. + @param BlkIo2Req The upstream BlockIo2 request. + @param Token The pointer to the token associated with the + non-blocking read request. + + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a + lack of resources. + @return others Status returned by calling + ScsiWrite10CommandEx(). + +**/ +EFI_STATUS +ScsiDiskAsyncWrite10 ( + IN SCSI_DISK_DEV *ScsiDiskDevice, + IN UINT64 Timeout, + IN UINT8 *DataBuffer, + IN UINT32 DataLength, + IN UINT32 StartLba, + IN UINT32 SectorCount, + IN OUT SCSI_BLKIO2_REQUEST *BlkIo2Req, + IN EFI_BLOCK_IO2_TOKEN *Token + ); + +/** + Submit Async Read(16) command. + + @param ScsiDiskDevice The pointer of ScsiDiskDevice. + @param Timeout The time to complete the command. + @param DataBuffer The buffer to fill with the read out data. + @param DataLength The length of buffer. + @param StartLba The start logic block address. + @param SectorCount The number of blocks to read. + @param BlkIo2Req The upstream BlockIo2 request. + @param Token The pointer to the token associated with the + non-blocking read request. + + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a + lack of resources. + @return others Status returned by calling + ScsiRead16CommandEx(). + +**/ +EFI_STATUS +ScsiDiskAsyncRead16 ( + IN SCSI_DISK_DEV *ScsiDiskDevice, + IN UINT64 Timeout, + OUT UINT8 *DataBuffer, + IN UINT32 DataLength, + IN UINT64 StartLba, + IN UINT32 SectorCount, + IN OUT SCSI_BLKIO2_REQUEST *BlkIo2Req, + IN EFI_BLOCK_IO2_TOKEN *Token + ); + +/** + Submit Async Write(16) command. + + @param ScsiDiskDevice The pointer of ScsiDiskDevice. + @param Timeout The time to complete the command. + @param DataBuffer The buffer contains the data to write. + @param DataLength The length of buffer. + @param StartLba The start logic block address. + @param SectorCount The number of blocks to write. + @param BlkIo2Req The upstream BlockIo2 request. + @param Token The pointer to the token associated with the + non-blocking read request. + + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a + lack of resources. + @return others Status returned by calling + ScsiWrite16CommandEx(). + +**/ +EFI_STATUS +ScsiDiskAsyncWrite16 ( + IN SCSI_DISK_DEV *ScsiDiskDevice, + IN UINT64 Timeout, + IN UINT8 *DataBuffer, + IN UINT32 DataLength, + IN UINT64 StartLba, + IN UINT32 SectorCount, + IN OUT SCSI_BLKIO2_REQUEST *BlkIo2Req, + IN EFI_BLOCK_IO2_TOKEN *Token + ); + /** Get information from media read capacity command. diff --git a/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDiskDxe.inf b/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDiskDxe.inf index ec96aa6f928c..47539e55c8e7 100644 --- a/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDiskDxe.inf +++ b/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDiskDxe.inf @@ -1,8 +1,9 @@ ## @file # The Scsi Disk driver is used to retrieve the media info in the attached SCSI disk. -# It detects the SCSI disk media and installs Block I/O Protocol on the device handle. +# It detects the SCSI disk media and installs Block I/O and Block I/O2 Protocol on +# the device handle. # -# Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.
+# Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
# This program and the accompanying materials # are licensed and made available under the terms and conditions of the BSD License # which accompanies this distribution. The full text of the license may be found at @@ -55,6 +56,7 @@ [Protocols] gEfiDiskInfoProtocolGuid ## BY_START gEfiBlockIoProtocolGuid ## BY_START + gEfiBlockIo2ProtocolGuid ## BY_START gEfiScsiIoProtocolGuid ## TO_START gEfiScsiPassThruProtocolGuid ## TO_START gEfiExtScsiPassThruProtocolGuid ## TO_START From c3a1d5980474c31dcdb0742a190f35fe7251aca3 Mon Sep 17 00:00:00 2001 From: Hao Wu Date: Fri, 11 Dec 2015 07:35:31 +0000 Subject: [PATCH 237/525] MdeModulePkg UfsPassThruDxe: Add Non-blocking I/O Support Previously, UfsPassThruPassThru function does not handle the 'Event' parameter and blocking read/write operations are always executed. This commit enables non-blocking read/write feature for UFS devices. (Sync patch r19216 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Hao Wu Reviewed-by: Feng Tian git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19223 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Bus/Ufs/UfsPassThruDxe/UfsPassThru.c | 70 ++++- .../Bus/Ufs/UfsPassThruDxe/UfsPassThru.h | 75 ++++- .../Bus/Ufs/UfsPassThruDxe/UfsPassThruHci.c | 288 ++++++++++++++++-- 3 files changed, 393 insertions(+), 40 deletions(-) diff --git a/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.c b/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.c index 306fd37a2979..aa40e2747097 100644 --- a/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.c +++ b/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.c @@ -1,6 +1,6 @@ /** @file - Copyright (c) 2014, Intel Corporation. All rights reserved.
+ Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -21,10 +21,7 @@ UFS_PASS_THRU_PRIVATE_DATA gUfsPassThruTemplate = { NULL, // Handle { // ExtScsiPassThruMode 0xFFFFFFFF, - // - // Note that the driver doesn't support ExtScsiPassThru non blocking I/O. - // - EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL | EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL, + EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL | EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL | EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_NONBLOCKIO, sizeof (UINTN) }, { // ExtScsiPassThru @@ -64,6 +61,11 @@ UFS_PASS_THRU_PRIVATE_DATA gUfsPassThruTemplate = { }, 0x0000, // By default don't expose any Luns. 0x0 + }, + NULL, // TimerEvent + { // Queue + NULL, + NULL } }; @@ -212,7 +214,7 @@ UfsPassThruPassThru ( return EFI_INVALID_PARAMETER; } - Status = UfsExecScsiCmds (Private, UfsLun, Packet); + Status = UfsExecScsiCmds (Private, UfsLun, Packet, Event); return Status; } @@ -816,6 +818,7 @@ UfsPassThruDriverBindingStart ( // Private = AllocateCopyPool (sizeof (UFS_PASS_THRU_PRIVATE_DATA), &gUfsPassThruTemplate); if (Private == NULL) { + DEBUG ((EFI_D_ERROR, "Unable to allocate Ufs Pass Thru private data\n")); Status = EFI_OUT_OF_RESOURCES; goto Error; } @@ -823,6 +826,7 @@ UfsPassThruDriverBindingStart ( Private->ExtScsiPassThru.Mode = &Private->ExtScsiPassThruMode; Private->UfsHostController = UfsHc; Private->UfsHcBase = UfsHcBase; + InitializeListHead (&Private->Queue); // // Initialize UFS Host Controller H/W. @@ -873,6 +877,31 @@ UfsPassThruDriverBindingStart ( } } + // + // Start the asynchronous interrupt monitor + // + Status = gBS->CreateEvent ( + EVT_TIMER | EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + ProcessAsyncTaskList, + Private, + &Private->TimerEvent + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Ufs Create Async Tasks Event Error, Status = %r\n", Status)); + goto Error; + } + + Status = gBS->SetTimer ( + Private->TimerEvent, + TimerPeriodic, + UFS_HC_ASYNC_TIMER + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Ufs Set Periodic Timer Error, Status = %r\n", Status)); + goto Error; + } + Status = gBS->InstallProtocolInterface ( &Controller, &gEfiExtScsiPassThruProtocolGuid, @@ -899,6 +928,10 @@ UfsPassThruDriverBindingStart ( UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (Private->Nutrs * sizeof (UTP_TMRD)), Private->UtpTrlBase); } + if (Private->TimerEvent != NULL) { + gBS->CloseEvent (Private->TimerEvent); + } + FreePool (Private); } @@ -953,6 +986,9 @@ UfsPassThruDriverBindingStop ( UFS_PASS_THRU_PRIVATE_DATA *Private; EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtScsiPassThru; EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc; + UFS_PASS_THRU_TRANS_REQ *TransReq; + LIST_ENTRY *Entry; + LIST_ENTRY *NextEntry; DEBUG ((EFI_D_INFO, "==UfsPassThru Stop== Controller Controller = %x\n", Controller)); @@ -972,6 +1008,24 @@ UfsPassThruDriverBindingStop ( Private = UFS_PASS_THRU_PRIVATE_DATA_FROM_THIS (ExtScsiPassThru); UfsHc = Private->UfsHostController; + // + // Cleanup the resources of I/O requests in the async I/O queue + // + if (!IsListEmpty(&Private->Queue)) { + EFI_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->Queue) { + TransReq = UFS_PASS_THRU_TRANS_REQ_FROM_THIS (Entry); + + // + // TODO: Should find/add a proper host adapter return status for this + // case. + // + TransReq->Packet->HostAdapterStatus = + EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR; + + SignalCallerEvent (Private, TransReq); + } + } + Status = gBS->UninstallProtocolInterface ( Controller, &gEfiExtScsiPassThruProtocolGuid, @@ -1002,6 +1056,10 @@ UfsPassThruDriverBindingStop ( UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (Private->Nutrs * sizeof (UTP_TMRD)), Private->UtpTrlBase); } + if (Private->TimerEvent != NULL) { + gBS->CloseEvent (Private->TimerEvent); + } + FreePool (Private); // diff --git a/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.h b/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.h index ce8066f71e84..4f7087f44f42 100644 --- a/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.h +++ b/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.h @@ -50,6 +50,14 @@ typedef struct { UINT16 Rsvd:4; } UFS_EXPOSED_LUNS; +// +// Iterate through the doule linked list. This is delete-safe. +// Do not touch NextEntry +// +#define EFI_LIST_FOR_EACH_SAFE(Entry, NextEntry, ListHead) \ + for(Entry = (ListHead)->ForwardLink, NextEntry = Entry->ForwardLink;\ + Entry != (ListHead); Entry = NextEntry, NextEntry = Entry->ForwardLink) + typedef struct _UFS_PASS_THRU_PRIVATE_DATA { UINT32 Signature; EFI_HANDLE Handle; @@ -69,9 +77,37 @@ typedef struct _UFS_PASS_THRU_PRIVATE_DATA { VOID *TmrlMapping; UFS_EXPOSED_LUNS Luns; + + // + // For Non-blocking operation. + // + EFI_EVENT TimerEvent; + LIST_ENTRY Queue; } UFS_PASS_THRU_PRIVATE_DATA; +#define UFS_PASS_THRU_TRANS_REQ_SIG SIGNATURE_32 ('U', 'F', 'S', 'T') + +typedef struct { + UINT32 Signature; + LIST_ENTRY TransferList; + + UINT8 Slot; + UTP_TRD *Trd; + UINT32 CmdDescSize; + VOID *CmdDescHost; + VOID *CmdDescMapping; + VOID *DataBufMapping; + + EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet; + UINT64 TimeoutRemain; + EFI_EVENT CallerEvent; +} UFS_PASS_THRU_TRANS_REQ; + +#define UFS_PASS_THRU_TRANS_REQ_FROM_THIS(a) \ + CR(a, UFS_PASS_THRU_TRANS_REQ, TransferList, UFS_PASS_THRU_TRANS_REQ_SIG) + #define UFS_TIMEOUT EFI_TIMER_PERIOD_SECONDS(3) +#define UFS_HC_ASYNC_TIMER EFI_TIMER_PERIOD_MILLISECONDS(1) #define ROUNDUP8(x) (((x) % 8 == 0) ? (x) : ((x) / 8 + 1) * 8) @@ -587,6 +623,11 @@ UfsPassThruGetNextTarget ( @param[in] Lun The LUN of the UFS device to send the SCSI Request Packet. @param[in, out] Packet A pointer to the SCSI Request Packet to send to a specified Lun of the UFS device. + @param[in] Event If nonblocking I/O is not supported then Event is ignored, and blocking + I/O is performed. If Event is NULL, then blocking I/O is performed. If + Event is not NULL and non blocking I/O is supported, then + nonblocking I/O is performed, and Event will be signaled when the + SCSI Request Packet completes. @retval EFI_SUCCESS The SCSI Request Packet was sent by the host. For bi-directional commands, InTransferLength bytes were transferred from @@ -603,7 +644,8 @@ EFI_STATUS UfsExecScsiCmds ( IN UFS_PASS_THRU_PRIVATE_DATA *Private, IN UINT8 Lun, - IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet + IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet, + IN EFI_EVENT Event OPTIONAL ); /** @@ -719,6 +761,37 @@ UfsExecNopCmds ( IN UFS_PASS_THRU_PRIVATE_DATA *Private ); +/** + Call back function when the timer event is signaled. + + @param[in] Event The Event this notify function registered to. + @param[in] Context Pointer to the context data registered to the Event. + +**/ +VOID +EFIAPI +ProcessAsyncTaskList ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +/** + Internal helper function which will signal the caller event and clean up + resources. + + @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data + structure. + @param[in] TransReq The pointer to the UFS_PASS_THRU_TRANS_REQ data + structure. + +**/ +VOID +EFIAPI +SignalCallerEvent ( + IN UFS_PASS_THRU_PRIVATE_DATA *Private, + IN UFS_PASS_THRU_TRANS_REQ *TransReq + ); + extern EFI_COMPONENT_NAME_PROTOCOL gUfsPassThruComponentName; extern EFI_COMPONENT_NAME2_PROTOCOL gUfsPassThruComponentName2; extern EFI_DRIVER_BINDING_PROTOCOL gUfsPassThruDriverBinding; diff --git a/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruHci.c b/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruHci.c index 9f9abab40fde..4fbe199390f4 100644 --- a/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruHci.c +++ b/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruHci.c @@ -729,6 +729,7 @@ UfsCreateNopCommandDesc ( @param[out] Slot The available slot. @retval EFI_SUCCESS The available slot was found successfully. + @retval EFI_NOT_READY No slot is available at this moment. **/ EFI_STATUS @@ -737,15 +738,28 @@ UfsFindAvailableSlotInTrl ( OUT UINT8 *Slot ) { + UINT8 Nutrs; + UINT8 Index; + UINT32 Data; + EFI_STATUS Status; + ASSERT ((Private != NULL) && (Slot != NULL)); - // - // The simplest algo to always use slot 0. - // TODO: enhance it to support async transfer with multiple slot. - // - *Slot = 0; + Status = UfsMmioRead32 (Private, UFS_HC_UTRLDBR_OFFSET, &Data); + if (EFI_ERROR (Status)) { + return Status; + } - return EFI_SUCCESS; + Nutrs = (UINT8)((Private->Capabilities & UFS_HC_CAP_NUTRS) + 1); + + for (Index = 0; Index < Nutrs; Index++) { + if ((Data & (BIT0 << Index)) == 0) { + *Slot = Index; + return EFI_SUCCESS; + } + } + + return EFI_NOT_READY; } /** @@ -1382,6 +1396,11 @@ UfsExecNopCmds ( @param[in] Lun The LUN of the UFS device to send the SCSI Request Packet. @param[in, out] Packet A pointer to the SCSI Request Packet to send to a specified Lun of the UFS device. + @param[in] Event If nonblocking I/O is not supported then Event is ignored, and blocking + I/O is performed. If Event is NULL, then blocking I/O is performed. If + Event is not NULL and non blocking I/O is supported, then + nonblocking I/O is performed, and Event will be signaled when the + SCSI Request Packet completes. @retval EFI_SUCCESS The SCSI Request Packet was sent by the host. For bi-directional commands, InTransferLength bytes were transferred from @@ -1398,19 +1417,14 @@ EFI_STATUS UfsExecScsiCmds ( IN UFS_PASS_THRU_PRIVATE_DATA *Private, IN UINT8 Lun, - IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet + IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet, + IN EFI_EVENT Event OPTIONAL ) { EFI_STATUS Status; - UINT8 Slot; - UTP_TRD *Trd; - UINT32 CmdDescSize; UTP_RESPONSE_UPIU *Response; UINT16 SenseDataLen; UINT32 ResTranCount; - VOID *CmdDescHost; - VOID *CmdDescMapping; - VOID *DataBufMapping; VOID *DataBuf; EFI_PHYSICAL_ADDRESS DataBufPhyAddr; UINT32 DataLen; @@ -1419,32 +1433,44 @@ UfsExecScsiCmds ( EDKII_UFS_HOST_CONTROLLER_OPERATION Flag; UFS_DATA_DIRECTION DataDirection; UTP_TR_PRD *PrdtBase; + EFI_TPL OldTpl; + UFS_PASS_THRU_TRANS_REQ *TransReq; - Trd = NULL; - CmdDescHost = NULL; - CmdDescMapping = NULL; - DataBufMapping = NULL; + TransReq = AllocateZeroPool (sizeof (UFS_PASS_THRU_TRANS_REQ)); + if (TransReq == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + TransReq->Signature = UFS_PASS_THRU_TRANS_REQ_SIG; + TransReq->TimeoutRemain = Packet->Timeout; DataBufPhyAddr = 0; UfsHc = Private->UfsHostController; // // Find out which slot of transfer request list is available. // - Status = UfsFindAvailableSlotInTrl (Private, &Slot); + Status = UfsFindAvailableSlotInTrl (Private, &TransReq->Slot); if (EFI_ERROR (Status)) { return Status; } - Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot; + TransReq->Trd = ((UTP_TRD*)Private->UtpTrlBase) + TransReq->Slot; // // Fill transfer request descriptor to this slot. // - Status = UfsCreateScsiCommandDesc (Private, Lun, Packet, Trd, &CmdDescHost, &CmdDescMapping); + Status = UfsCreateScsiCommandDesc ( + Private, + Lun, + Packet, + TransReq->Trd, + &TransReq->CmdDescHost, + &TransReq->CmdDescMapping + ); if (EFI_ERROR (Status)) { return Status; } - CmdDescSize = Trd->PrdtO * sizeof (UINT32) + Trd->PrdtL * sizeof (UTP_TR_PRD); + TransReq->CmdDescSize = TransReq->Trd->PrdtO * sizeof (UINT32) + TransReq->Trd->PrdtL * sizeof (UTP_TR_PRD); if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) { DataBuf = Packet->InDataBuffer; @@ -1468,7 +1494,7 @@ UfsExecScsiCmds ( DataBuf, &MapLength, &DataBufPhyAddr, - &DataBufMapping + &TransReq->DataBufMapping ); if (EFI_ERROR (Status) || (DataLen != MapLength)) { @@ -1478,14 +1504,32 @@ UfsExecScsiCmds ( // // Fill PRDT table of Command UPIU for executed SCSI cmd. // - PrdtBase = (UTP_TR_PRD*)((UINT8*)CmdDescHost + ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU))); + PrdtBase = (UTP_TR_PRD*)((UINT8*)TransReq->CmdDescHost + ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU))); ASSERT (PrdtBase != NULL); UfsInitUtpPrdt (PrdtBase, (VOID*)(UINTN)DataBufPhyAddr, DataLen); + // + // Insert the async SCSI cmd to the Async I/O list + // + if (Event != NULL) { + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + TransReq->Packet = Packet; + TransReq->CallerEvent = Event; + InsertTailList (&Private->Queue, &TransReq->TransferList); + gBS->RestoreTPL (OldTpl); + } + // // Start to execute the transfer request. // - UfsStartExecCmd (Private, Slot); + UfsStartExecCmd (Private, TransReq->Slot); + + // + // Immediately return for async I/O. + // + if (Event != NULL) { + return EFI_SUCCESS; + } // // Wait for the completion of the transfer request. @@ -1498,7 +1542,7 @@ UfsExecScsiCmds ( // // Get sense data if exists // - Response = (UTP_RESPONSE_UPIU*)((UINT8*)CmdDescHost + Trd->RuO * sizeof (UINT32)); + Response = (UTP_RESPONSE_UPIU*)((UINT8*)TransReq->CmdDescHost + TransReq->Trd->RuO * sizeof (UINT32)); ASSERT (Response != NULL); SenseDataLen = Response->SenseDataLen; SwapLittleEndianToBigEndian ((UINT8*)&SenseDataLen, sizeof (UINT16)); @@ -1518,7 +1562,7 @@ UfsExecScsiCmds ( goto Exit; } - if (Trd->Ocs == 0) { + if (TransReq->Trd->Ocs == 0) { if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) { if ((Response->Flags & BIT5) == BIT5) { ResTranCount = Response->ResTranCount; @@ -1539,18 +1583,21 @@ UfsExecScsiCmds ( Exit: UfsHc->Flush (UfsHc); - UfsStopExecCmd (Private, Slot); + UfsStopExecCmd (Private, TransReq->Slot); - if (DataBufMapping != NULL) { - UfsHc->Unmap (UfsHc, DataBufMapping); + if (TransReq->DataBufMapping != NULL) { + UfsHc->Unmap (UfsHc, TransReq->DataBufMapping); } Exit1: - if (CmdDescMapping != NULL) { - UfsHc->Unmap (UfsHc, CmdDescMapping); + if (TransReq->CmdDescMapping != NULL) { + UfsHc->Unmap (UfsHc, TransReq->CmdDescMapping); } - if (CmdDescHost != NULL) { - UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (CmdDescSize), CmdDescHost); + if (TransReq->CmdDescHost != NULL) { + UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (TransReq->CmdDescSize), TransReq->CmdDescHost); + } + if (TransReq != NULL) { + FreePool (TransReq); } return Status; } @@ -2123,3 +2170,178 @@ UfsControllerStop ( return EFI_SUCCESS; } + +/** + Internal helper function which will signal the caller event and clean up + resources. + + @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data + structure. + @param[in] TransReq The pointer to the UFS_PASS_THRU_TRANS_REQ data + structure. + +**/ +VOID +EFIAPI +SignalCallerEvent ( + IN UFS_PASS_THRU_PRIVATE_DATA *Private, + IN UFS_PASS_THRU_TRANS_REQ *TransReq + ) +{ + EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc; + EFI_EVENT CallerEvent; + + UfsHc = Private->UfsHostController; + CallerEvent = TransReq->CallerEvent; + + RemoveEntryList (&TransReq->TransferList); + + UfsHc->Flush (UfsHc); + + UfsStopExecCmd (Private, TransReq->Slot); + + if (TransReq->DataBufMapping != NULL) { + UfsHc->Unmap (UfsHc, TransReq->DataBufMapping); + } + + if (TransReq->CmdDescMapping != NULL) { + UfsHc->Unmap (UfsHc, TransReq->CmdDescMapping); + } + if (TransReq->CmdDescHost != NULL) { + UfsHc->FreeBuffer ( + UfsHc, + EFI_SIZE_TO_PAGES (TransReq->CmdDescSize), + TransReq->CmdDescHost + ); + } + if (TransReq != NULL) { + FreePool (TransReq); + } + + gBS->SignalEvent (CallerEvent); + return; +} + +/** + Call back function when the timer event is signaled. + + @param[in] Event The Event this notify function registered to. + @param[in] Context Pointer to the context data registered to the Event. + +**/ +VOID +EFIAPI +ProcessAsyncTaskList ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + UFS_PASS_THRU_PRIVATE_DATA *Private; + LIST_ENTRY *Entry; + LIST_ENTRY *NextEntry; + UFS_PASS_THRU_TRANS_REQ *TransReq; + EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet; + UTP_RESPONSE_UPIU *Response; + UINT16 SenseDataLen; + UINT32 ResTranCount; + UINT32 SlotsMap; + UINT32 Value; + EFI_STATUS Status; + + Private = (UFS_PASS_THRU_PRIVATE_DATA*) Context; + SlotsMap = 0; + + // + // Check the entries in the async I/O queue are done or not. + // + if (!IsListEmpty(&Private->Queue)) { + EFI_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->Queue) { + TransReq = UFS_PASS_THRU_TRANS_REQ_FROM_THIS (Entry); + Packet = TransReq->Packet; + + if ((SlotsMap & (BIT0 << TransReq->Slot)) != 0) { + return; + } + SlotsMap |= BIT0 << TransReq->Slot; + + Status = UfsMmioRead32 (Private, UFS_HC_UTRLDBR_OFFSET, &Value); + if (EFI_ERROR (Status)) { + // + // TODO: Should find/add a proper host adapter return status for this + // case. + // + Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR; + DEBUG ((EFI_D_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p UfsMmioRead32() Error.\n", TransReq->CallerEvent)); + SignalCallerEvent (Private, TransReq); + continue; + } + + if ((Value & (BIT0 << TransReq->Slot)) != 0) { + // + // Scsi cmd not finished yet. + // + if (TransReq->TimeoutRemain > UFS_HC_ASYNC_TIMER) { + TransReq->TimeoutRemain -= UFS_HC_ASYNC_TIMER; + continue; + } else { + // + // Timeout occurs. + // + Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND; + DEBUG ((EFI_D_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p EFI_TIMEOUT.\n", TransReq->CallerEvent)); + SignalCallerEvent (Private, TransReq); + continue; + } + } else { + // + // Scsi cmd finished. + // + // Get sense data if exists + // + Response = (UTP_RESPONSE_UPIU*)((UINT8*)TransReq->CmdDescHost + TransReq->Trd->RuO * sizeof (UINT32)); + ASSERT (Response != NULL); + SenseDataLen = Response->SenseDataLen; + SwapLittleEndianToBigEndian ((UINT8*)&SenseDataLen, sizeof (UINT16)); + + if ((Packet->SenseDataLength != 0) && (Packet->SenseData != NULL)) { + CopyMem (Packet->SenseData, Response->SenseData, SenseDataLen); + Packet->SenseDataLength = (UINT8)SenseDataLen; + } + + // + // Check the transfer request result. + // + Packet->TargetStatus = Response->Status; + if (Response->Response != 0) { + DEBUG ((EFI_D_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p Target Failure.\n", TransReq->CallerEvent)); + SignalCallerEvent (Private, TransReq); + continue; + } + + if (TransReq->Trd->Ocs == 0) { + if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) { + if ((Response->Flags & BIT5) == BIT5) { + ResTranCount = Response->ResTranCount; + SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32)); + Packet->InTransferLength -= ResTranCount; + } + } else { + if ((Response->Flags & BIT5) == BIT5) { + ResTranCount = Response->ResTranCount; + SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32)); + Packet->OutTransferLength -= ResTranCount; + } + } + } else { + DEBUG ((EFI_D_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p Target Device Error.\n", TransReq->CallerEvent)); + SignalCallerEvent (Private, TransReq); + continue; + } + + DEBUG ((EFI_D_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p Success.\n", TransReq->CallerEvent)); + SignalCallerEvent (Private, TransReq); + } + } + } +} + From 12c0612023fc1f6f1d62f21810ab146f8e3c6016 Mon Sep 17 00:00:00 2001 From: Hao Wu Date: Fri, 11 Dec 2015 07:36:06 +0000 Subject: [PATCH 238/525] MdeModulePkg ScsiBusDxe: Fix caller event may nerver be signaled For function ScsiExecuteSCSICommand(), when the 'Event' parameter is not NULL but the target SCSI device does not support non-blocking I/O, it will execute a blocking I/O operation instead. However, after the SCSI operation is done, the 'Event' is not signaled to inform the caller. (Sync patch r19217 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Hao Wu Reviewed-by: Feng Tian git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19224 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.c | 46 +++++++++++++++++----- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.c b/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.c index 3e49ffba6888..8eb73e7673fa 100644 --- a/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.c +++ b/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.c @@ -2,7 +2,7 @@ SCSI Bus driver that layers on every SCSI Pass Thru and Extended SCSI Pass Thru protocol in the system. -Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.
+Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -986,13 +986,34 @@ ScsiExecuteSCSICommand ( if (ScsiIoDevice->ExtScsiSupport) { ExtRequestPacket = (EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *) Packet; - Status = ScsiIoDevice->ExtScsiPassThru->PassThru ( - ScsiIoDevice->ExtScsiPassThru, - Target, - ScsiIoDevice->Lun, - ExtRequestPacket, - Event - ); + + if (((ScsiIoDevice->ExtScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_NONBLOCKIO) != 0) && (Event != NULL)) { + Status = ScsiIoDevice->ExtScsiPassThru->PassThru ( + ScsiIoDevice->ExtScsiPassThru, + Target, + ScsiIoDevice->Lun, + ExtRequestPacket, + Event + ); + } else { + // + // If there's no event or the SCSI Device doesn't support NON-BLOCKING, + // let the 'Event' parameter for PassThru() be NULL. + // + Status = ScsiIoDevice->ExtScsiPassThru->PassThru ( + ScsiIoDevice->ExtScsiPassThru, + Target, + ScsiIoDevice->Lun, + ExtRequestPacket, + NULL + ); + if (Event != NULL) { + // + // Signal Event to tell caller to pick up the SCSI IO Packet. + // + gBS->SignalEvent (Event); + } + } } else { mWorkingBuffer = AllocatePool (sizeof(EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET)); @@ -1052,7 +1073,7 @@ ScsiExecuteSCSICommand ( ScsiIoDevice->Pun.ScsiId.Scsi, ScsiIoDevice->Lun, mWorkingBuffer, - Event + NULL ); if (EFI_ERROR(Status)) { FreePool(mWorkingBuffer); @@ -1065,6 +1086,13 @@ ScsiExecuteSCSICommand ( // free mWorkingBuffer. // FreePool(mWorkingBuffer); + + // + // Signal Event to tell caller to pick up the SCSI IO Packet. + // + if (Event != NULL) { + gBS->SignalEvent (Event); + } } } return Status; From 6ba6beac50740f3d6d9d68889a646f169650006f Mon Sep 17 00:00:00 2001 From: Qin Long Date: Fri, 11 Dec 2015 07:41:49 +0000 Subject: [PATCH 239/525] CryptoPkg/OpensslLib: upgrade OpenSSL version to 1.0.2e OpenSSL has released version 1.0.2e with security fixes. Upgrade the supported OpenSSL version in CryptoPkg/OpensslLib from 1.0.2d to 1.0.2e. (Note: This is based on Ard's previous patch with extra fix https://rt.openssl.org/Ticket/Display.html?id=4175) (Sync patch r19218 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Singed-off-by: Ard Biesheuvel Signed-off-by: Qin Long Reviewed-by: Chao Zhang git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19225 6f19259b-4bc3-4df7-8a09-765794883524 --- .../OpensslLib/EDKII_openssl-1.0.2d.patch | 380 ---------- .../OpensslLib/EDKII_openssl-1.0.2e.patch | 707 ++++++++++++++++++ CryptoPkg/Library/OpensslLib/Install.cmd | 2 +- CryptoPkg/Library/OpensslLib/Install.sh | 158 ++-- CryptoPkg/Library/OpensslLib/OpensslLib.inf | 2 +- CryptoPkg/Library/OpensslLib/Patch-HOWTO.txt | 26 +- 6 files changed, 801 insertions(+), 474 deletions(-) delete mode 100644 CryptoPkg/Library/OpensslLib/EDKII_openssl-1.0.2d.patch create mode 100644 CryptoPkg/Library/OpensslLib/EDKII_openssl-1.0.2e.patch diff --git a/CryptoPkg/Library/OpensslLib/EDKII_openssl-1.0.2d.patch b/CryptoPkg/Library/OpensslLib/EDKII_openssl-1.0.2d.patch deleted file mode 100644 index 72e5f3da54c4..000000000000 --- a/CryptoPkg/Library/OpensslLib/EDKII_openssl-1.0.2d.patch +++ /dev/null @@ -1,380 +0,0 @@ -diff U3 crypto/bio/bio.h crypto/bio/bio.h ---- crypto/bio/bio.h Thu Jun 11 21:50:12 2015 -+++ crypto/bio/bio.h Fri Jun 12 11:00:52 2015 -@@ -646,10 +646,10 @@ - int BIO_asn1_get_suffix(BIO *b, asn1_ps_func **psuffix, - asn1_ps_func **psuffix_free); - --# ifndef OPENSSL_NO_FP_API - BIO_METHOD *BIO_s_file(void); - BIO *BIO_new_file(const char *filename, const char *mode); - BIO *BIO_new_fp(FILE *stream, int close_flag); -+# ifndef OPENSSL_NO_FP_API - # define BIO_s_file_internal BIO_s_file - # endif - BIO *BIO_new(BIO_METHOD *type); -diff U3 crypto/bio/bss_file.c crypto/bio/bss_file.c ---- crypto/bio/bss_file.c Thu Jun 11 21:01:06 2015 -+++ crypto/bio/bss_file.c Fri Jun 12 11:01:28 2015 -@@ -460,6 +460,23 @@ - return (ret); - } - -+# else -+ -+BIO_METHOD *BIO_s_file(void) -+{ -+ return NULL; -+} -+ -+BIO *BIO_new_file(const char *filename, const char *mode) -+{ -+ return NULL; -+} -+ -+BIO *BIO_new_fp(FILE *stream, int close_flag) -+{ -+ return NULL; -+} -+ - # endif /* OPENSSL_NO_STDIO */ - - #endif /* HEADER_BSS_FILE_C */ -diff U3 crypto/dh/dh_pmeth.c crypto/dh/dh_pmeth.c ---- crypto/dh/dh_pmeth.c Thu Jun 11 21:50:12 2015 -+++ crypto/dh/dh_pmeth.c Fri Jun 12 11:08:48 2015 -@@ -449,6 +449,9 @@ - *keylen = ret; - return 1; - } else if (dctx->kdf_type == EVP_PKEY_DH_KDF_X9_42) { -+#ifdef OPENSSL_NO_CMS -+ return 0; -+#else - unsigned char *Z = NULL; - size_t Zlen = 0; - if (!dctx->kdf_outlen || !dctx->kdf_oid) -@@ -478,6 +481,7 @@ - OPENSSL_free(Z); - } - return ret; -+#endif - } - return 1; - } -diff U3 crypto/pem/pem.h crypto/pem/pem.h ---- crypto/pem/pem.h Thu Jun 11 21:50:12 2015 -+++ crypto/pem/pem.h Fri Jun 12 10:58:18 2015 -@@ -324,6 +324,7 @@ - - # define DECLARE_PEM_read_fp(name, type) /**/ - # define DECLARE_PEM_write_fp(name, type) /**/ -+# define DECLARE_PEM_write_fp_const(name, type) /**/ - # define DECLARE_PEM_write_cb_fp(name, type) /**/ - # else - -diff U3 crypto/pkcs7/pk7_smime.c crypto/pkcs7/pk7_smime.c ---- crypto/pkcs7/pk7_smime.c Thu Jun 11 21:01:06 2015 -+++ crypto/pkcs7/pk7_smime.c Fri Jun 12 11:23:38 2015 -@@ -254,7 +254,8 @@ - STACK_OF(PKCS7_SIGNER_INFO) *sinfos; - PKCS7_SIGNER_INFO *si; - X509_STORE_CTX cert_ctx; -- char buf[4096]; -+ char *buf = NULL; -+ int bufsiz; - int i, j = 0, k, ret = 0; - BIO *p7bio; - BIO *tmpin, *tmpout; -@@ -365,9 +366,14 @@ - } else - tmpout = out; - -+ bufsiz = 4096; -+ buf = OPENSSL_malloc(bufsiz); -+ if (buf == NULL) { -+ goto err; -+ } - /* We now have to 'read' from p7bio to calculate digests etc. */ - for (;;) { -- i = BIO_read(p7bio, buf, sizeof(buf)); -+ i = BIO_read(p7bio, buf, bufsiz); - if (i <= 0) - break; - if (tmpout) -@@ -406,6 +412,10 @@ - BIO_free_all(p7bio); - - sk_X509_free(signers); -+ -+ if (buf != NULL) { -+ OPENSSL_free(buf); -+ } - - return ret; - } -diff U3 crypto/rand/rand_unix.c crypto/rand/rand_unix.c ---- crypto/rand/rand_unix.c Thu Jun 11 21:01:06 2015 -+++ crypto/rand/rand_unix.c Fri Jun 12 10:51:21 2015 -@@ -116,7 +116,7 @@ - #include - #include "rand_lcl.h" - --#if !(defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_VMS) || defined(OPENSSL_SYS_OS2) || defined(OPENSSL_SYS_VXWORKS) || defined(OPENSSL_SYS_NETWARE)) -+#if !(defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_VMS) || defined(OPENSSL_SYS_OS2) || defined(OPENSSL_SYS_VXWORKS) || defined(OPENSSL_SYS_NETWARE) || defined(OPENSSL_SYS_UEFI)) - - # include - # include -@@ -439,7 +439,7 @@ - * defined(OPENSSL_SYS_VXWORKS) || - * defined(OPENSSL_SYS_NETWARE)) */ - --#if defined(OPENSSL_SYS_VXWORKS) -+#if defined(OPENSSL_SYS_VXWORKS) || defined(OPENSSL_SYS_UEFI) - int RAND_poll(void) - { - return 0; -diff U3 crypto/rsa/rsa_ameth.c crypto/rsa/rsa_ameth.c ---- crypto/rsa/rsa_ameth.c Thu Jun 11 21:50:12 2015 -+++ crypto/rsa/rsa_ameth.c Fri Jun 12 10:45:38 2015 -@@ -68,10 +68,12 @@ - #endif - #include "asn1_locl.h" - -+#ifndef OPENSSL_NO_CMS - static int rsa_cms_sign(CMS_SignerInfo *si); - static int rsa_cms_verify(CMS_SignerInfo *si); - static int rsa_cms_decrypt(CMS_RecipientInfo *ri); - static int rsa_cms_encrypt(CMS_RecipientInfo *ri); -+#endif - - static int rsa_pub_encode(X509_PUBKEY *pk, const EVP_PKEY *pkey) - { -@@ -665,6 +667,7 @@ - return rv; - } - -+#ifndef OPENSSL_NO_CMS - static int rsa_cms_verify(CMS_SignerInfo *si) - { - int nid, nid2; -@@ -683,6 +686,7 @@ - } - return 0; - } -+#endif - - /* - * Customised RSA item verification routine. This is called when a signature -@@ -705,6 +709,7 @@ - return -1; - } - -+#ifndef OPENSSL_NO_CMS - static int rsa_cms_sign(CMS_SignerInfo *si) - { - int pad_mode = RSA_PKCS1_PADDING; -@@ -729,6 +734,7 @@ - X509_ALGOR_set0(alg, OBJ_nid2obj(NID_rsassaPss), V_ASN1_SEQUENCE, os); - return 1; - } -+#endif - - static int rsa_item_sign(EVP_MD_CTX *ctx, const ASN1_ITEM *it, void *asn, - X509_ALGOR *alg1, X509_ALGOR *alg2, -@@ -785,6 +791,7 @@ - return pss; - } - -+#ifndef OPENSSL_NO_CMS - static int rsa_cms_decrypt(CMS_RecipientInfo *ri) - { - EVP_PKEY_CTX *pkctx; -@@ -857,7 +864,9 @@ - X509_ALGOR_free(maskHash); - return rv; - } -+#endif - -+#ifndef OPENSSL_NO_CMS - static int rsa_cms_encrypt(CMS_RecipientInfo *ri) - { - const EVP_MD *md, *mgf1md; -@@ -920,6 +929,7 @@ - ASN1_STRING_free(os); - return rv; - } -+#endif - - const EVP_PKEY_ASN1_METHOD rsa_asn1_meths[] = { - { -diff U3 crypto/x509/x509_vfy.c crypto/x509/x509_vfy.c ---- crypto/x509/x509_vfy.c Thu Jun 11 21:52:58 2015 -+++ crypto/x509/x509_vfy.c Fri Jun 12 11:29:37 2015 -@@ -1653,6 +1653,10 @@ - - static int check_cert_time(X509_STORE_CTX *ctx, X509 *x) - { -+#ifdef OPENSSL_SYS_UEFI -+ /* Bypass Certificate Time Checking for UEFI version. */ -+ return 1; -+#else - time_t *ptime; - int i; - -@@ -1692,6 +1696,7 @@ - } - - return 1; -+#endif - } - - static int internal_verify(X509_STORE_CTX *ctx) -diff U3 crypto/x509v3/ext_dat.h crypto/x509v3/ext_dat.h ---- crypto/x509v3/ext_dat.h Thu Jun 11 21:50:12 2015 -+++ crypto/x509v3/ext_dat.h Fri Jun 12 11:11:03 2015 -@@ -127,8 +127,10 @@ - &v3_idp, - &v3_alt[2], - &v3_freshest_crl, -+#ifndef OPENSSL_SYS_UEFI - &v3_ct_scts[0], - &v3_ct_scts[1], -+#endif - }; - - /* Number of standard extensions */ -diff U3 crypto/crypto.h crypto/crypto.h ---- crypto/crypto.h Thu Jun 11 21:01:06 2015 -+++ crypto/crypto.h Fri Jun 12 11:33:27 2015 -@@ -235,15 +235,15 @@ - # ifndef OPENSSL_NO_LOCKING - # ifndef CRYPTO_w_lock - # define CRYPTO_w_lock(type) \ -- CRYPTO_lock(CRYPTO_LOCK|CRYPTO_WRITE,type,__FILE__,__LINE__) -+ CRYPTO_lock(CRYPTO_LOCK|CRYPTO_WRITE,type,NULL,0) - # define CRYPTO_w_unlock(type) \ -- CRYPTO_lock(CRYPTO_UNLOCK|CRYPTO_WRITE,type,__FILE__,__LINE__) -+ CRYPTO_lock(CRYPTO_UNLOCK|CRYPTO_WRITE,type,NULL,0) - # define CRYPTO_r_lock(type) \ -- CRYPTO_lock(CRYPTO_LOCK|CRYPTO_READ,type,__FILE__,__LINE__) -+ CRYPTO_lock(CRYPTO_LOCK|CRYPTO_READ,type,NULL,0) - # define CRYPTO_r_unlock(type) \ -- CRYPTO_lock(CRYPTO_UNLOCK|CRYPTO_READ,type,__FILE__,__LINE__) -+ CRYPTO_lock(CRYPTO_UNLOCK|CRYPTO_READ,type,NULL,0) - # define CRYPTO_add(addr,amount,type) \ -- CRYPTO_add_lock(addr,amount,type,__FILE__,__LINE__) -+ CRYPTO_add_lock(addr,amount,type,NULL,0) - # endif - # else - # define CRYPTO_w_lock(a) -@@ -378,19 +378,19 @@ - # define MemCheck_off() CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE) - # define is_MemCheck_on() CRYPTO_is_mem_check_on() - --# define OPENSSL_malloc(num) CRYPTO_malloc((int)num,__FILE__,__LINE__) --# define OPENSSL_strdup(str) CRYPTO_strdup((str),__FILE__,__LINE__) -+# define OPENSSL_malloc(num) CRYPTO_malloc((int)num,NULL,0) -+# define OPENSSL_strdup(str) CRYPTO_strdup((str),NULL,0) - # define OPENSSL_realloc(addr,num) \ -- CRYPTO_realloc((char *)addr,(int)num,__FILE__,__LINE__) -+ CRYPTO_realloc((char *)addr,(int)num,NULL,0) - # define OPENSSL_realloc_clean(addr,old_num,num) \ -- CRYPTO_realloc_clean(addr,old_num,num,__FILE__,__LINE__) -+ CRYPTO_realloc_clean(addr,old_num,num,NULL,0) - # define OPENSSL_remalloc(addr,num) \ -- CRYPTO_remalloc((char **)addr,(int)num,__FILE__,__LINE__) -+ CRYPTO_remalloc((char **)addr,(int)num,NULL,0) - # define OPENSSL_freeFunc CRYPTO_free - # define OPENSSL_free(addr) CRYPTO_free(addr) - - # define OPENSSL_malloc_locked(num) \ -- CRYPTO_malloc_locked((int)num,__FILE__,__LINE__) -+ CRYPTO_malloc_locked((int)num,NULL,0) - # define OPENSSL_free_locked(addr) CRYPTO_free_locked(addr) - - const char *SSLeay_version(int type); -@@ -545,7 +545,7 @@ - long CRYPTO_get_mem_debug_options(void); - - # define CRYPTO_push_info(info) \ -- CRYPTO_push_info_(info, __FILE__, __LINE__); -+ CRYPTO_push_info_(info, NULL, 0); - int CRYPTO_push_info_(const char *info, const char *file, int line); - int CRYPTO_pop_info(void); - int CRYPTO_remove_all_info(void); -@@ -588,7 +588,7 @@ - - /* die if we have to */ - void OpenSSLDie(const char *file, int line, const char *assertion); --# define OPENSSL_assert(e) (void)((e) ? 0 : (OpenSSLDie(__FILE__, __LINE__, #e),1)) -+# define OPENSSL_assert(e) (void)((e) ? 0 : (OpenSSLDie(NULL, 0, #e),1)) - - unsigned long *OPENSSL_ia32cap_loc(void); - # define OPENSSL_ia32cap (*(OPENSSL_ia32cap_loc())) -@@ -605,14 +605,14 @@ - # define fips_md_init_ctx(alg, cx) \ - int alg##_Init(cx##_CTX *c) \ - { \ -- if (FIPS_mode()) OpenSSLDie(__FILE__, __LINE__, \ -+ if (FIPS_mode()) OpenSSLDie(NULL, 0, \ - "Low level API call to digest " #alg " forbidden in FIPS mode!"); \ - return private_##alg##_Init(c); \ - } \ - int private_##alg##_Init(cx##_CTX *c) - - # define fips_cipher_abort(alg) \ -- if (FIPS_mode()) OpenSSLDie(__FILE__, __LINE__, \ -+ if (FIPS_mode()) OpenSSLDie(NULL, 0, \ - "Low level API call to cipher " #alg " forbidden in FIPS mode!") - - # else -diff U3 crypto/opensslconf.h crypto/opensslconf.h ---- crypto/opensslconf.h Thu Jun 11 21:55:38 2015 -+++ crypto/opensslconf.h Fri Jun 12 10:28:27 2015 -@@ -159,9 +159,12 @@ - /* Should we define BN_DIV2W here? */ - - /* Only one for the following should be defined */ -+/* Bypass the following definitions for UEFI version. */ -+#if !defined(OPENSSL_SYS_UEFI) - #undef SIXTY_FOUR_BIT_LONG - #undef SIXTY_FOUR_BIT - #define THIRTY_TWO_BIT -+#endif - #endif - - #if defined(HEADER_RC4_LOCL_H) && !defined(CONFIG_HEADER_RC4_LOCL_H) -diff U3 crypto/err/err.c crypto/err/err.c ---- crypto/err/err.c -+++ crypto/err/err.c -@@ -1072,7 +1072,12 @@ void ERR_set_error_data(char *data, int flags) - es->err_data_flags[i] = flags; - } - -+/* Add EFIAPI for UEFI version. */ -+#if defined(OPENSSL_SYS_UEFI) -+void EFIAPI ERR_add_error_data(int num, ...) -+#else - void ERR_add_error_data(int num, ...) -+#endif - { - va_list args; - va_start(args, num); -diff U3 crypto/err/err.h crypto/err/err.h ---- crypto/err/err.h -+++ crypto/err/err.h -@@ -344,7 +344,14 @@ void ERR_print_errors_fp(FILE *fp); - # ifndef OPENSSL_NO_BIO - void ERR_print_errors(BIO *bp); - # endif -+ -+/* Add EFIAPI for UEFI version. */ -+#if defined(OPENSSL_SYS_UEFI) -+void EFIAPI ERR_add_error_data(int num, ...); -+#else - void ERR_add_error_data(int num, ...); -+#endif -+ - void ERR_add_error_vdata(int num, va_list args); - void ERR_load_strings(int lib, ERR_STRING_DATA str[]); - void ERR_unload_strings(int lib, ERR_STRING_DATA str[]); diff --git a/CryptoPkg/Library/OpensslLib/EDKII_openssl-1.0.2e.patch b/CryptoPkg/Library/OpensslLib/EDKII_openssl-1.0.2e.patch new file mode 100644 index 000000000000..e4eaff6eadd2 --- /dev/null +++ b/CryptoPkg/Library/OpensslLib/EDKII_openssl-1.0.2e.patch @@ -0,0 +1,707 @@ +diff U3 crypto/bio/bio.h crypto/bio/bio.h +--- crypto/bio/bio.h Thu Jun 11 21:50:12 2015 ++++ crypto/bio/bio.h Fri Jun 12 11:00:52 2015 +@@ -646,10 +646,10 @@ + int BIO_asn1_get_suffix(BIO *b, asn1_ps_func **psuffix, + asn1_ps_func **psuffix_free); + +-# ifndef OPENSSL_NO_FP_API + BIO_METHOD *BIO_s_file(void); + BIO *BIO_new_file(const char *filename, const char *mode); + BIO *BIO_new_fp(FILE *stream, int close_flag); ++# ifndef OPENSSL_NO_FP_API + # define BIO_s_file_internal BIO_s_file + # endif + BIO *BIO_new(BIO_METHOD *type); +diff U3 crypto/bio/bss_file.c crypto/bio/bss_file.c +--- crypto/bio/bss_file.c Thu Jun 11 21:01:06 2015 ++++ crypto/bio/bss_file.c Fri Jun 12 11:01:28 2015 +@@ -467,6 +467,23 @@ + return (ret); + } + ++# else ++ ++BIO_METHOD *BIO_s_file(void) ++{ ++ return NULL; ++} ++ ++BIO *BIO_new_file(const char *filename, const char *mode) ++{ ++ return NULL; ++} ++ ++BIO *BIO_new_fp(FILE *stream, int close_flag) ++{ ++ return NULL; ++} ++ + # endif /* OPENSSL_NO_STDIO */ + + #endif /* HEADER_BSS_FILE_C */ +diff U3 crypto/dh/dh_pmeth.c crypto/dh/dh_pmeth.c +--- crypto/dh/dh_pmeth.c Thu Jun 11 21:50:12 2015 ++++ crypto/dh/dh_pmeth.c Fri Jun 12 11:08:48 2015 +@@ -449,6 +449,9 @@ + *keylen = ret; + return 1; + } else if (dctx->kdf_type == EVP_PKEY_DH_KDF_X9_42) { ++#ifdef OPENSSL_NO_CMS ++ return 0; ++#else + unsigned char *Z = NULL; + size_t Zlen = 0; + if (!dctx->kdf_outlen || !dctx->kdf_oid) +@@ -478,6 +481,7 @@ + OPENSSL_free(Z); + } + return ret; ++#endif + } + return 1; + } +diff U3 crypto/pem/pem.h crypto/pem/pem.h +--- crypto/pem/pem.h Thu Jun 11 21:50:12 2015 ++++ crypto/pem/pem.h Fri Jun 12 10:58:18 2015 +@@ -324,6 +324,7 @@ + + # define DECLARE_PEM_read_fp(name, type) /**/ + # define DECLARE_PEM_write_fp(name, type) /**/ ++# define DECLARE_PEM_write_fp_const(name, type) /**/ + # define DECLARE_PEM_write_cb_fp(name, type) /**/ + # else + +diff U3 crypto/pkcs7/pk7_smime.c crypto/pkcs7/pk7_smime.c +--- crypto/pkcs7/pk7_smime.c Thu Jun 11 21:01:06 2015 ++++ crypto/pkcs7/pk7_smime.c Fri Jun 12 11:23:38 2015 +@@ -254,7 +254,8 @@ + STACK_OF(PKCS7_SIGNER_INFO) *sinfos; + PKCS7_SIGNER_INFO *si; + X509_STORE_CTX cert_ctx; +- char buf[4096]; ++ char *buf = NULL; ++ int bufsiz; + int i, j = 0, k, ret = 0; + BIO *p7bio = NULL; + BIO *tmpin = NULL, *tmpout = NULL; +@@ -275,12 +276,6 @@ + return 0; + } + +- /* Check for data and content: two sets of data */ +- if (!PKCS7_get_detached(p7) && indata) { +- PKCS7err(PKCS7_F_PKCS7_VERIFY, PKCS7_R_CONTENT_AND_DATA_PRESENT); +- return 0; +- } +- + sinfos = PKCS7_get_signer_info(p7); + + if (!sinfos || !sk_PKCS7_SIGNER_INFO_num(sinfos)) { +@@ -355,9 +350,14 @@ + } else + tmpout = out; + ++ bufsiz = 4096; ++ buf = OPENSSL_malloc(bufsiz); ++ if (buf == NULL) { ++ goto err; ++ } + /* We now have to 'read' from p7bio to calculate digests etc. */ + for (;;) { +- i = BIO_read(p7bio, buf, sizeof(buf)); ++ i = BIO_read(p7bio, buf, bufsiz); + if (i <= 0) + break; + if (tmpout) +@@ -394,6 +394,10 @@ + } + BIO_free_all(p7bio); + sk_X509_free(signers); ++ ++ if (buf != NULL) { ++ OPENSSL_free(buf); ++ } + return ret; + } + +diff U3 crypto/rand/rand_unix.c crypto/rand/rand_unix.c +--- crypto/rand/rand_unix.c Thu Jun 11 21:01:06 2015 ++++ crypto/rand/rand_unix.c Fri Jun 12 10:51:21 2015 +@@ -116,7 +116,7 @@ + #include + #include "rand_lcl.h" + +-#if !(defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_VMS) || defined(OPENSSL_SYS_OS2) || defined(OPENSSL_SYS_VXWORKS) || defined(OPENSSL_SYS_NETWARE)) ++#if !(defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_VMS) || defined(OPENSSL_SYS_OS2) || defined(OPENSSL_SYS_VXWORKS) || defined(OPENSSL_SYS_NETWARE) || defined(OPENSSL_SYS_UEFI)) + + # include + # include +@@ -439,7 +439,7 @@ + * defined(OPENSSL_SYS_VXWORKS) || + * defined(OPENSSL_SYS_NETWARE)) */ + +-#if defined(OPENSSL_SYS_VXWORKS) ++#if defined(OPENSSL_SYS_VXWORKS) || defined(OPENSSL_SYS_UEFI) + int RAND_poll(void) + { + return 0; +diff U3 crypto/rsa/rsa_ameth.c crypto/rsa/rsa_ameth.c +--- crypto/rsa/rsa_ameth.c Thu Jun 11 21:50:12 2015 ++++ crypto/rsa/rsa_ameth.c Fri Jun 12 10:45:38 2015 +@@ -68,10 +68,12 @@ + #endif + #include "asn1_locl.h" + ++#ifndef OPENSSL_NO_CMS + static int rsa_cms_sign(CMS_SignerInfo *si); + static int rsa_cms_verify(CMS_SignerInfo *si); + static int rsa_cms_decrypt(CMS_RecipientInfo *ri); + static int rsa_cms_encrypt(CMS_RecipientInfo *ri); ++#endif + + static int rsa_pub_encode(X509_PUBKEY *pk, const EVP_PKEY *pkey) + { +@@ -665,6 +667,7 @@ + return rv; + } + ++#ifndef OPENSSL_NO_CMS + static int rsa_cms_verify(CMS_SignerInfo *si) + { + int nid, nid2; +@@ -683,6 +686,7 @@ + } + return 0; + } ++#endif + + /* + * Customised RSA item verification routine. This is called when a signature +@@ -705,6 +709,7 @@ + return -1; + } + ++#ifndef OPENSSL_NO_CMS + static int rsa_cms_sign(CMS_SignerInfo *si) + { + int pad_mode = RSA_PKCS1_PADDING; +@@ -729,6 +734,7 @@ + X509_ALGOR_set0(alg, OBJ_nid2obj(NID_rsassaPss), V_ASN1_SEQUENCE, os); + return 1; + } ++#endif + + static int rsa_item_sign(EVP_MD_CTX *ctx, const ASN1_ITEM *it, void *asn, + X509_ALGOR *alg1, X509_ALGOR *alg2, +@@ -785,6 +791,7 @@ + return pss; + } + ++#ifndef OPENSSL_NO_CMS + static int rsa_cms_decrypt(CMS_RecipientInfo *ri) + { + EVP_PKEY_CTX *pkctx; +@@ -857,7 +864,9 @@ + X509_ALGOR_free(maskHash); + return rv; + } ++#endif + ++#ifndef OPENSSL_NO_CMS + static int rsa_cms_encrypt(CMS_RecipientInfo *ri) + { + const EVP_MD *md, *mgf1md; +@@ -920,6 +929,7 @@ + ASN1_STRING_free(os); + return rv; + } ++#endif + + const EVP_PKEY_ASN1_METHOD rsa_asn1_meths[] = { + { +diff U3 crypto/x509/x509_vfy.c crypto/x509/x509_vfy.c +--- crypto/x509/x509_vfy.c Thu Jun 11 21:52:58 2015 ++++ crypto/x509/x509_vfy.c Fri Jun 12 11:29:37 2015 +@@ -940,6 +940,8 @@ + ctx->current_crl = crl; + if (ctx->param->flags & X509_V_FLAG_USE_CHECK_TIME) + ptime = &ctx->param->check_time; ++ else if (ctx->param->flags & X509_V_FLAG_NO_CHECK_TIME) ++ return 1; + else + ptime = NULL; + +@@ -1663,6 +1665,8 @@ + + if (ctx->param->flags & X509_V_FLAG_USE_CHECK_TIME) + ptime = &ctx->param->check_time; ++ else if (ctx->param->flags & X509_V_FLAG_NO_CHECK_TIME) ++ return 1; + else + ptime = NULL; + +diff U3 crypto/x509/x509_vfy.h crypto/x509/x509_vfy.h +--- crypto/x509/x509_vfy.h Thu Jul 09 19:57:16 2015 ++++ crypto/x509/x509_vfy.h Thu Oct 29 14:05:57 2015 +@@ -438,6 +438,8 @@ + * will force the behaviour to match that of previous versions. + */ + # define X509_V_FLAG_NO_ALT_CHAINS 0x100000 ++/* Do not check certificate/CRL validity against current time */ ++# define X509_V_FLAG_NO_CHECK_TIME 0x200000 + + # define X509_VP_FLAG_DEFAULT 0x1 + # define X509_VP_FLAG_OVERWRITE 0x2 +diff U3 crypto/x509v3/ext_dat.h crypto/x509v3/ext_dat.h +--- crypto/x509v3/ext_dat.h Thu Jun 11 21:50:12 2015 ++++ crypto/x509v3/ext_dat.h Fri Jun 12 11:11:03 2015 +@@ -127,8 +127,10 @@ + &v3_idp, + &v3_alt[2], + &v3_freshest_crl, ++#ifndef OPENSSL_SYS_UEFI + &v3_ct_scts[0], + &v3_ct_scts[1], ++#endif + }; + + /* Number of standard extensions */ +diff U3 crypto/crypto.h crypto/crypto.h +--- crypto/crypto.h Thu Jun 11 21:01:06 2015 ++++ crypto/crypto.h Fri Jun 12 11:33:27 2015 +@@ -235,15 +235,15 @@ + # ifndef OPENSSL_NO_LOCKING + # ifndef CRYPTO_w_lock + # define CRYPTO_w_lock(type) \ +- CRYPTO_lock(CRYPTO_LOCK|CRYPTO_WRITE,type,__FILE__,__LINE__) ++ CRYPTO_lock(CRYPTO_LOCK|CRYPTO_WRITE,type,NULL,0) + # define CRYPTO_w_unlock(type) \ +- CRYPTO_lock(CRYPTO_UNLOCK|CRYPTO_WRITE,type,__FILE__,__LINE__) ++ CRYPTO_lock(CRYPTO_UNLOCK|CRYPTO_WRITE,type,NULL,0) + # define CRYPTO_r_lock(type) \ +- CRYPTO_lock(CRYPTO_LOCK|CRYPTO_READ,type,__FILE__,__LINE__) ++ CRYPTO_lock(CRYPTO_LOCK|CRYPTO_READ,type,NULL,0) + # define CRYPTO_r_unlock(type) \ +- CRYPTO_lock(CRYPTO_UNLOCK|CRYPTO_READ,type,__FILE__,__LINE__) ++ CRYPTO_lock(CRYPTO_UNLOCK|CRYPTO_READ,type,NULL,0) + # define CRYPTO_add(addr,amount,type) \ +- CRYPTO_add_lock(addr,amount,type,__FILE__,__LINE__) ++ CRYPTO_add_lock(addr,amount,type,NULL,0) + # endif + # else + # define CRYPTO_w_lock(a) +@@ -378,19 +378,19 @@ + # define MemCheck_off() CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE) + # define is_MemCheck_on() CRYPTO_is_mem_check_on() + +-# define OPENSSL_malloc(num) CRYPTO_malloc((int)num,__FILE__,__LINE__) +-# define OPENSSL_strdup(str) CRYPTO_strdup((str),__FILE__,__LINE__) ++# define OPENSSL_malloc(num) CRYPTO_malloc((int)num,NULL,0) ++# define OPENSSL_strdup(str) CRYPTO_strdup((str),NULL,0) + # define OPENSSL_realloc(addr,num) \ +- CRYPTO_realloc((char *)addr,(int)num,__FILE__,__LINE__) ++ CRYPTO_realloc((char *)addr,(int)num,NULL,0) + # define OPENSSL_realloc_clean(addr,old_num,num) \ +- CRYPTO_realloc_clean(addr,old_num,num,__FILE__,__LINE__) ++ CRYPTO_realloc_clean(addr,old_num,num,NULL,0) + # define OPENSSL_remalloc(addr,num) \ +- CRYPTO_remalloc((char **)addr,(int)num,__FILE__,__LINE__) ++ CRYPTO_remalloc((char **)addr,(int)num,NULL,0) + # define OPENSSL_freeFunc CRYPTO_free + # define OPENSSL_free(addr) CRYPTO_free(addr) + + # define OPENSSL_malloc_locked(num) \ +- CRYPTO_malloc_locked((int)num,__FILE__,__LINE__) ++ CRYPTO_malloc_locked((int)num,NULL,0) + # define OPENSSL_free_locked(addr) CRYPTO_free_locked(addr) + + const char *SSLeay_version(int type); +@@ -545,7 +545,7 @@ + long CRYPTO_get_mem_debug_options(void); + + # define CRYPTO_push_info(info) \ +- CRYPTO_push_info_(info, __FILE__, __LINE__); ++ CRYPTO_push_info_(info, NULL, 0); + int CRYPTO_push_info_(const char *info, const char *file, int line); + int CRYPTO_pop_info(void); + int CRYPTO_remove_all_info(void); +@@ -588,7 +588,7 @@ + + /* die if we have to */ + void OpenSSLDie(const char *file, int line, const char *assertion); +-# define OPENSSL_assert(e) (void)((e) ? 0 : (OpenSSLDie(__FILE__, __LINE__, #e),1)) ++# define OPENSSL_assert(e) (void)((e) ? 0 : (OpenSSLDie(NULL, 0, #e),1)) + + unsigned long *OPENSSL_ia32cap_loc(void); + # define OPENSSL_ia32cap (*(OPENSSL_ia32cap_loc())) +@@ -605,14 +605,14 @@ + # define fips_md_init_ctx(alg, cx) \ + int alg##_Init(cx##_CTX *c) \ + { \ +- if (FIPS_mode()) OpenSSLDie(__FILE__, __LINE__, \ ++ if (FIPS_mode()) OpenSSLDie(NULL, 0, \ + "Low level API call to digest " #alg " forbidden in FIPS mode!"); \ + return private_##alg##_Init(c); \ + } \ + int private_##alg##_Init(cx##_CTX *c) + + # define fips_cipher_abort(alg) \ +- if (FIPS_mode()) OpenSSLDie(__FILE__, __LINE__, \ ++ if (FIPS_mode()) OpenSSLDie(NULL, 0, \ + "Low level API call to cipher " #alg " forbidden in FIPS mode!") + + # else +diff U3 crypto/opensslconf.h crypto/opensslconf.h +--- crypto/opensslconf.h Thu Jun 11 21:55:38 2015 ++++ crypto/opensslconf.h Fri Jun 12 10:28:27 2015 +@@ -5,15 +5,72 @@ + extern "C" { + #endif + /* OpenSSL was configured with the following options: */ ++#ifndef OPENSSL_SYSNAME_UEFI ++# define OPENSSL_SYSNAME_UEFI ++#endif + #ifndef OPENSSL_DOING_MAKEDEPEND + + ++#ifndef OPENSSL_NO_BF ++# define OPENSSL_NO_BF ++#endif ++#ifndef OPENSSL_NO_CAMELLIA ++# define OPENSSL_NO_CAMELLIA ++#endif ++#ifndef OPENSSL_NO_CAPIENG ++# define OPENSSL_NO_CAPIENG ++#endif ++#ifndef OPENSSL_NO_CAST ++# define OPENSSL_NO_CAST ++#endif ++#ifndef OPENSSL_NO_CMS ++# define OPENSSL_NO_CMS ++#endif ++#ifndef OPENSSL_NO_DEPRECATED ++# define OPENSSL_NO_DEPRECATED ++#endif ++#ifndef OPENSSL_NO_DGRAM ++# define OPENSSL_NO_DGRAM ++#endif ++#ifndef OPENSSL_NO_DSA ++# define OPENSSL_NO_DSA ++#endif ++#ifndef OPENSSL_NO_DYNAMIC_ENGINE ++# define OPENSSL_NO_DYNAMIC_ENGINE ++#endif ++#ifndef OPENSSL_NO_EC ++# define OPENSSL_NO_EC ++#endif + #ifndef OPENSSL_NO_EC_NISTP_64_GCC_128 + # define OPENSSL_NO_EC_NISTP_64_GCC_128 + #endif ++#ifndef OPENSSL_NO_ECDH ++# define OPENSSL_NO_ECDH ++#endif ++#ifndef OPENSSL_NO_ECDSA ++# define OPENSSL_NO_ECDSA ++#endif ++#ifndef OPENSSL_NO_ENGINE ++# define OPENSSL_NO_ENGINE ++#endif ++#ifndef OPENSSL_NO_ENGINES ++# define OPENSSL_NO_ENGINES ++#endif ++#ifndef OPENSSL_NO_FILENAMES ++# define OPENSSL_NO_FILENAMES ++#endif ++#ifndef OPENSSL_NO_FP_API ++# define OPENSSL_NO_FP_API ++#endif + #ifndef OPENSSL_NO_GMP + # define OPENSSL_NO_GMP + #endif ++#ifndef OPENSSL_NO_GOST ++# define OPENSSL_NO_GOST ++#endif ++#ifndef OPENSSL_NO_IDEA ++# define OPENSSL_NO_IDEA ++#endif + #ifndef OPENSSL_NO_JPAKE + # define OPENSSL_NO_JPAKE + #endif +@@ -23,30 +80,90 @@ + #ifndef OPENSSL_NO_LIBUNBOUND + # define OPENSSL_NO_LIBUNBOUND + #endif ++#ifndef OPENSSL_NO_LOCKING ++# define OPENSSL_NO_LOCKING ++#endif + #ifndef OPENSSL_NO_MD2 + # define OPENSSL_NO_MD2 + #endif ++#ifndef OPENSSL_NO_MDC2 ++# define OPENSSL_NO_MDC2 ++#endif ++#ifndef OPENSSL_NO_POSIX_IO ++# define OPENSSL_NO_POSIX_IO ++#endif ++#ifndef OPENSSL_NO_RC2 ++# define OPENSSL_NO_RC2 ++#endif + #ifndef OPENSSL_NO_RC5 + # define OPENSSL_NO_RC5 + #endif ++#ifndef OPENSSL_NO_RCS ++# define OPENSSL_NO_RCS ++#endif + #ifndef OPENSSL_NO_RFC3779 + # define OPENSSL_NO_RFC3779 + #endif ++#ifndef OPENSSL_NO_RIPEMD ++# define OPENSSL_NO_RIPEMD ++#endif ++#ifndef OPENSSL_NO_SCRYPT ++# define OPENSSL_NO_SCRYPT ++#endif ++#ifndef OPENSSL_NO_SCT ++# define OPENSSL_NO_SCT ++#endif + #ifndef OPENSSL_NO_SCTP + # define OPENSSL_NO_SCTP + #endif ++#ifndef OPENSSL_NO_SEED ++# define OPENSSL_NO_SEED ++#endif ++#ifndef OPENSSL_NO_SHA0 ++# define OPENSSL_NO_SHA0 ++#endif ++#ifndef OPENSSL_NO_SOCK ++# define OPENSSL_NO_SOCK ++#endif ++#ifndef OPENSSL_NO_SRP ++# define OPENSSL_NO_SRP ++#endif + #ifndef OPENSSL_NO_SSL_TRACE + # define OPENSSL_NO_SSL_TRACE + #endif ++#ifndef OPENSSL_NO_SSL2 ++# define OPENSSL_NO_SSL2 ++#endif ++#ifndef OPENSSL_NO_SSL3 ++# define OPENSSL_NO_SSL3 ++#endif ++#ifndef OPENSSL_NO_STDIO ++# define OPENSSL_NO_STDIO ++#endif + #ifndef OPENSSL_NO_STORE + # define OPENSSL_NO_STORE + #endif ++#ifndef OPENSSL_NO_UI ++# define OPENSSL_NO_UI ++#endif + #ifndef OPENSSL_NO_UNIT_TEST + # define OPENSSL_NO_UNIT_TEST + #endif ++#ifndef OPENSSL_NO_WHIRLPOOL ++# define OPENSSL_NO_WHIRLPOOL ++#endif + + #endif /* OPENSSL_DOING_MAKEDEPEND */ + ++#ifndef OPENSSL_NO_ASM ++# define OPENSSL_NO_ASM ++#endif ++#ifndef OPENSSL_NO_ERR ++# define OPENSSL_NO_ERR ++#endif ++#ifndef OPENSSL_NO_HW ++# define OPENSSL_NO_HW ++#endif + #ifndef OPENSSL_NO_DYNAMIC_ENGINE + # define OPENSSL_NO_DYNAMIC_ENGINE + #endif +@@ -56,12 +173,66 @@ + who haven't had the time to do the appropriate changes in their + applications. */ + #ifdef OPENSSL_ALGORITHM_DEFINES ++# if defined(OPENSSL_NO_BF) && !defined(NO_BF) ++# define NO_BF ++# endif ++# if defined(OPENSSL_NO_CAMELLIA) && !defined(NO_CAMELLIA) ++# define NO_CAMELLIA ++# endif ++# if defined(OPENSSL_NO_CAPIENG) && !defined(NO_CAPIENG) ++# define NO_CAPIENG ++# endif ++# if defined(OPENSSL_NO_CAST) && !defined(NO_CAST) ++# define NO_CAST ++# endif ++# if defined(OPENSSL_NO_CMS) && !defined(NO_CMS) ++# define NO_CMS ++# endif ++# if defined(OPENSSL_NO_DEPRECATED) && !defined(NO_DEPRECATED) ++# define NO_DEPRECATED ++# endif ++# if defined(OPENSSL_NO_DGRAM) && !defined(NO_DGRAM) ++# define NO_DGRAM ++# endif ++# if defined(OPENSSL_NO_DSA) && !defined(NO_DSA) ++# define NO_DSA ++# endif ++# if defined(OPENSSL_NO_DYNAMIC_ENGINE) && !defined(NO_DYNAMIC_ENGINE) ++# define NO_DYNAMIC_ENGINE ++# endif ++# if defined(OPENSSL_NO_EC) && !defined(NO_EC) ++# define NO_EC ++# endif + # if defined(OPENSSL_NO_EC_NISTP_64_GCC_128) && !defined(NO_EC_NISTP_64_GCC_128) + # define NO_EC_NISTP_64_GCC_128 + # endif ++# if defined(OPENSSL_NO_ECDH) && !defined(NO_ECDH) ++# define NO_ECDH ++# endif ++# if defined(OPENSSL_NO_ECDSA) && !defined(NO_ECDSA) ++# define NO_ECDSA ++# endif ++# if defined(OPENSSL_NO_ENGINE) && !defined(NO_ENGINE) ++# define NO_ENGINE ++# endif ++# if defined(OPENSSL_NO_ENGINES) && !defined(NO_ENGINES) ++# define NO_ENGINES ++# endif ++# if defined(OPENSSL_NO_FILENAMES) && !defined(NO_FILENAMES) ++# define NO_FILENAMES ++# endif ++# if defined(OPENSSL_NO_FP_API) && !defined(NO_FP_API) ++# define NO_FP_API ++# endif + # if defined(OPENSSL_NO_GMP) && !defined(NO_GMP) + # define NO_GMP + # endif ++# if defined(OPENSSL_NO_GOST) && !defined(NO_GOST) ++# define NO_GOST ++# endif ++# if defined(OPENSSL_NO_IDEA) && !defined(NO_IDEA) ++# define NO_IDEA ++# endif + # if defined(OPENSSL_NO_JPAKE) && !defined(NO_JPAKE) + # define NO_JPAKE + # endif +@@ -71,27 +242,78 @@ + # if defined(OPENSSL_NO_LIBUNBOUND) && !defined(NO_LIBUNBOUND) + # define NO_LIBUNBOUND + # endif ++# if defined(OPENSSL_NO_LOCKING) && !defined(NO_LOCKING) ++# define NO_LOCKING ++# endif + # if defined(OPENSSL_NO_MD2) && !defined(NO_MD2) + # define NO_MD2 + # endif ++# if defined(OPENSSL_NO_MDC2) && !defined(NO_MDC2) ++# define NO_MDC2 ++# endif ++# if defined(OPENSSL_NO_POSIX_IO) && !defined(NO_POSIX_IO) ++# define NO_POSIX_IO ++# endif ++# if defined(OPENSSL_NO_RC2) && !defined(NO_RC2) ++# define NO_RC2 ++# endif + # if defined(OPENSSL_NO_RC5) && !defined(NO_RC5) + # define NO_RC5 + # endif ++# if defined(OPENSSL_NO_RCS) && !defined(NO_RCS) ++# define NO_RCS ++# endif + # if defined(OPENSSL_NO_RFC3779) && !defined(NO_RFC3779) + # define NO_RFC3779 + # endif ++# if defined(OPENSSL_NO_RIPEMD) && !defined(NO_RIPEMD) ++# define NO_RIPEMD ++# endif ++# if defined(OPENSSL_NO_SCRYPT) && !defined(NO_SCRYPT) ++# define NO_SCRYPT ++# endif ++# if defined(OPENSSL_NO_SCT) && !defined(NO_SCT) ++# define NO_SCT ++# endif + # if defined(OPENSSL_NO_SCTP) && !defined(NO_SCTP) + # define NO_SCTP + # endif ++# if defined(OPENSSL_NO_SEED) && !defined(NO_SEED) ++# define NO_SEED ++# endif ++# if defined(OPENSSL_NO_SHA0) && !defined(NO_SHA0) ++# define NO_SHA0 ++# endif ++# if defined(OPENSSL_NO_SOCK) && !defined(NO_SOCK) ++# define NO_SOCK ++# endif ++# if defined(OPENSSL_NO_SRP) && !defined(NO_SRP) ++# define NO_SRP ++# endif + # if defined(OPENSSL_NO_SSL_TRACE) && !defined(NO_SSL_TRACE) + # define NO_SSL_TRACE + # endif ++# if defined(OPENSSL_NO_SSL2) && !defined(NO_SSL2) ++# define NO_SSL2 ++# endif ++# if defined(OPENSSL_NO_SSL3) && !defined(NO_SSL3) ++# define NO_SSL3 ++# endif ++# if defined(OPENSSL_NO_STDIO) && !defined(NO_STDIO) ++# define NO_STDIO ++# endif + # if defined(OPENSSL_NO_STORE) && !defined(NO_STORE) + # define NO_STORE + # endif ++# if defined(OPENSSL_NO_UI) && !defined(NO_UI) ++# define NO_UI ++# endif + # if defined(OPENSSL_NO_UNIT_TEST) && !defined(NO_UNIT_TEST) + # define NO_UNIT_TEST + # endif ++# if defined(OPENSSL_NO_WHIRLPOOL) && !defined(NO_WHIRLPOOL) ++# define NO_WHIRLPOOL ++# endif + #endif + + /* crypto/opensslconf.h.in */ +@@ -152,7 +374,7 @@ + #endif + #endif + +-#if defined(HEADER_BN_H) && !defined(CONFIG_HEADER_BN_H) ++#if defined(HEADER_BN_H) && !defined(CONFIG_HEADER_BN_H) && !defined(OPENSSL_SYSNAME_UEFI) + #define CONFIG_HEADER_BN_H + #undef BN_LLONG + +diff U3 e_os.h e_os.h +--- e_os.h Thu Jul 09 19:57:16 2015 ++++ e_os.h Thu Oct 29 16:54:10 2015 +@@ -136,7 +136,7 @@ + # define MSDOS + # endif + +-# if defined(MSDOS) && !defined(GETPID_IS_MEANINGLESS) ++# if (defined(MSDOS) || defined(OPENSSL_SYS_UEFI)) && !defined(GETPID_IS_MEANINGLESS) + # define GETPID_IS_MEANINGLESS + # endif + +diff U3 e_os2.h e_os2.h +--- e_os2.h Thu Jul 09 19:57:16 2015 ++++ e_os2.h Thu Oct 29 15:08:19 2015 +@@ -97,7 +97,14 @@ + * For 32 bit environment, there seems to be the CygWin environment and then + * all the others that try to do the same thing Microsoft does... + */ +-# if defined(OPENSSL_SYSNAME_UWIN) ++/* ++ * UEFI lives here because it might be built with a Microsoft toolchain and ++ * we need to avoid the false positive match on Windows. ++ */ ++# if defined(OPENSSL_SYSNAME_UEFI) ++# undef OPENSSL_SYS_UNIX ++# define OPENSSL_SYS_UEFI ++# elif defined(OPENSSL_SYSNAME_UWIN) + # undef OPENSSL_SYS_UNIX + # define OPENSSL_SYS_WIN32_UWIN + # else diff --git a/CryptoPkg/Library/OpensslLib/Install.cmd b/CryptoPkg/Library/OpensslLib/Install.cmd index ef0a4bdcebc9..b9b6fc6f7094 100755 --- a/CryptoPkg/Library/OpensslLib/Install.cmd +++ b/CryptoPkg/Library/OpensslLib/Install.cmd @@ -1,4 +1,4 @@ -cd openssl-1.0.2d +cd openssl-1.0.2e copy e_os2.h ..\..\..\Include\openssl copy crypto\crypto.h ..\..\..\Include\openssl copy crypto\opensslv.h ..\..\..\Include\openssl diff --git a/CryptoPkg/Library/OpensslLib/Install.sh b/CryptoPkg/Library/OpensslLib/Install.sh index 877e775b81af..82a7f409f105 100755 --- a/CryptoPkg/Library/OpensslLib/Install.sh +++ b/CryptoPkg/Library/OpensslLib/Install.sh @@ -1,79 +1,79 @@ -#!/bin/sh - -cd openssl-1.0.2d -cp e_os2.h ../../../Include/openssl -cp crypto/crypto.h ../../../Include/openssl -cp crypto/opensslv.h ../../../Include/openssl -cp crypto/opensslconf.h ../../../Include/openssl -cp crypto/ebcdic.h ../../../Include/openssl -cp crypto/symhacks.h ../../../Include/openssl -cp crypto/ossl_typ.h ../../../Include/openssl -cp crypto/objects/objects.h ../../../Include/openssl -cp crypto/objects/obj_mac.h ../../../Include/openssl -cp crypto/md4/md4.h ../../../Include/openssl -cp crypto/md5/md5.h ../../../Include/openssl -cp crypto/sha/sha.h ../../../Include/openssl -cp crypto/mdc2/mdc2.h ../../../Include/openssl -cp crypto/hmac/hmac.h ../../../Include/openssl -cp crypto/ripemd/ripemd.h ../../../Include/openssl -cp crypto/whrlpool/whrlpool.h ../../../Include/openssl -cp crypto/des/des.h ../../../Include/openssl -cp crypto/des/des_old.h ../../../Include/openssl -cp crypto/aes/aes.h ../../../Include/openssl -cp crypto/rc2/rc2.h ../../../Include/openssl -cp crypto/rc4/rc4.h ../../../Include/openssl -cp crypto/idea/idea.h ../../../Include/openssl -cp crypto/bf/blowfish.h ../../../Include/openssl -cp crypto/cast/cast.h ../../../Include/openssl -cp crypto/camellia/camellia.h ../../../Include/openssl -cp crypto/seed/seed.h ../../../Include/openssl -cp crypto/modes/modes.h ../../../Include/openssl -cp crypto/bn/bn.h ../../../Include/openssl -cp crypto/ec/ec.h ../../../Include/openssl -cp crypto/rsa/rsa.h ../../../Include/openssl -cp crypto/dsa/dsa.h ../../../Include/openssl -cp crypto/ecdsa/ecdsa.h ../../../Include/openssl -cp crypto/dh/dh.h ../../../Include/openssl -cp crypto/ecdh/ecdh.h ../../../Include/openssl -cp crypto/dso/dso.h ../../../Include/openssl -cp crypto/engine/engine.h ../../../Include/openssl -cp crypto/buffer/buffer.h ../../../Include/openssl -cp crypto/bio/bio.h ../../../Include/openssl -cp crypto/stack/stack.h ../../../Include/openssl -cp crypto/stack/safestack.h ../../../Include/openssl -cp crypto/lhash/lhash.h ../../../Include/openssl -cp crypto/rand/rand.h ../../../Include/openssl -cp crypto/err/err.h ../../../Include/openssl -cp crypto/evp/evp.h ../../../Include/openssl -cp crypto/asn1/asn1.h ../../../Include/openssl -cp crypto/asn1/asn1_mac.h ../../../Include/openssl -cp crypto/asn1/asn1t.h ../../../Include/openssl -cp crypto/pem/pem.h ../../../Include/openssl -cp crypto/pem/pem2.h ../../../Include/openssl -cp crypto/x509/x509.h ../../../Include/openssl -cp crypto/x509/x509_vfy.h ../../../Include/openssl -cp crypto/x509v3/x509v3.h ../../../Include/openssl -cp crypto/conf/conf.h ../../../Include/openssl -cp crypto/conf/conf_api.h ../../../Include/openssl -cp crypto/txt_db/txt_db.h ../../../Include/openssl -cp crypto/pkcs7/pkcs7.h ../../../Include/openssl -cp crypto/pkcs12/pkcs12.h ../../../Include/openssl -cp crypto/comp/comp.h ../../../Include/openssl -cp crypto/ocsp/ocsp.h ../../../Include/openssl -cp crypto/ui/ui.h ../../../Include/openssl -cp crypto/ui/ui_compat.h ../../../Include/openssl -cp crypto/krb5/krb5_asn.h ../../../Include/openssl -cp crypto/cms/cms.h ../../../Include/openssl -cp crypto/pqueue/pqueue.h ../../../Include/openssl -cp crypto/ts/ts.h ../../../Include/openssl -cp crypto/srp/srp.h ../../../Include/openssl -cp crypto/cmac/cmac.h ../../../Include/openssl -cp ssl/ssl.h ../../../Include/openssl -cp ssl/ssl2.h ../../../Include/openssl -cp ssl/ssl3.h ../../../Include/openssl -cp ssl/ssl23.h ../../../Include/openssl -cp ssl/tls1.h ../../../Include/openssl -cp ssl/dtls1.h ../../../Include/openssl -cp ssl/kssl.h ../../../Include/openssl -cp ssl/srtp.h ../../../Include/openssl -cd .. +#!/bin/sh + +cd openssl-1.0.2e +cp e_os2.h ../../../Include/openssl +cp crypto/crypto.h ../../../Include/openssl +cp crypto/opensslv.h ../../../Include/openssl +cp crypto/opensslconf.h ../../../Include/openssl +cp crypto/ebcdic.h ../../../Include/openssl +cp crypto/symhacks.h ../../../Include/openssl +cp crypto/ossl_typ.h ../../../Include/openssl +cp crypto/objects/objects.h ../../../Include/openssl +cp crypto/objects/obj_mac.h ../../../Include/openssl +cp crypto/md4/md4.h ../../../Include/openssl +cp crypto/md5/md5.h ../../../Include/openssl +cp crypto/sha/sha.h ../../../Include/openssl +cp crypto/mdc2/mdc2.h ../../../Include/openssl +cp crypto/hmac/hmac.h ../../../Include/openssl +cp crypto/ripemd/ripemd.h ../../../Include/openssl +cp crypto/whrlpool/whrlpool.h ../../../Include/openssl +cp crypto/des/des.h ../../../Include/openssl +cp crypto/des/des_old.h ../../../Include/openssl +cp crypto/aes/aes.h ../../../Include/openssl +cp crypto/rc2/rc2.h ../../../Include/openssl +cp crypto/rc4/rc4.h ../../../Include/openssl +cp crypto/idea/idea.h ../../../Include/openssl +cp crypto/bf/blowfish.h ../../../Include/openssl +cp crypto/cast/cast.h ../../../Include/openssl +cp crypto/camellia/camellia.h ../../../Include/openssl +cp crypto/seed/seed.h ../../../Include/openssl +cp crypto/modes/modes.h ../../../Include/openssl +cp crypto/bn/bn.h ../../../Include/openssl +cp crypto/ec/ec.h ../../../Include/openssl +cp crypto/rsa/rsa.h ../../../Include/openssl +cp crypto/dsa/dsa.h ../../../Include/openssl +cp crypto/ecdsa/ecdsa.h ../../../Include/openssl +cp crypto/dh/dh.h ../../../Include/openssl +cp crypto/ecdh/ecdh.h ../../../Include/openssl +cp crypto/dso/dso.h ../../../Include/openssl +cp crypto/engine/engine.h ../../../Include/openssl +cp crypto/buffer/buffer.h ../../../Include/openssl +cp crypto/bio/bio.h ../../../Include/openssl +cp crypto/stack/stack.h ../../../Include/openssl +cp crypto/stack/safestack.h ../../../Include/openssl +cp crypto/lhash/lhash.h ../../../Include/openssl +cp crypto/rand/rand.h ../../../Include/openssl +cp crypto/err/err.h ../../../Include/openssl +cp crypto/evp/evp.h ../../../Include/openssl +cp crypto/asn1/asn1.h ../../../Include/openssl +cp crypto/asn1/asn1_mac.h ../../../Include/openssl +cp crypto/asn1/asn1t.h ../../../Include/openssl +cp crypto/pem/pem.h ../../../Include/openssl +cp crypto/pem/pem2.h ../../../Include/openssl +cp crypto/x509/x509.h ../../../Include/openssl +cp crypto/x509/x509_vfy.h ../../../Include/openssl +cp crypto/x509v3/x509v3.h ../../../Include/openssl +cp crypto/conf/conf.h ../../../Include/openssl +cp crypto/conf/conf_api.h ../../../Include/openssl +cp crypto/txt_db/txt_db.h ../../../Include/openssl +cp crypto/pkcs7/pkcs7.h ../../../Include/openssl +cp crypto/pkcs12/pkcs12.h ../../../Include/openssl +cp crypto/comp/comp.h ../../../Include/openssl +cp crypto/ocsp/ocsp.h ../../../Include/openssl +cp crypto/ui/ui.h ../../../Include/openssl +cp crypto/ui/ui_compat.h ../../../Include/openssl +cp crypto/krb5/krb5_asn.h ../../../Include/openssl +cp crypto/cms/cms.h ../../../Include/openssl +cp crypto/pqueue/pqueue.h ../../../Include/openssl +cp crypto/ts/ts.h ../../../Include/openssl +cp crypto/srp/srp.h ../../../Include/openssl +cp crypto/cmac/cmac.h ../../../Include/openssl +cp ssl/ssl.h ../../../Include/openssl +cp ssl/ssl2.h ../../../Include/openssl +cp ssl/ssl3.h ../../../Include/openssl +cp ssl/ssl23.h ../../../Include/openssl +cp ssl/tls1.h ../../../Include/openssl +cp ssl/dtls1.h ../../../Include/openssl +cp ssl/kssl.h ../../../Include/openssl +cp ssl/srtp.h ../../../Include/openssl +cd .. diff --git a/CryptoPkg/Library/OpensslLib/OpensslLib.inf b/CryptoPkg/Library/OpensslLib/OpensslLib.inf index aaf0a2982e10..1b7eb07fab90 100644 --- a/CryptoPkg/Library/OpensslLib/OpensslLib.inf +++ b/CryptoPkg/Library/OpensslLib/OpensslLib.inf @@ -20,7 +20,7 @@ MODULE_TYPE = BASE VERSION_STRING = 1.0 LIBRARY_CLASS = OpensslLib - DEFINE OPENSSL_PATH = openssl-1.0.2d + DEFINE OPENSSL_PATH = openssl-1.0.2e DEFINE OPENSSL_FLAGS = -DOPENSSL_SYSNAME_UWIN -DOPENSSL_SYS_UEFI -DL_ENDIAN -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE -DOPENSSL_NO_CAMELLIA -DOPENSSL_NO_SEED -DOPENSSL_NO_RC5 -DOPENSSL_NO_MDC2 -DOPENSSL_NO_SOCK -DOPENSSL_NO_CMS -DOPENSSL_NO_JPAKE -DOPENSSL_NO_CAPIENG -DOPENSSL_NO_ERR -DOPENSSL_NO_KRB5 -DOPENSSL_NO_DYNAMIC_ENGINE -DGETPID_IS_MEANINGLESS -DOPENSSL_NO_STDIO -DOPENSSL_NO_POSIX_IO -DOPENSSL_NO_FP_API -DOPENSSL_NO_DGRAM -DOPENSSL_NO_ASM DEFINE OPENSSL_EXFLAGS = -DOPENSSL_SMALL_FOOTPRINT -DOPENSSL_NO_SHA0 -DOPENSSL_NO_LHASH -DOPENSSL_NO_HW -DOPENSSL_NO_OCSP -DOPENSSL_NO_LOCKING -DOPENSSL_NO_DEPRECATED -DOPENSSL_NO_RIPEMD -DOPENSSL_NO_RC2 -DOPENSSL_NO_IDEA -DOPENSSL_NO_BF -DOPENSSL_NO_CAST -DOPENSSL_NO_WHIRLPOOL -DOPENSSL_NO_DSA -DOPENSSL_NO_EC -DOPENSSL_NO_ECDH -DOPENSSL_NO_ECDSA -DOPENSSL_NO_SRP -DOPENSSL_NO_ENGINE diff --git a/CryptoPkg/Library/OpensslLib/Patch-HOWTO.txt b/CryptoPkg/Library/OpensslLib/Patch-HOWTO.txt index 59e74ee9b0d9..f575d7147bdf 100644 --- a/CryptoPkg/Library/OpensslLib/Patch-HOWTO.txt +++ b/CryptoPkg/Library/OpensslLib/Patch-HOWTO.txt @@ -17,36 +17,36 @@ cryptography. This patch will enable openssl building under UEFI environment. ================================================================================ OpenSSL-Version ================================================================================ - Current supported OpenSSL version for UEFI Crypto Library is 1.0.2d. - http://www.openssl.org/source/openssl-1.0.2d.tar.gz + Current supported OpenSSL version for UEFI Crypto Library is 1.0.2e. + http://www.openssl.org/source/openssl-1.0.2e.tar.gz ================================================================================ HOW to Install Openssl for UEFI Building ================================================================================ -1. Download OpenSSL 1.0.2d from official website: - http://www.openssl.org/source/openssl-1.0.2d.tar.gz +1. Download OpenSSL 1.0.2e from official website: + http://www.openssl.org/source/openssl-1.0.2e.tar.gz - NOTE: Some web browsers may rename the downloaded TAR file to openssl-1.0.2d.tar.tar. - When you do the download, rename the "openssl-1.0.2d.tar.tar" to - "openssl-1.0.2d.tar.gz" or rename the local downloaded file with ".tar.tar" + NOTE: Some web browsers may rename the downloaded TAR file to openssl-1.0.2e.tar.tar. + When you do the download, rename the "openssl-1.0.2e.tar.tar" to + "openssl-1.0.2e.tar.gz" or rename the local downloaded file with ".tar.tar" extension to ".tar.gz". -2. Extract TAR into CryptoPkg/Library/OpenSslLib/openssl-1.0.2d +2. Extract TAR into CryptoPkg/Library/OpenSslLib/openssl-1.0.2e NOTE: If you use WinZip to unpack the openssl source in Windows, please uncheck the WinZip smart CR/LF conversion option (WINZIP: Options --> Configuration --> Miscellaneous --> "TAR file smart CR/LF conversion"). -3. Apply this patch: EDKII_openssl-1.0.2d.patch, and make installation +3. Apply this patch: EDKII_openssl-1.0.2e.patch, and make installation For Windows Environment: ------------------------ 1) Make sure the patch utility has been installed in your machine. Install Cygwin or get the patch utility binary from http://gnuwin32.sourceforge.net/packages/patch.htm - 2) cd $(WORKSPACE)\CryptoPkg\Library\OpensslLib\openssl-1.0.2d - 3) patch -p0 -i ..\EDKII_openssl-1.0.2d.patch + 2) cd $(WORKSPACE)\CryptoPkg\Library\OpensslLib\openssl-1.0.2e + 3) patch -p0 -i ..\EDKII_openssl-1.0.2e.patch 4) cd .. 5) Install.cmd @@ -54,8 +54,8 @@ cryptography. This patch will enable openssl building under UEFI environment. ----------------------- 1) Make sure the patch utility has been installed in your machine. Patch utility is available from http://directory.fsf.org/project/patch/ - 2) cd $(WORKSPACE)/CryptoPkg/Library/OpensslLib/openssl-1.0.2d - 3) patch -p0 -i ../EDKII_openssl-1.0.2d.patch + 2) cd $(WORKSPACE)/CryptoPkg/Library/OpensslLib/openssl-1.0.2e + 3) patch -p0 -i ../EDKII_openssl-1.0.2e.patch 4) cd .. 5) ./Install.sh From 3163594ee114acff704c40fff4cfb007a55b9dac Mon Sep 17 00:00:00 2001 From: Jeff Fan Date: Fri, 11 Dec 2015 08:34:51 +0000 Subject: [PATCH 240/525] UefiCpuPkg/UefiCpuPkg.uni: Fix one typo '.' should be '_'. (Sync patch r19226 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan Reviewed-by: Shumin Qiu git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19227 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/UefiCpuPkg.uni | Bin 22498 -> 22498 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/UefiCpuPkg/UefiCpuPkg.uni b/UefiCpuPkg/UefiCpuPkg.uni index 542b1cd961caa039fb3bee7125f299a86f67ea72..4011cfd1816b133ea82e64335f35332c2fc7e656 100644 GIT binary patch delta 17 ZcmaE~p7GIo#tpB+CLa*xoBSi}6#!Iy3043A delta 15 XcmaE~p7GIo#tpB+81*K<4*L!OK#2$s From 7f58594c3263afcce15bcd1d784590a4f0083646 Mon Sep 17 00:00:00 2001 From: Michael Kinney Date: Tue, 15 Dec 2015 05:59:34 +0000 Subject: [PATCH 241/525] MdeModulePkg/PciSioSerialDxe: Fix compiler warnings Add missing braces in module global mControllerDevicePathTemplate. Initialize ControllerNumber and ContainsControllerNode in SerialControllerDriverStart() to address warning for potential use before initialization warning. Move initialization of local SerialIo earlier in SerialControllerDriverStart() to address warning for potential use before initialization warning. (Sync patch r19232 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Michael Kinney Reviewed-by: Feng Tian git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19269 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.c b/MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.c index 86e75a43f719..7fc053578d7d 100644 --- a/MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.c +++ b/MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.c @@ -31,8 +31,10 @@ CONTROLLER_DEVICE_PATH mControllerDevicePathTemplate = { { HARDWARE_DEVICE_PATH, HW_CONTROLLER_DP, - sizeof (CONTROLLER_DEVICE_PATH), - 0 + { + (UINT8) (sizeof (CONTROLLER_DEVICE_PATH)), + (UINT8) ((sizeof (CONTROLLER_DEVICE_PATH)) >> 8) + } }, 0 }; @@ -858,7 +860,8 @@ SerialControllerDriverStart ( return EFI_SUCCESS; } - + ControllerNumber = 0; + ContainsControllerNode = FALSE; SerialDevices = GetChildSerialDevices (Controller, IoProtocolGuid, &SerialDeviceCount); // // If the SerialIo instance specified by RemainingDevicePath is already created, @@ -870,6 +873,7 @@ SerialControllerDriverStart ( if ((!SerialDevices[Index]->ContainsControllerNode && !ContainsControllerNode) || (SerialDevices[Index]->ContainsControllerNode && ContainsControllerNode && SerialDevices[Index]->Instance == ControllerNumber) ) { + SerialIo = &SerialDevices[Index]->SerialIo; Status = EFI_INVALID_PARAMETER; // // Pass NULL ActualBaudRate to VerifyUartParameters to disallow baudrate degrade. @@ -877,7 +881,6 @@ SerialControllerDriverStart ( // if (VerifyUartParameters (SerialDevices[Index]->ClockRate, Uart->BaudRate, Uart->DataBits, (EFI_PARITY_TYPE) Uart->Parity, (EFI_STOP_BITS_TYPE) Uart->StopBits, NULL, NULL)) { - SerialIo = &SerialDevices[Index]->SerialIo; Status = SerialIo->SetAttributes ( SerialIo, Uart->BaudRate, From 623f8330bcc1aa12947c799cd8129075f52b39e0 Mon Sep 17 00:00:00 2001 From: Hao Wu Date: Tue, 15 Dec 2015 06:00:10 +0000 Subject: [PATCH 242/525] MdeModulePkg UfsPassThru: ASSERT if params are NULL in SignalCallerEvent In function SignalCallerEvent(), 'Private' and 'TransReq' are dereferenced before NULL checking. Since the function assumes that both 'Private' and 'TransReq' passed in are not NULL pointer, this commit will add an ASSERT to make sure the above assumption is satisfied. (Sync patch r19266 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Hao Wu Reviewed-by: Feng Tian git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19270 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruHci.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruHci.c b/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruHci.c index 4fbe199390f4..81653af5a8ad 100644 --- a/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruHci.c +++ b/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruHci.c @@ -2191,6 +2191,8 @@ SignalCallerEvent ( EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc; EFI_EVENT CallerEvent; + ASSERT ((Private != NULL) && (TransReq != NULL)); + UfsHc = Private->UfsHostController; CallerEvent = TransReq->CallerEvent; @@ -2214,9 +2216,8 @@ SignalCallerEvent ( TransReq->CmdDescHost ); } - if (TransReq != NULL) { - FreePool (TransReq); - } + + FreePool (TransReq); gBS->SignalEvent (CallerEvent); return; From dcf73c32bf8ea9307c148f672fcef0dbcb05aff6 Mon Sep 17 00:00:00 2001 From: Masamitsu MURASE Date: Tue, 15 Dec 2015 13:19:06 +0000 Subject: [PATCH 243/525] MdePkg: Add UefiDebugLibDebugPortProtocol to output logs via DebugPort. UefiDebugLibDebugPortProtocol is an implementation of DebugLib. It calls EFI_DEBUGPORT_PROTOCOL.Write in DebugPrint and DebugAssert. (Sync patch r18414 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Masamitsu MURASE Reviewed-by: Liming Gao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19276 6f19259b-4bc3-4df7-8a09-765794883524 --- .../UefiDebugLibDebugPortProtocol/DebugLib.c | 329 ++++++++++++++++++ .../UefiDebugLibDebugPortProtocol.inf | 57 +++ .../UefiDebugLibDebugPortProtocol.uni | Bin 0 -> 1812 bytes MdePkg/MdePkg.dsc | 1 + 4 files changed, 387 insertions(+) create mode 100644 MdePkg/Library/UefiDebugLibDebugPortProtocol/DebugLib.c create mode 100644 MdePkg/Library/UefiDebugLibDebugPortProtocol/UefiDebugLibDebugPortProtocol.inf create mode 100644 MdePkg/Library/UefiDebugLibDebugPortProtocol/UefiDebugLibDebugPortProtocol.uni diff --git a/MdePkg/Library/UefiDebugLibDebugPortProtocol/DebugLib.c b/MdePkg/Library/UefiDebugLibDebugPortProtocol/DebugLib.c new file mode 100644 index 000000000000..fdad2f5556f0 --- /dev/null +++ b/MdePkg/Library/UefiDebugLibDebugPortProtocol/DebugLib.c @@ -0,0 +1,329 @@ +/** @file + UEFI Debug Library that sends messages to EFI_DEBUGPORT_PROTOCOL.Write. + + Copyright (c) 2015, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +// +// Define the maximum debug and assert message length that this library supports +// +#define MAX_DEBUG_MESSAGE_LENGTH 0x100 + +// +// Define the timeout for EFI_DEBUGPORT_PROTOCOL.Write +// +#define WRITE_TIMEOUT 1000 + + +EFI_DEBUGPORT_PROTOCOL *mDebugPort = NULL; + +/** + Send message to DebugPort Protocol. + + If mDebugPort is NULL, i.e. EFI_DEBUGPORT_PROTOCOL is not located, + EFI_DEBUGPORT_PROTOCOL is located first. + Then, Buffer is sent via EFI_DEBUGPORT_PROTOCOL.Write. + + @param Buffer The message to be sent. + @param BufferLength The byte length of Buffer. +**/ +VOID +UefiDebugLibDebugPortProtocolWrite ( + IN CONST CHAR8 *Buffer, + IN UINTN BufferLength + ) +{ + UINTN Length; + EFI_STATUS Status; + + // + // If mDebugPort is NULL, initialize first. + // + if (mDebugPort == NULL) { + Status = gBS->LocateProtocol (&gEfiDebugPortProtocolGuid, NULL, (VOID **)&mDebugPort); + if (EFI_ERROR (Status)) { + return; + } + + mDebugPort->Reset (mDebugPort); + } + + // + // EFI_DEBUGPORT_PROTOCOL.Write is called until all message is sent. + // + while (BufferLength > 0) { + Length = BufferLength; + + Status = mDebugPort->Write (mDebugPort, WRITE_TIMEOUT, &Length, (VOID *) Buffer); + if (EFI_ERROR (Status) || BufferLength < Length) { + break; + } + + Buffer += Length; + BufferLength -= Length; + } +} + +/** + Prints a debug message to the debug output device if the specified error level is enabled. + + If any bit in ErrorLevel is also set in DebugPrintErrorLevelLib function + GetDebugPrintErrorLevel (), then print the message specified by Format and the + associated variable argument list to the debug output device. + + If Format is NULL, then ASSERT(). + + @param ErrorLevel The error level of the debug message. + @param Format Format string for the debug message to print. + @param ... A variable argument list whose contents are accessed + based on the format string specified by Format. + +**/ +VOID +EFIAPI +DebugPrint ( + IN UINTN ErrorLevel, + IN CONST CHAR8 *Format, + ... + ) +{ + CHAR8 Buffer[MAX_DEBUG_MESSAGE_LENGTH]; + VA_LIST Marker; + + // + // If Format is NULL, then ASSERT(). + // + ASSERT (Format != NULL); + + // + // Check driver debug mask value and global mask + // + if ((ErrorLevel & GetDebugPrintErrorLevel ()) == 0) { + return; + } + + // + // Convert the DEBUG() message to an ASCII String + // + VA_START (Marker, Format); + AsciiVSPrint (Buffer, sizeof (Buffer), Format, Marker); + VA_END (Marker); + + // + // Send the print string to EFI_DEBUGPORT_PROTOCOL.Write. + // + UefiDebugLibDebugPortProtocolWrite (Buffer, AsciiStrLen (Buffer)); +} + + +/** + Prints an assert message containing a filename, line number, and description. + This may be followed by a breakpoint or a dead loop. + + Print a message of the form "ASSERT (): \n" + to the debug output device. If DEBUG_PROPERTY_ASSERT_BREAKPOINT_ENABLED bit of + PcdDebugProperyMask is set then CpuBreakpoint() is called. Otherwise, if + DEBUG_PROPERTY_ASSERT_DEADLOOP_ENABLED bit of PcdDebugProperyMask is set then + CpuDeadLoop() is called. If neither of these bits are set, then this function + returns immediately after the message is printed to the debug output device. + DebugAssert() must actively prevent recursion. If DebugAssert() is called while + processing another DebugAssert(), then DebugAssert() must return immediately. + + If FileName is NULL, then a string of "(NULL) Filename" is printed. + If Description is NULL, then a string of "(NULL) Description" is printed. + + @param FileName The pointer to the name of the source file that generated + the assert condition. + @param LineNumber The line number in the source file that generated the + assert condition + @param Description The pointer to the description of the assert condition. + +**/ +VOID +EFIAPI +DebugAssert ( + IN CONST CHAR8 *FileName, + IN UINTN LineNumber, + IN CONST CHAR8 *Description + ) +{ + CHAR8 Buffer[MAX_DEBUG_MESSAGE_LENGTH]; + + // + // Generate the ASSERT() message in ASCII format + // + AsciiSPrint ( + Buffer, + sizeof (Buffer), + "ASSERT %a(%d): %a\n", + FileName, + LineNumber, + Description + ); + + // + // Send the print string to EFI_DEBUGPORT_PROTOCOL.Write. + // + UefiDebugLibDebugPortProtocolWrite (Buffer, AsciiStrLen (Buffer)); + + // + // Generate a Breakpoint, DeadLoop, or NOP based on PCD settings + // + if ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_ASSERT_BREAKPOINT_ENABLED) != 0) { + CpuBreakpoint (); + } else if ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_ASSERT_DEADLOOP_ENABLED) != 0) { + CpuDeadLoop (); + } +} + + +/** + Fills a target buffer with PcdDebugClearMemoryValue, and returns the target buffer. + + This function fills Length bytes of Buffer with the value specified by + PcdDebugClearMemoryValue, and returns Buffer. + + If Buffer is NULL, then ASSERT(). + If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT(). + + @param Buffer The pointer to the target buffer to be filled with PcdDebugClearMemoryValue. + @param Length The number of bytes in Buffer to fill with zeros PcdDebugClearMemoryValue. + + @return Buffer The pointer to the target buffer filled with PcdDebugClearMemoryValue. + +**/ +VOID * +EFIAPI +DebugClearMemory ( + OUT VOID *Buffer, + IN UINTN Length + ) +{ + // + // If Buffer is NULL, then ASSERT(). + // + ASSERT (Buffer != NULL); + + // + // SetMem() checks for the the ASSERT() condition on Length and returns Buffer + // + return SetMem (Buffer, Length, PcdGet8(PcdDebugClearMemoryValue)); +} + + +/** + Returns TRUE if ASSERT() macros are enabled. + + This function returns TRUE if the DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of + PcdDebugProperyMask is set. Otherwise FALSE is returned. + + @retval TRUE The DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of PcdDebugProperyMask is set. + @retval FALSE The DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of PcdDebugProperyMask is clear. + +**/ +BOOLEAN +EFIAPI +DebugAssertEnabled ( + VOID + ) +{ + return (BOOLEAN) ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED) != 0); +} + + +/** + Returns TRUE if DEBUG() macros are enabled. + + This function returns TRUE if the DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of + PcdDebugProperyMask is set. Otherwise FALSE is returned. + + @retval TRUE The DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of PcdDebugProperyMask is set. + @retval FALSE The DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of PcdDebugProperyMask is clear. + +**/ +BOOLEAN +EFIAPI +DebugPrintEnabled ( + VOID + ) +{ + return (BOOLEAN) ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_PRINT_ENABLED) != 0); +} + + +/** + Returns TRUE if DEBUG_CODE() macros are enabled. + + This function returns TRUE if the DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of + PcdDebugProperyMask is set. Otherwise FALSE is returned. + + @retval TRUE The DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of PcdDebugProperyMask is set. + @retval FALSE The DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of PcdDebugProperyMask is clear. + +**/ +BOOLEAN +EFIAPI +DebugCodeEnabled ( + VOID + ) +{ + return (BOOLEAN) ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_CODE_ENABLED) != 0); +} + + +/** + Returns TRUE if DEBUG_CLEAR_MEMORY() macro is enabled. + + This function returns TRUE if the DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED bit of + PcdDebugProperyMask is set. Otherwise FALSE is returned. + + @retval TRUE The DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED bit of PcdDebugProperyMask is set. + @retval FALSE The DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED bit of PcdDebugProperyMask is clear. + +**/ +BOOLEAN +EFIAPI +DebugClearMemoryEnabled ( + VOID + ) +{ + return (BOOLEAN) ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED) != 0); +} + +/** + Returns TRUE if any one of the bit is set both in ErrorLevel and PcdFixedDebugPrintErrorLevel. + + This function compares the bit mask of ErrorLevel and PcdFixedDebugPrintErrorLevel. + + @retval TRUE Current ErrorLevel is supported. + @retval FALSE Current ErrorLevel is not supported. + +**/ +BOOLEAN +EFIAPI +DebugPrintLevelEnabled ( + IN CONST UINTN ErrorLevel + ) +{ + return (BOOLEAN) ((ErrorLevel & PcdGet32(PcdFixedDebugPrintErrorLevel)) != 0); +} diff --git a/MdePkg/Library/UefiDebugLibDebugPortProtocol/UefiDebugLibDebugPortProtocol.inf b/MdePkg/Library/UefiDebugLibDebugPortProtocol/UefiDebugLibDebugPortProtocol.inf new file mode 100644 index 000000000000..11c7e815b8b5 --- /dev/null +++ b/MdePkg/Library/UefiDebugLibDebugPortProtocol/UefiDebugLibDebugPortProtocol.inf @@ -0,0 +1,57 @@ +## @file +# Instance of Debug Library using EFI_DEBUGPORT_PROTOCOL. +# +# Debug Lib that sends messages to EFI_DEBUGPORT_PROTOCOL.Write. +# +# Copyright (c) 2015, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = UefiDebugLibDebugPortProtocol + MODULE_UNI_FILE = UefiDebugLibDebugPortProtocol.uni + FILE_GUID = 102287b4-6b12-4D41-91e1-ebee1f3aa614 + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = DebugLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER + + +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + + +[Sources] + DebugLib.c + + + +[Packages] + MdePkg/MdePkg.dec + + +[LibraryClasses] + BaseMemoryLib + BaseLib + PcdLib + PrintLib + UefiBootServicesTableLib + DebugPrintErrorLevelLib + +[Protocols] + gEfiDebugPortProtocolGuid ## UNDEFINED + +[Pcd] + gEfiMdePkgTokenSpaceGuid.PcdDebugClearMemoryValue ## SOMETIMES_CONSUMES + gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask ## CONSUMES + gEfiMdePkgTokenSpaceGuid.PcdFixedDebugPrintErrorLevel ## CONSUMES + diff --git a/MdePkg/Library/UefiDebugLibDebugPortProtocol/UefiDebugLibDebugPortProtocol.uni b/MdePkg/Library/UefiDebugLibDebugPortProtocol/UefiDebugLibDebugPortProtocol.uni new file mode 100644 index 0000000000000000000000000000000000000000..83051cace477ca2941bd5523c2ea7ed35ab472ef GIT binary patch literal 1812 zcmc(fPj3@35XI+=#CNdL3!pXuBrXUcl6G5GwB0D#C~&Gaf10k;B-JJ@^vf51&rWtj z8U$QGE3e1)_|2Q~v%fzytYMD!g3s9pyR_V{ZER2N3A0*@ZDtEwT1G!)#n~J$XGhor zyR`}SDZ2(%;8WN=<6Cy*_-ie)V=yl8kE~@qJF&JU*0GeiHhqGX*dguI>Sf$2{^K|f zHdn-2g1&&o%trLirq~OF2sggPFepgVp}|ssduP+^DORv*aY+ z`dcPVg?!{+_)6EwzTi9?TeV*>Gl2QX4z^b6pj^?aTck`ra_`*grk$Xorkyd4sip3) z`jpw&-^~0|DZcVi)ZlfDm!f~6|HO)z>jp-vD3QmB>~o1zp~uvs z&AX$RM;mpkG^Ka3;kj#0ZLd^KxILkM7a%2I^gxSv*_z}YR+>~xS^nzV;}mrZCY*eD rxt!O+0a#*MgWbP-foo;1f0n0S^)4AoLGAKncIEo}JpboQU*-J+Kfe{x literal 0 HcmV?d00001 diff --git a/MdePkg/MdePkg.dsc b/MdePkg/MdePkg.dsc index e8a3ea76332e..4ea367ccc070 100644 --- a/MdePkg/MdePkg.dsc +++ b/MdePkg/MdePkg.dsc @@ -114,6 +114,7 @@ MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf + MdePkg/Library/UefiDebugLibDebugPortProtocol/UefiDebugLibDebugPortProtocol.inf MdePkg/Library/UefiDebugLibStdErr/UefiDebugLibStdErr.inf MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf MdePkg/Library/UefiDevicePathLib/UefiDevicePathLibOptionalDevicePathProtocol.inf From 2def2a6c41624a8c02cbb2c438744313a4d6d3cf Mon Sep 17 00:00:00 2001 From: Liming Gao Date: Tue, 15 Dec 2015 13:19:32 +0000 Subject: [PATCH 244/525] MdePkg: Correct Protocol usages in UefiDebugLibDebugPortProtocol (Sync patch r18415 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Liming Gao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19277 6f19259b-4bc3-4df7-8a09-765794883524 --- MdePkg/Library/UefiDebugLibDebugPortProtocol/DebugLib.c | 1 + .../UefiDebugLibDebugPortProtocol.inf | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/MdePkg/Library/UefiDebugLibDebugPortProtocol/DebugLib.c b/MdePkg/Library/UefiDebugLibDebugPortProtocol/DebugLib.c index fdad2f5556f0..10d3e347ccc6 100644 --- a/MdePkg/Library/UefiDebugLibDebugPortProtocol/DebugLib.c +++ b/MdePkg/Library/UefiDebugLibDebugPortProtocol/DebugLib.c @@ -327,3 +327,4 @@ DebugPrintLevelEnabled ( { return (BOOLEAN) ((ErrorLevel & PcdGet32(PcdFixedDebugPrintErrorLevel)) != 0); } + diff --git a/MdePkg/Library/UefiDebugLibDebugPortProtocol/UefiDebugLibDebugPortProtocol.inf b/MdePkg/Library/UefiDebugLibDebugPortProtocol/UefiDebugLibDebugPortProtocol.inf index 11c7e815b8b5..0f18c27a1130 100644 --- a/MdePkg/Library/UefiDebugLibDebugPortProtocol/UefiDebugLibDebugPortProtocol.inf +++ b/MdePkg/Library/UefiDebugLibDebugPortProtocol/UefiDebugLibDebugPortProtocol.inf @@ -48,7 +48,7 @@ DebugPrintErrorLevelLib [Protocols] - gEfiDebugPortProtocolGuid ## UNDEFINED + gEfiDebugPortProtocolGuid ## CONSUMES [Pcd] gEfiMdePkgTokenSpaceGuid.PcdDebugClearMemoryValue ## SOMETIMES_CONSUMES From f770b72f916d2fc96c40c183879a2af65fcc584c Mon Sep 17 00:00:00 2001 From: "Yao, Jiewen" Date: Tue, 15 Dec 2015 13:28:00 +0000 Subject: [PATCH 245/525] MdePkg: Add 3 macro defined in latest TPM2 specification. Add 3 macro to TPM_RH Constants, which is in latest TPM2 spec. (Sync patch r19230 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: "Yao, Jiewen" Reviewed-by: "Zhang, Chao B" git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19278 6f19259b-4bc3-4df7-8a09-765794883524 --- MdePkg/Include/IndustryStandard/Tpm20.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/MdePkg/Include/IndustryStandard/Tpm20.h b/MdePkg/Include/IndustryStandard/Tpm20.h index 05059270107a..cd68ce7c76e4 100644 --- a/MdePkg/Include/IndustryStandard/Tpm20.h +++ b/MdePkg/Include/IndustryStandard/Tpm20.h @@ -675,7 +675,10 @@ typedef UINT32 TPM_RH; #define TPM_RH_LOCKOUT (TPM_RH)(0x4000000A) #define TPM_RH_ENDORSEMENT (TPM_RH)(0x4000000B) #define TPM_RH_PLATFORM (TPM_RH)(0x4000000C) -#define TPM_RH_LAST (TPM_RH)(0x4000000C) +#define TPM_RH_PLATFORM_NV (TPM_RH)(0x4000000D) +#define TPM_RH_AUTH_00 (TPM_RH)(0x40000010) +#define TPM_RH_AUTH_FF (TPM_RH)(0x4000010F) +#define TPM_RH_LAST (TPM_RH)(0x4000010F) // Table 28 - TPM_HC Constants typedef TPM_HANDLE TPM_HC; From 69b6a5c34ac3775ffecb7d1a6acab04e55edb086 Mon Sep 17 00:00:00 2001 From: "Yao, Jiewen" Date: Tue, 15 Dec 2015 13:33:46 +0000 Subject: [PATCH 246/525] Fix >4G issue on IDT not restored correctly. Idtr might be changed inside of FSP. 32bit FSP only knows the <4G address. If IDTR.Base is >4G, FSP can not handle. So we need save/restore IDTR here. Interrupt is already disabled here, so it is safety to update IDTR. (Sync patch r19246 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: "Yao, Jiewen" Reviewed-by: "Ma, Maurice" Reviewed-by: "Mudusuru, Giri P" Reviewed-by: "Yarlagadda, Satya P" git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19279 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Library/BaseFspApiLib/X64/DispatchExecute.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/IntelFspWrapperPkg/Library/BaseFspApiLib/X64/DispatchExecute.c b/IntelFspWrapperPkg/Library/BaseFspApiLib/X64/DispatchExecute.c index e2f44225347c..360327ed08f5 100644 --- a/IntelFspWrapperPkg/Library/BaseFspApiLib/X64/DispatchExecute.c +++ b/IntelFspWrapperPkg/Library/BaseFspApiLib/X64/DispatchExecute.c @@ -89,6 +89,18 @@ Execute32BitCode ( IN UINT64 Param1 ) { - return AsmExecute32BitCode (Function, Param1, 0, &mGdt); + EFI_STATUS Status; + IA32_DESCRIPTOR Idtr; + + // + // Idtr might be changed inside of FSP. 32bit FSP only knows the <4G address. + // If IDTR.Base is >4G, FSP can not handle. So we need save/restore IDTR here for X64 only. + // Interrupt is already disabled here, so it is safety to update IDTR. + // + AsmReadIdtr (&Idtr); + Status = AsmExecute32BitCode (Function, Param1, 0, &mGdt); + AsmWriteIdtr (&Idtr); + + return Status; } From 4b71020adbcba630b37b86b920d98e40f0eb25df Mon Sep 17 00:00:00 2001 From: Feng Tian Date: Thu, 17 Dec 2015 15:02:17 +0000 Subject: [PATCH 247/525] MdeModulePkg/PciSioSerialDxe:add non-null pointer dereference assertion Add assertion to make sure there doesn't exist null pointer dereference. (Sync patch r19308 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Feng Tian Reviewed-by: Qiu Shumin git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19322 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.c b/MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.c index 7fc053578d7d..e8cefecd8d2d 100644 --- a/MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.c +++ b/MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.c @@ -870,6 +870,7 @@ SerialControllerDriverStart ( if ((SerialDeviceCount != 0) && (RemainingDevicePath != NULL)) { Uart = (UART_DEVICE_PATH *) SkipControllerDevicePathNode (RemainingDevicePath, &ContainsControllerNode, &ControllerNumber); for (Index = 0; Index < SerialDeviceCount; Index++) { + ASSERT ((SerialDevices != NULL) && (SerialDevices[Index] != NULL)); if ((!SerialDevices[Index]->ContainsControllerNode && !ContainsControllerNode) || (SerialDevices[Index]->ContainsControllerNode && ContainsControllerNode && SerialDevices[Index]->Instance == ControllerNumber) ) { @@ -963,6 +964,7 @@ SerialControllerDriverStart ( // Restore the PCI attributes when all children is destroyed (PciDeviceInfo->ChildCount == 0). // PciDeviceInfo = AllocatePool (sizeof (PCI_DEVICE_INFO)); + ASSERT (PciDeviceInfo != NULL); PciDeviceInfo->ChildCount = 0; PciDeviceInfo->PciIo = ParentIo.PciIo; Status = ParentIo.PciIo->Attributes ( @@ -993,6 +995,7 @@ SerialControllerDriverStart ( // // Re-use the PciDeviceInfo stored in existing children. // + ASSERT ((SerialDevices != NULL) && (SerialDevices[0] != NULL)); PciDeviceInfo = SerialDevices[0]->PciDeviceInfo; ASSERT (PciDeviceInfo != NULL); } From 4b2bb7094053f8e7624a435b57f3ab547c5de043 Mon Sep 17 00:00:00 2001 From: Feng Tian Date: Thu, 17 Dec 2015 15:14:25 +0000 Subject: [PATCH 248/525] MdeModulePkg/PciSioSerialDxe:bitwise operation have same width operands Operands in a bitwise operation have different size. Update code to fix it. (Sync patch r19309 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Feng Tian Reviewed-by: Qiu Shumin git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19323 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.c b/MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.c index e8cefecd8d2d..aeafee247c9b 100644 --- a/MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.c +++ b/MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.c @@ -982,7 +982,7 @@ SerialControllerDriverStart ( &Supports ); if (!EFI_ERROR (Status)) { - Supports &= EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_MEMORY; + Supports &= (UINT64)(EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_MEMORY); Status = ParentIo.PciIo->Attributes ( ParentIo.PciIo, EfiPciIoAttributeOperationEnable, From 99224547e3b98042aea13c48e67ebb0daf8e9e20 Mon Sep 17 00:00:00 2001 From: Zhang Lubo Date: Thu, 17 Dec 2015 15:15:13 +0000 Subject: [PATCH 249/525] MdeModulePkg:Fix a bug HttpLib can't parse last chunked data well When HttpLib parsing the last chunked data down, the Http NextMsg pointer in the HttpBodyParserCallback function should point to the character after '/n' flag. (Sync patch r19310 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Zhang Lubo Reviewed-by: Fu Siyuan Reviewed-by: Ye Ting Reviewed-by: Wu Jiaxin git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19324 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Library/DxeHttpLib/DxeHttpLib.c | 39 ++++++++++++-------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/MdeModulePkg/Library/DxeHttpLib/DxeHttpLib.c b/MdeModulePkg/Library/DxeHttpLib/DxeHttpLib.c index 500b3c72b38f..6b830fdd9be8 100644 --- a/MdeModulePkg/Library/DxeHttpLib/DxeHttpLib.c +++ b/MdeModulePkg/Library/DxeHttpLib/DxeHttpLib.c @@ -1161,21 +1161,7 @@ HttpParseMessageBody ( switch (Parser->State) { case BodyParserStateMax: return EFI_ABORTED; - - case BodyParserComplete: - if (Parser->Callback != NULL) { - Status = Parser->Callback ( - BodyParseEventOnComplete, - Char, - 0, - Parser->Context - ); - if (EFI_ERROR (Status)) { - return Status; - } - } - return EFI_SUCCESS; - + case BodyParserBodyIdentity: // // Identity transfer-coding, just notify user to save the body data. @@ -1195,6 +1181,17 @@ HttpParseMessageBody ( Parser->ParsedBodyLength += MIN (BodyLength, Parser->ContentLength - Parser->ParsedBodyLength); if (Parser->ParsedBodyLength == Parser->ContentLength) { Parser->State = BodyParserComplete; + if (Parser->Callback != NULL) { + Status = Parser->Callback ( + BodyParseEventOnComplete, + Char, + 0, + Parser->Context + ); + if (EFI_ERROR (Status)) { + return Status; + } + } } break; @@ -1272,6 +1269,18 @@ HttpParseMessageBody ( case BodyParserLastCRLFEnd: if (*Char == '\n') { Parser->State = BodyParserComplete; + Char++; + if (Parser->Callback != NULL) { + Status = Parser->Callback ( + BodyParseEventOnComplete, + Char, + 0, + Parser->Context + ); + if (EFI_ERROR (Status)) { + return Status; + } + } break; } else { Parser->State = BodyParserStateMax; From b85d3c6d351d59f96894134194ba4f85118ddb08 Mon Sep 17 00:00:00 2001 From: Liming Gao Date: Thu, 17 Dec 2015 15:15:42 +0000 Subject: [PATCH 250/525] MdeModulePkg: Update print error level for RuntimeDriver alignment check In DxeCore, use warning message for Runtime driver that doesn't satisfy section alignment requirement. This check is required when PropertiesTable is installed. So, add error message if PropertiesTable can't be installed successfully. (Sync patch r19312 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Liming Gao Reviewed-by: Jiewen Yao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19325 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Core/Dxe/Misc/PropertiesTable.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/MdeModulePkg/Core/Dxe/Misc/PropertiesTable.c b/MdeModulePkg/Core/Dxe/Misc/PropertiesTable.c index 34867375b157..adfc91c41f95 100644 --- a/MdeModulePkg/Core/Dxe/Misc/PropertiesTable.c +++ b/MdeModulePkg/Core/Dxe/Misc/PropertiesTable.c @@ -1120,11 +1120,11 @@ InsertImageRecord ( SetPropertiesTableSectionAlignment (SectionAlignment); if ((SectionAlignment & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) != 0) { - DEBUG ((EFI_D_ERROR, "!!!!!!!! InsertImageRecord - Section Alignment(0x%x) is not %dK !!!!!!!!\n", + DEBUG ((EFI_D_WARN, "!!!!!!!! InsertImageRecord - Section Alignment(0x%x) is not %dK !!!!!!!!\n", SectionAlignment, EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT >> 10)); PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress); if (PdbPointer != NULL) { - DEBUG ((EFI_D_ERROR, "!!!!!!!! Image - %a !!!!!!!!\n", PdbPointer)); + DEBUG ((EFI_D_WARN, "!!!!!!!! Image - %a !!!!!!!!\n", PdbPointer)); } goto Finish; } @@ -1320,6 +1320,8 @@ InstallPropertiesTable ( DEBUG ((EFI_D_INFO, "MemoryProtectionAttribute - 0x%016lx\n", mPropertiesTable.MemoryProtectionAttribute)); if ((mPropertiesTable.MemoryProtectionAttribute & EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA) == 0) { + DEBUG ((EFI_D_ERROR, "MemoryProtectionAttribute NON_EXECUTABLE_PE_DATA is not set, ")); + DEBUG ((EFI_D_ERROR, "because Runtime Driver Section Alignment is not %dK.\n", EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT >> 10)); return ; } From 323d56b992549db17e96251e03b9b40923c9ebe4 Mon Sep 17 00:00:00 2001 From: "Yao, Jiewen" Date: Thu, 17 Dec 2015 15:16:03 +0000 Subject: [PATCH 251/525] Add clarification for PcdAcpiDefault value PCD. Add clarification for PcdAcpiDefaultOemTableId, PcdAcpiDefaultOemRevision, PcdAcpiDefaultCreatorId, PcdAcpiDefaultCreatorRevision. According to ACPI spec, they are used as special meaning for SSDT, so we ignore them in updating generic SSDT provided by EDKII. (Sync patch r19321 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: "Yao, Jiewen" Reviewed-by: "Zeng, Star" com> git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19326 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/MdeModulePkg.dec | 14 ++++++++++++++ MdeModulePkg/MdeModulePkg.uni | Bin 184014 -> 188464 bytes 2 files changed, 14 insertions(+) diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec index 38eac142ac79..3ded8f1de1a5 100644 --- a/MdeModulePkg/MdeModulePkg.dec +++ b/MdeModulePkg/MdeModulePkg.dec @@ -1387,18 +1387,32 @@ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemId|"INTEL "|VOID*|0x30001034 ## Default OEM Table ID for ACPI table creation, it is "EDK2 ". + # Accroding to ACPI specification, this field is particularly useful when + # defining a definition block to distinguish definition block functions. + # The OEM assigns each dissimilar table a new OEM Table ID. + # This PCD is ignored for definition block. # @Prompt Default OEM Table ID for ACPI table creation. gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemTableId|0x20202020324B4445|UINT64|0x30001035 ## Default OEM Revision for ACPI table creation. + # Accroding to ACPI specification, for LoadTable() opcode, the OS can also + # check the OEM Table ID and Revision ID against a database for a newer + # revision Definition Block of the same OEM Table ID and load it instead. + # This PCD is ignored for definition block. # @Prompt Default OEM Revision for ACPI table creation. gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemRevision|0x00000002|UINT32|0x30001036 ## Default Creator ID for ACPI table creation. + # Accroding to ACPI specification, for tables containing Definition Blocks, + # this is the ID for the ASL Compiler. + # This PCD is ignored for definition block. # @Prompt Default Creator ID for ACPI table creation. gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorId|0x20202020|UINT32|0x30001037 ## Default Creator Revision for ACPI table creation. + # Accroding to ACPI specification, for tables containing Definition Blocks, + # this is the revision for the ASL Compiler. + # This PCD is ignored for definition block. # @Prompt Default Creator Revision for ACPI table creation. gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorRevision|0x01000013|UINT32|0x30001038 diff --git a/MdeModulePkg/MdeModulePkg.uni b/MdeModulePkg/MdeModulePkg.uni index b1fd210d2b93664435762262a67efa34006061b1..cf4f580dbe00f37290742a5e8eb968197b45653c 100644 GIT binary patch delta 1227 zcmcIjO=}ZT6umRHH5w__SO%-bG%7aGg^Rkjja8zg45f-o9g|5Swlgsw7I#`f7m7sg zVx%I}oh#dzmPlP_v1p|tBDj_Q0&(R|@!Xe8TQ>;vO3@W^C_`Z?lFJY0kD3GOJ&Sk&Z)vPHO`tB^h~&sZXA!$3 zm5`C$1l>Tsgbo`W5)IQ7WwCQS&D54dDU}c?AI{>+b|V_5%P4kn)K#=#1UzM=f&!4i zN@|yt>fXPr1;|0CjN+2R+M~BT6bx`KyK~f}Q#6XRESyw8K7&f3VM=i$d z3vnKro5p^oA^mD|>BmHRbu`ulAS`HcZeyZ;iX!e(4h+ONn|!NeT9d}{OrqMsYJpJ! zhISdtp@?E^<5|}jwt!J@yHuw5#LI5u42`Is4En?$Q6FdU*kH)moXA2<=>g=toUBDW zEvki%j36NQM9giNfzsF(V_iz~tynidsPr6Cu*i$;LQw9N!1=(i$h-DTdk-%=S}R^H zFRo|}c~_dtJHA!kO{3*nh@g%#zs{omMYQ5opaHLIPJ7L>PuuwS*dJ?yuBY#$ zA038634omh*d$z(TL&dQ?YjPfZ(eNkW*+OE-lYqANAo*YUOZg=R{QL;{$e!wn*Rr9 t?mNHcQ{D!0-miYm;PqZ^xJJ#+S5Od`Z8v_Ya$BFlGP% delta 76 zcmdmRfcxBBZl?eLHoV(3UCWj+ZSuTzGMmeG>|liP#5SMVzYd94bMzjRS8&FpdDZFm ORi_!ZuR6`tCISF|_9N5) From 9fe90f039a7784943362eab0ebc0949ebd1f6486 Mon Sep 17 00:00:00 2001 From: Liming Gao Date: Fri, 18 Dec 2015 05:40:43 +0000 Subject: [PATCH 252/525] SecurityPkg: Correct Pcd Usage PcdTpm2HashMask in Tcg2Pei Tcg2Pei sets PcdTpm2HashMask. Its usage should be both SOMETIMES_CONSUMES and SOMETIMES_PRODUCES. (Sync patch r19314 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Liming Gao Reviewed-by: Chao Zhang git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19348 6f19259b-4bc3-4df7-8a09-765794883524 --- SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.inf | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.inf b/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.inf index 29ca3aa918fb..007ce918eda9 100644 --- a/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.inf +++ b/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.inf @@ -78,7 +78,9 @@ gEfiSecurityPkgTokenSpaceGuid.PcdTpm2ScrtmPolicy ## CONSUMES gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreMaxFvSupported ## CONSUMES gEfiSecurityPkgTokenSpaceGuid.PcdStatusCodeSubClassTpmDevice ## SOMETIMES_CONSUMES - gEfiSecurityPkgTokenSpaceGuid.PcdTpm2HashMask ## CONSUMES + ## SOMETIMES_CONSUMES + ## SOMETIMES_PRODUCES + gEfiSecurityPkgTokenSpaceGuid.PcdTpm2HashMask [Depex] gEfiPeiMasterBootModePpiGuid AND From 72b61d20fc59d35232ad0960dcf89735b064a96b Mon Sep 17 00:00:00 2001 From: Liming Gao Date: Fri, 18 Dec 2015 05:41:21 +0000 Subject: [PATCH 253/525] MdeModulePkg: Correct usage gEfiIp4Config2ProtocolGuid in Ip4Dxe Ip4Dxe driver installs gEfiIp4Config2ProtocolGuid. Its usage should be BY_START. (Sync patch r19315 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Liming Gao Reviewed-by: Ye Ting git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19349 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Dxe.inf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Dxe.inf b/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Dxe.inf index b93f2b733023..f561af0c75a4 100644 --- a/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Dxe.inf +++ b/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Dxe.inf @@ -95,7 +95,7 @@ gEfiManagedNetworkServiceBindingProtocolGuid ## TO_START gEfiManagedNetworkProtocolGuid ## TO_START gEfiArpServiceBindingProtocolGuid ## TO_START - gEfiIp4Config2ProtocolGuid ## TO_START + gEfiIp4Config2ProtocolGuid ## BY_START gEfiArpProtocolGuid ## TO_START gEfiDhcp4ServiceBindingProtocolGuid ## TO_START gEfiDhcp4ProtocolGuid ## TO_START From 82e945021ef3e9a88cddf68e7d93b10bc7fe1c27 Mon Sep 17 00:00:00 2001 From: Liming Gao Date: Fri, 18 Dec 2015 05:41:59 +0000 Subject: [PATCH 254/525] SourceLevelDebugPkg: Correct gEfiDebugAgentGuid usage in DxeDebugAgentLib DxeDebugAgentLib instance produces gEfiDebugAgentGuid system table. Its usage should be PRODUCES instead of SOMETIMES_PRODUCES. (Sync patch r19316 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Liming Gao Reviewed-by: Jeff Fan git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19350 6f19259b-4bc3-4df7-8a09-765794883524 --- SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgentLib.inf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgentLib.inf b/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgentLib.inf index 7ed5f5514c00..8894a047c34c 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgentLib.inf +++ b/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgentLib.inf @@ -81,7 +81,7 @@ MemoryAllocationLib [Guids] - ## SOMETIMES_PRODUCES ## SystemTable + ## PRODUCES ## SystemTable ## CONSUMES ## HOB gEfiDebugAgentGuid ## SOMETIMES_CONSUMES ## SystemTable From 210774babaca41d457777aa030b571286b4dfc7a Mon Sep 17 00:00:00 2001 From: Liming Gao Date: Fri, 18 Dec 2015 05:42:32 +0000 Subject: [PATCH 255/525] NetworkPkg: Correct gEfiUdp4ProtocolGuid usage in DnsDxe DnsDxe driver locates gEfiUdp4ProtocolGuid. Its usage should be TO_START. (Sync patch r19317 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Liming Gao Reviewed-by: Ye Ting git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19351 6f19259b-4bc3-4df7-8a09-765794883524 --- NetworkPkg/DnsDxe/DnsDxe.inf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NetworkPkg/DnsDxe/DnsDxe.inf b/NetworkPkg/DnsDxe/DnsDxe.inf index d63bbbebc47e..0d1efd8e0179 100644 --- a/NetworkPkg/DnsDxe/DnsDxe.inf +++ b/NetworkPkg/DnsDxe/DnsDxe.inf @@ -57,7 +57,7 @@ gEfiDns4ServiceBindingProtocolGuid ## BY_START gEfiDns4ProtocolGuid ## BY_START gEfiUdp4ServiceBindingProtocolGuid ## TO_START - gEfiUdp4ProtocolGuid ## BY_START + gEfiUdp4ProtocolGuid ## TO_START gEfiDhcp4ServiceBindingProtocolGuid ## SOMETIMES_CONSUMES gEfiDhcp4ProtocolGuid ## SOMETIMES_CONSUMES gEfiIp4Config2ProtocolGuid ## SOMETIMES_CONSUMES From a8d5a3a25be665915784a0cbdec0ff7afab67a8e Mon Sep 17 00:00:00 2001 From: Zhang Lubo Date: Fri, 18 Dec 2015 05:43:19 +0000 Subject: [PATCH 256/525] NetworkPkg:Fix the issue Http boot hang when network failed. For both IPv4 and IPv6, when network transfer failed, such as disconnected cable or disable http server, HTTP boot should exit back to the menu UI rather than hang. (Sync patch r19335 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Zhang Lubo Reviewed-by: Ye Ting Reviewed-by: Wu Jiaxin git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19352 6f19259b-4bc3-4df7-8a09-765794883524 --- NetworkPkg/HttpDxe/HttpProto.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/NetworkPkg/HttpDxe/HttpProto.c b/NetworkPkg/HttpDxe/HttpProto.c index d4ab74f0094d..b7cd0fdfcc53 100644 --- a/NetworkPkg/HttpDxe/HttpProto.c +++ b/NetworkPkg/HttpDxe/HttpProto.c @@ -150,6 +150,9 @@ HttpTcpReceiveNotifyDpc ( gBS->CloseEvent (Wrap->TcpWrap.Rx6Token.CompletionToken.Event); if (EFI_ERROR (Wrap->TcpWrap.Rx6Token.CompletionToken.Status)) { + Wrap->HttpToken->Status = Wrap->TcpWrap.Rx6Token.CompletionToken.Status; + gBS->SignalEvent (Wrap->HttpToken->Event); + FreePool (Wrap); return ; } @@ -157,6 +160,9 @@ HttpTcpReceiveNotifyDpc ( gBS->CloseEvent (Wrap->TcpWrap.Rx4Token.CompletionToken.Event); if (EFI_ERROR (Wrap->TcpWrap.Rx4Token.CompletionToken.Status)) { + Wrap->HttpToken->Status = Wrap->TcpWrap.Rx4Token.CompletionToken.Status; + gBS->SignalEvent (Wrap->HttpToken->Event); + FreePool (Wrap); return ; } } From 9a46a893ddd9bbed649746e501facf5ec217272d Mon Sep 17 00:00:00 2001 From: Dandan Bi Date: Fri, 18 Dec 2015 05:43:54 +0000 Subject: [PATCH 257/525] MdeModulePkg:Fix bug that get the password width info incorrectly (Sync patch r19336 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Dandan Bi Reviewed-by: Eric Dong Reviewed-by: Liming Gao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19353 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Universal/HiiDatabaseDxe/ConfigKeywordHandler.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigKeywordHandler.c b/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigKeywordHandler.c index 52aa4d8bcf0b..0deaf205573b 100644 --- a/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigKeywordHandler.c +++ b/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigKeywordHandler.c @@ -1583,6 +1583,8 @@ GetWidth ( return (UINT16) sizeof (BOOLEAN); case EFI_IFR_PASSWORD_OP: + return (UINT16)((UINTN) ((EFI_IFR_PASSWORD *) OpCodeData)->MaxSize * sizeof (CHAR16)); + case EFI_IFR_STRING_OP: return (UINT16)((UINTN) ((EFI_IFR_STRING *) OpCodeData)->MaxSize * sizeof (CHAR16)); From f64559d605c9c2fb60770bd202dc3fea5dbb90e8 Mon Sep 17 00:00:00 2001 From: Liming Gao Date: Fri, 18 Dec 2015 05:44:39 +0000 Subject: [PATCH 258/525] EdkCompatibilityPkg: Fix GCC error to avoid the duplicated global variables SmmBaseHelper uses the same name global variables to the one in SmmMemoryAllocateLib. Update SmmBaseHelper to use SmmMemLib SmmIsBufferOutsideSmmValid(). (Sync patch r19337 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Liming Gao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19354 6f19259b-4bc3-4df7-8a09-765794883524 --- .../SmmBaseHelper/SmmBaseHelper.c | 84 +------------------ .../SmmBaseHelper/SmmBaseHelper.inf | 2 +- EdkCompatibilityPkg/EdkCompatibilityPkg.dsc | 2 + 3 files changed, 5 insertions(+), 83 deletions(-) diff --git a/EdkCompatibilityPkg/Compatibility/SmmBaseHelper/SmmBaseHelper.c b/EdkCompatibilityPkg/Compatibility/SmmBaseHelper/SmmBaseHelper.c index 1d1644923da1..16566d2b2948 100644 --- a/EdkCompatibilityPkg/Compatibility/SmmBaseHelper/SmmBaseHelper.c +++ b/EdkCompatibilityPkg/Compatibility/SmmBaseHelper/SmmBaseHelper.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -42,7 +43,6 @@ #include #include #include -#include /** Register SMM image to SMRAM profile. @@ -122,8 +122,6 @@ SPIN_LOCK mPFLock; UINT64 mPhyMask; VOID *mOriginalHandler; EFI_SMM_CPU_SAVE_STATE *mShadowSaveState; -EFI_SMRAM_DESCRIPTOR *mSmramRanges; -UINTN mSmramRangeCount; LIST_ENTRY mCallbackInfoListHead = INITIALIZE_LIST_HEAD_VARIABLE (mCallbackInfoListHead); @@ -743,60 +741,6 @@ LoadImage ( return Status; } -/** - This function check if the address is in SMRAM. - - @param Buffer the buffer address to be checked. - @param Length the buffer length to be checked. - - @retval TRUE this address is in SMRAM. - @retval FALSE this address is NOT in SMRAM. -**/ -BOOLEAN -IsAddressInSmram ( - IN EFI_PHYSICAL_ADDRESS Buffer, - IN UINT64 Length - ) -{ - UINTN Index; - - for (Index = 0; Index < mSmramRangeCount; Index ++) { - if (((Buffer >= mSmramRanges[Index].CpuStart) && (Buffer < mSmramRanges[Index].CpuStart + mSmramRanges[Index].PhysicalSize)) || - ((mSmramRanges[Index].CpuStart >= Buffer) && (mSmramRanges[Index].CpuStart < Buffer + Length))) { - return TRUE; - } - } - - return FALSE; -} - -/** - This function check if the address refered by Buffer and Length is valid. - - @param Buffer the buffer address to be checked. - @param Length the buffer length to be checked. - - @retval TRUE this address is valid. - @retval FALSE this address is NOT valid. -**/ -BOOLEAN -IsAddressValid ( - IN UINTN Buffer, - IN UINTN Length - ) -{ - if (Buffer > (MAX_ADDRESS - Length)) { - // - // Overflow happen - // - return FALSE; - } - if (IsAddressInSmram ((EFI_PHYSICAL_ADDRESS)Buffer, (UINT64)Length)) { - return FALSE; - } - return TRUE; -} - /** Thunk service of EFI_SMM_BASE_PROTOCOL.Register(). @@ -1133,7 +1077,7 @@ SmmHandlerEntry ( ASSERT (CommBufferSize != NULL); if (*CommBufferSize == sizeof (SMMBASE_FUNCTION_DATA) && - IsAddressValid ((UINTN)CommBuffer, *CommBufferSize)) { + SmmIsBufferOutsideSmmValid ((EFI_PHYSICAL_ADDRESS)(UINTN)CommBuffer, (UINT64)*CommBufferSize)) { FunctionData = (SMMBASE_FUNCTION_DATA *)CommBuffer; switch (FunctionData->Function) { @@ -1207,8 +1151,6 @@ SmmBaseHelperMain ( EFI_HANDLE Handle; UINTN NumberOfEnabledProcessors; VOID *Registration; - EFI_SMM_ACCESS2_PROTOCOL *SmmAccess; - UINTN Size; Handle = NULL; /// @@ -1253,28 +1195,6 @@ SmmBaseHelperMain ( mSmmBaseHelperReady->FrameworkSmst = mFrameworkSmst; mSmmBaseHelperReady->ServiceEntry = SmmHandlerEntry; - // - // Get SMRAM information - // - Status = gBS->LocateProtocol (&gEfiSmmAccess2ProtocolGuid, NULL, (VOID **)&SmmAccess); - ASSERT_EFI_ERROR (Status); - - Size = 0; - Status = SmmAccess->GetCapabilities (SmmAccess, &Size, NULL); - ASSERT (Status == EFI_BUFFER_TOO_SMALL); - - Status = gSmst->SmmAllocatePool ( - EfiRuntimeServicesData, - Size, - (VOID **)&mSmramRanges - ); - ASSERT_EFI_ERROR (Status); - - Status = SmmAccess->GetCapabilities (SmmAccess, &Size, mSmramRanges); - ASSERT_EFI_ERROR (Status); - - mSmramRangeCount = Size / sizeof (EFI_SMRAM_DESCRIPTOR); - // // Register SMM Ready To Lock Protocol notification // diff --git a/EdkCompatibilityPkg/Compatibility/SmmBaseHelper/SmmBaseHelper.inf b/EdkCompatibilityPkg/Compatibility/SmmBaseHelper/SmmBaseHelper.inf index 8e967dc2cb38..118640b1e4a0 100644 --- a/EdkCompatibilityPkg/Compatibility/SmmBaseHelper/SmmBaseHelper.inf +++ b/EdkCompatibilityPkg/Compatibility/SmmBaseHelper/SmmBaseHelper.inf @@ -60,6 +60,7 @@ SynchronizationLib CpuLib PcdLib + SmmMemLib [Guids] gEfiSmmBaseThunkCommunicationGuid @@ -75,7 +76,6 @@ gEfiSmmCpuIo2ProtocolGuid # PROTOCOL ALWAYS_CONSUMED gEfiLoadPeImageProtocolGuid # PROTOCOL ALWAYS_CONSUMED gEfiSmmReadyToLockProtocolGuid # PROTOCOL ALWAYS_CONSUMED - gEfiSmmAccess2ProtocolGuid # PROTOCOL ALWAYS_CONSUMED gEfiSmmCommunicationProtocolGuid [Pcd] diff --git a/EdkCompatibilityPkg/EdkCompatibilityPkg.dsc b/EdkCompatibilityPkg/EdkCompatibilityPkg.dsc index 016e9adeedf3..eca611de07e4 100644 --- a/EdkCompatibilityPkg/EdkCompatibilityPkg.dsc +++ b/EdkCompatibilityPkg/EdkCompatibilityPkg.dsc @@ -72,6 +72,7 @@ DEFINE GCC_MACRO = -DEFI_SPECIFICATION_VERSION=0x00020000 -DPI_S LocalApicLib|UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.inf DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf LockBoxLib|MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.inf + SmmMemLib|MdePkg/Library/SmmMemLib/SmmMemLib.inf [LibraryClasses.common.PEIM] MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf @@ -84,6 +85,7 @@ DEFINE GCC_MACRO = -DEFI_SPECIFICATION_VERSION=0x00020000 -DPI_S SmmServicesTableLib|MdePkg/Library/SmmServicesTableLib/SmmServicesTableLib.inf ReportStatusCodeLib|MdeModulePkg/Library/SmmReportStatusCodeLib/SmmReportStatusCodeLib.inf MemoryAllocationLib|MdePkg/Library/SmmMemoryAllocationLib/SmmMemoryAllocationLib.inf + HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf [BuildOptions.Common.EDK] GCC:*_*_IA32_CC_FLAGS = -DEFI32 $(GCC_MACRO) From bb44a4d107b7355d2daca93b679285cb5fd496c9 Mon Sep 17 00:00:00 2001 From: Liming Gao Date: Fri, 18 Dec 2015 05:45:12 +0000 Subject: [PATCH 259/525] DuetPkg: Fix GCC error to avoid the duplicated global variables in EfiLdr Move the global variable definitions into source code instead of head filer. (Sync patch r19338 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Liming Gao Reviewed-by: Jeff Fan git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19355 6f19259b-4bc3-4df7-8a09-765794883524 --- DuetPkg/EfiLdr/EfiLdr.h | 3 --- DuetPkg/EfiLdr/EfiLoader.c | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/DuetPkg/EfiLdr/EfiLdr.h b/DuetPkg/EfiLdr/EfiLdr.h index 665f40585507..4f21cf3f790f 100644 --- a/DuetPkg/EfiLdr/EfiLdr.h +++ b/DuetPkg/EfiLdr/EfiLdr.h @@ -80,9 +80,6 @@ typedef struct { BIOS_MEMORY_MAP_ENTRY MemoryMapEntry[1]; } BIOS_MEMORY_MAP; -EFILDR_LOADED_IMAGE DxeCoreImage; -EFILDR_LOADED_IMAGE DxeIplImage; - typedef VOID (EFIAPI * EFI_MAIN_ENTRYPOINT) ( diff --git a/DuetPkg/EfiLdr/EfiLoader.c b/DuetPkg/EfiLdr/EfiLoader.c index 691302765074..b23966e5ee1a 100644 --- a/DuetPkg/EfiLdr/EfiLoader.c +++ b/DuetPkg/EfiLdr/EfiLoader.c @@ -24,6 +24,9 @@ Revision History: #include "PeLoader.h" #include "LzmaDecompress.h" +EFILDR_LOADED_IMAGE DxeCoreImage; +EFILDR_LOADED_IMAGE DxeIplImage; + VOID SystemHang ( CHAR8 *Message From b95380aa266cf3e2869e7cd69ded5621f332d281 Mon Sep 17 00:00:00 2001 From: Liming Gao Date: Fri, 18 Dec 2015 05:45:52 +0000 Subject: [PATCH 260/525] DuetPkg: Fix GCC error to avoid the duplicated global variable in SmbiosGenDxe Update SmbiosGenDxe to use UefiHiiServicesLib. (Sync patch r19339 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Liming Gao Reviewed-by: Jeff Fan git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19356 6f19259b-4bc3-4df7-8a09-765794883524 --- DuetPkg/SmbiosGenDxe/SmbiosGen.c | 11 ----------- DuetPkg/SmbiosGenDxe/SmbiosGen.h | 1 + DuetPkg/SmbiosGenDxe/SmbiosGen.inf | 1 + 3 files changed, 2 insertions(+), 11 deletions(-) diff --git a/DuetPkg/SmbiosGenDxe/SmbiosGen.c b/DuetPkg/SmbiosGenDxe/SmbiosGen.c index 03e093639b64..393bb4d374e5 100644 --- a/DuetPkg/SmbiosGenDxe/SmbiosGen.c +++ b/DuetPkg/SmbiosGenDxe/SmbiosGen.c @@ -18,7 +18,6 @@ Module Name: **/ #include "SmbiosGen.h" -EFI_HII_DATABASE_PROTOCOL *gHiiDatabase; extern UINT8 SmbiosGenDxeStrings[]; EFI_SMBIOS_PROTOCOL *gSmbios; EFI_HII_HANDLE gStringHandle; @@ -211,16 +210,6 @@ SmbiosGenEntrypoint ( if (EFI_ERROR (Status)) { return Status; } - - Status = gBS->LocateProtocol ( - &gEfiHiiDatabaseProtocolGuid, - NULL, - (VOID**)&gHiiDatabase - ); - - if (EFI_ERROR (Status)) { - return Status; - } gStringHandle = HiiAddPackages ( &gEfiCallerIdGuid, diff --git a/DuetPkg/SmbiosGenDxe/SmbiosGen.h b/DuetPkg/SmbiosGenDxe/SmbiosGen.h index 0474366b04c8..3a42e22887c6 100644 --- a/DuetPkg/SmbiosGenDxe/SmbiosGen.h +++ b/DuetPkg/SmbiosGenDxe/SmbiosGen.h @@ -39,6 +39,7 @@ Module Name: #include #include #include +#include #define PRODUCT_NAME L"DUET" #define PRODUCT_VERSION L"Beta" diff --git a/DuetPkg/SmbiosGenDxe/SmbiosGen.inf b/DuetPkg/SmbiosGenDxe/SmbiosGen.inf index e413beb7f38d..c8568dabe474 100644 --- a/DuetPkg/SmbiosGenDxe/SmbiosGen.inf +++ b/DuetPkg/SmbiosGenDxe/SmbiosGen.inf @@ -41,6 +41,7 @@ UefiDriverEntryPoint BaseLib HiiLib + UefiHiiServicesLib [Sources] SmbiosGen.c From 2f10bcddc5be6f4809f3fd2874999627c2fa6b1b Mon Sep 17 00:00:00 2001 From: Jeff Fan Date: Fri, 18 Dec 2015 05:46:37 +0000 Subject: [PATCH 261/525] UefiCpuPkg/CpuMpPei: Fix pack(1) issue on x64 arch Packing alignment for MP_CPU_EXCHANGE_INFO should be 1. This should be typo when check-in CpuMpPei driver. IA32 arch MP_CPU_EXCHANGE_INFO is luckly pack(1). It leads CpuMpPei x64 version hung. (Sync patch r19340 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Reported-by: Michael Kinney Cc: Feng Tian Cc: Michael Kinney Cc: Jordan Justen Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan Tested-by: Michael Kinney Reviewed-by: Michael Kinney git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19357 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/CpuMpPei/CpuMpPei.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.h b/UefiCpuPkg/CpuMpPei/CpuMpPei.h index f2286b990ee9..2b960c6eb1fe 100644 --- a/UefiCpuPkg/CpuMpPei/CpuMpPei.h +++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.h @@ -72,7 +72,7 @@ typedef struct { typedef struct _PEI_CPU_MP_DATA PEI_CPU_MP_DATA; -#pragma pack() +#pragma pack(1) typedef union { struct { @@ -95,6 +95,8 @@ typedef union { // // MP CPU exchange information for AP reset code +// This structure is required to be packed because fixed field offsets +// into this structure are used in assembly code in this module // typedef struct { UINTN Lock; From 75cffb4d2e62d7be3d78d50ec97978fdfad570b4 Mon Sep 17 00:00:00 2001 From: Jeff Fan Date: Fri, 18 Dec 2015 05:47:12 +0000 Subject: [PATCH 262/525] UefiCpuPkg: Add PCD PcdCpuApLoopMode This new PCD is used to specify the AP loop mode during POST phase. The value 1 means we will place AP in the Hlt-Loop state by HLT instruction. BSP need to send INIT-SIPI-SIPI to wake up APs. The value 2 means we will place AP in the deepest C-state by MWAIT instruction. BSP need to modify the monitor buffer by MONITOR instruction to wake up APs. The value 3 means we will place AP in the Run-loop state. APs are running. BSP need to write one semaphore to wake up APs. (Sync patch r19341 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Cc: Feng Tian Cc: Michael Kinney Cc: Jordan Justen Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan Tested-by: Michael Kinney Reviewed-by: Michael Kinney git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19358 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/UefiCpuPkg.dec | 8 ++++++++ UefiCpuPkg/UefiCpuPkg.uni | Bin 22498 -> 22980 bytes 2 files changed, 8 insertions(+) diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec index a6941466891e..0d42918427ea 100644 --- a/UefiCpuPkg/UefiCpuPkg.dec +++ b/UefiCpuPkg/UefiCpuPkg.dec @@ -182,6 +182,14 @@ ## Specifies the size of the microcode Region. # @Prompt Microcode Region size. gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchRegionSize|0x0|UINT64|0x00000006 + ## Specifies the AP wait loop state during POST phase. + # The value is defined as below.

+ # 1: Place AP in the Hlt-Loop state.
+ # 2: Place AP in the Mwait-Loop state.
+ # 3: Place AP in the Run-Loop state.
+ # @Prompt The AP wait loop state. + # @ValidRange 0x80000001 | 1 - 3 + gUefiCpuPkgTokenSpaceGuid.PcdCpuApLoopMode|1|UINT8|0x60008006 [PcdsDynamic, PcdsDynamicEx] ## Contains the pointer to a CPU S3 data buffer of structure ACPI_CPU_DATA. diff --git a/UefiCpuPkg/UefiCpuPkg.uni b/UefiCpuPkg/UefiCpuPkg.uni index 4011cfd1816b133ea82e64335f35332c2fc7e656..b4c5376ca8c14132dcd12c30f0c1499599195d48 100644 GIT binary patch delta 178 zcmaE~p7F?L#to0cCm)cA;C5svVDMqc2f~8MhQ79w*93AXJ2C_?C@_>WBr;?&lmJ;d z5P2Z07|2fq;?&8G{OSBqeGI-p`4pg-VYqJy5qg2 Date: Fri, 18 Dec 2015 05:47:48 +0000 Subject: [PATCH 263/525] UefiCpuPkg: Add PCD PcdCpuApTargetCstate This new PCD is used to specify the AP C-state value by MWAIT instruction. More deeper C-state means more longer latency time when APs exiting from MWAIT state. Platforms need to balance the performance and power saving to find the proper C-state for APs. Also, some processor may not ready for the deepest C-state at the beginning. Platform also could choose the proper chance to place AP into the deeper C-state by set this PCD before hand-off to OS. (Sync patch r19342 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Cc: Feng Tian Cc: Michael Kinney Cc: Jordan Justen Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan Reviewed-by: Michael Kinney git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19359 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/UefiCpuPkg.dec | 5 +++++ UefiCpuPkg/UefiCpuPkg.uni | Bin 22980 -> 23534 bytes 2 files changed, 5 insertions(+) diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec index 0d42918427ea..472b38acbc1e 100644 --- a/UefiCpuPkg/UefiCpuPkg.dec +++ b/UefiCpuPkg/UefiCpuPkg.dec @@ -190,6 +190,11 @@ # @Prompt The AP wait loop state. # @ValidRange 0x80000001 | 1 - 3 gUefiCpuPkgTokenSpaceGuid.PcdCpuApLoopMode|1|UINT8|0x60008006 + ## Specifies the AP target C-state for Mwait during POST phase. + # The default value 0 means C1 state. + # The value is defined as below.

+ # @Prompt The specified AP target C-state for Mwait. + gUefiCpuPkgTokenSpaceGuid.PcdCpuApTargetCstate|0|UINT8|0x00000007 [PcdsDynamic, PcdsDynamicEx] ## Contains the pointer to a CPU S3 data buffer of structure ACPI_CPU_DATA. diff --git a/UefiCpuPkg/UefiCpuPkg.uni b/UefiCpuPkg/UefiCpuPkg.uni index b4c5376ca8c14132dcd12c30f0c1499599195d48..9fbc7310fd30d3349fc2c9a6b26029cc6f739b2f 100644 GIT binary patch delta 203 zcmX@Inep9r#tlazCm)cAm@E*=kL=*XXr Q!!E_hP<>KOn;dBf0QUqgOaK4? delta 9 QcmaF2o$<(K#tlaz0U9y{>;M1& From 6be91122b1b3303f6c97a9545a300021acc3e9c1 Mon Sep 17 00:00:00 2001 From: Jeff Fan Date: Fri, 18 Dec 2015 05:48:45 +0000 Subject: [PATCH 264/525] UefiCpuPkg/CpuMpPei: Add GetApLoopMode() to get AP loop mode Add GetApLoopMode() that will get PCD PcdCpuApLoopMode firstly. If it is ApInMwaitLoop, we will check if MONITOR/MWAIT feature supported by CPUID. If MONITOR/MWAIT feature is not supported, force AP loop mode to ApInHltLoop. GetApLoopMode() also return the largest line size required. (Sync patch r19343 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Cc: Feng Tian Cc: Michael Kinney Cc: Jordan Justen Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan Signed-off-by: Michael Kinney Tested-by: Michael Kinney Reviewed-by: Michael Kinney git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19360 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/CpuMpPei/CpuMpPei.c | 48 +++++++++++++++++++++++++++++ UefiCpuPkg/CpuMpPei/CpuMpPei.h | 6 ++++ UefiCpuPkg/CpuMpPei/CpuMpPei.inf | 1 + UefiCpuPkg/Include/Register/Cpuid.h | 2 ++ 4 files changed, 57 insertions(+) diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.c b/UefiCpuPkg/CpuMpPei/CpuMpPei.c index 2e6e7611a261..ac609a01f8cc 100644 --- a/UefiCpuPkg/CpuMpPei/CpuMpPei.c +++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.c @@ -117,6 +117,54 @@ ApFuncEnableX2Apic ( SetApicMode (LOCAL_APIC_MODE_X2APIC); } +/** + Get AP loop mode. + + @param MonitorFilterSize Returns the largest monitor-line size in bytes. + + @return The AP loop mode. +**/ +UINT8 +GetApLoopMode ( + OUT UINT16 *MonitorFilterSize + ) +{ + UINT8 ApLoopMode; + UINT32 RegEbx; + UINT32 RegEcx; + UINT32 RegEdx; + + ASSERT (MonitorFilterSize != NULL); + + ApLoopMode = PcdGet8 (PcdCpuApLoopMode); + ASSERT (ApLoopMode >= ApInHltLoop && ApLoopMode <= ApInRunLoop); + if (ApLoopMode == ApInMwaitLoop) { + AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, &RegEcx, NULL); + if ((RegEcx & BIT3) == 0) { + // + // If processor does not support MONITOR/MWAIT feature + // by CPUID.[EAX=01H]:ECX.BIT3, force AP in Hlt-loop mode + // + ApLoopMode = ApInHltLoop; + } + } + + if (ApLoopMode == ApInHltLoop) { + *MonitorFilterSize = 0; + } else if (ApLoopMode == ApInRunLoop) { + *MonitorFilterSize = sizeof (UINT32); + } else if (ApLoopMode == ApInMwaitLoop) { + // + // CPUID.[EAX=05H]:EBX.BIT0-15: Largest monitor-line size in bytes + // CPUID.[EAX=05H].EDX: C-states supported using MWAIT + // + AsmCpuid (CPUID_MONITOR_MWAIT, NULL, &RegEbx, NULL, &RegEdx); + *MonitorFilterSize = RegEbx & 0xFFFF; + } + + return ApLoopMode; +} + /** Get CPU MP Data pointer from the Guided HOB. diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.h b/UefiCpuPkg/CpuMpPei/CpuMpPei.h index 2b960c6eb1fe..be4e31237747 100644 --- a/UefiCpuPkg/CpuMpPei/CpuMpPei.h +++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.h @@ -50,6 +50,12 @@ typedef enum { CpuStateDisabled } CPU_STATE; +typedef enum { + ApInHltLoop = 1, + ApInMwaitLoop = 2, + ApInRunLoop = 3 +} AP_LOOP_MODE; + // // AP reset code information // diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.inf b/UefiCpuPkg/CpuMpPei/CpuMpPei.inf index 423f7f10ed52..4a5cfe75ff95 100644 --- a/UefiCpuPkg/CpuMpPei/CpuMpPei.inf +++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.inf @@ -81,6 +81,7 @@ gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize ## CONSUMES gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchAddress ## CONSUMES gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchRegionSize ## CONSUMES + gUefiCpuPkgTokenSpaceGuid.PcdCpuApLoopMode ## CONSUMES [Depex] gEfiPeiMemoryDiscoveredPpiGuid diff --git a/UefiCpuPkg/Include/Register/Cpuid.h b/UefiCpuPkg/Include/Register/Cpuid.h index 6730551ff8cd..f8ff247d098f 100644 --- a/UefiCpuPkg/Include/Register/Cpuid.h +++ b/UefiCpuPkg/Include/Register/Cpuid.h @@ -31,6 +31,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #define CPUID_CACHE_PARAMS 0x4 +#define CPUID_MONITOR_MWAIT 0x5 + #define CPUID_EXTENDED_TOPOLOGY 0xB #define CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_INVALID 0x0 #define CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT 0x1 From 18be815babcb4537128753b40b60aa257a6ece88 Mon Sep 17 00:00:00 2001 From: Jeff Fan Date: Fri, 18 Dec 2015 05:49:28 +0000 Subject: [PATCH 265/525] UefiCpuPkg/CpuMpPei: Prepare for monitor buffer Get AP loop mode to prepare for the monitor buffer required for ApInMwaitLoop and ApInRunLoop. (Sync patch r19344 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Cc: Feng Tian Cc: Michael Kinney Cc: Jordan Justen Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan Tested-by: Michael Kinney Reviewed-by: Michael Kinney git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19361 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/CpuMpPei/CpuMpPei.c | 25 +++++++++++++++++++++++-- UefiCpuPkg/CpuMpPei/CpuMpPei.h | 3 +++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.c b/UefiCpuPkg/CpuMpPei/CpuMpPei.c index ac609a01f8cc..b8fa5118b45a 100644 --- a/UefiCpuPkg/CpuMpPei/CpuMpPei.c +++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.c @@ -589,6 +589,10 @@ PrepareAPStartupVector ( UINTN WakeupBuffer; UINTN WakeupBufferSize; MP_ASSEMBLY_ADDRESS_MAP AddressMap; + UINT8 ApLoopMode; + UINT16 MonitorFilterSize; + UINT8 *MonitorBuffer; + UINTN Index; AsmGetAddressMap (&AddressMap); WakeupBufferSize = AddressMap.RendezvousFunnelSize + sizeof (MP_CPU_EXCHANGE_INFO); @@ -597,11 +601,14 @@ PrepareAPStartupVector ( DEBUG ((EFI_D_INFO, "CpuMpPei: WakeupBuffer = 0x%x\n", WakeupBuffer)); // - // Allocate Pages for APs stack, CPU MP Data and backup buffer for wakeup buffer + // Allocate Pages for APs stack, CPU MP Data, backup buffer for wakeup buffer, + // and monitor buffer if required. // MaxCpuCount = PcdGet32(PcdCpuMaxLogicalProcessorNumber); BufferSize = PcdGet32 (PcdCpuApStackSize) * MaxCpuCount + sizeof (PEI_CPU_MP_DATA) + WakeupBufferSize + sizeof (PEI_CPU_DATA) * MaxCpuCount; + ApLoopMode = GetApLoopMode (&MonitorFilterSize); + BufferSize += MonitorFilterSize * MaxCpuCount; Status = PeiServicesAllocatePages ( EfiBootServicesData, EFI_SIZE_TO_PAGES (BufferSize), @@ -627,7 +634,21 @@ PrepareAPStartupVector ( InitializeSpinLock(&PeiCpuMpData->MpLock); SaveVolatileRegisters (&PeiCpuMpData->CpuData[0].VolatileRegisters); CopyMem (&PeiCpuMpData->AddressMap, &AddressMap, sizeof (MP_ASSEMBLY_ADDRESS_MAP)); - + // + // Initialize AP loop mode + // + PeiCpuMpData->ApLoopMode = ApLoopMode; + DEBUG ((EFI_D_INFO, "AP Loop Mode is %d\n", PeiCpuMpData->ApLoopMode)); + MonitorBuffer = (UINT8 *)(PeiCpuMpData->CpuData + MaxCpuCount); + if (PeiCpuMpData->ApLoopMode != ApInHltLoop) { + // + // Set up APs wakeup signal buffer + // + for (Index = 0; Index < MaxCpuCount; Index++) { + PeiCpuMpData->CpuData[Index].StartupApSignal = + (UINT32 *)(MonitorBuffer + MonitorFilterSize * Index); + } + } // // Backup original data and copy AP reset code in it // diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.h b/UefiCpuPkg/CpuMpPei/CpuMpPei.h index be4e31237747..a22bae700542 100644 --- a/UefiCpuPkg/CpuMpPei/CpuMpPei.h +++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.h @@ -134,6 +134,7 @@ typedef struct { } CPU_VOLATILE_REGISTERS; typedef struct { + volatile UINT32 *StartupApSignal; UINT32 ApicId; EFI_HEALTH_FLAGS Health; CPU_STATE State; @@ -163,6 +164,8 @@ struct _PEI_CPU_MP_DATA { CPU_EXCHANGE_ROLE_INFO BSPInfo; CPU_EXCHANGE_ROLE_INFO APInfo; MTRR_SETTINGS MtrrTable; + UINT8 ApLoopMode; + UINT8 ApTargetCState; PEI_CPU_DATA *CpuData; volatile MP_CPU_EXCHANGE_INFO *MpCpuExchangeInfo; }; From e6c1d069fd25ef5db7a53a0cb1686b39d014da03 Mon Sep 17 00:00:00 2001 From: Jeff Fan Date: Fri, 18 Dec 2015 05:50:19 +0000 Subject: [PATCH 266/525] UefiCpuPkg/CpuMpPei: Place APs in proper loop mode after AP execution After AP function is executed, we will place AP in proper loop mode. Because AP maybe waken up by SMI or other reasons. We need to read signature in monitor buffer to check if APs is waken up by BSP. If it is not waken up by BSP, we will continue to place them into proper loop mode. (Sync patch r19345 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Cc: Feng Tian Cc: Michael Kinney Cc: Jordan Justen Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan Tested-by: Michael Kinney Reviewed-by: Michael Kinney git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19362 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/CpuMpPei/CpuMpPei.c | 148 +++++++++++++++++++++---------- UefiCpuPkg/CpuMpPei/CpuMpPei.h | 3 + UefiCpuPkg/CpuMpPei/CpuMpPei.inf | 1 + 3 files changed, 106 insertions(+), 46 deletions(-) diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.c b/UefiCpuPkg/CpuMpPei/CpuMpPei.c index b8fa5118b45a..ba82ba42184d 100644 --- a/UefiCpuPkg/CpuMpPei/CpuMpPei.c +++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.c @@ -273,68 +273,124 @@ ApCFunction ( UINTN ProcessorNumber; EFI_AP_PROCEDURE Procedure; UINTN BistData; + volatile UINT32 *ApStartupSignalBuffer; PeiCpuMpData = ExchangeInfo->PeiCpuMpData; - if (PeiCpuMpData->InitFlag) { - ProcessorNumber = NumApsExecuting; - // - // Sync BSP's Control registers to APs - // - RestoreVolatileRegisters (&PeiCpuMpData->CpuData[0].VolatileRegisters, FALSE); - // - // This is first time AP wakeup, get BIST information from AP stack - // - BistData = *(UINTN *) (PeiCpuMpData->Buffer + ProcessorNumber * PeiCpuMpData->CpuApStackSize - sizeof (UINTN)); - PeiCpuMpData->CpuData[ProcessorNumber].Health.Uint32 = (UINT32) BistData; - PeiCpuMpData->CpuData[ProcessorNumber].ApicId = GetInitialApicId (); - if (PeiCpuMpData->CpuData[ProcessorNumber].ApicId >= 0xFF) { + while (TRUE) { + if (PeiCpuMpData->InitFlag) { + ProcessorNumber = NumApsExecuting; + // + // Sync BSP's Control registers to APs + // + RestoreVolatileRegisters (&PeiCpuMpData->CpuData[0].VolatileRegisters, FALSE); + // + // This is first time AP wakeup, get BIST information from AP stack + // + BistData = *(UINTN *) (PeiCpuMpData->Buffer + ProcessorNumber * PeiCpuMpData->CpuApStackSize - sizeof (UINTN)); + PeiCpuMpData->CpuData[ProcessorNumber].Health.Uint32 = (UINT32) BistData; + PeiCpuMpData->CpuData[ProcessorNumber].ApicId = GetInitialApicId (); + if (PeiCpuMpData->CpuData[ProcessorNumber].ApicId >= 0xFF) { + // + // Set x2APIC mode if there are any logical processor reporting + // an APIC ID of 255 or greater. + // + AcquireSpinLock(&PeiCpuMpData->MpLock); + PeiCpuMpData->X2ApicEnable = TRUE; + ReleaseSpinLock(&PeiCpuMpData->MpLock); + } + // + // Sync BSP's Mtrr table to all wakeup APs and load microcode on APs. + // + MtrrSetAllMtrrs (&PeiCpuMpData->MtrrTable); + MicrocodeDetect (); + PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateIdle; + } else { // - // Set x2APIC mode if there are any logical processor reporting - // an APIC ID of 255 or greater. + // Execute AP function if AP is not disabled // - AcquireSpinLock(&PeiCpuMpData->MpLock); - PeiCpuMpData->X2ApicEnable = TRUE; - ReleaseSpinLock(&PeiCpuMpData->MpLock); + GetProcessorNumber (PeiCpuMpData, &ProcessorNumber); + if (PeiCpuMpData->ApLoopMode == ApInHltLoop) { + // + // Restore AP's volatile registers saved + // + RestoreVolatileRegisters (&PeiCpuMpData->CpuData[ProcessorNumber].VolatileRegisters, TRUE); + } + + if ((PeiCpuMpData->CpuData[ProcessorNumber].State != CpuStateDisabled) && + (PeiCpuMpData->ApFunction != 0)) { + PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateBusy; + Procedure = (EFI_AP_PROCEDURE)(UINTN)PeiCpuMpData->ApFunction; + // + // Invoke AP function here + // + Procedure ((VOID *)(UINTN)PeiCpuMpData->ApFunctionArgument); + // + // Re-get the processor number due to BSP/AP maybe exchange in AP function + // + GetProcessorNumber (PeiCpuMpData, &ProcessorNumber); + PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateIdle; + } } + // - // Sync BSP's Mtrr table to all wakeup APs and load microcode on APs. + // AP finished executing C code // - MtrrSetAllMtrrs (&PeiCpuMpData->MtrrTable); - MicrocodeDetect (); - PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateIdle; - } else { + InterlockedIncrement ((UINT32 *)&PeiCpuMpData->FinishedCount); + // - // Execute AP function if AP is not disabled + // Place AP is specified loop mode // - GetProcessorNumber (PeiCpuMpData, &ProcessorNumber); + if (PeiCpuMpData->ApLoopMode == ApInHltLoop) { + // + // Save AP volatile registers + // + SaveVolatileRegisters (&PeiCpuMpData->CpuData[ProcessorNumber].VolatileRegisters); + // + // Place AP in Hlt-loop + // + while (TRUE) { + DisableInterrupts (); + CpuSleep (); + CpuPause (); + } + } + ApStartupSignalBuffer = PeiCpuMpData->CpuData[ProcessorNumber].StartupApSignal; // - // Restore AP's volatile registers saved + // Clear AP start-up signal // - RestoreVolatileRegisters (&PeiCpuMpData->CpuData[ProcessorNumber].VolatileRegisters, TRUE); + *ApStartupSignalBuffer = 0; + while (TRUE) { + DisableInterrupts (); + if (PeiCpuMpData->ApLoopMode == ApInMwaitLoop) { + // + // Place AP in Mwait-loop + // + AsmMonitor ((UINTN)ApStartupSignalBuffer, 0, 0); + if (*ApStartupSignalBuffer != WAKEUP_AP_SIGNAL) { + // + // If AP start-up signal is not set, place AP into + // the maximum C-state + // + AsmMwait (PeiCpuMpData->ApTargetCState << 4, 0); + } + } else if (PeiCpuMpData->ApLoopMode == ApInRunLoop) { + // + // Place AP in Run-loop + // + CpuPause (); + } else { + ASSERT (FALSE); + } - if ((PeiCpuMpData->CpuData[ProcessorNumber].State != CpuStateDisabled) && - (PeiCpuMpData->ApFunction != 0)) { - PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateBusy; - Procedure = (EFI_AP_PROCEDURE)(UINTN)PeiCpuMpData->ApFunction; // - // Invoke AP function here + // If AP start-up signal is written, AP is waken up + // otherwise place AP in loop again // - Procedure ((VOID *)(UINTN)PeiCpuMpData->ApFunctionArgument); - PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateIdle; + if (*ApStartupSignalBuffer == WAKEUP_AP_SIGNAL) { + break; + } } } - - // - // AP finished executing C code - // - InterlockedIncrement ((UINT32 *)&PeiCpuMpData->FinishedCount); - - // - // Save AP volatile registers - // - SaveVolatileRegisters (&PeiCpuMpData->CpuData[ProcessorNumber].VolatileRegisters); - - AsmCliHltLoop (); } /** diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.h b/UefiCpuPkg/CpuMpPei/CpuMpPei.h index a22bae700542..47038c282533 100644 --- a/UefiCpuPkg/CpuMpPei/CpuMpPei.h +++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.h @@ -38,6 +38,7 @@ #include #include #include +#include #include "Microcode.h" @@ -50,6 +51,8 @@ typedef enum { CpuStateDisabled } CPU_STATE; +#define WAKEUP_AP_SIGNAL SIGNATURE_32 ('S', 'T', 'A', 'P') + typedef enum { ApInHltLoop = 1, ApInMwaitLoop = 2, diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.inf b/UefiCpuPkg/CpuMpPei/CpuMpPei.inf index 4a5cfe75ff95..ec353aed7d50 100644 --- a/UefiCpuPkg/CpuMpPei/CpuMpPei.inf +++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.inf @@ -66,6 +66,7 @@ SynchronizationLib TimerLib UefiCpuLib + CpuLib [Ppis] gEfiPeiMpServicesPpiGuid ## PRODUCES From 9a10f17a9cf897fd32be38e36a4b8dcd411bee64 Mon Sep 17 00:00:00 2001 From: Jeff Fan Date: Fri, 18 Dec 2015 05:51:24 +0000 Subject: [PATCH 267/525] UefiCpuPkg/CpuMpPei: Wake up APs by proper method If ApLoopMode is ApInHltLoop, BSP will send INIT-SIPI-SIPI to wake up APs. If ApLoopMode is ApInMwaitLoop or ApInRunLoop, BSP will write one semaphore to wake up APs. (Sync patch r19346 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Cc: Feng Tian Cc: Michael Kinney Cc: Jordan Justen Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan Tested-by: Michael Kinney Reviewed-by: Michael Kinney git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19363 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/CpuMpPei/CpuMpPei.c | 43 ++++++++++++++++++++++++----- UefiCpuPkg/CpuMpPei/CpuMpPei.h | 4 +-- UefiCpuPkg/CpuMpPei/CpuMpPei.inf | 1 + UefiCpuPkg/CpuMpPei/PeiMpServices.c | 6 ++-- 4 files changed, 42 insertions(+), 12 deletions(-) diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.c b/UefiCpuPkg/CpuMpPei/CpuMpPei.c index ba82ba42184d..950d61cc4853 100644 --- a/UefiCpuPkg/CpuMpPei/CpuMpPei.c +++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.c @@ -399,7 +399,7 @@ ApCFunction ( @param PeiCpuMpData Pointer to PEI CPU MP Data @param Broadcast TRUE: Send broadcast IPI to all APs FALSE: Send IPI to AP by ApicId - @param ApicId Apic ID for the processor to be waked + @param ProcessorNumber The handle number of specified processor @param Procedure The function to be invoked by AP @param ProcedureArgument The argument to be passed into AP function **/ @@ -407,12 +407,13 @@ VOID WakeUpAP ( IN PEI_CPU_MP_DATA *PeiCpuMpData, IN BOOLEAN Broadcast, - IN UINT32 ApicId, + IN UINTN ProcessorNumber, IN EFI_AP_PROCEDURE Procedure, OPTIONAL IN VOID *ProcedureArgument OPTIONAL ) { volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo; + UINTN Index; PeiCpuMpData->ApFunction = (UINTN) Procedure; PeiCpuMpData->ApFunctionArgument = (UINTN) ProcedureArgument; @@ -436,12 +437,40 @@ WakeUpAP ( CopyMem ((VOID *)&ExchangeInfo->GdtrProfile, &mGdt, sizeof(mGdt)); AsmReadIdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->IdtrProfile); - if (Broadcast) { - SendInitSipiSipiAllExcludingSelf ((UINT32) ExchangeInfo->BufferStart); - } else { - SendInitSipiSipi (ApicId, (UINT32) ExchangeInfo->BufferStart); + if (PeiCpuMpData->ApLoopMode == ApInMwaitLoop) { + // + // Get AP target C-state each time when waking up AP, + // for it maybe updated by platform again + // + PeiCpuMpData->ApTargetCState = PcdGet8 (PcdCpuApTargetCstate); } + // + // Wakeup APs per AP loop state + // + if (PeiCpuMpData->ApLoopMode == ApInHltLoop || PeiCpuMpData->InitFlag) { + if (Broadcast) { + SendInitSipiSipiAllExcludingSelf ((UINT32) ExchangeInfo->BufferStart); + } else { + SendInitSipiSipi ( + PeiCpuMpData->CpuData[ProcessorNumber].ApicId, + (UINT32) ExchangeInfo->BufferStart + ); + } + } else if ((PeiCpuMpData->ApLoopMode == ApInMwaitLoop) || + (PeiCpuMpData->ApLoopMode == ApInRunLoop)) { + if (Broadcast) { + for (Index = 0; Index < PeiCpuMpData->CpuCount; Index++) { + if (Index != PeiCpuMpData->BspNumber) { + *(PeiCpuMpData->CpuData[Index].StartupApSignal) = WAKEUP_AP_SIGNAL; + } + } + } else { + *(PeiCpuMpData->CpuData[ProcessorNumber].StartupApSignal) = WAKEUP_AP_SIGNAL; + } + } else { + ASSERT (FALSE); + } return ; } @@ -600,7 +629,7 @@ CountProcessorNumber ( if (PeiCpuMpData->X2ApicEnable) { DEBUG ((EFI_D_INFO, "Force x2APIC mode!\n")); // - // Send 2nd broadcast IPI to all APs to enable x2APIC mode + // Wakeup all APs to enable x2APIC mode // WakeUpAP (PeiCpuMpData, TRUE, 0, ApFuncEnableX2Apic, NULL); // diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.h b/UefiCpuPkg/CpuMpPei/CpuMpPei.h index 47038c282533..6f508b420be3 100644 --- a/UefiCpuPkg/CpuMpPei/CpuMpPei.h +++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.h @@ -255,7 +255,7 @@ CpuMpEndOfPeiCallback ( @param PeiCpuMpData Pointer to PEI CPU MP Data @param Broadcast TRUE: Send broadcast IPI to all APs FALSE: Send IPI to AP by ApicId - @param ApicId Apic ID for the processor to be waked + @param ProcessorNumber The handle number of specified processor @param Procedure The function to be invoked by AP @param ProcedureArgument The argument to be passed into AP function **/ @@ -263,7 +263,7 @@ VOID WakeUpAP ( IN PEI_CPU_MP_DATA *PeiCpuMpData, IN BOOLEAN Broadcast, - IN UINT32 ApicId, + IN UINTN ProcessorNumber, IN EFI_AP_PROCEDURE Procedure, OPTIONAL IN VOID *ProcedureArgument OPTIONAL ); diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.inf b/UefiCpuPkg/CpuMpPei/CpuMpPei.inf index ec353aed7d50..70b272e33bc4 100644 --- a/UefiCpuPkg/CpuMpPei/CpuMpPei.inf +++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.inf @@ -83,6 +83,7 @@ gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchAddress ## CONSUMES gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchRegionSize ## CONSUMES gUefiCpuPkgTokenSpaceGuid.PcdCpuApLoopMode ## CONSUMES + gUefiCpuPkgTokenSpaceGuid.PcdCpuApTargetCstate ## SOMETIMES_CONSUMES [Depex] gEfiPeiMemoryDiscoveredPpiGuid diff --git a/UefiCpuPkg/CpuMpPei/PeiMpServices.c b/UefiCpuPkg/CpuMpPei/PeiMpServices.c index 5dd2c153f46a..e784377d674a 100644 --- a/UefiCpuPkg/CpuMpPei/PeiMpServices.c +++ b/UefiCpuPkg/CpuMpPei/PeiMpServices.c @@ -520,7 +520,7 @@ PeiStartupAllAPs ( if (Index == CallerNumber) { continue; } - WakeUpAP (PeiCpuMpData, FALSE, PeiCpuMpData->CpuData[Index].ApicId, Procedure, ProcedureArgument); + WakeUpAP (PeiCpuMpData, FALSE, Index, Procedure, ProcedureArgument); // // Wait to finish // @@ -655,7 +655,7 @@ PeiStartupThisAP ( WaitCountIndex = 0; FinishedCount = &PeiCpuMpData->FinishedCount; - WakeUpAP (PeiCpuMpData, FALSE, PeiCpuMpData->CpuData[ProcessorNumber].ApicId, Procedure, ProcedureArgument); + WakeUpAP (PeiCpuMpData, FALSE, ProcessorNumber, Procedure, ProcedureArgument); // // Wait to finish @@ -791,7 +791,7 @@ PeiSwitchBSP ( // // Need to wakeUp AP (future BSP). // - WakeUpAP (PeiCpuMpData, FALSE, PeiCpuMpData->CpuData[ProcessorNumber].ApicId, FutureBSPProc, PeiCpuMpData); + WakeUpAP (PeiCpuMpData, FALSE, ProcessorNumber, FutureBSPProc, PeiCpuMpData); AsmExchangeRole (&PeiCpuMpData->BSPInfo, &PeiCpuMpData->APInfo); From e5cdee8d1de3af6e939b40ab372f946d6161dbb3 Mon Sep 17 00:00:00 2001 From: Jeff Fan Date: Fri, 18 Dec 2015 05:53:03 +0000 Subject: [PATCH 268/525] UefiCpuPkg/CpuMpPei: Remove un-used AsmCliHltLoop() (Sync patch r19347 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Cc: Feng Tian Cc: Michael Kinney Cc: Jordan Justen Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan Tested-by: Michael Kinney Reviewed-by: Michael Kinney git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19364 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/CpuMpPei/CpuMpPei.h | 10 ---------- UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.asm | 6 ------ UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.nasm | 6 ------ UefiCpuPkg/CpuMpPei/X64/MpFuncs.asm | 6 ------ UefiCpuPkg/CpuMpPei/X64/MpFuncs.nasm | 6 ------ 5 files changed, 34 deletions(-) diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.h b/UefiCpuPkg/CpuMpPei/CpuMpPei.h index 6f508b420be3..7c8a218e0ee3 100644 --- a/UefiCpuPkg/CpuMpPei/CpuMpPei.h +++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.h @@ -198,16 +198,6 @@ AsmInitializeGdt ( IN IA32_DESCRIPTOR *Gdtr ); -/** - Assembly code to do CLI-HALT loop. - -**/ -VOID -EFIAPI -AsmCliHltLoop ( - VOID - ); - /** Get available system memory below 1MB by specified size. diff --git a/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.asm b/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.asm index eb23a1691762..ab78bcc07b59 100644 --- a/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.asm +++ b/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.asm @@ -144,12 +144,6 @@ CProcedureInvoke: RendezvousFunnelProc ENDP RendezvousFunnelProcEnd:: -AsmCliHltLoop PROC near C PUBLIC - cli - hlt - jmp $-2 -AsmCliHltLoop ENDP - ;------------------------------------------------------------------------------------- ; AsmGetAddressMap (&AddressMap); ;------------------------------------------------------------------------------------- diff --git a/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.nasm b/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.nasm index 5d2da82d148c..2ff16dc297bc 100644 --- a/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.nasm +++ b/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.nasm @@ -132,12 +132,6 @@ CProcedureInvoke: jmp $ ; never reach here RendezvousFunnelProcEnd: -global ASM_PFX(AsmCliHltLoop) -ASM_PFX(AsmCliHltLoop): - cli - hlt - jmp $-2 - ;------------------------------------------------------------------------------------- ; AsmGetAddressMap (&AddressMap); ;------------------------------------------------------------------------------------- diff --git a/UefiCpuPkg/CpuMpPei/X64/MpFuncs.asm b/UefiCpuPkg/CpuMpPei/X64/MpFuncs.asm index fad5e8d443ce..1bb3b6d6b668 100644 --- a/UefiCpuPkg/CpuMpPei/X64/MpFuncs.asm +++ b/UefiCpuPkg/CpuMpPei/X64/MpFuncs.asm @@ -181,12 +181,6 @@ CProcedureInvoke: RendezvousFunnelProc ENDP RendezvousFunnelProcEnd:: -AsmCliHltLoop PROC - cli - hlt - jmp $-2 -AsmCliHltLoop ENDP - ;------------------------------------------------------------------------------------- ; AsmGetAddressMap (&AddressMap); ;------------------------------------------------------------------------------------- diff --git a/UefiCpuPkg/CpuMpPei/X64/MpFuncs.nasm b/UefiCpuPkg/CpuMpPei/X64/MpFuncs.nasm index 0b2e879905a4..00e5f5875860 100644 --- a/UefiCpuPkg/CpuMpPei/X64/MpFuncs.nasm +++ b/UefiCpuPkg/CpuMpPei/X64/MpFuncs.nasm @@ -175,12 +175,6 @@ CProcedureInvoke: RendezvousFunnelProcEnd: -global ASM_PFX(AsmCliHltLoop) -ASM_PFX(AsmCliHltLoop): - cli - hlt - jmp $-2 - ;------------------------------------------------------------------------------------- ; AsmGetAddressMap (&AddressMap); ;------------------------------------------------------------------------------------- From 36f30d41c5ade03206d9f1d5fdb652a382322dac Mon Sep 17 00:00:00 2001 From: Eric Dong Date: Fri, 18 Dec 2015 06:07:50 +0000 Subject: [PATCH 269/525] DxeTpmMeasureBootLib: Change global variable name to avoid name conflict. (Sync patch r19334 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Eric Dong Reviewed-by: Liming Gao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19366 6f19259b-4bc3-4df7-8a09-765794883524 --- .../DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c index cd48a1a9773a..25788b854937 100644 --- a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c +++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c @@ -53,7 +53,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. BOOLEAN mMeasureGptTableFlag = FALSE; UINTN mMeasureGptCount = 0; VOID *mFileBuffer; -UINTN mImageSize; +UINTN mTpmImageSize; // // Measured FV handle cache // @@ -95,11 +95,11 @@ DxeTpmMeasureBootLibImageRead ( } EndPosition = FileOffset + *ReadSize; - if (EndPosition > mImageSize) { - *ReadSize = (UINT32)(mImageSize - FileOffset); + if (EndPosition > mTpmImageSize) { + *ReadSize = (UINT32)(mTpmImageSize - FileOffset); } - if (FileOffset >= mImageSize) { + if (FileOffset >= mTpmImageSize) { *ReadSize = 0; } @@ -908,7 +908,7 @@ DxeTpmMeasureBootHandler ( goto Finish; } - mImageSize = FileSize; + mTpmImageSize = FileSize; mFileBuffer = FileBuffer; // From 818e60d95106bd68679bf4be1cef67f0d0af4b6c Mon Sep 17 00:00:00 2001 From: Yonghong Zhu Date: Fri, 18 Dec 2015 06:41:38 +0000 Subject: [PATCH 270/525] BaseTools/toolsetup.bat: fixed the error when the path contains space We have a new simple and effective method to resolve the original issue that the PATH env's update error when the path contains space, so this patch remove the last check in and use the new method to fix the original issue. (Sync patch r19028 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Yonghong Zhu Reviewed-by: Liming Gao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19368 6f19259b-4bc3-4df7-8a09-765794883524 --- BaseTools/toolsetup.bat | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/BaseTools/toolsetup.bat b/BaseTools/toolsetup.bat index 310ddd030c07..76fd8bb6ef9e 100755 --- a/BaseTools/toolsetup.bat +++ b/BaseTools/toolsetup.bat @@ -322,24 +322,13 @@ goto end echo !!! WARNING !!! Will not be able to compile Python programs to .exe echo Will setup environment to run Python scripts directly. echo. - goto UpdatePATH + set "PATH=%BASETOOLS_PYTHON_SOURCE%\Trim;%PATH%" + set "PATH=%BASETOOLS_PYTHON_SOURCE%\GenFds;%PATH%" + set "PATH=%BASETOOLS_PYTHON_SOURCE%\build;%PATH%" + set PATHEXT=%PATHEXT%;.py ) - else ( - goto UpdateEnv - ) - ) - else ( - goto UpdateEnv ) - -:UpdatePATH - set PATH=%BASETOOLS_PYTHON_SOURCE%\Trim;%PATH% - set PATH=%BASETOOLS_PYTHON_SOURCE%\GenFds;%PATH% - set PATH=%BASETOOLS_PYTHON_SOURCE%\build;%PATH% - set PATHEXT=%PATHEXT%;.py - goto UpdateEnv - -:UpdateEnv + echo BASE_TOOLS_PATH = %BASE_TOOLS_PATH% echo PYTHON_PATH = %PYTHON_PATH% echo PYTHON_FREEZER_PATH = %PYTHON_FREEZER_PATH% From 253a4b8ccbb4a984189eb29c48c25f6ef266ca80 Mon Sep 17 00:00:00 2001 From: Yonghong Zhu Date: Fri, 18 Dec 2015 06:43:57 +0000 Subject: [PATCH 271/525] BaseTools: Clean some coding style issues This patch clean some coding style issues, majorly for space character. (Sync patch r19080 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Yonghong Zhu Reviewed-by: Liming Gao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19369 6f19259b-4bc3-4df7-8a09-765794883524 --- BaseTools/Source/Python/AutoGen/AutoGen.py | 206 ++++++------ .../Source/Python/AutoGen/BuildEngine.py | 20 +- BaseTools/Source/Python/AutoGen/GenDepex.py | 4 +- BaseTools/Source/Python/AutoGen/GenMake.py | 12 +- BaseTools/Source/Python/AutoGen/GenPcdDb.py | 8 +- BaseTools/Source/Python/AutoGen/StrGather.py | 20 +- .../Source/Python/AutoGen/UniClassObject.py | 8 +- BaseTools/Source/Python/BPDG/GenVpd.py | 298 +++++++++--------- BaseTools/Source/Python/Common/Dictionary.py | 8 +- .../Source/Python/Common/EdkIIWorkspace.py | 24 +- .../Source/Python/Common/FdfParserLite.py | 8 +- .../Python/Common/MigrationUtilities.py | 4 +- BaseTools/Source/Python/Common/Misc.py | 62 ++-- .../Python/Common/ToolDefClassObject.py | 6 +- BaseTools/Source/Python/GenFds/GenFds.py | 14 +- .../Python/GenFds/GenFdsGlobalVariable.py | 38 +-- BaseTools/Source/Python/GenFds/GuidSection.py | 64 ++-- BaseTools/Source/Python/GenFds/Region.py | 44 +-- BaseTools/Source/Python/GenFds/UiSection.py | 2 +- BaseTools/Source/Python/GenFds/VerSection.py | 2 +- BaseTools/Source/Python/GenFds/Vtf.py | 98 +++--- .../GenPatchPcdTable/GenPatchPcdTable.py | 20 +- .../Python/PatchPcdValue/PatchPcdValue.py | 18 +- BaseTools/Source/Python/Table/TableReport.py | 10 +- .../Source/Python/Workspace/MetaFileParser.py | 2 +- .../Python/Workspace/WorkspaceDatabase.py | 34 +- BaseTools/Source/Python/build/BuildReport.py | 30 +- BaseTools/Source/Python/build/build.py | 50 +-- 28 files changed, 557 insertions(+), 557 deletions(-) diff --git a/BaseTools/Source/Python/AutoGen/AutoGen.py b/BaseTools/Source/Python/AutoGen/AutoGen.py index fe565743576b..4c627dfb555a 100644 --- a/BaseTools/Source/Python/AutoGen/AutoGen.py +++ b/BaseTools/Source/Python/AutoGen/AutoGen.py @@ -232,7 +232,7 @@ class WorkspaceAutoGen(AutoGen): # @param SkuId SKU id from command line # def _Init(self, WorkspaceDir, ActivePlatform, Target, Toolchain, ArchList, MetaFileDb, - BuildConfig, ToolDefinition, FlashDefinitionFile='', Fds=None, Fvs=None, Caps=None, SkuId='', UniFlag=None, + BuildConfig, ToolDefinition, FlashDefinitionFile='', Fds=None, Fvs=None, Caps=None, SkuId='', UniFlag=None, Progress=None, BuildModule=None): if Fds is None: Fds = [] @@ -280,7 +280,7 @@ def _Init(self, WorkspaceDir, ActivePlatform, Target, Toolchain, ArchList, MetaF # Validate build target if self.BuildTarget not in self.Platform.BuildTargets: - EdkLogger.error("build", PARAMETER_INVALID, + EdkLogger.error("build", PARAMETER_INVALID, ExtraData="Build target [%s] is not supported by the platform. [Valid target: %s]" % (self.BuildTarget, " ".join(self.Platform.BuildTargets))) @@ -288,30 +288,30 @@ def _Init(self, WorkspaceDir, ActivePlatform, Target, Toolchain, ArchList, MetaF # parse FDF file to get PCDs in it, if any if not self.FdfFile: self.FdfFile = self.Platform.FlashDefinition - + EdkLogger.info("") if self.ArchList: EdkLogger.info('%-16s = %s' % ("Architecture(s)", ' '.join(self.ArchList))) EdkLogger.info('%-16s = %s' % ("Build target", self.BuildTarget)) - EdkLogger.info('%-16s = %s' % ("Toolchain",self.ToolChain)) - + EdkLogger.info('%-16s = %s' % ("Toolchain", self.ToolChain)) + EdkLogger.info('\n%-24s = %s' % ("Active Platform", self.Platform)) if BuildModule: EdkLogger.info('%-24s = %s' % ("Active Module", BuildModule)) - + if self.FdfFile: EdkLogger.info('%-24s = %s' % ("Flash Image Definition", self.FdfFile)) EdkLogger.verbose("\nFLASH_DEFINITION = %s" % self.FdfFile) - + if Progress: Progress.Start("\nProcessing meta-data") - + if self.FdfFile: # # Mark now build in AutoGen Phase # - GlobalData.gAutoGenPhase = True + GlobalData.gAutoGenPhase = True Fdf = FdfParser(self.FdfFile.Path) Fdf.ParseFile() GlobalData.gFdfParser = Fdf @@ -336,7 +336,7 @@ def _Init(self, WorkspaceDir, ActivePlatform, Target, Toolchain, ArchList, MetaF if self.CapTargetList: EdkLogger.info("No flash definition file found. Capsule [%s] will be ignored." % " ".join(self.CapTargetList)) self.CapTargetList = [] - + # apply SKU and inject PCDs from Flash Definition file for Arch in self.ArchList: Platform = self.BuildDatabase[self.MetaFile, Arch, Target, Toolchain] @@ -391,12 +391,12 @@ def _Init(self, WorkspaceDir, ActivePlatform, Target, Toolchain, ArchList, MetaF Pa.CollectPlatformDynamicPcds() Pa.CollectFixedAtBuildPcds() self.AutoGenObjectList.append(Pa) - + # # Check PCDs token value conflict in each DEC file. # self._CheckAllPcdsTokenValueConflict() - + # # Check PCD type and definition between DSC and DEC # @@ -425,7 +425,7 @@ def _CheckDuplicateInFV(self, Fdf): # # Get INF file GUID # - InfFoundFlag = False + InfFoundFlag = False for Pa in self.AutoGenObjectList: if InfFoundFlag: break @@ -436,9 +436,9 @@ def _CheckDuplicateInFV(self, Fdf): _GuidDict[Module.Guid.upper()] = FfsFile break else: - EdkLogger.error("build", + EdkLogger.error("build", FORMAT_INVALID, - "Duplicate GUID found for these lines: Line %d: %s and Line %d: %s. GUID: %s"%(FfsFile.CurrentLineNum, + "Duplicate GUID found for these lines: Line %d: %s and Line %d: %s. GUID: %s" % (FfsFile.CurrentLineNum, FfsFile.CurrentLineContent, _GuidDict[Module.Guid.upper()].CurrentLineNum, _GuidDict[Module.Guid.upper()].CurrentLineContent, @@ -452,7 +452,7 @@ def _CheckDuplicateInFV(self, Fdf): InfPath = NormPath(FfsFile.InfFileName) if not os.path.exists(InfPath): EdkLogger.error('build', GENFDS_ERROR, "Non-existant Module %s !" % (FfsFile.InfFileName)) - + PathClassObj = PathClass(FfsFile.InfFileName, self.WorkspaceDir) # # Here we just need to get FILE_GUID from INF file, use 'COMMON' as ARCH attribute. and use @@ -462,19 +462,19 @@ def _CheckDuplicateInFV(self, Fdf): if not InfObj.Guid.upper() in _GuidDict.keys(): _GuidDict[InfObj.Guid.upper()] = FfsFile else: - EdkLogger.error("build", + EdkLogger.error("build", FORMAT_INVALID, - "Duplicate GUID found for these lines: Line %d: %s and Line %d: %s. GUID: %s"%(FfsFile.CurrentLineNum, + "Duplicate GUID found for these lines: Line %d: %s and Line %d: %s. GUID: %s" % (FfsFile.CurrentLineNum, FfsFile.CurrentLineContent, _GuidDict[InfObj.Guid.upper()].CurrentLineNum, _GuidDict[InfObj.Guid.upper()].CurrentLineContent, InfObj.Guid.upper()), ExtraData=self.FdfFile) InfFoundFlag = False - + if FfsFile.NameGuid != None: _CheckPCDAsGuidPattern = re.compile("^PCD\(.+\..+\)$") - + # # If the NameGuid reference a PCD name. # The style must match: PCD(xxxx.yyy) @@ -493,51 +493,51 @@ def _CheckDuplicateInFV(self, Fdf): # First convert from CFormatGuid to GUID string # _PcdGuidString = GuidStructureStringToGuidString(PcdItem.DefaultValue) - + if not _PcdGuidString: # # Then try Byte array. # _PcdGuidString = GuidStructureByteArrayToGuidString(PcdItem.DefaultValue) - + if not _PcdGuidString: # # Not Byte array or CFormat GUID, raise error. # EdkLogger.error("build", FORMAT_INVALID, - "The format of PCD value is incorrect. PCD: %s , Value: %s\n"%(_PcdName, PcdItem.DefaultValue), + "The format of PCD value is incorrect. PCD: %s , Value: %s\n" % (_PcdName, PcdItem.DefaultValue), ExtraData=self.FdfFile) - - if not _PcdGuidString.upper() in _GuidDict.keys(): + + if not _PcdGuidString.upper() in _GuidDict.keys(): _GuidDict[_PcdGuidString.upper()] = FfsFile PcdFoundFlag = True break else: - EdkLogger.error("build", + EdkLogger.error("build", FORMAT_INVALID, - "Duplicate GUID found for these lines: Line %d: %s and Line %d: %s. GUID: %s"%(FfsFile.CurrentLineNum, + "Duplicate GUID found for these lines: Line %d: %s and Line %d: %s. GUID: %s" % (FfsFile.CurrentLineNum, FfsFile.CurrentLineContent, _GuidDict[_PcdGuidString.upper()].CurrentLineNum, _GuidDict[_PcdGuidString.upper()].CurrentLineContent, FfsFile.NameGuid.upper()), - ExtraData=self.FdfFile) - + ExtraData=self.FdfFile) + if not FfsFile.NameGuid.upper() in _GuidDict.keys(): _GuidDict[FfsFile.NameGuid.upper()] = FfsFile else: # # Two raw file GUID conflict. # - EdkLogger.error("build", + EdkLogger.error("build", FORMAT_INVALID, - "Duplicate GUID found for these lines: Line %d: %s and Line %d: %s. GUID: %s"%(FfsFile.CurrentLineNum, + "Duplicate GUID found for these lines: Line %d: %s and Line %d: %s. GUID: %s" % (FfsFile.CurrentLineNum, FfsFile.CurrentLineContent, _GuidDict[FfsFile.NameGuid.upper()].CurrentLineNum, _GuidDict[FfsFile.NameGuid.upper()].CurrentLineContent, FfsFile.NameGuid.upper()), ExtraData=self.FdfFile) - + def _CheckPcdDefineAndType(self): PcdTypeList = [ @@ -552,17 +552,17 @@ def _CheckPcdDefineAndType(self): # Key of DSC's Pcds dictionary is PcdCName, TokenSpaceGuid for Pcd in Pa.Platform.Pcds: PcdType = Pa.Platform.Pcds[Pcd].Type - + # If no PCD type, this PCD comes from FDF if not PcdType: continue - + # Try to remove Hii and Vpd suffix if PcdType.startswith("DynamicEx"): PcdType = "DynamicEx" elif PcdType.startswith("Dynamic"): PcdType = "Dynamic" - + for Package in Pa.PackageList: # Key of DEC's Pcds dictionary is PcdCName, TokenSpaceGuid, PcdType if (Pcd[0], Pcd[1], PcdType) in Package.Pcds: @@ -640,7 +640,7 @@ def _GetBuildCommand(self): # BuildCommand should be all the same. So just get one from platform AutoGen self._BuildCommand = self.AutoGenObjectList[0].BuildCommand return self._BuildCommand - + ## Check the PCDs token value conflict in each DEC file. # # Will cause build break and raise error message while two PCDs conflict. @@ -672,12 +672,12 @@ def _CheckAllPcdsTokenValueConflict(self): # # Sort same token value PCD list with TokenGuid and TokenCName # - SameTokenValuePcdList.sort(lambda x, y: cmp("%s.%s"%(x.TokenSpaceGuidCName, x.TokenCName), "%s.%s"%(y.TokenSpaceGuidCName, y.TokenCName))) - SameTokenValuePcdListCount = 0 + SameTokenValuePcdList.sort(lambda x, y: cmp("%s.%s" % (x.TokenSpaceGuidCName, x.TokenCName), "%s.%s" % (y.TokenSpaceGuidCName, y.TokenCName))) + SameTokenValuePcdListCount = 0 while (SameTokenValuePcdListCount < len(SameTokenValuePcdList) - 1): - TemListItem = SameTokenValuePcdList[SameTokenValuePcdListCount] - TemListItemNext = SameTokenValuePcdList[SameTokenValuePcdListCount + 1] - + TemListItem = SameTokenValuePcdList[SameTokenValuePcdListCount] + TemListItemNext = SameTokenValuePcdList[SameTokenValuePcdListCount + 1] + if (TemListItem.TokenSpaceGuidCName == TemListItemNext.TokenSpaceGuidCName) and (TemListItem.TokenCName != TemListItemNext.TokenCName): EdkLogger.error( 'build', @@ -689,13 +689,13 @@ def _CheckAllPcdsTokenValueConflict(self): SameTokenValuePcdListCount += 1 Count += SameTokenValuePcdListCount Count += 1 - + PcdList = Package.Pcds.values() - PcdList.sort(lambda x, y: cmp("%s.%s"%(x.TokenSpaceGuidCName, x.TokenCName), "%s.%s"%(y.TokenSpaceGuidCName, y.TokenCName))) + PcdList.sort(lambda x, y: cmp("%s.%s" % (x.TokenSpaceGuidCName, x.TokenCName), "%s.%s" % (y.TokenSpaceGuidCName, y.TokenCName))) Count = 0 while (Count < len(PcdList) - 1) : Item = PcdList[Count] - ItemNext = PcdList[Count + 1] + ItemNext = PcdList[Count + 1] # # Check PCDs with same TokenSpaceGuidCName.TokenCName have same token value as well. # @@ -786,7 +786,7 @@ class PlatformAutoGen(AutoGen): "0x01001" : 3, # ******_TOOLCHAIN_****_***********_ATTRIBUTE "0x10001" : 2, # TARGET_*********_****_***********_ATTRIBUTE "0x00001" : 1} # ******_*********_****_***********_ATTRIBUTE (Lowest) - + ## The real constructor of PlatformAutoGen # # This method is not supposed to be called by users of PlatformAutoGen. It's @@ -960,8 +960,8 @@ def CollectPlatformDynamicPcds(self): #GuidValue.update(M.Guids) self.Platform.Modules[F].M = M - - for PcdFromModule in M.ModulePcdList+M.LibraryPcdList: + + for PcdFromModule in M.ModulePcdList + M.LibraryPcdList: # make sure that the "VOID*" kind of datum has MaxDatumSize set if PcdFromModule.DatumType == "VOID*" and PcdFromModule.MaxDatumSize in [None, '']: NoDatumTypePcdList.add("%s.%s [%s]" % (PcdFromModule.TokenSpaceGuidCName, PcdFromModule.TokenCName, F)) @@ -1111,9 +1111,9 @@ def CollectPlatformDynamicPcds(self): if (self.Workspace.ArchList[-1] == self.Arch): for Pcd in self._DynamicPcdList: # just pick the a value to determine whether is unicode string type - Sku = Pcd.SkuInfoList[Pcd.SkuInfoList.keys()[0]] + Sku = Pcd.SkuInfoList[Pcd.SkuInfoList.keys()[0]] Sku.VpdOffset = Sku.VpdOffset.strip() - + PcdValue = Sku.DefaultValue if Pcd.DatumType == 'VOID*' and PcdValue.startswith("L"): # if found PCD which datum value is unicode string the insert to left size of UnicodeIndex @@ -1124,10 +1124,10 @@ def CollectPlatformDynamicPcds(self): else: OtherPcdArray.append(Pcd) if Pcd.Type in [TAB_PCDS_DYNAMIC_VPD, TAB_PCDS_DYNAMIC_EX_VPD]: - VpdPcdDict[(Pcd.TokenCName, Pcd.TokenSpaceGuidCName)] = Pcd - + VpdPcdDict[(Pcd.TokenCName, Pcd.TokenSpaceGuidCName)] = Pcd + PlatformPcds = self.Platform.Pcds.keys() - PlatformPcds.sort() + PlatformPcds.sort() # # Add VPD type PCD into VpdFile and determine whether the VPD PCD need to be fixed up. # @@ -1145,8 +1145,8 @@ def CollectPlatformDynamicPcds(self): if self.Platform.VpdToolGuid == None or self.Platform.VpdToolGuid == '': EdkLogger.error("Build", FILE_NOT_FOUND, \ "Fail to find third-party BPDG tool to process VPD PCDs. BPDG Guid tool need to be defined in tools_def.txt and VPD_TOOL_GUID need to be provided in DSC file.") - - + + # # Fix the PCDs define in VPD PCD section that never referenced by module. # An example is PCD for signature usage. @@ -1161,7 +1161,7 @@ def CollectPlatformDynamicPcds(self): if (VpdPcd.TokenSpaceGuidCName == DscPcdEntry.TokenSpaceGuidCName) and \ (VpdPcd.TokenCName == DscPcdEntry.TokenCName): FoundFlag = True - + # Not found, it should be signature if not FoundFlag : # just pick the a value to determine whether is unicode string type @@ -1211,7 +1211,7 @@ def CollectPlatformDynamicPcds(self): VpdFile.GetCount() != 0: EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "Fail to get FLASH_DEFINITION definition in DSC file %s which is required when DSC contains VPD PCD." % str(self.Platform.MetaFile)) - + if VpdFile.GetCount() != 0: DscTimeStamp = self.Platform.MetaFile.TimeStamp FvPath = os.path.join(self.BuildDir, "FV") @@ -1220,14 +1220,14 @@ def CollectPlatformDynamicPcds(self): os.makedirs(FvPath) except: EdkLogger.error("build", FILE_WRITE_FAILURE, "Fail to create FV folder under %s" % self.BuildDir) - - + + VpdFilePath = os.path.join(FvPath, "%s.txt" % self.Platform.VpdToolGuid) - + if not os.path.exists(VpdFilePath) or os.path.getmtime(VpdFilePath) < DscTimeStamp: VpdFile.Write(VpdFilePath) - + # retrieve BPDG tool's path from tool_def.txt according to VPD_TOOL_GUID defined in DSC file. BPDGToolName = None for ToolDef in self.ToolDefinition.values(): @@ -1241,13 +1241,13 @@ def CollectPlatformDynamicPcds(self): VpdInfoFile.CallExtenalBPDGTool(BPDGToolName, VpdFilePath) else: EdkLogger.error("Build", FILE_NOT_FOUND, "Fail to find third-party BPDG tool to process VPD PCDs. BPDG Guid tool need to be defined in tools_def.txt and VPD_TOOL_GUID need to be provided in DSC file.") - + # Process VPD map file generated by third party BPDG tool if NeedProcessVpdMapFile: VpdMapFilePath = os.path.join(self.BuildDir, "FV", "%s.map" % self.Platform.VpdToolGuid) if os.path.exists(VpdMapFilePath): VpdFile.Read(VpdMapFilePath) - + # Fixup "*" offset for Pcd in self._DynamicPcdList: # just pick the a value to determine whether is unicode string type @@ -1258,9 +1258,9 @@ def CollectPlatformDynamicPcds(self): i += 1 else: EdkLogger.error("build", FILE_READ_FAILURE, "Can not find VPD map file %s to fix up VPD offset." % VpdMapFilePath) - + # Delete the DynamicPcdList At the last time enter into this function - del self._DynamicPcdList[:] + del self._DynamicPcdList[:] self._DynamicPcdList.extend(UnicodePcdArray) self._DynamicPcdList.extend(HiiPcdArray) self._DynamicPcdList.extend(OtherPcdArray) @@ -1471,10 +1471,10 @@ def _GetBuildRule(self): else: if self._BuildRule._FileVersion < AutoGenReqBuildRuleVerNum : # If Build Rule's version is less than the version number required by the tools, halting the build. - EdkLogger.error("build", AUTOGEN_ERROR, + EdkLogger.error("build", AUTOGEN_ERROR, ExtraData="The version number [%s] of build_rule.txt is less than the version number required by the AutoGen.(the minimum required version number is [%s])"\ % (self._BuildRule._FileVersion, AutoGenReqBuildRuleVerNum)) - + return self._BuildRule ## Summarize the packages used by modules in this platform @@ -1534,28 +1534,28 @@ def _GetPcdTokenNumbers(self): EdkLogger.debug(EdkLogger.DEBUG_5, "%s %s (%s) -> %d" % (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Pcd.Phase, TokenNumber)) self._PcdTokenNumber[Pcd.TokenCName, Pcd.TokenSpaceGuidCName] = TokenNumber TokenNumber += 1 - + for Pcd in self.DynamicPcdList: if Pcd.Phase == "PEI": if Pcd.Type in ["DynamicEx", "DynamicExDefault", "DynamicExVpd", "DynamicExHii"]: EdkLogger.debug(EdkLogger.DEBUG_5, "%s %s (%s) -> %d" % (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Pcd.Phase, TokenNumber)) self._PcdTokenNumber[Pcd.TokenCName, Pcd.TokenSpaceGuidCName] = TokenNumber TokenNumber += 1 - + for Pcd in self.DynamicPcdList: if Pcd.Phase == "DXE": if Pcd.Type in ["Dynamic", "DynamicDefault", "DynamicVpd", "DynamicHii"]: EdkLogger.debug(EdkLogger.DEBUG_5, "%s %s (%s) -> %d" % (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Pcd.Phase, TokenNumber)) self._PcdTokenNumber[Pcd.TokenCName, Pcd.TokenSpaceGuidCName] = TokenNumber TokenNumber += 1 - + for Pcd in self.DynamicPcdList: if Pcd.Phase == "DXE": if Pcd.Type in ["DynamicEx", "DynamicExDefault", "DynamicExVpd", "DynamicExHii"]: EdkLogger.debug(EdkLogger.DEBUG_5, "%s %s (%s) -> %d" % (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Pcd.Phase, TokenNumber)) self._PcdTokenNumber[Pcd.TokenCName, Pcd.TokenSpaceGuidCName] = TokenNumber TokenNumber += 1 - + for Pcd in self.NonDynamicPcdList: self._PcdTokenNumber[Pcd.TokenCName, Pcd.TokenSpaceGuidCName] = TokenNumber TokenNumber += 1 @@ -1787,7 +1787,7 @@ def _OverridePcd(self, ToPcd, FromPcd, Module=""): elif (ToPcd.Type not in [None, '']) and (FromPcd.Type not in [None, ''])\ and (ToPcd.Type != FromPcd.Type) and (ToPcd.Type in FromPcd.Type): if ToPcd.Type.strip() == "DynamicEx": - ToPcd.Type = FromPcd.Type + ToPcd.Type = FromPcd.Type elif ToPcd.Type not in [None, ''] and FromPcd.Type not in [None, ''] \ and ToPcd.Type != FromPcd.Type: EdkLogger.error("build", OPTION_CONFLICT, "Mismatched PCD type", @@ -1850,11 +1850,11 @@ def _OverridePcd(self, ToPcd, FromPcd, Module=""): # def ApplyPcdSetting(self, Module, Pcds): # for each PCD in module - for Name,Guid in Pcds: - PcdInModule = Pcds[Name,Guid] + for Name, Guid in Pcds: + PcdInModule = Pcds[Name, Guid] # find out the PCD setting in platform - if (Name,Guid) in self.Platform.Pcds: - PcdInPlatform = self.Platform.Pcds[Name,Guid] + if (Name, Guid) in self.Platform.Pcds: + PcdInPlatform = self.Platform.Pcds[Name, Guid] else: PcdInPlatform = None # then override the settings if any @@ -1927,8 +1927,8 @@ def ResolveLibraryReference(self, Module): # @retval Value Priority value based on the priority list. # def CalculatePriorityValue(self, Key): - Target, ToolChain, Arch, CommandType, Attr = Key.split('_') - PriorityValue = 0x11111 + Target, ToolChain, Arch, CommandType, Attr = Key.split('_') + PriorityValue = 0x11111 if Target == "*": PriorityValue &= 0x01111 if ToolChain == "*": @@ -1939,9 +1939,9 @@ def CalculatePriorityValue(self, Key): PriorityValue &= 0x11101 if Attr == "*": PriorityValue &= 0x11110 - - return self.PrioList["0x%0.5x"%PriorityValue] - + + return self.PrioList["0x%0.5x" % PriorityValue] + ## Expand * in build option key # @@ -1953,7 +1953,7 @@ def _ExpandBuildOption(self, Options, ModuleStyle=None): BuildOptions = {} FamilyMatch = False FamilyIsNull = True - + OverrideList = {} # # Construct a list contain the build options which need override. @@ -1970,7 +1970,7 @@ def _ExpandBuildOption(self, Options, ModuleStyle=None): if ToolChain == self.ToolChain or ToolChain == "*": if Arch == self.Arch or Arch == "*": if Options[Key].startswith("="): - if OverrideList.get(Key[1]) != None: + if OverrideList.get(Key[1]) != None: OverrideList.pop(Key[1]) OverrideList[Key[1]] = Options[Key] @@ -1978,9 +1978,9 @@ def _ExpandBuildOption(self, Options, ModuleStyle=None): # Use the highest priority value. # if (len(OverrideList) >= 2): - KeyList = OverrideList.keys() + KeyList = OverrideList.keys() for Index in range(len(KeyList)): - NowKey = KeyList[Index] + NowKey = KeyList[Index] Target1, ToolChain1, Arch1, CommandType1, Attr1 = NowKey.split("_") for Index1 in range(len(KeyList) - Index - 1): NextKey = KeyList[Index1 + Index + 1] @@ -1994,10 +1994,10 @@ def _ExpandBuildOption(self, Options, ModuleStyle=None): if CommandType1 == CommandType2 or CommandType1 == "*" or CommandType2 == "*": if Attr1 == Attr2 or Attr1 == "*" or Attr2 == "*": if self.CalculatePriorityValue(NowKey) > self.CalculatePriorityValue(NextKey): - if Options.get((self.BuildRuleFamily, NextKey)) != None: + if Options.get((self.BuildRuleFamily, NextKey)) != None: Options.pop((self.BuildRuleFamily, NextKey)) else: - if Options.get((self.BuildRuleFamily, NowKey)) != None: + if Options.get((self.BuildRuleFamily, NowKey)) != None: Options.pop((self.BuildRuleFamily, NowKey)) for Key in Options: @@ -2045,7 +2045,7 @@ def _ExpandBuildOption(self, Options, ModuleStyle=None): Family = Key[0] Target, Tag, Arch, Tool, Attr = Key[1].split("_") # if tool chain family doesn't match, skip it - if Tool not in self.ToolDefinition or Family =="": + if Tool not in self.ToolDefinition or Family == "": continue # option has been added before if Family != self.ToolDefinition[Tool][TAB_TOD_DEFINES_FAMILY]: @@ -2637,9 +2637,9 @@ def _GetBuildOptionIncPathList(self): # is the former use /I , the Latter used -I to specify include directories # if self.PlatformInfo.ToolChainFamily in ('MSFT'): - gBuildOptIncludePattern = re.compile(r"(?:.*?)/I[ \t]*([^ ]*)", re.MULTILINE|re.DOTALL) + gBuildOptIncludePattern = re.compile(r"(?:.*?)/I[ \t]*([^ ]*)", re.MULTILINE | re.DOTALL) elif self.PlatformInfo.ToolChainFamily in ('INTEL', 'GCC', 'RVCT'): - gBuildOptIncludePattern = re.compile(r"(?:.*?)-I[ \t]*([^ ]*)", re.MULTILINE|re.DOTALL) + gBuildOptIncludePattern = re.compile(r"(?:.*?)-I[ \t]*([^ ]*)", re.MULTILINE | re.DOTALL) else: # # New ToolChainFamily, don't known whether there is option to specify include directories @@ -2673,11 +2673,11 @@ def _GetBuildOptionIncPathList(self): if self.AutoGenVersion >= 0x00010005 and len(IncPathList) > 0: for Path in IncPathList: if (Path not in self.IncludePathList) and (CommonPath([Path, self.MetaFile.Dir]) != self.MetaFile.Dir): - ErrMsg = "The include directory for the EDK II module in this line is invalid %s specified in %s FLAGS '%s'" % (Path, Tool, FlagOption) - EdkLogger.error("build", + ErrMsg = "The include directory for the EDK II module in this line is invalid %s specified in %s FLAGS '%s'" % (Path, Tool, FlagOption) + EdkLogger.error("build", PARAMETER_INVALID, - ExtraData = ErrMsg, - File = str(self.MetaFile)) + ExtraData=ErrMsg, + File=str(self.MetaFile)) BuildOptionIncPathList += IncPathList @@ -2797,7 +2797,7 @@ def _ApplyBuildRule(self, File, FileType): if File.IsBinary and File == Source and self._BinaryFileList != None and File in self._BinaryFileList: # Skip all files that are not binary libraries if not self.IsLibrary: - continue + continue RuleObject = self.BuildRules[TAB_DEFAULT_BINARY_FILE] elif FileType in self.BuildRules: RuleObject = self.BuildRules[FileType] @@ -3215,7 +3215,7 @@ def CreateAsBuiltInf(self): # Also find all packages that the DynamicEx PCDs depend on Pcds = [] PatchablePcds = {} - Packages = [] + Packages = [] PcdCheckList = [] PcdTokenSpaceList = [] for Pcd in self.ModulePcdList + self.LibraryPcdList: @@ -3292,7 +3292,7 @@ def CreateAsBuiltInf(self): 'module_uefi_hii_resource_section' : [MDefs['UEFI_HII_RESOURCE_SECTION']] if 'UEFI_HII_RESOURCE_SECTION' in MDefs else [], 'module_uni_file' : [MDefs['MODULE_UNI_FILE']] if 'MODULE_UNI_FILE' in MDefs else [], 'module_arch' : self.Arch, - 'package_item' : ['%s' % (Package.MetaFile.File.replace('\\','/')) for Package in Packages], + 'package_item' : ['%s' % (Package.MetaFile.File.replace('\\', '/')) for Package in Packages], 'binary_item' : [], 'patchablepcd_item' : [], 'pcd_item' : [], @@ -3316,27 +3316,27 @@ def CreateAsBuiltInf(self): if 'PI_SPECIFICATION_VERSION' in self.Specification: AsBuiltInfDict['module_pi_specification_version'] += [self.Specification['PI_SPECIFICATION_VERSION']] - OutputDir = self.OutputDir.replace('\\','/').strip('/') + OutputDir = self.OutputDir.replace('\\', '/').strip('/') if self.ModuleType in ['BASE', 'USER_DEFINED']: for Item in self.CodaTargetList: - File = Item.Target.Path.replace('\\','/').strip('/').replace(OutputDir,'').strip('/') - if Item.Target.Ext.lower() == '.aml': + File = Item.Target.Path.replace('\\', '/').strip('/').replace(OutputDir, '').strip('/') + if Item.Target.Ext.lower() == '.aml': AsBuiltInfDict['binary_item'] += ['ASL|' + File] - elif Item.Target.Ext.lower() == '.acpi': + elif Item.Target.Ext.lower() == '.acpi': AsBuiltInfDict['binary_item'] += ['ACPI|' + File] else: AsBuiltInfDict['binary_item'] += ['BIN|' + File] else: for Item in self.CodaTargetList: - File = Item.Target.Path.replace('\\','/').strip('/').replace(OutputDir,'').strip('/') - if Item.Target.Ext.lower() == '.efi': + File = Item.Target.Path.replace('\\', '/').strip('/').replace(OutputDir, '').strip('/') + if Item.Target.Ext.lower() == '.efi': AsBuiltInfDict['binary_item'] += ['PE32|' + self.Name + '.efi'] else: AsBuiltInfDict['binary_item'] += ['BIN|' + File] if self.DepexGenerated: if self.ModuleType in ['PEIM']: AsBuiltInfDict['binary_item'] += ['PEI_DEPEX|' + self.Name + '.depex'] - if self.ModuleType in ['DXE_DRIVER','DXE_RUNTIME_DRIVER','DXE_SAL_DRIVER','UEFI_DRIVER']: + if self.ModuleType in ['DXE_DRIVER', 'DXE_RUNTIME_DRIVER', 'DXE_SAL_DRIVER', 'UEFI_DRIVER']: AsBuiltInfDict['binary_item'] += ['DXE_DEPEX|' + self.Name + '.depex'] if self.ModuleType in ['DXE_SMM_DRIVER']: AsBuiltInfDict['binary_item'] += ['SMM_DEPEX|' + self.Name + '.depex'] diff --git a/BaseTools/Source/Python/AutoGen/BuildEngine.py b/BaseTools/Source/Python/AutoGen/BuildEngine.py index ee1d3c89f292..63ed47d94bcb 100644 --- a/BaseTools/Source/Python/AutoGen/BuildEngine.py +++ b/BaseTools/Source/Python/AutoGen/BuildEngine.py @@ -388,7 +388,7 @@ def Parse(self): # find the build_rule_version if Line and Line[0] == "#" and Line.find(TAB_BUILD_RULE_VERSION) <> -1: - if Line.find("=") <> -1 and Line.find("=") < (len(Line)-1) and (Line[(Line.find("=") + 1):]).split(): + if Line.find("=") <> -1 and Line.find("=") < (len(Line) - 1) and (Line[(Line.find("=") + 1):]).split(): self._FileVersion = (Line[(Line.find("=") + 1):]).split()[0] # skip empty or comment line if Line == "" or Line[0] == "#": @@ -470,16 +470,16 @@ def ParseSectionHeader(self, LineIndex): if TokenList[0] == "BUILD": if len(TokenList) == 1: EdkLogger.error("build", FORMAT_INVALID, "Invalid rule section", - File=self.RuleFile, Line=LineIndex+1, + File=self.RuleFile, Line=LineIndex + 1, ExtraData=self.RuleContent[LineIndex]) FileType = TokenList[1] if FileType == '': EdkLogger.error("build", FORMAT_INVALID, "No file type given", - File=self.RuleFile, Line=LineIndex+1, + File=self.RuleFile, Line=LineIndex + 1, ExtraData=self.RuleContent[LineIndex]) if self._FileTypePattern.match(FileType) == None: - EdkLogger.error("build", FORMAT_INVALID, File=self.RuleFile, Line=LineIndex+1, + EdkLogger.error("build", FORMAT_INVALID, File=self.RuleFile, Line=LineIndex + 1, ExtraData="Only character, number (non-first character), '_' and '-' are allowed in file type") # new format: File-Type.Build-Type.Arch else: @@ -488,7 +488,7 @@ def ParseSectionHeader(self, LineIndex): elif FileType != TokenList[0]: EdkLogger.error("build", FORMAT_INVALID, "Different file types are not allowed in the same rule section", - File=self.RuleFile, Line=LineIndex+1, + File=self.RuleFile, Line=LineIndex + 1, ExtraData=self.RuleContent[LineIndex]) if len(TokenList) > 1: BuildType = TokenList[1] @@ -502,12 +502,12 @@ def ParseSectionHeader(self, LineIndex): if 'COMMON' in self._BuildTypeList and len(self._BuildTypeList) > 1: EdkLogger.error("build", FORMAT_INVALID, "Specific build types must not be mixed with common one", - File=self.RuleFile, Line=LineIndex+1, + File=self.RuleFile, Line=LineIndex + 1, ExtraData=self.RuleContent[LineIndex]) if 'COMMON' in self._ArchList and len(self._ArchList) > 1: EdkLogger.error("build", FORMAT_INVALID, "Specific ARCH must not be mixed with common one", - File=self.RuleFile, Line=LineIndex+1, + File=self.RuleFile, Line=LineIndex + 1, ExtraData=self.RuleContent[LineIndex]) self._FileType = FileType @@ -531,7 +531,7 @@ def ParseSubSectionHeader(self, LineIndex): elif SectionType != Type: EdkLogger.error("build", FORMAT_INVALID, "Two different section types are not allowed in the same sub-section", - File=self.RuleFile, Line=LineIndex+1, + File=self.RuleFile, Line=LineIndex + 1, ExtraData=self.RuleContent[LineIndex]) if len(TokenList) > 1: @@ -548,10 +548,10 @@ def ParseSubSectionHeader(self, LineIndex): if 'COMMON' in FamilyList and len(FamilyList) > 1: EdkLogger.error("build", FORMAT_INVALID, "Specific tool chain family should not be mixed with general one", - File=self.RuleFile, Line=LineIndex+1, + File=self.RuleFile, Line=LineIndex + 1, ExtraData=self.RuleContent[LineIndex]) if self._State not in self._StateHandler: - EdkLogger.error("build", FORMAT_INVALID, File=self.RuleFile, Line=LineIndex+1, + EdkLogger.error("build", FORMAT_INVALID, File=self.RuleFile, Line=LineIndex + 1, ExtraData="Unknown subsection: %s" % self.RuleContent[LineIndex]) ## Parse sub-section # diff --git a/BaseTools/Source/Python/AutoGen/GenDepex.py b/BaseTools/Source/Python/AutoGen/GenDepex.py index a390d560fc1a..5923a75ab7fb 100644 --- a/BaseTools/Source/Python/AutoGen/GenDepex.py +++ b/BaseTools/Source/Python/AutoGen/GenDepex.py @@ -286,7 +286,7 @@ def Optimize(self): # don't generate depex if only TRUE operand left if self.ModuleType == 'PEIM' and len(NewOperand) == 1 and NewOperand[0] == 'TRUE': self.PostfixNotation = [] - return + return # don't generate depex if all operands are architecture protocols if self.ModuleType in ['UEFI_DRIVER', 'DXE_DRIVER', 'DXE_RUNTIME_DRIVER', 'DXE_SAL_DRIVER', 'DXE_SMM_DRIVER'] and \ @@ -424,7 +424,7 @@ def Main(): Dpx = DependencyExpression(DxsString, Option.ModuleType, Option.Optimize) if Option.OutputFile != None: FileChangeFlag = Dpx.Generate(Option.OutputFile) - if not FileChangeFlag and DxsFile: + if not FileChangeFlag and DxsFile: # # Touch the output file if its time stamp is older than the original # DXS file to avoid re-invoke this tool for the dependency check in build rule. diff --git a/BaseTools/Source/Python/AutoGen/GenMake.py b/BaseTools/Source/Python/AutoGen/GenMake.py index d9b219e1c75f..89285c125433 100644 --- a/BaseTools/Source/Python/AutoGen/GenMake.py +++ b/BaseTools/Source/Python/AutoGen/GenMake.py @@ -27,7 +27,7 @@ import Common.GlobalData as GlobalData ## Regular expression for finding header file inclusions -gIncludePattern = re.compile(r"^[ \t]*#?[ \t]*include(?:[ \t]*(?:\\(?:\r\n|\r|\n))*[ \t]*)*(?:\(?[\"<]?[ \t]*)([-\w.\\/() \t]+)(?:[ \t]*[\">]?\)?)", re.MULTILINE|re.UNICODE|re.IGNORECASE) +gIncludePattern = re.compile(r"^[ \t]*#?[ \t]*include(?:[ \t]*(?:\\(?:\r\n|\r|\n))*[ \t]*)*(?:\(?[\"<]?[ \t]*)([-\w.\\/() \t]+)(?:[ \t]*[\">]?\)?)", re.MULTILINE | re.UNICODE | re.IGNORECASE) ## Regular expression for matching macro used in header file inclusion gMacroPattern = re.compile("([_A-Z][_A-Z0-9]*)[ \t]*\((.+)\)", re.UNICODE) @@ -499,7 +499,7 @@ def _CreateTemplateDict(self): # convert source files and binary files to build targets self.ResultFileList = [str(T.Target) for T in self._AutoGenObject.CodaTargetList] - if len(self.ResultFileList) == 0 and len(self._AutoGenObject.SourceFileList) <> 0: + if len(self.ResultFileList) == 0 and len(self._AutoGenObject.SourceFileList) <> 0: EdkLogger.error("build", AUTOGEN_ERROR, "Nothing to build", ExtraData="[%s]" % str(self._AutoGenObject)) @@ -520,9 +520,9 @@ def _CreateTemplateDict(self): FileMacro = "" IncludePathList = [] for P in self._AutoGenObject.IncludePathList: - IncludePathList.append(IncPrefix+self.PlaceMacro(P, self.Macros)) + IncludePathList.append(IncPrefix + self.PlaceMacro(P, self.Macros)) if FileBuildRule.INC_LIST_MACRO in self.ListFileMacros: - self.ListFileMacros[FileBuildRule.INC_LIST_MACRO].append(IncPrefix+P) + self.ListFileMacros[FileBuildRule.INC_LIST_MACRO].append(IncPrefix + P) FileMacro += self._FILE_MACRO_TEMPLATE.Replace( { "macro_name" : "INC", @@ -533,7 +533,7 @@ def _CreateTemplateDict(self): # Generate macros used to represent files containing list of input files for ListFileMacro in self.ListFileMacros: - ListFileName = os.path.join(self._AutoGenObject.OutputDir, "%s.lst" % ListFileMacro.lower()[:len(ListFileMacro)-5]) + ListFileName = os.path.join(self._AutoGenObject.OutputDir, "%s.lst" % ListFileMacro.lower()[:len(ListFileMacro) - 5]) FileMacroList.append("%s = %s" % (ListFileMacro, ListFileName)) SaveFileOnChange( ListFileName, @@ -767,7 +767,7 @@ def GetDependencyList(self, File, ForceList, SearchPathList): try: Fd = open(F.Path, 'r') except BaseException, X: - EdkLogger.error("build", FILE_OPEN_FAILURE, ExtraData=F.Path+"\n\t"+str(X)) + EdkLogger.error("build", FILE_OPEN_FAILURE, ExtraData=F.Path + "\n\t" + str(X)) FileContent = Fd.read() Fd.close() diff --git a/BaseTools/Source/Python/AutoGen/GenPcdDb.py b/BaseTools/Source/Python/AutoGen/GenPcdDb.py index d07ac60ef363..23865254d791 100644 --- a/BaseTools/Source/Python/AutoGen/GenPcdDb.py +++ b/BaseTools/Source/Python/AutoGen/GenPcdDb.py @@ -784,11 +784,11 @@ def BuildExDataBase(Dict): DbTotal = [InitValueUint64, VardefValueUint64, InitValueUint32, VardefValueUint32, VpdHeadValue, ExMapTable, LocalTokenNumberTable, GuidTable, StringHeadValue, PcdNameOffsetTable,VariableTable,SkuTable, StringTableLen, PcdTokenTable,PcdCNameTable, - SizeTableValue, InitValueUint16, VardefValueUint16,InitValueUint8, VardefValueUint8, InitValueBoolean, + SizeTableValue, InitValueUint16, VardefValueUint16, InitValueUint8, VardefValueUint8, InitValueBoolean, VardefValueBoolean, SkuidValue, SkuIndexValue, UnInitValueUint64, UnInitValueUint32, UnInitValueUint16, UnInitValueUint8, UnInitValueBoolean] DbItemTotal = [DbInitValueUint64, DbVardefValueUint64, DbInitValueUint32, DbVardefValueUint32, DbVpdHeadValue, DbExMapTable, DbLocalTokenNumberTable, DbGuidTable, DbStringHeadValue, DbPcdNameOffsetTable,DbVariableTable,DbSkuTable, DbStringTableLen, DbPcdTokenTable, DbPcdCNameTable, - DbSizeTableValue, DbInitValueUint16, DbVardefValueUint16,DbInitValueUint8, DbVardefValueUint8, DbInitValueBoolean, + DbSizeTableValue, DbInitValueUint16, DbVardefValueUint16, DbInitValueUint8, DbVardefValueUint8, DbInitValueBoolean, DbVardefValueBoolean, DbSkuidValue, DbSkuIndexValue, DbUnInitValueUint64, DbUnInitValueUint32, DbUnInitValueUint16, DbUnInitValueUint8, DbUnInitValueBoolean] # SkuidValue is the last table in the init table items @@ -1343,7 +1343,7 @@ def CreatePcdDatabasePhaseSpecificAutoGen (Platform, Phase): Dict['STRING_TABLE_VALUE'].append(DefaultValueBinStructure) elif Sku.DefaultValue[0] == '"': DefaultValueBinStructure = StringToArray(Sku.DefaultValue) - Size = len(Sku.DefaultValue) -2 + 1 + Size = len(Sku.DefaultValue) - 2 + 1 Dict['STRING_TABLE_VALUE'].append(DefaultValueBinStructure) elif Sku.DefaultValue[0] == '{': DefaultValueBinStructure = StringToArray(Sku.DefaultValue) @@ -1375,7 +1375,7 @@ def CreatePcdDatabasePhaseSpecificAutoGen (Platform, Phase): Pcd.InitString = 'INIT' else: if int(Sku.DefaultValue, 0) != 0: - Pcd.InitString = 'INIT' + Pcd.InitString = 'INIT' # # For UNIT64 type PCD's value, ULL should be append to avoid # warning under linux building environment. diff --git a/BaseTools/Source/Python/AutoGen/StrGather.py b/BaseTools/Source/Python/AutoGen/StrGather.py index 48c396a9aa96..60840041ba22 100644 --- a/BaseTools/Source/Python/AutoGen/StrGather.py +++ b/BaseTools/Source/Python/AutoGen/StrGather.py @@ -113,7 +113,7 @@ def DecToHexStr(Dec, Digit = 8): # @retval: A list for formatted hex string # def DecToHexList(Dec, Digit = 8): - Hex = eval("'%0" + str(Digit) + "X' % int(Dec)" ) + Hex = eval("'%0" + str(Digit) + "X' % int(Dec)") List = [] for Bit in range(Digit - 2, -1, -2): List.append(HexHeader + Hex[Bit:Bit + 2]) @@ -192,7 +192,7 @@ def CreateHFileContent(BaseName, UniObjectClass, IsCompatibleMode, UniGenCFlag): Line = COMMENT_DEFINE_STR + ' ' + Name + ' ' * (ValueStartPtr - len(DEFINE_STR + Name)) + DecToHexStr(Token, 4) + COMMENT_NOT_REFERENCED UnusedStr = WriteLine(UnusedStr, Line) - Str = ''.join([Str,UnusedStr]) + Str = ''.join([Str, UnusedStr]) Str = WriteLine(Str, '') if IsCompatibleMode or UniGenCFlag: @@ -235,7 +235,7 @@ def CreateCFileHeader(): # def CreateBinBuffer(BinBuffer, Array): for Item in Array: - BinBuffer.write(pack("B", int(Item,16))) + BinBuffer.write(pack("B", int(Item, 16))) ## Create a formatted string all items in an array # @@ -258,7 +258,7 @@ def CreateArrayItem(Array, Width = 16): Index = Index + 1 else: ArrayItem = WriteLine(ArrayItem, Line) - Line = ' ' + Item + ', ' + Line = ' ' + Item + ', ' Index = 1 ArrayItem = Write(ArrayItem, Line.rstrip()) @@ -320,7 +320,7 @@ def GetFilteredLanguage(UniLanguageList, LanguageFilterList): if PrimaryTag == UniLanguagePrimaryTag: if UniLanguage not in UniLanguageListFiltered: - UniLanguageListFiltered += [UniLanguage] + UniLanguageListFiltered += [UniLanguage] break else: # Here is rule 3 for "get best language" @@ -368,7 +368,7 @@ def CreateCFileContent(BaseName, UniObjectClass, IsCompatibleMode, UniBinBuffer, UniLanguageList = [] for IndexI in range(len(UniObjectClass.LanguageDef)): - UniLanguageList += [UniObjectClass.LanguageDef[IndexI][0]] + UniLanguageList += [UniObjectClass.LanguageDef[IndexI][0]] UniLanguageListFiltered = GetFilteredLanguage(UniLanguageList, LanguageFilterList) @@ -450,14 +450,14 @@ def CreateCFileContent(BaseName, UniObjectClass, IsCompatibleMode, UniBinBuffer, if UniBinBuffer: CreateBinBuffer (UniBinBuffer, List) UniBinBuffer.write (StringBuffer.getvalue()) - UniBinBuffer.write (pack("B", int(EFI_HII_SIBT_END,16))) + UniBinBuffer.write (pack("B", int(EFI_HII_SIBT_END, 16))) StringBuffer.close() # # Create line for string variable name # "unsigned char $(BaseName)Strings[] = {" # - AllStr = WriteLine('', CHAR_ARRAY_DEFIN + ' ' + BaseName + COMMON_FILE_NAME + '[] = {\n' ) + AllStr = WriteLine('', CHAR_ARRAY_DEFIN + ' ' + BaseName + COMMON_FILE_NAME + '[] = {\n') if IsCompatibleMode: # @@ -618,13 +618,13 @@ def GetStringFiles(UniFilList, SourceFileList, IncludeList, IncludePathList, Ski # Write an item # def Write(Target, Item): - return ''.join([Target,Item]) + return ''.join([Target, Item]) # # Write an item with a break line # def WriteLine(Target, Item): - return ''.join([Target,Item,'\n']) + return ''.join([Target, Item, '\n']) # This acts like the main() function for the script, unless it is 'import'ed into another # script. diff --git a/BaseTools/Source/Python/AutoGen/UniClassObject.py b/BaseTools/Source/Python/AutoGen/UniClassObject.py index 02a15cc0f0d4..a01381be5e64 100644 --- a/BaseTools/Source/Python/AutoGen/UniClassObject.py +++ b/BaseTools/Source/Python/AutoGen/UniClassObject.py @@ -248,7 +248,7 @@ def GetLangDef(self, File, Line): EdkLogger.error("build", FILE_OPEN_FAILURE, ExtraData=File); LineNo = GetLineNo(FileIn, Line, False) EdkLogger.error("Unicode File Parser", PARSER_ERROR, "Wrong language definition", - ExtraData="""%s\n\t*Correct format is like '#langdef en-US "English"'""" % Line, File = File, Line = LineNo) + ExtraData="""%s\n\t*Correct format is like '#langdef en-US "English"'""" % Line, File=File, Line=LineNo) else: LangName = GetLanguageCode(Lang[1], self.IsCompatibleMode, self.File) LangPrintName = Lang[2] @@ -352,7 +352,7 @@ def GetStringObject(self, Item): if Name != '': MatchString = re.match('[A-Z0-9_]+', Name, re.UNICODE) if MatchString == None or MatchString.end(0) != len(Name): - EdkLogger.error('Unicode File Parser', FORMAT_INVALID, 'The string token name %s defined in UNI file %s contains the invalid lower case character.' %(Name, self.File)) + EdkLogger.error('Unicode File Parser', FORMAT_INVALID, 'The string token name %s defined in UNI file %s contains the invalid lower case character.' % (Name, self.File)) LanguageList = Item.split(u'#language ') for IndexI in range(len(LanguageList)): if IndexI == 0: @@ -512,7 +512,7 @@ def LoadUniFile(self, File = None): if not self.IsCompatibleMode and Name != '': MatchString = re.match('[A-Z0-9_]+', Name, re.UNICODE) if MatchString == None or MatchString.end(0) != len(Name): - EdkLogger.error('Unicode File Parser', FORMAT_INVALID, 'The string token name %s defined in UNI file %s contains the invalid lower case character.' %(Name, self.File)) + EdkLogger.error('Unicode File Parser', FORMAT_INVALID, 'The string token name %s defined in UNI file %s contains the invalid lower case character.' % (Name, self.File)) self.AddStringToList(Name, Language, Value) continue @@ -571,7 +571,7 @@ def AddStringToList(self, Name, Language, Value, Token = None, Referenced = Fals ItemIndexInList = self.OrderedStringDict[Language][Name] Item = self.OrderedStringList[Language][ItemIndexInList] Item.UpdateValue(Value) - Item.UseOtherLangDef = '' + Item.UseOtherLangDef = '' if IsAdded: Token = len(self.OrderedStringList[Language]) diff --git a/BaseTools/Source/Python/BPDG/GenVpd.py b/BaseTools/Source/Python/BPDG/GenVpd.py index 76d30fa6ff49..d1da99fe5faa 100644 --- a/BaseTools/Source/Python/BPDG/GenVpd.py +++ b/BaseTools/Source/Python/BPDG/GenVpd.py @@ -48,19 +48,19 @@ def __init__(self, PcdCName, SkuId,PcdOffset, PcdSize, PcdValue, Lineno=None, Fi self.PcdBinSize = PcdBinSize if self.PcdValue == '' : - EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, - "Invalid PCD format(Name: %s File: %s line: %s) , no Value specified!" %(self.PcdCName, self.FileName, self.Lineno)) - + EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, + "Invalid PCD format(Name: %s File: %s line: %s) , no Value specified!" % (self.PcdCName, self.FileName, self.Lineno)) + if self.PcdOffset == '' : - EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, - "Invalid PCD format(Name: %s File: %s Line: %s) , no Offset specified!" %(self.PcdCName, self.FileName, self.Lineno)) - + EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, + "Invalid PCD format(Name: %s File: %s Line: %s) , no Offset specified!" % (self.PcdCName, self.FileName, self.Lineno)) + if self.PcdSize == '' : - EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, - "Invalid PCD format(Name: %s File: %s Line: %s), no PcdSize specified!" %(self.PcdCName, self.FileName, self.Lineno)) - + EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, + "Invalid PCD format(Name: %s File: %s Line: %s), no PcdSize specified!" % (self.PcdCName, self.FileName, self.Lineno)) + self._GenOffsetValue () - + ## Analyze the string value to judge the PCD's datum type euqal to Boolean or not. # # @param ValueString PCD's value @@ -74,10 +74,10 @@ def _IsBoolean(self, ValueString, Size): if ValueString.upper() in ["TRUE", "FALSE"]: return True elif ValueString in ["0", "1", "0x0", "0x1", "0x00", "0x01"]: - return True - + return True + return False - + ## Convert the PCD's value from string to integer. # # This function will try to convert the Offset value form string to integer @@ -91,9 +91,9 @@ def _GenOffsetValue(self): try: self.PcdBinOffset = int(self.PcdOffset, 16) except: - EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, - "Invalid offset value %s for PCD %s (File: %s Line: %s)" % (self.PcdOffset, self.PcdCName, self.FileName, self.Lineno)) - + EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, + "Invalid offset value %s for PCD %s (File: %s Line: %s)" % (self.PcdOffset, self.PcdCName, self.FileName, self.Lineno)) + ## Pack Boolean type VPD PCD's value form string to binary type. # # @param ValueString The boolean type string for pack. @@ -101,18 +101,18 @@ def _GenOffsetValue(self): # def _PackBooleanValue(self, ValueString): if ValueString.upper() == "TRUE" or ValueString in ["1", "0x1", "0x01"]: - try: - self.PcdValue = pack(_FORMAT_CHAR[1], 1) + try: + self.PcdValue = pack(_FORMAT_CHAR[1], 1) except: - EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, - "Invalid size or value for PCD %s to pack(File: %s Line: %s)." % (self.PcdCName, self.FileName, self.Lineno)) + EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, + "Invalid size or value for PCD %s to pack(File: %s Line: %s)." % (self.PcdCName, self.FileName, self.Lineno)) else: try: - self.PcdValue = pack(_FORMAT_CHAR[1], 0) + self.PcdValue = pack(_FORMAT_CHAR[1], 0) except: - EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, - "Invalid size or value for PCD %s to pack(File: %s Line: %s)." % (self.PcdCName, self.FileName, self.Lineno)) - + EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, + "Invalid size or value for PCD %s to pack(File: %s Line: %s)." % (self.PcdCName, self.FileName, self.Lineno)) + ## Pack Integer type VPD PCD's value form string to binary type. # # @param ValueString The Integer type string for pack. @@ -120,46 +120,46 @@ def _PackBooleanValue(self, ValueString): # def _PackIntValue(self, IntValue, Size): if Size not in _FORMAT_CHAR.keys(): - EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, - "Invalid size %d for PCD %s in integer datum size(File: %s Line: %s)." % (Size, self.PcdCName, self.FileName, self.Lineno)) - - if Size == 1: + EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, + "Invalid size %d for PCD %s in integer datum size(File: %s Line: %s)." % (Size, self.PcdCName, self.FileName, self.Lineno)) + + if Size == 1: if IntValue < 0: - EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, + EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, "PCD can't be set to negative value %d for PCD %s in UINT8 datum type(File: %s Line: %s)." % (IntValue, self.PcdCName, self.FileName, self.Lineno)) elif IntValue >= 0x100: - EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, - "Too large PCD value %d for datum type UINT8 for PCD %s(File: %s Line: %s)." % (IntValue, self.PcdCName, self.FileName, self.Lineno)) + EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, + "Too large PCD value %d for datum type UINT8 for PCD %s(File: %s Line: %s)." % (IntValue, self.PcdCName, self.FileName, self.Lineno)) elif Size == 2: if IntValue < 0: - EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, + EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, "PCD can't be set to negative value %d for PCD %s in UINT16 datum type(File: %s Line: %s)." % (IntValue, self.PcdCName, self.FileName, self.Lineno)) elif IntValue >= 0x10000: - EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, - "Too large PCD value %d for datum type UINT16 for PCD %s(File: %s Line: %s)." % (IntValue, self.PcdCName, self.FileName, self.Lineno)) + EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, + "Too large PCD value %d for datum type UINT16 for PCD %s(File: %s Line: %s)." % (IntValue, self.PcdCName, self.FileName, self.Lineno)) elif Size == 4: if IntValue < 0: - EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, + EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, "PCD can't be set to negative value %d for PCD %s in UINT32 datum type(File: %s Line: %s)." % (IntValue, self.PcdCName, self.FileName, self.Lineno)) elif IntValue >= 0x100000000: - EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, + EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, "Too large PCD value %d for datum type UINT32 for PCD %s(File: %s Line: %s)." % (IntValue, self.PcdCName, self.FileName, self.Lineno)) elif Size == 8: if IntValue < 0: - EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, + EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, "PCD can't be set to negative value %d for PCD %s in UINT32 datum type(File: %s Line: %s)." % (IntValue, self.PcdCName, self.FileName, self.Lineno)) elif IntValue >= 0x10000000000000000: - EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, + EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, "Too large PCD value %d for datum type UINT32 for PCD %s(File: %s Line: %s)." % (IntValue, self.PcdCName, self.FileName, self.Lineno)) else: - EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, - "Invalid size %d for PCD %s in integer datum size(File: %s Line: %s)." % (Size, self.PcdCName, self.FileName, self.Lineno)) - + EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, + "Invalid size %d for PCD %s in integer datum size(File: %s Line: %s)." % (Size, self.PcdCName, self.FileName, self.Lineno)) + try: - self.PcdValue = pack(_FORMAT_CHAR[Size], IntValue) + self.PcdValue = pack(_FORMAT_CHAR[Size], IntValue) except: - EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, - "Invalid size or value for PCD %s to pack(File: %s Line: %s)." % (self.PcdCName, self.FileName, self.Lineno)) + EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, + "Invalid size or value for PCD %s to pack(File: %s Line: %s)." % (self.PcdCName, self.FileName, self.Lineno)) ## Pack VOID* type VPD PCD's value form string to binary type. # @@ -178,53 +178,53 @@ def _PackPtrValue(self, ValueString, Size): elif ValueString.startswith('"') and ValueString.endswith('"'): self._PackString(ValueString, Size) else: - EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, - "Invalid VOID* type PCD %s value %s (File: %s Line: %s)" % (self.PcdCName, ValueString, self.FileName, self.Lineno)) - + EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, + "Invalid VOID* type PCD %s value %s (File: %s Line: %s)" % (self.PcdCName, ValueString, self.FileName, self.Lineno)) + ## Pack an Ascii PCD value. # # An Ascii string for a PCD should be in format as "". # def _PackString(self, ValueString, Size): if (Size < 0): - EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, + EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, "Invalid parameter Size %s of PCD %s!(File: %s Line: %s)" % (self.PcdBinSize, self.PcdCName, self.FileName, self.Lineno)) if (ValueString == ""): - EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, "Invalid parameter ValueString %s of PCD %s!(File: %s Line: %s)" % (self.PcdUnpackValue, self.PcdCName, self.FileName, self.Lineno)) + EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, "Invalid parameter ValueString %s of PCD %s!(File: %s Line: %s)" % (self.PcdUnpackValue, self.PcdCName, self.FileName, self.Lineno)) if (len(ValueString) < 2): EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, "For PCD: %s ,ASCII string %s at least contains two!(File: %s Line: %s)" % (self.PcdCName, self.PcdUnpackValue, self.FileName, self.Lineno)) - + ValueString = ValueString[1:-1] if len(ValueString) + 1 > Size: - EdkLogger.error("BPDG", BuildToolError.RESOURCE_OVERFLOW, + EdkLogger.error("BPDG", BuildToolError.RESOURCE_OVERFLOW, "PCD value string %s is exceed to size %d(File: %s Line: %s)" % (ValueString, Size, self.FileName, self.Lineno)) try: - self.PcdValue= pack('%ds' % Size, ValueString) + self.PcdValue = pack('%ds' % Size, ValueString) except: - EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, - "Invalid size or value for PCD %s to pack(File: %s Line: %s)." % (self.PcdCName, self.FileName, self.Lineno)) - + EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, + "Invalid size or value for PCD %s to pack(File: %s Line: %s)." % (self.PcdCName, self.FileName, self.Lineno)) + ## Pack a byte-array PCD value. # # A byte-array for a PCD should be in format as {0x01, 0x02, ...}. # def _PackByteArray(self, ValueString, Size): - if (Size < 0): + if (Size < 0): EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, "Invalid parameter Size %s of PCD %s!(File: %s Line: %s)" % (self.PcdBinSize, self.PcdCName, self.FileName, self.Lineno)) if (ValueString == ""): - EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, "Invalid parameter ValueString %s of PCD %s!(File: %s Line: %s)" % (self.PcdUnpackValue, self.PcdCName, self.FileName, self.Lineno)) - + EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, "Invalid parameter ValueString %s of PCD %s!(File: %s Line: %s)" % (self.PcdUnpackValue, self.PcdCName, self.FileName, self.Lineno)) + ValueString = ValueString.strip() ValueString = ValueString.lstrip('{').strip('}') ValueList = ValueString.split(',') ValueList = [item.strip() for item in ValueList] - + if len(ValueList) > Size: - EdkLogger.error("BPDG", BuildToolError.RESOURCE_OVERFLOW, + EdkLogger.error("BPDG", BuildToolError.RESOURCE_OVERFLOW, "The byte array %s is too large for size %d(File: %s Line: %s)" % (ValueString, Size, self.FileName, self.Lineno)) - + ReturnArray = array.array('B') - + for Index in xrange(len(ValueList)): Value = None if ValueList[Index].lower().startswith('0x'): @@ -232,7 +232,7 @@ def _PackByteArray(self, ValueString, Size): try: Value = int(ValueList[Index], 16) except: - EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, + EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, "The value item %s in byte array %s is an invalid HEX value.(File: %s Line: %s)" % \ (ValueList[Index], ValueString, self.FileName, self.Lineno)) else: @@ -243,52 +243,52 @@ def _PackByteArray(self, ValueString, Size): EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, "The value item %s in byte array %s is an invalid DECIMAL value.(File: %s Line: %s)" % \ (ValueList[Index], ValueString, self.FileName, self.Lineno)) - + if Value > 255: - EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, - "The value item %s in byte array %s do not in range 0 ~ 0xFF(File: %s Line: %s)" %\ + EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, + "The value item %s in byte array %s do not in range 0 ~ 0xFF(File: %s Line: %s)" % \ (ValueList[Index], ValueString, self.FileName, self.Lineno)) - + ReturnArray.append(Value) - + for Index in xrange(len(ValueList), Size): ReturnArray.append(0) - - self.PcdValue = ReturnArray.tolist() + + self.PcdValue = ReturnArray.tolist() ## Pack a unicode PCD value into byte array. # # A unicode string for a PCD should be in format as L"". # def _PackUnicode(self, UnicodeString, Size): - if (Size < 0): - EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, "Invalid parameter Size %s of PCD %s!(File: %s Line: %s)" %\ + if (Size < 0): + EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, "Invalid parameter Size %s of PCD %s!(File: %s Line: %s)" % \ (self.PcdBinSize, self.PcdCName, self.FileName, self.Lineno)) if (len(UnicodeString) < 3): - EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, "For PCD: %s ,ASCII string %s at least contains two!(File: %s Line: %s)" %\ + EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, "For PCD: %s ,ASCII string %s at least contains two!(File: %s Line: %s)" % \ (self.PcdCName, self.PcdUnpackValue, self.FileName, self.Lineno)) - + UnicodeString = UnicodeString[2:-1] - + if (len(UnicodeString) + 1) * 2 > Size: EdkLogger.error("BPDG", BuildToolError.RESOURCE_OVERFLOW, "The size of unicode string %s is too larger for size %s(File: %s Line: %s)" % \ (UnicodeString, Size, self.FileName, self.Lineno)) - + ReturnArray = array.array('B') for Value in UnicodeString: try: ReturnArray.append(ord(Value)) ReturnArray.append(0) except: - EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, + EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, "Invalid unicode character %s in unicode string %s(File: %s Line: %s)" % \ (Value, UnicodeString, self.FileName, self.Lineno)) - + for Index in xrange(len(UnicodeString) * 2, Size): ReturnArray.append(0) - - self.PcdValue = ReturnArray.tolist() + + self.PcdValue = ReturnArray.tolist() @@ -300,7 +300,7 @@ def _PackUnicode(self, UnicodeString, Size): # 3. Fixed offset if needed; # 4. Generate output file, including guided.map and guided.bin file; # -class GenVPD : +class GenVPD : ## Constructor of DscBuildData # # Initialize object of GenVPD @@ -322,47 +322,47 @@ def __init__(self, InputFileName, MapFileName, VpdFileName): try: self.FileLinesList = fInputfile.readlines() except: - EdkLogger.error("BPDG", BuildToolError.FILE_READ_FAILURE, "File read failed for %s" %InputFileName,None) + EdkLogger.error("BPDG", BuildToolError.FILE_READ_FAILURE, "File read failed for %s" % InputFileName, None) finally: fInputfile.close() except: - EdkLogger.error("BPDG", BuildToolError.FILE_OPEN_FAILURE, "File open failed for %s" %InputFileName,None) - + EdkLogger.error("BPDG", BuildToolError.FILE_OPEN_FAILURE, "File open failed for %s" % InputFileName, None) + ## # Parser the input file which is generated by the build tool. Convert the value of each pcd's # from string to it's real format. Also remove the useless line in the input file. # def ParserInputFile (self): - count = 0 + count = 0 for line in self.FileLinesList: # Strip "\r\n" generated by readlines (). line = line.strip() line = line.rstrip(os.linesep) - + # Skip the comment line if (not line.startswith("#")) and len(line) > 1 : # # Enhanced for support "|" character in the string. # ValueList = ['', '', '', '',''] - - ValueRe = re.compile(r'\s*L?\".*\|.*\"\s*$') + + ValueRe = re.compile(r'\s*L?\".*\|.*\"\s*$') PtrValue = ValueRe.findall(line) - + ValueUpdateFlag = False - + if len(PtrValue) >= 1: line = re.sub(ValueRe, '', line) - ValueUpdateFlag = True - + ValueUpdateFlag = True + TokenList = line.split('|') ValueList[0:len(TokenList)] = TokenList - + if ValueUpdateFlag: ValueList[4] = PtrValue[0] self.FileLinesList[count] = ValueList # Store the line number - self.FileLinesList[count].append(str(count+1)) + self.FileLinesList[count].append(str(count + 1)) elif len(line) <= 1 : # Set the blank line to "None" self.FileLinesList[count] = None @@ -370,9 +370,9 @@ def ParserInputFile (self): # Set the comment line to "None" self.FileLinesList[count] = None count += 1 - + # The line count contain usage information - count = 0 + count = 0 # Delete useless lines while (True) : try : @@ -381,18 +381,18 @@ def ParserInputFile (self): else : count += 1 except : - break + break # # After remove the useless line, if there are no data remain in the file line list, # Report warning messages to user's. # if len(self.FileLinesList) == 0 : - EdkLogger.warn('BPDG', BuildToolError.RESOURCE_NOT_AVAILABLE, + EdkLogger.warn('BPDG', BuildToolError.RESOURCE_NOT_AVAILABLE, "There are no VPD type pcds defined in DSC file, Please check it.") - + # Process the pcds one by one base on the pcd's value and size count = 0 - for line in self.FileLinesList: + for line in self.FileLinesList: if line != None : PCD = PcdEntry(line[0], line[1], line[2], line[3], line[4],line[5], self.InputFileName) # Strip the space char @@ -421,7 +421,7 @@ def ParserInputFile (self): PCD.PcdBinSize = PackSize except: EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, "Invalid PCD size value %s at file: %s line: %s" % (PCD.PcdSize, self.InputFileName, PCD.Lineno)) - + if PCD._IsBoolean(PCD.PcdValue, PCD.PcdSize): PCD._PackBooleanValue(PCD.PcdValue) self.FileLinesList[count] = PCD @@ -431,7 +431,7 @@ def ParserInputFile (self): # Try to translate value to an integer firstly. # IsInteger = True - PackValue = None + PackValue = None try: PackValue = int(PCD.PcdValue) except: @@ -439,23 +439,23 @@ def ParserInputFile (self): PackValue = int(PCD.PcdValue, 16) except: IsInteger = False - + if IsInteger: PCD._PackIntValue(PackValue, PackSize) else: PCD._PackPtrValue(PCD.PcdValue, PackSize) - + self.FileLinesList[count] = PCD count += 1 else : continue - + ## # This function used to create a clean list only contain useful information and reorganized to make it # easy to be sorted # def FormatFileLine (self) : - + for eachPcd in self.FileLinesList : if eachPcd.PcdOffset != '*' : # Use pcd's Offset value as key, and pcd's Value as value @@ -463,43 +463,43 @@ def FormatFileLine (self) : else : # Use pcd's CName as key, and pcd's Size as value self.PcdUnknownOffsetList.append(eachPcd) - - + + ## # This function is use to fix the offset value which the not specified in the map file. # Usually it use the star (meaning any offset) character in the offset field # - def FixVpdOffset (self): + def FixVpdOffset (self): # At first, the offset should start at 0 # Sort fixed offset list in order to find out where has free spaces for the pcd's offset # value is "*" to insert into. - - self.PcdFixedOffsetSizeList.sort(lambda x,y: cmp(x.PcdBinOffset, y.PcdBinOffset)) - + + self.PcdFixedOffsetSizeList.sort(lambda x, y: cmp(x.PcdBinOffset, y.PcdBinOffset)) + # # Sort the un-fixed pcd's offset by it's size. # - self.PcdUnknownOffsetList.sort(lambda x,y: cmp(x.PcdBinSize, y.PcdBinSize)) - + self.PcdUnknownOffsetList.sort(lambda x, y: cmp(x.PcdBinSize, y.PcdBinSize)) + # # Process all Offset value are "*" # if (len(self.PcdFixedOffsetSizeList) == 0) and (len(self.PcdUnknownOffsetList) != 0) : # The offset start from 0 NowOffset = 0 - for Pcd in self.PcdUnknownOffsetList : + for Pcd in self.PcdUnknownOffsetList : Pcd.PcdBinOffset = NowOffset Pcd.PcdOffset = str(hex(Pcd.PcdBinOffset)) NowOffset += Pcd.PcdBinSize self.PcdFixedOffsetSizeList = self.PcdUnknownOffsetList return - + # Check the offset of VPD type pcd's offset start from 0. - if self.PcdFixedOffsetSizeList[0].PcdBinOffset != 0 : + if self.PcdFixedOffsetSizeList[0].PcdBinOffset != 0 : EdkLogger.warn("BPDG", "The offset of VPD type pcd should start with 0, please check it.", - None) - + None) + # Judge whether the offset in fixed pcd offset list is overlapped or not. lenOfList = len(self.PcdFixedOffsetSizeList) count = 0 @@ -508,22 +508,22 @@ def FixVpdOffset (self): PcdNext = self.PcdFixedOffsetSizeList[count+1] # Two pcd's offset is same if PcdNow.PcdBinOffset == PcdNext.PcdBinOffset : - EdkLogger.error("BPDG", BuildToolError.ATTRIBUTE_GET_FAILURE, - "The offset of %s at line: %s is same with %s at line: %s in file %s" %\ + EdkLogger.error("BPDG", BuildToolError.ATTRIBUTE_GET_FAILURE, + "The offset of %s at line: %s is same with %s at line: %s in file %s" % \ (PcdNow.PcdCName, PcdNow.Lineno, PcdNext.PcdCName, PcdNext.Lineno, PcdNext.FileName), None) - + # Overlapped if PcdNow.PcdBinOffset + PcdNow.PcdBinSize > PcdNext.PcdBinOffset : - EdkLogger.error("BPDG", BuildToolError.ATTRIBUTE_GET_FAILURE, - "The offset of %s at line: %s is overlapped with %s at line: %s in file %s" %\ + EdkLogger.error("BPDG", BuildToolError.ATTRIBUTE_GET_FAILURE, + "The offset of %s at line: %s is overlapped with %s at line: %s in file %s" % \ (PcdNow.PcdCName, PcdNow.Lineno, PcdNext.PcdCName, PcdNext.Lineno, PcdNext.FileName), None) - + # Has free space, raise a warning message if PcdNow.PcdBinOffset + PcdNow.PcdBinSize < PcdNext.PcdBinOffset : - EdkLogger.warn("BPDG", BuildToolError.ATTRIBUTE_GET_FAILURE, - "The offsets have free space of between %s at line: %s and %s at line: %s in file %s" %\ + EdkLogger.warn("BPDG", BuildToolError.ATTRIBUTE_GET_FAILURE, + "The offsets have free space of between %s at line: %s and %s at line: %s in file %s" % \ (PcdNow.PcdCName, PcdNow.Lineno, PcdNext.PcdCName, PcdNext.Lineno, PcdNext.FileName), None) count += 1 @@ -545,7 +545,7 @@ def FixVpdOffset (self): if LastOffset < NowOffset : if lenOfUnfixedList != 0 : countOfUnfixedList = 0 - while(countOfUnfixedList < lenOfUnfixedList) : + while(countOfUnfixedList < lenOfUnfixedList) : eachUnfixedPcd = self.PcdUnknownOffsetList[countOfUnfixedList] needFixPcdSize = eachUnfixedPcd.PcdBinSize # Not been fixed @@ -586,8 +586,8 @@ def FixVpdOffset (self): FixOffsetSizeListCount += 1 # Usually it will not enter into this thunk, if so, means it overlapped. else : - EdkLogger.error("BPDG", BuildToolError.ATTRIBUTE_NOT_AVAILABLE, - "The offset value definition has overlapped at pcd: %s, it's offset is: %s, in file: %s line: %s" %\ + EdkLogger.error("BPDG", BuildToolError.ATTRIBUTE_NOT_AVAILABLE, + "The offset value definition has overlapped at pcd: %s, it's offset is: %s, in file: %s line: %s" % \ (eachFixedPcd.PcdCName, eachFixedPcd.PcdOffset, eachFixedPcd.InputFileName, eachFixedPcd.Lineno), None) FixOffsetSizeListCount += 1 @@ -618,46 +618,46 @@ def GenerateVpdFile (self, MapFileName, BinFileName): #Open an VPD file to process try: - fVpdFile = open (BinFileName, "wb", 0) + fVpdFile = open(BinFileName, "wb", 0) except: # Open failed - EdkLogger.error("BPDG", BuildToolError.FILE_OPEN_FAILURE, "File open failed for %s" %self.VpdFileName,None) - + EdkLogger.error("BPDG", BuildToolError.FILE_OPEN_FAILURE, "File open failed for %s" % self.VpdFileName, None) + try : - fMapFile = open (MapFileName, "w", 0) + fMapFile = open(MapFileName, "w", 0) except: # Open failed - EdkLogger.error("BPDG", BuildToolError.FILE_OPEN_FAILURE, "File open failed for %s" %self.MapFileName,None) - + EdkLogger.error("BPDG", BuildToolError.FILE_OPEN_FAILURE, "File open failed for %s" % self.MapFileName, None) + # Use a instance of StringIO to cache data - fStringIO = StringIO.StringIO('') - + fStringIO = StringIO.StringIO('') + # Write the header of map file. try : fMapFile.write (st.MAP_FILE_COMMENT_TEMPLATE + "\n") except: - EdkLogger.error("BPDG", BuildToolError.FILE_WRITE_FAILURE, "Write data to file %s failed, please check whether the file been locked or using by other applications." %self.MapFileName,None) - + EdkLogger.error("BPDG", BuildToolError.FILE_WRITE_FAILURE, "Write data to file %s failed, please check whether the file been locked or using by other applications." % self.MapFileName, None) + for eachPcd in self.PcdFixedOffsetSizeList : # write map file try : fMapFile.write("%s | %s | %s | %s | %s \n" % (eachPcd.PcdCName, eachPcd.SkuId,eachPcd.PcdOffset, eachPcd.PcdSize,eachPcd.PcdUnpackValue)) except: - EdkLogger.error("BPDG", BuildToolError.FILE_WRITE_FAILURE, "Write data to file %s failed, please check whether the file been locked or using by other applications." %self.MapFileName,None) - + EdkLogger.error("BPDG", BuildToolError.FILE_WRITE_FAILURE, "Write data to file %s failed, please check whether the file been locked or using by other applications." % self.MapFileName, None) + # Write Vpd binary file - fStringIO.seek (eachPcd.PcdBinOffset) + fStringIO.seek (eachPcd.PcdBinOffset) if isinstance(eachPcd.PcdValue, list): ValueList = [chr(Item) for Item in eachPcd.PcdValue] - fStringIO.write(''.join(ValueList)) - else: + fStringIO.write(''.join(ValueList)) + else: fStringIO.write (eachPcd.PcdValue) - - try : + + try : fVpdFile.write (fStringIO.getvalue()) except: - EdkLogger.error("BPDG", BuildToolError.FILE_WRITE_FAILURE, "Write data to file %s failed, please check whether the file been locked or using by other applications." %self.VpdFileName,None) - + EdkLogger.error("BPDG", BuildToolError.FILE_WRITE_FAILURE, "Write data to file %s failed, please check whether the file been locked or using by other applications." % self.VpdFileName, None) + fStringIO.close () fVpdFile.close () fMapFile.close () diff --git a/BaseTools/Source/Python/Common/Dictionary.py b/BaseTools/Source/Python/Common/Dictionary.py index 5300a5456c1e..1c33fefabf98 100644 --- a/BaseTools/Source/Python/Common/Dictionary.py +++ b/BaseTools/Source/Python/Common/Dictionary.py @@ -27,19 +27,19 @@ # def ConvertTextFileToDictionary(FileName, Dictionary, CommentCharacter, KeySplitCharacter, ValueSplitFlag, ValueSplitCharacter): try: - F = open(FileName,'r') + F = open(FileName, 'r') Keys = [] for Line in F: if Line.startswith(CommentCharacter): continue - LineList = Line.split(KeySplitCharacter,1) + LineList = Line.split(KeySplitCharacter, 1) if len(LineList) >= 2: Key = LineList[0].split() if len(Key) == 1 and Key[0][0] != CommentCharacter and Key[0] not in Keys: if ValueSplitFlag: - Dictionary[Key[0]] = LineList[1].replace('\\','/').split(ValueSplitCharacter) + Dictionary[Key[0]] = LineList[1].replace('\\', '/').split(ValueSplitCharacter) else: - Dictionary[Key[0]] = LineList[1].strip().replace('\\','/') + Dictionary[Key[0]] = LineList[1].strip().replace('\\', '/') Keys += [Key[0]] F.close() return 0 diff --git a/BaseTools/Source/Python/Common/EdkIIWorkspace.py b/BaseTools/Source/Python/Common/EdkIIWorkspace.py index 401efeef3c94..f22a545b77ce 100644 --- a/BaseTools/Source/Python/Common/EdkIIWorkspace.py +++ b/BaseTools/Source/Python/Common/EdkIIWorkspace.py @@ -59,7 +59,7 @@ def __init__(self): # # Load TianoCoreOrgLogo, used for GUI tool # - self.Icon = wx.Icon(self.WorkspaceFile('tools/Python/TianoCoreOrgLogo.gif'),wx.BITMAP_TYPE_GIF) + self.Icon = wx.Icon(self.WorkspaceFile('tools/Python/TianoCoreOrgLogo.gif'), wx.BITMAP_TYPE_GIF) except: self.Icon = None @@ -151,7 +151,7 @@ def XmlParseFile (self, FileName): def XmlParseFileSection (self, FileName, SectionTag): if self.Verbose: print FileName - return XmlParseFileSection (self.WorkspaceFile(FileName), SectionTag) + return XmlParseFileSection (self.WorkspaceFile(FileName), SectionTag) ## Save a XML file # @@ -219,19 +219,19 @@ def ConvertDictionaryToTextFile(self, FileName, Dictionary, CommentCharacter, Ke # def ConvertTextFileToDictionary(FileName, Dictionary, CommentCharacter, KeySplitCharacter, ValueSplitFlag, ValueSplitCharacter): try: - F = open(FileName,'r') + F = open(FileName, 'r') except: return False Keys = [] for Line in F: - LineList = Line.split(KeySplitCharacter,1) + LineList = Line.split(KeySplitCharacter, 1) if len(LineList) >= 2: Key = LineList[0].split() - if len(Key) == 1 and Key[0][0] != CommentCharacter and Key[0] not in Keys: + if len(Key) == 1 and Key[0][0] != CommentCharacter and Key[0] not in Keys: if ValueSplitFlag: - Dictionary[Key[0]] = LineList[1].replace('\\','/').split(ValueSplitCharacter) + Dictionary[Key[0]] = LineList[1].replace('\\', '/').split(ValueSplitCharacter) else: - Dictionary[Key[0]] = LineList[1].strip().replace('\\','/') + Dictionary[Key[0]] = LineList[1].strip().replace('\\', '/') Keys += [Key[0]] F.close() return True @@ -252,7 +252,7 @@ def ConvertTextFileToDictionary(FileName, Dictionary, CommentCharacter, KeySplit # def ConvertDictionaryToTextFile(FileName, Dictionary, CommentCharacter, KeySplitCharacter, ValueSplitFlag, ValueSplitCharacter): try: - F = open(FileName,'r') + F = open(FileName, 'r') Lines = [] Lines = F.readlines() F.close() @@ -265,7 +265,7 @@ def ConvertDictionaryToTextFile(FileName, Dictionary, CommentCharacter, KeySplit MaxLength = len(Key) Index = 0 for Line in Lines: - LineList = Line.split(KeySplitCharacter,1) + LineList = Line.split(KeySplitCharacter, 1) if len(LineList) >= 2: Key = LineList[0].split() if len(Key) == 1 and Key[0][0] != CommentCharacter and Key[0] in Dictionary: @@ -275,17 +275,17 @@ def ConvertDictionaryToTextFile(FileName, Dictionary, CommentCharacter, KeySplit Line = '%-*s %c %s\n' % (MaxLength, Key[0], KeySplitCharacter, Dictionary[Key[0]]) Lines.pop(Index) if Key[0] in Keys: - Lines.insert(Index,Line) + Lines.insert(Index, Line) Keys.remove(Key[0]) Index += 1 for RemainingKey in Keys: if ValueSplitFlag: - Line = '%-*s %c %s\n' % (MaxLength, RemainingKey, KeySplitCharacter,' '.join(Dictionary[RemainingKey])) + Line = '%-*s %c %s\n' % (MaxLength, RemainingKey, KeySplitCharacter, ' '.join(Dictionary[RemainingKey])) else: Line = '%-*s %c %s\n' % (MaxLength, RemainingKey, KeySplitCharacter, Dictionary[RemainingKey]) Lines.append(Line) try: - F = open(FileName,'w') + F = open(FileName, 'w') except: return False F.writelines(Lines) diff --git a/BaseTools/Source/Python/Common/FdfParserLite.py b/BaseTools/Source/Python/Common/FdfParserLite.py index a0ee249748e1..a8cce261202e 100644 --- a/BaseTools/Source/Python/Common/FdfParserLite.py +++ b/BaseTools/Source/Python/Common/FdfParserLite.py @@ -69,8 +69,8 @@ class Warning (Exception): # @param File The FDF name # @param Line The Line number that error occurs # - def __init__(self, Str, File = None, Line = None): - + def __init__(self, Str, File=None, Line=None): + FileLineTuple = GetRealFileLine(File, Line) self.FileName = FileLineTuple[0] self.LineNumber = FileLineTuple[1] @@ -359,8 +359,8 @@ def __ReplaceMacros(self, Str, File, Line): else: raise Warning("Macro not complete At Line ", self.FileName, self.CurrentLineNumber) return Str - - def __ReplaceFragment(self, StartPos, EndPos, Value = ' '): + + def __ReplaceFragment(self, StartPos, EndPos, Value=' '): if StartPos[0] == EndPos[0]: Offset = StartPos[1] while Offset <= EndPos[1]: diff --git a/BaseTools/Source/Python/Common/MigrationUtilities.py b/BaseTools/Source/Python/Common/MigrationUtilities.py index 6d6669d7ae57..e9f1cabcb794 100644 --- a/BaseTools/Source/Python/Common/MigrationUtilities.py +++ b/BaseTools/Source/Python/Common/MigrationUtilities.py @@ -423,7 +423,7 @@ def StoreHeader(TextFile, CommonHeader): Description = CommonHeader.Description License = CommonHeader.License - Header = "#/** @file\n#\n" + Header = "#/** @file\n#\n" Header += "# " + Abstract + "\n#\n" Header += "# " + Description.strip().replace("\n", "\n# ") + "\n" Header += "# " + CopyRight + "\n#\n" @@ -519,7 +519,7 @@ def GetXmlFileInfo(FileName, TagTuple): # @retval Options A optparse object containing the parsed options. # @retval InputFile Path of an source file to be migrated. # -def MigrationOptionParser(Source, Destinate, ToolName, VersionNumber = 1.0): +def MigrationOptionParser(Source, Destinate, ToolName, VersionNumber=1.0): # use clearer usage to override default usage message UsageString = "%s [-a] [-v|-q] [-o ] " % ToolName Version = "%s Version %.2f" % (ToolName, VersionNumber) diff --git a/BaseTools/Source/Python/Common/Misc.py b/BaseTools/Source/Python/Common/Misc.py index 0eedddc86125..777450d81860 100644 --- a/BaseTools/Source/Python/Common/Misc.py +++ b/BaseTools/Source/Python/Common/Misc.py @@ -38,7 +38,7 @@ from Common.MultipleWorkspace import MultipleWorkspace as mws ## Regular expression used to find out place holders in string template -gPlaceholderPattern = re.compile("\$\{([^$()\s]+)\}", re.MULTILINE|re.UNICODE) +gPlaceholderPattern = re.compile("\$\{([^$()\s]+)\}", re.MULTILINE | re.UNICODE) ## Dictionary used to store file time stamp for quick re-access gFileTimeStampCache = {} # {file path : file time stamp} @@ -293,11 +293,11 @@ def ProcessVariableArgument(Option, OptionString, Value, Parser): def GuidStringToGuidStructureString(Guid): GuidList = Guid.split('-') Result = '{' - for Index in range(0,3,1): + for Index in range(0, 3, 1): Result = Result + '0x' + GuidList[Index] + ', ' Result = Result + '{0x' + GuidList[3][0:2] + ', 0x' + GuidList[3][2:4] - for Index in range(0,12,2): - Result = Result + ', 0x' + GuidList[4][Index:Index+2] + for Index in range(0, 12, 2): + Result = Result + ', 0x' + GuidList[4][Index:Index + 2] Result += '}}' return Result @@ -494,7 +494,7 @@ def SaveFileOnChange(File, Content, IsBinaryFile=True): Fd.write(Content) Fd.close() except IOError, X: - EdkLogger.error(None, FILE_CREATE_FAILURE, ExtraData='IOError %s'%X) + EdkLogger.error(None, FILE_CREATE_FAILURE, ExtraData='IOError %s' % X) return True @@ -613,7 +613,7 @@ def __getitem__(self, Path): # # @retval A list of all files # -def GetFiles(Root, SkipList=None, FullPath = True): +def GetFiles(Root, SkipList=None, FullPath=True): OriPath = Root FileList = [] for Root, Dirs, Files in os.walk(Root): @@ -663,7 +663,7 @@ def RealPath2(File, Dir='', OverrideDir=''): if OverrideDir[-1] == os.path.sep: return NewFile[len(OverrideDir):], NewFile[0:len(OverrideDir)] else: - return NewFile[len(OverrideDir)+1:], NewFile[0:len(OverrideDir)] + return NewFile[len(OverrideDir) + 1:], NewFile[0:len(OverrideDir)] if GlobalData.gAllFiles: NewFile = GlobalData.gAllFiles[os.path.normpath(os.path.join(Dir, File))] if not NewFile: @@ -675,7 +675,7 @@ def RealPath2(File, Dir='', OverrideDir=''): if Dir[-1] == os.path.sep: return NewFile[len(Dir):], NewFile[0:len(Dir)] else: - return NewFile[len(Dir)+1:], NewFile[0:len(Dir)] + return NewFile[len(Dir) + 1:], NewFile[0:len(Dir)] else: return NewFile, '' @@ -701,7 +701,7 @@ def ValidFile2(AllFiles, File, Ext=None, Workspace='', EfiSource='', EdkSource=' # Replace the default dir to current dir if Dir == '.': Dir = os.getcwd() - Dir = Dir[len(Workspace)+1:] + Dir = Dir[len(Workspace) + 1:] # First check if File has Edk definition itself if File.find('$(EFI_SOURCE)') > -1 or File.find('$(EDK_SOURCE)') > -1: @@ -740,7 +740,7 @@ def ValidFile3(AllFiles, File, Workspace='', EfiSource='', EdkSource='', Dir='.' # Dir is current module dir related to workspace if Dir == '.': Dir = os.getcwd() - Dir = Dir[len(Workspace)+1:] + Dir = Dir[len(Workspace) + 1:] NewFile = File RelaPath = AllFiles[os.path.normpath(Dir)] @@ -865,7 +865,7 @@ def __init__(self, TemplateSection, PlaceHolderList): # # PlaceHolderName, PlaceHolderStartPoint, PlaceHolderEndPoint # - for PlaceHolder,Start,End in PlaceHolderList: + for PlaceHolder, Start, End in PlaceHolderList: self._SubSectionList.append(TemplateSection[SubSectionStart:Start]) self._SubSectionList.append(TemplateSection[Start:End]) self._PlaceHolderList.append(PlaceHolder) @@ -1251,11 +1251,11 @@ def __getitem__(self, key): if len(key) > 1: RestKeys = key[1:] elif self._Level_ > 1: - RestKeys = [self._Wildcard for i in range(0, self._Level_-1)] + RestKeys = [self._Wildcard for i in range(0, self._Level_ - 1)] else: FirstKey = key if self._Level_ > 1: - RestKeys = [self._Wildcard for i in range(0, self._Level_-1)] + RestKeys = [self._Wildcard for i in range(0, self._Level_ - 1)] if FirstKey == None or str(FirstKey).upper() in self._ValidWildcardList: FirstKey = self._Wildcard @@ -1328,11 +1328,11 @@ def __setitem__(self, key, value): if len(key) > 1: RestKeys = key[1:] else: - RestKeys = [self._Wildcard for i in range(0, self._Level_-1)] + RestKeys = [self._Wildcard for i in range(0, self._Level_ - 1)] else: FirstKey = key if self._Level_ > 1: - RestKeys = [self._Wildcard for i in range(0, self._Level_-1)] + RestKeys = [self._Wildcard for i in range(0, self._Level_ - 1)] if FirstKey in self._ValidWildcardList: FirstKey = self._Wildcard @@ -1437,7 +1437,7 @@ def AnalyzeDscPcd(Setting, PcdType, DataType=''): Pair += 1 elif ch == ')' and not InStr: Pair -= 1 - + if (Pair > 0 or InStr) and ch == TAB_VALUE_SPLIT: NewStr += '-' else: @@ -1491,7 +1491,7 @@ def AnalyzeDscPcd(Setting, PcdType, DataType=''): IsValid = (len(FieldList) <= 3) else: IsValid = (len(FieldList) <= 1) - return [Value, Type, Size], IsValid, 0 + return [Value, Type, Size], IsValid, 0 elif PcdType in (MODEL_PCD_DYNAMIC_VPD, MODEL_PCD_DYNAMIC_EX_VPD): VpdOffset = FieldList[0] Value = Size = '' @@ -1532,17 +1532,17 @@ def AnalyzeDscPcd(Setting, PcdType, DataType=''): # # @retval ValueList: A List contain value, datum type and toke number. # -def AnalyzePcdData(Setting): - ValueList = ['', '', ''] - - ValueRe = re.compile(r'^\s*L?\".*\|.*\"') +def AnalyzePcdData(Setting): + ValueList = ['', '', ''] + + ValueRe = re.compile(r'^\s*L?\".*\|.*\"') PtrValue = ValueRe.findall(Setting) ValueUpdateFlag = False if len(PtrValue) >= 1: Setting = re.sub(ValueRe, '', Setting) - ValueUpdateFlag = True + ValueUpdateFlag = True TokenList = Setting.split(TAB_VALUE_SPLIT) ValueList[0:len(TokenList)] = TokenList @@ -1578,17 +1578,17 @@ def AnalyzeHiiPcdData(Setting): # # @retval ValueList: A List contain VpdOffset, MaxDatumSize and InitialValue. # -def AnalyzeVpdPcdData(Setting): - ValueList = ['', '', ''] - - ValueRe = re.compile(r'\s*L?\".*\|.*\"\s*$') +def AnalyzeVpdPcdData(Setting): + ValueList = ['', '', ''] + + ValueRe = re.compile(r'\s*L?\".*\|.*\"\s*$') PtrValue = ValueRe.findall(Setting) ValueUpdateFlag = False if len(PtrValue) >= 1: Setting = re.sub(ValueRe, '', Setting) - ValueUpdateFlag = True + ValueUpdateFlag = True TokenList = Setting.split(TAB_VALUE_SPLIT) ValueList[0:len(TokenList)] = TokenList @@ -1604,12 +1604,12 @@ def AnalyzeVpdPcdData(Setting): # def CheckPcdDatum(Type, Value): if Type == "VOID*": - ValueRe = re.compile(r'\s*L?\".*\"\s*$') + ValueRe = re.compile(r'\s*L?\".*\"\s*$') if not (((Value.startswith('L"') or Value.startswith('"')) and Value.endswith('"')) or (Value.startswith('{') and Value.endswith('}')) ): return False, "Invalid value [%s] of type [%s]; must be in the form of {...} for array"\ - ", or \"...\" for string, or L\"...\" for unicode string" % (Value, Type) + ", or \"...\" for string, or L\"...\" for unicode string" % (Value, Type) elif ValueRe.match(Value): # Check the chars in UnicodeString or CString is printable if Value.startswith("L"): @@ -1662,7 +1662,7 @@ def SplitOption(OptionString): if CurrentChar in ["/", "-"] and LastChar in [" ", "\t", "\r", "\n"]: if Index > OptionStart: - OptionList.append(OptionString[OptionStart:Index-1]) + OptionList.append(OptionString[OptionStart:Index - 1]) OptionStart = Index LastChar = CurrentChar OptionList.append(OptionString[OptionStart:]) @@ -1739,7 +1739,7 @@ def __init__(self, File='', Root='', AlterRoot='', Type='', IsBinary=False, if self.Root[-1] == os.path.sep: self.File = self.Path[len(self.Root):] else: - self.File = self.Path[len(self.Root)+1:] + self.File = self.Path[len(self.Root) + 1:] else: self.Path = os.path.normpath(self.File) diff --git a/BaseTools/Source/Python/Common/ToolDefClassObject.py b/BaseTools/Source/Python/Common/ToolDefClassObject.py index 4fefbd91e0a0..4d54027820ff 100644 --- a/BaseTools/Source/Python/Common/ToolDefClassObject.py +++ b/BaseTools/Source/Python/Common/ToolDefClassObject.py @@ -42,7 +42,7 @@ # @var MacroDictionary: To store keys and values defined in DEFINE statement # class ToolDefClassObject(object): - def __init__(self, FileName = None): + def __init__(self, FileName=None): self.ToolsDefTxtDictionary = {} self.MacroDictionary = {} for Env in os.environ: @@ -61,7 +61,7 @@ def LoadToolDefFile(self, FileName): FileContent = [] if os.path.isfile(FileName): try: - F = open(FileName,'r') + F = open(FileName, 'r') FileContent = F.readlines() except: EdkLogger.error("tools_def.txt parser", FILE_OPEN_FAILURE, ExtraData=FileName) @@ -155,7 +155,7 @@ def LoadToolDefFile(self, FileName): self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_COMMAND_TYPE].sort() KeyList = [TAB_TOD_DEFINES_TARGET, TAB_TOD_DEFINES_TOOL_CHAIN_TAG, TAB_TOD_DEFINES_TARGET_ARCH, TAB_TOD_DEFINES_COMMAND_TYPE] - for Index in range(3,-1,-1): + for Index in range(3, -1, -1): for Key in dict(self.ToolsDefTxtDictionary): List = Key.split('_') if List[Index] == '*': diff --git a/BaseTools/Source/Python/GenFds/GenFds.py b/BaseTools/Source/Python/GenFds/GenFds.py index a0beff039132..4fa4eda04a5f 100644 --- a/BaseTools/Source/Python/GenFds/GenFds.py +++ b/BaseTools/Source/Python/GenFds/GenFds.py @@ -34,7 +34,7 @@ import Common.GlobalData as GlobalData from Common import EdkLogger from Common.String import * -from Common.Misc import DirCache,PathClass +from Common.Misc import DirCache, PathClass from Common.Misc import SaveFileOnChange from Common.Misc import ClearDuplicatedInf from Common.Misc import GuidStructureStringToGuidString @@ -93,7 +93,7 @@ def main(): if 'EDK_SOURCE' in os.environ.keys(): GenFdsGlobalVariable.EdkSourceDir = os.path.normcase(os.environ['EDK_SOURCE']) if (Options.debug): - GenFdsGlobalVariable.VerboseLogger( "Using Workspace:" + Workspace) + GenFdsGlobalVariable.VerboseLogger("Using Workspace:" + Workspace) os.chdir(GenFdsGlobalVariable.WorkSpaceDir) # set multiple workspace @@ -106,7 +106,7 @@ def main(): if FdfFilename[0:2] == '..': FdfFilename = os.path.realpath(FdfFilename) - if not os.path.isabs (FdfFilename): + if not os.path.isabs(FdfFilename): FdfFilename = mws.join(GenFdsGlobalVariable.WorkSpaceDir, FdfFilename) if not os.path.exists(FdfFilename): EdkLogger.error("GenFds", FILE_NOT_FOUND, ExtraData=FdfFilename) @@ -287,7 +287,7 @@ def main(): GenFds.DisplayFvSpaceInfo(FdfParserObj) except FdfParser.Warning, X: - EdkLogger.error(X.ToolName, FORMAT_INVALID, File=X.FileName, Line=X.LineNumber, ExtraData=X.Message, RaiseError = False) + EdkLogger.error(X.ToolName, FORMAT_INVALID, File=X.FileName, Line=X.LineNumber, ExtraData=X.Message, RaiseError=False) ReturnCode = FORMAT_INVALID except FatalError, X: if Options.debug != None: @@ -326,7 +326,7 @@ def SingleCheckCallback(option, opt_str, value, parser): # def myOptionParser(): usage = "%prog [options] -f input_file -a arch_list -b build_target -p active_platform -t tool_chain_tag -D \"MacroName [= MacroValue]\"" - Parser = OptionParser(usage=usage,description=__copyright__,version="%prog " + str(versionNumber)) + Parser = OptionParser(usage=usage, description=__copyright__, version="%prog " + str(versionNumber)) Parser.add_option("-f", "--file", dest="filename", type="string", help="Name of FDF file to convert", action="callback", callback=SingleCheckCallback) Parser.add_option("-a", "--arch", dest="archList", help="comma separated list containing one or more of: IA32, X64, IPF, ARM, AARCH64 or EBC which should be built, overrides target.txt?s TARGET_ARCH") Parser.add_option("-q", "--quiet", action="store_true", type=None, help="Disable all messages except FATAL ERRORS.") @@ -503,8 +503,8 @@ def DisplayFvSpaceInfo(FdfParser): if UsedSizeValue == TotalSizeValue: Percentage = '100' else: - Percentage = str((UsedSizeValue+0.0)/TotalSizeValue)[0:4].lstrip('0.') - + Percentage = str((UsedSizeValue + 0.0) / TotalSizeValue)[0:4].lstrip('0.') + GenFdsGlobalVariable.InfLogger(Name + ' ' + '[' + Percentage + '%Full] ' + str(TotalSizeValue) + ' total, ' + str(UsedSizeValue) + ' used, ' + str(FreeSizeValue) + ' free') ## PreprocessImage() diff --git a/BaseTools/Source/Python/GenFds/GenFdsGlobalVariable.py b/BaseTools/Source/Python/GenFds/GenFdsGlobalVariable.py index 5bdc1b8288a8..8a974236f221 100644 --- a/BaseTools/Source/Python/GenFds/GenFdsGlobalVariable.py +++ b/BaseTools/Source/Python/GenFds/GenFdsGlobalVariable.py @@ -274,7 +274,7 @@ def GetModuleCodaTargetList(Inf, Arch): # @param ArchList The Arch list of platform # def SetDir (OutputDir, FdfParser, WorkSpace, ArchList): - GenFdsGlobalVariable.VerboseLogger( "GenFdsGlobalVariable.OutputDir :%s" %OutputDir) + GenFdsGlobalVariable.VerboseLogger("GenFdsGlobalVariable.OutputDir :%s" % OutputDir) # GenFdsGlobalVariable.OutputDirDict = OutputDir GenFdsGlobalVariable.FdfParser = FdfParser GenFdsGlobalVariable.WorkSpace = WorkSpace @@ -292,7 +292,7 @@ def SetDir (OutputDir, FdfParser, WorkSpace, ArchList): # Create FV Address inf file # GenFdsGlobalVariable.FvAddressFileName = os.path.join(GenFdsGlobalVariable.FfsDir, 'FvAddress.inf') - FvAddressFile = open (GenFdsGlobalVariable.FvAddressFileName, 'w') + FvAddressFile = open(GenFdsGlobalVariable.FvAddressFileName, 'w') # # Add [Options] # @@ -304,7 +304,7 @@ def SetDir (OutputDir, FdfParser, WorkSpace, ArchList): break FvAddressFile.writelines("EFI_BOOT_DRIVER_BASE_ADDRESS = " + \ - BsAddress + \ + BsAddress + \ T_CHAR_LF) RtAddress = '0' @@ -313,7 +313,7 @@ def SetDir (OutputDir, FdfParser, WorkSpace, ArchList): RtAddress = GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag].RtBaseAddress FvAddressFile.writelines("EFI_RUNTIME_DRIVER_BASE_ADDRESS = " + \ - RtAddress + \ + RtAddress + \ T_CHAR_LF) FvAddressFile.close() @@ -386,13 +386,13 @@ def GenerateSection(Output, Input, Type=None, CompressionType=None, Guid=None, CommandFile = Output + '.txt' if Ui not in [None, '']: #Cmd += ["-n", '"' + Ui + '"'] - SectionData = array.array('B', [0,0,0,0]) + SectionData = array.array('B', [0, 0, 0, 0]) SectionData.fromstring(Ui.encode("utf_16_le")) SectionData.append(0) SectionData.append(0) Len = len(SectionData) GenFdsGlobalVariable.SectionHeader.pack_into(SectionData, 0, Len & 0xff, (Len >> 8) & 0xff, (Len >> 16) & 0xff, 0x15) - SaveFileOnChange(Output, SectionData.tostring()) + SaveFileOnChange(Output, SectionData.tostring()) elif Ver not in [None, '']: Cmd += ["-n", Ver] if BuildNumber: @@ -461,12 +461,12 @@ def GenerateFirmwareVolume(Output, Input, BaseAddress=None, ForceRebase=None, Ca Cmd = ["GenFv"] if BaseAddress not in [None, '']: Cmd += ["-r", BaseAddress] - + if ForceRebase == False: - Cmd +=["-F", "FALSE"] + Cmd += ["-F", "FALSE"] elif ForceRebase == True: - Cmd +=["-F", "TRUE"] - + Cmd += ["-F", "TRUE"] + if Capsule: Cmd += ["-c"] if Dump: @@ -570,7 +570,7 @@ def GenerateOptionRom(Output, EfiInput, BinaryInput, Compress=False, ClassCode=N if VendorId != None: Cmd += ["-f", VendorId] - Cmd += ["-o", Output] + Cmd += ["-o", Output] GenFdsGlobalVariable.CallExternalTool(Cmd, "Failed to generate option rom") @staticmethod @@ -606,7 +606,7 @@ def CallExternalTool (cmd, errorMess, returnValue=[]): sys.stdout.write('\n') try: - PopenObject = subprocess.Popen(' '.join(cmd), stdout=subprocess.PIPE, stderr= subprocess.PIPE, shell=True) + PopenObject = subprocess.Popen(' '.join(cmd), stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) except Exception, X: EdkLogger.error("GenFds", COMMAND_FAILURE, ExtraData="%s: %s" % (str(X), cmd[0])) (out, error) = PopenObject.communicate() @@ -618,7 +618,7 @@ def CallExternalTool (cmd, errorMess, returnValue=[]): returnValue[0] = PopenObject.returncode return if PopenObject.returncode != 0 or GenFdsGlobalVariable.VerboseMode or GenFdsGlobalVariable.DebugLevel != -1: - GenFdsGlobalVariable.InfLogger ("Return Value = %d" %PopenObject.returncode) + GenFdsGlobalVariable.InfLogger ("Return Value = %d" % PopenObject.returncode) GenFdsGlobalVariable.InfLogger (out) GenFdsGlobalVariable.InfLogger (error) if PopenObject.returncode != 0: @@ -631,7 +631,7 @@ def VerboseLogger (msg): def InfLogger (msg): EdkLogger.info(msg) - def ErrorLogger (msg, File = None, Line = None, ExtraData = None): + def ErrorLogger (msg, File=None, Line=None, ExtraData=None): EdkLogger.error('GenFds', GENFDS_ERROR, msg, File, Line, ExtraData) def DebugLogger (Level, msg): @@ -642,7 +642,7 @@ def DebugLogger (Level, msg): # @param Str String that may contain macro # @param MacroDict Dictionary that contains macro value pair # - def MacroExtend (Str, MacroDict = {}, Arch = 'COMMON'): + def MacroExtend (Str, MacroDict={}, Arch='COMMON'): if Str == None : return None @@ -699,10 +699,10 @@ def GetPcdValue (PcdPattern): PcdValue = PcdObj.DefaultValue return PcdValue - - for Package in GenFdsGlobalVariable.WorkSpace.GetPackageList(GenFdsGlobalVariable.ActivePlatform, - Arch, - GenFdsGlobalVariable.TargetName, + + for Package in GenFdsGlobalVariable.WorkSpace.GetPackageList(GenFdsGlobalVariable.ActivePlatform, + Arch, + GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag): PcdDict = Package.Pcds for Key in PcdDict: diff --git a/BaseTools/Source/Python/GenFds/GuidSection.py b/BaseTools/Source/Python/GenFds/GuidSection.py index 006cf0f2169b..cc0c05a28c1e 100644 --- a/BaseTools/Source/Python/GenFds/GuidSection.py +++ b/BaseTools/Source/Python/GenFds/GuidSection.py @@ -53,7 +53,7 @@ def __init__(self): # @param Dict dictionary contains macro and its value # @retval tuple (Generated file name, section alignment) # - def GenSection(self, OutputPath, ModuleName, SecNum, KeyStringList, FfsInf = None, Dict = {}): + def GenSection(self, OutputPath, ModuleName, SecNum, KeyStringList, FfsInf=None, Dict={}): # # Generate all section # @@ -65,7 +65,7 @@ def GenSection(self, OutputPath, ModuleName, SecNum, KeyStringList, FfsInf = Non self.SectionType = FfsInf.__ExtendMacro__(self.SectionType) self.CurrentArchList = [FfsInf.CurrentArch] - SectFile = tuple() + SectFile = tuple() SectAlign = [] Index = 0 MaxAlign = None @@ -84,7 +84,7 @@ def GenSection(self, OutputPath, ModuleName, SecNum, KeyStringList, FfsInf = Non for Sect in self.SectionList: Index = Index + 1 - SecIndex = '%s.%d' %(SecNum,Index) + SecIndex = '%s.%d' % (SecNum, Index) # set base address for inside FvImage if isinstance(Sect, FvImageSection): if self.FvAddr != []: @@ -93,7 +93,7 @@ def GenSection(self, OutputPath, ModuleName, SecNum, KeyStringList, FfsInf = Non elif isinstance(Sect, GuidSection): Sect.FvAddr = self.FvAddr Sect.FvParentAddr = self.FvParentAddr - ReturnSectList, align = Sect.GenSection(OutputPath, ModuleName, SecIndex, KeyStringList,FfsInf, Dict) + ReturnSectList, align = Sect.GenSection(OutputPath, ModuleName, SecIndex, KeyStringList, FfsInf, Dict) if isinstance(Sect, GuidSection): if Sect.IncludeFvSection: self.IncludeFvSection = Sect.IncludeFvSection @@ -118,10 +118,10 @@ def GenSection(self, OutputPath, ModuleName, SecNum, KeyStringList, FfsInf = Non self.Alignment = MaxAlign OutputFile = OutputPath + \ - os.sep + \ + os.sep + \ ModuleName + \ - 'SEC' + \ - SecNum + \ + 'SEC' + \ + SecNum + \ Ffs.SectionSuffix['GUIDED'] OutputFile = os.path.normpath(OutputFile) @@ -135,7 +135,7 @@ def GenSection(self, OutputPath, ModuleName, SecNum, KeyStringList, FfsInf = Non # GENCRC32 section # if self.NameGuid == None : - GenFdsGlobalVariable.VerboseLogger( "Use GenSection function Generate CRC32 Section") + GenFdsGlobalVariable.VerboseLogger("Use GenSection function Generate CRC32 Section") GenFdsGlobalVariable.GenerateSection(OutputFile, SectFile, Section.Section.SectionType[self.SectionType], InputAlign=SectAlign) OutputFileList = [] OutputFileList.append(OutputFile) @@ -144,7 +144,7 @@ def GenSection(self, OutputPath, ModuleName, SecNum, KeyStringList, FfsInf = Non elif ExternalTool == None: EdkLogger.error("GenFds", GENFDS_ERROR, "No tool found with GUID %s" % self.NameGuid) else: - DummyFile = OutputFile+".dummy" + DummyFile = OutputFile + ".dummy" # # Call GenSection with DUMMY section type. # @@ -153,10 +153,10 @@ def GenSection(self, OutputPath, ModuleName, SecNum, KeyStringList, FfsInf = Non # Use external tool process the Output # TempFile = OutputPath + \ - os.sep + \ + os.sep + \ ModuleName + \ - 'SEC' + \ - SecNum + \ + 'SEC' + \ + SecNum + \ '.tmp' TempFile = os.path.normpath(TempFile) # @@ -197,12 +197,12 @@ def GenSection(self, OutputPath, ModuleName, SecNum, KeyStringList, FfsInf = Non if not os.path.exists(TempFile): EdkLogger.error("GenFds", COMMAND_FAILURE, 'Fail to call %s, no output file was generated' % ExternalTool) - FileHandleIn = open(DummyFile,'rb') - FileHandleIn.seek(0,2) + FileHandleIn = open(DummyFile, 'rb') + FileHandleIn.seek(0, 2) InputFileSize = FileHandleIn.tell() - - FileHandleOut = open(TempFile,'rb') - FileHandleOut.seek(0,2) + + FileHandleOut = open(TempFile, 'rb') + FileHandleOut.seek(0, 2) TempFileSize = FileHandleOut.tell() Attribute = [] @@ -213,7 +213,7 @@ def GenSection(self, OutputPath, ModuleName, SecNum, KeyStringList, FfsInf = Non if self.ProcessRequired == "NONE" and HeaderLength == None: if TempFileSize > InputFileSize: FileHandleIn.seek(0) - BufferIn = FileHandleIn.read() + BufferIn = FileHandleIn.read() FileHandleOut.seek(0) BufferOut = FileHandleOut.read() if BufferIn == BufferOut[TempFileSize - InputFileSize:]: @@ -224,18 +224,18 @@ def GenSection(self, OutputPath, ModuleName, SecNum, KeyStringList, FfsInf = Non FileHandleIn.close() FileHandleOut.close() - + if FirstCall and 'PROCESSING_REQUIRED' in Attribute: # Guided data by -z option on first call is the process required data. Call the guided tool with the real option. GenFdsGlobalVariable.GuidTool(TempFile, [DummyFile], ExternalTool, CmdOption) - + # # Call Gensection Add Section Header # if self.ProcessRequired in ("TRUE", "1"): if 'PROCESSING_REQUIRED' not in Attribute: Attribute.append('PROCESSING_REQUIRED') - + if self.AuthStatusValid in ("TRUE", "1"): Attribute.append('AUTH_STATUS_VALID') GenFdsGlobalVariable.GenerateSection(OutputFile, [TempFile], Section.Section.SectionType['GUIDED'], @@ -263,7 +263,7 @@ def __FindExtendTool__(self): ToolDb = ToolDefClassObject.ToolDefDict(GenFdsGlobalVariable.ConfDir).ToolsDefTxtDatabase if ToolChain not in ToolDb['TOOL_CHAIN_TAG']: EdkLogger.error("GenFds", GENFDS_ERROR, "Can not find external tool because tool tag %s is not defined in tools_def.txt!" % ToolChain) - self.KeyStringList = [Target+'_'+ToolChain+'_'+self.CurrentArchList[0]] + self.KeyStringList = [Target + '_' + ToolChain + '_' + self.CurrentArchList[0]] for Arch in self.CurrentArchList: if Target + '_' + ToolChain + '_' + Arch not in self.KeyStringList: self.KeyStringList.append(Target + '_' + ToolChain + '_' + Arch) @@ -275,30 +275,30 @@ def __FindExtendTool__(self): if self.NameGuid == ToolDef[1]: KeyList = ToolDef[0].split('_') Key = KeyList[0] + \ - '_' + \ + '_' + \ KeyList[1] + \ - '_' + \ + '_' + \ KeyList[2] if Key in self.KeyStringList and KeyList[4] == 'GUID': - ToolPath = ToolDefinition.get( Key + \ - '_' + \ + ToolPath = ToolDefinition.get(Key + \ + '_' + \ KeyList[3] + \ - '_' + \ + '_' + \ 'PATH') - ToolOption = ToolDefinition.get( Key + \ - '_' + \ + ToolOption = ToolDefinition.get(Key + \ + '_' + \ KeyList[3] + \ - '_' + \ + '_' + \ 'FLAGS') if ToolPathTmp == None: ToolPathTmp = ToolPath else: if ToolPathTmp != ToolPath: EdkLogger.error("GenFds", GENFDS_ERROR, "Don't know which tool to use, %s or %s ?" % (ToolPathTmp, ToolPath)) - - + + return ToolPathTmp, ToolOption diff --git a/BaseTools/Source/Python/GenFds/Region.py b/BaseTools/Source/Python/GenFds/Region.py index feb56cb60f27..01e998e54c6f 100644 --- a/BaseTools/Source/Python/GenFds/Region.py +++ b/BaseTools/Source/Python/GenFds/Region.py @@ -54,10 +54,10 @@ def __init__(self): # @retval string Generated FV file path # - def AddToBuffer(self, Buffer, BaseAddress, BlockSizeList, ErasePolarity, ImageBinDict, vtfDict = None, MacroDict = {}): + def AddToBuffer(self, Buffer, BaseAddress, BlockSizeList, ErasePolarity, ImageBinDict, vtfDict=None, MacroDict={}): Size = self.Size GenFdsGlobalVariable.InfLogger('\nGenerate Region at Offset 0x%X' % self.Offset) - GenFdsGlobalVariable.InfLogger(" Region Size = 0x%X" %Size) + GenFdsGlobalVariable.InfLogger(" Region Size = 0x%X" % Size) GenFdsGlobalVariable.SharpCounter = 0 if self.RegionType == 'FV': @@ -65,13 +65,13 @@ def AddToBuffer(self, Buffer, BaseAddress, BlockSizeList, ErasePolarity, ImageBi # Get Fv from FvDict # self.FvAddress = int(BaseAddress, 16) + self.Offset - FvBaseAddress = '0x%X' %self.FvAddress - FvOffset = 0 + FvBaseAddress = '0x%X' % self.FvAddress + FvOffset = 0 for RegionData in self.RegionDataList: FileName = None if RegionData.endswith(".fv"): RegionData = GenFdsGlobalVariable.MacroExtend(RegionData, MacroDict) - GenFdsGlobalVariable.InfLogger(' Region FV File Name = .fv : %s'%RegionData) + GenFdsGlobalVariable.InfLogger(' Region FV File Name = .fv : %s' % RegionData) if RegionData[1] != ':' : RegionData = os.path.join (GenFdsGlobalVariable.WorkSpaceDir, RegionData) if not os.path.exists(RegionData): @@ -101,7 +101,7 @@ def AddToBuffer(self, Buffer, BaseAddress, BlockSizeList, ErasePolarity, ImageBi EdkLogger.error("GenFds", GENFDS_ERROR, "FV (%s) is NOT %s Aligned!" % (FvObj.UiFvName, FvObj.FvAlignment)) FvBuffer = StringIO.StringIO('') - FvBaseAddress = '0x%X' %self.FvAddress + FvBaseAddress = '0x%X' % self.FvAddress BlockSize = None BlockNum = None FvObj.AddToBuffer(FvBuffer, FvBaseAddress, BlockSize, BlockNum, ErasePolarity, vtfDict) @@ -128,7 +128,7 @@ def AddToBuffer(self, Buffer, BaseAddress, BlockSizeList, ErasePolarity, ImageBi EdkLogger.error("GenFds", GENFDS_ERROR, "Size of FV File (%s) is larger than Region Size 0x%X specified." \ % (RegionData, Size)) - BinFile = open (FileName, 'r+b') + BinFile = open(FileName, 'r+b') Buffer.write(BinFile.read()) BinFile.close() Size = Size - FileLength @@ -150,7 +150,7 @@ def AddToBuffer(self, Buffer, BaseAddress, BlockSizeList, ErasePolarity, ImageBi for RegionData in self.RegionDataList: if RegionData.endswith(".cap"): RegionData = GenFdsGlobalVariable.MacroExtend(RegionData, MacroDict) - GenFdsGlobalVariable.InfLogger(' Region CAPSULE Image Name = .cap : %s'%RegionData) + GenFdsGlobalVariable.InfLogger(' Region CAPSULE Image Name = .cap : %s' % RegionData) if RegionData[1] != ':' : RegionData = os.path.join (GenFdsGlobalVariable.WorkSpaceDir, RegionData) if not os.path.exists(RegionData): @@ -187,7 +187,7 @@ def AddToBuffer(self, Buffer, BaseAddress, BlockSizeList, ErasePolarity, ImageBi EdkLogger.error("GenFds", GENFDS_ERROR, "Size 0x%X of Capsule File (%s) is larger than Region Size 0x%X specified." \ % (FileLength, RegionData, Size)) - BinFile = open (FileName, 'r+b') + BinFile = open(FileName, 'r+b') Buffer.write(BinFile.read()) BinFile.close() Size = Size - FileLength @@ -217,8 +217,8 @@ def AddToBuffer(self, Buffer, BaseAddress, BlockSizeList, ErasePolarity, ImageBi EdkLogger.error("GenFds", GENFDS_ERROR, "Size of File (%s) is larger than Region Size 0x%X specified." \ % (RegionData, Size)) - GenFdsGlobalVariable.InfLogger(' Region File Name = %s'%RegionData) - BinFile = open (RegionData, 'rb') + GenFdsGlobalVariable.InfLogger(' Region File Name = %s' % RegionData) + BinFile = open(RegionData, 'rb') Buffer.write(BinFile.read()) BinFile.close() Size = Size - FileLength @@ -273,17 +273,17 @@ def GetFvAlignValue(self, Str): Granu = 1024 Str = Str[:-1] elif Str.endswith('M'): - Granu = 1024*1024 + Granu = 1024 * 1024 Str = Str[:-1] elif Str.endswith('G'): - Granu = 1024*1024*1024 + Granu = 1024 * 1024 * 1024 Str = Str[:-1] else: pass - AlignValue = int(Str)*Granu + AlignValue = int(Str) * Granu return AlignValue - + ## BlockSizeOfRegion() # # @param BlockSizeList List of block information @@ -304,7 +304,7 @@ def BlockInfoOfRegion(self, BlockSizeList, FvObj): else: # region ended within current blocks if self.Offset + self.Size <= End: - ExpectedList.append((BlockSize, (RemindingSize + BlockSize - 1)/BlockSize)) + ExpectedList.append((BlockSize, (RemindingSize + BlockSize - 1) / BlockSize)) break # region not ended yet else: @@ -313,11 +313,11 @@ def BlockInfoOfRegion(self, BlockSizeList, FvObj): UsedBlockNum = BlockNum # region started in middle of current blocks else: - UsedBlockNum = (End - self.Offset)/BlockSize + UsedBlockNum = (End - self.Offset) / BlockSize Start = End ExpectedList.append((BlockSize, UsedBlockNum)) RemindingSize -= BlockSize * UsedBlockNum - + if FvObj.BlockSizeList == []: FvObj.BlockSizeList = ExpectedList else: @@ -333,22 +333,22 @@ def BlockInfoOfRegion(self, BlockSizeList, FvObj): Sum += Item[0] * Item[1] if self.Size < Sum: EdkLogger.error("GenFds", GENFDS_ERROR, "Total Size of FV %s 0x%x is larger than Region Size 0x%x " - %(FvObj.UiFvName, Sum, self.Size)) + % (FvObj.UiFvName, Sum, self.Size)) # check whether the BlockStatements in FV section is appropriate ExpectedListData = '' for Item in ExpectedList: - ExpectedListData += "BlockSize = 0x%x\n\tNumBlocks = 0x%x\n\t"%Item + ExpectedListData += "BlockSize = 0x%x\n\tNumBlocks = 0x%x\n\t" % Item Index = 0 for Item in FvObj.BlockSizeList: if Item[0] != ExpectedList[Index][0]: EdkLogger.error("GenFds", GENFDS_ERROR, "BlockStatements of FV %s are not align with FD's, suggested FV BlockStatement" - %FvObj.UiFvName, ExtraData = ExpectedListData) + % FvObj.UiFvName, ExtraData=ExpectedListData) elif Item[1] != ExpectedList[Index][1]: if (Item[1] < ExpectedList[Index][1]) and (Index == len(FvObj.BlockSizeList) - 1): break; else: EdkLogger.error("GenFds", GENFDS_ERROR, "BlockStatements of FV %s are not align with FD's, suggested FV BlockStatement" - %FvObj.UiFvName, ExtraData = ExpectedListData) + % FvObj.UiFvName, ExtraData=ExpectedListData) else: Index += 1 diff --git a/BaseTools/Source/Python/GenFds/UiSection.py b/BaseTools/Source/Python/GenFds/UiSection.py index e4f3647f1323..d54e3b2a6d04 100644 --- a/BaseTools/Source/Python/GenFds/UiSection.py +++ b/BaseTools/Source/Python/GenFds/UiSection.py @@ -48,7 +48,7 @@ def __init__(self): # @param Dict dictionary contains macro and its value # @retval tuple (Generated file name, section alignment) # - def GenSection(self, OutputPath, ModuleName, SecNum, KeyStringList, FfsInf = None, Dict = {}): + def GenSection(self, OutputPath, ModuleName, SecNum, KeyStringList, FfsInf=None, Dict={}): # # Prepare the parameter of GenSection # diff --git a/BaseTools/Source/Python/GenFds/VerSection.py b/BaseTools/Source/Python/GenFds/VerSection.py index 7399e7a5d4c7..ad995d314bd6 100644 --- a/BaseTools/Source/Python/GenFds/VerSection.py +++ b/BaseTools/Source/Python/GenFds/VerSection.py @@ -48,7 +48,7 @@ def __init__(self): # @param Dict dictionary contains macro and its value # @retval tuple (Generated file name, section alignment) # - def GenSection(self,OutputPath, ModuleName, SecNum, KeyStringList, FfsInf = None, Dict = {}): + def GenSection(self, OutputPath, ModuleName, SecNum, KeyStringList, FfsInf=None, Dict={}): # # Prepare the parameter of GenSection # diff --git a/BaseTools/Source/Python/GenFds/Vtf.py b/BaseTools/Source/Python/GenFds/Vtf.py index 64b5d771382d..06e3d275c381 100644 --- a/BaseTools/Source/Python/GenFds/Vtf.py +++ b/BaseTools/Source/Python/GenFds/Vtf.py @@ -67,80 +67,80 @@ def GenVtf(self, FdAddressDict) : def GenBsfInf (self): FvList = self.GetFvList() self.BsfInfName = os.path.join(GenFdsGlobalVariable.FvDir, self.UiName + '.inf') - BsfInf = open (self.BsfInfName, 'w+') + BsfInf = open(self.BsfInfName, 'w+') if self.ResetBin != None: BsfInf.writelines ("[OPTIONS]" + T_CHAR_LF) - BsfInf.writelines ("IA32_RST_BIN" + \ - " = " + \ + BsfInf.writelines ("IA32_RST_BIN" + \ + " = " + \ GenFdsGlobalVariable.MacroExtend(GenFdsGlobalVariable.ReplaceWorkspaceMacro(self.ResetBin)) + \ - T_CHAR_LF ) - BsfInf.writelines (T_CHAR_LF ) - + T_CHAR_LF) + BsfInf.writelines (T_CHAR_LF) + BsfInf.writelines ("[COMPONENTS]" + T_CHAR_LF) for ComponentObj in self.ComponentStatementList : - BsfInf.writelines ("COMP_NAME" + \ - " = " + \ + BsfInf.writelines ("COMP_NAME" + \ + " = " + \ ComponentObj.CompName + \ - T_CHAR_LF ) + T_CHAR_LF) if ComponentObj.CompLoc.upper() == 'NONE': - BsfInf.writelines ("COMP_LOC" + \ - " = " + \ - 'N' + \ - T_CHAR_LF ) - + BsfInf.writelines ("COMP_LOC" + \ + " = " + \ + 'N' + \ + T_CHAR_LF) + elif ComponentObj.FilePos != None: - BsfInf.writelines ("COMP_LOC" + \ - " = " + \ + BsfInf.writelines ("COMP_LOC" + \ + " = " + \ ComponentObj.FilePos + \ - T_CHAR_LF ) + T_CHAR_LF) else: Index = FvList.index(ComponentObj.CompLoc.upper()) if Index == 0: - BsfInf.writelines ("COMP_LOC" + \ - " = " + \ - 'F' + \ - T_CHAR_LF ) + BsfInf.writelines ("COMP_LOC" + \ + " = " + \ + 'F' + \ + T_CHAR_LF) elif Index == 1: - BsfInf.writelines ("COMP_LOC" + \ - " = " + \ - 'S' + \ - T_CHAR_LF ) - - BsfInf.writelines ("COMP_TYPE" + \ - " = " + \ + BsfInf.writelines ("COMP_LOC" + \ + " = " + \ + 'S' + \ + T_CHAR_LF) + + BsfInf.writelines ("COMP_TYPE" + \ + " = " + \ ComponentObj.CompType + \ - T_CHAR_LF ) - BsfInf.writelines ("COMP_VER" + \ - " = " + \ + T_CHAR_LF) + BsfInf.writelines ("COMP_VER" + \ + " = " + \ ComponentObj.CompVer + \ - T_CHAR_LF ) - BsfInf.writelines ("COMP_CS" + \ - " = " + \ + T_CHAR_LF) + BsfInf.writelines ("COMP_CS" + \ + " = " + \ ComponentObj.CompCs + \ - T_CHAR_LF ) - + T_CHAR_LF) + BinPath = ComponentObj.CompBin if BinPath != '-': BinPath = GenFdsGlobalVariable.MacroExtend(GenFdsGlobalVariable.ReplaceWorkspaceMacro(BinPath)) - BsfInf.writelines ("COMP_BIN" + \ - " = " + \ + BsfInf.writelines ("COMP_BIN" + \ + " = " + \ BinPath + \ - T_CHAR_LF ) - + T_CHAR_LF) + SymPath = ComponentObj.CompSym if SymPath != '-': SymPath = GenFdsGlobalVariable.MacroExtend(GenFdsGlobalVariable.ReplaceWorkspaceMacro(SymPath)) - BsfInf.writelines ("COMP_SYM" + \ - " = " + \ + BsfInf.writelines ("COMP_SYM" + \ + " = " + \ SymPath + \ - T_CHAR_LF ) - BsfInf.writelines ("COMP_SIZE" + \ - " = " + \ + T_CHAR_LF) + BsfInf.writelines ("COMP_SIZE" + \ + " = " + \ ComponentObj.CompSize + \ - T_CHAR_LF ) - BsfInf.writelines (T_CHAR_LF ) - + T_CHAR_LF) + BsfInf.writelines (T_CHAR_LF) + BsfInf.close() ## GenFvList() method @@ -170,7 +170,7 @@ def GetBaseAddressArg(self, FdAddressDict): (BaseAddress, Size) = FdAddressDict.get(i) CmdStr += ( '-r', '0x%x' % BaseAddress, - '-s', '0x%x' %Size, + '-s', '0x%x' % Size, ) return CmdStr diff --git a/BaseTools/Source/Python/GenPatchPcdTable/GenPatchPcdTable.py b/BaseTools/Source/Python/GenPatchPcdTable/GenPatchPcdTable.py index 50d99f7267a3..36e539f67458 100644 --- a/BaseTools/Source/Python/GenPatchPcdTable/GenPatchPcdTable.py +++ b/BaseTools/Source/Python/GenPatchPcdTable/GenPatchPcdTable.py @@ -112,11 +112,11 @@ def _parseGeneral(lines, efifilepath): @param lines line array for map file @return a list which element hold (PcdName, Offset, SectionName) - """ + """ status = 0 #0 - beginning of file; 1 - PE section definition; 2 - symbol table - secs = [] # key = section name + secs = [] # key = section name bPcds = [] - + for line in lines: line = line.strip() @@ -128,9 +128,9 @@ def _parseGeneral(lines, efifilepath): continue if re.match("^entry point at", line): status = 3 - continue + continue if status == 1 and len(line) != 0: - m = secRe.match(line) + m = secRe.match(line) assert m != None, "Fail to parse the section in map file , line is %s" % line sec_no, sec_start, sec_length, sec_name, sec_class = m.groups(0) secs.append([int(sec_no, 16), int(sec_start, 16), int(sec_length, 16), sec_name, sec_class]) @@ -138,9 +138,9 @@ def _parseGeneral(lines, efifilepath): m = symRe.match(line) assert m != None, "Fail to parse the symbol in map file, line is %s" % line sec_no, sym_offset, sym_name, vir_addr = m.groups(0) - sec_no = int(sec_no, 16) + sec_no = int(sec_no, 16) sym_offset = int(sym_offset, 16) - vir_addr = int(vir_addr, 16) + vir_addr = int(vir_addr, 16) m2 = re.match('^[_]+gPcd_BinaryPatch_([\w]+)', sym_name) if m2 != None: # fond a binary pcd entry in map file @@ -179,7 +179,7 @@ def generatePcdTable(list, pcdpath): f.close() #print 'Success to generate Binary Patch PCD table at %s!' % pcdpath - + if __name__ == '__main__': UsageString = "%prog -m -e -o " AdditionalNotes = "\nPCD table is generated in file name with .BinaryPcdTable.txt postfix" @@ -196,12 +196,12 @@ def generatePcdTable(list, pcdpath): if options.mapfile == None or options.efifile == None: print parser.get_usage() elif os.path.exists(options.mapfile) and os.path.exists(options.efifile): - list = parsePcdInfoFromMapFile(options.mapfile, options.efifile) + list = parsePcdInfoFromMapFile(options.mapfile, options.efifile) if list != None: if options.outfile != None: generatePcdTable(list, options.outfile) else: - generatePcdTable(list, options.mapfile.replace('.map', '.BinaryPcdTable.txt')) + generatePcdTable(list, options.mapfile.replace('.map', '.BinaryPcdTable.txt')) else: print 'Fail to generate Patch PCD Table based on map file and efi file' else: diff --git a/BaseTools/Source/Python/PatchPcdValue/PatchPcdValue.py b/BaseTools/Source/Python/PatchPcdValue/PatchPcdValue.py index 1b3a0ec93d62..882da81930da 100644 --- a/BaseTools/Source/Python/PatchPcdValue/PatchPcdValue.py +++ b/BaseTools/Source/Python/PatchPcdValue/PatchPcdValue.py @@ -48,7 +48,7 @@ def PatchBinaryFile(FileName, ValueOffset, TypeName, ValueString, MaxSize=0): # # Length of Binary File # - FileHandle = open (FileName, 'rb') + FileHandle = open(FileName, 'rb') FileHandle.seek (0, 2) FileLength = FileHandle.tell() FileHandle.close() @@ -75,7 +75,7 @@ def PatchBinaryFile(FileName, ValueOffset, TypeName, ValueString, MaxSize=0): return OPTION_MISSING, "PcdMaxSize is not specified for VOID* type PCD." ValueLength = int(MaxSize) else: - return PARAMETER_INVALID, "PCD type %s is not valid." %(CommandOptions.PcdTypeName) + return PARAMETER_INVALID, "PCD type %s is not valid." % (CommandOptions.PcdTypeName) # # Check PcdValue is in the input binary file. # @@ -84,7 +84,7 @@ def PatchBinaryFile(FileName, ValueOffset, TypeName, ValueString, MaxSize=0): # # Read binary file into array # - FileHandle = open (FileName, 'rb') + FileHandle = open(FileName, 'rb') ByteArray = array.array('B') ByteArray.fromfile(FileHandle, FileLength) FileHandle.close() @@ -117,7 +117,7 @@ def PatchBinaryFile(FileName, ValueOffset, TypeName, ValueString, MaxSize=0): if ValueNumber != 0: ValueNumber = 1 except: - return PARAMETER_INVALID, "PCD Value %s is not valid dec or hex string." %(ValueString) + return PARAMETER_INVALID, "PCD Value %s is not valid dec or hex string." % (ValueString) # # Set PCD value into binary data # @@ -132,7 +132,7 @@ def PatchBinaryFile(FileName, ValueOffset, TypeName, ValueString, MaxSize=0): else: ValueNumber = int (ValueString) except: - return PARAMETER_INVALID, "PCD Value %s is not valid dec or hex string." %(ValueString) + return PARAMETER_INVALID, "PCD Value %s is not valid dec or hex string." % (ValueString) # # Set PCD value into binary data # @@ -174,7 +174,7 @@ def PatchBinaryFile(FileName, ValueOffset, TypeName, ValueString, MaxSize=0): if Index >= ValueLength: break except: - return PARAMETER_INVALID, "PCD Value %s is not valid dec or hex string array." %(ValueString) + return PARAMETER_INVALID, "PCD Value %s is not valid dec or hex string array." % (ValueString) else: # # Patch ascii string @@ -197,10 +197,10 @@ def PatchBinaryFile(FileName, ValueOffset, TypeName, ValueString, MaxSize=0): if ByteList != OrigByteList: ByteArray = array.array('B') ByteArray.fromlist(ByteList) - FileHandle = open (FileName, 'wb') + FileHandle = open(FileName, 'wb') ByteArray.tofile(FileHandle) FileHandle.close() - return 0, "Patch Value into File %s successfully." %(FileName) + return 0, "Patch Value into File %s successfully." % (FileName) ## Parse command line options # @@ -270,7 +270,7 @@ def Main(): EdkLogger.error("PatchPcdValue", OPTION_MISSING, ExtraData="PcdOffset or PcdValue of PcdTypeName is not specified.") return 1 if CommandOptions.PcdTypeName.upper() not in ["BOOLEAN", "UINT8", "UINT16", "UINT32", "UINT64", "VOID*"]: - EdkLogger.error("PatchPcdValue", PARAMETER_INVALID, ExtraData="PCD type %s is not valid." %(CommandOptions.PcdTypeName)) + EdkLogger.error("PatchPcdValue", PARAMETER_INVALID, ExtraData="PCD type %s is not valid." % (CommandOptions.PcdTypeName)) return 1 if CommandOptions.PcdTypeName.upper() == "VOID*" and CommandOptions.PcdMaxSize == None: EdkLogger.error("PatchPcdValue", OPTION_MISSING, ExtraData="PcdMaxSize is not specified for VOID* type PCD.") diff --git a/BaseTools/Source/Python/Table/TableReport.py b/BaseTools/Source/Python/Table/TableReport.py index c7829c0097bf..4af0e98d86b4 100644 --- a/BaseTools/Source/Python/Table/TableReport.py +++ b/BaseTools/Source/Python/Table/TableReport.py @@ -68,14 +68,14 @@ def Create(self): # @param Enabled: If this error enabled # @param Corrected: if this error corrected # - def Insert(self, ErrorID, OtherMsg = '', BelongsToTable = '', BelongsToItem = -1, Enabled = 0, Corrected = -1): + def Insert(self, ErrorID, OtherMsg='', BelongsToTable='', BelongsToItem= -1, Enabled=0, Corrected= -1): self.ID = self.ID + 1 SqlCommand = """insert into %s values(%s, %s, '%s', '%s', %s, %s, %s)""" \ % (self.Table, self.ID, ErrorID, ConvertToSqlString2(OtherMsg), BelongsToTable, BelongsToItem, Enabled, Corrected) Table.Insert(self, SqlCommand) - + return self.ID - + ## Query table # # @retval: A recordSet of all found records @@ -98,7 +98,7 @@ def UpdateBelongsToItemByFile(self, ItemID=-1, File=""): # # @param Filename: To filename to save the report content # - def ToCSV(self, Filename = 'Report.csv'): + def ToCSV(self, Filename='Report.csv'): try: File = open(Filename, 'w+') File.write("""No, Error Code, Error Message, File, LineNo, Other Error Message\n""") @@ -123,7 +123,7 @@ def ToCSV(self, Filename = 'Report.csv'): if NewRecord != []: File.write("""%s,%s,"%s",%s,%s,"%s"\n""" % (Index, ErrorID, EccToolError.gEccErrorMessage[ErrorID], NewRecord[0][1], NewRecord[0][0], OtherMsg)) EdkLogger.quiet("%s(%s): [%s]%s %s" % (NewRecord[0][1], NewRecord[0][0], ErrorID, EccToolError.gEccErrorMessage[ErrorID], OtherMsg)) - + File.close() except IOError: NewFilename = 'Report_' + time.strftime("%Y%m%d_%H%M%S.csv", time.localtime()) diff --git a/BaseTools/Source/Python/Workspace/MetaFileParser.py b/BaseTools/Source/Python/Workspace/MetaFileParser.py index e7d6df659590..451d8547d22b 100644 --- a/BaseTools/Source/Python/Workspace/MetaFileParser.py +++ b/BaseTools/Source/Python/Workspace/MetaFileParser.py @@ -1525,7 +1525,7 @@ def __ProcessPcd(self): ValList, Valid, Index = AnalyzeDscPcd(self._ValueList[2], self._ItemType) if not Valid: - EdkLogger.error('build', FORMAT_INVALID, "Pcd format incorrect.", File=self._FileWithError, Line=self._LineIndex+1, + EdkLogger.error('build', FORMAT_INVALID, "Pcd format incorrect.", File=self._FileWithError, Line=self._LineIndex + 1, ExtraData="%s.%s|%s" % (self._ValueList[0], self._ValueList[1], self._ValueList[2])) PcdValue = ValList[Index] if PcdValue: diff --git a/BaseTools/Source/Python/Workspace/WorkspaceDatabase.py b/BaseTools/Source/Python/Workspace/WorkspaceDatabase.py index 46eb5d3a8c2f..1f236e83ff51 100644 --- a/BaseTools/Source/Python/Workspace/WorkspaceDatabase.py +++ b/BaseTools/Source/Python/Workspace/WorkspaceDatabase.py @@ -1863,11 +1863,11 @@ def _GetHeaderInfo(self): LineNo = Record[6] break EdkLogger.error("build", FORMAT_NOT_SUPPORTED, - "MODULE_TYPE %s is not supported for EDK II, valid values are:\n %s" % (self._ModuleType,' '.join(l for l in SUP_MODULE_LIST)), + "MODULE_TYPE %s is not supported for EDK II, valid values are:\n %s" % (self._ModuleType, ' '.join(l for l in SUP_MODULE_LIST)), File=self.MetaFile, Line=LineNo) if (self._Specification == None) or (not 'PI_SPECIFICATION_VERSION' in self._Specification) or (int(self._Specification['PI_SPECIFICATION_VERSION'], 16) < 0x0001000A): if self._ModuleType == SUP_MODULE_SMM_CORE: - EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "SMM_CORE module type can't be used in the module with PI_SPECIFICATION_VERSION less than 0x0001000A", File=self.MetaFile) + EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "SMM_CORE module type can't be used in the module with PI_SPECIFICATION_VERSION less than 0x0001000A", File=self.MetaFile) if self._Defs and 'PCI_DEVICE_ID' in self._Defs and 'PCI_VENDOR_ID' in self._Defs \ and 'PCI_CLASS_CODE' in self._Defs: self._BuildType = 'UEFI_OPTIONROM' @@ -1876,7 +1876,7 @@ def _GetHeaderInfo(self): self._BuildType = 'UEFI_HII' else: self._BuildType = self._ModuleType.upper() - + if self._DxsFile: File = PathClass(NormPath(self._DxsFile), self._ModuleDir, Arch=self._Arch) # check the file validation @@ -1891,7 +1891,7 @@ def _GetHeaderInfo(self): if not self._ComponentType: EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "COMPONENT_TYPE is not given", File=self.MetaFile) - self._BuildType = self._ComponentType.upper() + self._BuildType = self._ComponentType.upper() if self._ComponentType in self._MODULE_TYPE_: self._ModuleType = self._MODULE_TYPE_[self._ComponentType] if self._ComponentType == 'LIBRARY': @@ -1901,7 +1901,7 @@ def _GetHeaderInfo(self): Macros["EDK_SOURCE"] = GlobalData.gEcpSource Macros['PROCESSOR'] = self._Arch RecordList = self._RawData[MODEL_META_DATA_NMAKE, self._Arch, self._Platform] - for Name,Value,Dummy,Arch,Platform,ID,LineNo in RecordList: + for Name, Value, Dummy, Arch, Platform, ID, LineNo in RecordList: Value = ReplaceMacro(Value, Macros, True) if Name == "IMAGE_ENTRY_POINT": if self._ModuleEntryPointList == None: @@ -2584,7 +2584,7 @@ def _GetPcd(self, Type): 'build', FORMAT_INVALID, "No TokenValue for PCD [%s.%s] in [%s]!" % (TokenSpaceGuid, PcdCName, str(Package)), - File =self.MetaFile, Line=LineNo, + File=self.MetaFile, Line=LineNo, ExtraData=None ) # @@ -2597,7 +2597,7 @@ def _GetPcd(self, Type): 'build', FORMAT_INVALID, "The format of TokenValue [%s] of PCD [%s.%s] in [%s] is invalid:" % (Pcd.TokenValue, TokenSpaceGuid, PcdCName, str(Package)), - File =self.MetaFile, Line=LineNo, + File=self.MetaFile, Line=LineNo, ExtraData=None ) @@ -2611,19 +2611,19 @@ def _GetPcd(self, Type): EdkLogger.error( 'build', FORMAT_INVALID, - "The format of TokenValue [%s] of PCD [%s.%s] in [%s] is invalid, as a decimal it should between: 0 - 4294967295!"% (Pcd.TokenValue, TokenSpaceGuid, PcdCName, str(Package)), - File =self.MetaFile, Line=LineNo, + "The format of TokenValue [%s] of PCD [%s.%s] in [%s] is invalid, as a decimal it should between: 0 - 4294967295!" % (Pcd.TokenValue, TokenSpaceGuid, PcdCName, str(Package)), + File=self.MetaFile, Line=LineNo, ExtraData=None - ) + ) except: EdkLogger.error( 'build', FORMAT_INVALID, - "The format of TokenValue [%s] of PCD [%s.%s] in [%s] is invalid, it should be hexadecimal or decimal!"% (Pcd.TokenValue, TokenSpaceGuid, PcdCName, str(Package)), - File =self.MetaFile, Line=LineNo, + "The format of TokenValue [%s] of PCD [%s.%s] in [%s] is invalid, it should be hexadecimal or decimal!" % (Pcd.TokenValue, TokenSpaceGuid, PcdCName, str(Package)), + File=self.MetaFile, Line=LineNo, ExtraData=None ) - + Pcd.DatumType = PcdInPackage.DatumType Pcd.MaxDatumSize = PcdInPackage.MaxDatumSize Pcd.InfDefaultValue = Pcd.DefaultValue @@ -2635,7 +2635,7 @@ def _GetPcd(self, Type): 'build', FORMAT_INVALID, "PCD [%s.%s] in [%s] is not found in dependent packages:" % (TokenSpaceGuid, PcdCName, self.MetaFile), - File =self.MetaFile, Line=LineNo, + File=self.MetaFile, Line=LineNo, ExtraData="\t%s" % '\n\t'.join([str(P) for P in self.Packages]) ) Pcds[PcdCName, TokenSpaceGuid] = Pcd @@ -2946,7 +2946,7 @@ def Close(self): ## Summarize all packages in the database def GetPackageList(self, Platform, Arch, TargetName, ToolChainTag): self.Platform = Platform - PackageList =[] + PackageList = [] Pa = self.BuildObject[self.Platform, 'COMMON'] # # Get Package related to Modules @@ -2963,8 +2963,8 @@ def GetPackageList(self, Platform, Arch, TargetName, ToolChainTag): LibObj = self.BuildObject[Lib, Arch, TargetName, ToolChainTag] for Package in LibObj.Packages: if Package not in PackageList: - PackageList.append(Package) - + PackageList.append(Package) + return PackageList ## Summarize all platforms in the database diff --git a/BaseTools/Source/Python/build/BuildReport.py b/BaseTools/Source/Python/build/BuildReport.py index 38e55f3e07f6..722d8b7f458c 100644 --- a/BaseTools/Source/Python/build/BuildReport.py +++ b/BaseTools/Source/Python/build/BuildReport.py @@ -78,13 +78,13 @@ gEndOfLine = "\r\n" ## Tags for section start, end and separator -gSectionStart = ">" + "=" * (gLineMaxLength-2) + "<" -gSectionEnd = "<" + "=" * (gLineMaxLength-2) + ">" + "\n" +gSectionStart = ">" + "=" * (gLineMaxLength - 2) + "<" +gSectionEnd = "<" + "=" * (gLineMaxLength - 2) + ">" + "\n" gSectionSep = "=" * gLineMaxLength ## Tags for subsection start, end and separator -gSubSectionStart = ">" + "-" * (gLineMaxLength-2) + "<" -gSubSectionEnd = "<" + "-" * (gLineMaxLength-2) + ">" +gSubSectionStart = ">" + "-" * (gLineMaxLength - 2) + "<" +gSubSectionEnd = "<" + "-" * (gLineMaxLength - 2) + ">" gSubSectionSep = "-" * gLineMaxLength @@ -233,7 +233,7 @@ class DepexParser(object): def __init__(self, Wa): self._GuidDb = {} for Pa in Wa.AutoGenObjectList: - for Package in Pa.PackageList: + for Package in Pa.PackageList: for Protocol in Package.Protocols: GuidValue = GuidStructureStringToGuidString(Package.Protocols[Protocol]) self._GuidDb[GuidValue.upper()] = Protocol @@ -265,8 +265,8 @@ def ParseDepexFile(self, DepexFileName): GuidString = self._GuidDb.get(GuidValue, GuidValue) Statement = "%s %s" % (Statement, GuidString) DepexStatement.append(Statement) - OpCode = DepexFile.read(1) - + OpCode = DepexFile.read(1) + return DepexStatement ## @@ -361,7 +361,7 @@ class DepexReport(object): # def __init__(self, M): self.Depex = "" - self._DepexFileName = os.path.join(M.BuildDir, "OUTPUT", M.Module.BaseName + ".depex") + self._DepexFileName = os.path.join(M.BuildDir, "OUTPUT", M.Module.BaseName + ".depex") ModuleType = M.ModuleType if not ModuleType: ModuleType = gComponentType2ModuleType.get(M.ComponentType, "") @@ -536,7 +536,7 @@ def __init__(self, M, ReportType): # If a module complies to PI 1.1, promote Module type to "SMM_DRIVER" # if ModuleType == "DXE_SMM_DRIVER": - PiSpec = M.Module.Specification.get("PI_SPECIFICATION_VERSION", "0x00010000") + PiSpec = M.Module.Specification.get("PI_SPECIFICATION_VERSION", "0x00010000") if int(PiSpec, 0) >= 0x0001000A: ModuleType = "SMM_DRIVER" self.DriverType = gDriverTypeMap.get(ModuleType, "0x2 (FREE_FORM)") @@ -813,20 +813,20 @@ def GenerateReport(self, File, ModulePcdSet): # Report PCD item according to their override relationship # if DecMatch and InfMatch: - FileWrite(File, ' %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '('+Pcd.DatumType+')', PcdValue.strip())) + FileWrite(File, ' %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '(' + Pcd.DatumType + ')', PcdValue.strip())) else: if DscMatch: if (Pcd.TokenCName, Key) in self.FdfPcdSet: - FileWrite(File, ' *F %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '('+Pcd.DatumType+')', PcdValue.strip())) + FileWrite(File, ' *F %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '(' + Pcd.DatumType + ')', PcdValue.strip())) else: - FileWrite(File, ' *P %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '('+Pcd.DatumType+')', PcdValue.strip())) + FileWrite(File, ' *P %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '(' + Pcd.DatumType + ')', PcdValue.strip())) else: - FileWrite(File, ' *M %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '('+Pcd.DatumType+')', PcdValue.strip())) - + FileWrite(File, ' *M %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '(' + Pcd.DatumType + ')', PcdValue.strip())) + if TypeName in ('DYNHII', 'DEXHII', 'DYNVPD', 'DEXVPD'): for SkuInfo in Pcd.SkuInfoList.values(): if TypeName in ('DYNHII', 'DEXHII'): - FileWrite(File, '%*s: %s: %s' % (self.MaxLen + 4, SkuInfo.VariableGuid, SkuInfo.VariableName, SkuInfo.VariableOffset)) + FileWrite(File, '%*s: %s: %s' % (self.MaxLen + 4, SkuInfo.VariableGuid, SkuInfo.VariableName, SkuInfo.VariableOffset)) else: FileWrite(File, '%*s' % (self.MaxLen + 4, SkuInfo.VpdOffset)) diff --git a/BaseTools/Source/Python/build/build.py b/BaseTools/Source/Python/build/build.py index 6d83ac9701ba..3cd385d69d99 100644 --- a/BaseTools/Source/Python/build/build.py +++ b/BaseTools/Source/Python/build/build.py @@ -210,7 +210,7 @@ def NormFile(FilePath, Workspace): # check if the file path exists or not if not os.path.isfile(FileFullPath): - EdkLogger.error("build", FILE_NOT_FOUND, ExtraData="\t%s (Please give file in absolute path or relative to WORKSPACE)" % FileFullPath) + EdkLogger.error("build", FILE_NOT_FOUND, ExtraData="\t%s (Please give file in absolute path or relative to WORKSPACE)" % FileFullPath) # remove workspace directory from the beginning part of the file path if Workspace[-1] in ["\\", "/"]: @@ -1122,13 +1122,13 @@ def _RebaseModule (self, MapBuffer, BaseAddress, ModuleList, AddrIsOffset = True # Update Image to new BaseAddress by GenFw tool # LaunchCommand(["GenFw", "--rebase", str(BaseAddress), "-r", ModuleOutputImage], ModuleInfo.OutputDir) - LaunchCommand(["GenFw", "--rebase", str(BaseAddress), "-r", ModuleDebugImage], ModuleInfo.DebugDir) + LaunchCommand(["GenFw", "--rebase", str(BaseAddress), "-r", ModuleDebugImage], ModuleInfo.DebugDir) else: # # Set new address to the section header only for SMM driver. # LaunchCommand(["GenFw", "--address", str(BaseAddress), "-r", ModuleOutputImage], ModuleInfo.OutputDir) - LaunchCommand(["GenFw", "--address", str(BaseAddress), "-r", ModuleDebugImage], ModuleInfo.DebugDir) + LaunchCommand(["GenFw", "--address", str(BaseAddress), "-r", ModuleDebugImage], ModuleInfo.DebugDir) # # Collect funtion address from Map file # @@ -1136,7 +1136,7 @@ def _RebaseModule (self, MapBuffer, BaseAddress, ModuleList, AddrIsOffset = True FunctionList = [] if os.path.exists(ImageMapTable): OrigImageBaseAddress = 0 - ImageMap = open (ImageMapTable, 'r') + ImageMap = open(ImageMapTable, 'r') for LinStr in ImageMap: if len (LinStr.strip()) == 0: continue @@ -1149,7 +1149,7 @@ def _RebaseModule (self, MapBuffer, BaseAddress, ModuleList, AddrIsOffset = True StrList = LinStr.split() if len (StrList) > 4: - if StrList[3] == 'f' or StrList[3] =='F': + if StrList[3] == 'f' or StrList[3] == 'F': Name = StrList[1] RelativeAddress = int (StrList[2], 16) - OrigImageBaseAddress FunctionList.append ((Name, RelativeAddress)) @@ -1273,7 +1273,7 @@ def _CollectModuleMapBuffer (self, MapBuffer, ModuleList): if not ImageClass.IsValid: EdkLogger.error("build", FILE_PARSE_FAILURE, ExtraData=ImageClass.ErrorInfo) ImageInfo = PeImageInfo(Module.Name, Module.Guid, Module.Arch, Module.OutputDir, Module.DebugDir, ImageClass) - if Module.ModuleType in ['PEI_CORE', 'PEIM', 'COMBINED_PEIM_DRIVER','PIC_PEIM', 'RELOCATABLE_PEIM', 'DXE_CORE']: + if Module.ModuleType in ['PEI_CORE', 'PEIM', 'COMBINED_PEIM_DRIVER', 'PIC_PEIM', 'RELOCATABLE_PEIM', 'DXE_CORE']: PeiModuleList[Module.MetaFile] = ImageInfo PeiSize += ImageInfo.Image.Size elif Module.ModuleType in ['BS_DRIVER', 'DXE_DRIVER', 'UEFI_DRIVER']: @@ -1354,21 +1354,21 @@ def _CollectModuleMapBuffer (self, MapBuffer, ModuleList): for PcdInfo in PcdTable: ReturnValue = 0 if PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE: - ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE_DATA_TYPE, str (PeiSize/0x1000)) + ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE_DATA_TYPE, str (PeiSize / 0x1000)) elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE: - ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE_DATA_TYPE, str (BtSize/0x1000)) + ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE_DATA_TYPE, str (BtSize / 0x1000)) elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE: - ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE_DATA_TYPE, str (RtSize/0x1000)) + ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE_DATA_TYPE, str (RtSize / 0x1000)) elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE and len (SmmModuleList) > 0: - ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE_DATA_TYPE, str (SmmSize/0x1000)) + ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE_DATA_TYPE, str (SmmSize / 0x1000)) if ReturnValue != 0: EdkLogger.error("build", PARAMETER_INVALID, "Patch PCD value failed", ExtraData=ErrorInfo) - MapBuffer.write('PEI_CODE_PAGE_NUMBER = 0x%x\n' % (PeiSize/0x1000)) - MapBuffer.write('BOOT_CODE_PAGE_NUMBER = 0x%x\n' % (BtSize/0x1000)) - MapBuffer.write('RUNTIME_CODE_PAGE_NUMBER = 0x%x\n' % (RtSize/0x1000)) + MapBuffer.write('PEI_CODE_PAGE_NUMBER = 0x%x\n' % (PeiSize / 0x1000)) + MapBuffer.write('BOOT_CODE_PAGE_NUMBER = 0x%x\n' % (BtSize / 0x1000)) + MapBuffer.write('RUNTIME_CODE_PAGE_NUMBER = 0x%x\n' % (RtSize / 0x1000)) if len (SmmModuleList) > 0: - MapBuffer.write('SMM_CODE_PAGE_NUMBER = 0x%x\n' % (SmmSize/0x1000)) + MapBuffer.write('SMM_CODE_PAGE_NUMBER = 0x%x\n' % (SmmSize / 0x1000)) PeiBaseAddr = TopMemoryAddress - RtSize - BtSize BtBaseAddr = TopMemoryAddress - RtSize @@ -1377,7 +1377,7 @@ def _CollectModuleMapBuffer (self, MapBuffer, ModuleList): self._RebaseModule (MapBuffer, PeiBaseAddr, PeiModuleList, TopMemoryAddress == 0) self._RebaseModule (MapBuffer, BtBaseAddr, BtModuleList, TopMemoryAddress == 0) self._RebaseModule (MapBuffer, RtBaseAddr, RtModuleList, TopMemoryAddress == 0) - self._RebaseModule (MapBuffer, 0x1000, SmmModuleList, AddrIsOffset = False, ModeIsSmm = True) + self._RebaseModule (MapBuffer, 0x1000, SmmModuleList, AddrIsOffset=False, ModeIsSmm=True) MapBuffer.write('\n\n') sys.stdout.write ("\n") sys.stdout.flush() @@ -1395,7 +1395,7 @@ def _SaveMapFile (self, MapBuffer, Wa): SaveFileOnChange(MapFilePath, MapBuffer.getvalue(), False) MapBuffer.close() if self.LoadFixAddress != 0: - sys.stdout.write ("\nLoad Module At Fix Address Map file can be found at %s\n" %(MapFilePath)) + sys.stdout.write ("\nLoad Module At Fix Address Map file can be found at %s\n" % (MapFilePath)) sys.stdout.flush() ## Build active platform for different build targets and different tool chains @@ -1529,7 +1529,7 @@ def _BuildModule(self): BUILD_ERROR, "Module for [%s] is not a component of active platform."\ " Please make sure that the ARCH and inf file path are"\ - " given in the same as in [%s]" %\ + " given in the same as in [%s]" % \ (', '.join(Wa.ArchList), self.PlatformFile), ExtraData=self.ModuleFile ) @@ -1874,8 +1874,8 @@ def SingleCheckCallback(option, opt_str, value, parser): # @retval Args Target of build command # def MyOptionParser(): - Parser = OptionParser(description=__copyright__,version=__version__,prog="build.exe",usage="%prog [options] [all|fds|genc|genmake|clean|cleanall|cleanlib|modules|libraries|run]") - Parser.add_option("-a", "--arch", action="append", type="choice", choices=['IA32','X64','IPF','EBC','ARM', 'AARCH64'], dest="TargetArch", + Parser = OptionParser(description=__copyright__, version=__version__, prog="build.exe", usage="%prog [options] [all|fds|genc|genmake|clean|cleanall|cleanlib|modules|libraries|run]") + Parser.add_option("-a", "--arch", action="append", type="choice", choices=['IA32', 'X64', 'IPF', 'EBC', 'ARM', 'AARCH64'], dest="TargetArch", help="ARCHS is one of list: IA32, X64, IPF, ARM, AARCH64 or EBC, which overrides target.txt's TARGET_ARCH definition. To specify more archs, please repeat this option.") Parser.add_option("-p", "--platform", action="callback", type="string", dest="PlatformFile", callback=SingleCheckCallback, help="Build the platform specified by the DSC file name argument, overriding target.txt's ACTIVE_PLATFORM definition.") @@ -1917,7 +1917,7 @@ def MyOptionParser(): Parser.add_option("-D", "--define", action="append", type="string", dest="Macros", help="Macro: \"Name [= Value]\".") Parser.add_option("-y", "--report-file", action="store", dest="ReportFile", help="Create/overwrite the report to the specified filename.") - Parser.add_option("-Y", "--report-type", action="append", type="choice", choices=['PCD','LIBRARY','FLASH','DEPEX','BUILD_FLAGS','FIXED_ADDRESS', 'EXECUTION_ORDER'], dest="ReportType", default=[], + Parser.add_option("-Y", "--report-type", action="append", type="choice", choices=['PCD', 'LIBRARY', 'FLASH', 'DEPEX', 'BUILD_FLAGS', 'FIXED_ADDRESS', 'EXECUTION_ORDER'], dest="ReportType", default=[], help="Flags that control the type of build report to generate. Must be one of: [PCD, LIBRARY, FLASH, DEPEX, BUILD_FLAGS, FIXED_ADDRESS, EXECUTION_ORDER]. "\ "To specify more than one flag, repeat this option on the command line and the default flag set is [PCD, LIBRARY, FLASH, DEPEX, BUILD_FLAGS, FIXED_ADDRESS]") Parser.add_option("-F", "--flag", action="store", type="string", dest="Flag", @@ -1929,7 +1929,7 @@ def MyOptionParser(): Parser.add_option("--check-usage", action="store_true", dest="CheckUsage", default=False, help="Check usage content of entries listed in INF file.") Parser.add_option("--ignore-sources", action="store_true", dest="IgnoreSources", default=False, help="Focus to a binary build and ignore all source files") - (Opt, Args)=Parser.parse_args() + (Opt, Args) = Parser.parse_args() return (Opt, Args) ## Tool entrance method @@ -1985,13 +1985,13 @@ def Main(): Target = "all" elif len(Target) >= 2: EdkLogger.error("build", OPTION_NOT_SUPPORTED, "More than one targets are not supported.", - ExtraData="Please select one of: %s" %(' '.join(gSupportedTarget))) + ExtraData="Please select one of: %s" % (' '.join(gSupportedTarget))) else: Target = Target[0].lower() if Target not in gSupportedTarget: EdkLogger.error("build", OPTION_NOT_SUPPORTED, "Not supported target [%s]." % Target, - ExtraData="Please select one of: %s" %(' '.join(gSupportedTarget))) + ExtraData="Please select one of: %s" % (' '.join(gSupportedTarget))) # # Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH @@ -2069,7 +2069,7 @@ def Main(): if Option != None and Option.debug != None: EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc()) else: - EdkLogger.error(X.ToolName, FORMAT_INVALID, File=X.FileName, Line=X.LineNumber, ExtraData=X.Message, RaiseError = False) + EdkLogger.error(X.ToolName, FORMAT_INVALID, File=X.FileName, Line=X.LineNumber, ExtraData=X.Message, RaiseError=False) ReturnCode = FORMAT_INVALID except KeyboardInterrupt: ReturnCode = ABORT_ERROR @@ -2110,7 +2110,7 @@ def Main(): BuildDuration = time.gmtime(int(round(FinishTime - StartTime))) BuildDurationStr = "" if BuildDuration.tm_yday > 1: - BuildDurationStr = time.strftime("%H:%M:%S", BuildDuration) + ", %d day(s)"%(BuildDuration.tm_yday - 1) + BuildDurationStr = time.strftime("%H:%M:%S", BuildDuration) + ", %d day(s)" % (BuildDuration.tm_yday - 1) else: BuildDurationStr = time.strftime("%H:%M:%S", BuildDuration) if MyBuild != None: From 7da20f7b917cf7c501c452db8f90b700e5d49cd1 Mon Sep 17 00:00:00 2001 From: Eugene Cohen Date: Fri, 18 Dec 2015 06:44:26 +0000 Subject: [PATCH 272/525] BaseTools RVCT: add preprocessor preinclude for AutoGen.h Ensure that AutoGen.h is force-included when the RVCT preprocessor is invoked. (Sync patch r19097 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Eugene Cohen Reviewed-by: Ard Biesheuvel git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19370 6f19259b-4bc3-4df7-8a09-765794883524 --- BaseTools/Conf/tools_def.template | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BaseTools/Conf/tools_def.template b/BaseTools/Conf/tools_def.template index 88d4b4f3b6c9..d6b0af43d772 100644 --- a/BaseTools/Conf/tools_def.template +++ b/BaseTools/Conf/tools_def.template @@ -7152,7 +7152,7 @@ RELEASE_RVCT_ARM_DLINK_FLAGS = $(ARCHDLINK_FLAGS) DEF(RVCT_ALL_DLINK_FLAGS) *_RVCT_ARM_ASM_FLAGS = $(ARCHASM_FLAGS) $(PLATFORM_FLAGS) DEF(RVCT_ALL_ASM_FLAGS) -*_RVCT_ARM_PP_FLAGS = $(ARCHCC_FLAGS) $(PLATFORM_FLAGS) -E +*_RVCT_ARM_PP_FLAGS = $(ARCHCC_FLAGS) $(PLATFORM_FLAGS) -E --preinclude AutoGen.h *_RVCT_ARM_VFRPP_FLAGS = $(ARCHCC_FLAGS) $(PLATFORM_FLAGS) -E -DVFRCOMPILE --preinclude $(DEST_DIR_DEBUG)/$(MODULE_NAME)StrDefs.h *_RVCT_ARM_MAKE_PATH = nmake /NOLOGO *_RVCT_ARM_SLINK_FLAGS = --partial -o From a166931e9404a5b42aa9955282d21d09a0a5df6d Mon Sep 17 00:00:00 2001 From: Jordan Justen Date: Fri, 18 Dec 2015 06:44:53 +0000 Subject: [PATCH 273/525] BaseTools PatchCheck.py: Support binary diff This allows a patch with binary data that is generated with --binary to be parsed by the PatchCheck.py script. (Sync patch r19104 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jordan Justen Reviewed-by: Liming Gao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19371 6f19259b-4bc3-4df7-8a09-765794883524 --- BaseTools/Scripts/PatchCheck.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/BaseTools/Scripts/PatchCheck.py b/BaseTools/Scripts/PatchCheck.py index 340a9972b838..455c1309b6d3 100644 --- a/BaseTools/Scripts/PatchCheck.py +++ b/BaseTools/Scripts/PatchCheck.py @@ -285,6 +285,10 @@ def run(self): self.set_filename(line[6:].rstrip()) if line.startswith('@@ '): self.state = PATCH + self.binary = False + elif line.startswith('GIT binary patch'): + self.state = PATCH + self.binary = True else: ok = False for pfx in self.pre_patch_prefixes: @@ -294,6 +298,8 @@ def run(self): self.format_error("didn't find diff hunk marker (@@)") self.line_num += 1 elif self.state == PATCH: + if self.binary: + pass if line.startswith('-'): pass elif line.startswith('+'): From 5fbc2feda298235bd54b38a1e2838db01501aca3 Mon Sep 17 00:00:00 2001 From: Yonghong Zhu Date: Fri, 18 Dec 2015 06:45:34 +0000 Subject: [PATCH 274/525] BaseTools: Add support for INF statement in FD region FD region today can be file or data, but not a patched image.Add support for an INF statement in an FD region, so the binary from the INF can be patched prior to being added to the FD region. (Sync patch r19136 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Yonghong Zhu Reviewed-by: Liming Gao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19372 6f19259b-4bc3-4df7-8a09-765794883524 --- BaseTools/Source/Python/GenFds/FdfParser.py | 57 ++++++++++++------- .../Source/Python/GenFds/FfsInfStatement.py | 44 +++++++++++++- BaseTools/Source/Python/GenFds/Region.py | 21 ++++--- 3 files changed, 91 insertions(+), 31 deletions(-) diff --git a/BaseTools/Source/Python/GenFds/FdfParser.py b/BaseTools/Source/Python/GenFds/FdfParser.py index 664bf8e87d26..788190567eef 100644 --- a/BaseTools/Source/Python/GenFds/FdfParser.py +++ b/BaseTools/Source/Python/GenFds/FdfParser.py @@ -1,7 +1,7 @@ ## @file # parse FDF file # -# Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.
+# Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.
# Copyright (c) 2015, Hewlett Packard Enterprise Development, L.P.
# # This program and the accompanying materials @@ -1846,7 +1846,7 @@ def __GetRegionLayout(self, Fd): if not self.__GetNextWord(): return True - if not self.__Token in ("SET", "FV", "FILE", "DATA", "CAPSULE"): + if not self.__Token in ("SET", "FV", "FILE", "DATA", "CAPSULE", "INF"): # # If next token is a word which is not a valid FV type, it might be part of [PcdOffset[|PcdSize]] # Or it might be next region's offset described by an expression which starts with a PCD. @@ -1887,17 +1887,27 @@ def __GetRegionLayout(self, Fd): elif self.__Token == "FILE": self.__UndoToken() - self.__GetRegionFileType( RegionObj) + self.__GetRegionFileType(RegionObj) + + elif self.__Token == "INF": + self.__UndoToken() + RegionObj.RegionType = "INF" + while self.__IsKeyword("INF"): + self.__UndoToken() + ffsInf = self.__ParseInfStatement() + if not ffsInf: + break + RegionObj.RegionDataList.append(ffsInf) elif self.__Token == "DATA": self.__UndoToken() - self.__GetRegionDataType( RegionObj) + self.__GetRegionDataType(RegionObj) else: self.__UndoToken() if self.__GetRegionLayout(Fd): return True raise Warning("A valid region type was not found. " - "Valid types are [SET, FV, CAPSULE, FILE, DATA]. This error occurred", + "Valid types are [SET, FV, CAPSULE, FILE, DATA, INF]. This error occurred", self.FileName, self.CurrentLineNumber) return True @@ -2426,23 +2436,12 @@ def __GetAprioriSection(self, FvObj, MacroDict = {}): FvObj.AprioriSectionList.append(AprSectionObj) return True - ## __GetInfStatement() method - # - # Get INF statements - # - # @param self The object pointer - # @param Obj for whom inf statement is got - # @param MacroDict dictionary used to replace macro - # @retval True Successfully find inf statement - # @retval False Not able to find inf statement - # - def __GetInfStatement(self, Obj, ForCapsule = False, MacroDict = {}): - - if not self.__IsKeyword( "INF"): - return False + def __ParseInfStatement(self): + if not self.__IsKeyword("INF"): + return None ffsInf = FfsInfStatement.FfsInfStatement() - self.__GetInfOptions( ffsInf) + self.__GetInfOptions(ffsInf) if not self.__GetNextToken(): raise Warning("expected INF file path", self.FileName, self.CurrentLineNumber) @@ -2472,7 +2471,23 @@ def __GetInfStatement(self, Obj, ForCapsule = False, MacroDict = {}): ffsInf.KeepReloc = True else: raise Warning("Unknown reloc strip flag '%s'" % self.__Token, self.FileName, self.CurrentLineNumber) - + return ffsInf + + ## __GetInfStatement() method + # + # Get INF statements + # + # @param self The object pointer + # @param Obj for whom inf statement is got + # @param MacroDict dictionary used to replace macro + # @retval True Successfully find inf statement + # @retval False Not able to find inf statement + # + def __GetInfStatement(self, Obj, ForCapsule=False, MacroDict={}): + ffsInf = self.__ParseInfStatement() + if not ffsInf: + return False + if ForCapsule: capsuleFfs = CapsuleData.CapsuleFfs() capsuleFfs.Ffs = ffsInf diff --git a/BaseTools/Source/Python/GenFds/FfsInfStatement.py b/BaseTools/Source/Python/GenFds/FfsInfStatement.py index ed767d3fa698..7b221399b401 100644 --- a/BaseTools/Source/Python/GenFds/FfsInfStatement.py +++ b/BaseTools/Source/Python/GenFds/FfsInfStatement.py @@ -331,25 +331,63 @@ def __InfParse__(self, Dict = {}): # If passed in file does not end with efi, return as is # def PatchEfiFile(self, EfiFile, FileType): + # + # If the module does not have any patches, then return path to input file + # if not self.PatchPcds: return EfiFile + + # + # Only patch file if FileType is PE32 or ModuleType is USER_DEFINED + # if FileType != 'PE32' and self.ModuleType != "USER_DEFINED": return EfiFile + + # + # Generate path to patched output file + # + Basename = os.path.basename(EfiFile) + Output = os.path.normpath (os.path.join(self.OutputPath, Basename)) + + # + # If this file has already been patched, then return the path to the patched file + # + if self.PatchedBinFile == Output: + return Output + + # + # If a different file from the same module has already been patched, then generate an error + # if self.PatchedBinFile: EdkLogger.error("GenFds", GENFDS_ERROR, 'Only one binary file can be patched:\n' ' a binary file has been patched: %s\n' ' current file: %s' % (self.PatchedBinFile, EfiFile), File=self.InfFileName) - Basename = os.path.basename(EfiFile) - Output = os.path.join(self.OutputPath, Basename) + + # + # Copy unpatched file contents to output file location to perform patching + # CopyLongFilePath(EfiFile, Output) + + # + # Apply patches to patched output file + # for Pcd, Value in self.PatchPcds: RetVal, RetStr = PatchBinaryFile(Output, int(Pcd.Offset, 0), Pcd.DatumType, Value, Pcd.MaxDatumSize) if RetVal: EdkLogger.error("GenFds", GENFDS_ERROR, RetStr, File=self.InfFileName) - self.PatchedBinFile = os.path.normpath(EfiFile) + + # + # Save the path of the patched output file + # + self.PatchedBinFile = Output + + # + # Return path to patched output file + # return Output + ## GenFfs() method # # Generate FFS diff --git a/BaseTools/Source/Python/GenFds/Region.py b/BaseTools/Source/Python/GenFds/Region.py index 01e998e54c6f..8734635fda29 100644 --- a/BaseTools/Source/Python/GenFds/Region.py +++ b/BaseTools/Source/Python/GenFds/Region.py @@ -1,7 +1,7 @@ ## @file # process FD Region generation # -# Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.
+# Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.
# # This program and the accompanying materials # are licensed and made available under the terms and conditions of the BSD License @@ -202,13 +202,20 @@ def AddToBuffer(self, Buffer, BaseAddress, BlockSizeList, ErasePolarity, ImageBi for i in range(0, Size): Buffer.write(pack('B', PadData)) - if self.RegionType == 'FILE': + if self.RegionType in ('FILE', 'INF'): for RegionData in self.RegionDataList: - RegionData = GenFdsGlobalVariable.MacroExtend(RegionData, MacroDict) - if RegionData[1] != ':' : - RegionData = mws.join (GenFdsGlobalVariable.WorkSpaceDir, RegionData) - if not os.path.exists(RegionData): - EdkLogger.error("GenFds", FILE_NOT_FOUND, ExtraData=RegionData) + if self.RegionType == 'INF': + RegionData.__InfParse__(None) + if len(RegionData.BinFileList) != 1: + EdkLogger.error('GenFds', GENFDS_ERROR, 'INF in FD region can only contain one binary: %s' % RegionData) + File = RegionData.BinFileList[0] + RegionData = RegionData.PatchEfiFile(File.Path, File.Type) + else: + RegionData = GenFdsGlobalVariable.MacroExtend(RegionData, MacroDict) + if RegionData[1] != ':' : + RegionData = os.path.join (GenFdsGlobalVariable.WorkSpaceDir, RegionData) + if not os.path.exists(RegionData): + EdkLogger.error("GenFds", FILE_NOT_FOUND, ExtraData=RegionData) # # Add the file image into FD buffer # From 9ada9cb84cb0693d545a0286f940afaa79765e04 Mon Sep 17 00:00:00 2001 From: Yonghong Zhu Date: Fri, 18 Dec 2015 06:46:23 +0000 Subject: [PATCH 275/525] BaseTools: Enhance GenFv Tool to report error message When two vtf files in one FV image, no FV file can be generated, but it report the stack trace info. so we enhance the tool to report error message directly but not the stack trace info. (Sync patch r19137 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Yonghong Zhu Reviewed-by: Liming Gao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19373 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Source/C/Include/Common/BuildVersion.h | 2 +- BaseTools/Source/Python/GenFds/Fv.py | 43 ++++++++++--------- 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/BaseTools/Source/C/Include/Common/BuildVersion.h b/BaseTools/Source/C/Include/Common/BuildVersion.h index d5bc56cb873c..8bfa74114022 100644 --- a/BaseTools/Source/C/Include/Common/BuildVersion.h +++ b/BaseTools/Source/C/Include/Common/BuildVersion.h @@ -12,4 +12,4 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ -#define __BUILD_VERSION "" +#define __BUILD_VERSION "Build 99862" diff --git a/BaseTools/Source/Python/GenFds/Fv.py b/BaseTools/Source/Python/GenFds/Fv.py index 163ccd37f158..df97ccbab648 100644 --- a/BaseTools/Source/Python/GenFds/Fv.py +++ b/BaseTools/Source/Python/GenFds/Fv.py @@ -181,30 +181,33 @@ def AddToBuffer (self, Buffer, BaseAddress=None, BlockSize= None, BlockNum=None, # # Write the Fv contents to Buffer # - FvFileObj = open ( FvOutputFile,'r+b') + if os.path.isfile(FvOutputFile): + FvFileObj = open ( FvOutputFile,'r+b') - GenFdsGlobalVariable.VerboseLogger( "\nGenerate %s FV Successfully" %self.UiFvName) - GenFdsGlobalVariable.SharpCounter = 0 + GenFdsGlobalVariable.VerboseLogger( "\nGenerate %s FV Successfully" %self.UiFvName) + GenFdsGlobalVariable.SharpCounter = 0 - Buffer.write(FvFileObj.read()) - FvFileObj.seek(0) - # PI FvHeader is 0x48 byte - FvHeaderBuffer = FvFileObj.read(0x48) - # FV alignment position. - FvAlignmentValue = 1 << (ord (FvHeaderBuffer[0x2E]) & 0x1F) - # FvAlignmentValue is larger than or equal to 1K - if FvAlignmentValue >= 0x400: - if FvAlignmentValue >= 0x10000: - #The max alignment supported by FFS is 64K. - self.FvAlignment = "64K" + Buffer.write(FvFileObj.read()) + FvFileObj.seek(0) + # PI FvHeader is 0x48 byte + FvHeaderBuffer = FvFileObj.read(0x48) + # FV alignment position. + FvAlignmentValue = 1 << (ord (FvHeaderBuffer[0x2E]) & 0x1F) + # FvAlignmentValue is larger than or equal to 1K + if FvAlignmentValue >= 0x400: + if FvAlignmentValue >= 0x10000: + #The max alignment supported by FFS is 64K. + self.FvAlignment = "64K" + else: + self.FvAlignment = str (FvAlignmentValue / 0x400) + "K" else: - self.FvAlignment = str (FvAlignmentValue / 0x400) + "K" + # FvAlignmentValue is less than 1K + self.FvAlignment = str (FvAlignmentValue) + FvFileObj.close() + GenFds.ImageBinDict[self.UiFvName.upper() + 'fv'] = FvOutputFile + GenFdsGlobalVariable.LargeFileInFvFlags.pop() else: - # FvAlignmentValue is less than 1K - self.FvAlignment = str (FvAlignmentValue) - FvFileObj.close() - GenFds.ImageBinDict[self.UiFvName.upper() + 'fv'] = FvOutputFile - GenFdsGlobalVariable.LargeFileInFvFlags.pop() + GenFdsGlobalVariable.ErrorLogger("Failed to generate %s FV file." %self.UiFvName) return FvOutputFile ## _GetBlockSize() From e6ad964ec7a1f6f98a2b14d374541c02f48fdf2e Mon Sep 17 00:00:00 2001 From: Yonghong Zhu Date: Fri, 18 Dec 2015 06:47:07 +0000 Subject: [PATCH 276/525] Revert the change in r19137. (Sync patch r19138 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Yonghong Zhu git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19374 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Source/C/Include/Common/BuildVersion.h | 2 +- BaseTools/Source/Python/GenFds/Fv.py | 43 +++++++++---------- 2 files changed, 21 insertions(+), 24 deletions(-) diff --git a/BaseTools/Source/C/Include/Common/BuildVersion.h b/BaseTools/Source/C/Include/Common/BuildVersion.h index 8bfa74114022..d5bc56cb873c 100644 --- a/BaseTools/Source/C/Include/Common/BuildVersion.h +++ b/BaseTools/Source/C/Include/Common/BuildVersion.h @@ -12,4 +12,4 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ -#define __BUILD_VERSION "Build 99862" +#define __BUILD_VERSION "" diff --git a/BaseTools/Source/Python/GenFds/Fv.py b/BaseTools/Source/Python/GenFds/Fv.py index df97ccbab648..163ccd37f158 100644 --- a/BaseTools/Source/Python/GenFds/Fv.py +++ b/BaseTools/Source/Python/GenFds/Fv.py @@ -181,33 +181,30 @@ def AddToBuffer (self, Buffer, BaseAddress=None, BlockSize= None, BlockNum=None, # # Write the Fv contents to Buffer # - if os.path.isfile(FvOutputFile): - FvFileObj = open ( FvOutputFile,'r+b') + FvFileObj = open ( FvOutputFile,'r+b') - GenFdsGlobalVariable.VerboseLogger( "\nGenerate %s FV Successfully" %self.UiFvName) - GenFdsGlobalVariable.SharpCounter = 0 + GenFdsGlobalVariable.VerboseLogger( "\nGenerate %s FV Successfully" %self.UiFvName) + GenFdsGlobalVariable.SharpCounter = 0 - Buffer.write(FvFileObj.read()) - FvFileObj.seek(0) - # PI FvHeader is 0x48 byte - FvHeaderBuffer = FvFileObj.read(0x48) - # FV alignment position. - FvAlignmentValue = 1 << (ord (FvHeaderBuffer[0x2E]) & 0x1F) - # FvAlignmentValue is larger than or equal to 1K - if FvAlignmentValue >= 0x400: - if FvAlignmentValue >= 0x10000: - #The max alignment supported by FFS is 64K. - self.FvAlignment = "64K" - else: - self.FvAlignment = str (FvAlignmentValue / 0x400) + "K" + Buffer.write(FvFileObj.read()) + FvFileObj.seek(0) + # PI FvHeader is 0x48 byte + FvHeaderBuffer = FvFileObj.read(0x48) + # FV alignment position. + FvAlignmentValue = 1 << (ord (FvHeaderBuffer[0x2E]) & 0x1F) + # FvAlignmentValue is larger than or equal to 1K + if FvAlignmentValue >= 0x400: + if FvAlignmentValue >= 0x10000: + #The max alignment supported by FFS is 64K. + self.FvAlignment = "64K" else: - # FvAlignmentValue is less than 1K - self.FvAlignment = str (FvAlignmentValue) - FvFileObj.close() - GenFds.ImageBinDict[self.UiFvName.upper() + 'fv'] = FvOutputFile - GenFdsGlobalVariable.LargeFileInFvFlags.pop() + self.FvAlignment = str (FvAlignmentValue / 0x400) + "K" else: - GenFdsGlobalVariable.ErrorLogger("Failed to generate %s FV file." %self.UiFvName) + # FvAlignmentValue is less than 1K + self.FvAlignment = str (FvAlignmentValue) + FvFileObj.close() + GenFds.ImageBinDict[self.UiFvName.upper() + 'fv'] = FvOutputFile + GenFdsGlobalVariable.LargeFileInFvFlags.pop() return FvOutputFile ## _GetBlockSize() From b30dd623c9151866cd1ef1cf31de62d415586875 Mon Sep 17 00:00:00 2001 From: Yonghong Zhu Date: Fri, 18 Dec 2015 06:47:44 +0000 Subject: [PATCH 277/525] BaseTools: Fix a bug in the VPD report generation Changed the if condition to check whether current Region is FD VPD region to fix a bug in the VPD report generation. (Sync patch r19139 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Yonghong Zhu Reviewed-by: Liming Gao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19375 6f19259b-4bc3-4df7-8a09-765794883524 --- BaseTools/Source/Python/build/BuildReport.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/BaseTools/Source/Python/build/BuildReport.py b/BaseTools/Source/Python/build/BuildReport.py index 722d8b7f458c..d459a0113acb 100644 --- a/BaseTools/Source/Python/build/BuildReport.py +++ b/BaseTools/Source/Python/build/BuildReport.py @@ -1389,11 +1389,11 @@ def __init__(self, Fd, Wa): self.FdRegionList = [FdRegionReport(FdRegion, Wa) for FdRegion in Fd.RegionList] self.FvPath = os.path.join(Wa.BuildDir, "FV") self.VpdFilePath = os.path.join(self.FvPath, "%s.map" % Wa.Platform.VpdToolGuid) - VpdPcdToken = 'gEfiMdeModulePkgTokenSpaceGuid' - VpdPcdName = 'PcdVpdBaseAddress' + self.VPDBaseAddress = 0 + self.VPDSize = 0 self.VPDInfoList = [] for index, FdRegion in enumerate(Fd.RegionList): - if (VpdPcdName, VpdPcdToken) == FdRegion.PcdOffset: + if str(FdRegion.RegionType) is 'FILE' and Wa.Platform.VpdToolGuid in str(FdRegion.RegionDataList): self.VPDBaseAddress = self.FdRegionList[index].BaseAddress self.VPDSize = self.FdRegionList[index].Size break From 8e3314b048ed8efac7d743d23a32f89634055bac Mon Sep 17 00:00:00 2001 From: Yonghong Zhu Date: Fri, 18 Dec 2015 06:48:32 +0000 Subject: [PATCH 278/525] BaseTools: Enhance GenFv Tool to report error message When two vtf files in one FV image, no FV file can be generated, but it report the stack trace info. so we enhance the tool to report error message directly but not the stack trace info. (Sync patch r19141 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Yonghong Zhu Reviewed-by: Liming Gao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19376 6f19259b-4bc3-4df7-8a09-765794883524 --- BaseTools/Source/C/GenFv/GenFvInternalLib.c | 23 +++++------ BaseTools/Source/Python/GenFds/Fv.py | 43 +++++++++++---------- 2 files changed, 35 insertions(+), 31 deletions(-) diff --git a/BaseTools/Source/C/GenFv/GenFvInternalLib.c b/BaseTools/Source/C/GenFv/GenFvInternalLib.c index 6d2d5d1f8c67..10bb88b0a88c 100644 --- a/BaseTools/Source/C/GenFv/GenFvInternalLib.c +++ b/BaseTools/Source/C/GenFv/GenFvInternalLib.c @@ -2854,17 +2854,18 @@ Routine Description: fclose (fpin); if (FvInfoPtr->IsPiFvImage) { - // - // Check whether this ffs file is vtf file - // - if (IsVtfFile (&FfsHeader)) { - if (VtfFileFlag) { - // - // One Fv image can't have two vtf files. - // - return EFI_ABORTED; - } - VtfFileFlag = TRUE; + // + // Check whether this ffs file is vtf file + // + if (IsVtfFile (&FfsHeader)) { + if (VtfFileFlag) { + // + // One Fv image can't have two vtf files. + // + Error (NULL, 0, 3000,"Invalid", "One Fv image can't have two vtf files."); + return EFI_ABORTED; + } + VtfFileFlag = TRUE; VtfFileSize = FfsFileSize; continue; } diff --git a/BaseTools/Source/Python/GenFds/Fv.py b/BaseTools/Source/Python/GenFds/Fv.py index 163ccd37f158..df97ccbab648 100644 --- a/BaseTools/Source/Python/GenFds/Fv.py +++ b/BaseTools/Source/Python/GenFds/Fv.py @@ -181,30 +181,33 @@ def AddToBuffer (self, Buffer, BaseAddress=None, BlockSize= None, BlockNum=None, # # Write the Fv contents to Buffer # - FvFileObj = open ( FvOutputFile,'r+b') + if os.path.isfile(FvOutputFile): + FvFileObj = open ( FvOutputFile,'r+b') - GenFdsGlobalVariable.VerboseLogger( "\nGenerate %s FV Successfully" %self.UiFvName) - GenFdsGlobalVariable.SharpCounter = 0 + GenFdsGlobalVariable.VerboseLogger( "\nGenerate %s FV Successfully" %self.UiFvName) + GenFdsGlobalVariable.SharpCounter = 0 - Buffer.write(FvFileObj.read()) - FvFileObj.seek(0) - # PI FvHeader is 0x48 byte - FvHeaderBuffer = FvFileObj.read(0x48) - # FV alignment position. - FvAlignmentValue = 1 << (ord (FvHeaderBuffer[0x2E]) & 0x1F) - # FvAlignmentValue is larger than or equal to 1K - if FvAlignmentValue >= 0x400: - if FvAlignmentValue >= 0x10000: - #The max alignment supported by FFS is 64K. - self.FvAlignment = "64K" + Buffer.write(FvFileObj.read()) + FvFileObj.seek(0) + # PI FvHeader is 0x48 byte + FvHeaderBuffer = FvFileObj.read(0x48) + # FV alignment position. + FvAlignmentValue = 1 << (ord (FvHeaderBuffer[0x2E]) & 0x1F) + # FvAlignmentValue is larger than or equal to 1K + if FvAlignmentValue >= 0x400: + if FvAlignmentValue >= 0x10000: + #The max alignment supported by FFS is 64K. + self.FvAlignment = "64K" + else: + self.FvAlignment = str (FvAlignmentValue / 0x400) + "K" else: - self.FvAlignment = str (FvAlignmentValue / 0x400) + "K" + # FvAlignmentValue is less than 1K + self.FvAlignment = str (FvAlignmentValue) + FvFileObj.close() + GenFds.ImageBinDict[self.UiFvName.upper() + 'fv'] = FvOutputFile + GenFdsGlobalVariable.LargeFileInFvFlags.pop() else: - # FvAlignmentValue is less than 1K - self.FvAlignment = str (FvAlignmentValue) - FvFileObj.close() - GenFds.ImageBinDict[self.UiFvName.upper() + 'fv'] = FvOutputFile - GenFdsGlobalVariable.LargeFileInFvFlags.pop() + GenFdsGlobalVariable.ErrorLogger("Failed to generate %s FV file." %self.UiFvName) return FvOutputFile ## _GetBlockSize() From 7182a9146f26fa424deccf3c8d0b691cc5bd3c23 Mon Sep 17 00:00:00 2001 From: Yonghong Zhu Date: Fri, 18 Dec 2015 06:49:12 +0000 Subject: [PATCH 279/525] BaseTools: Fix a bug when apply patches to SEC use the FILE_GUID override Fix a bug when applying patches to SEC modules that use the FILE_GUID override. Since a temp dir is used when FILE_GUID override is used, the INF file path comparisons fail. The fix is to capture the real INF file path comparisons instead of using the temp dir path to the INF. (Sync patch r19142 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Yonghong Zhu Reviewed-by: Liming Gao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19377 6f19259b-4bc3-4df7-8a09-765794883524 --- BaseTools/Source/Python/GenFds/FfsInfStatement.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/BaseTools/Source/Python/GenFds/FfsInfStatement.py b/BaseTools/Source/Python/GenFds/FfsInfStatement.py index 7b221399b401..864e5be7d9e0 100644 --- a/BaseTools/Source/Python/GenFds/FfsInfStatement.py +++ b/BaseTools/Source/Python/GenFds/FfsInfStatement.py @@ -174,6 +174,10 @@ def __InfParse__(self, Dict = {}): if ErrorCode != 0: EdkLogger.error("GenFds", ErrorCode, ExtraData=ErrorInfo) + # + # Cache lower case version of INF path before processing FILE_GUID override + # + InfLowerPath = str(PathClassObj).lower() if self.OverrideGuid: PathClassObj = ProcessDuplicatedInf(PathClassObj, self.OverrideGuid, GenFdsGlobalVariable.WorkSpaceDir) if self.CurrentArch != None: @@ -241,7 +245,6 @@ def __InfParse__(self, Dict = {}): continue # Override Patchable PCD value by the value from DSC PatchPcd = None - InfLowerPath = str(PathClassObj).lower() if InfLowerPath in DscModules and PcdKey in DscModules[InfLowerPath].Pcds: PatchPcd = DscModules[InfLowerPath].Pcds[PcdKey] elif PcdKey in Platform.Pcds: From f91c838c59db44a2ed89dc55e4d5ce075772eb5f Mon Sep 17 00:00:00 2001 From: Yonghong Zhu Date: Fri, 18 Dec 2015 06:49:46 +0000 Subject: [PATCH 280/525] BaseTools: process the files by the priority in BUILDRULEORDER By the BUILDRULEORDER feature to process files listed in INF [Sources] sections in priority order, if a filename is listed with multiple extensions, the tools will use only the file that matches the first extension in the space separated list. (Sync patch r19143 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Yonghong Zhu Reviewed-by: Liming Gao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19378 6f19259b-4bc3-4df7-8a09-765794883524 --- BaseTools/Source/Python/AutoGen/AutoGen.py | 27 ++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/BaseTools/Source/Python/AutoGen/AutoGen.py b/BaseTools/Source/Python/AutoGen/AutoGen.py index 4c627dfb555a..cf0b4466f992 100644 --- a/BaseTools/Source/Python/AutoGen/AutoGen.py +++ b/BaseTools/Source/Python/AutoGen/AutoGen.py @@ -2713,9 +2713,36 @@ def _GetSourceFileList(self): if F.Dir not in self.IncludePathList and self.AutoGenVersion >= 0x00010005: self.IncludePathList.insert(0, F.Dir) self._SourceFileList.append(F) + + self._MatchBuildRuleOrder(self._SourceFileList) + + for F in self._SourceFileList: self._ApplyBuildRule(F, TAB_UNKNOWN_FILE) return self._SourceFileList + def _MatchBuildRuleOrder(self, FileList): + Order_Dict = {} + self._GetModuleBuildOption() + for SingleFile in FileList: + if self.BuildRuleOrder and SingleFile.Ext in self.BuildRuleOrder: + key = SingleFile.Path.split(SingleFile.Ext)[0] + if key in Order_Dict: + Order_Dict[key].append(SingleFile.Ext) + else: + Order_Dict[key] = [SingleFile.Ext] + + RemoveList = [] + for F in Order_Dict: + if len(Order_Dict[F]) > 1: + Order_Dict[F].sort(key=lambda i: self.BuildRuleOrder.index(i)) + for Ext in Order_Dict[F][1:]: + RemoveList.append(F + Ext) + + for item in RemoveList: + FileList.remove(item) + + return FileList + ## Return the list of unicode files def _GetUnicodeFileList(self): if self._UnicodeFileList == None: From 57b4b9977d0a45a90a7c784bc3bd9036d674e6ef Mon Sep 17 00:00:00 2001 From: Yonghong Zhu Date: Fri, 18 Dec 2015 06:50:15 +0000 Subject: [PATCH 281/525] BaseTools: update man page to add some descriptions add the description for --ignore-sources and --check-usage into man page. (Sync patch r19144 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Yonghong Zhu Reviewed-by: Liming Gao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19379 6f19259b-4bc3-4df7-8a09-765794883524 --- .../UserManuals/Build_Utility_Man_Page.rtf | 723 +++++++++--------- 1 file changed, 378 insertions(+), 345 deletions(-) diff --git a/BaseTools/UserManuals/Build_Utility_Man_Page.rtf b/BaseTools/UserManuals/Build_Utility_Man_Page.rtf index 6a0e7d996850..af3a071ad6a6 100644 --- a/BaseTools/UserManuals/Build_Utility_Man_Page.rtf +++ b/BaseTools/UserManuals/Build_Utility_Man_Page.rtf @@ -1,29 +1,31 @@ -{\rtf1\adeflang1025\ansi\ansicpg936\uc2\adeff0\deff0\stshfdbch13\stshfloch37\stshfhich37\stshfbi0\deflang1033\deflangfe2052\themelang1033\themelangfe2052\themelangcs0{\fonttbl{\f0\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman{\*\falt Times};} +{\rtf1\adeflang1025\ansi\ansicpg1252\uc2\adeff0\deff0\stshfdbch13\stshfloch37\stshfhich37\stshfbi0\deflang1033\deflangfe2052\themelang1033\themelangfe2052\themelangcs0{\fonttbl{\f0\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman{\*\falt Times};} {\f2\fbidi \fmodern\fcharset0\fprq1{\*\panose 02070309020205020404}Courier New{\*\falt Courier New};}{\f13\fbidi \fnil\fcharset134\fprq2{\*\panose 02010600030101010101}\'cb\'ce\'cc\'e5{\*\falt SimSun};} -{\f34\fbidi \froman\fcharset1\fprq2{\*\panose 02040503050406030204}Cambria Math;}{\f36\fbidi \froman\fcharset0\fprq2{\*\panose 02040503050406030204}Cambria;} -{\f37\fbidi \fswiss\fcharset0\fprq2{\*\panose 020f0502020204030204}Calibri{\*\falt Century Gothic};}{\f38\fbidi \fswiss\fcharset0\fprq2{\*\panose 020b0604030504040204}Tahoma{\*\falt Times New Roman};} -{\f40\fbidi \fnil\fcharset134\fprq2{\*\panose 02010600030101010101}@\'cb\'ce\'cc\'e5;}{\f41\fbidi \fswiss\fcharset0\fprq2{\*\panose 00000000000000000000}Verdana{\*\falt Verdana};} -{\f42\fbidi \fmodern\fcharset0\fprq1{\*\panose 00000000000000000000}Consolas;}{\flomajor\f31500\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman{\*\falt Times};} -{\fdbmajor\f31501\fbidi \fnil\fcharset134\fprq2{\*\panose 02010600030101010101}\'cb\'ce\'cc\'e5{\*\falt SimSun};}{\fhimajor\f31502\fbidi \froman\fcharset0\fprq2{\*\panose 02040503050406030204}Cambria;} +{\f34\fbidi \froman\fcharset0\fprq2{\*\panose 02040503050406030204}Cambria Math;}{\f37\fbidi \fswiss\fcharset0\fprq2{\*\panose 020f0502020204030204}Calibri{\*\falt Century Gothic};} +{\f39\fbidi \froman\fcharset0\fprq2{\*\panose 00000000000000000000}Cambria;}{\f40\fbidi \fswiss\fcharset0\fprq2{\*\panose 00000000000000000000}Tahoma{\*\falt Times New Roman};} +{\f41\fbidi \fnil\fcharset134\fprq2{\*\panose 00000000000000000000}@\'cb\'ce\'cc\'e5;}{\f42\fbidi \fswiss\fcharset0\fprq2{\*\panose 020b0604030504040204}Verdana{\*\falt Verdana};} +{\f43\fbidi \fmodern\fcharset0\fprq1{\*\panose 020b0609020204030204}Consolas;}{\flomajor\f31500\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman{\*\falt Times};} +{\fdbmajor\f31501\fbidi \fnil\fcharset134\fprq2{\*\panose 02010600030101010101}\'cb\'ce\'cc\'e5{\*\falt SimSun};}{\fhimajor\f31502\fbidi \froman\fcharset0\fprq2{\*\panose 00000000000000000000}Cambria;} {\fbimajor\f31503\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman{\*\falt Times};}{\flominor\f31504\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman{\*\falt Times};} {\fdbminor\f31505\fbidi \fnil\fcharset134\fprq2{\*\panose 02010600030101010101}\'cb\'ce\'cc\'e5{\*\falt SimSun};}{\fhiminor\f31506\fbidi \fswiss\fcharset0\fprq2{\*\panose 020f0502020204030204}Calibri{\*\falt Century Gothic};} -{\fbiminor\f31507\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman{\*\falt Times};}{\f44\fbidi \froman\fcharset238\fprq2 Times New Roman CE{\*\falt Times};} -{\f45\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr{\*\falt Times};}{\f47\fbidi \froman\fcharset161\fprq2 Times New Roman Greek{\*\falt Times};}{\f48\fbidi \froman\fcharset162\fprq2 Times New Roman Tur{\*\falt Times};} -{\f49\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew){\*\falt Times};}{\f50\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic){\*\falt Times};}{\f51\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic{\*\falt Times};} -{\f52\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese){\*\falt Times};}{\f64\fbidi \fmodern\fcharset238\fprq1 Courier New CE{\*\falt Courier New};}{\f65\fbidi \fmodern\fcharset204\fprq1 Courier New Cyr{\*\falt Courier New};} -{\f67\fbidi \fmodern\fcharset161\fprq1 Courier New Greek{\*\falt Courier New};}{\f68\fbidi \fmodern\fcharset162\fprq1 Courier New Tur{\*\falt Courier New};}{\f69\fbidi \fmodern\fcharset177\fprq1 Courier New (Hebrew){\*\falt Courier New};} -{\f70\fbidi \fmodern\fcharset178\fprq1 Courier New (Arabic){\*\falt Courier New};}{\f71\fbidi \fmodern\fcharset186\fprq1 Courier New Baltic{\*\falt Courier New};}{\f72\fbidi \fmodern\fcharset163\fprq1 Courier New (Vietnamese){\*\falt Courier New};} -{\f176\fbidi \fnil\fcharset0\fprq2 SimSun Western{\*\falt SimSun};}{\f404\fbidi \froman\fcharset238\fprq2 Cambria CE;}{\f405\fbidi \froman\fcharset204\fprq2 Cambria Cyr;}{\f407\fbidi \froman\fcharset161\fprq2 Cambria Greek;} -{\f408\fbidi \froman\fcharset162\fprq2 Cambria Tur;}{\f411\fbidi \froman\fcharset186\fprq2 Cambria Baltic;}{\f412\fbidi \froman\fcharset163\fprq2 Cambria (Vietnamese);}{\f414\fbidi \fswiss\fcharset238\fprq2 Calibri CE{\*\falt Century Gothic};} -{\f415\fbidi \fswiss\fcharset204\fprq2 Calibri Cyr{\*\falt Century Gothic};}{\f417\fbidi \fswiss\fcharset161\fprq2 Calibri Greek{\*\falt Century Gothic};}{\f418\fbidi \fswiss\fcharset162\fprq2 Calibri Tur{\*\falt Century Gothic};} -{\f421\fbidi \fswiss\fcharset186\fprq2 Calibri Baltic{\*\falt Century Gothic};}{\f422\fbidi \fswiss\fcharset163\fprq2 Calibri (Vietnamese){\*\falt Century Gothic};}{\f424\fbidi \fswiss\fcharset238\fprq2 Tahoma CE{\*\falt Times New Roman};} -{\f425\fbidi \fswiss\fcharset204\fprq2 Tahoma Cyr{\*\falt Times New Roman};}{\f427\fbidi \fswiss\fcharset161\fprq2 Tahoma Greek{\*\falt Times New Roman};}{\f428\fbidi \fswiss\fcharset162\fprq2 Tahoma Tur{\*\falt Times New Roman};} -{\f429\fbidi \fswiss\fcharset177\fprq2 Tahoma (Hebrew){\*\falt Times New Roman};}{\f430\fbidi \fswiss\fcharset178\fprq2 Tahoma (Arabic){\*\falt Times New Roman};}{\f431\fbidi \fswiss\fcharset186\fprq2 Tahoma Baltic{\*\falt Times New Roman};} -{\f432\fbidi \fswiss\fcharset163\fprq2 Tahoma (Vietnamese){\*\falt Times New Roman};}{\f433\fbidi \fswiss\fcharset222\fprq2 Tahoma (Thai){\*\falt Times New Roman};}{\f446\fbidi \fnil\fcharset0\fprq2 @\'cb\'ce\'cc\'e5 Western;} -{\f454\fbidi \fswiss\fcharset238\fprq2 Verdana CE{\*\falt Verdana};}{\f455\fbidi \fswiss\fcharset204\fprq2 Verdana Cyr{\*\falt Verdana};}{\f457\fbidi \fswiss\fcharset161\fprq2 Verdana Greek{\*\falt Verdana};} -{\f458\fbidi \fswiss\fcharset162\fprq2 Verdana Tur{\*\falt Verdana};}{\f461\fbidi \fswiss\fcharset186\fprq2 Verdana Baltic{\*\falt Verdana};}{\f462\fbidi \fswiss\fcharset163\fprq2 Verdana (Vietnamese){\*\falt Verdana};} -{\f464\fbidi \fmodern\fcharset238\fprq1 Consolas CE;}{\f465\fbidi \fmodern\fcharset204\fprq1 Consolas Cyr;}{\f467\fbidi \fmodern\fcharset161\fprq1 Consolas Greek;}{\f468\fbidi \fmodern\fcharset162\fprq1 Consolas Tur;} -{\f471\fbidi \fmodern\fcharset186\fprq1 Consolas Baltic;}{\f472\fbidi \fmodern\fcharset163\fprq1 Consolas (Vietnamese);}{\flomajor\f31508\fbidi \froman\fcharset238\fprq2 Times New Roman CE{\*\falt Times};} +{\fbiminor\f31507\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman{\*\falt Times};}{\f45\fbidi \froman\fcharset238\fprq2 Times New Roman CE{\*\falt Times};} +{\f46\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr{\*\falt Times};}{\f48\fbidi \froman\fcharset161\fprq2 Times New Roman Greek{\*\falt Times};}{\f49\fbidi \froman\fcharset162\fprq2 Times New Roman Tur{\*\falt Times};} +{\f50\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew){\*\falt Times};}{\f51\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic){\*\falt Times};}{\f52\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic{\*\falt Times};} +{\f53\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese){\*\falt Times};}{\f65\fbidi \fmodern\fcharset238\fprq1 Courier New CE{\*\falt Courier New};}{\f66\fbidi \fmodern\fcharset204\fprq1 Courier New Cyr{\*\falt Courier New};} +{\f68\fbidi \fmodern\fcharset161\fprq1 Courier New Greek{\*\falt Courier New};}{\f69\fbidi \fmodern\fcharset162\fprq1 Courier New Tur{\*\falt Courier New};}{\f70\fbidi \fmodern\fcharset177\fprq1 Courier New (Hebrew){\*\falt Courier New};} +{\f71\fbidi \fmodern\fcharset178\fprq1 Courier New (Arabic){\*\falt Courier New};}{\f72\fbidi \fmodern\fcharset186\fprq1 Courier New Baltic{\*\falt Courier New};}{\f73\fbidi \fmodern\fcharset163\fprq1 Courier New (Vietnamese){\*\falt Courier New};} +{\f177\fbidi \fnil\fcharset0\fprq2 SimSun Western{\*\falt SimSun};}{\f385\fbidi \froman\fcharset238\fprq2 Cambria Math CE;}{\f386\fbidi \froman\fcharset204\fprq2 Cambria Math Cyr;}{\f388\fbidi \froman\fcharset161\fprq2 Cambria Math Greek;} +{\f389\fbidi \froman\fcharset162\fprq2 Cambria Math Tur;}{\f392\fbidi \froman\fcharset186\fprq2 Cambria Math Baltic;}{\f393\fbidi \froman\fcharset163\fprq2 Cambria Math (Vietnamese);} +{\f415\fbidi \fswiss\fcharset238\fprq2 Calibri CE{\*\falt Century Gothic};}{\f416\fbidi \fswiss\fcharset204\fprq2 Calibri Cyr{\*\falt Century Gothic};}{\f418\fbidi \fswiss\fcharset161\fprq2 Calibri Greek{\*\falt Century Gothic};} +{\f419\fbidi \fswiss\fcharset162\fprq2 Calibri Tur{\*\falt Century Gothic};}{\f422\fbidi \fswiss\fcharset186\fprq2 Calibri Baltic{\*\falt Century Gothic};}{\f423\fbidi \fswiss\fcharset163\fprq2 Calibri (Vietnamese){\*\falt Century Gothic};} +{\f435\fbidi \froman\fcharset238\fprq2 Cambria CE;}{\f436\fbidi \froman\fcharset204\fprq2 Cambria Cyr;}{\f438\fbidi \froman\fcharset161\fprq2 Cambria Greek;}{\f439\fbidi \froman\fcharset162\fprq2 Cambria Tur;} +{\f442\fbidi \froman\fcharset186\fprq2 Cambria Baltic;}{\f443\fbidi \froman\fcharset163\fprq2 Cambria (Vietnamese);}{\f445\fbidi \fswiss\fcharset238\fprq2 Tahoma CE{\*\falt Times New Roman};} +{\f446\fbidi \fswiss\fcharset204\fprq2 Tahoma Cyr{\*\falt Times New Roman};}{\f448\fbidi \fswiss\fcharset161\fprq2 Tahoma Greek{\*\falt Times New Roman};}{\f449\fbidi \fswiss\fcharset162\fprq2 Tahoma Tur{\*\falt Times New Roman};} +{\f450\fbidi \fswiss\fcharset177\fprq2 Tahoma (Hebrew){\*\falt Times New Roman};}{\f451\fbidi \fswiss\fcharset178\fprq2 Tahoma (Arabic){\*\falt Times New Roman};}{\f452\fbidi \fswiss\fcharset186\fprq2 Tahoma Baltic{\*\falt Times New Roman};} +{\f453\fbidi \fswiss\fcharset163\fprq2 Tahoma (Vietnamese){\*\falt Times New Roman};}{\f454\fbidi \fswiss\fcharset222\fprq2 Tahoma (Thai){\*\falt Times New Roman};}{\f457\fbidi \fnil\fcharset0\fprq2 @\'cb\'ce\'cc\'e5 Western;} +{\f465\fbidi \fswiss\fcharset238\fprq2 Verdana CE{\*\falt Verdana};}{\f466\fbidi \fswiss\fcharset204\fprq2 Verdana Cyr{\*\falt Verdana};}{\f468\fbidi \fswiss\fcharset161\fprq2 Verdana Greek{\*\falt Verdana};} +{\f469\fbidi \fswiss\fcharset162\fprq2 Verdana Tur{\*\falt Verdana};}{\f472\fbidi \fswiss\fcharset186\fprq2 Verdana Baltic{\*\falt Verdana};}{\f473\fbidi \fswiss\fcharset163\fprq2 Verdana (Vietnamese){\*\falt Verdana};} +{\f475\fbidi \fmodern\fcharset238\fprq1 Consolas CE;}{\f476\fbidi \fmodern\fcharset204\fprq1 Consolas Cyr;}{\f478\fbidi \fmodern\fcharset161\fprq1 Consolas Greek;}{\f479\fbidi \fmodern\fcharset162\fprq1 Consolas Tur;} +{\f482\fbidi \fmodern\fcharset186\fprq1 Consolas Baltic;}{\f483\fbidi \fmodern\fcharset163\fprq1 Consolas (Vietnamese);}{\flomajor\f31508\fbidi \froman\fcharset238\fprq2 Times New Roman CE{\*\falt Times};} {\flomajor\f31509\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr{\*\falt Times};}{\flomajor\f31511\fbidi \froman\fcharset161\fprq2 Times New Roman Greek{\*\falt Times};} {\flomajor\f31512\fbidi \froman\fcharset162\fprq2 Times New Roman Tur{\*\falt Times};}{\flomajor\f31513\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew){\*\falt Times};} {\flomajor\f31514\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic){\*\falt Times};}{\flomajor\f31515\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic{\*\falt Times};} @@ -47,387 +49,418 @@ {\fbiminor\f31585\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic{\*\falt Times};}{\fbiminor\f31586\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese){\*\falt Times};}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255; \red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128\green0\blue0; \red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;\red8\green96\blue168;}{\*\defchp \fs21\kerning2\loch\af37\hich\af37\dbch\af13 }{\*\defpap \ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 } -\noqfpromote {\stylesheet{\ql \li0\ri0\nowidctlpar\wrapdefault\faauto\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\f41\hich\af41\dbch\af13\cgrid\langnp1033\langfenp1033 \snext0 \sqformat \spriority0 Normal;}{ -\s1\ql \li0\ri0\nowidctlpar\wrapdefault\faauto\outlinelevel0\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\f41\hich\af41\dbch\af13\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext0 \slink15 \sqformat -heading 1;}{\s2\ql \li0\ri0\nowidctlpar\wrapdefault\faauto\outlinelevel1\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\f41\hich\af41\dbch\af13\cgrid\langnp1033\langfenp1033 +\noqfpromote {\stylesheet{\ql \li0\ri0\nowidctlpar\wrapdefault\faauto\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\f42\hich\af42\dbch\af13\cgrid\langnp1033\langfenp1033 \snext0 \sqformat \spriority0 Normal;}{ +\s1\ql \li0\ri0\nowidctlpar\wrapdefault\faauto\outlinelevel0\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\f42\hich\af42\dbch\af13\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext0 \slink15 \sqformat +heading 1;}{\s2\ql \li0\ri0\nowidctlpar\wrapdefault\faauto\outlinelevel1\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\f42\hich\af42\dbch\af13\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext0 \slink16 \sqformat heading 2;}{\*\cs10 \additive \ssemihidden Default Paragraph Font;}{\* -\ts11\tsrowd\trftsWidthB3\trpaddl108\trpaddr108\trpaddfl3\trpaddft3\trpaddfb3\trpaddfr3\tblind0\tblindtype3\tscellwidthfts0\tsvertalt\tsbrdrt\tsbrdrl\tsbrdrb\tsbrdrr\tsbrdrdgl\tsbrdrdgr\tsbrdrh\tsbrdrv -\ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs22\alang1025 \ltrch\fcs0 \fs21\lang1033\langfe2052\kerning2\loch\f37\hich\af37\dbch\af13\cgrid\langnp1033\langfenp2052 -\snext11 \ssemihidden \sunhideused \sqformat Normal Table;}{\*\cs15 \additive \rtlch\fcs1 \ab\af0\afs32 \ltrch\fcs0 \b\fs32\kerning32\loch\f36\hich\af36\dbch\af13 \sbasedon10 \slink1 \slocked Heading 1 Char;}{\*\cs16 \additive \rtlch\fcs1 -\ab\ai\af0\afs28 \ltrch\fcs0 \b\i\fs28\loch\f36\hich\af36\dbch\af13 \sbasedon10 \slink2 \slocked Heading 2 Char;}{\*\cs17 \additive \rtlch\fcs1 \af0\afs16 \ltrch\fcs0 \fs16 \sbasedon10 \ssemihidden \styrsid16534634 annotation reference;}{ -\s18\ql \li0\ri0\nowidctlpar\wrapdefault\faauto\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\f41\hich\af41\dbch\af13\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext18 \slink19 \ssemihidden \styrsid16534634 -annotation text;}{\*\cs19 \additive \rtlch\fcs1 \af0 \ltrch\fcs0 \f41 \sbasedon10 \slink18 \slocked \ssemihidden \styrsid16534634 Comment Text Char;}{\s20\ql \li0\ri0\nowidctlpar\wrapdefault\faauto\rin0\lin0\itap0 \rtlch\fcs1 \ab\af0\afs20\alang1025 -\ltrch\fcs0 \b\fs20\lang1033\langfe1033\loch\f41\hich\af41\dbch\af13\cgrid\langnp1033\langfenp1033 \sbasedon18 \snext18 \slink21 \ssemihidden \styrsid16534634 annotation subject;}{\*\cs21 \additive \rtlch\fcs1 \ab\af0 \ltrch\fcs0 \b\f41 -\sbasedon19 \slink20 \slocked \ssemihidden \styrsid16534634 Comment Subject Char;}{\s22\ql \li0\ri0\nowidctlpar\wrapdefault\faauto\rin0\lin0\itap0 \rtlch\fcs1 \af38\afs16\alang1025 \ltrch\fcs0 -\fs16\lang1033\langfe1033\loch\f38\hich\af38\dbch\af13\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext22 \slink23 \ssemihidden \styrsid16534634 Balloon Text;}{\*\cs23 \additive \rtlch\fcs1 \af38\afs16 \ltrch\fcs0 \f38\fs16 +\ts11\tsrowd\trftsWidthB3\trpaddl108\trpaddr108\trpaddfl3\trpaddft3\trpaddfb3\trpaddfr3\tblind0\tblindtype3\tsvertalt\tsbrdrt\tsbrdrl\tsbrdrb\tsbrdrr\tsbrdrdgl\tsbrdrdgr\tsbrdrh\tsbrdrv +\ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs21\alang1025 \ltrch\fcs0 \fs21\lang1033\langfe2052\kerning2\loch\f37\hich\af37\dbch\af13\cgrid\langnp1033\langfenp2052 +\snext11 \ssemihidden \sunhideused Normal Table;}{\*\cs15 \additive \rtlch\fcs1 \ab\af0\afs32 \ltrch\fcs0 \b\fs32\kerning32\loch\f39\hich\af39\dbch\af13 \sbasedon10 \slink1 \slocked Heading 1 Char;}{\*\cs16 \additive \rtlch\fcs1 \ab\ai\af0\afs28 +\ltrch\fcs0 \b\i\fs28\loch\f39\hich\af39\dbch\af13 \sbasedon10 \slink2 \slocked Heading 2 Char;}{\*\cs17 \additive \rtlch\fcs1 \af0\afs16 \ltrch\fcs0 \fs16 \sbasedon10 \ssemihidden \styrsid16534634 annotation reference;}{ +\s18\ql \li0\ri0\nowidctlpar\wrapdefault\faauto\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\f42\hich\af42\dbch\af13\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext18 \slink19 \ssemihidden \styrsid16534634 +annotation text;}{\*\cs19 \additive \rtlch\fcs1 \af0 \ltrch\fcs0 \f42 \sbasedon10 \slink18 \slocked \ssemihidden \styrsid16534634 Comment Text Char;}{\s20\ql \li0\ri0\nowidctlpar\wrapdefault\faauto\rin0\lin0\itap0 \rtlch\fcs1 \ab\af0\afs20\alang1025 +\ltrch\fcs0 \b\fs20\lang1033\langfe1033\loch\f42\hich\af42\dbch\af13\cgrid\langnp1033\langfenp1033 \sbasedon18 \snext18 \slink21 \ssemihidden \styrsid16534634 annotation subject;}{\*\cs21 \additive \rtlch\fcs1 \ab\af0 \ltrch\fcs0 \b\f42 +\sbasedon19 \slink20 \slocked \ssemihidden \styrsid16534634 Comment Subject Char;}{\s22\ql \li0\ri0\nowidctlpar\wrapdefault\faauto\rin0\lin0\itap0 \rtlch\fcs1 \af40\afs16\alang1025 \ltrch\fcs0 +\fs16\lang1033\langfe1033\loch\f40\hich\af40\dbch\af13\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext22 \slink23 \ssemihidden \styrsid16534634 Balloon Text;}{\*\cs23 \additive \rtlch\fcs1 \af40\afs16 \ltrch\fcs0 \f40\fs16 \sbasedon10 \slink22 \slocked \ssemihidden \styrsid16534634 Balloon Text Char;}{\s24\ql \li0\ri20\sb60\sa60\sl-200\slmult0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin20\lin0\itap0 \rtlch\fcs1 \af0\afs16\alang1025 \ltrch\fcs0 -\fs16\cf1\lang1033\langfe1033\loch\f41\hich\af41\dbch\af13\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext24 \styrsid14971029 CellBodyLeft;}{\*\cs25 \additive \b\f2\cf13 \styrsid14971029 CodeCharacter;}{\*\ts26\tsrowd\trbrdrt\brdrs\brdrw10 \trbrdrl +\fs16\cf1\lang1033\langfe1033\loch\f42\hich\af42\dbch\af13\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext24 \styrsid14971029 CellBodyLeft;}{\*\cs25 \additive \b\f2\cf13 \styrsid14971029 CodeCharacter;}{\*\ts26\tsrowd\trbrdrt\brdrs\brdrw10 \trbrdrl \brdrs\brdrw10 \trbrdrb\brdrs\brdrw10 \trbrdrr\brdrs\brdrw10 \trbrdrh\brdrs\brdrw10 \trbrdrv\brdrs\brdrw10 -\trftsWidthB3\trpaddl108\trpaddr108\trpaddfl3\trpaddft3\trpaddfb3\trpaddfr3\tblind0\tblindtype3\tscellwidthfts0\tsvertalt\tsbrdrt\tsbrdrl\tsbrdrb\tsbrdrr\tsbrdrdgl\tsbrdrdgr\tsbrdrh\tsbrdrv +\trftsWidthB3\trpaddl108\trpaddr108\trpaddfl3\trpaddft3\trpaddfb3\trpaddfr3\tblind0\tblindtype3\tsvertalt\tsbrdrt\tsbrdrl\tsbrdrb\tsbrdrr\tsbrdrdgl\tsbrdrdgr\tsbrdrh\tsbrdrv \ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs22\alang1025 \ltrch\fcs0 \fs22\lang1033\langfe2052\loch\f37\hich\af37\dbch\af13\cgrid\langnp1033\langfenp2052 \sbasedon11 \snext26 \styrsid14971029 -Table Grid;}}{\*\revtbl {Unknown;}{yzeng15;}}{\*\rsidtbl \rsid1063253\rsid1211840\rsid1381256\rsid1839752\rsid2442797\rsid2694053\rsid2974720\rsid4338091\rsid4590013\rsid4999604\rsid5116989\rsid5911148\rsid6164334\rsid6375506\rsid6492146\rsid6561745\rsid6579891\rsid6637302 -\rsid6827362\rsid7278947\rsid7820891\rsid8023663\rsid8600807\rsid8996461\rsid9010967\rsid10121491\rsid10897639\rsid11224689\rsid11427337\rsid12210198\rsid13245303\rsid13716787\rsid14971029\rsid15538292\rsid15612145\rsid16533044\rsid16534634}{\mmathPr -\mmathFont34\mbrkBin0\mbrkBinSub0\msmallFrac0\mdispDef1\mlMargin0\mrMargin0\mdefJc1\mwrapIndent1440\mintLim0\mnaryLim1}{\info{\operator yzeng15}{\creatim\yr2010\mo10\dy6\hr13\min22}{\revtim\yr2011\mo8\dy31\hr14\min13}{\version29}{\edmins158}{\nofpages5} -{\nofwords1165}{\nofchars6672}{\nofcharsws7822}{\vern32771}}{\*\xmlnstbl {\xmlns1 http://schemas.microsoft.com/office/word/2003/wordml}}\paperw12240\paperh15840\margl1440\margr1440\margt1440\margb1440\gutter0\ltrsect -\ftnbj\aenddoc\revisions\trackmoves1\trackformatting1\donotembedsysfont0\relyonvml0\donotembedlingdata1\grfdocevents0\validatexml0\showplaceholdtext0\ignoremixedcontent0\saveinvalidxml0\showxmlerrors0\horzdoc\dghspace120\dgvspace120\dghorigin1701 -\dgvorigin1984\dghshow0\dgvshow3\jcompress\viewkind1\viewscale135\rsidroot1211840 \fet0{\*\wgrffmtfilter 2450}\ilfomacatclnup0\ltrpar \sectd \ltrsect\linex0\sectdefaultcl\sftnbj {\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang {\pntxta \dbch .}} -{\*\pnseclvl2\pnucltr\pnstart1\pnindent720\pnhang {\pntxta \dbch .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang {\pntxta \dbch .}}{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang {\pntxta \dbch )}}{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang -{\pntxtb \dbch (}{\pntxta \dbch )}}{\*\pnseclvl6\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb \dbch (}{\pntxta \dbch )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb \dbch (}{\pntxta \dbch )}}{\*\pnseclvl8\pnlcltr\pnstart1\pnindent720\pnhang -{\pntxtb \dbch (}{\pntxta \dbch )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb \dbch (}{\pntxta \dbch )}}\pard\plain \ltrpar\s2\ql \li-1440\ri0\sb400\sa60\sl-340\slmult0\keep\keepn\nowidctlpar -\tx360\wrapdefault\faauto\outlinelevel1\rin0\lin-1440\itap0 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af41\hich\af41\dbch\af13\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \ab\af41\afs28 \ltrch\fcs0 -\b\fs28\cf17\insrsid11224689 \hich\af41\dbch\af13\loch\f41 Name -\par }\pard\plain \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af41\hich\af41\dbch\af13\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af41\afs18 -\ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 Build.exe \hich\f41 \endash \loch\f41 }{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid1063253 \hich\af41\dbch\af13\loch\f41 is }{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 -\fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 the master command that provides }{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid1063253 \hich\af41\dbch\af13\loch\f41 developers}{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 -\fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 with a single command for selecting various options of a build +Table Grid;}}{\*\revtbl {Unknown;}{Zhu, Yonghong;}{yzeng15;}}{\*\rsidtbl \rsid1063253\rsid1211840\rsid1381256\rsid1839752\rsid2442797\rsid2694053\rsid2974720\rsid4338091\rsid4590013\rsid4999604\rsid5116989\rsid5911148\rsid6164334\rsid6375506\rsid6492146\rsid6561745\rsid6579891\rsid6637302 +\rsid6827362\rsid7278947\rsid7479872\rsid7820891\rsid8023663\rsid8081890\rsid8600807\rsid8996461\rsid9010967\rsid10121491\rsid10756011\rsid10897639\rsid11224689\rsid11413092\rsid11427337\rsid12210198\rsid13245303\rsid13716787\rsid14971029\rsid15538292 +\rsid15612145\rsid16533044\rsid16534634}{\mmathPr\mmathFont34\mbrkBin0\mbrkBinSub0\msmallFrac0\mdispDef1\mlMargin0\mrMargin0\mdefJc1\mwrapIndent1440\mintLim0\mnaryLim1}{\info{\operator Zhu, Yonghong}{\creatim\yr2010\mo10\dy6\hr13\min22} +{\revtim\yr2015\mo12\dy2\hr15\min37}{\version33}{\edmins160}{\nofpages5}{\nofwords1253}{\nofchars7144}{\nofcharsws8381}{\vern57435}}{\*\xmlnstbl {\xmlns1 http://schemas.microsoft.com/office/word/2003/wordml}} +\paperw12240\paperh15840\margl1440\margr1440\margt1440\margb1440\gutter0\ltrsect +\widowctrl\ftnbj\aenddoc\revisions\trackmoves0\trackformatting1\donotembedsysfont0\relyonvml0\donotembedlingdata1\grfdocevents0\validatexml0\showplaceholdtext0\ignoremixedcontent0\saveinvalidxml0\showxmlerrors0\horzdoc\dghspace120\dgvspace120 +\dghorigin1701\dgvorigin1984\dghshow0\dgvshow3\jcompress\viewkind1\viewscale200\rsidroot1211840 \fet0{\*\wgrffmtfilter 2450}\ilfomacatclnup0\ltrpar \sectd \ltrsect\linex0\sectdefaultcl\sftnbj {\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang +{\pntxta \hich .}}{\*\pnseclvl2\pnucltr\pnstart1\pnindent720\pnhang {\pntxta \hich .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang {\pntxta \hich .}}{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang {\pntxta \hich )}}{\*\pnseclvl5 +\pndec\pnstart1\pnindent720\pnhang {\pntxtb \hich (}{\pntxta \hich )}}{\*\pnseclvl6\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb \hich (}{\pntxta \hich )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb \hich (}{\pntxta \hich )}}{\*\pnseclvl8 +\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb \hich (}{\pntxta \hich )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb \hich (}{\pntxta \hich )}}\pard\plain \ltrpar\s2\ql \li-1440\ri0\sb400\sa60\sl-340\slmult0\keep\keepn\nowidctlpar +\tx360\wrapdefault\faauto\outlinelevel1\rin0\lin-1440\itap0 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af42\hich\af42\dbch\af13\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \ab\af42\afs28 \ltrch\fcs0 +\b\fs28\cf17\insrsid11224689 \hich\af42\dbch\af13\loch\f42 Name +\par }\pard\plain \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af42\hich\af42\dbch\af13\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af42\afs18 +\ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 Build.exe \hich\f42 \endash \loch\f42 }{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid1063253 \hich\af42\dbch\af13\loch\f42 is }{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 +\fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 the master command that provides }{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid1063253 \hich\af42\dbch\af13\loch\f42 developers}{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 +\fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 with a single command for selecting various options of a build \par }\pard\plain \ltrpar\s2\ql \li-1440\ri0\sb400\sa60\sl-340\slmult0\keep\keepn\nowidctlpar\tx360\wrapdefault\faauto\outlinelevel1\rin0\lin-1440\itap0 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 -\fs24\lang1033\langfe1033\loch\af41\hich\af41\dbch\af13\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \ab\af41\afs28 \ltrch\fcs0 \b\fs28\cf17\insrsid11224689 \hich\af41\dbch\af13\loch\f41 Synopsis -\par }\pard\plain \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af41\hich\af41\dbch\af13\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \ab\af41\afs18 -\ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 Build.exe }{\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\lang1033\langfe2052\langfenp2052\insrsid2442797 \hich\af41\dbch\af13\loch\f41 -[-v | -q | -d] [-a ] [-p ] [-m ] [-b ] [-t ] [-f FdfFile] [-r ] [-i ] }{\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\lang1033\langfe2052\langfenp2052\insrsid15612145 -\hich\af41\dbch\af13\loch\f41 [-C ] }{\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\lang1033\langfe2052\langfenp2052\insrsid2442797 \hich\af41\dbch\af13\loch\f41 -[-n ThreadNum] [-x ] [-u] [-e] [-w] [-j ] [-s] [-D ] [-y ]\hich\af41\dbch\af13\loch\f41 [-Y ] [-F ] }{\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 -[}{\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\lang1033\langfe2052\langfenp2052\insrsid2442797 \hich\af41\dbch\af13\loch\f41 All | GenC | GenMake | Fds | Libraries | Modules | Clean | CleanAll | CleanLib | run}{\rtlch\fcs1 \ab\af41\afs18 -\ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 ]}{\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\lang1033\langfe2052\langfenp2052\insrsid11224689 -\par }{\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid13716787 \hich\af41\dbch\af13\loch\f41 Build.exe}{\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\lang1033\langfe2052\langfenp2052\insrsid13716787 \hich\af41\dbch\af13\loch\f41 \hich\f41 -\endash \loch\f41 h -\par }{\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid13716787 \hich\af41\dbch\af13\loch\f41 Build.exe}{\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\lang1033\langfe2052\langfenp2052\insrsid13716787 \hich\af41\dbch\af13\loch\f41 --version}{ -\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\lang1033\langfe2052\langfenp2052\insrsid13716787\charrsid13716787 +\fs24\lang1033\langfe1033\loch\af42\hich\af42\dbch\af13\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \ab\af42\afs28 \ltrch\fcs0 \b\fs28\cf17\insrsid11224689 \hich\af42\dbch\af13\loch\f42 Synopsis +\par }\pard\plain \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af42\hich\af42\dbch\af13\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \ab\af42\afs18 +\ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 Build.exe }{\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\lang1033\langfe2052\langfenp2052\insrsid2442797 \hich\af42\dbch\af13\loch\f42 +[-v | -q | -d] [-a ] [-p ] [-m ] [-b ] [-t ] [-f FdfFile] [-r ] [-i ] }{\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\lang1033\langfe2052\langfenp2052\insrsid15612145 +\hich\af42\dbch\af13\loch\f42 [-C ] }{\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\lang1033\langfe2052\langfenp2052\insrsid2442797 \hich\af42\dbch\af13\loch\f42 +[-n ThreadNum] [-x ] [-u] [-e] [-w] [-j ] [-s] [-D ] [-y ]\hich\af42\dbch\af13\loch\f42 [-Y ] [-F ]}{\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 +\b\fs18\cf1\revised\lang1033\langfe2052\revauth1\revdttm1731990500\langfenp2052\insrsid11413092 \hich\af42\dbch\af13\loch\f42 }{\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 +\b\fs18\cf1\revised\lang1033\langfe2052\revauth1\revdttm1731990499\langfenp2052\insrsid10756011 \hich\af42\dbch\af13\loch\f42 [}{\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 +\b\fs18\cf1\revised\lang1033\langfe2052\revauth1\revdttm1731990499\langfenp2052\insrsid10756011\charrsid11689747 \hich\af42\dbch\af13\loch\f42 --ignore-sources}{\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 +\b\fs18\cf1\revised\lang1033\langfe2052\revauth1\revdttm1731990499\langfenp2052\insrsid10756011 \hich\af42\dbch\af13\loch\f42 ] \hich\af42\dbch\af13\loch\f42 [}{\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 +\b\fs18\cf1\revised\lang1033\langfe2052\revauth1\revdttm1731990499\langfenp2052\insrsid10756011\charrsid10894100 \hich\af42\dbch\af13\loch\f42 --check-usage}{\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 +\b\fs18\cf1\revised\lang1033\langfe2052\revauth1\revdttm1731990499\langfenp2052\insrsid10756011 \hich\af42\dbch\af13\loch\f42 ]}{\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 +\b\deleted\fs18\cf1\lang1033\langfe2052\revauthdel1\revdttmdel1731990499\langfenp2052\insrsid2442797\delrsid10756011 \hich\af42\dbch\af13\loch\f42 }{\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 [}{ +\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\lang1033\langfe2052\langfenp2052\insrsid2442797 \hich\af42\dbch\af13\loch\f42 All | GenC | GenMake | Fds | Libraries | Modules | Clean | CleanAll | CleanLib | run}{\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 +\b\fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 ]}{\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\lang1033\langfe2052\langfenp2052\insrsid11224689 +\par }{\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid13716787 \hich\af42\dbch\af13\loch\f42 Build.exe}{\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\lang1033\langfe2052\langfenp2052\insrsid13716787 \hich\af42\dbch\af13\loch\f42 \hich\f42 +\endash \loch\f42 h +\par }{\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid13716787 \hich\af42\dbch\af13\loch\f42 Build.exe}{\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\lang1033\langfe2052\langfenp2052\insrsid13716787 \hich\af42\dbch\af13\loch\f42 --version}{ +\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\lang1033\langfe2052\langfenp2052\insrsid13716787\charrsid13716787 \par }\pard\plain \ltrpar\s2\ql \li-1440\ri0\sb400\sa60\sl-340\slmult0\keep\keepn\nowidctlpar\wrapdefault\faauto\outlinelevel1\rin0\lin-1440\itap0 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 -\fs24\lang1033\langfe1033\loch\af41\hich\af41\dbch\af13\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \ab\af41\afs28 \ltrch\fcs0 \b\fs28\cf17\insrsid11224689 \hich\af41\dbch\af13\loch\f41 Description -\par }\pard\plain \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af41\hich\af41\dbch\af13\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af41\afs18 -\ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 Build.exe is the master command line (CLI) tool that provides a single command for selecting various }{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid9010967 -\hich\af41\dbch\af13\loch\f41 build options}{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 . In general, it checks the environment variables, gets the user\hich\f41 \rquote \loch\f41 -s configuration from either the CLI or target.txt, parses the dsc, dec, inf, \hich\af41\dbch\af13\loch\f41 +\fs24\lang1033\langfe1033\loch\af42\hich\af42\dbch\af13\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \ab\af42\afs28 \ltrch\fcs0 \b\fs28\cf17\insrsid11224689 \hich\af42\dbch\af13\loch\f42 Description +\par }\pard\plain \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af42\hich\af42\dbch\af13\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af42\afs18 +\ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 Build.exe is the master command line (CLI) tool that provides a single command for selecting various }{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid9010967 +\hich\af42\dbch\af13\loch\f42 build options}{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 . In general, it checks the environment variables, gets the user\hich\f42 \rquote \loch\f42 +s configuration from either the CLI or target.txt, parses the dsc, dec, inf, \hich\af42\dbch\af13\loch\f42 target.txt, tools_def.txt, generates .C, .H files and the Makefiles for one or more modules and/or the active platform, calls a make (NMake or make) program to process these Makefiles, then optionally calls GenFds to generate an fd file. -\par \hich\af41\dbch\af13\loch\f41 The build tool sup\hich\af41\dbch\af13\loch\f41 ports two kinds of path specifications on command line - an absolutely path or a relative (to the WORKSPACE environment variable) path \hich\f41 \endash \loch\f41 +\par \hich\af42\dbch\af13\loch\f42 The build tool sup\hich\af42\dbch\af13\loch\f42 ports two kinds of path specifications on command line - an absolutely path or a relative (to the WORKSPACE environment variable) path \hich\f42 \endash \loch\f42 in command line. \par }\pard\plain \ltrpar\s2\ql \li-1440\ri0\sb400\sa60\sl-340\slmult0\keep\keepn\nowidctlpar\tx360\tx1440\wrapdefault\faauto\outlinelevel1\rin0\lin-1440\itap0 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 -\fs24\lang1033\langfe1033\loch\af41\hich\af41\dbch\af13\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \ab\af41\afs28 \ltrch\fcs0 \b\fs28\cf17\insrsid11224689 \hich\af41\dbch\af13\loch\f41 Options -\par }\pard\plain \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af41\hich\af41\dbch\af13\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af41\afs18 -\ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 There are no required options. }{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\lang1033\langfe2052\langfenp2052\insrsid11427337 \hich\af41\dbch\af13\loch\f41 -If no options are specified, it uses options specified in targe\hich\af41\dbch\af13\loch\f41 t.txt.}{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\lang1033\langfe2052\langfenp2052\insrsid11224689 -\par }{\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 -a, --arch -\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 ARCH is one of }{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid2974720 -\hich\af41\dbch\af13\loch\f41 a }{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 list: IA32, X64, IPF or EBC, which overrides }{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid2974720 -\hich\af41\dbch\af13\loch\f41 the }{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 target.txt's TARGET_ARCH definition. To specify }{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid1063253 -\hich\af41\dbch\af13\loch\f41 another }{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 ARCH, repeat this option. -\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 -p, --platform PlatformName.dsc -\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 Build}{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid6164334 -\hich\af41\dbch\af13\loch\f41 s}{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 the platform specified by the DSC file}{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid9010967 -\hich\af41\dbch\af13\loch\f41 . }{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid1063253 \hich\af41\dbch\af13\loch\f41 The}{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 name argument, overrides }{ -\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid1063253 \hich\af41\dbch\af13\loch\f41 the }{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 target.txt's ACTIVE_PLATFORM definition. -\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 -m, --module ModuleName.inf -\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 Build}{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid6164334 -\hich\af41\dbch\af13\loch\f41 s}{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 the module specified by the INF file name argument. -\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 -b, --buildtarget -\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 TARGET is one of}{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 -\fs18\cf1\insrsid1063253 \hich\af41\dbch\af13\loch\f41 a}{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 list: DEBUG, RELEASE,}{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 -\fs18\cf1\revised\lang1033\langfe2052\revauth1\revdttm1727593357\langfenp2052\insrsid15538292 \hich\af41\dbch\af13\loch\f41 NOOPT}{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 -\fs18\cf1\revised\lang1033\langfe2052\revauth1\revdttm1727593357\langfenp2052\insrsid15538292 \loch\af41\hich\af41\dbch\f13 \'a3\'ac}{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 which overrides }{ -\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid1063253 \hich\af41\dbch\af13\loch\f41 the }{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 target.txt\hich\af41\dbch\af13\loch\f41 -'s TARGET definition. To specify }{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid1063253 \hich\af41\dbch\af13\loch\f41 another }{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 -TARGET, please repeat this option. -\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 -t, --tagname Tagname -\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 Us}{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid1063253 -\hich\af41\dbch\af13\loch\f41 e}{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid6164334 \hich\af41\dbch\af13\loch\f41 s}{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 - the Tool Chain Tagname to build the platform}{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid1063253 .}{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid9010967 \hich\af41\dbch\af13\loch\f41 }{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 -\fs18\cf1\insrsid1063253 \hich\af41\dbch\af13\loch\f41 It }{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 overrides target.txt's TOOL_CHAIN_TAG definition. -\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 -f --fdf Filename.fdf -\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 The name of the FDF file }{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 -\fs18\cf1\insrsid6164334 \hich\af41\dbch\af13\loch\f41 to use to}{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 override the setting in the DSC file. -\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 -r --rom-image ROM_IMAGE_NAME -\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 +\fs24\lang1033\langfe1033\loch\af42\hich\af42\dbch\af13\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \ab\af42\afs28 \ltrch\fcs0 \b\fs28\cf17\insrsid11224689 \hich\af42\dbch\af13\loch\f42 Options +\par }\pard\plain \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af42\hich\af42\dbch\af13\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af42\afs18 +\ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 There are no required options. }{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\lang1033\langfe2052\langfenp2052\insrsid11427337 \hich\af42\dbch\af13\loch\f42 +If no options are specified, it uses options specified in targe\hich\af42\dbch\af13\loch\f42 t.txt.}{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\lang1033\langfe2052\langfenp2052\insrsid11224689 +\par }{\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 -a, --arch +\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 ARCH is one of }{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid2974720 +\hich\af42\dbch\af13\loch\f42 a }{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 list: IA32, X64, IPF or EBC, which overrides }{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid2974720 +\hich\af42\dbch\af13\loch\f42 the }{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 target.txt's TARGET_ARCH definition. To specify }{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid1063253 +\hich\af42\dbch\af13\loch\f42 another }{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 ARCH, repeat this option. +\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 -p, --platform PlatformName.dsc +\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 Build}{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid6164334 +\hich\af42\dbch\af13\loch\f42 s}{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 the platform specified by the DSC file}{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid9010967 +\hich\af42\dbch\af13\loch\f42 . }{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid1063253 \hich\af42\dbch\af13\loch\f42 The}{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 name argument, overrides }{ +\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid1063253 \hich\af42\dbch\af13\loch\f42 the }{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 target.txt's ACTIVE_PLATFORM definition. +\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 -m, --module ModuleName.inf +\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 Build}{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid6164334 +\hich\af42\dbch\af13\loch\f42 s}{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 the module specified by the INF file name argument. +\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 -b, --buildtarget +\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 TARGET is one of}{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 +\fs18\cf1\insrsid1063253 \hich\af42\dbch\af13\loch\f42 a}{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 list: DEBUG, RELEASE,}{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 +\fs18\cf1\revised\lang1033\langfe2052\revauth2\revdttm1727593357\langfenp2052\insrsid15538292 \hich\af42\dbch\af13\loch\f42 NOOPT}{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 +\fs18\cf1\revised\lang1033\langfe2052\revauth2\revdttm1727593357\langfenp2052\insrsid15538292 \loch\af42\hich\af42\dbch\f13 \u-244\'a3\'ac}{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 which overrides }{ +\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid1063253 \hich\af42\dbch\af13\loch\f42 the }{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 target.txt's TARGET definition. To specify }{\rtlch\fcs1 +\af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid1063253 \hich\af42\dbch\af13\loch\f42 another }{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 TARGET, please repeat this option. +\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 -t, --tagname Tagname +\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 Us}{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid1063253 +\hich\af42\dbch\af13\loch\f42 e}{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid6164334 \hich\af42\dbch\af13\loch\f42 s}{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 + the Tool Chain Tagname to build the platform}{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid1063253 .}{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid9010967 \hich\af42\dbch\af13\loch\f42 }{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 +\fs18\cf1\insrsid1063253 \hich\af42\dbch\af13\loch\f42 It }{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 overrides target.txt's TOOL_CHAIN_TAG definition. +\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 -f --fdf Filename.fdf +\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 The name of the FDF file }{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 +\fs18\cf1\insrsid6164334 \hich\af42\dbch\af13\loch\f42 to use to}{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 override the setting in the DSC file. +\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 -r --rom-image ROM_IMAGE_NAME +\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 The name of FD to be generated. The name must be from [FD] section in FDF file. -\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 -i --fv-image FV_IMAGE_NAME -\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 The name of FV to be generated. The name must be from [FV] section in -\hich\af41\dbch\af13\loch\f41 FDF file.}{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\lang1033\langfe2052\langfenp2052\insrsid11224689 -\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0\pararsid10121491 {\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid10121491 -}{\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 -\b\fs18\cf1\lang1033\langfe2052\langfenp2052\insrsid10121491 \hich\af41\dbch\af13\loch\f41 C}{\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid10121491 \hich\af41\dbch\af13\loch\f41 --}{\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 -\b\fs18\cf1\insrsid6637302\charrsid6637302 \hich\af41\dbch\af13\loch\f41 capsule-image}{\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\lang1033\langfe2052\langfenp2052\insrsid10121491 \hich\af41\dbch\af13\loch\f41 CAPSULE}{\rtlch\fcs1 \ab\af41\afs18 -\ltrch\fcs0 \b\fs18\cf1\insrsid10121491 \hich\af41\dbch\af13\loch\f41 _IMAGE_NAME -\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0\pararsid6375506 {\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid10121491\charrsid6375506 \hich\af41\dbch\af13\loch\f41 +\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 -i --fv-image FV_IMAGE_NAME +\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 The name of FV to be generated. The name must\hich\af42\dbch\af13\loch\f42 + be from [FV] section in FDF file.}{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\lang1033\langfe2052\langfenp2052\insrsid11224689 +\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0\pararsid10121491 {\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid10121491 -}{\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 +\b\fs18\cf1\lang1033\langfe2052\langfenp2052\insrsid10121491 \hich\af42\dbch\af13\loch\f42 C}{\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid10121491 \hich\af42\dbch\af13\loch\f42 --}{\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 +\b\fs18\cf1\insrsid6637302\charrsid6637302 \hich\af42\dbch\af13\loch\f42 capsule-image}{\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\lang1033\langfe2052\langfenp2052\insrsid10121491 \hich\af42\dbch\af13\loch\f42 CAPSULE}{\rtlch\fcs1 \ab\af42\afs18 +\ltrch\fcs0 \b\fs18\cf1\insrsid10121491 \hich\af42\dbch\af13\loch\f42 _IMAGE_NAME +\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0\pararsid6375506 {\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid10121491\charrsid6375506 \hich\af42\dbch\af13\loch\f42 The name of Capsule to be generated. The name must be from [Capsule] section in FDF file. -\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\pnrdate1190691435\pnrnot1\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 -n NUM -\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 Build}{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid6164334 -\hich\af41\dbch\af13\loch\f41 s}{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 the platform using multi-threaded compiler. The value overrides }{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid7820891 -\hich\af41\dbch\af13\loch\f41 the }{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 target.txt's MULTIPLE_THREAD and MAX_CONCURRENT_THREAD_NUMBER. }{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid7820891 -\hich\af41\dbch\af13\loch\f41 Using l}{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 ess than 2 will disable multi-thread builds. -\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 -x --sku-id SKU_ID}{\rtlch\fcs1 \ab\af0\afs18 \ltrch\fcs0 +\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\pnrdate1190691435\pnrnot1\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 -n NUM +\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 Build}{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid6164334 +\hich\af42\dbch\af13\loch\f42 s}{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 the platform using multi-threaded compiler. The value overrides }{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid7820891 +\hich\af42\dbch\af13\loch\f42 the }{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 target.txt's MULTIPLE_THREAD and MAX_CONCURRENT_THREAD_NUMBER. }{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid7820891 +\hich\af42\dbch\af13\loch\f42 Using l}{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 ess than 2 will disable multi-thread builds. +\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 -x --sku-id SKU_ID}{\rtlch\fcs1 \ab\af0\afs18 \ltrch\fcs0 \b\f0\fs18\cf1\insrsid11224689 -\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid7820891 \hich\af41\dbch\af13\loch\f41 Use}{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 -\hich\af41\dbch\af13\loch\f41 SKU ID to build the platform}{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid7820891 \hich\af41\dbch\af13\loch\f41 and override the}{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 -\hich\af41\dbch\af13\loch\f41 SKUID_IDENTIFIER in DSC file. -\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 -u --skip-autogen}{\rtlch\fcs1 \ab\af0\afs18 \ltrch\fcs0 +\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid7820891 \hich\af42\dbch\af13\loch\f42 Use}{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 +\hich\af42\dbch\af13\loch\f42 SKU ID to build the platform}{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid7820891 \hich\af42\dbch\af13\loch\f42 and override the}{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 +\hich\af42\dbch\af13\loch\f42 SKUID_IDENTIFIER in DSC file. +\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 -u --skip-autogen}{\rtlch\fcs1 \ab\af0\afs18 \ltrch\fcs0 \b\f0\fs18\cf1\insrsid11224689 -\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid7820891 \hich\af41\dbch\af13\loch\f41 Use to s}{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 -\hich\af41\dbch\af13\loch\f41 kip }{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid7820891 \hich\af41\dbch\af13\loch\f41 the }{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 AutoGen -\hich\af41\dbch\af13\loch\f41 step. Note the build may fail if there\hich\f41 \rquote \loch\f41 s no AutoGen-ed files before. -\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 -e --re-parse}{\rtlch\fcs1 \ab\af0\afs18 \ltrch\fcs0 +\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid7820891 \hich\af42\dbch\af13\loch\f42 Use to s}{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 +\hich\af42\dbch\af13\loch\f42 kip }{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid7820891 \hich\af42\dbch\af13\loch\f42 the }{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 AutoGen +\hich\af42\dbch\af13\loch\f42 step. Note the build may fail if there\hich\f42 \rquote \loch\f42 s no AutoGen-ed files before. +\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 -e --re-parse}{\rtlch\fcs1 \ab\af0\afs18 \ltrch\fcs0 \b\f0\fs18\cf1\insrsid11224689 -\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid7820891 \hich\af41\dbch\af13\loch\f41 Use to r}{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 -\hich\af41\dbch\af13\loch\f41 e-parse all meta-data files. Use this option if you encounter }{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid7820891 \hich\af41\dbch\af13\loch\f41 an }{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 -\hich\af41\dbch\af13\loch\f41 inconsistency issue.}{\rtlch\fcs1 \af0\afs18 \ltrch\fcs0 \f0\fs18\cf1\insrsid11224689 -\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 -w --warning-as-error}{\rtlch\fcs1 \ab\af0\afs18 \ltrch\fcs0 +\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid7820891 \hich\af42\dbch\af13\loch\f42 Use to r}{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 +\hich\af42\dbch\af13\loch\f42 e-parse all meta-data files. Use this option if you encounter }{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid7820891 \hich\af42\dbch\af13\loch\f42 an }{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 +\hich\af42\dbch\af13\loch\f42 inconsistency issue.}{\rtlch\fcs1 \af0\afs18 \ltrch\fcs0 \f0\fs18\cf1\insrsid11224689 +\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 -w --warning-as-error}{\rtlch\fcs1 \ab\af0\afs18 \ltrch\fcs0 \b\f0\fs18\cf1\insrsid11224689 -\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid7820891 \hich\af41\dbch\af13\loch\f41 Use to t}{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 -\hich\af41\dbch\af13\loch\f41 reat warning in }{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid7820891 \hich\af41\dbch\af13\loch\f41 the }{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 tool as }{ -\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid7820891 \hich\af41\dbch\af13\loch\f41 an }{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 error. -\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 -j --log LOGFILE}{\rtlch\fcs1 \ab\af0\afs18 \ltrch\fcs0 +\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid7820891 \hich\af42\dbch\af13\loch\f42 Use to t}{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 +\hich\af42\dbch\af13\loch\f42 reat warning in }{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid7820891 \hich\af42\dbch\af13\loch\f42 the }{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 tool as }{ +\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid7820891 \hich\af42\dbch\af13\loch\f42 an }{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 error. +\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 -j --log LOGFILE}{\rtlch\fcs1 \ab\af0\afs18 \ltrch\fcs0 \b\f0\fs18\cf1\insrsid11224689 -\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid7820891 \hich\af41\dbch\af13\loch\f41 Use to p}{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 -\hich\af41\dbch\af13\loch\f41 ut screen output in specified file. -\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 -s \hich\f41 \endash \loch\f41 silent -\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid2974720 \hich\af41\dbch\af13\loch\f41 Enable }{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 -\loch\af41\dbch\af13\hich\f41 \'93\loch\f41 \hich\f41 make\'94\loch\f41 \hich\f41 tool to run \'93\loch\f41 \hich\f41 silently\'94\loch\f41 . Internally, a \hich\f41 \lquote \loch\f41 -s\hich\f41 \rquote \loch\f41 \hich\f41 switch will be passed to \'93 -\loch\f41 \hich\f41 make\'94\loch\f41 tool. Don\hich\f41 \rquote \loch\f41 \hich\f41 t use this option if your \'93\loch\f41 \hich\f41 make\'94\loch\f41 tool doesn\hich\f41 \rquote \loch\f41 t support \hich\f41 \lquote \loch\f41 -s\hich\f41 \rquote -\loch\f41 \hich\f41 . Instead, if your \'93\loch\f41 \hich\f41 make\'94\loch\f41 \hich\af41\dbch\af13\loch\f41 tool uses other option}{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid2974720 \hich\af41\dbch\af13\loch\f41 s}{\rtlch\fcs1 \af41\afs18 -\ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 you could add it to the XX_XX_XX_MAKE_FLAGS in tools_def.txt. -\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 -d, --debug [#] -\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 Enable debug messages at specified level. It is used by Tool itself. -\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 -q, --quiet -\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 Disable all messages except FATAL ERRORS. -\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 -v, --verbose -\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid2974720 \hich\af41\dbch\af13\loch\f41 Enable}{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 -\hich\af41\dbch\af13\loch\f41 verbose ou\hich\af41\dbch\af13\loch\f41 tput with informational messages printed. -\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 -D, --define MACROS -\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 Macro: "Name [= Value]". -\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 -y, --report-file REPORTFILE}{\rtlch\fcs1 \ab\af0\afs18 \ltrch\fcs0 +\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid7820891 \hich\af42\dbch\af13\loch\f42 Use to p}{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 +\hich\af42\dbch\af13\loch\f42 ut screen output in specified file. +\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 -s \hich\f42 \endash \loch\f42 silent +\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid2974720 \hich\af42\dbch\af13\loch\f42 Enable }{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 +\loch\af42\dbch\af13\hich\f42 \'93\loch\f42 \hich\f42 make\'94\loch\f42 \hich\f42 tool to run \'93\loch\f42 \hich\f42 silently\'94\loch\f42 . Internally, a \hich\f42 \lquote \loch\f42 -s\hich\f42 \rquote \loch\f42 \hich\f42 switch will be passed to \'93 +\loch\f42 \hich\f42 make\'94\loch\f42 tool. Don\hich\f42 \rquote \loch\f42 \hich\f42 t use this option if your \'93\loch\f42 \hich\f42 make\'94\loch\f42 tool doesn\hich\f42 \rquote \loch\f42 t support \hich\f42 \lquote \loch\f42 -s\hich\f42 \rquote +\loch\f42 \hich\f42 . Instead, if your \'93\loch\f42 \hich\f42 make\'94\loch\f42 \hich\af42\dbch\af13\loch\f42 tool uses other option}{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid2974720 \hich\af42\dbch\af13\loch\f42 s}{\rtlch\fcs1 \af42\afs18 +\ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 you could add it to the XX_XX_XX_MAKE_FLAGS in tools_def.txt. +\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 -d, --debug [#] +\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 Enable debug messages at specified level. It is used by Tool itself. +\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 -q, --quiet +\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 Disable all messages except FATAL ERRORS. +\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 -v, --verbose +\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid2974720 \hich\af42\dbch\af13\loch\f42 Enable}{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 +\hich\af42\dbch\af13\loch\f42 verbose ou\hich\af42\dbch\af13\loch\f42 tput with informational messages printed. +\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 -D, --define MACROS +\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 Macro: "Name [= Value]". +\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 -y, --report-file REPORTFILE}{\rtlch\fcs1 \ab\af0\afs18 \ltrch\fcs0 \b\f0\fs18\cf1\insrsid11224689 -\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 Create/overwrite the report to the specified filename. -\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 -Y, --report-type REPORTTYPE -\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 Flags that control the type of build report to generate. -\hich\af41\dbch\af13\loch\f41 +\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 Create/overwrite the report to the specified filename. +\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 -Y, --report-type REPORTTYPE +\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 Flags that control the type of build report to generate. +\hich\af42\dbch\af13\loch\f42 Must be one of: [PCD, LIBRARY, FLASH, DEPEX, BUILD_FLAGS, FIXED_ADDRESS, EXECUTION_ORDER]. To specify more than one flag, repeat this option on the command line and the default flag set is [PCD, LIBRARY, FLASH, DEPEX, BUILD_FLAGS, FIXED_ADDRESS]}{ \rtlch\fcs1 \af0\afs18 \ltrch\fcs0 \f0\fs18\cf1\insrsid11224689 -\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 -F FLAG\hich\af41\dbch\af13\loch\f41 , --flag=FLAG}{\rtlch\fcs1 +\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 -F FLAG\hich\af42\dbch\af13\loch\f42 , --flag=FLAG}{\rtlch\fcs1 \ab\af0\afs18 \ltrch\fcs0 \b\f0\fs18\cf1\insrsid11224689 -\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 +\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 Specify the specific option to parse EDK UNI file. Must be one of: [-c, -s]. -c is for EDK framework UNI file, and -s is for EDK UEFI UNI file. This option can also be specified by setting *_*_*_BUILD_FLAGS in [BuildOptions] section of platfo -\hich\af41\dbch\af13\loch\f41 rm DSC. If they are both specified, this value will override the setting in [BuildOptions] section of platform DSC. -\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 --version -\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 Show program copyright and version number then exit. -\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 -h, --help -\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 Print the copyright, version and usage of this program then exit. +\hich\af42\dbch\af13\loch\f42 rm DSC. If they are both specified, this value will override the setting in [BuildOptions] section of platform DSC. +\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0\pararsid10756011 {\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\revised\lang1033\langfe2052\revauth1\revdttm1731990499\langfenp2052\insrsid10756011\charrsid10894100 +\hich\af42\dbch\af13\loch\f42 --check-usage}{\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\revised\lang1033\langfe2052\revauth1\revdttm1731990499\langfenp2052\insrsid10756011 +\par \hich\af42\dbch\af13\loch\f42 }{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\revised\revauth1\revdttm1731990499\insrsid10756011\charrsid10894100 \hich\af42\dbch\af13\loch\f42 Check usage content of entries listed in INF file.}{\rtlch\fcs1 +\af42\afs18 \ltrch\fcs0 \fs18\cf1\revised\lang1033\langfe2052\revauth1\revdttm1731990499\langfenp2052\insrsid10756011\charrsid12155946 +\par }{\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\revised\revauth1\revdttm1731990499\insrsid10756011\charrsid2178333 \hich\af42\dbch\af13\loch\f42 --ignore-sources +\par }\pard \ltrpar\ql \li0\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin0\itap0\pararsid10756011 {\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\revised\revauth1\revdttm1731990499\insrsid10756011 \tab }{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 +\fs18\cf1\revised\revauth1\revdttm1731990499\insrsid10756011\charrsid11689747 \hich\af42\dbch\af13\loch\f42 Focus to a binary build and ignore all source files}{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 +\fs18\cf1\revised\revauth1\revdttm1731990499\insrsid10756011 . +\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0\pararsid10756011 {\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\revised\revauth1\revdttm1731990499\insrsid10756011\charrsid11689747 \hich\af42\dbch\af13\loch\f42 +If an INF file listed in the DSC or FDF file contains a [Sources] section and it also contains a [Binaries] section, do not generate a Makefile, ignoring the sources, and just use the binaries listed in the [Binaries] section +\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\prauth1\prdate1731990500\rin0\lin720\itap0\pararsid10756011 {\*\oldpprops \pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0\pararsid10756011 }{\rtlch\fcs1 +\af42\afs18 \ltrch\fcs0 \fs18\cf1\revised\revauth1\revdttm1731990499\insrsid10756011\charrsid11689747 \hich\af42\dbch\af13\loch\f42 If an INF file listed in the D\hich\af42\dbch\af13\loch\f42 +SC or FDF file contains a [Sources] section and it does not contain a [Binaries] section, break the build with an error message}{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\revised\revauth1\revdttm1731990499\insrsid10756011 .}{\rtlch\fcs1 \af42\afs18 +\ltrch\fcs0 \fs18\cf1\revised\revauth1\revdttm1731990499\crauth1\crdate1731990500\insrsid10756011\charrsid10756011 {\*\oldcprops \b\crauth1\crdate1731990500\insrsid10756011\charrsid10756011 } +\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 --version +\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 Show program copyright and version number then exit. +\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 -h, --help +\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 Print the copyright, version and usage of this program then exit. \par }\pard\plain \ltrpar\s2\ql \li-1440\ri0\sb400\sa60\sl-340\slmult0\keep\keepn\nowidctlpar\tx360\tx1440\wrapdefault\faauto\outlinelevel1\rin0\lin-1440\itap0 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 -\fs24\lang1033\langfe1033\loch\af41\hich\af41\dbch\af13\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \ab\af41\afs28 \ltrch\fcs0 \b\fs28\cf17\insrsid11224689 {\*\bkmkstart _Ref299349210}\hich\af41\dbch\af13\loch\f41 Target{\*\bkmkend _Ref299349210} -\par }\pard\plain \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af41\hich\af41\dbch\af13\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af41\afs18 -\ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 If no target is given, then default target is ALL. -\par }{\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 ALL}{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 +\fs24\lang1033\langfe1033\loch\af42\hich\af42\dbch\af13\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \ab\af42\afs28 \ltrch\fcs0 \b\fs28\cf17\insrsid11224689 {\*\bkmkstart _Ref299349210}\hich\af42\dbch\af13\loch\f42 Target{\*\bkmkend _Ref299349210} +\par }\pard\plain \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af42\hich\af42\dbch\af13\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af42\afs18 +\ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 If no target is given, then default target is ALL. +\par }{\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 ALL}{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 Build everything for either the platform or module. -\par }{\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 GenC}{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 +\par }{\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 GenC}{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 Auto-generate all C files for either the platform or module. -\par }{\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 GenMake}{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 Generate the Makefiles \hich\f41 \endash -\loch\f41 if auto-generated files are missing, -\par }\pard \ltrpar\ql \li360\ri0\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 +\par }{\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 GenMake}{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 Generate the Makefiles \hich\f42 \endash +\loch\f42 if auto-generated files are missing, +\par }\pard \ltrpar\ql \li360\ri0\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 then auto-generate all C files first for either the platform or module. -\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 Fds}{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 -\hich\af41\dbch\af13\loch\f41 Create the FD Image files. -\par }{\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 Libraries}{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 Build all EDK Libraries and EDK II Libra -\hich\af41\dbch\af13\loch\f41 ry Instances which are specified. -\par }{\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 Modules}{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 +\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 Fds}{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 +\hich\af42\dbch\af13\loch\f42 Create the FD Image files. +\par }{\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 Libraries}{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 Build all EDK Libraries and EDK II Libra +\hich\af42\dbch\af13\loch\f42 ry Instances which are specified. +\par }{\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 Modules}{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 Build all EDK components and EDK II modules which are specified. -\par }{\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 Clean}{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 +\par }{\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 Clean}{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 Remove intermediate files generated by the NMAKE command (leaving -\par }\pard \ltrpar\ql \li360\ri0\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 the auto-generated C format, FD image files -\hich\af41\dbch\af13\loch\f41 , PE32 output files, PCH -\par \hich\af41\dbch\af13\loch\f41 files and LIB files). -\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 CleanAll}{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 -\hich\af41\dbch\af13\loch\f41 Remove all }{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid6164334 \hich\af41\dbch\af13\loch\f41 intermediate}{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 -, auto-generated, FV and FD image files \hich\f41 \endash \loch\f41 -\par }\pard \ltrpar\ql \li360\ri0\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 +\par }\pard \ltrpar\ql \li360\ri0\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 the auto-generated C format, FD image files +\hich\af42\dbch\af13\loch\f42 , PE32 output files, PCH +\par \hich\af42\dbch\af13\loch\f42 files and LIB files). +\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 CleanAll}{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 +\hich\af42\dbch\af13\loch\f42 Remove all }{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid6164334 \hich\af42\dbch\af13\loch\f42 intermediate}{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 +, auto-generated, FV and FD image files \hich\f42 \endash \loch\f42 +\par }\pard \ltrpar\ql \li360\ri0\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 state of the tree should be exactly as if a fresh checkout or install has -\par \hich\af41\dbch\af13\loch\f41 \hich\af41\dbch\af13\loch\f41 occurred. -\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 CleanLib}{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 -\hich\af41\dbch\af13\loch\f41 Remove intermediate files generated by the NMAKE command AND LIB -\par }\pard \ltrpar\ql \li360\ri0\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 +\par \hich\af42\dbch\af13\loch\f42 \hich\af42\dbch\af13\loch\f42 occurred. +\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 CleanLib}{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 +\hich\af42\dbch\af13\loch\f42 Remove intermediate files generated by the NMAKE command AND LIB +\par }\pard \ltrpar\ql \li360\ri0\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 files (leaving the auto-generated, FV and FD image files, PE32 output -\par \hich\af41\dbch\af13\loch\f41 files and PCH files) -\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 run}{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 -\hich\af41\dbch\af13\loch\f41 Run platform (for \hich\af41\dbch\af13\loch\f41 emulator platform only) +\par \hich\af42\dbch\af13\loch\f42 files and PCH files) +\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 run}{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 +\hich\af42\dbch\af13\loch\f42 Run platform (for \hich\af42\dbch\af13\loch\f42 emulator platform only) \par }\pard\plain \ltrpar\s2\ql \li-1440\ri0\sb400\sa60\sl-340\slmult0\keep\keepn\nowidctlpar\tx1440\wrapdefault\faauto\outlinelevel1\rin0\lin-1440\itap0\pararsid14971029 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 -\fs24\lang1033\langfe1033\loch\af41\hich\af41\dbch\af13\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \ab\af41\afs28 \ltrch\fcs0 \b\fs28\cf17\lang1033\langfe2052\langfenp2052\insrsid14971029 {\*\bkmkstart OLE_LINK3}{\*\bkmkstart OLE_LINK4} -{\*\bkmkstart OLE_LINK5}{\*\bkmkstart OLE_LINK6}\hich\af41\dbch\af13\loch\f41 Status codes returned}{\rtlch\fcs1 \ab\af41\afs28 \ltrch\fcs0 \b\fs28\cf17\lang1033\langfe2052\langfenp2052\insrsid14971029\charrsid4999604 +\fs24\lang1033\langfe1033\loch\af42\hich\af42\dbch\af13\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \ab\af42\afs28 \ltrch\fcs0 \b\fs28\cf17\lang1033\langfe2052\langfenp2052\insrsid14971029 {\*\bkmkstart OLE_LINK3}{\*\bkmkstart OLE_LINK4} +{\*\bkmkstart OLE_LINK5}{\*\bkmkstart OLE_LINK6}\hich\af42\dbch\af13\loch\f42 Status codes returned}{\rtlch\fcs1 \ab\af42\afs28 \ltrch\fcs0 \b\fs28\cf17\lang1033\langfe2052\langfenp2052\insrsid14971029\charrsid4999604 \par \ltrrow}\trowd \irow0\irowband0\ltrrow\ts26\trleft-108\trbrdrt\brdrs\brdrw10 \trbrdrl\brdrs\brdrw10 \trbrdrb\brdrs\brdrw10 \trbrdrr\brdrs\brdrw10 \trbrdrh\brdrs\brdrw10 \trbrdrv\brdrs\brdrw10 \trftsWidth3\trwWidth8820\trftsWidthB3\trftsWidthA3\trautofit1\trpaddl108\trpaddr108\trpaddfl3\trpaddft3\trpaddfb3\trpaddfr3\tblrsid5911148\tbllkhdrrows\tbllkhdrcols\tblind0\tblindtype3 \clvertalt\clbrdrt\brdrs\brdrw10 \clbrdrl\brdrs\brdrw10 \clbrdrb \brdrs\brdrw10 \clbrdrr\brdrs\brdrw10 \cltxlrtb\clftsWidth3\clwWidth2970\clshdrawnil \cellx2862\clvertalt\clbrdrt\brdrs\brdrw10 \clbrdrl\brdrs\brdrw10 \clbrdrb\brdrs\brdrw10 \clbrdrr\brdrs\brdrw10 \cltxlrtb\clftsWidth3\clwWidth5850\clshdrawnil \cellx8712 \pard\plain \ltrpar\s24\ql \li0\ri20\sb60\sa60\sl-200\slmult0\widctlpar\intbl\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin20\lin0\pararsid5911148\yts26 \rtlch\fcs1 \af0\afs16\alang1025 \ltrch\fcs0 -\fs16\cf1\lang1033\langfe1033\loch\af41\hich\af41\dbch\af13\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \ab\af2\afs18 \ltrch\fcs0 \cs25\b\f2\fs18\cf13\lang1033\langfe2052\kerning2\langfenp2052\insrsid14971029 0}{\rtlch\fcs1 \ab\af2\afs18 \ltrch\fcs0 -\cs25\b\f2\fs18\lang1033\langfe2052\kerning2\langfenp2052\insrsid14971029 \cell }{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid14971029 \hich\af41\dbch\af13\loch\f41 The action was completed as requested.}{\rtlch\fcs1 \af0 \ltrch\fcs0 \kerning2\insrsid14971029 -\cell }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\intbl\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af41\hich\af41\dbch\af13\cgrid\langnp1033\langfenp1033 { +\fs16\cf1\lang1033\langfe1033\loch\af42\hich\af42\dbch\af13\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \ab\af2\afs18 \ltrch\fcs0 \cs25\b\f2\fs18\cf13\lang1033\langfe2052\kerning2\langfenp2052\insrsid14971029 0}{\rtlch\fcs1 \ab\af2\afs18 \ltrch\fcs0 +\cs25\b\f2\fs18\lang1033\langfe2052\kerning2\langfenp2052\insrsid14971029 \cell }{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid14971029 \hich\af42\dbch\af13\loch\f42 The action was completed as requested.}{\rtlch\fcs1 \af0 \ltrch\fcs0 \kerning2\insrsid14971029 +\cell }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\intbl\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af42\hich\af42\dbch\af13\cgrid\langnp1033\langfenp1033 { \rtlch\fcs1 \af37\afs20 \ltrch\fcs0 \fs20\insrsid14971029 \trowd \irow0\irowband0\ltrrow\ts26\trleft-108\trbrdrt\brdrs\brdrw10 \trbrdrl\brdrs\brdrw10 \trbrdrb\brdrs\brdrw10 \trbrdrr\brdrs\brdrw10 \trbrdrh\brdrs\brdrw10 \trbrdrv\brdrs\brdrw10 \trftsWidth3\trwWidth8820\trftsWidthB3\trftsWidthA3\trautofit1\trpaddl108\trpaddr108\trpaddfl3\trpaddft3\trpaddfb3\trpaddfr3\tblrsid5911148\tbllkhdrrows\tbllkhdrcols\tblind0\tblindtype3 \clvertalt\clbrdrt\brdrs\brdrw10 \clbrdrl\brdrs\brdrw10 \clbrdrb \brdrs\brdrw10 \clbrdrr\brdrs\brdrw10 \cltxlrtb\clftsWidth3\clwWidth2970\clshdrawnil \cellx2862\clvertalt\clbrdrt\brdrs\brdrw10 \clbrdrl\brdrs\brdrw10 \clbrdrb\brdrs\brdrw10 \clbrdrr\brdrs\brdrw10 \cltxlrtb\clftsWidth3\clwWidth5850\clshdrawnil \cellx8712 \row \ltrrow}\pard\plain \ltrpar\s24\ql \li0\ri20\sb60\sa60\sl-200\slmult0\widctlpar\intbl\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin20\lin0\pararsid5911148\yts26 \rtlch\fcs1 \af0\afs16\alang1025 \ltrch\fcs0 -\fs16\cf1\lang1033\langfe1033\loch\af41\hich\af41\dbch\af13\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \ab\af2\afs18 \ltrch\fcs0 \cs25\b\f2\fs18\cf13\lang1033\langfe2052\kerning2\langfenp2052\insrsid4338091 \hich\af2\dbch\af13\loch\f2 Nonzero}{ -\rtlch\fcs1 \af42\afs19 \ltrch\fcs0 \cs25\f42\fs19\cf0\lang1033\langfe2052\langfenp2052\insrsid14971029\charrsid8600807 \cell }\pard \ltrpar\s24\ql \li0\ri20\sb60\sa60\sl-200\slmult0 -\widctlpar\intbl\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin20\lin0\pararsid13245303\yts26 {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1033\langfe2052\kerning2\langfenp2052\insrsid14971029 \hich\af41\dbch\af13\loch\f41 The action failed.\cell -}\pard\plain \ltrpar\ql \li0\ri0\widctlpar\intbl\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af41\hich\af41\dbch\af13\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 +\fs16\cf1\lang1033\langfe1033\loch\af42\hich\af42\dbch\af13\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \ab\af2\afs18 \ltrch\fcs0 \cs25\b\f2\fs18\cf13\lang1033\langfe2052\kerning2\langfenp2052\insrsid4338091 \hich\af2\dbch\af13\loch\f2 Nonzero}{ +\rtlch\fcs1 \af43\afs19 \ltrch\fcs0 \cs25\f43\fs19\cf0\lang1033\langfe2052\langfenp2052\insrsid14971029\charrsid8600807 \cell }\pard \ltrpar\s24\ql \li0\ri20\sb60\sa60\sl-200\slmult0 +\widctlpar\intbl\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin20\lin0\pararsid13245303\yts26 {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1033\langfe2052\kerning2\langfenp2052\insrsid14971029 \hich\af42\dbch\af13\loch\f42 The action failed.\cell +}\pard\plain \ltrpar\ql \li0\ri0\widctlpar\intbl\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af42\hich\af42\dbch\af13\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af37\afs20 \ltrch\fcs0 \fs20\insrsid14971029 \trowd \irow1\irowband1\lastrow \ltrrow\ts26\trleft-108\trbrdrt\brdrs\brdrw10 \trbrdrl\brdrs\brdrw10 \trbrdrb\brdrs\brdrw10 \trbrdrr\brdrs\brdrw10 \trbrdrh\brdrs\brdrw10 \trbrdrv\brdrs\brdrw10 \trftsWidth3\trwWidth8820\trftsWidthB3\trftsWidthA3\trautofit1\trpaddl108\trpaddr108\trpaddfl3\trpaddft3\trpaddfb3\trpaddfr3\tblrsid5911148\tbllkhdrrows\tbllkhdrcols\tblind0\tblindtype3 \clvertalt\clbrdrt\brdrs\brdrw10 \clbrdrl\brdrs\brdrw10 \clbrdrb \brdrs\brdrw10 \clbrdrr\brdrs\brdrw10 \cltxlrtb\clftsWidth3\clwWidth2970\clshdrawnil \cellx2862\clvertalt\clbrdrt\brdrs\brdrw10 \clbrdrl\brdrs\brdrw10 \clbrdrb\brdrs\brdrw10 \clbrdrr\brdrs\brdrw10 \cltxlrtb\clftsWidth3\clwWidth5850\clshdrawnil \cellx8712 -\row }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\lang1033\langfe2052\langfenp2052\insrsid16534634 {\*\bkmkend OLE_LINK3}{\*\bkmkend OLE_LINK4}{\*\bkmkend OLE_LINK5} +\row }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\lang1033\langfe2052\langfenp2052\insrsid16534634 {\*\bkmkend OLE_LINK3}{\*\bkmkend OLE_LINK4}{\*\bkmkend OLE_LINK5} {\*\bkmkend OLE_LINK6} \par }\pard \ltrpar\ql \li360\ri0\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \af0\afs18 \ltrch\fcs0 \f0\fs18\cf1\insrsid11224689 \par }{\rtlch\fcs1 \af0\afs18 \ltrch\fcs0 \f0\fs18\cf1\lang1033\langfe2052\langfenp2052\insrsid11224689 \par }\pard\plain \ltrpar\s2\ql \li-1440\ri0\sb400\sa60\sl-340\slmult0\keep\keepn\nowidctlpar\tx360\tx1440\wrapdefault\faauto\outlinelevel1\rin0\lin-1440\itap0 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 -\fs24\lang1033\langfe1033\loch\af41\hich\af41\dbch\af13\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \ab\af41\afs28 \ltrch\fcs0 \b\fs28\cf17\insrsid11224689 \hich\af41\dbch\af13\loch\f41 Examples -\par }\pard\plain \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af41\hich\af41\dbch\af13\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af41\afs18 -\ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 Assume that $(WORKSPACE) is C:\\MyWorkspace -\par }\pard \ltrpar\ql \li180\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin180\itap0 {\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 Build platform: Nt32Pkg.dsc -\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 Specify the platform description file on the command line. -\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 C:\\MyWorkspace>build -p Nt32Pkg\\Nt32Pkg.dsc \hich\f41 \endash -\loch\f41 a IA32 -\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 +\fs24\lang1033\langfe1033\loch\af42\hich\af42\dbch\af13\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \ab\af42\afs28 \ltrch\fcs0 \b\fs28\cf17\insrsid11224689 \hich\af42\dbch\af13\loch\f42 Examples +\par }\pard\plain \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af42\hich\af42\dbch\af13\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af42\afs18 +\ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 Assume that $(WORKSPACE) is C:\\MyWorkspace +\par }\pard \ltrpar\ql \li180\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin180\itap0 {\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 Build platform: Nt32Pkg.dsc +\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 Specify the platform description file on the command line. +\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 C:\\MyWorkspace>build -p Nt32Pkg\\Nt32Pkg.dsc \hich\f42 \endash +\loch\f42 a IA32 +\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 Build the platform in the current working directory if it contains a platform description file. -\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 C:\\MyWorkspace\\Nt32Pk\hich\af41\dbch\af13\loch\f41 g>build \hich\f41 -\endash \loch\f41 a IA32 -\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 Build the active platform specified in the target.txt file. -\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 C:\\ MyWorkspace>build \hich\f41 \endash \loch\f41 a Ia32 +\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 C:\\MyWorkspace\\Nt32Pk\hich\af42\dbch\af13\loch\f42 g>build \hich\f42 +\endash \loch\f42 a IA32 +\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 Build the active platform specified in the target.txt file. +\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 C:\\ MyWorkspace>build \hich\f42 \endash \loch\f42 a Ia32 \par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \af0\afs18 \ltrch\fcs0 \f0\fs18\cf1\insrsid11224689 -\par }\pard \ltrpar\ql \li180\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin180\itap0 {\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 Build Module: HelloWorld.inf -\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 Specify the platform and Module on the command line. -\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 C:\\MyWorkspace>build -p Nt32Pkg\\Nt32Pkg.dsc \hich\f41 \endash -\loch\f41 a IA32 \\ -\par }\pard \ltrpar\ql \li720\ri0\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 \hich\f41 \endash \hich\af41\dbch\af13\loch\f41 +\par }\pard \ltrpar\ql \li180\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin180\itap0 {\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 Build Module: HelloWorld.inf +\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 Specify the platform and Module on the command line. +\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 C:\\MyWorkspace>build -p Nt32Pkg\\Nt32Pkg.dsc \hich\f42 \endash +\loch\f42 a IA32 \\ +\par }\pard \ltrpar\ql \li720\ri0\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 \hich\f42 \endash \hich\af42\dbch\af13\loch\f42 m MdeModulePkg/Application/HelloWorld/HelloWorld.inf -\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 +\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 Specify the Module on the command line and use the active platform specified in the target.txt file. -\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 C:\\MyWorkspace>build \hich\f41 \endash \loch\f41 a IA32 \\ -\par }\pard \ltrpar\ql \li720\ri0\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \loch\af41\dbch\af13\hich\f41 \endash \loch\f41 m MdeModulePkg/Application/HelloWorld/HelloWorld.inf -\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 Build the module \hich\af41\dbch\af13\loch\f41 +\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 C:\\MyWorkspace>build \hich\f42 \endash \loch\f42 a IA32 \\ +\par }\pard \ltrpar\ql \li720\ri0\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \loch\af42\dbch\af13\hich\f42 \endash \loch\f42 m MdeModulePkg/Application/HelloWorld/HelloWorld.inf +\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 Build the module \hich\af42\dbch\af13\loch\f42 in the current working directory if it contains a module description file and specify the platform on the command line. -\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 C:\\ MyWorkspace\\MdeModulePkg\\Application\\HelloWorld>build \hich\f41 -\endash \loch\f41 a Ia32 \\ -\par }\pard \ltrpar\ql \li720\ri0\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \loch\af41\dbch\af13\hich\f41 \endash \loch\f41 p Nt32Pkg\\Nt32Pkg.dsc -\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 Build the module in the current working direc\hich\af41\dbch\af13\loch\f41 +\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 C:\\ MyWorkspace\\MdeModulePkg\\Application\\HelloWorld>build \hich\f42 +\endash \loch\f42 a Ia32 \\ +\par }\pard \ltrpar\ql \li720\ri0\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \loch\af42\dbch\af13\hich\f42 \endash \loch\f42 p Nt32Pkg\\Nt32Pkg.dsc +\par }\pard \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 {\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 Build the module in the current working direc\hich\af42\dbch\af13\loch\f42 tory and use the active platform specified in the target.txt file. -\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \ab\af41\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 C:\\ MyWorkspace\\MdeModulePkg\\Application\\HelloWorld>build \hich\f41 -\endash \loch\f41 a Ia32 +\par }\pard \ltrpar\ql \li720\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \ab\af42\afs18 \ltrch\fcs0 \b\fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 C:\\ MyWorkspace\\MdeModulePkg\\Application\\HelloWorld>build \hich\f42 +\endash \loch\f42 a Ia32 \par }\pard\plain \ltrpar\s2\ql \li-1440\ri0\sb400\sa60\sl-340\slmult0\keep\keepn\nowidctlpar\tx360\tx1440\wrapdefault\faauto\outlinelevel1\rin0\lin-1440\itap0 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 -\fs24\lang1033\langfe1033\loch\af41\hich\af41\dbch\af13\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \ab\af41\afs28 \ltrch\fcs0 \b\fs28\cf17\insrsid11224689 \hich\af41\dbch\af13\loch\f41 Bugs -\par }\pard\plain \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af41\hich\af41\dbch\af13\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af41\afs18 -\ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 No known }{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid9010967 \hich\af41\dbch\af13\loch\f41 issues.}{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 -\par \hich\af41\dbch\af13\loch\f41 Report bugs to edk2-buildtools-devel@lists.sourceforge.net}{\rtlch\fcs1 \af0\afs18 \ltrch\fcs0 \f0\fs18\cf1\insrsid11224689 +\fs24\lang1033\langfe1033\loch\af42\hich\af42\dbch\af13\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \ab\af42\afs28 \ltrch\fcs0 \b\fs28\cf17\insrsid11224689 \hich\af42\dbch\af13\loch\f42 Bugs +\par }\pard\plain \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af42\hich\af42\dbch\af13\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af42\afs18 +\ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 No known }{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid9010967 \hich\af42\dbch\af13\loch\f42 issues.}{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\insrsid11224689 +\par \hich\af42\dbch\af13\loch\f42 Report bugs to edk2-buildtools-devel@lists.sourceforge.net}{\rtlch\fcs1 \af0\afs18 \ltrch\fcs0 \f0\fs18\cf1\insrsid11224689 \par }\pard\plain \ltrpar\s2\ql \li-1440\ri0\sb400\sa60\sl-340\slmult0\keep\keepn\nowidctlpar\tx360\tx1440\wrapdefault\faauto\outlinelevel1\rin0\lin-1440\itap0 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 -\fs24\lang1033\langfe1033\loch\af41\hich\af41\dbch\af13\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \ab\af41\afs28 \ltrch\fcs0 \b\fs28\cf17\insrsid11224689 \hich\af41\dbch\af13\loch\f41 Files -\par }\pard\plain \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af41\hich\af41\dbch\af13\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af41\afs18 -\ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 target.txt, tools_def.txt, platform.dsc, flashmap.fdf, package.dec and module.inf. +\fs24\lang1033\langfe1033\loch\af42\hich\af42\dbch\af13\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \ab\af42\afs28 \ltrch\fcs0 \b\fs28\cf17\insrsid11224689 \hich\af42\dbch\af13\loch\f42 Files +\par }\pard\plain \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af42\hich\af42\dbch\af13\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af42\afs18 +\ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 target.txt, tools_def.txt, platfo\hich\af42\dbch\af13\loch\f42 rm.dsc, flashmap.fdf, package.dec and module.inf. \par }\pard\plain \ltrpar\s2\ql \li-1440\ri0\sb400\sa60\sl-340\slmult0\keep\keepn\nowidctlpar\tx360\tx1440\wrapdefault\faauto\outlinelevel1\rin0\lin-1440\itap0 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 -\fs24\lang1033\langfe1033\loch\af41\hich\af41\dbch\af13\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \ab\af41\afs28 \ltrch\fcs0 \b\fs28\cf17\insrsid11224689 \hich\af41\dbch\af13\loch\f41 See also -\par }\pard\plain \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af41\hich\af41\dbch\af13\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af41\afs18 -\ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 GenFds.exe +\fs24\lang1033\langfe1033\loch\af42\hich\af42\dbch\af13\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \ab\af42\afs28 \ltrch\fcs0 \b\fs28\cf17\insrsid11224689 \hich\af42\dbch\af13\loch\f42 See also +\par }\pard\plain \ltrpar\ql \li360\ri0\sb200\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af42\hich\af42\dbch\af13\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af42\afs18 +\ltrch\fcs0 \fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 GenFds.exe \par }\pard\plain \ltrpar\s2\ql \li-1440\ri0\sb400\sa60\sl-340\slmult0\keep\keepn\nowidctlpar\tx360\tx1440\wrapdefault\faauto\outlinelevel1\rin0\lin-1440\itap0 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 -\fs24\lang1033\langfe1033\loch\af41\hich\af41\dbch\af13\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \ab\af41\afs28 \ltrch\fcs0 \b\fs28\cf17\insrsid11224689 \hich\af41\dbch\af13\loch\f41 License -\par }\pard\plain \ltrpar\ql \li360\ri0\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af41\hich\af41\dbch\af13\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 -\fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 Copyright (c) 1999 - 201}{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 \fs18\cf1\lang1033\langfe2052\langfenp2052\insrsid1381256 \hich\af41\dbch\af13\loch\f41 1}{\rtlch\fcs1 \af41\afs18 \ltrch\fcs0 -\fs18\cf1\insrsid11224689 \hich\af41\dbch\af13\loch\f41 , Intel Corporation. All rights reserved. +\fs24\lang1033\langfe1033\loch\af42\hich\af42\dbch\af13\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \ab\af42\afs28 \ltrch\fcs0 \b\fs28\cf17\insrsid11224689 \hich\af42\dbch\af13\loch\f42 License +\par }\pard\plain \ltrpar\ql \li360\ri0\nowidctlpar\wrapdefault\faauto\rin0\lin360\itap0 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af42\hich\af42\dbch\af13\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 +\fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 Copyright (c) 1999 - 201}{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 \fs18\cf1\lang1033\langfe2052\langfenp2052\insrsid1381256 \hich\af42\dbch\af13\loch\f42 1}{\rtlch\fcs1 \af42\afs18 \ltrch\fcs0 +\fs18\cf1\insrsid11224689 \hich\af42\dbch\af13\loch\f42 , Intel Corporation. All rights reserved. \par -\par \hich\af41\dbch\af13\loch\f41 This program and the accompanying materials are licensed and made available under the terms and -\par \hich\af41\dbch\af13\loch\f41 conditions of the BSD License which accompanies this distribution. The full text of the license may be -\par \hich\af41\dbch\af13\loch\f41 found at: -\par \hich\af41\dbch\af13\loch\f41 http://opensource.org/licenses/bsd-license.php +\par \hich\af42\dbch\af13\loch\f42 This program and the accompanying materials are licensed and made available under the terms and +\par \hich\af42\dbch\af13\loch\f42 conditions of the BSD License which accompanies this distribution. The full text of the license may be +\par \hich\af42\dbch\af13\loch\f42 found at: +\par \hich\af42\dbch\af13\loch\f42 http://opensource.org/licenses/bsd-license.php \par -\par \hich\af41\dbch\af13\loch\f41 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES -\par \hich\af41\dbch\af13\loch\f41 OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -\par }{\*\themedata 504b030414000600080000002100828abc13fa0000001c020000130000005b436f6e74656e745f54797065735d2e786d6cac91cb6ac3301045f785fe83d0b6d8 -72ba28a5d8cea249777d2cd20f18e4b12d6a8f843409c9df77ecb850ba082d74231062ce997b55ae8fe3a00e1893f354e9555e6885647de3a8abf4fbee29bbd7 -2a3150038327acf409935ed7d757e5ee14302999a654e99e393c18936c8f23a4dc072479697d1c81e51a3b13c07e4087e6b628ee8cf5c4489cf1c4d075f92a0b -44d7a07a83c82f308ac7b0a0f0fbf90c2480980b58abc733615aa2d210c2e02cb04430076a7ee833dfb6ce62e3ed7e14693e8317d8cd0433bf5c60f53fea2fe7 -065bd80facb647e9e25c7fc421fd2ddb526b2e9373fed4bb902e182e97b7b461e6bfad3f010000ffff0300504b030414000600080000002100a5d6a7e7c00000 -00360100000b0000005f72656c732f2e72656c73848fcf6ac3300c87ef85bd83d17d51d2c31825762fa590432fa37d00e1287f68221bdb1bebdb4fc7060abb08 -84a4eff7a93dfeae8bf9e194e720169aaa06c3e2433fcb68e1763dbf7f82c985a4a725085b787086a37bdbb55fbc50d1a33ccd311ba548b63095120f88d94fbc -52ae4264d1c910d24a45db3462247fa791715fd71f989e19e0364cd3f51652d73760ae8fa8c9ffb3c330cc9e4fc17faf2ce545046e37944c69e462a1a82fe353 -bd90a865aad41ed0b5b8f9d6fd010000ffff0300504b0304140006000800000021006b799616830000008a0000001c0000007468656d652f7468656d652f7468 -656d654d616e616765722e786d6c0ccc4d0ac3201040e17da17790d93763bb284562b2cbaebbf600439c1a41c7a0d29fdbd7e5e38337cedf14d59b4b0d592c9c -070d8a65cd2e88b7f07c2ca71ba8da481cc52c6ce1c715e6e97818c9b48d13df49c873517d23d59085adb5dd20d6b52bd521ef2cdd5eb9246a3d8b4757e8d3f7 -29e245eb2b260a0238fd010000ffff0300504b03041400060008000000210096b5ade296060000501b0000160000007468656d652f7468656d652f7468656d65 -312e786d6cec594f6fdb3614bf0fd87720746f6327761a07758ad8b19b2d4d1bc46e871e698996d850a240d2497d1bdae38001c3ba618715d86d87615b8116d8 -a5fb34d93a6c1dd0afb0475292c5585e9236d88aad3e2412f9e3fbff1e1fa9abd7eec70c1d1221294fda5efd72cd4324f1794093b0eddd1ef62fad79482a9c04 -98f184b4bd2991deb58df7dfbb8ad755446282607d22d771db8b944ad79796a40fc3585ee62949606ecc458c15bc8a702910f808e8c66c69b9565b5d8a314d3c -94e018c8de1a8fa94fd05093f43672e23d06af89927ac06762a049136785c10607758d9053d965021d62d6f6804fc08f86e4bef210c352c144dbab999fb7b471 -7509af678b985ab0b6b4ae6f7ed9ba6c4170b06c788a705430adf71bad2b5b057d03606a1ed7ebf5babd7a41cf00b0ef83a6569632cd467faddec9699640f671 -9e76b7d6ac355c7c89feca9cccad4ea7d36c65b258a206641f1b73f8b5da6a6373d9c11b90c537e7f08dce66b7bbeae00dc8e257e7f0fd2badd5868b37a088d1 -e4600ead1ddaef67d40bc898b3ed4af81ac0d76a197c86826828a24bb318f3442d8ab518dfe3a20f000d6458d104a9694ac6d88728eee2782428d60cf03ac1a5 -193be4cbb921cd0b495fd054b5bd0f530c1931a3f7eaf9f7af9e3f45c70f9e1d3ff8e9f8e1c3e3073f5a42ceaa6d9c84e5552fbffdeccfc71fa33f9e7ef3f2d1 -17d57859c6fffac327bffcfc793510d26726ce8b2f9ffcf6ecc98baf3efdfdbb4715f04d814765f890c644a29be408edf3181433567125272371be15c308d3f2 -8acd249438c19a4b05fd9e8a1cf4cd296699771c393ac4b5e01d01e5a30a787d72cf1178108989a2159c77a2d801ee72ce3a5c545a6147f32a99793849c26ae6 -6252c6ed637c58c5bb8b13c7bfbd490a75330f4b47f16e441c31f7184e140e494214d273fc80900aedee52ead87597fa824b3e56e82e451d4c2b4d32a423279a -668bb6690c7e9956e90cfe766cb37b077538abd27a8b1cba48c80acc2a841f12e698f13a9e281c57911ce298950d7e03aba84ac8c154f8655c4f2af074481847 -bd804859b5e696007d4b4edfc150b12addbecba6b18b148a1e54d1bc81392f23b7f84137c2715a851dd0242a633f900710a218ed715505dfe56e86e877f0034e -16bafb0e258ebb4faf06b769e888340b103d3311da9750aa9d0a1cd3e4efca31a3508f6d0c5c5c398602f8e2ebc71591f5b616e24dd893aa3261fb44f95d843b -5974bb5c04f4edafb95b7892ec1108f3f98de75dc97d5772bdff7cc95d94cf672db4b3da0a6557f70db629362d72bcb0431e53c6066acac80d699a6409fb44d0 -8741bdce9c0e4971624a2378cceaba830b05366b90e0ea23aaa241845368b0eb9e2612ca8c742851ca251ceccc70256d8d87265dd96361531f186c3d9058edf2 -c00eafe8e1fc5c509031bb4d680e9f39a3154de0accc56ae644441edd76156d7429d995bdd88664a9dc3ad50197c38af1a0c16d684060441db02565e85f3b966 -0d0713cc48a0ed6ef7dedc2dc60b17e92219e180643ed27acffba86e9c94c78ab90980d8a9f0913ee49d62b512b79626fb06dccee2a432bbc60276b9f7dec44b -7904cfbca4f3f6443ab2a49c9c2c41476dafd55c6e7ac8c769db1bc399161ee314bc2e75cf8759081743be1236ec4f4d6693e5336fb672c5dc24a8c33585b5fb -9cc24e1d4885545b58463634cc5416022cd19cacfccb4d30eb45296023fd35a458598360f8d7a4003bbaae25e331f155d9d9a5116d3bfb9a95523e51440ca2e0 -088dd844ec6370bf0e55d027a012ae264c45d02f708fa6ad6da6dce29c255df9f6cae0ec38666984b372ab5334cf640b37795cc860de4ae2816e95b21be5ceaf -8a49f90b52a51cc6ff3355f47e0237052b81f6800fd7b802239daf6d8f0b1571a8426944fdbe80c6c1d40e8816b88b8569082ab84c36ff0539d4ff6dce591a26 -ade1c0a7f669880485fd484582903d284b26fa4e2156cff62e4b9265844c4495c495a9157b440e091bea1ab8aaf7760f4510eaa69a6465c0e04ec69ffb9e65d0 -28d44d4e39df9c1a52ecbd3607fee9cec7263328e5d661d3d0e4f62f44acd855ed7ab33cdf7bcb8ae889599bd5c8b3029895b6825696f6af29c239b75a5bb1e6 -345e6ee6c28117e73586c1a2214ae1be07e93fb0ff51e133fb65426fa843be0fb515c187064d0cc206a2fa926d3c902e907670048d931db4c1a44959d366ad93 -b65abe595f70a75bf03d616c2dd959fc7d4e6317cd99cbcec9c58b34766661c7d6766ca1a9c1b327531486c6f941c638c67cd22a7f75e2a37be0e82db8df9f30 -254d30c1372581a1f51c983c80e4b71ccdd28dbf000000ffff0300504b0304140006000800000021000dd1909fb60000001b010000270000007468656d652f74 -68656d652f5f72656c732f7468656d654d616e616765722e786d6c2e72656c73848f4d0ac2301484f78277086f6fd3ba109126dd88d0add40384e4350d363f24 -51eced0dae2c082e8761be9969bb979dc9136332de3168aa1a083ae995719ac16db8ec8e4052164e89d93b64b060828e6f37ed1567914b284d262452282e3198 -720e274a939cd08a54f980ae38a38f56e422a3a641c8bbd048f7757da0f19b017cc524bd62107bd5001996509affb3fd381a89672f1f165dfe514173d9850528 -a2c6cce0239baa4c04ca5bbabac4df000000ffff0300504b01022d0014000600080000002100828abc13fa0000001c0200001300000000000000000000000000 -000000005b436f6e74656e745f54797065735d2e786d6c504b01022d0014000600080000002100a5d6a7e7c0000000360100000b000000000000000000000000 -002b0100005f72656c732f2e72656c73504b01022d00140006000800000021006b799616830000008a0000001c00000000000000000000000000140200007468 -656d652f7468656d652f7468656d654d616e616765722e786d6c504b01022d001400060008000000210096b5ade296060000501b000016000000000000000000 -00000000d10200007468656d652f7468656d652f7468656d65312e786d6c504b01022d00140006000800000021000dd1909fb60000001b010000270000000000 -00000000000000009b0900007468656d652f7468656d652f5f72656c732f7468656d654d616e616765722e786d6c2e72656c73504b050600000000050005005d010000960a00000000} +\par \hich\af42\dbch\af13\loch\f42 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES +\par \hich\af42\dbch\af13\loch\f42 OR RE\hich\af42\dbch\af13\loch\f42 PRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +\par }{\*\themedata 504b030414000600080000002100e9de0fbfff0000001c020000130000005b436f6e74656e745f54797065735d2e786d6cac91cb4ec3301045f748fc83e52d4a +9cb2400825e982c78ec7a27cc0c8992416c9d8b2a755fbf74cd25442a820166c2cd933f79e3be372bd1f07b5c3989ca74aaff2422b24eb1b475da5df374fd9ad +5689811a183c61a50f98f4babebc2837878049899a52a57be670674cb23d8e90721f90a4d2fa3802cb35762680fd800ecd7551dc18eb899138e3c943d7e503b6 +b01d583deee5f99824e290b4ba3f364eac4a430883b3c092d4eca8f946c916422ecab927f52ea42b89a1cd59c254f919b0e85e6535d135a8de20f20b8c12c3b0 +0c895fcf6720192de6bf3b9e89ecdbd6596cbcdd8eb28e7c365ecc4ec1ff1460f53fe813d3cc7f5b7f020000ffff0300504b030414000600080000002100a5d6 +a7e7c0000000360100000b0000005f72656c732f2e72656c73848fcf6ac3300c87ef85bd83d17d51d2c31825762fa590432fa37d00e1287f68221bdb1bebdb4f +c7060abb0884a4eff7a93dfeae8bf9e194e720169aaa06c3e2433fcb68e1763dbf7f82c985a4a725085b787086a37bdbb55fbc50d1a33ccd311ba548b6309512 +0f88d94fbc52ae4264d1c910d24a45db3462247fa791715fd71f989e19e0364cd3f51652d73760ae8fa8c9ffb3c330cc9e4fc17faf2ce545046e37944c69e462 +a1a82fe353bd90a865aad41ed0b5b8f9d6fd010000ffff0300504b0304140006000800000021006b799616830000008a0000001c0000007468656d652f746865 +6d652f7468656d654d616e616765722e786d6c0ccc4d0ac3201040e17da17790d93763bb284562b2cbaebbf600439c1a41c7a0d29fdbd7e5e38337cedf14d59b +4b0d592c9c070d8a65cd2e88b7f07c2ca71ba8da481cc52c6ce1c715e6e97818c9b48d13df49c873517d23d59085adb5dd20d6b52bd521ef2cdd5eb9246a3d8b +4757e8d3f729e245eb2b260a0238fd010000ffff0300504b03041400060008000000210096b5ade296060000501b0000160000007468656d652f7468656d652f +7468656d65312e786d6cec594f6fdb3614bf0fd87720746f6327761a07758ad8b19b2d4d1bc46e871e698996d850a240d2497d1bdae38001c3ba618715d86d87 +615b8116d8a5fb34d93a6c1dd0afb0475292c5585e9236d88aad3e2412f9e3fbff1e1fa9abd7eec70c1d1221294fda5efd72cd4324f1794093b0eddd1ef62fad +79482a9c0498f184b4bd2991deb58df7dfbb8ad755446282607d22d771db8b944ad79796a40fc3585ee62949606ecc458c15bc8a702910f808e8c66c69b9565b +5d8a314d3c94e018c8de1a8fa94fd05093f43672e23d06af89927ac06762a049136785c10607758d9053d965021d62d6f6804fc08f86e4bef210c352c144dbab +999fb7b4717509af678b985ab0b6b4ae6f7ed9ba6c4170b06c788a705430adf71bad2b5b057d03606a1ed7ebf5babd7a41cf00b0ef83a6569632cd467faddec9 +699640f6719e76b7d6ac355c7c89feca9cccad4ea7d36c65b258a206641f1b73f8b5da6a6373d9c11b90c537e7f08dce66b7bbeae00dc8e257e7f0fd2badd586 +8b37a088d1e4600ead1ddaef67d40bc898b3ed4af81ac0d76a197c86826828a24bb318f3442d8ab518dfe3a20f000d6458d104a9694ac6d88728eee2782428d6 +0cf03ac1a5193be4cbb921cd0b495fd054b5bd0f530c1931a3f7eaf9f7af9e3f45c70f9e1d3ff8e9f8e1c3e3073f5a42ceaa6d9c84e5552fbffdeccfc71fa33f +9e7ef3f2d117d57859c6fffac327bffcfc793510d26726ce8b2f9ffcf6ecc98baf3efdfdbb4715f04d814765f890c644a29be408edf3181433567125272371be +15c308d3f28acd249438c19a4b05fd9e8a1cf4cd296699771c393ac4b5e01d01e5a30a787d72cf1178108989a2159c77a2d801ee72ce3a5c545a6147f32a9979 +3849c26ae66252c6ed637c58c5bb8b13c7bfbd490a75330f4b47f16e441c31f7184e140e494214d273fc80900aedee52ead87597fa824b3e56e82e451d4c2b4d +32a423279a668bb6690c7e9956e90cfe766cb37b077538abd27a8b1cba48c80acc2a841f12e698f13a9e281c57911ce298950d7e03aba84ac8c154f8655c4f2a +f074481847bd804859b5e696007d4b4edfc150b12addbecba6b18b148a1e54d1bc81392f23b7f84137c2715a851dd0242a633f900710a218ed715505dfe56e86 +e877f0034e16bafb0e258ebb4faf06b769e888340b103d3311da9750aa9d0a1cd3e4efca31a3508f6d0c5c5c398602f8e2ebc71591f5b616e24dd893aa3261fb +44f95d843b5974bb5c04f4edafb95b7892ec1108f3f98de75dc97d5772bdff7cc95d94cf672db4b3da0a6557f70db629362d72bcb0431e53c6066acac80d699a +6409fb44d08741bdce9c0e4971624a2378cceaba830b05366b90e0ea23aaa241845368b0eb9e2612ca8c742851ca251ceccc70256d8d87265dd96361531f186c +3d9058edf2c00eafe8e1fc5c509031bb4d680e9f39a3154de0accc56ae644441edd76156d7429d995bdd88664a9dc3ad50197c38af1a0c16d684060441db0256 +5e85f3b9660d0713cc48a0ed6ef7dedc2dc60b17e92219e180643ed27acffba86e9c94c78ab90980d8a9f0913ee49d62b512b79626fb06dccee2a432bbc60276 +b9f7dec44b7904cfbca4f3f6443ab2a49c9c2c41476dafd55c6e7ac8c769db1bc399161ee314bc2e75cf8759081743be1236ec4f4d6693e5336fb672c5dc24a8 +c33585b5fb9cc24e1d4885545b58463634cc5416022cd19cacfccb4d30eb45296023fd35a458598360f8d7a4003bbaae25e331f155d9d9a5116d3bfb9a95523e +51440ca2e0088dd844ec6370bf0e55d027a012ae264c45d02f708fa6ad6da6dce29c255df9f6cae0ec38666984b372ab5334cf640b37795cc860de4ae2816e95 +b21be5ceaf8a49f90b52a51cc6ff3355f47e0237052b81f6800fd7b802239daf6d8f0b1571a8426944fdbe80c6c1d40e8816b88b8569082ab84c36ff0539d4ff +6dce591a26ade1c0a7f669880485fd484582903d284b26fa4e2156cff62e4b9265844c4495c495a9157b440e091bea1ab8aaf7760f4510eaa69a6465c0e04ec6 +9ffb9e65d028d44d4e39df9c1a52ecbd3607fee9cec7263328e5d661d3d0e4f62f44acd855ed7ab33cdf7bcb8ae889599bd5c8b3029895b6825696f6af29c239 +b75a5bb1e6345e6ee6c28117e73586c1a2214ae1be07e93fb0ff51e133fb65426fa843be0fb515c187064d0cc206a2fa926d3c902e907670048d931db4c1a449 +59d366ad93b65abe595f70a75bf03d616c2dd959fc7d4e6317cd99cbcec9c58b34766661c7d6766ca1a9c1b327531486c6f941c638c67cd22a7f75e2a37be0e8 +2db8df9f30254d30c1372581a1f51c983c80e4b71ccdd28dbf000000ffff0300504b0304140006000800000021000dd1909fb60000001b010000270000007468 +656d652f7468656d652f5f72656c732f7468656d654d616e616765722e786d6c2e72656c73848f4d0ac2301484f78277086f6fd3ba109126dd88d0add40384e4 +350d363f2451eced0dae2c082e8761be9969bb979dc9136332de3168aa1a083ae995719ac16db8ec8e4052164e89d93b64b060828e6f37ed1567914b284d2624 +52282e3198720e274a939cd08a54f980ae38a38f56e422a3a641c8bbd048f7757da0f19b017cc524bd62107bd5001996509affb3fd381a89672f1f165dfe5141 +73d9850528a2c6cce0239baa4c04ca5bbabac4df000000ffff0300504b01022d0014000600080000002100e9de0fbfff0000001c020000130000000000000000 +0000000000000000005b436f6e74656e745f54797065735d2e786d6c504b01022d0014000600080000002100a5d6a7e7c0000000360100000b00000000000000 +000000000000300100005f72656c732f2e72656c73504b01022d00140006000800000021006b799616830000008a0000001c0000000000000000000000000019 +0200007468656d652f7468656d652f7468656d654d616e616765722e786d6c504b01022d001400060008000000210096b5ade296060000501b00001600000000 +000000000000000000d60200007468656d652f7468656d652f7468656d65312e786d6c504b01022d00140006000800000021000dd1909fb60000001b01000027 +00000000000000000000000000a00900007468656d652f7468656d652f5f72656c732f7468656d654d616e616765722e786d6c2e72656c73504b050600000000050005005d0100009b0a00000000} {\*\colorschememapping 3c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d3822207374616e64616c6f6e653d22796573223f3e0d0a3c613a636c724d 617020786d6c6e733a613d22687474703a2f2f736368656d61732e6f70656e786d6c666f726d6174732e6f72672f64726177696e676d6c2f323030362f6d6169 6e22206267313d226c743122207478313d22646b3122206267323d226c743222207478323d22646b322220616363656e74313d22616363656e74312220616363 656e74323d22616363656e74322220616363656e74333d22616363656e74332220616363656e74343d22616363656e74342220616363656e74353d22616363656e74352220616363656e74363d22616363656e74362220686c696e6b3d22686c696e6b2220666f6c486c696e6b3d22666f6c486c696e6b222f3e} -{\*\latentstyles\lsdstimax267\lsdlockeddef0\lsdsemihiddendef1\lsdunhideuseddef1\lsdqformatdef0\lsdprioritydef99{\lsdlockedexcept \lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority0 Normal; -\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority0 heading 1;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority0 heading 2;\lsdqformat1 \lsdpriority0 heading 3;\lsdqformat1 \lsdpriority0 heading 4;\lsdqformat1 \lsdpriority0 heading 5; -\lsdqformat1 \lsdpriority0 heading 6;\lsdqformat1 \lsdpriority0 heading 7;\lsdqformat1 \lsdpriority0 heading 8;\lsdqformat1 \lsdpriority0 heading 9;\lsdsemihidden0 \lsdunhideused0 \lsdpriority0 toc 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority0 toc 2; -\lsdsemihidden0 \lsdunhideused0 \lsdpriority0 toc 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority0 toc 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority0 toc 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority0 toc 6; -\lsdsemihidden0 \lsdunhideused0 \lsdpriority0 toc 7;\lsdsemihidden0 \lsdunhideused0 \lsdpriority0 toc 8;\lsdsemihidden0 \lsdunhideused0 \lsdpriority0 toc 9;\lsdqformat1 \lsdpriority0 caption; -\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority0 Title;\lsdsemihidden0 \lsdunhideused0 \lsdpriority0 Default Paragraph Font;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority0 Subtitle; -\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority0 Strong;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority0 Emphasis;\lsdsemihidden0 \lsdunhideused0 \lsdpriority0 Table Grid;\lsdunhideused0 \lsdlocked0 Placeholder Text; -\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority1 \lsdlocked0 No Spacing;\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading;\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List; -\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid;\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2; -\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1; -\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List; -\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading;\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List;\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid; -\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 1; -\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 1; -\lsdunhideused0 \lsdlocked0 Revision;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority34 \lsdlocked0 List Paragraph;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority29 \lsdlocked0 Quote; -\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority30 \lsdlocked0 Intense Quote;\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 1; -\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 1; -\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 1; -\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 2; -\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 2; -\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 2; -\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 2; -\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 3; -\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 3; -\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 3; -\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 3; -\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 3; -\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 4; -\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 4; -\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 4; -\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 4; -\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 4; -\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 5; -\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 5; -\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 5; -\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 5; -\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 6; -\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 6; -\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 6; -\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 6; -\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 6; -\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority19 \lsdlocked0 Subtle Emphasis; -\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority21 \lsdlocked0 Intense Emphasis;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority31 \lsdlocked0 Subtle Reference; -\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority32 \lsdlocked0 Intense Reference;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority33 \lsdlocked0 Book Title;\lsdpriority37 \lsdlocked0 Bibliography; -\lsdqformat1 \lsdpriority39 \lsdlocked0 TOC Heading;}}{\*\datastore 0105000002000000180000004d73786d6c322e534158584d4c5265616465722e352e3000000000000000000000060000 +{\*\latentstyles\lsdstimax371\lsdlockeddef0\lsdsemihiddendef0\lsdunhideuseddef0\lsdqformatdef0\lsdprioritydef99{\lsdlockedexcept \lsdqformat1 \lsdpriority0 Normal;\lsdqformat1 \lsdpriority0 heading 1;\lsdqformat1 \lsdpriority0 heading 2; +\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority0 heading 3;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority0 heading 4;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority0 heading 5; +\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority0 heading 6;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority0 heading 7;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority0 heading 8; +\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority0 heading 9;\lsdpriority0 toc 1;\lsdpriority0 toc 2;\lsdpriority0 toc 3;\lsdpriority0 toc 4;\lsdpriority0 toc 5;\lsdpriority0 toc 6;\lsdpriority0 toc 7;\lsdpriority0 toc 8;\lsdpriority0 toc 9; +\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority0 caption;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List 5; +\lsdqformat1 \lsdpriority0 Title;\lsdpriority0 Default Paragraph Font;\lsdqformat1 \lsdpriority0 Subtitle;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Salutation;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Date; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text First Indent;\lsdqformat1 \lsdpriority0 Strong;\lsdqformat1 \lsdpriority0 Emphasis;\lsdpriority0 Table Grid;\lsdsemihidden1 \lsdlocked0 Placeholder Text; +\lsdqformat1 \lsdpriority1 \lsdlocked0 No Spacing;\lsdpriority60 \lsdlocked0 Light Shading;\lsdpriority61 \lsdlocked0 Light List;\lsdpriority62 \lsdlocked0 Light Grid;\lsdpriority63 \lsdlocked0 Medium Shading 1;\lsdpriority64 \lsdlocked0 Medium Shading 2; +\lsdpriority65 \lsdlocked0 Medium List 1;\lsdpriority66 \lsdlocked0 Medium List 2;\lsdpriority67 \lsdlocked0 Medium Grid 1;\lsdpriority68 \lsdlocked0 Medium Grid 2;\lsdpriority69 \lsdlocked0 Medium Grid 3;\lsdpriority70 \lsdlocked0 Dark List; +\lsdpriority71 \lsdlocked0 Colorful Shading;\lsdpriority72 \lsdlocked0 Colorful List;\lsdpriority73 \lsdlocked0 Colorful Grid;\lsdpriority60 \lsdlocked0 Light Shading Accent 1;\lsdpriority61 \lsdlocked0 Light List Accent 1; +\lsdpriority62 \lsdlocked0 Light Grid Accent 1;\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 1;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 1;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 1;\lsdsemihidden1 \lsdlocked0 Revision; +\lsdqformat1 \lsdpriority34 \lsdlocked0 List Paragraph;\lsdqformat1 \lsdpriority29 \lsdlocked0 Quote;\lsdqformat1 \lsdpriority30 \lsdlocked0 Intense Quote;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 1;\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 1; +\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 1;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 1;\lsdpriority70 \lsdlocked0 Dark List Accent 1;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 1;\lsdpriority72 \lsdlocked0 Colorful List Accent 1; +\lsdpriority73 \lsdlocked0 Colorful Grid Accent 1;\lsdpriority60 \lsdlocked0 Light Shading Accent 2;\lsdpriority61 \lsdlocked0 Light List Accent 2;\lsdpriority62 \lsdlocked0 Light Grid Accent 2;\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 2; +\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 2;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 2;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 2;\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 2;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 2; +\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 2;\lsdpriority70 \lsdlocked0 Dark List Accent 2;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 2;\lsdpriority72 \lsdlocked0 Colorful List Accent 2;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 2; +\lsdpriority60 \lsdlocked0 Light Shading Accent 3;\lsdpriority61 \lsdlocked0 Light List Accent 3;\lsdpriority62 \lsdlocked0 Light Grid Accent 3;\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 3;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 3; +\lsdpriority65 \lsdlocked0 Medium List 1 Accent 3;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 3;\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 3;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 3;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 3; +\lsdpriority70 \lsdlocked0 Dark List Accent 3;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 3;\lsdpriority72 \lsdlocked0 Colorful List Accent 3;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 3;\lsdpriority60 \lsdlocked0 Light Shading Accent 4; +\lsdpriority61 \lsdlocked0 Light List Accent 4;\lsdpriority62 \lsdlocked0 Light Grid Accent 4;\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 4;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 4;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 4; +\lsdpriority66 \lsdlocked0 Medium List 2 Accent 4;\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 4;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 4;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 4;\lsdpriority70 \lsdlocked0 Dark List Accent 4; +\lsdpriority71 \lsdlocked0 Colorful Shading Accent 4;\lsdpriority72 \lsdlocked0 Colorful List Accent 4;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 4;\lsdpriority60 \lsdlocked0 Light Shading Accent 5;\lsdpriority61 \lsdlocked0 Light List Accent 5; +\lsdpriority62 \lsdlocked0 Light Grid Accent 5;\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 5;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 5;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 5;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 5; +\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 5;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 5;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 5;\lsdpriority70 \lsdlocked0 Dark List Accent 5;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 5; +\lsdpriority72 \lsdlocked0 Colorful List Accent 5;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 5;\lsdpriority60 \lsdlocked0 Light Shading Accent 6;\lsdpriority61 \lsdlocked0 Light List Accent 6;\lsdpriority62 \lsdlocked0 Light Grid Accent 6; +\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 6;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 6;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 6;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 6; +\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 6;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 6;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 6;\lsdpriority70 \lsdlocked0 Dark List Accent 6;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 6; +\lsdpriority72 \lsdlocked0 Colorful List Accent 6;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 6;\lsdqformat1 \lsdpriority19 \lsdlocked0 Subtle Emphasis;\lsdqformat1 \lsdpriority21 \lsdlocked0 Intense Emphasis; +\lsdqformat1 \lsdpriority31 \lsdlocked0 Subtle Reference;\lsdqformat1 \lsdpriority32 \lsdlocked0 Intense Reference;\lsdqformat1 \lsdpriority33 \lsdlocked0 Book Title;\lsdsemihidden1 \lsdunhideused1 \lsdpriority37 \lsdlocked0 Bibliography; +\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority39 \lsdlocked0 TOC Heading;\lsdpriority41 \lsdlocked0 Plain Table 1;\lsdpriority42 \lsdlocked0 Plain Table 2;\lsdpriority43 \lsdlocked0 Plain Table 3;\lsdpriority44 \lsdlocked0 Plain Table 4; +\lsdpriority45 \lsdlocked0 Plain Table 5;\lsdpriority40 \lsdlocked0 Grid Table Light;\lsdpriority46 \lsdlocked0 Grid Table 1 Light;\lsdpriority47 \lsdlocked0 Grid Table 2;\lsdpriority48 \lsdlocked0 Grid Table 3;\lsdpriority49 \lsdlocked0 Grid Table 4; +\lsdpriority50 \lsdlocked0 Grid Table 5 Dark;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 1;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 1; +\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 1;\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 1;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 1;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 1; +\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 1;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 2;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 2;\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 2; +\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 2;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 2;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 2;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 2; +\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 3;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 3;\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 3;\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 3; +\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 3;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 3;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 3;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 4; +\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 4;\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 4;\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 4;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 4; +\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 4;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 4;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 5;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 5; +\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 5;\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 5;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 5;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 5; +\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 5;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 6;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 6;\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 6; +\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 6;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 6;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 6;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 6; +\lsdpriority46 \lsdlocked0 List Table 1 Light;\lsdpriority47 \lsdlocked0 List Table 2;\lsdpriority48 \lsdlocked0 List Table 3;\lsdpriority49 \lsdlocked0 List Table 4;\lsdpriority50 \lsdlocked0 List Table 5 Dark; +\lsdpriority51 \lsdlocked0 List Table 6 Colorful;\lsdpriority52 \lsdlocked0 List Table 7 Colorful;\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 1;\lsdpriority47 \lsdlocked0 List Table 2 Accent 1;\lsdpriority48 \lsdlocked0 List Table 3 Accent 1; +\lsdpriority49 \lsdlocked0 List Table 4 Accent 1;\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 1;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 1;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 1; +\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 2;\lsdpriority47 \lsdlocked0 List Table 2 Accent 2;\lsdpriority48 \lsdlocked0 List Table 3 Accent 2;\lsdpriority49 \lsdlocked0 List Table 4 Accent 2; +\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 2;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 2;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 2;\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 3; +\lsdpriority47 \lsdlocked0 List Table 2 Accent 3;\lsdpriority48 \lsdlocked0 List Table 3 Accent 3;\lsdpriority49 \lsdlocked0 List Table 4 Accent 3;\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 3; +\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 3;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 3;\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 4;\lsdpriority47 \lsdlocked0 List Table 2 Accent 4; +\lsdpriority48 \lsdlocked0 List Table 3 Accent 4;\lsdpriority49 \lsdlocked0 List Table 4 Accent 4;\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 4;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 4; +\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 4;\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 5;\lsdpriority47 \lsdlocked0 List Table 2 Accent 5;\lsdpriority48 \lsdlocked0 List Table 3 Accent 5; +\lsdpriority49 \lsdlocked0 List Table 4 Accent 5;\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 5;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 5;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 5; +\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 6;\lsdpriority47 \lsdlocked0 List Table 2 Accent 6;\lsdpriority48 \lsdlocked0 List Table 3 Accent 6;\lsdpriority49 \lsdlocked0 List Table 4 Accent 6; +\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 6;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 6;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 6;}}{\*\datastore 010500000200000018000000 +4d73786d6c322e534158584d4c5265616465722e362e3000000000000000000000060000 d0cf11e0a1b11ae1000000000000000000000000000000003e000300feff090006000000000000000000000001000000010000000000000000100000feffffff00000000feffffff0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff @@ -436,8 +469,8 @@ fffffffffffffffffdfffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff -ffffffffffffffffffffffffffffffff52006f006f007400200045006e00740072007900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000500ffffffffffffffffffffffffec69d9888b8b3d4c859eaf6cd158be0f000000000000000000000000e0ee -b81fa567cc01feffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000 +ffffffffffffffffffffffffffffffff52006f006f007400200045006e00740072007900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000500ffffffffffffffffffffffff0c6ad98892f1d411a65f0040963251e5000000000000000000000000705c +ab3bd42cd101feffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000105000000000000}} \ No newline at end of file From f8ae6c9e4c81bcc2b77e11a79b6bfd45390e0c9f Mon Sep 17 00:00:00 2001 From: Yonghong Zhu Date: Fri, 18 Dec 2015 06:51:00 +0000 Subject: [PATCH 282/525] Revert the change in r19143 for BUILDRULEORDER. (Sync patch r19150 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Yonghong Zhu git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19380 6f19259b-4bc3-4df7-8a09-765794883524 --- BaseTools/Source/Python/AutoGen/AutoGen.py | 27 ---------------------- 1 file changed, 27 deletions(-) diff --git a/BaseTools/Source/Python/AutoGen/AutoGen.py b/BaseTools/Source/Python/AutoGen/AutoGen.py index cf0b4466f992..4c627dfb555a 100644 --- a/BaseTools/Source/Python/AutoGen/AutoGen.py +++ b/BaseTools/Source/Python/AutoGen/AutoGen.py @@ -2713,36 +2713,9 @@ def _GetSourceFileList(self): if F.Dir not in self.IncludePathList and self.AutoGenVersion >= 0x00010005: self.IncludePathList.insert(0, F.Dir) self._SourceFileList.append(F) - - self._MatchBuildRuleOrder(self._SourceFileList) - - for F in self._SourceFileList: self._ApplyBuildRule(F, TAB_UNKNOWN_FILE) return self._SourceFileList - def _MatchBuildRuleOrder(self, FileList): - Order_Dict = {} - self._GetModuleBuildOption() - for SingleFile in FileList: - if self.BuildRuleOrder and SingleFile.Ext in self.BuildRuleOrder: - key = SingleFile.Path.split(SingleFile.Ext)[0] - if key in Order_Dict: - Order_Dict[key].append(SingleFile.Ext) - else: - Order_Dict[key] = [SingleFile.Ext] - - RemoveList = [] - for F in Order_Dict: - if len(Order_Dict[F]) > 1: - Order_Dict[F].sort(key=lambda i: self.BuildRuleOrder.index(i)) - for Ext in Order_Dict[F][1:]: - RemoveList.append(F + Ext) - - for item in RemoveList: - FileList.remove(item) - - return FileList - ## Return the list of unicode files def _GetUnicodeFileList(self): if self._UnicodeFileList == None: From 033469d9a9ed257afe3073e9d97ef4a85cbcf366 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Fri, 18 Dec 2015 06:51:36 +0000 Subject: [PATCH 283/525] BaseTools GCC: avoid the use of COMMON symbols The default behavior of the GCC compiler is to emit uninitialized globals with external linkage into a COMMON section, where duplicate definitions are merged. This may result in unexpected behavior, since global variables defined under the same name in different C files may not refer to the same logical data item. For instance, the definitions of EFI_EVENT mVirtualAddressChangeEvent that [used to] appear in the following files: CryptoPkg/Library/BaseCryptLib/SysCall/RuntimeMemAllocation.c MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c will be folded into a single instance of the variable when the latter module includes the former library, which can lead to unexpected results. Even if some may argue that there are legal uses for COMMON allocation, the high modularity of EDK2 combined with the low level of awareness of the intracicies surrounding common allocation and the generally poor EDK2 developer discipline regarding the use of the STATIC keyword* make a strong case for disabling it by default, and re-enabling it explicitly for packages that depend on it. So prevent GCC from emitting variables into the COMMON section, by passing -fno-common to the compiler, and discarding the section in the GNU ld linker script. * Any function or variable that is only referenced from the translation unit that defines it could be made STATIC. This does not only prevent issues like the above, it also allows the compiler to generate better code, e.g., drop out of line function definitions after inlining all invocations or perform constant propagation on variables. (Sync patch r19164 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ard Biesheuvel Reviewed-by: Liming Gao Reviewed-by: Laszlo Ersek Tested-by: Laszlo Ersek git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19381 6f19259b-4bc3-4df7-8a09-765794883524 --- BaseTools/Conf/tools_def.template | 4 ++-- BaseTools/Scripts/GccBase.lds | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/BaseTools/Conf/tools_def.template b/BaseTools/Conf/tools_def.template index d6b0af43d772..1a44fbd1d3eb 100644 --- a/BaseTools/Conf/tools_def.template +++ b/BaseTools/Conf/tools_def.template @@ -4318,7 +4318,7 @@ NOOPT_DDK3790xASL_IPF_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /LTCG /DLL /OPT:REF DEBUG_*_*_OBJCOPY_ADDDEBUGFLAG = --add-gnu-debuglink=$(DEBUG_DIR)/$(MODULE_NAME).debug RELEASE_*_*_OBJCOPY_ADDDEBUGFLAG = -DEFINE GCC_ALL_CC_FLAGS = -g -Os -fshort-wchar -fno-strict-aliasing -Wall -Werror -Wno-array-bounds -c -include AutoGen.h +DEFINE GCC_ALL_CC_FLAGS = -g -Os -fshort-wchar -fno-strict-aliasing -Wall -Werror -Wno-array-bounds -c -include AutoGen.h -fno-common DEFINE GCC_IA32_CC_FLAGS = DEF(GCC_ALL_CC_FLAGS) -m32 -malign-double -freorder-blocks -freorder-blocks-and-partition -O2 -mno-stack-arg-probe DEFINE GCC_X64_CC_FLAGS = DEF(GCC_ALL_CC_FLAGS) -mno-red-zone -Wno-address -mno-stack-arg-probe DEFINE GCC_IPF_CC_FLAGS = DEF(GCC_ALL_CC_FLAGS) -minline-int-divide-min-latency @@ -4349,7 +4349,7 @@ DEFINE GCC_IPF_RC_FLAGS = -I binary -O elf64-ia64-little -B ia64 DEFINE GCC_ARM_RC_FLAGS = -I binary -O elf32-littlearm -B arm --rename-section .data=.hii DEFINE GCC_AARCH64_RC_FLAGS = -I binary -O elf64-littleaarch64 -B aarch64 --rename-section .data=.hii -DEFINE GCC44_ALL_CC_FLAGS = -g -fshort-wchar -fno-strict-aliasing -Wall -Werror -Wno-array-bounds -ffunction-sections -fdata-sections -c -include AutoGen.h -DSTRING_ARRAY_NAME=$(BASE_NAME)Strings +DEFINE GCC44_ALL_CC_FLAGS = -g -fshort-wchar -fno-strict-aliasing -Wall -Werror -Wno-array-bounds -ffunction-sections -fdata-sections -c -include AutoGen.h -fno-common -DSTRING_ARRAY_NAME=$(BASE_NAME)Strings DEFINE GCC44_IA32_CC_FLAGS = DEF(GCC44_ALL_CC_FLAGS) -m32 -malign-double -fno-stack-protector -D EFI32 -fno-asynchronous-unwind-tables DEFINE GCC44_X64_CC_FLAGS = DEF(GCC44_ALL_CC_FLAGS) -m64 -fno-stack-protector "-DEFIAPI=__attribute__((ms_abi))" -DNO_BUILTIN_VA_FUNCS -mno-red-zone -Wno-address -mcmodel=large -fno-asynchronous-unwind-tables DEFINE GCC44_IA32_X64_DLINK_COMMON = -nostdlib -n -q --gc-sections -z common-page-size=0x20 diff --git a/BaseTools/Scripts/GccBase.lds b/BaseTools/Scripts/GccBase.lds index 4ee6d998532c..32310bc75dcc 100644 --- a/BaseTools/Scripts/GccBase.lds +++ b/BaseTools/Scripts/GccBase.lds @@ -46,7 +46,7 @@ SECTIONS { */ .data ALIGN(ALIGNOF(.text)) : ALIGN(CONSTANT(COMMONPAGESIZE)) { *(.data .data.* .gnu.linkonce.d.*) - *(.bss .bss.* *COM*) + *(.bss .bss.*) } .eh_frame ALIGN(CONSTANT(COMMONPAGESIZE)) : { @@ -66,5 +66,6 @@ SECTIONS { *(.dynamic) *(.hash) *(.comment) + *(COMMON) } } From 8bc5c95c550103317b739d3d620b189d03121062 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Fri, 18 Dec 2015 06:52:09 +0000 Subject: [PATCH 284/525] BaseTools RVCT: use scatter file to enforce minimum section alignment Up until SVN r18540, GenFw created invalid PE/COFF binaries for the ARM architecture, by allowing PE/COFF .data sections to appear at offsets that were not aligned to the global PE/COFF section alignment. The reason for this was that the relocation metadata emitted by RVCT's armlink only contains dynamic absolute relocations, so it is impossible to recalculate relative relocations between .text and .data, and so the relative offset between the two needs to be preserved. Since r18540, we do align .data to the PE/COFF section alignment, resulting in potentially corrupt PE/COFF binaries unless .data happens to appear at a 32-byte aligned offset. So let's introduce a RVCT scatter file that sets this alignment for the ELF .data section (and subsequent .bss section). At the same time, set the start offset to 0x220 bytes (which is the size of our 32-bit PE/COFF header) so that the memory layouts are identical between ELF and PE/COFF. Also add a 4 KB aligned version that can be used to build DXE_RUNTIME_DRIVER modules with runtime memory protection enabled. (Sync patch r19235 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ard Biesheuvel Reviewed-by: Eugene Cohen Reviewed-by: Liming Gao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19382 6f19259b-4bc3-4df7-8a09-765794883524 --- BaseTools/Conf/tools_def.template | 2 +- BaseTools/Scripts/Rvct-Align32.sct | 25 +++++++++++++++++++++++++ BaseTools/Scripts/Rvct-Align4K.sct | 25 +++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 BaseTools/Scripts/Rvct-Align32.sct create mode 100644 BaseTools/Scripts/Rvct-Align4K.sct diff --git a/BaseTools/Conf/tools_def.template b/BaseTools/Conf/tools_def.template index 1a44fbd1d3eb..fc79bd660142 100644 --- a/BaseTools/Conf/tools_def.template +++ b/BaseTools/Conf/tools_def.template @@ -7128,7 +7128,7 @@ RELEASE_XCODE5_X64_CC_FLAGS = -target x86_64-pc-win32-macho -c -Os -W DEFINE RVCT_ALL_ASM_FLAGS = --diag_suppress=1786 --diag_error=warning --apcs /interwork DEFINE RVCT_ALL_CC_FLAGS = --c90 -c --no_autoinline --asm --gnu --apcs /interwork --signed_chars --no_unaligned_access --split_sections --enum_is_int --preinclude AutoGen.h --diag_suppress=186 --diag_warning 167 --diag_error=warning --diag_style=ide --protect_stack -DEFINE RVCT_ALL_DLINK_FLAGS = --ro-base 0 --no_scanlib --reloc --no_exceptions --datacompressor off --strict --symbols --diag_style=ide --no_legacyalign +DEFINE RVCT_ALL_DLINK_FLAGS = --no_scanlib --no_exceptions --datacompressor off --strict --symbols --diag_style=ide --no_legacyalign --scatter $(EDK_TOOLS_PATH)/Scripts/Rvct-Align32.sct #################################################################################### # diff --git a/BaseTools/Scripts/Rvct-Align32.sct b/BaseTools/Scripts/Rvct-Align32.sct new file mode 100644 index 000000000000..4f29ad416b82 --- /dev/null +++ b/BaseTools/Scripts/Rvct-Align32.sct @@ -0,0 +1,25 @@ +/** @file + + Copyright (c) 2015, Linaro Ltd. All rights reserved.
+ + This program and the accompanying materials are licensed and made available under + the terms and conditions of the BSD License that accompanies this distribution. + The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +REGION 0x220 RELOC { + ER_RO +0 ALIGN 32 { + * (+RO) + } + ER_RW +0 ALIGN 32 { + * (+RW) + } + ER_ZI +0 { + * (+ZI) + } +} diff --git a/BaseTools/Scripts/Rvct-Align4K.sct b/BaseTools/Scripts/Rvct-Align4K.sct new file mode 100644 index 000000000000..83f5a0d5e4cd --- /dev/null +++ b/BaseTools/Scripts/Rvct-Align4K.sct @@ -0,0 +1,25 @@ +/** @file + + Copyright (c) 2015, Linaro Ltd. All rights reserved.
+ + This program and the accompanying materials are licensed and made available under + the terms and conditions of the BSD License that accompanies this distribution. + The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +REGION 0x1000 RELOC { + ER_RO +0 ALIGN 4096 { + * (+RO) + } + ER_RW +0 ALIGN 4096 { + * (+RW) + } + ER_ZI +0 { + * (+ZI) + } +} From 7f33c1d949d8ce1f1bff57a230d42d1c2ac1b1f8 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Fri, 18 Dec 2015 06:52:50 +0000 Subject: [PATCH 285/525] BaseTools/GenFw RVCT: fix relocation processing of PT_DYNAMIC sections Unlike GNU ld, which can be instructed to emit symbol based static relocations into fully linked binaries using the --emit-relocs command line switch, the RVCT armlink tool can only emit dynamic relocations into the PT_DYNAMIC segment. This has two consequences . we can only identify absolute relocations, so there is no way to fix up relative relocations between sections, or check their validity in the PE/COFF layout . the r_offset fields of the PT_DYNAMIC DT_REL entries are relative either to the base of the image or to any of its segments but *not* to the base of the input section that contains the location they refer to, and converting them to PE/COFF image offsets is non-trivial unless the sections are laid out in the same way in the ELF and PE/COFF versions of the binary. There is really only one way to deal with this, and that is to require that the ELF and PE/COFF versions of the binary are identical in memory. So enforce that in the code. Also, fix the utterly broken relocation fixup code that dereferences ELF32_R_SYM(r_info) both as a 1-based program header index and a 0-based section header index. If this code ever produced working binaries, it was purely by chance. (Sync patch r19236 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ard Biesheuvel Reviewed-by: Liming Gao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19383 6f19259b-4bc3-4df7-8a09-765794883524 --- BaseTools/Source/C/GenFw/Elf32Convert.c | 36 ++++++++++++++++++------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/BaseTools/Source/C/GenFw/Elf32Convert.c b/BaseTools/Source/C/GenFw/Elf32Convert.c index 469394540e6a..eede64576940 100644 --- a/BaseTools/Source/C/GenFw/Elf32Convert.c +++ b/BaseTools/Source/C/GenFw/Elf32Convert.c @@ -804,9 +804,7 @@ WriteRelocations32 ( UINTN RelSize; UINTN RelOffset; UINTN K; - UINT8 *Targ; Elf32_Phdr *DynamicSegment; - Elf32_Phdr *TargetSegment; for (Index = 0, FoundRelocations = FALSE; Index < mEhdr->e_shnum; Index++) { Elf_Shdr *RelShdr = GetShdrByIndex(Index); @@ -957,6 +955,31 @@ WriteRelocations32 ( Error (NULL, 0, 3000, "Invalid", "%s bad ARM dynamic relocations.", mInImageName); } + for (Index = 0; Index < mEhdr->e_shnum; Index++) { + Elf_Shdr *shdr = GetShdrByIndex(Index); + + // + // The PT_DYNAMIC section contains DT_REL relocations whose r_offset + // field is relative to the base of a segment (or the entire image), + // and not to the base of an ELF input section as is the case for + // SHT_REL sections. This means that we cannot fix up such relocations + // unless we cross-reference ELF sections and segments, considering + // that the output placement recorded in mCoffSectionsOffset[] is + // section based, not segment based. + // + // Fortunately, there is a simple way around this: we require that the + // in-memory layout of the ELF and PE/COFF versions of the binary is + // identical. That way, r_offset will retain its validity as a PE/COFF + // image offset, and we can record it in the COFF fixup table + // unmodified. + // + if (shdr->sh_addr != mCoffSectionsOffset[Index]) { + Error (NULL, 0, 3000, + "Invalid", "%s: PT_DYNAMIC relocations require identical ELF and PE/COFF section offsets.", + mInImageName); + } + } + for (K = 0; K < RelSize; K += RelElementSize) { if (DynamicSegment->p_paddr == 0) { @@ -973,14 +996,7 @@ WriteRelocations32 ( break; case R_ARM_RABS32: - TargetSegment = GetPhdrByIndex (ELF32_R_SYM (Rel->r_info) - 1); - - // Note: r_offset in a memory address. Convert it to a pointer in the coff file. - Targ = mCoffFile + mCoffSectionsOffset[ ELF32_R_SYM( Rel->r_info ) ] + Rel->r_offset - TargetSegment->p_vaddr; - - *(UINT32 *)Targ = *(UINT32 *)Targ + mCoffSectionsOffset [ELF32_R_SYM( Rel->r_info )]; - - CoffAddFixup (mCoffSectionsOffset[ELF32_R_SYM (Rel->r_info)] + (Rel->r_offset - TargetSegment->p_vaddr), EFI_IMAGE_REL_BASED_HIGHLOW); + CoffAddFixup (Rel->r_offset, EFI_IMAGE_REL_BASED_HIGHLOW); break; default: From 336e74a8acb29568004d64eeca1067bdcfdfad70 Mon Sep 17 00:00:00 2001 From: Hess Chen Date: Fri, 18 Dec 2015 06:53:30 +0000 Subject: [PATCH 286/525] BaseTools/Ecc: Fix a bug to report fake issue Fix a bug to ignore the lib ins defined in [components] section but also listed in SkipDir (Sync patch r19238 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Hess Chen Reviewed-by: Yonghong Zhu git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19384 6f19259b-4bc3-4df7-8a09-765794883524 --- BaseTools/Source/Python/Ecc/Check.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/BaseTools/Source/Python/Ecc/Check.py b/BaseTools/Source/Python/Ecc/Check.py index 5e5c8e72e400..a69ae344a3c3 100644 --- a/BaseTools/Source/Python/Ecc/Check.py +++ b/BaseTools/Source/Python/Ecc/Check.py @@ -653,6 +653,10 @@ def MetaDataFileCheckLibraryInstanceDependent(self): continue else: LibraryIns = os.path.normpath(mws.join(EccGlobalData.gWorkspace, LibraryClass[2])) + SkipDirString = '|'.join(EccGlobalData.gConfig.SkipDirList) + p = re.compile(r'.*[\\/](?:%s^\S)[\\/]?.*' % SkipDirString) + if p.match(os.path.split(LibraryIns)[0].upper()): + continue SqlCommand = """select Value3 from Inf where BelongsToFile = (select ID from File where lower(FullPath) = lower('%s')) and Value2 = '%s'""" % (LibraryIns, 'LIBRARY_CLASS') From 4bf20e4d6fbc1308527cbfab0d868ef13953870f Mon Sep 17 00:00:00 2001 From: Jordan Justen Date: Fri, 18 Dec 2015 06:54:03 +0000 Subject: [PATCH 287/525] BaseTools/Scripts: Add ConvertUni.py script This script uses python codecs to convert .uni string files between the utf-16 and utf-8 formats. The advantages of utf-8 data: * Generally smaller files * More commonly supported by editors * Not treated as binary data in patch files The script was tested on MdePkg with both python 2.7 and python 3.4. It was able to convert all MdePkg .uni files between utf-8 and utf-16 multiple times always producing the same files for each format. v2: * Rename ConvertUtf16ToUtf8.py to ConvertUni.py * Also support utf-8 to utf-16 conversion (with --utf-16) (Sync patch r19247 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jordan Justen Reviewed-by: Jaben Carsey Reviewed-by: Michael Kinney Reviewed-by: Yonghong Zhu git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19385 6f19259b-4bc3-4df7-8a09-765794883524 --- BaseTools/Scripts/ConvertUni.py | 137 ++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100755 BaseTools/Scripts/ConvertUni.py diff --git a/BaseTools/Scripts/ConvertUni.py b/BaseTools/Scripts/ConvertUni.py new file mode 100755 index 000000000000..2af55dfc6702 --- /dev/null +++ b/BaseTools/Scripts/ConvertUni.py @@ -0,0 +1,137 @@ +## @file +# Check a patch for various format issues +# +# Copyright (c) 2015, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials are licensed and made +# available under the terms and conditions of the BSD License which +# accompanies this distribution. The full text of the license may be +# found at http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" +# BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER +# EXPRESS OR IMPLIED. +# + +from __future__ import print_function + +VersionNumber = '0.1' +__copyright__ = "Copyright (c) 2015, Intel Corporation All rights reserved." + +import argparse +import codecs +import os +import sys + +try: + from io import StringIO +except ImportError: + from StringIO import StringIO + +class ConvertOneArg: + """Converts utf-16 to utf-8 for one command line argument. + + This could be a single file, or a directory. + """ + + def __init__(self, utf8, source): + self.utf8 = utf8 + self.source = source + + self.ok = True + + if not os.path.exists(source): + self.ok = False + elif os.path.isdir(source): + for (root, dirs, files) in os.walk(source): + files = filter(lambda a: a.endswith('.uni'), files) + for filename in files: + path = os.path.join(root, filename) + self.ok &= self.convert_one_file(path) + if not self.ok: + break + + if not self.ok: + break + else: + self.ok &= self.convert_one_file(source) + + def convert_one_file(self, source): + if self.utf8: + new_enc, old_enc = 'utf-8', 'utf-16' + else: + new_enc, old_enc = 'utf-16', 'utf-8' + # + # Read file + # + f = open(source, mode='rb') + file_content = f.read() + f.close() + + # + # Detect UTF-16 Byte Order Mark at beginning of file. + # + bom = (file_content.startswith(codecs.BOM_UTF16_BE) or + file_content.startswith(codecs.BOM_UTF16_LE)) + if bom != self.utf8: + print("%s: already %s" % (source, new_enc)) + return True + + # + # Decode old string data + # + str_content = file_content.decode(old_enc, 'ignore') + + # + # Encode new string data + # + new_content = str_content.encode(new_enc, 'ignore') + + # + # Write converted data back to file + # + f = open(source, mode='wb') + f.write(new_content) + f.close() + + print(source + ": converted, size", len(file_content), '=>', len(new_content)) + return True + + +class ConvertUniApp: + """Converts .uni files between utf-16 and utf-8.""" + + def __init__(self): + self.parse_options() + sources = self.args.source + + self.ok = True + for patch in sources: + self.process_one_arg(patch) + + if self.ok: + self.retval = 0 + else: + self.retval = -1 + + def process_one_arg(self, arg): + self.ok &= ConvertOneArg(self.utf8, arg).ok + + def parse_options(self): + parser = argparse.ArgumentParser(description=__copyright__) + parser.add_argument('--version', action='version', + version='%(prog)s ' + VersionNumber) + parser.add_argument('source', nargs='+', + help='[uni file | directory]') + group = parser.add_mutually_exclusive_group() + group.add_argument("--utf-8", + action="store_true", + help="Convert from utf-16 to utf-8 [default]") + group.add_argument("--utf-16", + action="store_true", + help="Convert from utf-8 to utf-16") + self.args = parser.parse_args() + self.utf8 = not self.args.utf_16 + +if __name__ == "__main__": + sys.exit(ConvertUniApp().retval) From 075c88d540f90f98800f537c9e5a95eac1e75a37 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Fri, 18 Dec 2015 06:54:36 +0000 Subject: [PATCH 288/525] BaseTools ARM: add CLANG35 support This extends the existing CLANG35 toolchain definition with support for building for the ARM architecture. In order to be able to reuse the existing ARM GCC definitions as much as possible, the following changes have been made to the existing ARM GCC support: - the -mapcs option has been removed; it is a no-op under Thumb (our default) and we use AAPCS (-mabi=aapcs) anyway - the -mword-relocations option has been moved from GCC_ARM_CC_FLAGS to the GCC4x specific option: CLANG does not support it, and uses '-mllvm -marm-use-movt=0' instead. (Sync patch r19284 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ard Biesheuvel Reviewed-by: Leif Lindholm Reviewed-by: Liming Gao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19386 6f19259b-4bc3-4df7-8a09-765794883524 --- BaseTools/Conf/tools_def.template | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/BaseTools/Conf/tools_def.template b/BaseTools/Conf/tools_def.template index fc79bd660142..6e26bbca934b 100644 --- a/BaseTools/Conf/tools_def.template +++ b/BaseTools/Conf/tools_def.template @@ -366,7 +366,7 @@ DEFINE SOURCERY_CYGWIN_TOOLS = /cygdrive/c/Program Files/CodeSourcery/Sourcery G # Intel(r) ACPI Compiler from # https://acpica.org/downloads # CLANG35 -Linux,Windows- Requires: -# Clang v3.5 or later, and GNU binutils targeting aarch64-linux-gnu +# Clang v3.5 or later, and GNU binutils targeting aarch64-linux-gnu or arm-linux-gnueabi # Optional: # Required to build platforms or ACPI tables: # Intel(r) ACPI Compiler from @@ -4322,7 +4322,7 @@ DEFINE GCC_ALL_CC_FLAGS = -g -Os -fshort-wchar -fno-strict-aliasing - DEFINE GCC_IA32_CC_FLAGS = DEF(GCC_ALL_CC_FLAGS) -m32 -malign-double -freorder-blocks -freorder-blocks-and-partition -O2 -mno-stack-arg-probe DEFINE GCC_X64_CC_FLAGS = DEF(GCC_ALL_CC_FLAGS) -mno-red-zone -Wno-address -mno-stack-arg-probe DEFINE GCC_IPF_CC_FLAGS = DEF(GCC_ALL_CC_FLAGS) -minline-int-divide-min-latency -DEFINE GCC_ARM_CC_FLAGS = DEF(GCC_ALL_CC_FLAGS) -mword-relocations -mlittle-endian -mabi=aapcs -mapcs -fno-short-enums -save-temps -fsigned-char -ffunction-sections -fdata-sections -fomit-frame-pointer -Wno-address -mthumb -mfloat-abi=soft +DEFINE GCC_ARM_CC_FLAGS = DEF(GCC_ALL_CC_FLAGS) -mlittle-endian -mabi=aapcs -fno-short-enums -save-temps -fsigned-char -ffunction-sections -fdata-sections -fomit-frame-pointer -Wno-address -mthumb -mfloat-abi=soft DEFINE GCC_AARCH64_CC_FLAGS = DEF(GCC_ALL_CC_FLAGS) -mlittle-endian -fno-short-enums -save-temps -fverbose-asm -fsigned-char -ffunction-sections -fdata-sections -fomit-frame-pointer -fno-builtin -Wno-address -fno-asynchronous-unwind-tables DEFINE GCC_DLINK_FLAGS_COMMON = -nostdlib --pie DEFINE GCC_DLINK2_FLAGS_COMMON = --script=$(EDK_TOOLS_PATH)/Scripts/GccBase.lds @@ -4380,7 +4380,7 @@ DEFINE GCC46_X64_DLINK_FLAGS = DEF(GCC45_X64_DLINK_FLAGS) DEFINE GCC46_X64_DLINK2_FLAGS = DEF(GCC45_X64_DLINK2_FLAGS) DEFINE GCC46_ASM_FLAGS = DEF(GCC45_ASM_FLAGS) DEFINE GCC46_ARM_ASM_FLAGS = $(ARCHASM_FLAGS) $(PLATFORM_FLAGS) DEF(GCC_ASM_FLAGS) -mlittle-endian -DEFINE GCC46_ARM_CC_FLAGS = $(ARCHCC_FLAGS) $(PLATFORM_FLAGS) DEF(GCC44_ALL_CC_FLAGS) DEF(GCC_ARM_CC_FLAGS) -fstack-protector +DEFINE GCC46_ARM_CC_FLAGS = $(ARCHCC_FLAGS) $(PLATFORM_FLAGS) DEF(GCC44_ALL_CC_FLAGS) DEF(GCC_ARM_CC_FLAGS) -fstack-protector -mword-relocations DEFINE GCC46_ARM_DLINK_FLAGS = DEF(GCC_ARM_DLINK_FLAGS) --oformat=elf32-littlearm DEFINE GCC46_ARM_DLINK2_FLAGS = DEF(GCC_DLINK2_FLAGS_COMMON) --defsym=PECOFF_HEADER_SIZE=0x220 DEFINE GCC46_ARM_ASLDLINK_FLAGS = DEF(GCC_ARM_ASLDLINK_FLAGS) --oformat=elf32-littlearm @@ -5184,8 +5184,30 @@ RELEASE_GCC49_AARCH64_CC_FLAGS = DEF(GCC49_AARCH64_CC_FLAGS) -Wno-unused-but-s *_CLANG35_*_ASLPP_PATH = ENV(CLANG35_BIN)clang DEFINE CLANG35_WARNING_OVERRIDES = -Wno-parentheses-equality -Wno-tautological-compare -Wno-tautological-constant-out-of-range-compare -Wno-empty-body +DEFINE CLANG35_ARM_CC_FLAGS = DEF(GCC_ARM_CC_FLAGS) -target armv7-a -mstrict-align -mllvm -arm-use-movt=0 DEF(CLANG35_WARNING_OVERRIDES) DEFINE CLANG35_AARCH64_CC_FLAGS = DEF(GCC_AARCH64_CC_FLAGS) -target aarch64 -mcmodel=small -mstrict-align DEF(CLANG35_WARNING_OVERRIDES) +################## +# CLANG35 ARM definitions +################## +*_CLANG35_ARM_SLINK_PATH = ENV(CLANG35_ARM_PREFIX)ar +*_CLANG35_ARM_DLINK_PATH = ENV(CLANG35_ARM_PREFIX)ld +*_CLANG35_ARM_ASLDLINK_PATH = ENV(CLANG35_ARM_PREFIX)ld +*_CLANG35_ARM_RC_PATH = ENV(CLANG35_ARM_PREFIX)objcopy + +*_CLANG35_ARM_ASLCC_FLAGS = DEF(GCC_ASLCC_FLAGS) +*_CLANG35_ARM_ASLDLINK_FLAGS = DEF(GCC_ARM_ASLDLINK_FLAGS) +*_CLANG35_ARM_ASM_FLAGS = DEF(GCC_ASM_FLAGS) $(ARCHASM_FLAGS) $(PLATFORM_FLAGS) -target armv7-a -Qunused-arguments +*_CLANG35_ARM_DLINK_FLAGS = DEF(GCC_ARM_DLINK_FLAGS) +*_CLANG35_ARM_DLINK2_FLAGS = DEF(GCC_DLINK2_FLAGS_COMMON) --defsym=PECOFF_HEADER_SIZE=0x220 +*_CLANG35_ARM_PLATFORM_FLAGS = +*_CLANG35_ARM_PP_FLAGS = DEF(GCC_PP_FLAGS) $(ARCHCC_FLAGS) $(PLATFORM_FLAGS) +*_CLANG35_ARM_RC_FLAGS = DEF(GCC_ARM_RC_FLAGS) +*_CLANG35_ARM_VFRPP_FLAGS = DEF(GCC_VFRPP_FLAGS) $(ARCHCC_FLAGS) $(PLATFORM_FLAGS) + + DEBUG_CLANG35_ARM_CC_FLAGS = DEF(CLANG35_ARM_CC_FLAGS) $(ARCHCC_FLAGS) $(PLATFORM_FLAGS) -O0 +RELEASE_CLANG35_ARM_CC_FLAGS = DEF(CLANG35_ARM_CC_FLAGS) $(ARCHCC_FLAGS) $(PLATFORM_FLAGS) -Oz + ################## # CLANG35 AARCH64 definitions ################## From d33e7a2627cc25284e8412d94157fae7c9eac1e3 Mon Sep 17 00:00:00 2001 From: Yonghong Zhu Date: Fri, 18 Dec 2015 06:55:09 +0000 Subject: [PATCH 289/525] BaseTools: Fix one bug in FD region for multiple workspace support Update the os.path.join to mws.join for FILE/INF/CAPSULE/FV region type. (Sync patch r19319 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Yonghong Zhu Reviewed-by: Liming Gao git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19387 6f19259b-4bc3-4df7-8a09-765794883524 --- BaseTools/Source/Python/GenFds/Region.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/BaseTools/Source/Python/GenFds/Region.py b/BaseTools/Source/Python/GenFds/Region.py index 8734635fda29..6015e24e25a5 100644 --- a/BaseTools/Source/Python/GenFds/Region.py +++ b/BaseTools/Source/Python/GenFds/Region.py @@ -73,7 +73,7 @@ def AddToBuffer(self, Buffer, BaseAddress, BlockSizeList, ErasePolarity, ImageBi RegionData = GenFdsGlobalVariable.MacroExtend(RegionData, MacroDict) GenFdsGlobalVariable.InfLogger(' Region FV File Name = .fv : %s' % RegionData) if RegionData[1] != ':' : - RegionData = os.path.join (GenFdsGlobalVariable.WorkSpaceDir, RegionData) + RegionData = mws.join (GenFdsGlobalVariable.WorkSpaceDir, RegionData) if not os.path.exists(RegionData): EdkLogger.error("GenFds", FILE_NOT_FOUND, ExtraData=RegionData) @@ -152,7 +152,7 @@ def AddToBuffer(self, Buffer, BaseAddress, BlockSizeList, ErasePolarity, ImageBi RegionData = GenFdsGlobalVariable.MacroExtend(RegionData, MacroDict) GenFdsGlobalVariable.InfLogger(' Region CAPSULE Image Name = .cap : %s' % RegionData) if RegionData[1] != ':' : - RegionData = os.path.join (GenFdsGlobalVariable.WorkSpaceDir, RegionData) + RegionData = mws.join (GenFdsGlobalVariable.WorkSpaceDir, RegionData) if not os.path.exists(RegionData): EdkLogger.error("GenFds", FILE_NOT_FOUND, ExtraData=RegionData) @@ -213,7 +213,7 @@ def AddToBuffer(self, Buffer, BaseAddress, BlockSizeList, ErasePolarity, ImageBi else: RegionData = GenFdsGlobalVariable.MacroExtend(RegionData, MacroDict) if RegionData[1] != ':' : - RegionData = os.path.join (GenFdsGlobalVariable.WorkSpaceDir, RegionData) + RegionData = mws.join (GenFdsGlobalVariable.WorkSpaceDir, RegionData) if not os.path.exists(RegionData): EdkLogger.error("GenFds", FILE_NOT_FOUND, ExtraData=RegionData) # From 0d2f9e91bf2bb40a09840fe4c80eadb001d696dc Mon Sep 17 00:00:00 2001 From: Jeff Fan Date: Fri, 18 Dec 2015 07:01:30 +0000 Subject: [PATCH 290/525] External link to BaseTools Win binary r112(main trunk r19319) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19388 6f19259b-4bc3-4df7-8a09-765794883524 --- BaseTools/Bin/externals.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BaseTools/Bin/externals.txt b/BaseTools/Bin/externals.txt index c2c4ab729732..146687fa930d 100644 --- a/BaseTools/Bin/externals.txt +++ b/BaseTools/Bin/externals.txt @@ -1 +1 @@ -Win32 https://svn.code.sf.net/p/edk2-toolbinaries/code/trunk/Win32 +Win32 -r 112 https://svn.code.sf.net/p/edk2-toolbinaries/code/trunk/Win32 From b73e1f6915b2cc49e9a8bc5c379e63cefc5013be Mon Sep 17 00:00:00 2001 From: Laszlo Ersek Date: Fri, 18 Dec 2015 07:25:22 +0000 Subject: [PATCH 291/525] ShellPkg: UefiShellTftpCommandLib: fix incompatible pointer assignment Add the missing EFIAPI calling convention to the CheckPacket() function. Without it, the gcc build breaks due to the incompatible pointer assignment in "Mtftp4Token.CheckPacket = CheckPacket". (Sync patch r18553 from main trunk.) Cc: Jaben Carsey Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Laszlo Ersek Reviewed-by: Jaben Carsey Reviewed-by: Jordan Justen git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19389 6f19259b-4bc3-4df7-8a09-765794883524 --- ShellPkg/Library/UefiShellTftpCommandLib/Tftp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ShellPkg/Library/UefiShellTftpCommandLib/Tftp.c b/ShellPkg/Library/UefiShellTftpCommandLib/Tftp.c index 2dc9287020d7..4bb21aae6fb6 100644 --- a/ShellPkg/Library/UefiShellTftpCommandLib/Tftp.c +++ b/ShellPkg/Library/UefiShellTftpCommandLib/Tftp.c @@ -197,6 +197,7 @@ DownloadFile ( **/ STATIC EFI_STATUS +EFIAPI CheckPacket ( IN EFI_MTFTP4_PROTOCOL *This, IN EFI_MTFTP4_TOKEN *Token, @@ -940,6 +941,7 @@ Error : **/ STATIC EFI_STATUS +EFIAPI CheckPacket ( IN EFI_MTFTP4_PROTOCOL *This, IN EFI_MTFTP4_TOKEN *Token, From e2ef42aad648f01d8d41093d02c62a93b9904dc3 Mon Sep 17 00:00:00 2001 From: Qiu Shumin Date: Fri, 18 Dec 2015 07:26:39 +0000 Subject: [PATCH 292/525] ShellPkg: Build all libraries unconditionally. Build all the optional libraries unconditionally so we can catch changes and how they affect the package regardless of the NO_SHELL_PROFILES, INCLUDE_DP, and INCLUDE_TFTP_COMMAND settings. (Sync patch r18557 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Qiu Shumin Signed-off-by: Jaben Carsey Reviewed-by: Laszlo Ersek git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19390 6f19259b-4bc3-4df7-8a09-765794883524 --- ShellPkg/ShellPkg.dsc | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/ShellPkg/ShellPkg.dsc b/ShellPkg/ShellPkg.dsc index c9ed0f8fbafc..7e07cfb43778 100644 --- a/ShellPkg/ShellPkg.dsc +++ b/ShellPkg/ShellPkg.dsc @@ -1,7 +1,7 @@ ## @file # Shell Package # -# Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.
+# Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.
# # This program and the accompanying materials # are licensed and made available under the terms and conditions of the BSD License @@ -74,10 +74,21 @@ !endif #$(NO_SHELL_PROFILES) [Components] + # + # Build all the libraries when building this package. + # This helps developers test changes and how they affect the package. + # ShellPkg/Library/UefiShellLib/UefiShellLib.inf ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.inf - ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.inf ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.inf + ShellPkg/Library/UefiShellLevel1CommandsLib/UefiShellLevel1CommandsLib.inf + ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.inf + ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.inf + ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.inf + ShellPkg/Library/UefiShellInstall1CommandsLib/UefiShellInstall1CommandsLib.inf + ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.inf + ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.inf + ShellPkg/Library/UefiShellTftpCommandLib/UefiShellTftpCommandLib.inf ShellPkg/Library/UefiDpLib/UefiDpLib.inf { From 8368182d00a164b7b4d12ffc2c3c65cd51e749a7 Mon Sep 17 00:00:00 2001 From: Ruiyu Ni Date: Fri, 18 Dec 2015 07:27:10 +0000 Subject: [PATCH 293/525] ShellPkg: Add a simple case to test shell parameter parsing logic TestArgv.nsh is a very simple shell script to test how the interpreter parses the parameters. It uses ShellCTestApp.efi to dump the parameters passed from the interpreter. TestArgv.log is the desired output created using "TestArgv.nsh > TestArgv.log". (Sync patch r18558 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ruiyu Ni Reviewed-by: Jaben Carsey git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19391 6f19259b-4bc3-4df7-8a09-765794883524 --- ShellPkg/Application/ShellCTestApp/README.txt | 5 ++ .../Application/ShellCTestApp/ShellCTestApp.c | 11 +-- .../Application/ShellCTestApp/TestArgv.log | Bin 0 -> 3320 bytes .../Application/ShellCTestApp/TestArgv.nsh | 64 ++++++++++++++++++ 4 files changed, 75 insertions(+), 5 deletions(-) create mode 100644 ShellPkg/Application/ShellCTestApp/README.txt create mode 100644 ShellPkg/Application/ShellCTestApp/TestArgv.log create mode 100644 ShellPkg/Application/ShellCTestApp/TestArgv.nsh diff --git a/ShellPkg/Application/ShellCTestApp/README.txt b/ShellPkg/Application/ShellCTestApp/README.txt new file mode 100644 index 000000000000..7814bb838605 --- /dev/null +++ b/ShellPkg/Application/ShellCTestApp/README.txt @@ -0,0 +1,5 @@ +TestArgv.nsh is a very simple shell script to test how the interpreter parses +the parameters. It uses ShellCTestApp.efi to dump the parameters passed from the +intepreter. + +TestArgv.log is the desired output created using "TestArgv.nsh > TestArgv.log". \ No newline at end of file diff --git a/ShellPkg/Application/ShellCTestApp/ShellCTestApp.c b/ShellPkg/Application/ShellCTestApp/ShellCTestApp.c index 8d3fa4c6621a..08c830cfb79a 100644 --- a/ShellPkg/Application/ShellCTestApp/ShellCTestApp.c +++ b/ShellPkg/Application/ShellCTestApp/ShellCTestApp.c @@ -2,7 +2,7 @@ This is a test application that demonstrates how to use the C-style entry point for a shell application. - Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+ Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -40,10 +40,11 @@ ShellAppMain ( ) { UINTN Index; - - Print(L"ShellCTestApp.c:ShellAppMain called with %d parameters\n", Argc); - for (Index = 0; Index < Argc; Index++) { - Print(L"Argv[%d]: %s\n", Index, Argv[Index]); + if (Argc == 1) { + Print (L"Argv[1] = NULL\n"); + } + for (Index = 1; Index < Argc; Index++) { + Print(L"Argv[%d]: \"%s\"\n", Index, Argv[Index]); } return 0; diff --git a/ShellPkg/Application/ShellCTestApp/TestArgv.log b/ShellPkg/Application/ShellCTestApp/TestArgv.log new file mode 100644 index 0000000000000000000000000000000000000000..e76781ea0e4387cf97ad42d5ccbb8a72f99c8d61 GIT binary patch literal 3320 zcmcha-EPxB5QWcmCEmeumCH&=6Q>ChNOt0IgFvXzn?fx_-5;r<5dp;01K+G=wZUFT z4t8bPp6txdIXgS!+5Gvv(y4}eu8(@DK)Jr?M)ycZJiqFh4zz8t!R9;qGkw-KWlGU6 zxW|e#<(=u6YsOfniB5PQBgI;RVq;?^SS}e^XwK6tSG z6wbzGjsFynkz~r3x3bglzc99*ns>FZui6^ z$5YB|TUqKjByMDk?-*&K5xNLzj@B?UxXl@z5|O#n4|!TFACSWa^b?g9C`41Yx6R&)JgoC}xQDkv=M_BguC@=X z_VFub)Wt8{BYpw9>Dyh?wdWUj{k8Yy=e7?s%VdA_OxK=ax7AVIi9j!?v^V;o*Iex? zci_HvU3V0JeYCINP<_-?Kz|&lkDlgVdws7rCUrUWuxkIe(mHWBeXox7|KwFjS1x)? zS%r09qknC-&tLv^TVGjo`)hx_$9HL)bB_OC+-1c#^Us}awf4$0 +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#**/ +echo -on +set Var_EFCF356F_228C_47C2_AD0C_3B5DAC9A8CFA ValueOfGuid +set Sharp_E8528E46_A008_4221_8DE0_D5AB42A9C580 ^# +set Quote_E95DEE8B_E3AA_4155_9ED5_6916394104FC ^" +set Var_ShellCTestApp_EE6E8BC6_71A6_44A5_BED3_D8F901105CDE ShellCTestApp_EE6E8BC6_71A6_44A5_BED3_D8F901105CDE +alias ShellCTestApp_EE6E8BC6_71A6_44A5_BED3_D8F901105CDE ShellCTestApp + +# +# '^' should escape all special characters (including space) +# but has no impact to non-special characters +# +ShellCTestApp ^^ +ShellCTestApp ^# +ShellCTestApp ^%Var_EFCF356F_228C_47C2_AD0C_3B5DAC9A8CFA% +ShellCTestApp ^" +ShellCTestApp ^ 1 +ShellCTestApp ^ +ShellCTestApp ^1 +ShellCTestApp ^^^" +ShellCTestApp ^^^ + +# +# '#' should be processed before %% replacement, and inside '"' +# +ShellCTestApp #%Var_EFCF356F_228C_47C2_AD0C_3B5DAC9A8CFA% +#ShellCTestApp "#" +ShellCTestApp %Sharp_E8528E46_A008_4221_8DE0_D5AB42A9C580% + +# +# '%' should be processed before grouping parameters +# +ShellCTestApp "%Var_EFCF356F_228C_47C2_AD0C_3B5DAC9A8CFA% 2%Quote_E95DEE8B_E3AA_4155_9ED5_6916394104FC% + +# +# alias should be processed after %% replacement +# +%Var_ShellCTestApp_EE6E8BC6_71A6_44A5_BED3_D8F901105CDE% + +# +# '"' should be stripped, space inside '"' should be kept, +# +ShellCTestApp "p 1" +ShellCTestApp "p"1 +ShellCTestApp "p 1"e"x""" + +set -d Var_EFCF356F_228C_47C2_AD0C_3B5DAC9A8CFA +set -d Sharp_E8528E46_A008_4221_8DE0_D5AB42A9C580 +set -d Quote_E95DEE8B_E3AA_4155_9ED5_6916394104FC +set -d Var_ShellCTestApp_EE6E8BC6_71A6_44A5_BED3_D8F901105CDE +alias -d ShellCTestApp_EE6E8BC6_71A6_44A5_BED3_D8F901105CDE +echo -off \ No newline at end of file From 1bd38073f35107cf8d6af0b294b9f2641287683d Mon Sep 17 00:00:00 2001 From: Qiu Shumin Date: Fri, 18 Dec 2015 07:27:50 +0000 Subject: [PATCH 294/525] ShellPkg: Print error message when Shell set environment variable fail. If you try to 'set' a read only environment variable and it fails without printing any information. This patch add error message printing when 'set' environment variable fails. (Sync patch r18598 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Qiu Shumin Reviewed-by: Jaben Carsey git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19392 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Library/UefiShellLevel2CommandsLib/Set.c | 7 ++++++- .../UefiShellLevel2CommandsLib.uni | Bin 109570 -> 109742 bytes 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ShellPkg/Library/UefiShellLevel2CommandsLib/Set.c b/ShellPkg/Library/UefiShellLevel2CommandsLib/Set.c index 45948e127531..d5e6a089782a 100644 --- a/ShellPkg/Library/UefiShellLevel2CommandsLib/Set.c +++ b/ShellPkg/Library/UefiShellLevel2CommandsLib/Set.c @@ -2,7 +2,7 @@ Main file for attrib shell level 2 function. (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
- Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+ Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -141,6 +141,11 @@ ShellCommandRunSet ( // assigning one // Status = ShellSetEnvironmentVariable(KeyName, Value, ShellCommandLineGetFlag(Package, L"-v")); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SET_ERROR_SET), gShellLevel2HiiHandle, L"set", KeyName); + ShellStatus = (SHELL_STATUS) (Status & (~MAX_BIT)); + } + } else { if (KeyName != NULL) { // diff --git a/ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.uni b/ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.uni index 29563d2e21737be3c84a7e3413596a4fc8e0850b..cc2c33cda4a6bf1c4f5dbc8527dfaaab5185ca53 100644 GIT binary patch delta 93 zcmZp=!M5%u+k_{KrW>CgSD0+TAu%~mo`c_&AqWWlfjFKan89_jqps-W2b@Ne6F6B! t6B&{iau`w>6c|bv@_}SAkXM8@X?uwhqg59Gwb%>C From bd8504381c8acf81d4abfe252751a2d93ae97d0d Mon Sep 17 00:00:00 2001 From: Qiu Shumin Date: Fri, 18 Dec 2015 07:28:26 +0000 Subject: [PATCH 295/525] ShellPkg: Use safe string functions to refine 'Tftp.c' code. Safe string functions can help avoid potential buffer overflow. This patch replaces the StrCpy with StCpyS. (Sync patch r18608 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Qiu Shumin Reviewed-by: Jaben Carsey git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19393 6f19259b-4bc3-4df7-8a09-765794883524 --- ShellPkg/Library/UefiShellTftpCommandLib/Tftp.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ShellPkg/Library/UefiShellTftpCommandLib/Tftp.c b/ShellPkg/Library/UefiShellTftpCommandLib/Tftp.c index 4bb21aae6fb6..02099febef08 100644 --- a/ShellPkg/Library/UefiShellTftpCommandLib/Tftp.c +++ b/ShellPkg/Library/UefiShellTftpCommandLib/Tftp.c @@ -955,6 +955,7 @@ CheckPacket ( UINTN Index; UINTN LastStep; UINTN Step; + EFI_STATUS Status; if ((NTOHS (Packet->OpCode)) != EFI_MTFTP4_OPCODE_DATA) { return EFI_SUCCESS; @@ -984,7 +985,10 @@ CheckPacket ( ShellPrintEx (-1, -1, L"%s", mTftpProgressDelete); - StrCpy (Progress, mTftpProgressFrame); + Status = StrCpyS (Progress, TFTP_PROGRESS_MESSAGE_SIZE, mTftpProgressFrame); + if (EFI_ERROR(Status)) { + return Status; + } for (Index = 1; Index < Step; Index++) { Progress[Index] = L'='; } From 90fb9ed5a0d24117a4847b5d25bca84d8d90c5c2 Mon Sep 17 00:00:00 2001 From: Qiu Shumin Date: Fri, 18 Dec 2015 07:29:05 +0000 Subject: [PATCH 296/525] ShellPkg: Fix ASCII input redirection does not work correctly. When executing 'ls -b
Signed-off-by: Felix Poludov Signed-off-by: Oleksiy Yakovlev Reviewed-by: Jaben Carsey git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19394 6f19259b-4bc3-4df7-8a09-765794883524 --- ShellPkg/Application/Shell/ConsoleWrappers.c | 14 +++++++-- .../Application/Shell/FileHandleWrappers.c | 29 +++++++++++++++---- .../Shell/ShellParametersProtocol.c | 4 +++ 3 files changed, 39 insertions(+), 8 deletions(-) diff --git a/ShellPkg/Application/Shell/ConsoleWrappers.c b/ShellPkg/Application/Shell/ConsoleWrappers.c index feea6ef3a22e..04a7513a3346 100644 --- a/ShellPkg/Application/Shell/ConsoleWrappers.c +++ b/ShellPkg/Application/Shell/ConsoleWrappers.c @@ -2,7 +2,7 @@ Function definitions for shell simple text in and out on top of file handles. (C) Copyright 2013 Hewlett-Packard Development Company, L.P.
- Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.
+ Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -15,6 +15,8 @@ #include "Shell.h" +extern BOOLEAN AsciiRedirection; + typedef struct { EFI_SIMPLE_TEXT_INPUT_PROTOCOL SimpleTextIn; SHELL_FILE_HANDLE FileHandle; @@ -81,6 +83,7 @@ FileBasedSimpleTextInReadKeyStroke( ) { UINTN Size; + UINTN CharSize; // // Verify the parameters @@ -98,11 +101,16 @@ FileBasedSimpleTextInReadKeyStroke( Size = sizeof(CHAR16); + if(!AsciiRedirection) { + CharSize = sizeof(CHAR16); + } else { + CharSize = sizeof(CHAR8); + } // // Decrement the amount of free space by Size or set to zero (for odd length files) // - if (((SHELL_EFI_SIMPLE_TEXT_INPUT_PROTOCOL *)This)->RemainingBytesOfInputFile > Size) { - ((SHELL_EFI_SIMPLE_TEXT_INPUT_PROTOCOL *)This)->RemainingBytesOfInputFile -= Size; + if (((SHELL_EFI_SIMPLE_TEXT_INPUT_PROTOCOL *)This)->RemainingBytesOfInputFile > CharSize) { + ((SHELL_EFI_SIMPLE_TEXT_INPUT_PROTOCOL *)This)->RemainingBytesOfInputFile -= CharSize; } else { ((SHELL_EFI_SIMPLE_TEXT_INPUT_PROTOCOL *)This)->RemainingBytesOfInputFile = 0; } diff --git a/ShellPkg/Application/Shell/FileHandleWrappers.c b/ShellPkg/Application/Shell/FileHandleWrappers.c index 18b6c3e76829..91c35f7cb70a 100644 --- a/ShellPkg/Application/Shell/FileHandleWrappers.c +++ b/ShellPkg/Application/Shell/FileHandleWrappers.c @@ -1670,8 +1670,10 @@ FileInterfaceFileRead( OUT VOID *Buffer ) { - CHAR8 *AsciiBuffer; + CHAR8 *AsciiStrBuffer; + CHAR16 *UscStrBuffer; UINTN Size; + UINTN CharNum; EFI_STATUS Status; if (((EFI_FILE_PROTOCOL_FILE*)This)->Unicode) { // @@ -1682,10 +1684,27 @@ FileInterfaceFileRead( // // Ascii // - AsciiBuffer = AllocateZeroPool((Size = *BufferSize)); - Status = (((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Read(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, &Size, AsciiBuffer)); - UnicodeSPrint(Buffer, *BufferSize, L"%a", AsciiBuffer); - FreePool(AsciiBuffer); + Size = (*BufferSize) / sizeof(CHAR16); + AsciiStrBuffer = AllocateZeroPool(Size + sizeof(CHAR8)); + if (AsciiStrBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + UscStrBuffer = AllocateZeroPool(*BufferSize + sizeof(CHAR16)); + if (UscStrBuffer== NULL) { + SHELL_FREE_NON_NULL(AsciiStrBuffer); + return EFI_OUT_OF_RESOURCES; + } + Status = (((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Read(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, &Size, AsciiStrBuffer)); + if (!EFI_ERROR(Status)) { + CharNum = UnicodeSPrint(UscStrBuffer, *BufferSize + sizeof(CHAR16), L"%a", AsciiStrBuffer); + if (CharNum == Size) { + CopyMem (Buffer, UscStrBuffer, *BufferSize); + } else { + Status = EFI_UNSUPPORTED; + } + } + SHELL_FREE_NON_NULL(AsciiStrBuffer); + SHELL_FREE_NON_NULL(UscStrBuffer); return (Status); } } diff --git a/ShellPkg/Application/Shell/ShellParametersProtocol.c b/ShellPkg/Application/Shell/ShellParametersProtocol.c index bbe026b644b2..9c502f8f212e 100644 --- a/ShellPkg/Application/Shell/ShellParametersProtocol.c +++ b/ShellPkg/Application/Shell/ShellParametersProtocol.c @@ -17,6 +17,8 @@ #include "Shell.h" +BOOLEAN AsciiRedirection = FALSE; + /** Return the next parameter's end from a command line string. @@ -726,6 +728,7 @@ UpdateStdInStdOutStdErr( OutUnicode = TRUE; InUnicode = TRUE; + AsciiRedirection = FALSE; ErrUnicode = TRUE; StdInVarName = NULL; StdOutVarName = NULL; @@ -1004,6 +1007,7 @@ UpdateStdInStdOutStdErr( } else { StdInFileName = CommandLineWalker += 4; InUnicode = FALSE; + AsciiRedirection = TRUE; } if (StrStr(CommandLineWalker, L"
Date: Fri, 18 Dec 2015 07:30:21 +0000 Subject: [PATCH 297/525] ShellPkg: Follow spec to remove the last '\' char in return name of GetCurDir(). In Shell spec 2.1 the return name of EFI_SHELL_PROTOCOL.GetCurDir() is defined as 'fs0:\current-dir' while in current implementation it's 'fs0:\current-dir\'. To follow spec the patch removed the redundant '\' char. Since it has been broken for a long time, some codes may depend on the broken behavior. After this change 'EFI_SHELL_PROTOCOL.GetCurDir()' and 'UefiShellLib.ShellGetCurrentDir()' will return a current directory string without tailing '\' (fs0:\current-dir), the value of Shell environment variable 'cwd' will become 'fs0:\current-dir' as well. This patch has updated all the code in EDKII to make them depend on the new behavior. Developers should check whether 'GetCurDir()' and 'ShellGetCurrentDir' are used in their source code. (Sync patch r18653 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Qiu Shumin Reviewed-by: Jaben Carsey git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19395 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Application/Shell/FileHandleWrappers.c | 1 + ShellPkg/Application/Shell/Shell.uni | Bin 4838 -> 4840 bytes ShellPkg/Application/Shell/ShellProtocol.c | 18 +++++++--- ShellPkg/Include/Library/ShellLib.h | 4 ++- ShellPkg/Include/Protocol/EfiShell.h | 4 ++- .../Library/UefiShellLevel2CommandsLib/Cd.c | 23 ++++++++++--- .../Library/UefiShellLevel2CommandsLib/Cp.c | 12 +++++-- .../Library/UefiShellLevel2CommandsLib/Ls.c | 6 +++- .../Library/UefiShellLevel2CommandsLib/Mv.c | 32 +++++++++++++++--- .../Library/UefiShellLevel2CommandsLib/Rm.c | 4 ++- .../UefiShellLevel2CommandsLib.c | 3 +- ShellPkg/Library/UefiShellLib/UefiShellLib.c | 5 ++- 12 files changed, 91 insertions(+), 21 deletions(-) diff --git a/ShellPkg/Application/Shell/FileHandleWrappers.c b/ShellPkg/Application/Shell/FileHandleWrappers.c index 91c35f7cb70a..64f382718b85 100644 --- a/ShellPkg/Application/Shell/FileHandleWrappers.c +++ b/ShellPkg/Application/Shell/FileHandleWrappers.c @@ -510,6 +510,7 @@ FileInterfaceStdInRead( Cwd = ShellInfoObject.NewEfiShellProtocol->GetCurDir(NULL); if (Cwd != NULL) { StrnCpyS(TabStr, (*BufferSize)/sizeof(CHAR16), Cwd, (*BufferSize)/sizeof(CHAR16) - 1); + StrCatS(TabStr, (*BufferSize)/sizeof(CHAR16), L"\\"); if (TabStr[StrLen(TabStr)-1] == L'\\' && *(CurrentString + TabPos) == L'\\' ) { TabStr[StrLen(TabStr)-1] = CHAR_NULL; } diff --git a/ShellPkg/Application/Shell/Shell.uni b/ShellPkg/Application/Shell/Shell.uni index 04f001d3870ac3d9f59ebea4617ab5f13e2c4ce9..25cf69966b733e7b2488413361cfab98c2249bfd 100644 GIT binary patch delta 19 bcmaE+`a*TW6GqdGPp`8w#%$irrp*HYUOEUp delta 17 ZcmaE%`b>4g6Gp?0Pp`9X-p8iJ0{~Bl2i^bx diff --git a/ShellPkg/Application/Shell/ShellProtocol.c b/ShellPkg/Application/Shell/ShellProtocol.c index 28521ecc154b..3a963849f29a 100644 --- a/ShellPkg/Application/Shell/ShellProtocol.c +++ b/ShellPkg/Application/Shell/ShellProtocol.c @@ -532,12 +532,13 @@ EfiShellGetDevicePathFromFilePath( if (Cwd == NULL) { return (NULL); } - Size = StrSize(Cwd) + StrSize(Path) - sizeof(CHAR16); + Size = StrSize(Cwd) + StrSize(Path); NewPath = AllocateZeroPool(Size); if (NewPath == NULL) { return (NULL); } StrCpyS(NewPath, Size/sizeof(CHAR16), Cwd); + StrCatS(NewPath, Size/sizeof(CHAR16), L"\\"); if (*Path == L'\\') { Path++; while (PathRemoveLastItem(NewPath)) ; @@ -2495,6 +2496,7 @@ EfiShellOpenFileList( CurDir = EfiShellGetCurDir(NULL); ASSERT((Path2 == NULL && Path2Size == 0) || (Path2 != NULL)); StrnCatGrow(&Path2, &Path2Size, CurDir, 0); + StrnCatGrow(&Path2, &Path2Size, L"\\", 0); if (*Path == L'\\') { Path++; while (PathRemoveLastItem(Path2)) ; @@ -2796,6 +2798,8 @@ EfiShellSetEnv( FileSystemMapping is not NULL, it returns the current directory associated with the FileSystemMapping. In both cases, the returned name includes the file system mapping (i.e. fs0:\current-dir). + + Note that the current directory string should exclude the tailing backslash character. @param FileSystemMapping A pointer to the file system mapping. If NULL, then the current working directory is returned. @@ -2852,6 +2856,8 @@ EfiShellGetCurDir( If the current working directory or the current working file system is changed then the %cwd% environment variable will be updated + Note that the current directory string should exclude the tailing backslash character. + @param FileSystem A pointer to the file system's mapped name. If NULL, then the current working directory is changed. @param Dir Points to the NULL-terminated directory on the device specified by FileSystem. @@ -2939,9 +2945,11 @@ EfiShellSetCurDir( ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL)); MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, DirectoryName, 0); } - if ((MapListItem->CurrentDirectoryPath != NULL && MapListItem->CurrentDirectoryPath[StrLen(MapListItem->CurrentDirectoryPath)-1] != L'\\') || (MapListItem->CurrentDirectoryPath == NULL)) { + if ((MapListItem->CurrentDirectoryPath != NULL && MapListItem->CurrentDirectoryPath[StrLen(MapListItem->CurrentDirectoryPath)-1] == L'\\') || (MapListItem->CurrentDirectoryPath == NULL)) { ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL)); - MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, L"\\", 0); + if (MapListItem->CurrentDirectoryPath != NULL) { + MapListItem->CurrentDirectoryPath[StrLen(MapListItem->CurrentDirectoryPath)-1] = CHAR_NULL; + } } } else { // @@ -2973,9 +2981,9 @@ EfiShellSetCurDir( MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, L"\\", 0); ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL)); MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, DirectoryName, 0); - if (MapListItem->CurrentDirectoryPath != NULL && MapListItem->CurrentDirectoryPath[StrLen(MapListItem->CurrentDirectoryPath)-1] != L'\\') { + if (MapListItem->CurrentDirectoryPath != NULL && MapListItem->CurrentDirectoryPath[StrLen(MapListItem->CurrentDirectoryPath)-1] == L'\\') { ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL)); - MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, L"\\", 0); + MapListItem->CurrentDirectoryPath[StrLen(MapListItem->CurrentDirectoryPath)-1] = CHAR_NULL; } } } diff --git a/ShellPkg/Include/Library/ShellLib.h b/ShellPkg/Include/Library/ShellLib.h index 23da4eeaf610..d02d6e9de1f1 100644 --- a/ShellPkg/Include/Library/ShellLib.h +++ b/ShellPkg/Include/Library/ShellLib.h @@ -1,7 +1,7 @@ /** @file Provides interface to shell functionality for shell commands and applications. - Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.
+ Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -550,6 +550,8 @@ ShellExecute ( name. If the DeviceName is not NULL, it returns the current directory name on specified drive. + Note that the current directory string should exclude the tailing backslash character. + @param[in] DeviceName The name of the file system to get directory on. @retval NULL The directory does not exist. diff --git a/ShellPkg/Include/Protocol/EfiShell.h b/ShellPkg/Include/Protocol/EfiShell.h index 6c1d66a6696d..5c7f4f635726 100644 --- a/ShellPkg/Include/Protocol/EfiShell.h +++ b/ShellPkg/Include/Protocol/EfiShell.h @@ -2,7 +2,7 @@ EFI Shell protocol as defined in the UEFI Shell 2.0 specification including errata. (C) Copyright 2014 Hewlett-Packard Development Company, L.P.
- Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.
+ Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -294,6 +294,8 @@ EFI_STATUS FileSystemMapping. In both cases, the returned name includes the file system mapping (i.e. fs0:\current-dir). + Note that the current directory string should exclude the tailing backslash character. + @param[in] FileSystemMapping A pointer to the file system mapping. If NULL, then the current working directory is returned. diff --git a/ShellPkg/Library/UefiShellLevel2CommandsLib/Cd.c b/ShellPkg/Library/UefiShellLevel2CommandsLib/Cd.c index 10bc185dbaf6..19e8e2ff9a79 100644 --- a/ShellPkg/Library/UefiShellLevel2CommandsLib/Cd.c +++ b/ShellPkg/Library/UefiShellLevel2CommandsLib/Cd.c @@ -2,7 +2,7 @@ Main file for attrib shell level 2 function. (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
- Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.
+ Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -31,8 +31,10 @@ ShellCommandRunCd ( EFI_STATUS Status; LIST_ENTRY *Package; CONST CHAR16 *Directory; + CHAR16 *Cwd; CHAR16 *Path; CHAR16 *Drive; + UINTN CwdSize; UINTN DriveSize; CHAR16 *ProblemParam; SHELL_STATUS ShellStatus; @@ -121,8 +123,14 @@ ShellCommandRunCd ( ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle, L"cd"); ShellStatus = SHELL_NOT_FOUND; } else { - Drive = GetFullyQualifiedPath(Directory); + CwdSize = StrSize(Directory) + sizeof(CHAR16); + Cwd = AllocateZeroPool(CwdSize); + ASSERT(Cwd!=NULL); + StrCpyS(Cwd, StrSize(Directory)/sizeof(CHAR16)+1, Directory); + StrCatS(Cwd, StrSize(Directory)/sizeof(CHAR16)+1, L"\\"); + Drive = GetFullyQualifiedPath(Cwd); PathRemoveLastItem(Drive); + FreePool(Cwd); } if (ShellStatus == SHELL_SUCCESS && Drive != NULL) { // @@ -143,8 +151,14 @@ ShellCommandRunCd ( ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle, L"cd"); ShellStatus = SHELL_NOT_FOUND; } else { - Drive = GetFullyQualifiedPath(Directory); - while (PathRemoveLastItem(Drive)) ; + CwdSize = StrSize(Directory) + sizeof(CHAR16); + Cwd = AllocateZeroPool(CwdSize); + ASSERT(Cwd!=NULL); + StrCpyS(Cwd, StrSize(Directory)/sizeof(CHAR16)+1, Directory); + StrCatS(Cwd, StrSize(Directory)/sizeof(CHAR16)+1, L"\\"); + Drive = GetFullyQualifiedPath(Cwd); + while (PathRemoveLastItem(Drive)); + FreePool(Cwd); } if (ShellStatus == SHELL_SUCCESS && Drive != NULL) { // @@ -166,6 +180,7 @@ ShellCommandRunCd ( } else { ASSERT((Drive == NULL && DriveSize == 0) || (Drive != NULL)); Drive = StrnCatGrow(&Drive, &DriveSize, ShellGetCurrentDir(NULL), 0); + Drive = StrnCatGrow(&Drive, &DriveSize, L"\\", 0); if (*Param1Copy == L'\\') { while (PathRemoveLastItem(Drive)) ; Drive = StrnCatGrow(&Drive, &DriveSize, Param1Copy+1, 0); diff --git a/ShellPkg/Library/UefiShellLevel2CommandsLib/Cp.c b/ShellPkg/Library/UefiShellLevel2CommandsLib/Cp.c index deff42e0494e..5cfbc9064f83 100644 --- a/ShellPkg/Library/UefiShellLevel2CommandsLib/Cp.c +++ b/ShellPkg/Library/UefiShellLevel2CommandsLib/Cp.c @@ -360,7 +360,7 @@ ValidateAndCopyFiles( NewSize = StrSize(CleanFilePathStr); NewSize += StrSize(Node->FullName); - NewSize += (Cwd == NULL)? 0 : StrSize(Cwd); + NewSize += (Cwd == NULL)? 0 : (StrSize(Cwd) + sizeof(CHAR16)); if (NewSize > PathSize) { PathSize = NewSize; } @@ -428,6 +428,7 @@ ValidateAndCopyFiles( // if (Cwd != NULL) { StrCpyS(DestPath, PathSize / sizeof(CHAR16), Cwd); + StrCatS(DestPath, PathSize / sizeof(CHAR16), L"\\"); } else { ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cp", CleanFilePathStr); FreePool (CleanFilePathStr); @@ -456,6 +457,7 @@ ValidateAndCopyFiles( // if (Cwd != NULL) { StrCpyS(DestPath, PathSize/sizeof(CHAR16), Cwd); + StrCatS(DestPath, PathSize/sizeof(CHAR16), L"\\"); } else { ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cp", CleanFilePathStr); FreePool(CleanFilePathStr); @@ -467,6 +469,7 @@ ValidateAndCopyFiles( } else if (StrStr(CleanFilePathStr, L":") == NULL) { if (Cwd != NULL) { StrCpyS(DestPath, PathSize/sizeof(CHAR16), Cwd); + StrCatS(DestPath, PathSize/sizeof(CHAR16), L"\\"); } else { ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cp", CleanFilePathStr); FreePool(CleanFilePathStr); @@ -644,6 +647,7 @@ ShellCommandRunCp ( BOOLEAN SilentMode; BOOLEAN RecursiveMode; CONST CHAR16 *Cwd; + CHAR16 *FullCwd; ProblemParam = NULL; ShellStatus = SHELL_SUCCESS; @@ -712,7 +716,11 @@ ShellCommandRunCp ( ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, L"cp", ShellCommandLineGetRawValue(Package, 1)); ShellStatus = SHELL_NOT_FOUND; } else { - ShellStatus = ProcessValidateAndCopyFiles(FileList, Cwd, SilentMode, RecursiveMode); + FullCwd = AllocateZeroPool(StrSize(Cwd) + sizeof(CHAR16)); + ASSERT (FullCwd != NULL); + StrCpyS(FullCwd, StrSize(Cwd)/sizeof(CHAR16)+1, Cwd); + ShellStatus = ProcessValidateAndCopyFiles(FileList, FullCwd, SilentMode, RecursiveMode); + FreePool(FullCwd); } } diff --git a/ShellPkg/Library/UefiShellLevel2CommandsLib/Ls.c b/ShellPkg/Library/UefiShellLevel2CommandsLib/Ls.c index c1e2887aa1fb..25bf8ca9e13a 100644 --- a/ShellPkg/Library/UefiShellLevel2CommandsLib/Ls.c +++ b/ShellPkg/Library/UefiShellLevel2CommandsLib/Ls.c @@ -2,7 +2,7 @@ Main file for ls shell level 2 function. (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.
- Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.
+ Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -669,6 +669,8 @@ ShellCommandRunLs ( ASSERT(FullPath == NULL); StrnCatGrow(&SearchString, NULL, L"*", 0); StrnCatGrow(&FullPath, NULL, CurDir, 0); + Size = FullPath != NULL? StrSize(FullPath) : 0; + StrnCatGrow(&FullPath, &Size, L"\\", 0); } else { if (StrStr(PathName, L":") == NULL && gEfiShellProtocol->GetCurDir(NULL) == NULL) { // @@ -687,6 +689,8 @@ ShellCommandRunLs ( ShellCommandLineFreeVarList (Package); return SHELL_OUT_OF_RESOURCES; } + Size = FullPath != NULL? StrSize(FullPath) : 0; + StrnCatGrow(&FullPath, &Size, L"\\", 0); } StrnCatGrow(&FullPath, &Size, PathName, 0); if (FullPath == NULL) { diff --git a/ShellPkg/Library/UefiShellLevel2CommandsLib/Mv.c b/ShellPkg/Library/UefiShellLevel2CommandsLib/Mv.c index fa6753374394..eb7287e48a38 100644 --- a/ShellPkg/Library/UefiShellLevel2CommandsLib/Mv.c +++ b/ShellPkg/Library/UefiShellLevel2CommandsLib/Mv.c @@ -467,6 +467,7 @@ ValidateAndMoveFiles( CHAR16 *DestPath; CHAR16 *FullDestPath; CONST CHAR16 *Cwd; + CHAR16 *FullCwd; SHELL_STATUS ShellStatus; EFI_SHELL_FILE_INFO *Node; VOID *Response; @@ -483,8 +484,17 @@ ValidateAndMoveFiles( Attr = 0; CleanFilePathStr = NULL; + FullCwd = AllocateZeroPool(StrSize(Cwd) + sizeof(CHAR16)); + if (FullCwd == NULL) { + return SHELL_OUT_OF_RESOURCES; + } else { + StrCpyS(FullCwd, StrSize(Cwd)/sizeof(CHAR16)+1, Cwd); + StrCatS(FullCwd, StrSize(Cwd)/sizeof(CHAR16)+1, L"\\"); + } + Status = ShellLevel2StripQuotes (DestParameter, &CleanFilePathStr); if (EFI_ERROR (Status)) { + FreePool (FullCwd); if (Status == EFI_OUT_OF_RESOURCES) { return SHELL_OUT_OF_RESOURCES; } else { @@ -497,14 +507,16 @@ ValidateAndMoveFiles( // // Get and validate the destination location // - ShellStatus = GetDestinationLocation(CleanFilePathStr, &DestPath, Cwd, (BOOLEAN)(FileList->Link.ForwardLink == FileList->Link.BackLink), &Attr); + ShellStatus = GetDestinationLocation(CleanFilePathStr, &DestPath, FullCwd, (BOOLEAN)(FileList->Link.ForwardLink == FileList->Link.BackLink), &Attr); FreePool (CleanFilePathStr); if (ShellStatus != SHELL_SUCCESS) { + FreePool (FullCwd); return (ShellStatus); } DestPath = PathCleanUpDirectories(DestPath); if (DestPath == NULL) { + FreePool (FullCwd); return (SHELL_OUT_OF_RESOURCES); } @@ -514,6 +526,7 @@ ValidateAndMoveFiles( SHELL_FREE_NON_NULL(DestPath); SHELL_FREE_NON_NULL(HiiOutput); SHELL_FREE_NON_NULL(HiiResultOk); + FreePool (FullCwd); return (SHELL_OUT_OF_RESOURCES); } @@ -551,7 +564,7 @@ ValidateAndMoveFiles( // // Validate that the move is valid // - if (!IsValidMove(Node->FullName, Cwd, FullDestPath!=NULL? FullDestPath:DestPath, Node->Info->Attribute, Attr, Node->Status)) { + if (!IsValidMove(Node->FullName, FullCwd, FullDestPath!=NULL? FullDestPath:DestPath, Node->Info->Attribute, Attr, Node->Status)) { ShellStatus = SHELL_INVALID_PARAMETER; continue; } @@ -575,6 +588,7 @@ ValidateAndMoveFiles( // // indicate to stop everything // + FreePool(FullCwd); return (SHELL_ABORTED); case ShellPromptResponseAll: *Resp = Response; @@ -585,12 +599,13 @@ ValidateAndMoveFiles( break; default: FreePool(Response); + FreePool(FullCwd); return SHELL_ABORTED; } Status = ShellDeleteFileByName(FullDestPath!=NULL? FullDestPath:DestPath); } - if (IsBetweenFileSystem(Node->FullName, Cwd, DestPath)) { + if (IsBetweenFileSystem(Node->FullName, FullCwd, DestPath)) { while (FullDestPath == NULL && DestPath != NULL && DestPath[0] != CHAR_NULL && DestPath[StrLen(DestPath) - 1] == L'\\') { DestPath[StrLen(DestPath) - 1] = CHAR_NULL; } @@ -631,6 +646,7 @@ ValidateAndMoveFiles( SHELL_FREE_NON_NULL(DestPath); SHELL_FREE_NON_NULL(HiiOutput); SHELL_FREE_NON_NULL(HiiResultOk); + FreePool (FullCwd); return (ShellStatus); } @@ -650,6 +666,8 @@ ShellCommandRunMv ( EFI_STATUS Status; LIST_ENTRY *Package; CHAR16 *ProblemParam; + CHAR16 *Cwd; + UINTN CwdSize; SHELL_STATUS ShellStatus; UINTN ParamCount; UINTN LoopCounter; @@ -713,7 +731,13 @@ ShellCommandRunMv ( // // ValidateAndMoveFiles will report errors to the screen itself // - ShellStatus = ValidateAndMoveFiles(FileList, &Response, ShellGetCurrentDir(NULL)); + CwdSize = StrSize(ShellGetCurrentDir(NULL)) + 1; + Cwd = AllocateZeroPool(CwdSize); + ASSERT (Cwd != NULL); + StrCpyS(Cwd, CwdSize/sizeof(CHAR16), ShellGetCurrentDir(NULL)); + StrCatS(Cwd, CwdSize/sizeof(CHAR16), L"\\"); + ShellStatus = ValidateAndMoveFiles(FileList, &Response, Cwd); + FreePool(Cwd); } } diff --git a/ShellPkg/Library/UefiShellLevel2CommandsLib/Rm.c b/ShellPkg/Library/UefiShellLevel2CommandsLib/Rm.c index ed9940d82704..0b23fba15081 100644 --- a/ShellPkg/Library/UefiShellLevel2CommandsLib/Rm.c +++ b/ShellPkg/Library/UefiShellLevel2CommandsLib/Rm.c @@ -231,7 +231,9 @@ IsValidDeleteTarget( Pattern = NULL; SearchString = NULL; Size = 0; - Pattern = StrnCatGrow(&Pattern , NULL, TempLocation , 0); + Pattern = StrnCatGrow(&Pattern, &Size, TempLocation , 0); + Pattern = StrnCatGrow(&Pattern, &Size, L"\\" , 0); + Size = 0; SearchString = StrnCatGrow(&SearchString, &Size, Node->FullName, 0); if (!EFI_ERROR(ShellIsDirectory(SearchString))) { SearchString = StrnCatGrow(&SearchString, &Size, L"\\", 0); diff --git a/ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.c b/ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.c index 4ac7e67007f8..0dafb19969c5 100644 --- a/ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.c +++ b/ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.c @@ -22,7 +22,7 @@ * functions are non-interactive only Copyright (c) 2014 Hewlett-Packard Development Company, L.P. - Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.
+ Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -188,6 +188,7 @@ GetFullyQualifiedPath( if (StrStr(Path, L":") == NULL) { CurDir = gEfiShellProtocol->GetCurDir(NULL); StrnCatGrow(&PathToReturn, &Size, CurDir, 0); + StrnCatGrow(&PathToReturn, &Size, L"\\", 0); if (*Path == L'\\') { Path++; } diff --git a/ShellPkg/Library/UefiShellLib/UefiShellLib.c b/ShellPkg/Library/UefiShellLib/UefiShellLib.c index 6e0f61130ff4..44ac382980c0 100644 --- a/ShellPkg/Library/UefiShellLib/UefiShellLib.c +++ b/ShellPkg/Library/UefiShellLib/UefiShellLib.c @@ -1276,6 +1276,8 @@ ShellExecute ( name. If the DeviceName is not NULL, it returns the current directory name on specified drive. + Note that the current directory string should exclude the tailing backslash character. + @param DeviceName the name of the drive to get directory on @retval NULL the directory does not exist @@ -1708,13 +1710,14 @@ ShellFindFilePath ( Path = ShellGetEnvironmentVariable(L"cwd"); if (Path != NULL) { - Size = StrSize(Path); + Size = StrSize(Path) + sizeof(CHAR16); Size += StrSize(FileName); TestPath = AllocateZeroPool(Size); if (TestPath == NULL) { return (NULL); } StrCpyS(TestPath, Size/sizeof(CHAR16), Path); + StrCatS(TestPath, Size/sizeof(CHAR16), L"\\"); StrCatS(TestPath, Size/sizeof(CHAR16), FileName); Status = ShellOpenFileByName(TestPath, &Handle, EFI_FILE_MODE_READ, 0); if (!EFI_ERROR(Status)){ From 44114063177170f05e2e4a040e5a06a0214a4b7d Mon Sep 17 00:00:00 2001 From: Tapan Shah Date: Fri, 18 Dec 2015 07:30:58 +0000 Subject: [PATCH 298/525] ShellPkg: Update 'tftp' command help output and error messages Changing 'tftp' command's help output .uni file to match other EDK2 Shell commands as well as adjusting error messages text. (Sync patch r18659 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Tapan Shah Reviewed-by: Jaben Carsey git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19396 6f19259b-4bc3-4df7-8a09-765794883524 --- .../UefiShellTftpCommandLib.uni | Bin 8856 -> 9952 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/ShellPkg/Library/UefiShellTftpCommandLib/UefiShellTftpCommandLib.uni b/ShellPkg/Library/UefiShellTftpCommandLib/UefiShellTftpCommandLib.uni index 43b8cc5e7cd8726138c600b96b4ebbb1c960824c..d12a87cb56a06ec796d3054e0aa9fd158937f004 100644 GIT binary patch delta 956 zcmZ`&O=}ZD7=D|^G)ZHP`;kp{Yg`MSB%Z{B1TolHE3MX~5y6VYq@jT{X*O$WPZ7_e z;#;tI>cy*AbCVtvJbCgD6x5R^F(r8RnORd>stmI``+m&xF|!-lud{D=Bb3Q0Y+J;;?~a}GaWG)BPpOSgQiE2hPBm(9Q#r}&%C$o=zgizoQI$Jk zy>pjrxaMWf#!1 zfZ7S(QAhYvJj_qk4SpQf_@{33Z7nyn!aI6``}zdGvLgITYjatDxEFnrNMnb8V)M(` zYrbH($J4+%fXmNfXZVNlh%50rZ)*M{OJLOEZ@SJOLP7qmM-xKFJYB(@!zvF1huY%F zQ|1X?H#B~e7$32bvnj>JQM;; z>gfX+dywOvZ6)$_6rK+SChhQ{8ye0-aQ@=ypKJ^y)UEwEcZg{A3;Xe%>V!Z delta 257 zcmaFhJHvIuC!Wbl+#-|NcuxUomC0Ygw8-QTDW%C@_*Q}BHgDoLVVa!5D>0c#sDL?$ zA$9UcA$i8c$?{T?lQ#*OpoypnM@T9#_%j4BgfMslX+MTw20buTV2GWpEHZm?k$}kL zD Date: Fri, 18 Dec 2015 07:31:38 +0000 Subject: [PATCH 299/525] ShellPkg: Fix 'EfiShellExecute' doesn't get command status correctly. 1. Add a new function 'RunShellCommand' to return command status, thus 'EfiShellExecute' can get the command return status of 'CommandLine'. 2. Refine the code logic of 'EfiShellExecute' to make the new image of shell be loaded only if 'Environment' isn't NULL. (Sync patch r18664 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Qiu Shumin Signed-off-by: Jin Eric Signed-off-by: Jaben Carsey Reviewed-by: Ruiyu Ni git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19397 6f19259b-4bc3-4df7-8a09-765794883524 --- ShellPkg/Application/Shell/Shell.c | 69 +++++++++++++++++---- ShellPkg/Application/Shell/Shell.h | 19 ++++++ ShellPkg/Application/Shell/ShellEnvVar.c | 5 +- ShellPkg/Application/Shell/ShellProtocol.c | 72 ++++++++++++++-------- 4 files changed, 125 insertions(+), 40 deletions(-) diff --git a/ShellPkg/Application/Shell/Shell.c b/ShellPkg/Application/Shell/Shell.c index 03f5e4f05fe8..cb9d96944150 100644 --- a/ShellPkg/Application/Shell/Shell.c +++ b/ShellPkg/Application/Shell/Shell.c @@ -1053,6 +1053,7 @@ DoStartupScript( ) { EFI_STATUS Status; + EFI_STATUS CalleeStatus; UINTN Delay; EFI_INPUT_KEY Key; SHELL_FILE_HANDLE FileHandle; @@ -1084,7 +1085,10 @@ DoStartupScript( StrnCatS(FileStringPath, NewSize/sizeof(CHAR16), L" ", NewSize/sizeof(CHAR16) - StrLen(FileStringPath) -1); StrnCatS(FileStringPath, NewSize/sizeof(CHAR16), ShellInfoObject.ShellInitSettings.FileOptions, NewSize/sizeof(CHAR16) - StrLen(FileStringPath) -1); } - Status = RunCommand(FileStringPath); + Status = RunShellCommand(FileStringPath, &CalleeStatus); + if (ShellInfoObject.ShellInitSettings.BitUnion.Bits.Exit == TRUE) { + ShellCommandRegisterExit(gEfiShellProtocol->BatchIsActive(), (CONST UINT64)CalleeStatus); + } FreePool(FileStringPath); return (Status); @@ -2133,6 +2137,7 @@ ProcessCommandLineToFinal( @param[in] CmdLine the command line to run. @param[in] FirstParameter the first parameter on the command line @param[in] ParamProtocol the shell parameters protocol pointer + @param[out] CommandStatus the status from the command line. @retval EFI_SUCCESS The command was completed. @retval EFI_ABORTED The command's operation was aborted. @@ -2142,7 +2147,8 @@ EFIAPI RunInternalCommand( IN CONST CHAR16 *CmdLine, IN CHAR16 *FirstParameter, - IN EFI_SHELL_PARAMETERS_PROTOCOL *ParamProtocol + IN EFI_SHELL_PARAMETERS_PROTOCOL *ParamProtocol, + OUT EFI_STATUS *CommandStatus ) { EFI_STATUS Status; @@ -2175,6 +2181,14 @@ RunInternalCommand( Status = ShellCommandRunCommandHandler(FirstParameter, &CommandReturnedStatus, &LastError); if (!EFI_ERROR(Status)) { + if (CommandStatus != NULL) { + if (CommandReturnedStatus != SHELL_SUCCESS) { + *CommandStatus = (EFI_STATUS)(CommandReturnedStatus | MAX_BIT); + } else { + *CommandStatus = EFI_SUCCESS; + } + } + // // Update last error status. // some commands do not update last error. @@ -2236,6 +2250,7 @@ RunInternalCommand( @param[in] CmdLine the command line to run. @param[in] FirstParameter the first parameter on the command line @param[in] ParamProtocol the shell parameters protocol pointer + @param[out] CommandStatus the status from the command line. @retval EFI_SUCCESS The command was completed. @retval EFI_ABORTED The command's operation was aborted. @@ -2246,7 +2261,8 @@ RunCommandOrFile( IN SHELL_OPERATION_TYPES Type, IN CONST CHAR16 *CmdLine, IN CHAR16 *FirstParameter, - IN EFI_SHELL_PARAMETERS_PROTOCOL *ParamProtocol + IN EFI_SHELL_PARAMETERS_PROTOCOL *ParamProtocol, + OUT EFI_STATUS *CommandStatus ) { EFI_STATUS Status; @@ -2262,7 +2278,7 @@ RunCommandOrFile( switch (Type) { case Internal_Command: - Status = RunInternalCommand(CmdLine, FirstParameter, ParamProtocol); + Status = RunInternalCommand(CmdLine, FirstParameter, ParamProtocol, CommandStatus); break; case Script_File_Name: case Efi_Application: @@ -2328,6 +2344,10 @@ RunCommandOrFile( CalleeExitStatus = (SHELL_STATUS) StartStatus; } + if (CommandStatus != NULL) { + *CommandStatus = CalleeExitStatus; + } + // // Update last error status. // @@ -2360,6 +2380,7 @@ RunCommandOrFile( @param[in] CmdLine the command line to run. @param[in] FirstParameter the first parameter on the command line. @param[in] ParamProtocol the shell parameters protocol pointer + @param[out] CommandStatus the status from the command line. @retval EFI_SUCCESS The command was completed. @retval EFI_ABORTED The command's operation was aborted. @@ -2367,10 +2388,11 @@ RunCommandOrFile( EFI_STATUS EFIAPI SetupAndRunCommandOrFile( - IN SHELL_OPERATION_TYPES Type, - IN CHAR16 *CmdLine, - IN CHAR16 *FirstParameter, - IN EFI_SHELL_PARAMETERS_PROTOCOL *ParamProtocol + IN SHELL_OPERATION_TYPES Type, + IN CHAR16 *CmdLine, + IN CHAR16 *FirstParameter, + IN EFI_SHELL_PARAMETERS_PROTOCOL *ParamProtocol, + OUT EFI_STATUS *CommandStatus ) { EFI_STATUS Status; @@ -2390,7 +2412,7 @@ SetupAndRunCommandOrFile( // if (!EFI_ERROR(Status)) { TrimSpaces(&CmdLine); - Status = RunCommandOrFile(Type, CmdLine, FirstParameter, ParamProtocol); + Status = RunCommandOrFile(Type, CmdLine, FirstParameter, ParamProtocol, CommandStatus); } // @@ -2415,14 +2437,16 @@ SetupAndRunCommandOrFile( command or dispatch an external application. @param[in] CmdLine The command line to parse. + @param[out] CommandStatus The status from the command line. @retval EFI_SUCCESS The command was completed. @retval EFI_ABORTED The command's operation was aborted. **/ EFI_STATUS EFIAPI -RunCommand( - IN CONST CHAR16 *CmdLine +RunShellCommand( + IN CONST CHAR16 *CmdLine, + OUT EFI_STATUS *CommandStatus ) { EFI_STATUS Status; @@ -2507,7 +2531,7 @@ RunCommand( case Internal_Command: case Script_File_Name: case Efi_Application: - Status = SetupAndRunCommandOrFile(Type, CleanOriginal, FirstParameter, ShellInfoObject.NewShellParametersProtocol); + Status = SetupAndRunCommandOrFile(Type, CleanOriginal, FirstParameter, ShellInfoObject.NewShellParametersProtocol, CommandStatus); break; default: // @@ -2528,6 +2552,27 @@ RunCommand( return (Status); } +/** + Function will process and run a command line. + + This will determine if the command line represents an internal shell + command or dispatch an external application. + + @param[in] CmdLine The command line to parse. + + @retval EFI_SUCCESS The command was completed. + @retval EFI_ABORTED The command's operation was aborted. +**/ +EFI_STATUS +EFIAPI +RunCommand( + IN CONST CHAR16 *CmdLine + ) +{ + return (RunShellCommand(CmdLine, NULL)); +} + + STATIC CONST UINT16 InvalidChars[] = {L'*', L'?', L'<', L'>', L'\\', L'/', L'\"', 0x0001, 0x0002}; /** Function determines if the CommandName COULD be a valid command. It does not determine whether diff --git a/ShellPkg/Application/Shell/Shell.h b/ShellPkg/Application/Shell/Shell.h index b6686256aac3..7c876510dd29 100644 --- a/ShellPkg/Application/Shell/Shell.h +++ b/ShellPkg/Application/Shell/Shell.h @@ -293,6 +293,25 @@ RunCommand( IN CONST CHAR16 *CmdLine ); +/** + Function will process and run a command line. + + This will determine if the command line represents an internal shell + command or dispatch an external application. + + @param[in] CmdLine The command line to parse. + @param[out] CommandStatus The status from the command line. + + @retval EFI_SUCCESS The command was completed. + @retval EFI_ABORTED The command's operation was aborted. +**/ +EFI_STATUS +EFIAPI +RunShellCommand( + IN CONST CHAR16 *CmdLine, + OUT EFI_STATUS *CommandStatus + ); + /** Function determines if the CommandName COULD be a valid command. It does not determine whether this is a valid command. It only checks for invalid characters. diff --git a/ShellPkg/Application/Shell/ShellEnvVar.c b/ShellPkg/Application/Shell/ShellEnvVar.c index 8ed14b34a2f4..a8f177e6adae 100644 --- a/ShellPkg/Application/Shell/ShellEnvVar.c +++ b/ShellPkg/Application/Shell/ShellEnvVar.c @@ -339,9 +339,10 @@ SetEnvironmentVariables( // // Copy the string into the Key, leaving the last character allocated as NULL to terminate // - StrCpyS( Node->Key, + StrnCpyS( Node->Key, StrStr(CurrentString, L"=") - CurrentString + 1, - CurrentString + CurrentString, + StrStr(CurrentString, L"=") - CurrentString ); // diff --git a/ShellPkg/Application/Shell/ShellProtocol.c b/ShellPkg/Application/Shell/ShellProtocol.c index 3a963849f29a..af00fe401d9c 100644 --- a/ShellPkg/Application/Shell/ShellProtocol.c +++ b/ShellPkg/Application/Shell/ShellProtocol.c @@ -1631,40 +1631,60 @@ EfiShellExecute( CHAR16 *Temp; EFI_DEVICE_PATH_PROTOCOL *DevPath; UINTN Size; - + EFI_STATUS CalleeStatusCode; + if ((PcdGet8(PcdShellSupportLevel) < 1)) { return (EFI_UNSUPPORTED); } - DevPath = AppendDevicePath (ShellInfoObject.ImageDevPath, ShellInfoObject.FileDevPath); + if (Environment != NULL) { + // If Environment isn't null, load a new image of the shell with its own + // environment + DevPath = AppendDevicePath (ShellInfoObject.ImageDevPath, ShellInfoObject.FileDevPath); + + DEBUG_CODE_BEGIN(); + Temp = ConvertDevicePathToText(ShellInfoObject.FileDevPath, TRUE, TRUE); + FreePool(Temp); + Temp = ConvertDevicePathToText(ShellInfoObject.ImageDevPath, TRUE, TRUE); + FreePool(Temp); + Temp = ConvertDevicePathToText(DevPath, TRUE, TRUE); + FreePool(Temp); + DEBUG_CODE_END(); + + Temp = NULL; + Size = 0; + ASSERT((Temp == NULL && Size == 0) || (Temp != NULL)); + StrnCatGrow(&Temp, &Size, L"Shell.efi -_exit ", 0); + StrnCatGrow(&Temp, &Size, CommandLine, 0); - DEBUG_CODE_BEGIN(); - Temp = ConvertDevicePathToText(ShellInfoObject.FileDevPath, TRUE, TRUE); - FreePool(Temp); - Temp = ConvertDevicePathToText(ShellInfoObject.ImageDevPath, TRUE, TRUE); - FreePool(Temp); - Temp = ConvertDevicePathToText(DevPath, TRUE, TRUE); - FreePool(Temp); - DEBUG_CODE_END(); + Status = InternalShellExecuteDevicePath( + ParentImageHandle, + DevPath, + Temp, + (CONST CHAR16**)Environment, + StatusCode); - Temp = NULL; - Size = 0; - ASSERT((Temp == NULL && Size == 0) || (Temp != NULL)); - StrnCatGrow(&Temp, &Size, L"Shell.efi -_exit ", 0); - StrnCatGrow(&Temp, &Size, CommandLine, 0); + // + // de-allocate and return + // + FreePool(DevPath); + FreePool(Temp); + } else { + // If Environment is NULL, we are free to use and mutate the current shell + // environment. This is much faster as uses much less memory. - Status = InternalShellExecuteDevicePath( - ParentImageHandle, - DevPath, - Temp, - (CONST CHAR16**)Environment, - StatusCode); + if (CommandLine == NULL) { + CommandLine = L""; + } + + Status = RunShellCommand (CommandLine, &CalleeStatusCode); + + // Pass up the command's exit code if the caller wants it + if (StatusCode != NULL) { + *StatusCode = (EFI_STATUS) CalleeStatusCode; + } + } - // - // de-allocate and return - // - FreePool(DevPath); - FreePool(Temp); return(Status); } From 45ac3433b58fb87cf63960cf3f1492b22df0d255 Mon Sep 17 00:00:00 2001 From: Qiu Shumin Date: Fri, 18 Dec 2015 07:32:17 +0000 Subject: [PATCH 300/525] ShellPkg: Refine code by initializing local variable and adding ASSERT statement. Add ASSERT statement and initialize local variable to make code more readable. (Sync patch r18689 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Qiu Shumin Reviewed-by: Jaben Carsey git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19398 6f19259b-4bc3-4df7-8a09-765794883524 --- ShellPkg/Application/Shell/ShellProtocol.c | 2 ++ ShellPkg/Library/UefiShellTftpCommandLib/Tftp.c | 1 + 2 files changed, 3 insertions(+) diff --git a/ShellPkg/Application/Shell/ShellProtocol.c b/ShellPkg/Application/Shell/ShellProtocol.c index af00fe401d9c..fc13595dbb03 100644 --- a/ShellPkg/Application/Shell/ShellProtocol.c +++ b/ShellPkg/Application/Shell/ShellProtocol.c @@ -1632,6 +1632,8 @@ EfiShellExecute( EFI_DEVICE_PATH_PROTOCOL *DevPath; UINTN Size; EFI_STATUS CalleeStatusCode; + + CalleeStatusCode = EFI_SUCCESS; if ((PcdGet8(PcdShellSupportLevel) < 1)) { return (EFI_UNSUPPORTED); diff --git a/ShellPkg/Library/UefiShellTftpCommandLib/Tftp.c b/ShellPkg/Library/UefiShellTftpCommandLib/Tftp.c index 02099febef08..831b9c3d0250 100644 --- a/ShellPkg/Library/UefiShellTftpCommandLib/Tftp.c +++ b/ShellPkg/Library/UefiShellTftpCommandLib/Tftp.c @@ -341,6 +341,7 @@ ShellCommandRunTftp ( } RemoteFilePath = ShellCommandLineGetRawValue (CheckPackage, 2); + ASSERT(RemoteFilePath != NULL); AsciiRemoteFilePath = AllocatePool ( (StrLen (RemoteFilePath) + 1) * sizeof (CHAR8) ); From 66fb2e8febaf403cf1dfaa1bea718faf4529cacd Mon Sep 17 00:00:00 2001 From: Star Zeng Date: Fri, 18 Dec 2015 07:32:50 +0000 Subject: [PATCH 301/525] ShellPkg UefiDpLib: Use correct string length for the input UnicodeBuffer Same as the beginning of function to use DP_GAUGE_STRING_LENGTH, but not DXE_PERFORMANCE_STRING_LENGTH. (Sync patch r18725 from main trunk.) Cc: Jaben Carsey Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Star Zeng Reviewed-by: Jaben Carsey git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19399 6f19259b-4bc3-4df7-8a09-765794883524 --- ShellPkg/Library/UefiDpLib/DpUtilities.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ShellPkg/Library/UefiDpLib/DpUtilities.c b/ShellPkg/Library/UefiDpLib/DpUtilities.c index 5237459e5b00..e9d8fb3adf31 100644 --- a/ShellPkg/Library/UefiDpLib/DpUtilities.c +++ b/ShellPkg/Library/UefiDpLib/DpUtilities.c @@ -164,8 +164,8 @@ DpGetShortPdbFileName ( for (IndexA = StartIndex; IndexA < EndIndex; IndexA++) { UnicodeBuffer[IndexU] = (CHAR16) PdbFileName[IndexA]; IndexU++; - if (IndexU >= DXE_PERFORMANCE_STRING_LENGTH) { - UnicodeBuffer[DXE_PERFORMANCE_STRING_LENGTH] = 0; + if (IndexU >= DP_GAUGE_STRING_LENGTH) { + UnicodeBuffer[DP_GAUGE_STRING_LENGTH] = 0; break; } } From e52ab636c6e22788d5a968da3198498f20487aaa Mon Sep 17 00:00:00 2001 From: Cinnamon Shia Date: Fri, 18 Dec 2015 07:33:22 +0000 Subject: [PATCH 302/525] ShellPkg/UefiDpLib: Fix a DP cumulative data issue The value of PERF_CUM_DATA.Count and PERF_CUM_DATA.Duration field keep cumulating on every execution of dp. Initialize the CumData at dp's entry point. (Sync patch r18727 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Cinnamon Shia Reviewed-by: Star Zeng Reviewed-by: Jaben Carsey git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19400 6f19259b-4bc3-4df7-8a09-765794883524 --- ShellPkg/Library/UefiDpLib/Dp.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/ShellPkg/Library/UefiDpLib/Dp.c b/ShellPkg/Library/UefiDpLib/Dp.c index 82701723c894..62a4e7b57782 100644 --- a/ShellPkg/Library/UefiDpLib/Dp.c +++ b/ShellPkg/Library/UefiDpLib/Dp.c @@ -14,6 +14,7 @@ timer information to calculate elapsed time for each measurement. Copyright (c) 2009 - 2013, Intel Corporation. All rights reserved. + (C) Copyright 2015 Hewlett Packard Enterprise Development LP
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -110,7 +111,26 @@ DumpStatistics( void ) SHELL_FREE_NON_NULL (StringPtrUnknown); } -/** +/** + Initialize the cumulative data. + +**/ +VOID +InitCumulativeData ( + VOID + ) +{ + UINTN Index; + + for (Index = 0; Index < NumCum; ++Index) { + CumData[Index].Count = 0; + CumData[Index].MinDur = PERF_MAXDUR; + CumData[Index].MaxDur = 0; + CumData[Index].Duration = 0; + } +} + +/** Dump performance data. @param[in] ImageHandle The image handle. @@ -218,6 +238,11 @@ ShellCommandRunDp ( #endif // PROFILING_IMPLEMENTED } + // + // Initialize the pre-defined cumulative data. + // + InitCumulativeData (); + // // Timer specific processing // From b8e0c9e02451ea95052a0c18f86ff61141df0547 Mon Sep 17 00:00:00 2001 From: Cinnamon Shia Date: Fri, 18 Dec 2015 07:34:01 +0000 Subject: [PATCH 303/525] ShellPkg/UefiDpLib: Support dumping cumulative data Add a new option -c to dump cumulative data. For example: shell> dp -c ==[ Cumulative ]======== (Times in microsec.) Cumulative Average Shortest Longest Name Count Duration Duration Duration Duration LoadImage: 200 1000000 7000 0 100000 StartImage: 200 20000000 90000 0 7000000 DB:Start: 200 20000000 100000 0 9000000 DB:Support: 200000 100000 0 0 7000 shell> dp -c DXE ==[ Cumulative ]======== (Times in microsec.) Cumulative Average Shortest Longest Name Count Duration Duration Duration Duration LoadImage: 200 1000000 7000 0 100000 StartImage: 200 20000000 90000 0 7000000 DB:Start: 200 20000000 100000 0 9000000 DB:Support: 200000 100000 0 0 7000 DXE 1 30000000 30000000 0 30000000 (Sync patch r18728 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Cinnamon Shia Reviewed-by: Star Zeng Reviewed-by: Jaben Carsey Reviewed-by: El-Haj-Mahmoud Samer git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19401 6f19259b-4bc3-4df7-8a09-765794883524 --- ShellPkg/Library/UefiDpLib/Dp.c | 33 ++++++++++++-- ShellPkg/Library/UefiDpLib/DpInternal.h | 9 +++- ShellPkg/Library/UefiDpLib/DpTrace.c | 55 ++++++++++++++++++++--- ShellPkg/Library/UefiDpLib/UefiDpLib.uni | Bin 17466 -> 18146 bytes 4 files changed, 87 insertions(+), 10 deletions(-) diff --git a/ShellPkg/Library/UefiDpLib/Dp.c b/ShellPkg/Library/UefiDpLib/Dp.c index 62a4e7b57782..4d109d037c1b 100644 --- a/ShellPkg/Library/UefiDpLib/Dp.c +++ b/ShellPkg/Library/UefiDpLib/Dp.c @@ -79,6 +79,7 @@ STATIC CONST SHELL_PARAM_ITEM ParamList[] = { #endif // PROFILING_IMPLEMENTED {L"-x", TypeFlag}, // -x eXclude Cumulative Items {L"-i", TypeFlag}, // -i Display Identifier + {L"-c", TypeValue}, // -c Display cumulative data. {L"-n", TypeValue}, // -n # Number of records to display for A and R {L"-t", TypeValue}, // -t # Threshold of interest {NULL, TypeMax} @@ -164,6 +165,9 @@ ShellCommandRunDp ( BOOLEAN TraceMode; BOOLEAN ProfileMode; BOOLEAN ExcludeMode; + BOOLEAN CumulativeMode; + CONST CHAR16 *CustomCumulativeToken; + PERF_CUM_DATA *CustomCumulativeData; StringPtr = NULL; SummaryMode = FALSE; @@ -173,6 +177,8 @@ ShellCommandRunDp ( TraceMode = FALSE; ProfileMode = FALSE; ExcludeMode = FALSE; + CumulativeMode = FALSE; + CustomCumulativeData = NULL; // Get DP's entry time as soon as possible. // This is used as the Shell-Phase end time. @@ -210,6 +216,7 @@ ShellCommandRunDp ( #endif // PROFILING_IMPLEMENTED ExcludeMode = ShellCommandLineGetFlag (ParamPackage, L"-x"); mShowId = ShellCommandLineGetFlag (ParamPackage, L"-i"); + CumulativeMode = ShellCommandLineGetFlag (ParamPackage, L"-c"); // Options with Values CmdLineArg = ShellCommandLineGetValue (ParamPackage, L"-n"); @@ -243,6 +250,20 @@ ShellCommandRunDp ( // InitCumulativeData (); + // + // Init the custom cumulative data. + // + CustomCumulativeToken = ShellCommandLineGetValue (ParamPackage, L"-c"); + if (CustomCumulativeToken != NULL) { + CustomCumulativeData = AllocateZeroPool (sizeof (PERF_CUM_DATA)); + CustomCumulativeData->MinDur = 0; + CustomCumulativeData->MaxDur = 0; + CustomCumulativeData->Count = 0; + CustomCumulativeData->Duration = 0; + CustomCumulativeData->Name = AllocateZeroPool (StrLen (CustomCumulativeToken) + 1); + UnicodeStrToAsciiStr (CustomCumulativeToken, CustomCumulativeData->Name); + } + // // Timer specific processing // @@ -302,8 +323,10 @@ ShellCommandRunDp ( **** !T && P := (2) Only Profile records are displayed **** T && P := (3) Same as Default, both are displayed ****************************************************************************/ - GatherStatistics(); - if (AllMode) { + GatherStatistics (CustomCumulativeData); + if (CumulativeMode) { + ProcessCumulative (CustomCumulativeData); + } else if (AllMode) { if (TraceMode) { DumpAllTrace( Number2Display, ExcludeMode); } @@ -326,7 +349,7 @@ ShellCommandRunDp ( if ( ! EFI_ERROR( Status)) { ProcessPeims (); ProcessGlobal (); - ProcessCumulative (); + ProcessCumulative (NULL); } } } @@ -339,6 +362,10 @@ ShellCommandRunDp ( } SHELL_FREE_NON_NULL (StringPtr); + if (CustomCumulativeData != NULL) { + SHELL_FREE_NON_NULL (CustomCumulativeData->Name); + } + SHELL_FREE_NON_NULL (CustomCumulativeData); return SHELL_SUCCESS; } diff --git a/ShellPkg/Library/UefiDpLib/DpInternal.h b/ShellPkg/Library/UefiDpLib/DpInternal.h index 9b8163aaa0f7..aa07fea8c21d 100644 --- a/ShellPkg/Library/UefiDpLib/DpInternal.h +++ b/ShellPkg/Library/UefiDpLib/DpInternal.h @@ -172,10 +172,13 @@ GetCumulativeItem( @post The SummaryData and CumData structures contain statistics for the current performance logs. + + @param[in, out] CustomCumulativeData The pointer to the custom cumulative data. + **/ VOID GatherStatistics( - VOID + IN OUT PERF_CUM_DATA *CustomCumulativeData OPTIONAL ); /** @@ -283,11 +286,13 @@ ProcessGlobal( For each record with a Token listed in the CumData array:
- Update the instance count and the total, minimum, and maximum durations. Finally, print the gathered cumulative statistics. + + @param[in] CustomCumulativeData The pointer to the custom cumulative data. **/ VOID ProcessCumulative( - VOID + IN PERF_CUM_DATA *CustomCumulativeData OPTIONAL ); /** diff --git a/ShellPkg/Library/UefiDpLib/DpTrace.c b/ShellPkg/Library/UefiDpLib/DpTrace.c index cf8200c6f1a2..d17d514bf12e 100644 --- a/ShellPkg/Library/UefiDpLib/DpTrace.c +++ b/ShellPkg/Library/UefiDpLib/DpTrace.c @@ -43,11 +43,14 @@ @post The SummaryData and CumData structures contain statistics for the current performance logs. + + @param[in, out] CustomCumulativeData A pointer to the cumtom cumulative data. + **/ VOID GatherStatistics( - VOID -) + IN OUT PERF_CUM_DATA *CustomCumulativeData OPTIONAL + ) { MEASUREMENT_RECORD Measurement; UINT64 Duration; @@ -99,6 +102,20 @@ GatherStatistics( CumData[TIndex].MaxDur = Duration; } } + + // + // Collect the data for custom cumulative data. + // + if ((CustomCumulativeData != NULL) && (AsciiStrCmp (Measurement.Token, CustomCumulativeData->Name) == 0)) { + CustomCumulativeData->Duration += Duration; + CustomCumulativeData->Count++; + if (Duration < CustomCumulativeData->MinDur) { + CustomCumulativeData->MinDur = Duration; + } + if (Duration > CustomCumulativeData->MaxDur) { + CustomCumulativeData->MaxDur = Duration; + } + } } } @@ -782,12 +799,14 @@ ProcessGlobal( For each record with a Token listed in the CumData array:
- Update the instance count and the total, minimum, and maximum durations. Finally, print the gathered cumulative statistics. - + + @param[in] CustomCumulativeData A pointer to the cumtom cumulative data. + **/ VOID ProcessCumulative( - VOID -) + IN PERF_CUM_DATA *CustomCumulativeData OPTIONAL + ) { UINT64 AvgDur; // the computed average duration UINT64 Dur; @@ -826,4 +845,30 @@ ProcessCumulative( ); } } + + // + // Print the custom cumulative data. + // + if (CustomCumulativeData != NULL) { + if (CustomCumulativeData->Count != 0) { + AvgDur = DivU64x32 (CustomCumulativeData->Duration, CustomCumulativeData->Count); + AvgDur = DurationInMicroSeconds (AvgDur); + Dur = DurationInMicroSeconds (CustomCumulativeData->Duration); + MaxDur = DurationInMicroSeconds (CustomCumulativeData->MaxDur); + MinDur = DurationInMicroSeconds (CustomCumulativeData->MinDur); + } else { + AvgDur = 0; + Dur = 0; + MaxDur = 0; + MinDur = 0; + } + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_CUMULATIVE_STATS), gDpHiiHandle, + CustomCumulativeData->Name, + CustomCumulativeData->Count, + Dur, + AvgDur, + MinDur, + MaxDur + ); + } } diff --git a/ShellPkg/Library/UefiDpLib/UefiDpLib.uni b/ShellPkg/Library/UefiDpLib/UefiDpLib.uni index 1e5c26ac944e3f626c97c79ac9bb1c4196c70ed3..5bcb4964523aa7839694bc430f57ad27e8f63047 100644 GIT binary patch delta 437 zcmZvY%}&BV6ot>kz=Fh81IBbSc8>}EM5qg+kpz)o6WIZaNgW8GMN$D@!HtWiPv9G9 zy5nu+NjTFG(MTq}(|hlC&$*f9n^?Vz&!&i_b8!xd1~gs~FwS@+JSg}WGe&q~UdM!W z&1}kVgcs;IwD(%@;twlrilA!w#JYr@Ii`vC(NDi>!(7(r-~snkX%i|#CP!7P8xbp0 zU1LDS32)=1_-Ae(bGjJ0aFd0s1nkd9FGx#rCR6Bfryl1V*7i|=lc>CX?XkMc!6^UN z+AeN(Fq3ZbeOXKf`O;wp$5d`{7e&uIPAd$56ZT0)JZ9TOj60Zv(~P;r4P0!=9~b-V RPk+vrp3>2%xv99S<<^p%SkM3f delta 24 gcmaFV%ebq9af27*<|~Xj7Mmlil2|t%a8zOi0D&(FVgLXD From 916f81f23277fa9a7451783d207e3485c779d5d6 Mon Sep 17 00:00:00 2001 From: Qiu Shumin Date: Fri, 18 Dec 2015 07:34:43 +0000 Subject: [PATCH 304/525] ShellPkg: Don't strip positional parameters of quotation marks. Per Shell SPEC 2.1 'Double-quotation marks that surround arguments are not stripped in positional parameters'. This patch makes Shell implementation to follow SPEC. (Sync patch r18742 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Qiu Shumin Reviewed-by: Jaben Carsey git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19402 6f19259b-4bc3-4df7-8a09-765794883524 --- ShellPkg/Application/Shell/Shell.c | 30 +++++------ ShellPkg/Application/Shell/Shell.h | 8 --- .../Shell/ShellParametersProtocol.c | 52 ++++++++++++++----- .../Shell/ShellParametersProtocol.h | 36 +++++++++---- ShellPkg/Application/Shell/ShellProtocol.c | 2 +- 5 files changed, 80 insertions(+), 48 deletions(-) diff --git a/ShellPkg/Application/Shell/Shell.c b/ShellPkg/Application/Shell/Shell.c index cb9d96944150..8af66479a3b4 100644 --- a/ShellPkg/Application/Shell/Shell.c +++ b/ShellPkg/Application/Shell/Shell.c @@ -1863,7 +1863,7 @@ IsValidSplit( return (EFI_OUT_OF_RESOURCES); } TempWalker = (CHAR16*)Temp; - if (!EFI_ERROR(GetNextParameter(&TempWalker, &FirstParameter, StrSize(CmdLine)))) { + if (!EFI_ERROR(GetNextParameter(&TempWalker, &FirstParameter, StrSize(CmdLine), TRUE))) { if (GetOperationType(FirstParameter) == Unknown_Invalid) { ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_NOT_FOUND), ShellInfoObject.HiiHandle, FirstParameter); SetLastError(SHELL_NOT_FOUND); @@ -2029,7 +2029,7 @@ DoHelpUpdate( Walker = *CmdLine; while(Walker != NULL && *Walker != CHAR_NULL) { - if (!EFI_ERROR(GetNextParameter(&Walker, &CurrentParameter, StrSize(*CmdLine)))) { + if (!EFI_ERROR(GetNextParameter(&Walker, &CurrentParameter, StrSize(*CmdLine), TRUE))) { if (StrStr(CurrentParameter, L"-?") == CurrentParameter) { CurrentParameter[0] = L' '; CurrentParameter[1] = L' '; @@ -2173,7 +2173,7 @@ RunInternalCommand( // // get the argc and argv updated for internal commands // - Status = UpdateArgcArgv(ParamProtocol, NewCmdLine, &Argv, &Argc); + Status = UpdateArgcArgv(ParamProtocol, NewCmdLine, Internal_Command, &Argv, &Argc); if (!EFI_ERROR(Status)) { // // Run the internal command. @@ -2520,7 +2520,7 @@ RunShellCommand( return (EFI_OUT_OF_RESOURCES); } TempWalker = CleanOriginal; - if (!EFI_ERROR(GetNextParameter(&TempWalker, &FirstParameter, StrSize(CleanOriginal)))) { + if (!EFI_ERROR(GetNextParameter(&TempWalker, &FirstParameter, StrSize(CleanOriginal), TRUE))) { // // Depending on the first parameter we change the behavior // @@ -2767,34 +2767,34 @@ RunScriptFileHandle ( if (NewScriptFile->Argv != NULL) { switch (NewScriptFile->Argc) { default: - Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PrintBuffSize, L"%9", NewScriptFile->Argv[9], FALSE, TRUE); + Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PrintBuffSize, L"%9", NewScriptFile->Argv[9], FALSE, FALSE); ASSERT_EFI_ERROR(Status); case 9: - Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PrintBuffSize, L"%8", NewScriptFile->Argv[8], FALSE, TRUE); + Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PrintBuffSize, L"%8", NewScriptFile->Argv[8], FALSE, FALSE); ASSERT_EFI_ERROR(Status); case 8: - Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PrintBuffSize, L"%7", NewScriptFile->Argv[7], FALSE, TRUE); + Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PrintBuffSize, L"%7", NewScriptFile->Argv[7], FALSE, FALSE); ASSERT_EFI_ERROR(Status); case 7: - Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PrintBuffSize, L"%6", NewScriptFile->Argv[6], FALSE, TRUE); + Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PrintBuffSize, L"%6", NewScriptFile->Argv[6], FALSE, FALSE); ASSERT_EFI_ERROR(Status); case 6: - Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PrintBuffSize, L"%5", NewScriptFile->Argv[5], FALSE, TRUE); + Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PrintBuffSize, L"%5", NewScriptFile->Argv[5], FALSE, FALSE); ASSERT_EFI_ERROR(Status); case 5: - Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PrintBuffSize, L"%4", NewScriptFile->Argv[4], FALSE, TRUE); + Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PrintBuffSize, L"%4", NewScriptFile->Argv[4], FALSE, FALSE); ASSERT_EFI_ERROR(Status); case 4: - Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PrintBuffSize, L"%3", NewScriptFile->Argv[3], FALSE, TRUE); + Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PrintBuffSize, L"%3", NewScriptFile->Argv[3], FALSE, FALSE); ASSERT_EFI_ERROR(Status); case 3: - Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PrintBuffSize, L"%2", NewScriptFile->Argv[2], FALSE, TRUE); + Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PrintBuffSize, L"%2", NewScriptFile->Argv[2], FALSE, FALSE); ASSERT_EFI_ERROR(Status); case 2: - Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PrintBuffSize, L"%1", NewScriptFile->Argv[1], FALSE, TRUE); + Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PrintBuffSize, L"%1", NewScriptFile->Argv[1], FALSE, FALSE); ASSERT_EFI_ERROR(Status); case 1: - Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PrintBuffSize, L"%0", NewScriptFile->Argv[0], FALSE, TRUE); + Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PrintBuffSize, L"%0", NewScriptFile->Argv[0], FALSE, FALSE); ASSERT_EFI_ERROR(Status); break; case 0: @@ -2944,7 +2944,7 @@ RunScriptFile ( // // get the argc and argv updated for scripts // - Status = UpdateArgcArgv(ParamProtocol, CmdLine, &Argv, &Argc); + Status = UpdateArgcArgv(ParamProtocol, CmdLine, Script_File_Name, &Argv, &Argc); if (!EFI_ERROR(Status)) { if (Handle == NULL) { diff --git a/ShellPkg/Application/Shell/Shell.h b/ShellPkg/Application/Shell/Shell.h index 7c876510dd29..57263204e388 100644 --- a/ShellPkg/Application/Shell/Shell.h +++ b/ShellPkg/Application/Shell/Shell.h @@ -124,14 +124,6 @@ typedef struct { extern SHELL_INFO ShellInfoObject; -typedef enum { - Internal_Command, - Script_File_Name, - Efi_Application, - File_Sys_Change, - Unknown_Invalid -} SHELL_OPERATION_TYPES; - /** Converts the command line to it's post-processed form. this replaces variables and alias' per UEFI Shell spec. diff --git a/ShellPkg/Application/Shell/ShellParametersProtocol.c b/ShellPkg/Application/Shell/ShellParametersProtocol.c index 9c502f8f212e..56dd79214b3a 100644 --- a/ShellPkg/Application/Shell/ShellParametersProtocol.c +++ b/ShellPkg/Application/Shell/ShellParametersProtocol.c @@ -74,10 +74,12 @@ FindEndOfParameter( This will also remove all remaining ^ characters after processing. - @param[in, out] Walker pointer to string of command line. Adjusted to - reminaing command line on return - @param[in, out] TempParameter pointer to string of command line item extracted. - @param[in] Length buffer size of TempParameter. + @param[in, out] Walker pointer to string of command line. Adjusted to + reminaing command line on return + @param[in, out] TempParameter pointer to string of command line item extracted. + @param[in] Length buffer size of TempParameter. + @param[in] StripQuotation if TRUE then strip the quotation marks surrounding + the parameters. @return EFI_INALID_PARAMETER A required parameter was NULL or pointed to a NULL or empty string. @return EFI_NOT_FOUND A closing " could not be found on the specified string @@ -87,7 +89,8 @@ EFIAPI GetNextParameter( IN OUT CHAR16 **Walker, IN OUT CHAR16 **TempParameter, - IN CONST UINTN Length + IN CONST UINTN Length, + IN BOOLEAN StripQuotation ) { CONST CHAR16 *NextDelim; @@ -161,7 +164,11 @@ DEBUG_CODE_END(); // // eliminate the unescaped quote // - CopyMem ((CHAR16*)NextDelim, NextDelim + 1, StrSize (NextDelim + 1)); + if (StripQuotation) { + CopyMem ((CHAR16*)NextDelim, NextDelim + 1, StrSize (NextDelim + 1)); + } else{ + NextDelim++; + } } } @@ -178,9 +185,11 @@ DEBUG_CODE_END(); All special character processing (alias, environment variable, redirection, etc... must be complete before calling this API. - @param[in] CommandLine String of command line to parse - @param[in, out] Argv pointer to array of strings; one for each parameter - @param[in, out] Argc pointer to number of strings in Argv array + @param[in] CommandLine String of command line to parse + @param[in] StripQuotation if TRUE then strip the quotation marks surrounding + the parameters. + @param[in, out] Argv pointer to array of strings; one for each parameter + @param[in, out] Argc pointer to number of strings in Argv array @return EFI_SUCCESS the operation was sucessful @return EFI_OUT_OF_RESOURCES a memory allocation failed. @@ -189,8 +198,9 @@ EFI_STATUS EFIAPI ParseCommandLineToArgs( IN CONST CHAR16 *CommandLine, - IN OUT CHAR16 ***Argv, - IN OUT UINTN *Argc + IN BOOLEAN StripQuotation, + IN OUT CHAR16 ***Argv, + IN OUT UINTN *Argc ) { UINTN Count; @@ -228,7 +238,7 @@ ParseCommandLineToArgs( ; Walker != NULL && *Walker != CHAR_NULL ; Count++ ) { - if (EFI_ERROR(GetNextParameter(&Walker, &TempParameter, Size))) { + if (EFI_ERROR(GetNextParameter(&Walker, &TempParameter, Size, TRUE))) { break; } } @@ -246,7 +256,7 @@ ParseCommandLineToArgs( Walker = (CHAR16*)NewCommandLine; while(Walker != NULL && *Walker != CHAR_NULL) { SetMem16(TempParameter, Size, CHAR_NULL); - if (EFI_ERROR(GetNextParameter(&Walker, &TempParameter, Size))) { + if (EFI_ERROR(GetNextParameter(&Walker, &TempParameter, Size, StripQuotation))) { Status = EFI_INVALID_PARAMETER; goto Done; } @@ -375,6 +385,7 @@ CreatePopulateInstallShellParametersProtocol ( // Populate Argc and Argv // Status = ParseCommandLineToArgs(FullCommandLine, + TRUE, &(*NewShellParameters)->Argv, &(*NewShellParameters)->Argc); @@ -1369,6 +1380,7 @@ RestoreStdInStdOutStdErr ( @param[in, out] ShellParameters Pointer to parameter structure to modify. @param[in] NewCommandLine The new command line to parse and use. + @param[in] Type The type of operation. @param[out] OldArgv Pointer to old list of parameters. @param[out] OldArgc Pointer to old number of items in Argv list. @@ -1380,11 +1392,15 @@ EFIAPI UpdateArgcArgv( IN OUT EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters, IN CONST CHAR16 *NewCommandLine, + IN SHELL_OPERATION_TYPES Type, OUT CHAR16 ***OldArgv OPTIONAL, OUT UINTN *OldArgc OPTIONAL ) { + BOOLEAN StripParamQuotation; + ASSERT(ShellParameters != NULL); + StripParamQuotation = TRUE; if (OldArgc != NULL) { *OldArgc = ShellParameters->Argc; @@ -1393,7 +1409,15 @@ UpdateArgcArgv( *OldArgv = ShellParameters->Argv; } - return (ParseCommandLineToArgs(NewCommandLine, &(ShellParameters->Argv), &(ShellParameters->Argc))); + if (Type == Script_File_Name) { + StripParamQuotation = FALSE; + } + + return ParseCommandLineToArgs( NewCommandLine, + StripParamQuotation, + &(ShellParameters->Argv), + &(ShellParameters->Argc) + ); } /** diff --git a/ShellPkg/Application/Shell/ShellParametersProtocol.h b/ShellPkg/Application/Shell/ShellParametersProtocol.h index 2fd8f8c88b33..926f36242cde 100644 --- a/ShellPkg/Application/Shell/ShellParametersProtocol.h +++ b/ShellPkg/Application/Shell/ShellParametersProtocol.h @@ -18,6 +18,14 @@ #include "Shell.h" +typedef enum { + Internal_Command, + Script_File_Name, + Efi_Application, + File_Sys_Change, + Unknown_Invalid +} SHELL_OPERATION_TYPES; + /** creates a new EFI_SHELL_PARAMETERS_PROTOCOL instance and populates it and then installs it on our handle and if there is an existing version of the protocol @@ -66,6 +74,7 @@ CleanUpShellParametersProtocol ( @param[in, out] ShellParameters pointer to parameter structure to modify @param[in] NewCommandLine the new command line to parse and use + @param[in] Type the type of operation. @param[out] OldArgv pointer to old list of parameters @param[out] OldArgc pointer to old number of items in Argv list @@ -77,6 +86,7 @@ EFIAPI UpdateArgcArgv( IN OUT EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters, IN CONST CHAR16 *NewCommandLine, + IN SHELL_OPERATION_TYPES Type, OUT CHAR16 ***OldArgv, OUT UINTN *OldArgc ); @@ -162,9 +172,11 @@ RestoreStdInStdOutStdErr ( parameters for inclusion in EFI_SHELL_PARAMETERS_PROTOCOL. this supports space delimited and quote surrounded parameter definition. - @param[in] CommandLine String of command line to parse - @param[in, out] Argv pointer to array of strings; one for each parameter - @param[in, out] Argc pointer to number of strings in Argv array + @param[in] CommandLine String of command line to parse + @param[in] StripQuotation if TRUE then strip the quotation marks surrounding + the parameters. + @param[in, out] Argv pointer to array of strings; one for each parameter + @param[in, out] Argc pointer to number of strings in Argv array @return EFI_SUCCESS the operation was sucessful @return EFI_OUT_OF_RESOURCES a memory allocation failed. @@ -173,8 +185,9 @@ EFI_STATUS EFIAPI ParseCommandLineToArgs( IN CONST CHAR16 *CommandLine, - IN OUT CHAR16 ***Argv, - IN OUT UINTN *Argc + IN BOOLEAN StripQuotation, + IN OUT CHAR16 ***Argv, + IN OUT UINTN *Argc ); /** @@ -187,10 +200,12 @@ ParseCommandLineToArgs( Temp Parameter must be large enough to hold the parameter before calling this function. - @param[in, out] Walker pointer to string of command line. Adjusted to - reminaing command line on return - @param[in, out] TempParameter pointer to string of command line item extracted. - @param[in] Length Length of (*TempParameter) in bytes + @param[in, out] Walker pointer to string of command line. Adjusted to + reminaing command line on return + @param[in, out] TempParameter pointer to string of command line item extracted. + @param[in] Length Length of (*TempParameter) in bytes + @param[in] StripQuotation if TRUE then strip the quotation marks surrounding + the parameters. @return EFI_INALID_PARAMETER A required parameter was NULL or pointed to a NULL or empty string. @return EFI_NOT_FOUND A closing " could not be found on the specified string @@ -200,7 +215,8 @@ EFIAPI GetNextParameter( IN OUT CHAR16 **Walker, IN OUT CHAR16 **TempParameter, - IN CONST UINTN Length + IN CONST UINTN Length, + IN BOOLEAN StripQuotation ); #endif //_SHELL_PARAMETERS_PROTOCOL_PROVIDER_HEADER_ diff --git a/ShellPkg/Application/Shell/ShellProtocol.c b/ShellPkg/Application/Shell/ShellProtocol.c index fc13595dbb03..9c370ccef5af 100644 --- a/ShellPkg/Application/Shell/ShellProtocol.c +++ b/ShellPkg/Application/Shell/ShellProtocol.c @@ -1501,7 +1501,7 @@ InternalShellExecuteDevicePath( ShellParamsProtocol.StdIn = ShellInfoObject.NewShellParametersProtocol->StdIn; ShellParamsProtocol.StdOut = ShellInfoObject.NewShellParametersProtocol->StdOut; ShellParamsProtocol.StdErr = ShellInfoObject.NewShellParametersProtocol->StdErr; - Status = UpdateArgcArgv(&ShellParamsProtocol, NewCmdLine, NULL, NULL); + Status = UpdateArgcArgv(&ShellParamsProtocol, NewCmdLine, Efi_Application, NULL, NULL); ASSERT_EFI_ERROR(Status); // // Replace Argv[0] with the full path of the binary we're executing: From b5e0f73c8f0e5344d17071e6791749700fb63fd4 Mon Sep 17 00:00:00 2001 From: Cecil Sheng Date: Fri, 18 Dec 2015 07:35:18 +0000 Subject: [PATCH 305/525] ShellPkg: Corrected CatSPrint usage to prevent memory leaks. CatSPrint allocates return buffer for the caller. The caller doesn't have to allocate one, and has to free the used buffers. (Sync patch r18902 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Cecil Sheng Reviewed-by: Qiu Shumin Reviewed-by: Jaben Carsey git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19403 6f19259b-4bc3-4df7-8a09-765794883524 --- .../UefiHandleParsingLib.c | 230 +++++++++--------- 1 file changed, 121 insertions(+), 109 deletions(-) diff --git a/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.c b/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.c index b6ce509af3f2..b211de7d1d76 100644 --- a/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.c +++ b/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.c @@ -1,6 +1,7 @@ /** @file Provides interface to advanced shell functionality for parsing both handle and protocol database. + (C) Copyright 2015 Hewlett Packard Enterprise Development LP
(C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.
Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials @@ -108,9 +109,9 @@ HandleParsingLibConstructor ( return (EFI_SUCCESS); } -/** +/** Initialization function for HII packages. - + **/ VOID HandleParsingHiiInit (VOID) @@ -180,10 +181,7 @@ LoadedImageProtocolDumpInformation( HandleParsingHiiInit(); Temp = HiiGetString(mHandleParsingHiiHandle, STRING_TOKEN(STR_LI_DUMP_MAIN), NULL); - RetVal = AllocateZeroPool (PcdGet16 (PcdShellPrintBufferSize)); - if (Temp == NULL || RetVal == NULL) { - SHELL_FREE_NON_NULL(Temp); - SHELL_FREE_NON_NULL(RetVal); + if (Temp == NULL) { return NULL; } @@ -198,29 +196,30 @@ LoadedImageProtocolDumpInformation( if (EFI_ERROR (Status)) { SHELL_FREE_NON_NULL (Temp); - SHELL_FREE_NON_NULL (RetVal); return NULL; } DataType = ConvertMemoryType(LoadedImage->ImageDataType); CodeType = ConvertMemoryType(LoadedImage->ImageCodeType); - RetVal = CatSPrint(RetVal, - Temp, - LoadedImage->Revision, - LoadedImage->ParentHandle, - LoadedImage->SystemTable, - LoadedImage->DeviceHandle, - LoadedImage->FilePath, - LoadedImage->LoadOptionsSize, - LoadedImage->LoadOptions, - LoadedImage->ImageBase, - LoadedImage->ImageSize, - CodeType, - DataType, - LoadedImage->Unload); - - + RetVal = CatSPrint( + NULL, + Temp, + LoadedImage->Revision, + LoadedImage->ParentHandle, + LoadedImage->SystemTable, + LoadedImage->DeviceHandle, + LoadedImage->FilePath, + LoadedImage->LoadOptionsSize, + LoadedImage->LoadOptions, + LoadedImage->ImageBase, + LoadedImage->ImageSize, + CodeType, + DataType, + LoadedImage->Unload + ); + + SHELL_FREE_NON_NULL(Temp); SHELL_FREE_NON_NULL(CodeType); SHELL_FREE_NON_NULL(DataType); @@ -258,10 +257,7 @@ GraphicsOutputProtocolDumpInformation( HandleParsingHiiInit(); Temp = HiiGetString(mHandleParsingHiiHandle, STRING_TOKEN(STR_GOP_DUMP_MAIN), NULL); - RetVal = AllocateZeroPool (PcdGet16 (PcdShellPrintBufferSize)); - if (Temp == NULL || RetVal == NULL) { - SHELL_FREE_NON_NULL(Temp); - SHELL_FREE_NON_NULL(RetVal); + if (Temp == NULL) { return NULL; } @@ -276,29 +272,29 @@ GraphicsOutputProtocolDumpInformation( if (EFI_ERROR (Status)) { SHELL_FREE_NON_NULL (Temp); - SHELL_FREE_NON_NULL (RetVal); return NULL; } Fmt = ConvertPixelFormat(GraphicsOutput->Mode->Info->PixelFormat); - RetVal = CatSPrint(RetVal, - Temp, - GraphicsOutput->Mode->MaxMode, - GraphicsOutput->Mode->Mode, - GraphicsOutput->Mode->FrameBufferBase, - (UINT64)GraphicsOutput->Mode->FrameBufferSize, - (UINT64)GraphicsOutput->Mode->SizeOfInfo, - GraphicsOutput->Mode->Info->Version, - GraphicsOutput->Mode->Info->HorizontalResolution, - GraphicsOutput->Mode->Info->VerticalResolution, - Fmt, - GraphicsOutput->Mode->Info->PixelsPerScanLine, - GraphicsOutput->Mode->Info->PixelFormat!=PixelBitMask?0:GraphicsOutput->Mode->Info->PixelInformation.RedMask, - GraphicsOutput->Mode->Info->PixelFormat!=PixelBitMask?0:GraphicsOutput->Mode->Info->PixelInformation.GreenMask, - GraphicsOutput->Mode->Info->PixelFormat!=PixelBitMask?0:GraphicsOutput->Mode->Info->PixelInformation.BlueMask - ); - + RetVal = CatSPrint( + NULL, + Temp, + GraphicsOutput->Mode->MaxMode, + GraphicsOutput->Mode->Mode, + GraphicsOutput->Mode->FrameBufferBase, + (UINT64)GraphicsOutput->Mode->FrameBufferSize, + (UINT64)GraphicsOutput->Mode->SizeOfInfo, + GraphicsOutput->Mode->Info->Version, + GraphicsOutput->Mode->Info->HorizontalResolution, + GraphicsOutput->Mode->Info->VerticalResolution, + Fmt, + GraphicsOutput->Mode->Info->PixelsPerScanLine, + GraphicsOutput->Mode->Info->PixelFormat!=PixelBitMask?0:GraphicsOutput->Mode->Info->PixelInformation.RedMask, + GraphicsOutput->Mode->Info->PixelFormat!=PixelBitMask?0:GraphicsOutput->Mode->Info->PixelInformation.GreenMask, + GraphicsOutput->Mode->Info->PixelFormat!=PixelBitMask?0:GraphicsOutput->Mode->Info->PixelInformation.BlueMask + ); + SHELL_FREE_NON_NULL(Temp); SHELL_FREE_NON_NULL(Fmt); @@ -356,7 +352,7 @@ PciRootBridgeIoDumpInformation( FreePool(Temp); RetVal = Temp2; Temp2 = NULL; - + Temp = HiiGetString(mHandleParsingHiiHandle, STRING_TOKEN(STR_PCIRB_DUMP_SEG), NULL); if (Temp == NULL) { SHELL_FREE_NON_NULL(RetVal); @@ -376,13 +372,13 @@ PciRootBridgeIoDumpInformation( if (Temp == NULL) { SHELL_FREE_NON_NULL(RetVal); return NULL; - } + } Temp2 = CatSPrint(RetVal, Temp, Attributes); FreePool(Temp); FreePool(RetVal); RetVal = Temp2; Temp2 = NULL; - + Temp = HiiGetString(mHandleParsingHiiHandle, STRING_TOKEN(STR_PCIRB_DUMP_SUPPORTS), NULL); if (Temp == NULL) { SHELL_FREE_NON_NULL(RetVal); @@ -429,7 +425,7 @@ PciRootBridgeIoDumpInformation( Temp2 = NULL; } - Temp2 = CatSPrint(RetVal, + Temp2 = CatSPrint(RetVal, L"%H%02x %016lx %016lx %02x%N\r\n", Configuration->SpecificFlag, Configuration->AddrRangeMin, @@ -618,23 +614,17 @@ AdapterInformationDumpInformation ( CHAR16 *GuidStr; CHAR16 *TempStr; CHAR16 *RetVal; + CHAR16 *TempRetVal; VOID *InformationBlock; UINTN InformationBlockSize; - + if (!Verbose) { return (CatSPrint(NULL, L"AdapterInfo")); } InfoTypesBuffer = NULL; InformationBlock = NULL; - - // - // Allocate print buffer to store data - // - RetVal = AllocateZeroPool (PcdGet16(PcdShellPrintBufferSize)); - if (RetVal == NULL) { - return NULL; - } + Status = gBS->OpenProtocol ( (EFI_HANDLE) (TheHandle), @@ -646,7 +636,6 @@ AdapterInformationDumpInformation ( ); if (EFI_ERROR (Status)) { - SHELL_FREE_NON_NULL (RetVal); return NULL; } @@ -655,22 +644,23 @@ AdapterInformationDumpInformation ( // Status = EfiAdptrInfoProtocol->GetSupportedTypes ( EfiAdptrInfoProtocol, - &InfoTypesBuffer, + &InfoTypesBuffer, &InfoTypesBufferCount ); + RetVal = NULL; if (EFI_ERROR (Status)) { TempStr = HiiGetString (mHandleParsingHiiHandle, STRING_TOKEN(STR_GET_SUPP_TYPES_FAILED), NULL); if (TempStr != NULL) { - RetVal = CatSPrint (RetVal, TempStr, Status); + RetVal = CatSPrint (NULL, TempStr, Status); } else { goto ERROR_EXIT; - } + } } else { TempStr = HiiGetString (mHandleParsingHiiHandle, STRING_TOKEN(STR_SUPP_TYPE_HEADER), NULL); if (TempStr == NULL) { goto ERROR_EXIT; } - RetVal = CatSPrint (RetVal, TempStr); + RetVal = CatSPrint (NULL, TempStr); SHELL_FREE_NON_NULL (TempStr); for (GuidIndex = 0; GuidIndex < InfoTypesBufferCount; GuidIndex++) { @@ -678,7 +668,9 @@ AdapterInformationDumpInformation ( if (TempStr == NULL) { goto ERROR_EXIT; } - RetVal = CatSPrint (RetVal, TempStr, (GuidIndex + 1), InfoTypesBuffer[GuidIndex]); + TempRetVal = CatSPrint (RetVal, TempStr, (GuidIndex + 1), InfoTypesBuffer[GuidIndex]); + SHELL_FREE_NON_NULL (RetVal); + RetVal = TempRetVal; SHELL_FREE_NON_NULL (TempStr); TempStr = HiiGetString (mHandleParsingHiiHandle, STRING_TOKEN(STR_GUID_STRING), NULL); @@ -687,32 +679,42 @@ AdapterInformationDumpInformation ( } if (CompareGuid (&InfoTypesBuffer[GuidIndex], &gEfiAdapterInfoMediaStateGuid)) { - RetVal = CatSPrint (RetVal, TempStr, L"gEfiAdapterInfoMediaStateGuid"); + TempRetVal = CatSPrint (RetVal, TempStr, L"gEfiAdapterInfoMediaStateGuid"); + SHELL_FREE_NON_NULL (RetVal); + RetVal = TempRetVal; } else if (CompareGuid (&InfoTypesBuffer[GuidIndex], &gEfiAdapterInfoNetworkBootGuid)) { - RetVal = CatSPrint (RetVal, TempStr, L"gEfiAdapterInfoNetworkBootGuid"); + TempRetVal = CatSPrint (RetVal, TempStr, L"gEfiAdapterInfoNetworkBootGuid"); + SHELL_FREE_NON_NULL (RetVal); + RetVal = TempRetVal; } else if (CompareGuid (&InfoTypesBuffer[GuidIndex], &gEfiAdapterInfoSanMacAddressGuid)) { - RetVal = CatSPrint (RetVal, TempStr, L"gEfiAdapterInfoSanMacAddressGuid"); + TempRetVal = CatSPrint (RetVal, TempStr, L"gEfiAdapterInfoSanMacAddressGuid"); + SHELL_FREE_NON_NULL (RetVal); + RetVal = TempRetVal; } else { GuidStr = GetStringNameFromGuid (&InfoTypesBuffer[GuidIndex], NULL); - + if (GuidStr != NULL) { if (StrCmp(GuidStr, L"UnknownDevice") == 0) { - RetVal = CatSPrint (RetVal, TempStr, L"UnknownInfoType"); - + TempRetVal = CatSPrint (RetVal, TempStr, L"UnknownInfoType"); + SHELL_FREE_NON_NULL (RetVal); + RetVal = TempRetVal; + SHELL_FREE_NON_NULL (TempStr); SHELL_FREE_NON_NULL(GuidStr); // // So that we never have to pass this UnknownInfoType to the parsing function "GetInformation" service of AIP // - continue; + continue; } else { - RetVal = CatSPrint (RetVal, TempStr, GuidStr); + TempRetVal = CatSPrint (RetVal, TempStr, GuidStr); + SHELL_FREE_NON_NULL (RetVal); + RetVal = TempRetVal; SHELL_FREE_NON_NULL(GuidStr); } } } - + SHELL_FREE_NON_NULL (TempStr); Status = EfiAdptrInfoProtocol->GetInformation ( @@ -727,57 +729,67 @@ AdapterInformationDumpInformation ( if (TempStr == NULL) { goto ERROR_EXIT; } - RetVal = CatSPrint (RetVal, TempStr, Status); + TempRetVal = CatSPrint (RetVal, TempStr, Status); + SHELL_FREE_NON_NULL (RetVal); + RetVal = TempRetVal; } else { if (CompareGuid (&InfoTypesBuffer[GuidIndex], &gEfiAdapterInfoMediaStateGuid)) { TempStr = HiiGetString (mHandleParsingHiiHandle, STRING_TOKEN(STR_MEDIA_STATE), NULL); if (TempStr == NULL) { goto ERROR_EXIT; } - RetVal = CatSPrint ( - RetVal, - TempStr, - ((EFI_ADAPTER_INFO_MEDIA_STATE *)InformationBlock)->MediaState, - ((EFI_ADAPTER_INFO_MEDIA_STATE *)InformationBlock)->MediaState - ); + TempRetVal = CatSPrint ( + RetVal, + TempStr, + ((EFI_ADAPTER_INFO_MEDIA_STATE *)InformationBlock)->MediaState, + ((EFI_ADAPTER_INFO_MEDIA_STATE *)InformationBlock)->MediaState + ); + SHELL_FREE_NON_NULL (RetVal); + RetVal = TempRetVal; } else if (CompareGuid (&InfoTypesBuffer[GuidIndex], &gEfiAdapterInfoNetworkBootGuid)) { TempStr = HiiGetString (mHandleParsingHiiHandle, STRING_TOKEN(STR_NETWORK_BOOT_INFO), NULL); if (TempStr == NULL) { goto ERROR_EXIT; } - RetVal = CatSPrint ( - RetVal, - TempStr, - ((EFI_ADAPTER_INFO_NETWORK_BOOT *)InformationBlock)->iScsiIpv4BootCapablity, - ((EFI_ADAPTER_INFO_NETWORK_BOOT *)InformationBlock)->iScsiIpv6BootCapablity, - ((EFI_ADAPTER_INFO_NETWORK_BOOT *)InformationBlock)->FCoeBootCapablity, - ((EFI_ADAPTER_INFO_NETWORK_BOOT *)InformationBlock)->OffloadCapability, - ((EFI_ADAPTER_INFO_NETWORK_BOOT *)InformationBlock)->iScsiMpioCapability, - ((EFI_ADAPTER_INFO_NETWORK_BOOT *)InformationBlock)->iScsiIpv4Boot, - ((EFI_ADAPTER_INFO_NETWORK_BOOT *)InformationBlock)->iScsiIpv6Boot, - ((EFI_ADAPTER_INFO_NETWORK_BOOT *)InformationBlock)->FCoeBoot - ); - } else if (CompareGuid (&InfoTypesBuffer[GuidIndex], &gEfiAdapterInfoSanMacAddressGuid) == TRUE) { + TempRetVal = CatSPrint ( + RetVal, + TempStr, + ((EFI_ADAPTER_INFO_NETWORK_BOOT *)InformationBlock)->iScsiIpv4BootCapablity, + ((EFI_ADAPTER_INFO_NETWORK_BOOT *)InformationBlock)->iScsiIpv6BootCapablity, + ((EFI_ADAPTER_INFO_NETWORK_BOOT *)InformationBlock)->FCoeBootCapablity, + ((EFI_ADAPTER_INFO_NETWORK_BOOT *)InformationBlock)->OffloadCapability, + ((EFI_ADAPTER_INFO_NETWORK_BOOT *)InformationBlock)->iScsiMpioCapability, + ((EFI_ADAPTER_INFO_NETWORK_BOOT *)InformationBlock)->iScsiIpv4Boot, + ((EFI_ADAPTER_INFO_NETWORK_BOOT *)InformationBlock)->iScsiIpv6Boot, + ((EFI_ADAPTER_INFO_NETWORK_BOOT *)InformationBlock)->FCoeBoot + ); + SHELL_FREE_NON_NULL (RetVal); + RetVal = TempRetVal; + } else if (CompareGuid (&InfoTypesBuffer[GuidIndex], &gEfiAdapterInfoSanMacAddressGuid) == TRUE) { TempStr = HiiGetString (mHandleParsingHiiHandle, STRING_TOKEN(STR_SAN_MAC_ADDRESS_INFO), NULL); if (TempStr == NULL) { goto ERROR_EXIT; } - RetVal = CatSPrint ( - RetVal, - TempStr, - ((EFI_ADAPTER_INFO_SAN_MAC_ADDRESS *)InformationBlock)->SanMacAddress.Addr[0], - ((EFI_ADAPTER_INFO_SAN_MAC_ADDRESS *)InformationBlock)->SanMacAddress.Addr[1], - ((EFI_ADAPTER_INFO_SAN_MAC_ADDRESS *)InformationBlock)->SanMacAddress.Addr[2], - ((EFI_ADAPTER_INFO_SAN_MAC_ADDRESS *)InformationBlock)->SanMacAddress.Addr[3], - ((EFI_ADAPTER_INFO_SAN_MAC_ADDRESS *)InformationBlock)->SanMacAddress.Addr[4], - ((EFI_ADAPTER_INFO_SAN_MAC_ADDRESS *)InformationBlock)->SanMacAddress.Addr[5] - ); + TempRetVal = CatSPrint ( + RetVal, + TempStr, + ((EFI_ADAPTER_INFO_SAN_MAC_ADDRESS *)InformationBlock)->SanMacAddress.Addr[0], + ((EFI_ADAPTER_INFO_SAN_MAC_ADDRESS *)InformationBlock)->SanMacAddress.Addr[1], + ((EFI_ADAPTER_INFO_SAN_MAC_ADDRESS *)InformationBlock)->SanMacAddress.Addr[2], + ((EFI_ADAPTER_INFO_SAN_MAC_ADDRESS *)InformationBlock)->SanMacAddress.Addr[3], + ((EFI_ADAPTER_INFO_SAN_MAC_ADDRESS *)InformationBlock)->SanMacAddress.Addr[4], + ((EFI_ADAPTER_INFO_SAN_MAC_ADDRESS *)InformationBlock)->SanMacAddress.Addr[5] + ); + SHELL_FREE_NON_NULL (RetVal); + RetVal = TempRetVal; } else { TempStr = HiiGetString (mHandleParsingHiiHandle, STRING_TOKEN(STR_UNKNOWN_INFO_TYPE), NULL); if (TempStr == NULL) { goto ERROR_EXIT; } - RetVal = CatSPrint (RetVal, TempStr, &InfoTypesBuffer[GuidIndex]); + TempRetVal = CatSPrint (RetVal, TempStr, &InfoTypesBuffer[GuidIndex]); + SHELL_FREE_NON_NULL (RetVal); + RetVal = TempRetVal; } } SHELL_FREE_NON_NULL (TempStr); @@ -821,7 +833,7 @@ STATIC CONST EFI_GUID WinNtSerialPortGuid = LOCAL_EFI_WIN_NT_SERIAL_PORT_GUID #define LOCAL_EFI_ISA_IO_PROTOCOL_GUID \ { \ 0x7ee2bd44, 0x3da0, 0x11d4, { 0x9a, 0x38, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \ - } + } #define LOCAL_EFI_ISA_ACPI_PROTOCOL_GUID \ { \ 0x64a892dc, 0x5561, 0x4536, { 0x92, 0xc7, 0x79, 0x9b, 0xfc, 0x18, 0x33, 0x55 } \ @@ -1290,9 +1302,9 @@ GetGuidFromStringName( /** Get best support language for this driver. - - First base on the user input language to search, second base on the current - platform used language to search, third get the first language from the + + First base on the user input language to search, second base on the current + platform used language to search, third get the first language from the support language list. The caller need to free the buffer of the best language. @param[in] SupportedLanguages The support languages for this driver. @@ -1690,7 +1702,7 @@ ParseHandleDatabaseByRelationshipWithType ( if (ControllerHandle == NULL) { // - // ControllerHandle == NULL and DriverBindingHandle != NULL. + // ControllerHandle == NULL and DriverBindingHandle != NULL. // Return information on all the controller handles that the driver specified by DriverBindingHandle is managing // for (OpenInfoIndex = 0; OpenInfoIndex < OpenInfoCount; OpenInfoIndex++) { From b2a2d3c39cc2c589326b0b693ac3297205d518bd Mon Sep 17 00:00:00 2001 From: Cohen Eugene Date: Fri, 18 Dec 2015 07:35:47 +0000 Subject: [PATCH 306/525] ShellPkg: fix RVCT warning due to CONST in typecast. Building the latest shell on RVCT exposed this warning: ShellPkg\Application\Shell\Shell.c(1090,69): error #191-D: type qualifier is meaningless on cast type The CONST in the cast was deemed meaningless. Removing the CONST fixed the warning. (Sync patch r18954 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Cohen Eugene Reviewed-by: Qiu Shumin git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19404 6f19259b-4bc3-4df7-8a09-765794883524 --- ShellPkg/Application/Shell/Shell.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ShellPkg/Application/Shell/Shell.c b/ShellPkg/Application/Shell/Shell.c index 8af66479a3b4..36063227a2d8 100644 --- a/ShellPkg/Application/Shell/Shell.c +++ b/ShellPkg/Application/Shell/Shell.c @@ -1087,7 +1087,7 @@ DoStartupScript( } Status = RunShellCommand(FileStringPath, &CalleeStatus); if (ShellInfoObject.ShellInitSettings.BitUnion.Bits.Exit == TRUE) { - ShellCommandRegisterExit(gEfiShellProtocol->BatchIsActive(), (CONST UINT64)CalleeStatus); + ShellCommandRegisterExit(gEfiShellProtocol->BatchIsActive(), (UINT64)CalleeStatus); } FreePool(FileStringPath); return (Status); From 322afa48f37a70db8c26a5c9561801861ad5d22f Mon Sep 17 00:00:00 2001 From: Qiu Shumin Date: Fri, 18 Dec 2015 07:36:16 +0000 Subject: [PATCH 307/525] ShellPkg: Add NULL check to pointer returned from 'AllocateZeroPool'. When CustomCumulativeToken is not NULL, the CustomCumulativeData is expected non-NULL. Add 'ASSERT' statement to ensure this. (Sync patch r18956 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Qiu Shumin Reviewed-by: Ruiyu Ni git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19405 6f19259b-4bc3-4df7-8a09-765794883524 --- ShellPkg/Library/UefiDpLib/Dp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ShellPkg/Library/UefiDpLib/Dp.c b/ShellPkg/Library/UefiDpLib/Dp.c index 4d109d037c1b..6b06d20749f2 100644 --- a/ShellPkg/Library/UefiDpLib/Dp.c +++ b/ShellPkg/Library/UefiDpLib/Dp.c @@ -13,7 +13,7 @@ Dp uses this information to group records in different ways. It also uses timer information to calculate elapsed time for each measurement. - Copyright (c) 2009 - 2013, Intel Corporation. All rights reserved. + Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved. (C) Copyright 2015 Hewlett Packard Enterprise Development LP
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License @@ -256,6 +256,7 @@ ShellCommandRunDp ( CustomCumulativeToken = ShellCommandLineGetValue (ParamPackage, L"-c"); if (CustomCumulativeToken != NULL) { CustomCumulativeData = AllocateZeroPool (sizeof (PERF_CUM_DATA)); + ASSERT (CustomCumulativeData != NULL); CustomCumulativeData->MinDur = 0; CustomCumulativeData->MaxDur = 0; CustomCumulativeData->Count = 0; From adec21510c8b70a78435c82d248594ee8a4d0e06 Mon Sep 17 00:00:00 2001 From: Jordan Justen Date: Fri, 18 Dec 2015 07:37:57 +0000 Subject: [PATCH 308/525] ShellPkg: Convert all .uni files to utf-8 To convert these files I ran: $ python3 BaseTools/Scripts/ConvertUni.py ShellPkg (Sync patch r19176 from main trunk.) Cc: Jaben Carsey Cc: Shumin Qiu Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jordan Justen Reviewed-by: Jaben Carsey git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19406 6f19259b-4bc3-4df7-8a09-765794883524 --- ShellPkg/Application/Shell/Shell.uni | Bin 4840 -> 2419 bytes ShellPkg/Library/UefiDpLib/UefiDpLib.uni | Bin 18146 -> 9072 bytes .../UefiHandleParsingLib.uni | Bin 32404 -> 16201 bytes .../UefiShellBcfgCommandLib.uni | Bin 18414 -> 9206 bytes .../Edit/TextEditStrings.uni | Bin 11484 -> 5741 bytes .../HexEdit/HexeditStrings.uni | Bin 13156 -> 6577 bytes .../SmbiosView/SmbiosViewStrings.uni | Bin 109944 -> 54971 bytes .../UefiShellDebug1CommandsLib.uni | Bin 139228 -> 140676 bytes .../UefiShellDriver1CommandsLib.uni | Bin 70806 -> 35402 bytes .../UefiShellLevel1CommandsLib.uni | Bin 43930 -> 21964 bytes .../UefiShellLevel2CommandsLib.uni | Bin 109742 -> 54870 bytes .../UefiShellLevel3CommandsLib.uni | Bin 44956 -> 22477 bytes .../UefiShellNetwork1CommandsLib.uni | Bin 21094 -> 10546 bytes .../UefiShellTftpCommandLib.uni | Bin 9952 -> 4975 bytes 14 files changed, 0 insertions(+), 0 deletions(-) diff --git a/ShellPkg/Application/Shell/Shell.uni b/ShellPkg/Application/Shell/Shell.uni index 25cf69966b733e7b2488413361cfab98c2249bfd..301d8797ff460a944de3123c34d6edbdd423112b 100644 GIT binary patch literal 2419 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 E2MdYQRR910 literal 18146 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 QGS3U_e`z$ezpmr|1r4*+QUCw| diff --git a/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.uni b/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.uni index d8e45d049638a4956ee09e51574bcdae0376f411..1d142e9c9801b3fbe9ded9e773572cbfdde96de3 100644 GIT binary patch literal 16201 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 S4{+lqMxL!RY$Nye!~X)pPorD_ literal 32404 zcmdU&eQz5#62|xM1MWK*DSGYQHEG&wgG134@Vkx1wqV(AgX_Ua?8Ft4*n#b|>3#US zdwv|zB&A)FE2*sl!Pf3-#d+q1Gs7Xd`rm&)Z9Z*Q^!GQt{@naYN1xukuQVSw>&;*F z`FeBJylH-IuA5PF(frih>e}bc!{)Q*AI<&o(U-cm(>!l}XuA|qIM-zPep&Eqf60RX;$?)cLY9f+}ZQyMp&;M_H%dVG_E7b zWu*I7)bh1jyl}0*);V0k{jKhJ?#|DIH|BVxJ1+FeYljC)BOSd`YhEX`a_zqTN}ruM z$$^P>efxa-d`#hI9goz))8?7}L-nmgLE8bztvGkg&c1TCkDX(cH{$rM5FzOYI=+^EJ{5wP-y2%dXud{vY{wy*2EYLzw) z9Q8w;ft_p6Jknj<168|gOZW24Cwl)*pMabmy*Z|0Tx>Q!+_e*0-<2!|vMOk9NbX*4 z{(VKCUrFBB0#>mvUE)Q)YPs`R*I!6qJ7de{8~CGZY0UZ?*85CU=ozDy7FL~hu}f_D zwuOqv<=ra?o0AW;hsCYaMpAq3%Ymr-PA7+ zgy~9%u7vAKcdw`olf;dV--<)?40wc>V{SvQ-xjr9XIEc~^0)eimm|Gpq-*p@ybWBN zcf=d5jB$nD16P6fXQGB|&-5RggZhP9;p{K^Gw*Lbh#o*c{KNWI(PWmHhm&B>_8N1R{tc|iR+UOrUYr~Ubb=XZ_HeHC0?i%#u6ctg>CS3Z!q zeX0z?B0B%K@9_1}UZA@s1eR&y_4Aq|E5P?|xjbY~NDjuBK!+#r7;5Z!ph!mad7=JI z{(CT%1lZ2i-}6|=%!XM6eXy*#cs+D^=b7k}vz&>eAg6xlQhkw85;Fs$_^7701soef zMnu1q)UXwc^m$peqxrlQ&mz!#UeH~NXI)kt%OgE5<6$hyxRnu;jb(i%)ki9zXqO0h z=0Q=ChVNCUvbRI^r&Ia#tqyA`v&pxPM8X7*&%(h%PZAuU?^{JuKs`MF|xUJ`*i z5sQ&dNe{*%5~oE!IGDHKsP^@l1`{~WB-<|=K5fbPF5um?B6ogwEu+&K^<>58y)P9L*=ri z%&`WQZ|zE&x>cK2b77vK+)M4dWfXP2#aatggG|T`i43`z>F*)CpR6_qo3W#^<@nZ^ z6}ZuhdCzO*w0Z0G->Q*FJ%%8Wu33>l7v62O*(HNAUB;ByD78ScXWx3eEP|FscX#IW zWSKtNoYcznc^PYsVx3vJ1xpJ_cIt0XT zYF><=@qa-(T^7UGd7xf>D%n$K$&Fgd7#KajQGX_5v=uXD1X#kli;2FzWYTD>HI)%q zYj_ol*Cq=)4p?lx*1n{4tCd#h>t)tnhw@5cPAh1o?Wl|~9^a%G3}Kh9_NAv9{|l-z zij;DY*bC{7^*XyQjvz;yO`*Tn;5*f7w$B#e31`6vJ!PhT>=RI-B zN*%J@bG01z;-Su1VaQnKxu}g?KE(gh+^Atpx$inFOC^WVWR;5ytQ;G-*tiIJS!=UP z#=hSri}ZR~GS*t&UN%(aCN7;cUlgTKrs!MyS*^`31>XvoQl6*J`eDk;;;32@HD2FZ zn@gYFq-Prsg~jWSpjTKmH^VvZ_tC2;SYG`df zS%h{@ie9oWDw9VTY2wMxG~T1~b*tHdTs+;;*k-7hQj>v{aj_Pfb;YyC5|5|bQo<+o zc=8sr>gI`&!6N2GRwa4X9ou>xvMuU2Rx4&K5#~yQ#+bRzR|D-1W{{ZIY^w(JlMD2= zl$A4z$xFvm_WK6f*5!HHH5!33Gm2PeIrsF`!#ZV8Yx=#GdRV1g$2m1~s{zng+UG87 zX>T}dpax(gqdEjOpUnInbs=_ku)ZOcKrMnerX9)xu+~1BNU=~QS)V{s6JJcPF%~K$ zj7&mxrYq8Un+R()*~4|9eI>REC62wdQlT%fQj__DD^)&jgru#CH*`Il5oOM+;!!tM zF=8zYYx->$&Zcz6jC?x6EF%mwsaUhFjXfz=x$%{(E?EU6skOA7^+A%i+d!4IFi+&M z*oDOEoN2m!sBS2lF}{5*i#=0o)b!W|LS^3&<+QRXk4HUkTY5Q=rfsd#iPH}&m*N^< z8I`rRElap^z4?{KWN3%A5R(-?UsXF&1qkb8uAV(cAu{A}vwv#ed3|b;JL>!UnpvHe zBv;C~zjwWz7{VM7dy`64k(hqEzLhzE6h|NW@k+_^Y(k78U2Qg9qwa&kauwSTSzn)_xyPDv=tUFvt8-e|VltwZ$%0tJ4IlHXEXfW|dpZD{LPYSK|Fz`4#tZ z?+j}fx6}jJg_NQ%OEP#TvK#YCzEWE6CD`kCGC?~=(g(+;a3DWqa;ctXnOI*eaTJM> z)aWzFq#a9XEEj8tQQfKAnbuxs?<1Mmvi$xq>Tz!hIbe(juZg!zqgaqoA3W@brstKS zSlqixvzTT2u@uUF$Eq-azuZxowzZbGMP~n2olhZe_&(DsYHZP3!`D8Qcd4U1?boNd zF7s-X%MxaJLe=7OyfVzPCbC>V4$DhnTWDByu&<2ZFf08U`9GHbxsdG7l)LP? z7W3582pebHvq&S3v2nIN`~HX+(X@{&TSXnBl80mrNgr8^rCMucOZ8O!-0-wU!j-Zl ztTo?O-YQCCoZ~dsuCNH;c#KiCYB-5)y{Gogp$X_e3A`b=ext>~JPds7&KIbd)ndGr{ zmSW9GIQ4sEquskO%XniivnB7#i1C#?aKBvytl;B0BsH%xrh(+=$EjW8b@GF*-IS9k z$`p@8u{3kxJqvXTdXqf?foCJ&pVBH*nc|M*JW{`~*>;mo`@JlQfG95qn{}&^LX8}b<^SfB zg2&U%d-$X*1&=2$0~@m~N(T7k`DEbn1Wvn;$};eH@-jG4Jm9HIWM9lc*<3_B-7?J+ zSNptFTVcm`o<2F&BFBj3nuk%O^0KYJG!9PkUFLXG5%G=M3G1`!>QXk7U0&-0qB4pt z=a1)E>*MiEN}%n$9#3BPL`8A})&!UAuS}DuNKRn$2mW~hc?9_0HV)gal@Y|bDNi(H zg(5S?B@9$H81Z6};n`KQV&LgzWJb25ILwLq9gcZ4tfyx#3w^LcJC`MwC2~BTZ(ARu z@pI=$rWOaQ6xj*hCJ(z-k0b71?S+ zSm&qed<2#A*BZgu6Cq<+)cLHqzfQ{_y;7D)=&yN8h^bE3rDmsEsziOK{@7IuPpQ^O z|2s*(R1J@JR?g39ytDG^Zr@7R_!J9YZ?Wu2PB|~@mUSS^yW2R?ymDB#)Hc7{g^PWb z=7&lWslk==N8TRt<5*@ae5|6DOvQz#U{1@aEG64-V7Zdt@npMd_QX<`S zO{T23fE3HVP|r53SRfefwMeAIqG=oJgEX!<+EZX|eiNkW-Zt+)`yfqsv;~xl*1kQB zE$GsY`XJ@Gxa3PK&MNbLwcP^uWPv=zH+}WP;M>67X2H-t)6x%vZ(~*rJj>=tBhhq~ zLO%>gssi)O24uPA#-SJP*zZ+JWt^T-$)u8e>%NhG=FjZ;L6;LA$A9`;zTZnwebd+r zifzaK+T?qD|Kw->JiceT!cSz(MMo;jaU|fWyTr#f+4Rxvp|r}nj~o3_SMVM-cm(EG z9=eF|P*1-kGEB#YHWZ7#7Hg^;#cWn+Inc)Q>R~UdN!lXWGNFxEdbDQ<%Y@cHQ3s2l z9?)*TmeKt2c6%T%>eo};D7uZB|ET{ht0nlVMv8hG?afm7giwv~Q7PEM^7XQSHnjpU z$7mlfiN|Fm#r(C;1cGc+yvtz=e#gN3ftHo5tcd10__16kZJ|Ay<+6rt%{x#B4kO6! zyrEClKz-|-au56E2k*fqvB#FNY#GG5R&iS$m-V;ZoP@r(Y#i|HdE3>%Sm~`Q(^i}2 z%=XEcJ|;PM?0zHY(USO;ZZ1;4xZGU$e!wqmScPY0BD%j1y71VkWRp$Vh#(!SEIO-i zYcJ09`8<6h^t6}Z%A|cP&sYTx7-ik)ohLC}Px<(E+gMHxOc(E?4hFL4chUoE?))lF ztUTr=SkZ^l*D{QBv7Ue&8{)U&hMI|GR@{E=>rz|=15{P%)%-T1U(0;m>Up|mil%vK zTVIWwr(b2B_)a=&VA$Jp1%3(7^MuyYKHkNF|Lrq&kFY{~O&Z9pNr?HV416)S*w4C|fnhF|eJjYE*}8NlBOseRs<(|j^}=&m$5YW@EeSg^+r5tGr5_jU z95~X76P`-R^PSgpbf7CX$KC!!Z_iDc3!9np_y3;nAyXeoa{S`LNVvzi-?GFYrEc zGwB7|cnH_Zy6MV9*kj6?cPh=SJ!YRD`_#y>$+CTp5@>~^a;)?B4i!;s#B(MJUAqEp z@85m(lzvCnvug9#$>&;l4#Vieqn>`R=a?stuma;FNziJHX_nR&TR;aL3z11dhtt3f1d3c)L@AQx;iKpu|GwGf zE@{haJFgFT3}R8_?l-e@?aZu>kLmc;tM9)%KIZ@Q@TZ@LG!oY$PP3gzN{ruSesXt2lisxV%V74KL~2le41Qvy6Y5I9BN`{A zh%qhC(%dhjH0e=4j!DuiC>MpuuSM8EEw)iXS)N|y{*L@4q;f0B4+2FuO0H<YZA}K^D$M5_Q6R!Oz_SdnXDhWj{K`?7q$RR z*+#+Ekc~uvQQ#|#iZYMZm0HIFoNX#BrWCiOMyh!Mmv^+r`xFe2UrN+%S!N%OkJAj? zrd1w@UYcJW*E5RabrE*!FTHG=@f102apur;=6#&?&uKiT(RjX?jR(txGoqzCa%RK> z^ZfdAJmtXb^0!U@$wV zv6w{bUX?`VeSZy6`a#*um_xKsZ-|LWt({Gp)6zK|(|ju+=Qq6*8VpZA60CtiH5h-= zt5=W~?tVSskAv7xt^h?uBIz#Y)Dg*592MJ+e9LMCEeLY;(Q#Lo#uG1gpie&t^Y zJ^k?PusC!-(7D*9`5nO+lC*5>toKL$M*{4F2guOdU~&)Iio8tzOwyZ#HnD#N_xV9l z{NZWf)kS|&Gi?PP_#s{UaV1))FwFdglpq`sSvp2GWTkW-6$Q)H&#x*OE?!P$+J||s z#_ok7W2G`qu$l;7rKvnCEG%I(8(%oH)xh%>Ou-61%A;!p3`l2?LczPLDA|t-5sRQi zpt7igaaW!@`SLvbkK#&wY(el(aYtz;gOiQc!t++A&SyjEiPbF9ls4kVh^lxB^PIij zTviD&CcN+NdC=4G#94V$IM``_EX~vkI`k9vCk~CYi4aYm)#)k1lfji-Tft8mkl|G{ zeij-b@7S9g26!ErK;vaEXw1^5*u?{Yqhq zJ(X3m^{)kI7}$KLez~>Eifzf*Cf`_>Be!MNxRwxS48a!kc2!(P8Q!pkJ?aWla>i^m zy>B2DA}(n|esV3V(Nx2K(^`VGiWLcDF^E(p+XCeGr0^E~*+*xwa!)l$>xza39=mXe z?5X0sszj(2CE8xM`WR3ex<{ccXpgPIKAl48o$`X(R*>@6$Q9cPalcT zQmKrHZNOdXZQhDnhoS(^08jfQ?hbHa14Yh>gz|$-UpXmFs@+=Th4Pn^+Y?-fS|_)s zxRhD11)>=X&?+;qGgu)N`>1W(%9UGF(;Je?YY(4*_FN6Bbg~ESrh2DQfl+gLKZ}vl zn|MQ+92#Etz-kjQVNmn=3$$%#a^fLKc~g~lGMjt2p4G9fEHz% zBThsKxfjUev?WQ<`4`ulq6E>vq;KR36c_(Ut}erBm(gYS`s-J^^uv%2R4&j7p`(s^ zmOXr^(Tptg4I^wZy54*YNWP;3VC}B)4mbAsUF2aHb9u?zMS|+)>pz#B&@cTC`1{8` z(J+A6F~V^AWghs+FhyOuOrijv!>ynH_VueK&7!ZJKtF1scds=d8|f%2ve>^X2(f>i z76LLyl8qe>6~tA@2{|iKJ@#WmqJfonyfULWkmA+XSBoqX<6Rm? z8&wlGsKnFBFN!pX5H~}*iAq$^t#xQH^{MpEdA3x&Vy;K3{P$7(3)JgeW^GdBRyP1# z-^pdj?2xrlSKPMc$Z^s@Vf&>Yq1czE93?*LH_0t_PNen^dB!Lk=A%p-!Aj60UJ?`f zt4d2dkcgul5;=Gwi_OYN?WDl8vDA{@eMVZUtl5@=e?padb<%v$R4K|9hNSbnIkee% zfFPZFAE7bLha@=y=&MWpFy!t{y-2nc0q2B)Fo4>N*&=G=XOZ&!D6t7{D{j##3Zk7K zbMXZaQkac>Y3#<l?+Xp0LcGq!hSL@ZNRn0cZjnJ0aBAshejPJg>eqTupNp5sp5qT$ zq-;e*l==zE)aT~b;-jo6{)tOY;Z5oUu}za zMP*v553T#5qI|0L6UYs*M_v-EXo#*V2YVZrb$hcV9&FV1@XMyj3$}12 zV{9R~UA|AwhOVO~x=x0ZmZj9*z*J3HfUu=gC1$Wo^Ew(SNoP2RfWfI2=EL0@u_`UQ z=$f^Hl}WcA0poUZSN50zSs*V%GZ~3l?MKh#6qt(^&zU#tkz}5i(oT!jN!1`n*LMnI^0yIB$YDC*Ar94>fzs7R@Lh4T+@t zx5!h)-;vZt=7Ytsosg=xb~e#~m(3cV7^}PXxig?xY$ml5+&w+k?`kROcpM-X#yJ3z zy+&3tHZ`EqYRw-u-~WrOj9JM=+t|B_ULYvW_(#rsI2+5_*I?-z*IPLA5BeL?>)OET zgAeY%K3kmGYBIt(3N2ANupnhp)+7`-;Nt2+_P%A?1DobZW(e||NUoziO=N3dH$+Sy z4PN}V0p{eZ!R2qTL&Ssu%FjoTo25d}kCAD)_q&D)qIW|iM2{XF8~?wiaU|{FoI+obbjySG|$l%!8b#`? z?l;wWsE4tY8BWa&-9v0u4uus@4tfciy*mCjI@G;3{F)oZxU%Vcf}n%mVP$4=BAcE&Kj@K^Pu5kHt7y@9pBC|N8#rE`S0#$pNh89lLc*S~I`wek--2Q!Gee72pFqjeF5~VR21l&@ z$#}Gq2d>TnXZwV5LU&V;P8QhLyGY1Q(pyL_(M(EnmDOm`v>4gDRV6hq3IQuZ&a84H z=1umfHt74Hhuz*i)H0Xud^w$ZGyZvlzFGoni%9ZSB}J8S`gSj$tcC9kmpEhlvbq?1 z6WPEfm8fm1q>(?L*JL7Rj=^q-b8@7`D7i#X;jr!QC9A!T(pdevr5UYQ;Il;UbcG*J zc*_|qftQ5kpl8aWKt@+>Hc=4qZ)-NWKqnR1F8^#q6|1#w8&EBg{ZH_WW|pxft@rQ0 F`wva#vRVKD literal 18414 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 SZE3j2Eqd(wr8Y-cng1WBXS7!U diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/TextEditStrings.uni b/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/TextEditStrings.uni index a61cae33d3f32312741b0505e85395fd51903b98..f79914813553d612b17ee35fbdeccdace41597d7 100644 GIT binary patch literal 5741 zcmbtYZExE)5dNG2`wxc{0k*7;2Df?kqlzkWx` zl%h(ZoW?-H7u`M2-SH$I+3!RD`1sdf`hETfqbPn%{PiY--@M=9?DX^;de{sGZ@~yN z7N9^9M+wdRC_Diz2tY`ukg${`_iTCc=g|6FKsg&fg*b`U3Ect>mym53P|u6DF%2L6 za1C3UvBalAD&%RxAn-jFrfezXw{(dL_tX#QUBDm@mn;z=sI^Unh!=%RpWBi`v=YyT z_82Awia>qX_}-?Z^;wEiXxGwDv&6s43qKsRY?Y%k8T+0|q@68j==M#gBPfGi=JB$kTvQO2_vWPDYfCmg0ZOK-C zxQqEJO28$$0rrMr^v+IBVa)FG^?J)3)g|4ZVtuM9W_R4LB@u&m>5Ie&a8!FI1@6|EL7ybg9Cw-(>0SoM`TL< zklTUAa?4?b8HFhph2Z#Ez=pJ#|CW3Uk4z+d^E};DGt4P5-GWX0--GahrVvIMq`Bv@ zG{sEg=SvJWsA{-Xr?=Fi+q_&UchLW$Ix7LPSufLm|Ga*Cp^s{ z^PJ(adks&SN)=Nho>hvxhDoN4BsyqG+Ao)5c^K$$h2saOV*v&(^a8JgVbGg-zzT|B*Jb7C%dzzz;@JzA`v;l>6$S{*>P z_L(SwY)+HCcz*u07FwsV&?L91D`WA}=>U9N) zr_aLqI>%rai`EDe&mV9e<4&XjckEe|L5E-ZnNt0%OZ}Zv{au&(d!_pOF7ZOZ`%*e%Yn|L8<2O5A+;+m;w!vJJ$-Jndt50v)YrN9eEQrgeFYL6}K7xNZ(af6`xCVcV%-&N9 z{s|t$+JeyFA4Or7L;>8eN95J>(BlWl-EdSKbDlFu!9O-Ww`w)`d({sWszI;!!%#e` zV=DNoeX6d~;OFVsyOKisK=wpi?Pj%UIZ*JIWrUR7we9@2l+w>+PqbyNQJXCX3jSvG zQE0XE|05ywcd{p1UZB(_>H`ITu{GDl`KX;=mxB6x*%NKCeb=U*4m$Z|X;3M(^Ot8Z z{k#&zUcG#%J>mlezpUGS)M@80zZCjKO+i+7waIFr;I9h4N}TuF`ODM4epwT*%EH>T z94Pq9dR)rx+IIe#l+r)Qo@mRWy*6786#Qi^R|*%Mc7Ac-;R5={ntWOB)n?0qf}g*C z3%(PS!bPXS@1_jIH|Q3!2pE6i#C0BCKXvX)?fm>SwJ^-j+Qb-(lgz@@ro1}lzXt!& zHN%UfBl8p9hThY_Uy8F0m~_jYJKXOG&_P|pl6kBsS)QWf4IASBCoWoFaFrm~ikp%r v#g)>Nqf}|SYu=c%TT@)T;e{KqEM9UcBIAbthS5VPuKw`KjU-8w>=^zBxH~X~ literal 11484 zcmc&)X-^|Z5UsC7%6}Mvka8@CxmhKVu<@`KU=wUZR$9s8UTeXuY_l8kYBd(`*%fF#KZ3wTtCVWNUcoop48+~KFhNVr7w5#QO2nIlU&Kq zxUb17u1%ztCQlWq$Qz^^GC<86xks83hLFMk3*`2Z8ptwA_E63mR`y6e-N*><4&@8} zuTk?ismiJR5kS=el0IsAkUNCDJ0<%8&liw=jr$liZq)M?&_2ooYO?GZ?+sAjLk`hU zPamm!NHgpyWvJf1N7)rp1BHlkjeNd+J<;$5={_V}$R+-%^+}PzedQhm16e1(u z{?sny^eDH1_o~vCeLNq9uvn~Ll`XFDPjq3neW0O4T0`55x<+^=>r3Dawg;_B^tZ^@ zEkn$IqfQi4*e=?Z&!}}ddH-=@0U{a)>`MO`qb1%dFQaE^+p_*pS$Y}lhiIP_APCxi zgq%wtzlN`cOO_$!BYwsr=I%*H-bo#(PT)N)Il%v(9OJnGi+Zpr?;Yee;9p&&>dMYt zY2sc-zLj9xpaFlbqefdvZXrcK=KnnIluN1exL4IPpWaNdd2)_&;%X_4eBOg5B5NYQ z0jZSHQrb`PMC{C?&JJp^4z=o9KI-z#_qZRTgviJu%RMP2@y%CXWLu*C_yiaPhv z%Z%O3oswyB`U?GOj8-#c=FU3TA^&Ah@}?f9dm8)6En0JcpYgX5YTc@~_F##+_`u`?|`^zNxRrz4y$`&|}PZ9XkP zD&N0@1Y-8oMIT)PO4@E7`7Eaoj(~PP@UH1snzi<=p0Y06yr*nkoj$XTd#XJC9OPFw33#fZw@JivbkXDoTU( zKj7&D>MX*eG{c2Ro91J84F8~49s^es77TK;X=`;ChF`&fUNrzaG9JNa7!4T#N8rzx zW|$jm9V<&dA>VlCteDe2?5*?~MuKR|YWClsc^kH2On!n*zE!KU#ZSPzlfvAakzW^S z^#*+7GnkLR8FNN4-Iu$FXg<6?solSStNZY8#>*<$-{R6ElUe&bzfHkd*2A}w*5DVa z3y;X_^YOTJrO-1nKcNLZ$XBiXyMY zDH?5}jOLWzWpj#0hu3116h-2!vKb}!`qyG*#sVB|GEV664_l8%pCx3&u6=m8Jc5srY2YZrOHhe0$eka2^)&)G3&RBq_Z z_l<4$Ud5zf6v`KgO#ET{J*%kXim5VfG23Q&u~eKbvgV+D%~|`pgZ6c2?Hdl-H=MO^ zI%wZ?*1qMSeal(cDTb=F={Yn#z;ME-cQIs*h;Pc4tYJ?2%g zgXDt1HSX2$?Ks7Ek!!SNanvx%8{)h8D`dERfh?Ny8K61OjfQ(9NB9Z{*P`uMH!YPt z=6i>+!o6CtNs}}CGOk_cZ4Jx6s>Vo7?4;yFl+8b%oY~hZ$DdaqD%JJvA#MuO09*x=jm#}XXzqIUlzRpQ6 zwQr>%EXO}-K9!~=o4<*UOW1vlO7hiyUNqM{C(X@FS@yjg|M+S|x~3xhxpx@8eD(DU z=h>(Dx`r*wPL<=IXYC`Xy9ob3BkbA#*JF8Bx>-T7IYmXX%d%7D_{Z1f(lr&~Z+Cc%OkZ|W_{Z1x%zJt6<@lTLUr(JI zx#$z4efbB7?ffNe*U_9nD$k8)6wR3uvuYD=5Bf~DPbTr=-eP%VJTZBQUkj%hxw{zN p;pG{aQ`H9L@pa)dpYVIc$q(*6hEKWGF~8&tlV{fSxivla{~x9-GJ*gA diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/HexeditStrings.uni b/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/HexeditStrings.uni index f52193106f022e90c8752fba3738d5d6ec10330b..d9591ca13da0f6d663db305bd5b153a65c459573 100644 GIT binary patch literal 6577 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 SI&wb4-HY6<`oWfVZS)_J>Eg@) diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/SmbiosViewStrings.uni b/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/SmbiosViewStrings.uni index f36882573a5fc8ecad9e9cb4ecb02e586982a7b3..24fca87adfa2104d9877a261727a4cb96c435b96 100644 GIT binary patch literal 54971 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 GZ~q^FQ5%#1 literal 109944 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 diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.uni b/ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.uni index 2d9bed75c60e9689aab39654f005c2b95690fbb0..448897024f199b23370ee36914188c9084f6a72b 100644 GIT binary patch delta 808 zcmb`FPiPZS5XNWHbhE}*LjP-`Spu!1ZOJB9d(k!lEfHc%lT?yeO=T0?5=|N#h!R9l zJf`AP=4dP46p2*G!9WU%2wv*NlR{7Gsp!p+3OEk73u5IK;u|W|I5xLmn=HJ}dIy2LTx6@vmpdcOL^HD_N-{j@inI)9ANQb`P5A zW*lEM*6*b^B|Jc1pP_>m`%$LwDB1>ckl{}!cMfte0~*sz@+!sITwOWH&<*t|W~}Ks z@g&kopJ(}w2S>4sN>#Md+Y!jf_ zEAfo*J=#fm#GqfLv4w_1X!fR=-vy<9yH({<8yzobrMC%HA0=)(f;AgRb) cSNEg2brbq8jnLs0RB81&Ua4H2!!wV60RNrHEdT%j delta 164 zcmZoU&2eWx$3~`*1F5xtq{3_T4 diff --git a/ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.uni b/ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.uni index a28985300e18d78785e752ac57fd71a966704442..a14469afdb53e659d941e54906690cdde4be6fcb 100644 GIT binary patch literal 35402 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 LF;=67tmpp#1>jX@ diff --git a/ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.uni b/ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.uni index cc2c33cda4a6bf1c4f5dbc8527dfaaab5185ca53..60f48f4633d7d12b4b4426812732990b279e759d 100644 GIT binary patch literal 54870 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 literal 44956 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 F{{gac1vmfz diff --git a/ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.uni b/ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.uni index 43259591820582cc38937ad680739fcff21b96c5..4c68e416406a8a9a985feec992f6bdd45bce8ce2 100644 GIT binary patch literal 10546 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 Jh5h=={{Vh46Egq+ literal 21094 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 diff --git a/ShellPkg/Library/UefiShellTftpCommandLib/UefiShellTftpCommandLib.uni b/ShellPkg/Library/UefiShellTftpCommandLib/UefiShellTftpCommandLib.uni index d12a87cb56a06ec796d3054e0aa9fd158937f004..33a8944504c3484ebaf53e9caed7c624b192a136 100644 GIT binary patch literal 4975 zcmbtYYj4}g75%=z{)Y<%hIS2`vePu^8fgGoqGF;lC5Y5I+oTXi%*V{R=ia$b_IlJiKmYlsUXTCim%*^PIjE>WqZp?s8)-fd-^(RljlcJ|qTGyuN@zcR=bUGl%{3v#eIf`nwJ6Okz$ zThxytGU8H7WGa(K8Cq0h`5TqeF45~mY)Ql+WgAH%2=sO*;wKfaX)C}-i6}L)MItFu zfs9ibn)O=|V#A|Qkyu8O@;H=<0l}_qYL)~#4i%G0Nw3ViTW?6?0>z;2H!9fFVwFs> z3cNyGCNA|| z>hwJ<@6c`EbG!?K^x*h+lete1{n@PV`i||7{gv04<<9+d?ASxA=6A2d9F}&)R^HSP=W?aIjf^6HmF)(4yTw_K)zZpiRj=tU zVNMZb%`Ok-#Sw?t9G54w(h1G&kwXTJ{EVN1&tWZG{q-IHdl!j#4HzPl z@#Wm3j*QolN;e(zmX8r~V93Q6+gN@MZhi(J7i(GVKf60i&)ggGwZ`GbPb89c z&XJIQPrk>1eRl$MWIr^JM6ZIb}X&+9oaNOS;)E6 zliiN(`v&_J#`E|`toJdkBC&oOdE|`k#bgRokNVEo2zZhAK*X^|JRwSGrQld^@*d2_ zqc&+=AEB2jA087s)54z37Vc!>I)e)1XtS#+mf2n>KS*&lT!}zZz{%0Xw{^mv4YV^@ zxcz&(06&5rAyFZ7Wt!G9Gr1^6997xm1*vhqT_UTUg|N+8@|tvGbDXO`8BE5&7VYSiE8G(#u0)fuX8BzGd)(6>kjBC2ld^~`WGHC;jt zQD0D-oI$=MZzlt_;{Hj*Bto%+6A>r43sRP}E=XpZt15kVh@cSbQy&YmP6NT7VR#j5 ziX>>EDP4&?$_UjiM+BsF)lh1H>Z_`!G;+#BicKQVG&)NKwIkH_G*#;ujcEe~`@T-C zFyR~AKK|B*e0EIGmV3&Q6t|{0FtnbU&?d#{R`EIgGnY889h!5QnRd3JSnJqa>;*P) z3njSO-l64{mJx#9=+J5(+r(PVVz8bQOC|TvhS~`UBvv@*S9zrpEjXf`X|**vahxC0 z7Bl0lje78y(m|ezVDxyNNXVH!et^G)(7C<)nV0i!6IVqD7lCd3A0|Ia;4Kyh(ZOsk zY0LqG#x>1UYzCbMt=`DtGqkqTK8n(Tg>W=8TI4VQ2Y6vgz9Fg9rrNM)MkL$GK9tYnW*6Bis96_?YHNS5e1*=8Y5!?4mx`ElTh zHUgGhN-)EaA7~^IEDLipCPK&ozco0RN^_NjsGI_QM*iByl0q7(PMXRks(^8 zS2y237rjnf#382!wvx+g&uo7_bARuT=OjY5hZf!QFaIm;G32NOkK#nP7iy{9fYKmYU}iD~ml literal 9952 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 From 91cf863a549d441f73ed55b19af95c5ff65d7913 Mon Sep 17 00:00:00 2001 From: Jaben Carsey Date: Fri, 18 Dec 2015 07:38:33 +0000 Subject: [PATCH 309/525] ShellPkg: Make 'dh' support showing all spec defined protocols. When using 'dh' to dump all protocols installed on a handle, some of them are shown as 'UnknownDevice'. Device patch make 'dh' support all spec defined protocols. (Sync patch r19177 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jaben Carsey Reviewed-by: Qiu Shumin Reviewed-by: Ruiyu Ni Reviewed-by: Samer El-Haj-Mahmoud git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19407 6f19259b-4bc3-4df7-8a09-765794883524 --- .../UefiHandleParsingLib.c | 123 ++++++++++++++++++ .../UefiHandleParsingLib.inf | 115 ++++++++++++++++ .../UefiHandleParsingLib.uni | 116 +++++++++++++++++ 3 files changed, 354 insertions(+) diff --git a/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.c b/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.c index b211de7d1d76..6f093ffe0e82 100644 --- a/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.c +++ b/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.c @@ -1025,6 +1025,124 @@ STATIC CONST GUID_INFO_BLOCK mGuidStringList[] = { {STRING_TOKEN(STR_IDE_CONT_INIT), &gEfiIdeControllerInitProtocolGuid, NULL}, {STRING_TOKEN(STR_DISK_INFO), &gEfiDiskInfoProtocolGuid, NULL}, +// +// PI Spec 1.0 +// + {STRING_TOKEN(STR_BDS_ARCH), &gEfiBdsArchProtocolGuid, NULL}, + {STRING_TOKEN(STR_CPU_ARCH), &gEfiCpuArchProtocolGuid, NULL}, + {STRING_TOKEN(STR_MET_ARCH), &gEfiMetronomeArchProtocolGuid, NULL}, + {STRING_TOKEN(STR_MON_ARCH), &gEfiMonotonicCounterArchProtocolGuid, NULL}, + {STRING_TOKEN(STR_RTC_ARCH), &gEfiRealTimeClockArchProtocolGuid, NULL}, + {STRING_TOKEN(STR_RESET_ARCH), &gEfiResetArchProtocolGuid, NULL}, + {STRING_TOKEN(STR_RT_ARCH), &gEfiRuntimeArchProtocolGuid, NULL}, + {STRING_TOKEN(STR_SEC_ARCH), &gEfiSecurityArchProtocolGuid, NULL}, + {STRING_TOKEN(STR_TIMER_ARCH), &gEfiTimerArchProtocolGuid, NULL}, + {STRING_TOKEN(STR_VAR_ARCH), &gEfiVariableWriteArchProtocolGuid, NULL}, + {STRING_TOKEN(STR_V_ARCH), &gEfiVariableArchProtocolGuid, NULL}, + {STRING_TOKEN(STR_SECP), &gEfiSecurityPolicyProtocolGuid, NULL}, + {STRING_TOKEN(STR_WDT_ARCH), &gEfiWatchdogTimerArchProtocolGuid, NULL}, + {STRING_TOKEN(STR_SCR), &gEfiStatusCodeRuntimeProtocolGuid, NULL}, + {STRING_TOKEN(STR_SMB_HC), &gEfiSmbusHcProtocolGuid, NULL}, + {STRING_TOKEN(STR_FV_2), &gEfiFirmwareVolume2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_FV_BLOCK), &gEfiFirmwareVolumeBlockProtocolGuid, NULL}, + {STRING_TOKEN(STR_CAP_ARCH), &gEfiCapsuleArchProtocolGuid, NULL}, + {STRING_TOKEN(STR_MP_SERVICE), &gEfiMpServiceProtocolGuid, NULL}, + {STRING_TOKEN(STR_HBRAP), &gEfiPciHostBridgeResourceAllocationProtocolGuid, NULL}, + {STRING_TOKEN(STR_PCIP), &gEfiPciPlatformProtocolGuid, NULL}, + {STRING_TOKEN(STR_PCIO), &gEfiPciOverrideProtocolGuid, NULL}, + {STRING_TOKEN(STR_PCIE), &gEfiPciEnumerationCompleteProtocolGuid, NULL}, + {STRING_TOKEN(STR_IPCID), &gEfiIncompatiblePciDeviceSupportProtocolGuid, NULL}, + {STRING_TOKEN(STR_PCIHPI), &gEfiPciHotPlugInitProtocolGuid, NULL}, + {STRING_TOKEN(STR_PCIHPR), &gEfiPciHotPlugRequestProtocolGuid, NULL}, + {STRING_TOKEN(STR_SMBIOS), &gEfiSmbiosProtocolGuid, NULL}, + {STRING_TOKEN(STR_S3_SAVE), &gEfiS3SaveStateProtocolGuid, NULL}, + {STRING_TOKEN(STR_S3_S_SMM), &gEfiS3SmmSaveStateProtocolGuid, NULL}, + {STRING_TOKEN(STR_RSC), &gEfiRscHandlerProtocolGuid, NULL}, + {STRING_TOKEN(STR_S_RSC), &gEfiSmmRscHandlerProtocolGuid, NULL}, + {STRING_TOKEN(STR_ACPI_SDT), &gEfiAcpiSdtProtocolGuid, NULL}, + {STRING_TOKEN(STR_SIO), &gEfiSioProtocolGuid, NULL}, + {STRING_TOKEN(STR_S_CPU2), &gEfiSmmCpuIo2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_S_BASE2), &gEfiSmmBase2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_S_ACC_2), &gEfiSmmAccess2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_S_CON_2), &gEfiSmmControl2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_S_CONFIG), &gEfiSmmConfigurationProtocolGuid, NULL}, + {STRING_TOKEN(STR_S_RTL), &gEfiSmmReadyToLockProtocolGuid, NULL}, + {STRING_TOKEN(STR_DS_RTL), &gEfiDxeSmmReadyToLockProtocolGuid, NULL}, + {STRING_TOKEN(STR_S_COMM), &gEfiSmmCommunicationProtocolGuid, NULL}, + {STRING_TOKEN(STR_S_STAT), &gEfiSmmStatusCodeProtocolGuid, NULL}, + {STRING_TOKEN(STR_S_CPU), &gEfiSmmCpuProtocolGuid, NULL}, + {STRING_TOKEN(STR_S_PCIRBIO), &gEfiPciRootBridgeIoProtocolGuid, NULL}, + {STRING_TOKEN(STR_S_SWD), &gEfiSmmSwDispatch2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_S_SXD), &gEfiSmmSxDispatch2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_S_PTD2), &gEfiSmmPeriodicTimerDispatch2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_S_UD2), &gEfiSmmUsbDispatch2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_S_GD2), &gEfiSmmGpiDispatch2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_S_SBD2), &gEfiSmmStandbyButtonDispatch2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_S_PBD2), &gEfiSmmPowerButtonDispatch2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_S_ITD2), &gEfiSmmIoTrapDispatch2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_PCD), &gEfiPcdProtocolGuid, NULL}, + {STRING_TOKEN(STR_FVB2), &gEfiFirmwareVolumeBlock2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_CPUIO2), &gEfiCpuIo2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_LEGACY_R2), &gEfiLegacyRegion2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_SAL_MIP), &gEfiSalMcaInitPmiProtocolGuid, NULL}, + {STRING_TOKEN(STR_ES_BS), &gEfiExtendedSalBootServiceProtocolGuid, NULL}, + {STRING_TOKEN(STR_ES_BIO), &gEfiExtendedSalBaseIoServicesProtocolGuid, NULL}, + {STRING_TOKEN(STR_ES_STALL), &gEfiExtendedSalStallServicesProtocolGuid, NULL}, + {STRING_TOKEN(STR_ES_RTC), &gEfiExtendedSalRtcServicesProtocolGuid, NULL}, + {STRING_TOKEN(STR_ES_VS), &gEfiExtendedSalVariableServicesProtocolGuid, NULL}, + {STRING_TOKEN(STR_ES_MTC), &gEfiExtendedSalMtcServicesProtocolGuid, NULL}, + {STRING_TOKEN(STR_ES_RESET), &gEfiExtendedSalResetServicesProtocolGuid, NULL}, + {STRING_TOKEN(STR_ES_SC), &gEfiExtendedSalStatusCodeServicesProtocolGuid, NULL}, + {STRING_TOKEN(STR_ES_FBS), &gEfiExtendedSalFvBlockServicesProtocolGuid, NULL}, + {STRING_TOKEN(STR_ES_MP), &gEfiExtendedSalMpServicesProtocolGuid, NULL}, + {STRING_TOKEN(STR_ES_PAL), &gEfiExtendedSalPalServicesProtocolGuid, NULL}, + {STRING_TOKEN(STR_ES_BASE), &gEfiExtendedSalBaseServicesProtocolGuid, NULL}, + {STRING_TOKEN(STR_ES_MCA), &gEfiExtendedSalMcaServicesProtocolGuid, NULL}, + {STRING_TOKEN(STR_ES_PCI), &gEfiExtendedSalPciServicesProtocolGuid, NULL}, + {STRING_TOKEN(STR_ES_CACHE), &gEfiExtendedSalCacheServicesProtocolGuid, NULL}, + {STRING_TOKEN(STR_ES_MCA_LOG), &gEfiExtendedSalMcaLogServicesProtocolGuid, NULL}, + {STRING_TOKEN(STR_S2ARCH), &gEfiSecurity2ArchProtocolGuid, NULL}, + {STRING_TOKEN(STR_EODXE), &gEfiSmmEndOfDxeProtocolGuid, NULL}, + {STRING_TOKEN(STR_ISAHC), &gEfiIsaHcProtocolGuid, NULL}, + {STRING_TOKEN(STR_ISAHC_B), &gEfiIsaHcServiceBindingProtocolGuid, NULL}, + {STRING_TOKEN(STR_SIO_C), &gEfiSioControlProtocolGuid, NULL}, + {STRING_TOKEN(STR_GET_PCD), &gEfiGetPcdInfoProtocolGuid, NULL}, + {STRING_TOKEN(STR_I2C_M), &gEfiI2cMasterProtocolGuid, NULL}, + {STRING_TOKEN(STR_I2CIO), &gEfiI2cIoProtocolGuid, NULL}, + {STRING_TOKEN(STR_I2CEN), &gEfiI2cEnumerateProtocolGuid, NULL}, + {STRING_TOKEN(STR_I2C_H), &gEfiI2cHostProtocolGuid, NULL}, + {STRING_TOKEN(STR_I2C_BCM), &gEfiI2cBusConfigurationManagementProtocolGuid, NULL}, + {STRING_TOKEN(STR_TREE), &gEfiTrEEProtocolGuid, NULL}, + {STRING_TOKEN(STR_TCG2), &gEfiTcg2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_TIMESTAMP), &gEfiTimestampProtocolGuid, NULL}, + {STRING_TOKEN(STR_RNG), &gEfiRngProtocolGuid, NULL}, + {STRING_TOKEN(STR_NVMEPT), &gEfiNvmExpressPassThruProtocolGuid, NULL}, + {STRING_TOKEN(STR_H2_SB), &gEfiHash2ServiceBindingProtocolGuid, NULL}, + {STRING_TOKEN(STR_HASH2), &gEfiHash2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_BIO_C), &gEfiBlockIoCryptoProtocolGuid, NULL}, + {STRING_TOKEN(STR_SCR), &gEfiSmartCardReaderProtocolGuid, NULL}, + {STRING_TOKEN(STR_SCE), &gEfiSmartCardEdgeProtocolGuid, NULL}, + {STRING_TOKEN(STR_USB_FIO), &gEfiUsbFunctionIoProtocolGuid, NULL}, + {STRING_TOKEN(STR_BC_HC), &gEfiBluetoothHcProtocolGuid, NULL}, + {STRING_TOKEN(STR_BC_IO_SB), &gEfiBluetoothIoServiceBindingProtocolGuid, NULL}, + {STRING_TOKEN(STR_BC_IO), &gEfiBluetoothIoProtocolGuid, NULL}, + {STRING_TOKEN(STR_BC_C), &gEfiBluetoothConfigProtocolGuid, NULL}, + {STRING_TOKEN(STR_REG_EXP), &gEfiRegularExpressionProtocolGuid, NULL}, + {STRING_TOKEN(STR_B_MGR_P), &gEfiBootManagerPolicyProtocolGuid, NULL}, + {STRING_TOKEN(STR_CKH), &gEfiConfigKeywordHandlerProtocolGuid, NULL}, + {STRING_TOKEN(STR_WIFI), &gEfiWiFiProtocolGuid, NULL}, + {STRING_TOKEN(STR_EAP_M), &gEfiEapManagement2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_EAP_C), &gEfiEapConfigurationProtocolGuid, NULL}, + {STRING_TOKEN(STR_PKCS7), &gEfiPkcs7VerifyProtocolGuid, NULL}, + {STRING_TOKEN(STR_NET_DNS4_SB), &gEfiDns4ServiceBindingProtocolGuid, NULL}, + {STRING_TOKEN(STR_NET_DNS4), &gEfiDns4ProtocolGuid, NULL}, + {STRING_TOKEN(STR_NET_DNS6_SB), &gEfiDns6ServiceBindingProtocolGuid, NULL}, + {STRING_TOKEN(STR_NET_DNS6), &gEfiDns6ProtocolGuid, NULL}, + {STRING_TOKEN(STR_NET_HTTP_SB), &gEfiHttpServiceBindingProtocolGuid, NULL}, + {STRING_TOKEN(STR_NET_HTTP), &gEfiHttpProtocolGuid, NULL}, + {STRING_TOKEN(STR_NET_HTTP_U), &gEfiHttpUtilitiesProtocolGuid, NULL}, + {STRING_TOKEN(STR_REST), &gEfiRestProtocolGuid, NULL}, + // // UEFI Shell Spec 2.0 // @@ -1036,6 +1154,11 @@ STATIC CONST GUID_INFO_BLOCK mGuidStringList[] = { // {STRING_TOKEN(STR_SHELL_DYNAMIC), &gEfiShellDynamicCommandProtocolGuid, NULL}, +// +// Misc +// + {STRING_TOKEN(STR_PCDINFOPROT), &gGetPcdInfoProtocolGuid, NULL}, + // // terminator // diff --git a/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.inf b/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.inf index 4cd81f59ed66..4a19e3945057 100644 --- a/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.inf +++ b/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.inf @@ -175,6 +175,121 @@ gEfiAdapterInformationProtocolGuid ## UNDEFINED gEfiShellDynamicCommandProtocolGuid ## UNDEFINED gEfiDiskInfoProtocolGuid ## UNDEFINED + gGetPcdInfoProtocolGuid ## UNDEFINED + gEfiBdsArchProtocolGuid ## UNDEFINED + gEfiCpuArchProtocolGuid ## UNDEFINED + gEfiMetronomeArchProtocolGuid ## UNDEFINED + gEfiMonotonicCounterArchProtocolGuid ## UNDEFINED + gEfiRealTimeClockArchProtocolGuid ## UNDEFINED + gEfiResetArchProtocolGuid ## UNDEFINED + gEfiRuntimeArchProtocolGuid ## UNDEFINED + gEfiSecurityArchProtocolGuid ## UNDEFINED + gEfiTimerArchProtocolGuid ## UNDEFINED + gEfiVariableWriteArchProtocolGuid ## UNDEFINED + gEfiVariableArchProtocolGuid ## UNDEFINED + gEfiSecurityPolicyProtocolGuid ## UNDEFINED + gEfiWatchdogTimerArchProtocolGuid ## UNDEFINED + gEfiStatusCodeRuntimeProtocolGuid ## UNDEFINED + gEfiSmbusHcProtocolGuid ## UNDEFINED + gEfiFirmwareVolume2ProtocolGuid ## UNDEFINED + gEfiFirmwareVolumeBlockProtocolGuid ## UNDEFINED + gEfiCapsuleArchProtocolGuid ## UNDEFINED + gEfiMpServiceProtocolGuid ## UNDEFINED + gEfiPciHostBridgeResourceAllocationProtocolGuid ## UNDEFINED + gEfiPciPlatformProtocolGuid ## UNDEFINED + gEfiPciOverrideProtocolGuid ## UNDEFINED + gEfiPciEnumerationCompleteProtocolGuid ## UNDEFINED + gEfiIncompatiblePciDeviceSupportProtocolGuid ## UNDEFINED + gEfiPciHotPlugInitProtocolGuid ## UNDEFINED + gEfiPciHotPlugRequestProtocolGuid ## UNDEFINED + gEfiSmbiosProtocolGuid ## UNDEFINED + gEfiS3SaveStateProtocolGuid ## UNDEFINED + gEfiS3SmmSaveStateProtocolGuid ## UNDEFINED + gEfiRscHandlerProtocolGuid ## UNDEFINED + gEfiSmmRscHandlerProtocolGuid ## UNDEFINED + gEfiAcpiSdtProtocolGuid ## UNDEFINED + gEfiSioProtocolGuid ## UNDEFINED + gEfiSmmCpuIo2ProtocolGuid ## UNDEFINED + gEfiSmmBase2ProtocolGuid ## UNDEFINED + gEfiSmmAccess2ProtocolGuid ## UNDEFINED + gEfiSmmControl2ProtocolGuid ## UNDEFINED + gEfiSmmConfigurationProtocolGuid ## UNDEFINED + gEfiSmmReadyToLockProtocolGuid ## UNDEFINED + gEfiDxeSmmReadyToLockProtocolGuid ## UNDEFINED + gEfiSmmCommunicationProtocolGuid ## UNDEFINED + gEfiSmmStatusCodeProtocolGuid ## UNDEFINED + gEfiSmmCpuProtocolGuid ## UNDEFINED + gEfiSmmPciRootBridgeIoProtocolGuid ## UNDEFINED + gEfiSmmSwDispatch2ProtocolGuid ## UNDEFINED + gEfiSmmSxDispatch2ProtocolGuid ## UNDEFINED + gEfiSmmPeriodicTimerDispatch2ProtocolGuid ## UNDEFINED + gEfiSmmUsbDispatch2ProtocolGuid ## UNDEFINED + gEfiSmmGpiDispatch2ProtocolGuid ## UNDEFINED + gEfiSmmStandbyButtonDispatch2ProtocolGuid ## UNDEFINED + gEfiSmmPowerButtonDispatch2ProtocolGuid ## UNDEFINED + gEfiSmmIoTrapDispatch2ProtocolGuid ## UNDEFINED + gEfiPcdProtocolGuid ## UNDEFINED + gEfiFirmwareVolumeBlock2ProtocolGuid ## UNDEFINED + gEfiCpuIo2ProtocolGuid ## UNDEFINED + gEfiLegacyRegion2ProtocolGuid ## UNDEFINED + gEfiSalMcaInitPmiProtocolGuid ## UNDEFINED + gEfiExtendedSalBootServiceProtocolGuid ## UNDEFINED + gEfiExtendedSalBaseIoServicesProtocolGuid ## UNDEFINED + gEfiExtendedSalStallServicesProtocolGuid ## UNDEFINED + gEfiExtendedSalRtcServicesProtocolGuid ## UNDEFINED + gEfiExtendedSalVariableServicesProtocolGuid ## UNDEFINED + gEfiExtendedSalMtcServicesProtocolGuid ## UNDEFINED + gEfiExtendedSalResetServicesProtocolGuid ## UNDEFINED + gEfiExtendedSalStatusCodeServicesProtocolGuid ## UNDEFINED + gEfiExtendedSalFvBlockServicesProtocolGuid ## UNDEFINED + gEfiExtendedSalMpServicesProtocolGuid ## UNDEFINED + gEfiExtendedSalPalServicesProtocolGuid ## UNDEFINED + gEfiExtendedSalBaseServicesProtocolGuid ## UNDEFINED + gEfiExtendedSalMcaServicesProtocolGuid ## UNDEFINED + gEfiExtendedSalPciServicesProtocolGuid ## UNDEFINED + gEfiExtendedSalCacheServicesProtocolGuid ## UNDEFINED + gEfiExtendedSalMcaLogServicesProtocolGuid ## UNDEFINED + gEfiSecurity2ArchProtocolGuid ## UNDEFINED + gEfiSmmEndOfDxeProtocolGuid ## UNDEFINED + gEfiIsaHcProtocolGuid ## UNDEFINED + gEfiIsaHcServiceBindingProtocolGuid ## UNDEFINED + gEfiSioControlProtocolGuid ## UNDEFINED + gEfiGetPcdInfoProtocolGuid ## UNDEFINED + gEfiI2cMasterProtocolGuid ## UNDEFINED + gEfiI2cIoProtocolGuid ## UNDEFINED + gEfiI2cEnumerateProtocolGuid ## UNDEFINED + gEfiI2cHostProtocolGuid ## UNDEFINED + gEfiI2cBusConfigurationManagementProtocolGuid ## UNDEFINED + gEfiTrEEProtocolGuid ## UNDEFINED + gEfiTcg2ProtocolGuid ## UNDEFINED + gEfiTimestampProtocolGuid ## UNDEFINED + gEfiRngProtocolGuid ## UNDEFINED + gEfiNvmExpressPassThruProtocolGuid ## UNDEFINED + gEfiHash2ServiceBindingProtocolGuid ## UNDEFINED + gEfiHash2ProtocolGuid ## UNDEFINED + gEfiBlockIoCryptoProtocolGuid ## UNDEFINED + gEfiSmartCardReaderProtocolGuid ## UNDEFINED + gEfiSmartCardEdgeProtocolGuid ## UNDEFINED + gEfiUsbFunctionIoProtocolGuid ## UNDEFINED + gEfiBluetoothHcProtocolGuid ## UNDEFINED + gEfiBluetoothIoServiceBindingProtocolGuid ## UNDEFINED + gEfiBluetoothIoProtocolGuid ## UNDEFINED + gEfiBluetoothConfigProtocolGuid ## UNDEFINED + gEfiRegularExpressionProtocolGuid ## UNDEFINED + gEfiBootManagerPolicyProtocolGuid ## UNDEFINED + gEfiConfigKeywordHandlerProtocolGuid ## UNDEFINED + gEfiWiFiProtocolGuid ## UNDEFINED + gEfiEapManagement2ProtocolGuid ## UNDEFINED + gEfiEapConfigurationProtocolGuid ## UNDEFINED + gEfiPkcs7VerifyProtocolGuid ## UNDEFINED + gEfiDns4ServiceBindingProtocolGuid ## UNDEFINED + gEfiDns4ProtocolGuid ## UNDEFINED + gEfiDns6ServiceBindingProtocolGuid ## UNDEFINED + gEfiDns6ProtocolGuid ## UNDEFINED + gEfiHttpServiceBindingProtocolGuid ## UNDEFINED + gEfiHttpProtocolGuid ## UNDEFINED + gEfiHttpUtilitiesProtocolGuid ## UNDEFINED + gEfiRestProtocolGuid ## UNDEFINED [Guids] gEfiFileInfoGuid ## CONSUMES ## GUID diff --git a/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.uni b/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.uni index 1d142e9c9801..f7d54855fb66 100644 --- a/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.uni +++ b/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.uni @@ -218,6 +218,122 @@ #string STR_SSC #language en-US "StorageSecurityCommand" #string STR_UCRED2 #language en-US "UserCredential2" +#string STR_PCDINFOPROT #language en-US "GetPcdInfoProtocol" +#string STR_BDS_ARCH #language en-US "BdsArch" +#string STR_CPU_ARCH #language en-US "CpuArch" +#string STR_MET_ARCH #language en-US "MetronomeArch" +#string STR_MON_ARCH #language en-US "MonotonicCounterArch" +#string STR_RTC_ARCH #language en-US "RealTimeClockArch" +#string STR_RESET_ARCH #language en-US "ResetArch" +#string STR_RT_ARCH #language en-US "RuntimeArch" +#string STR_SEC_ARCH #language en-US "SecurityArch" +#string STR_TIMER_ARCH #language en-US "TimerArch" +#string STR_VAR_ARCH #language en-US "VariableWriteArch" +#string STR_V_ARCH #language en-US "VariableArch" +#string STR_SECP #language en-US "SecurityPolicy" +#string STR_WDT_ARCH #language en-US "WatchdogTimerArch" +#string STR_SCR #language en-US "StatusCodeRuntime" +#string STR_SMB_HC #language en-US "SmbusHc" +#string STR_FV_2 #language en-US "FirmwareVolume2" +#string STR_FV_BLOCK #language en-US "FirmwareVolumeBlock" +#string STR_CAP_ARCH #language en-US "CapsuleArch" +#string STR_MP_SERVICE #language en-US "MpService" +#string STR_HBRAP #language en-US "PciHostBridgeResourceAllocation" +#string STR_PCIP #language en-US "PciPlatform" +#string STR_PCIO #language en-US "PciOverride" +#string STR_PCIE #language en-US "PciEnumerationComplete" +#string STR_IPCID #language en-US "IncompatiblePciDeviceSupport" +#string STR_PCIHPI #language en-US "PciHotPlugInit" +#string STR_PCIHPR #language en-US "PciHotPlugRequest" +#string STR_SMBIOS #language en-US "Smbios" +#string STR_S3_SAVE #language en-US "S3SaveState" +#string STR_S3_S_SMM #language en-US "S3SmmSaveState" +#string STR_RSC #language en-US "RscHandler" +#string STR_S_RSC #language en-US "SmmRscHandler" +#string STR_ACPI_SDT #language en-US "AcpiSdt" +#string STR_SIO #language en-US "Sio" +#string STR_S_CPU2 #language en-US "SmmCpuIo2" +#string STR_S_BASE2 #language en-US "SmmBase2" +#string STR_S_ACC_2 #language en-US "SmmAccess2" +#string STR_S_CON_2 #language en-US "SmmControl2" +#string STR_S_CONFIG #language en-US "SmmConfig" +#string STR_S_RTL #language en-US "SmmReadyToLock" +#string STR_DS_RTL #language en-US "DxeSmmReadyToLock" +#string STR_S_COMM #language en-US "SmmCommunication" +#string STR_S_STAT #language en-US "SmmStatusCode" +#string STR_S_CPU #language en-US "SmmCpu" +#string STR_S_PCIRBIO #language en-US "SmmPCIRootBridgeIO" +#string STR_S_SWD #language en-US "SmmSwDispatch2" +#string STR_S_SXD #language en-US "SmmSxDispatch2" +#string STR_S_PTD2 #language en-US "SmmPeriodicTimerDispatch2" +#string STR_S_UD2 #language en-US "SmmUsbDispatch2" +#string STR_S_GD2 #language en-US "SmmGpiDispatch2" +#string STR_S_SBD2 #language en-US "SmmStandbyButtonDispatch2" +#string STR_S_PBD2 #language en-US "SmmPowerButtonDispatch2" +#string STR_S_ITD2 #language en-US "SmmIoTrapDispatch2" +#string STR_PCD #language en-US "Pcd" +#string STR_FVB2 #language en-US "FirmwareVolumeBlock2" +#string STR_CPUIO2 #language en-US "CpuIo2" +#string STR_LEGACY_R2 #language en-US "LegacyRegion2" +#string STR_SAL_MIP #language en-US "SalMcaInitPmi" +#string STR_ES_BS #language en-US "ExtendedSalBootService" +#string STR_ES_BIO #language en-US "ExtendedSalBaseIoServices" +#string STR_ES_STALL #language en-US "ExtendedSalStallServices" +#string STR_ES_RTC #language en-US "ExtendedSalRtcServices" +#string STR_ES_VS #language en-US "ExtendedSalVariableServices" +#string STR_ES_MTC #language en-US "ExtendedSalMtcServices" +#string STR_ES_RESET #language en-US "ExtendedSalResetServices" +#string STR_ES_SC #language en-US "ExtendedSalStatusCodeServices" +#string STR_ES_FBS #language en-US "ExtendedSalFvBlockServices" +#string STR_ES_MP #language en-US "ExtendedSalMpServices" +#string STR_ES_PAL #language en-US "ExtendedSalPalServices" +#string STR_ES_BASE #language en-US "ExtendedSalBaseServices" +#string STR_ES_MCA #language en-US "ExtendedSalMcaServices" +#string STR_ES_PCI #language en-US "ExtendedSalPciServices" +#string STR_ES_CACHE #language en-US "ExtendedSalCacheServices" +#string STR_ES_MCA_LOG #language en-US "ExtendedSalMcaLogServices" +#string STR_S2ARCH #language en-US "Security2Arch" +#string STR_EODXE #language en-US "SmmEndOfDxe" +#string STR_ISAHC #language en-US "IsaHc" +#string STR_ISAHC_B #language en-US "IsaHcServiceBinding" +#string STR_SIO_C #language en-US "SioControl" +#string STR_GET_PCD #language en-US "GetPcdInfo" +#string STR_I2C_M #language en-US "I2cMaster" +#string STR_I2CIO #language en-US "I2cIo" +#string STR_I2CEN #language en-US "I2cEnumerate" +#string STR_I2C_H #language en-US "I2cHost" +#string STR_I2C_BCM #language en-US "I2cBusConfigurationManagement" +#string STR_TREE #language en-US "TrEE" +#string STR_TCG2 #language en-US "Tcg2" +#string STR_TIMESTAMP #language en-US "Timestamp" +#string STR_RNG #language en-US "Rng" +#string STR_NVMEPT #language en-US "NvmExpressPassThru" +#string STR_H2_SB #language en-US "Hash2ServiceBinding" +#string STR_HASH2 #language en-US "Hash2" +#string STR_BIO_C #language en-US "BlockIoCrypto" +#string STR_SCR #language en-US "SmartCardReader" +#string STR_SCE #language en-US "SmartCardEdge" +#string STR_USB_FIO #language en-US "UsbFunctionIo" +#string STR_BC_HC #language en-US "BluetoothHc" +#string STR_BC_IO_SB #language en-US "BluetoothIoServiceBinding" +#string STR_BC_IO #language en-US "BluetoothIo" +#string STR_BC_C #language en-US "BluetoothConfig" +#string STR_REG_EXP #language en-US "RegularExpression" +#string STR_B_MGR_P #language en-US "BootManagerPolicy" +#string STR_CKH #language en-US "ConfigKeywordHandler" +#string STR_WIFI #language en-US "WiFi" +#string STR_EAP_M #language en-US "EapManagement2" +#string STR_EAP_C #language en-US "EapConfiguration" +#string STR_PKCS7 #language en-US "Pkcs7Verify" +#string STR_NET_DNS4_SB #language en-US "Dns4ServiceBinding" +#string STR_NET_DNS4 #language en-US "Dns4" +#string STR_NET_DNS6_SB #language en-US "Dns6ServiceBinding" +#string STR_NET_DNS6 #language en-US "Dns6" +#string STR_NET_HTTP_SB #language en-US "HttpServiceBinding" +#string STR_NET_HTTP #language en-US "Http" +#string STR_NET_HTTP_U #language en-US "HttpUtilities" +#string STR_REST #language en-US "Rest" + #string STR_IDE_CONT_INIT #language en-US "IdeControllerInit" #string STR_DISK_INFO #language en-US "DiskInfo" From 89ed8b7770eee793c2375abb479d1db7eaa8a823 Mon Sep 17 00:00:00 2001 From: Jiaxin Wu Date: Fri, 18 Dec 2015 07:39:06 +0000 Subject: [PATCH 310/525] ShellPkg: Fix ifconfig hang issue with incomplete parameters This patch is used to fix ifconfig hang issue with incomplete parameters. In addition, some error related output information is added to increase the interactivity. (Sync patch r19212 from main trunk.) Cc: Leekha Shaveta Cc: Carsey Jaben Cc: Ye Ting Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiaxin Wu Reviewed-by: Jaben Carsey Tested-by: Leekha Shaveta git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19408 6f19259b-4bc3-4df7-8a09-765794883524 --- .../UefiShellNetwork1CommandsLib/Ifconfig.c | 61 ++++++++++++++----- .../UefiShellNetwork1CommandsLib.uni | 7 ++- 2 files changed, 51 insertions(+), 17 deletions(-) diff --git a/ShellPkg/Library/UefiShellNetwork1CommandsLib/Ifconfig.c b/ShellPkg/Library/UefiShellNetwork1CommandsLib/Ifconfig.c index fb6f57518422..f8dbc88cf842 100644 --- a/ShellPkg/Library/UefiShellNetwork1CommandsLib/Ifconfig.c +++ b/ShellPkg/Library/UefiShellNetwork1CommandsLib/Ifconfig.c @@ -828,6 +828,7 @@ IfConfigClearInterfaceInfo ( &Policy ); if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_AD), gShellNetwork1HiiHandle, L"ifconfig"); ShellStatus = SHELL_ACCESS_DENIED; break; } @@ -904,6 +905,7 @@ IfConfigSetInterfaceInfo ( &TimeOutEvt ); if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_AD), gShellNetwork1HiiHandle, L"ifconfig"); ShellStatus = SHELL_ACCESS_DENIED; goto ON_EXIT; } @@ -916,6 +918,7 @@ IfConfigSetInterfaceInfo ( &MappedEvt ); if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_AD), gShellNetwork1HiiHandle, L"ifconfig"); ShellStatus = SHELL_ACCESS_DENIED; goto ON_EXIT; } @@ -974,6 +977,7 @@ IfConfigSetInterfaceInfo ( if (IfCb->Policy == Ip4Config2PolicyDhcp) { Status = IfConfigStartIp4 (IfCb->NicHandle, gImageHandle); if (EFI_ERROR(Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_AD), gShellNetwork1HiiHandle, L"ifconfig"); ShellStatus = SHELL_ACCESS_DENIED; goto ON_EXIT; } @@ -989,6 +993,7 @@ IfConfigSetInterfaceInfo ( &Policy ); if (EFI_ERROR(Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_AD), gShellNetwork1HiiHandle, L"ifconfig"); ShellStatus = SHELL_ACCESS_DENIED; goto ON_EXIT; } @@ -997,23 +1002,13 @@ IfConfigSetInterfaceInfo ( VarArg= VarArg->Next; } else if (StrCmp (VarArg->Arg, L"static") == 0) { - // - // Set manual config policy. - // - Policy = Ip4Config2PolicyStatic; - Status = IfCb->IfCfg->SetData ( - IfCb->IfCfg, - Ip4Config2DataTypePolicy, - sizeof (EFI_IP4_CONFIG2_POLICY), - &Policy - ); - if (EFI_ERROR(Status)) { - ShellStatus = SHELL_ACCESS_DENIED; + VarArg= VarArg->Next; + if (VarArg == NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_LACK_COMMAND), gShellNetwork1HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; goto ON_EXIT; } - VarArg= VarArg->Next; - ZeroMem (&ManualAddress, sizeof (ManualAddress)); // @@ -1021,6 +1016,7 @@ IfConfigSetInterfaceInfo ( // Status = NetLibStrToIp4 (VarArg->Arg, &ManualAddress.Address); if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_INVALID_IPADDRESS), gShellNetwork1HiiHandle, VarArg->Arg); ShellStatus = SHELL_INVALID_PARAMETER; goto ON_EXIT; } @@ -1029,8 +1025,15 @@ IfConfigSetInterfaceInfo ( // Get subnetmask. // VarArg = VarArg->Next; + if (VarArg == NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_LACK_COMMAND), gShellNetwork1HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + Status = NetLibStrToIp4 (VarArg->Arg, &ManualAddress.SubnetMask); if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_INVALID_IPADDRESS), gShellNetwork1HiiHandle, VarArg->Arg); ShellStatus = SHELL_INVALID_PARAMETER; goto ON_EXIT; } @@ -1039,12 +1042,38 @@ IfConfigSetInterfaceInfo ( // Get gateway. // VarArg = VarArg->Next; + if (VarArg == NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_LACK_COMMAND), gShellNetwork1HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + Status = NetLibStrToIp4 (VarArg->Arg, &Gateway); if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_INVALID_IPADDRESS), gShellNetwork1HiiHandle, VarArg->Arg); ShellStatus = SHELL_INVALID_PARAMETER; goto ON_EXIT; } + + // + // Set manual config policy. + // + Policy = Ip4Config2PolicyStatic; + Status = IfCb->IfCfg->SetData ( + IfCb->IfCfg, + Ip4Config2DataTypePolicy, + sizeof (EFI_IP4_CONFIG2_POLICY), + &Policy + ); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_AD), gShellNetwork1HiiHandle, L"ifconfig"); + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + // + // Set Manual Address. + // IsAddressOk = FALSE; Status = IfCb->IfCfg->RegisterDataNotify ( @@ -1053,6 +1082,7 @@ IfConfigSetInterfaceInfo ( MappedEvt ); if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_SET_ADDR_FAILED), gShellNetwork1HiiHandle, Status); ShellStatus = SHELL_ACCESS_DENIED; goto ON_EXIT; } @@ -1101,6 +1131,7 @@ IfConfigSetInterfaceInfo ( &Gateway ); if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_SET_ADDR_FAILED), gShellNetwork1HiiHandle, Status); ShellStatus = SHELL_ACCESS_DENIED; goto ON_EXIT; } @@ -1126,6 +1157,7 @@ IfConfigSetInterfaceInfo ( while (Tmp != NULL) { Status = NetLibStrToIp4 (Tmp->Arg, Dns + Index); if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_INVALID_IPADDRESS), gShellNetwork1HiiHandle, Tmp->Arg); ShellStatus = SHELL_INVALID_PARAMETER; goto ON_EXIT; } @@ -1147,6 +1179,7 @@ IfConfigSetInterfaceInfo ( Dns ); if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_AD), gShellNetwork1HiiHandle, L"ifconfig"); ShellStatus = SHELL_ACCESS_DENIED; goto ON_EXIT; } diff --git a/ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.uni b/ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.uni index 4c68e416406a..bc6acac0c12a 100644 --- a/ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.uni +++ b/ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.uni @@ -63,10 +63,11 @@ #string STR_IFCONFIG_LACK_INTERFACE #language en-US "Lack interface name.\n" #string STR_IFCONFIG_LACK_COMMAND #language en-US "Lack interface config option.\n" #string STR_IFCONFIG_INVALID_INTERFACE #language en-US "Invalid interface name.\n" +#string STR_IFCONFIG_INVALID_IPADDRESS #language en-US "Invalid ipv4 address: '%H%s%N'\n" #string STR_IFCONFIG_DUPLICATE_COMMAND #language en-US "Duplicate commands. Bad command %H%s%N is skipped.\n" #string STR_IFCONFIG_CONFLICT_COMMAND #language en-US "Conflict commands. Bad command %H%s%N is skipped.\n" #string STR_IFCONFIG_UNKNOWN_COMMAND #language en-US "Unknown commands. Bad command %H%s%N is skipped.\n" -#string STR_IFCONFIG_SET_ADDR_FAILED #language en-US "It failed to set .\n" +#string STR_IFCONFIG_SET_ADDR_FAILED #language en-US "Failed to set address.\n" #string STR_IFCONFIG_ROUTES_SIZE #language en-US "\n%H Routes (%d entries):\n" #string STR_IFCONFIG_ROUTES_ENTRY_INDEX #language en-US "%H Entry[%d]\n" #string STR_IFCONFIG_SHOW_IP_ADDR #language en-US "%12s: %N%d.%d.%d.%d\n" @@ -156,9 +157,9 @@ " 3. Use '-l' to list the DNS and other address related settings for all\r\n" " interfaces or the specified interface.\r\n" " 4. Use '-s static ' with \r\n" -" static IP4 address configuration for all or specified interface.\r\n" +" static IP4 address configuration for specified interface.\r\n" " 5. Use '-s dhcp' for DHCP4 to request the IP4 address\r\n" -" configuration dynamically for all interface or specified interface.\r\n" +" configuration dynamically for specified interface.\r\n" " 6. Use '-s dns ' must under manual policy.\r\n" ".SH EXAMPLES\r\n" " \r\n" From 1d8a8d09eef4028fee03ab9660aab9398ebe6675 Mon Sep 17 00:00:00 2001 From: Michael Kinney Date: Fri, 18 Dec 2015 07:39:35 +0000 Subject: [PATCH 311/525] ShellPkg/Shell - Fix ASSERT() when FvSimpleFileSystemDxe is used When the FvSimpleFileSystemDxe module is included in a platform, Simple File System Protocols are produced for firmware volumes(FV) that do not have the same style device paths as file systems with file names. The ShellPkg has an assumption that the device path contains device path nodes of type MEDIA_FILEPATH_DP and generates an ASSERT() if any other device path nodes are encountered. This change removes the ASSERT() condition and instead returns NULL that means EfiShellGetFilePathFromDevicePath() can not convert the device path nodes that represent the file path to a Unicode string. (Sync patch r19228 from main trunk.) Cc: Jaben Carsey Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Michael Kinney Reviewed-by: Jaben Carsey git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19409 6f19259b-4bc3-4df7-8a09-765794883524 --- ShellPkg/Application/Shell/ShellProtocol.c | 51 +++++++++++----------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/ShellPkg/Application/Shell/ShellProtocol.c b/ShellPkg/Application/Shell/ShellProtocol.c index 9c370ccef5af..def3bd35c208 100644 --- a/ShellPkg/Application/Shell/ShellProtocol.c +++ b/ShellPkg/Application/Shell/ShellProtocol.c @@ -449,38 +449,37 @@ EfiShellGetFilePathFromDevicePath( ; FilePath = (FILEPATH_DEVICE_PATH*)NextDevicePathNode (&FilePath->Header) ){ // - // all the rest should be file path nodes + // If any node is not a file path node, then the conversion can not be completed // if ((DevicePathType(&FilePath->Header) != MEDIA_DEVICE_PATH) || (DevicePathSubType(&FilePath->Header) != MEDIA_FILEPATH_DP)) { FreePool(PathForReturn); - PathForReturn = NULL; - ASSERT(FALSE); - } else { - // - // append the path part onto the filepath. - // - ASSERT((PathForReturn == NULL && PathSize == 0) || (PathForReturn != NULL)); - - AlignedNode = AllocateCopyPool (DevicePathNodeLength(FilePath), FilePath); - ASSERT (AlignedNode != NULL); - - // File Path Device Path Nodes 'can optionally add a "\" separator to - // the beginning and/or the end of the Path Name string.' - // (UEFI Spec 2.4 section 9.3.6.4). - // If necessary, add a "\", but otherwise don't - // (This is specified in the above section, and also implied by the - // UEFI Shell spec section 3.7) - if ((PathSize != 0) && - (PathForReturn != NULL) && - (PathForReturn[PathSize - 1] != L'\\') && - (AlignedNode->PathName[0] != L'\\')) { - PathForReturn = StrnCatGrow (&PathForReturn, &PathSize, L"\\", 1); - } + return NULL; + } - PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, AlignedNode->PathName, 0); - FreePool(AlignedNode); + // + // append the path part onto the filepath. + // + ASSERT((PathForReturn == NULL && PathSize == 0) || (PathForReturn != NULL)); + + AlignedNode = AllocateCopyPool (DevicePathNodeLength(FilePath), FilePath); + ASSERT (AlignedNode != NULL); + + // File Path Device Path Nodes 'can optionally add a "\" separator to + // the beginning and/or the end of the Path Name string.' + // (UEFI Spec 2.4 section 9.3.6.4). + // If necessary, add a "\", but otherwise don't + // (This is specified in the above section, and also implied by the + // UEFI Shell spec section 3.7) + if ((PathSize != 0) && + (PathForReturn != NULL) && + (PathForReturn[PathSize - 1] != L'\\') && + (AlignedNode->PathName[0] != L'\\')) { + PathForReturn = StrnCatGrow (&PathForReturn, &PathSize, L"\\", 1); } + + PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, AlignedNode->PathName, 0); + FreePool(AlignedNode); } // for loop of remaining nodes } if (PathForReturn != NULL) { From bd3445a74754f3eeda9d2f2cc89803c27f046531 Mon Sep 17 00:00:00 2001 From: Qiu Shumin Date: Fri, 18 Dec 2015 07:40:05 +0000 Subject: [PATCH 312/525] ShellPkg: Initialize the local pointer to avoid potential suspicious dereference. 1. Initialize the local pointer 'HandleBuffer'. 2. When 'LocateHandleBuffer' return error 'HandleBuffer' is expected unchanged, add code make sure this. (Sync patch r19229 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Qiu Shumin Reviewed-by: Ruiyu Ni git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19410 6f19259b-4bc3-4df7-8a09-765794883524 --- ShellPkg/Library/UefiShellDebug1CommandsLib/Mm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/Mm.c b/ShellPkg/Library/UefiShellDebug1CommandsLib/Mm.c index 3f08cc84dc24..7b26e4d27f6e 100644 --- a/ShellPkg/Library/UefiShellDebug1CommandsLib/Mm.c +++ b/ShellPkg/Library/UefiShellDebug1CommandsLib/Mm.c @@ -317,6 +317,7 @@ ShellMmLocateIoProtocol ( } *PciRootBridgeIo = NULL; + HandleBuffer = NULL; Status = gBS->LocateHandleBuffer ( ByProtocol, &gEfiPciRootBridgeIoProtocolGuid, @@ -324,7 +325,7 @@ ShellMmLocateIoProtocol ( &HandleCount, &HandleBuffer ); - if (EFI_ERROR (Status) || (HandleCount == 0)) { + if (EFI_ERROR (Status) || (HandleCount == 0) || (HandleBuffer == NULL)) { return FALSE; } From a672cba6b879a6c7a30b05a0ee48d5bdc771554f Mon Sep 17 00:00:00 2001 From: Michael Kinney Date: Fri, 18 Dec 2015 07:40:34 +0000 Subject: [PATCH 313/525] ShellPkg/Mm: Fix build warnings Fix build warnings for potentially uninitialized local variables in the functions ShellMmLocateIoProtocol() and ShellCommandRunMm() in the Shell implementation of the 'mm' command. (Sync patch r19233 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Michael Kinney Reviewed-by: Feng Tian git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19411 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Library/UefiShellDebug1CommandsLib/Mm.c | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/Mm.c b/ShellPkg/Library/UefiShellDebug1CommandsLib/Mm.c index 7b26e4d27f6e..26a758b6cdd7 100644 --- a/ShellPkg/Library/UefiShellDebug1CommandsLib/Mm.c +++ b/ShellPkg/Library/UefiShellDebug1CommandsLib/Mm.c @@ -329,6 +329,8 @@ ShellMmLocateIoProtocol ( return FALSE; } + Segment = 0; + Bus = 0; if ((AccessType == ShellMmPci) || (AccessType == ShellMmPciExpress)) { ShellMmDecodePciAddress ((BOOLEAN) (AccessType == ShellMmPci), Address, &Segment, &Bus, NULL, NULL, NULL); } @@ -615,18 +617,18 @@ ShellCommandRunMm ( // skip space characters // for (Index = 0; InputStr[Index] == ' '; Index++); - } - if ((InputStr != NULL) && (InputStr[Index] != CHAR_NULL)) { - if ((InputStr[Index] == '.') || (InputStr[Index] == 'q') || (InputStr[Index] == 'Q')) { - Complete = TRUE; - } else if (!EFI_ERROR (ShellConvertStringToUint64 (InputStr + Index, &Buffer, TRUE, TRUE)) && - (Buffer <= mShellMmMaxNumber[Size]) - ) { - ShellMmAccess (AccessType, PciRootBridgeIo, CpuIo, FALSE, Address, Size, &Buffer); - } else { - ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_MM_ERROR), gShellDebug1HiiHandle, L"mm"); - continue; + if (InputStr[Index] != CHAR_NULL) { + if ((InputStr[Index] == '.') || (InputStr[Index] == 'q') || (InputStr[Index] == 'Q')) { + Complete = TRUE; + } else if (!EFI_ERROR (ShellConvertStringToUint64 (InputStr + Index, &Buffer, TRUE, TRUE)) && + (Buffer <= mShellMmMaxNumber[Size]) + ) { + ShellMmAccess (AccessType, PciRootBridgeIo, CpuIo, FALSE, Address, Size, &Buffer); + } else { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_MM_ERROR), gShellDebug1HiiHandle, L"mm"); + continue; + } } } From 5fe2882981b8e4b9b179c7f3e0a58e96b5115a20 Mon Sep 17 00:00:00 2001 From: Jim Dailey Date: Fri, 18 Dec 2015 07:41:07 +0000 Subject: [PATCH 314/525] ShellPkg: Ease the shell's MAN file Title Header syntax requirements. Prior to this change, the shell would not use a MAN file if the Title Header line was not strictly formatted. For example, if the case of the command name in the file was not exactly the same as the case of the command name as typed by the user, the MAN file would not be used. Also, extra whitespace on the line would also cause the shell to ignore the MAN file. This change allows "extra" white space and ignores case when looking for the command name. It also ignores any path information for cases where the user enters a relative or absolute path to the EFI file. (Sync patch r19290 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jim Dailey Reviewed-by: Jaben Carsey git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19412 6f19259b-4bc3-4df7-8a09-765794883524 --- ShellPkg/Application/Shell/ShellManParser.c | 198 +++++++++++++++----- 1 file changed, 150 insertions(+), 48 deletions(-) diff --git a/ShellPkg/Application/Shell/ShellManParser.c b/ShellPkg/Application/Shell/ShellManParser.c index 78b8decd8324..ce471cffdaf4 100644 --- a/ShellPkg/Application/Shell/ShellManParser.c +++ b/ShellPkg/Application/Shell/ShellManParser.c @@ -2,6 +2,7 @@ Provides interface to shell MAN file parser. Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.
+ Copyright 2015 Dell Inc. This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -14,6 +15,8 @@ #include "Shell.h" +CHAR16 EFIAPI InternalShellCharToUpper (IN CHAR16 Char); + /** Verifies that the filename has .MAN on the end. @@ -444,23 +447,150 @@ ManBufferFindTitleSection( return (Status); } +/** + Parses a line from a MAN file to see if it is the Title Header. If it is, then + if the "Brief Description" is desired, allocate a buffer for it and return a + copy. Upon a sucessful return the caller is responsible to free the memory in + *BriefDesc + + Uses a simple state machine that allows "unlimited" whitespace before and after the + ".TH", compares Command and the MAN file commnd name without respect to case, and + allows "unlimited" whitespace and '0' and '1' characters before the Short Description. + The PCRE regex describing this functionality is: ^\s*\.TH\s+(\S)\s[\s01]*(.*)$ + where group 1 is the Command Name and group 2 is the Short Description. + + @param[in] Command name of command whose MAN file we think Line came from + @param[in] Line Pointer to a line from the MAN file + @param[out] BriefDesc pointer to pointer to string where description goes. + @param[out] BriefSize pointer to size of allocated BriefDesc + @param[out] Found TRUE if the Title Header was found and it belongs to Command + + @retval TRUE Line contained the Title Header + @retval FALSE Line did not contain the Title Header +**/ +BOOLEAN +IsTitleHeader( + IN CONST CHAR16 *Command, + IN CHAR16 *Line, + OUT CHAR16 **BriefDesc OPTIONAL, + OUT UINTN *BriefSize OPTIONAL, + OUT BOOLEAN *Found + ) +{ + // The states of a simple state machine used to recognize a title header line + // and to extract the Short Description, if desired. + typedef enum { + LookForThMacro, LookForCommandName, CompareCommands, GetBriefDescription, Final + } STATEVALUES; + + STATEVALUES State; + UINTN CommandIndex; // Indexes Command as we compare its chars to the MAN file. + BOOLEAN ReturnValue; // TRUE if this the Title Header line of *some* MAN file. + BOOLEAN ReturnFound; // TRUE if this the Title Header line of *the desired* MAN file. + + ReturnValue = FALSE; + ReturnFound = FALSE; + CommandIndex = 0; + State = LookForThMacro; + + do { + + if (*Line == L'\0') { + break; + } + + switch (State) { + + // Handle "^\s*.TH\s" + // Go to state LookForCommandName if the title header macro is present; otherwise, + // eat white space. If we see something other than white space, this is not a + // title header line. + case LookForThMacro: + if (StrnCmp (L".TH ", Line, 4) == 0 || StrnCmp (L".TH\t", Line, 4) == 0) { + Line += 4; + State = LookForCommandName; + } + else if (*Line == L' ' || *Line == L'\t') { + Line++; + } + else { + State = Final; + } + break; + + // Handle "\s*" + // Eat any "extra" whitespace after the title header macro (we have already seen + // at least one white space character). Go to state CompareCommands when a + // non-white space is seen. + case LookForCommandName: + if (*Line == L' ' || *Line == L'\t') { + Line++; + } + else { + ReturnValue = TRUE; // This is *some* command's title header line. + State = CompareCommands; + // Do not increment Line; it points to the first character of the command + // name on the title header line. + } + break; + + // Handle "(\S)\s" + // Compare Command to the title header command name, ignoring case. When we + // reach the end of the command (i.e. we see white space), the next state + // depends on whether the caller wants a copy of the Brief Description. + case CompareCommands: + if (*Line == L' ' || *Line == L'\t') { + ReturnFound = TRUE; // This is the desired command's title header line. + State = (BriefDesc == NULL) ? Final : GetBriefDescription; + } + else if (InternalShellCharToUpper (*Line) != InternalShellCharToUpper (*(Command + CommandIndex++))) { + State = Final; + } + Line++; + break; + + // Handle "[\s01]*(.*)$" + // Skip whitespace, '0', and '1' characters, if any, prior to the brief description. + // Return the description to the caller. + case GetBriefDescription: + if (*Line != L' ' && *Line != L'\t' && *Line != L'0' && *Line != L'1') { + *BriefSize = StrSize(Line); + *BriefDesc = AllocateZeroPool(*BriefSize); + if (*BriefDesc != NULL) { + StrCpyS(*BriefDesc, (*BriefSize)/sizeof(CHAR16), Line); + } + State = Final; + } + Line++; + break; + + } + + } while (State < Final); + + *Found = ReturnFound; + return ReturnValue; +} + /** parses through the MAN file specified by SHELL_FILE_HANDLE and returns the - "Brief Description" for the .TH section as specified by Command. if the + "Brief Description" for the .TH section as specified by Command. If the command section is not found return EFI_NOT_FOUND. Upon a sucessful return the caller is responsible to free the memory in *BriefDesc @param[in] Handle FileHandle to read from - @param[in] Command name of command's section to find + @param[in] Command name of command's section to find as entered on the + command line (may be a relative or absolute path or + be in any case: upper, lower, or mixed in numerous ways!). @param[out] BriefDesc pointer to pointer to string where description goes. @param[out] BriefSize pointer to size of allocated BriefDesc @param[in, out] Ascii TRUE if the file is ASCII, FALSE otherwise, will be set if the file handle is at the 0 position. @retval EFI_OUT_OF_RESOURCES a memory allocation failed. - @retval EFI_SUCCESS the section was found and its description sotred in - an alloceted buffer. + @retval EFI_SUCCESS the section was found and its description stored in + an allocated buffer if requested. **/ EFI_STATUS EFIAPI @@ -473,13 +603,10 @@ ManFileFindTitleSection( ) { EFI_STATUS Status; - CHAR16 *TitleString; CHAR16 *ReadLine; UINTN Size; - CHAR16 *TitleEnd; - UINTN TitleLen; BOOLEAN Found; - UINTN TitleSize; + UINTN Start; if ( Handle == NULL || Command == NULL @@ -497,59 +624,34 @@ ManFileFindTitleSection( return (EFI_OUT_OF_RESOURCES); } - TitleSize = (4*sizeof(CHAR16)) + StrSize(Command); - TitleString = AllocateZeroPool(TitleSize); - if (TitleString == NULL) { - FreePool(ReadLine); - return (EFI_OUT_OF_RESOURCES); + // + // Do not pass any leading path information that may be present to IsTitleHeader(). + // + Start = StrLen(Command); + while (Start + && (*(Command + Start - 1) != L'\\') + && (*(Command + Start - 1) != L'/') + && (*(Command + Start - 1) != L':')) { + --Start; } - StrCpyS(TitleString, TitleSize/sizeof(CHAR16), L".TH "); - StrCatS(TitleString, TitleSize/sizeof(CHAR16), Command); - TitleLen = StrLen(TitleString); for (;!ShellFileHandleEof(Handle);Size = 1024) { Status = ShellFileHandleReadLine(Handle, ReadLine, &Size, TRUE, Ascii); - if (ReadLine[0] == L'#') { - // - // Skip comment lines - // - continue; - } // // ignore too small of buffer... // - if (Status == EFI_BUFFER_TOO_SMALL) { - Status = EFI_SUCCESS; - } - if (EFI_ERROR(Status)) { + if (EFI_ERROR(Status) && Status != EFI_BUFFER_TOO_SMALL) { break; } - if (StrnCmp(ReadLine, TitleString, TitleLen) == 0) { - Found = TRUE; - // - // we found it so copy out the rest of the line into BriefDesc - // After skipping any spaces or zeroes - // - for ( TitleEnd = ReadLine+TitleLen - ; *TitleEnd == L' ' || *TitleEnd == L'0' || *TitleEnd == L'1' - ; TitleEnd++); - if (BriefDesc != NULL) { - *BriefSize = StrSize(TitleEnd); - *BriefDesc = AllocateZeroPool(*BriefSize); - if (*BriefDesc == NULL) { - Status = EFI_OUT_OF_RESOURCES; - break; - } - StrCpyS(*BriefDesc, (*BriefSize)/sizeof(CHAR16), TitleEnd); - } + + Status = EFI_NOT_FOUND; + if (IsTitleHeader (Command+Start, ReadLine, BriefDesc, BriefSize, &Found)) { + Status = Found ? EFI_SUCCESS : EFI_NOT_FOUND; break; } } + FreePool(ReadLine); - FreePool(TitleString); - if (!Found && !EFI_ERROR(Status)) { - return (EFI_NOT_FOUND); - } return (Status); } From ff8da347261ec80529f6c2398d9905a289b81ba3 Mon Sep 17 00:00:00 2001 From: Samer El-Haj-Mahmoud Date: Fri, 18 Dec 2015 07:41:39 +0000 Subject: [PATCH 315/525] ShellPkg: Fix a bug in smbiosview PowerSupply Characteristics. Fix bit shifting when isolating the Characteristics of Power Supply information. (Sync patch r19291 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Samer El-Haj-Mahmoud Reviewed-by: Qiu Shumin git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19413 6f19259b-4bc3-4df7-8a09-765794883524 --- .../UefiShellDebug1CommandsLib/SmbiosView/PrintInfo.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/PrintInfo.c b/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/PrintInfo.c index e348c6f25c3a..3f99dc4825dc 100644 --- a/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/PrintInfo.c +++ b/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/PrintInfo.c @@ -3100,7 +3100,7 @@ DisplaySPSCharacteristics ( // Bits 13:10 - DMTF Power Supply Type // ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_TYPE), gShellDebug1HiiHandle); - Temp = (Characteristics & 0x1C00) << 10; + Temp = (Characteristics & 0x1C00) >> 10; switch (Temp) { case 1: ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_OTHER_SPACE), gShellDebug1HiiHandle); @@ -3141,7 +3141,7 @@ DisplaySPSCharacteristics ( // Bits 9:7 - Status // ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_STATUS_DASH), gShellDebug1HiiHandle); - Temp = (Characteristics & 0x380) << 7; + Temp = (Characteristics & 0x380) >> 7; switch (Temp) { case 1: ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_OTHER_SPACE), gShellDebug1HiiHandle); @@ -3170,7 +3170,7 @@ DisplaySPSCharacteristics ( // Bits 6:3 - DMTF Input Voltage Range Switching // ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_INPUT_VOLTAGE_RANGE), gShellDebug1HiiHandle); - Temp = (Characteristics & 0x78) << 3; + Temp = (Characteristics & 0x78) >> 3; switch (Temp) { case 1: ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_OTHER_SPACE), gShellDebug1HiiHandle); From 147f4c29a2b1903b160cdda1693d35e3a6a8ee32 Mon Sep 17 00:00:00 2001 From: Samer El-Haj-Mahmoud Date: Fri, 18 Dec 2015 07:42:12 +0000 Subject: [PATCH 316/525] ShellPkg: Use %p for smbiosview SMBIOS table addresses. (Sync patch r19293 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Samer El-Haj-Mahmoud Reviewed-by: Jaben Carsey git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19414 6f19259b-4bc3-4df7-8a09-765794883524 --- .../SmbiosView/SmbiosViewStrings.uni | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/SmbiosViewStrings.uni b/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/SmbiosViewStrings.uni index 24fca87adfa2..9811542013c2 100644 --- a/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/SmbiosViewStrings.uni +++ b/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/SmbiosViewStrings.uni @@ -2,6 +2,7 @@ // // Copyright (c) 2005 - 2015, Intel Corporation. All rights reserved.
// (C) Copyright 2014-2015 Hewlett-Packard Development Company, L.P.
+// (C) Copyright 2015 Hewlett Packard Enterprise Development LP
// This program and the accompanying materials // are licensed and made available under the terms and conditions of the BSD License // which accompanies this distribution. The full text of the license may be found at @@ -78,7 +79,7 @@ #string STR_SMBIOSVIEW_PRINTINFO_DOCREV #language en-US "SMBIOS Docrev: 0x%x\r\n" #string STR_SMBIOSVIEW_PRINTINFO_NUMBER_STRUCT #language en-US "Number of Structures: %d\r\n" #string STR_SMBIOSVIEW_PRINTINFO_MAX_STRUCT_SIZE #language en-US "Max Struct size: %d\r\n" -#string STR_SMBIOSVIEW_PRINTINFO_TABLE_ADDR #language en-US "Table Address: 0x%x\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_TABLE_ADDR #language en-US "Table Address: 0x%p\r\n" #string STR_SMBIOSVIEW_PRINTINFO_TABLE_LENGTH #language en-US "Table Length: %d\r\n" #string STR_SMBIOSVIEW_PRINTINFO_TABLE_MAX_SIZE #language en-US "Table Max Size: %d\r\n" #string STR_SMBIOSVIEW_PRINTINFO_ANCHOR_STR #language en-US "Anchor String: %a\r\n" @@ -452,7 +453,7 @@ #string STR_SMBIOSVIEW_SMBIOSVIEW_SHOWTYPE #language en-US "ShowType = " #string STR_SMBIOSVIEW_SMBIOSVIEW_TYPE_HANDLE_DUMP_STRUCT #language en-US "Type=%d, Handle=0x%x\r\nDump Structure as:\r\n" #string STR_SMBIOSVIEW_SMBIOSVIEW_INDEX_LENGTH #language en-US "Index=%d,Length=0x%x," -#string STR_SMBIOSVIEW_SMBIOSVIEW_ADDR #language en-US "Addr=0x%x\r\n" +#string STR_SMBIOSVIEW_SMBIOSVIEW_ADDR #language en-US "Addr=0x%p\r\n" #string STR_SMBIOSVIEW_SMBIOSVIEW_ENTRYLEN #language en-US "Entry Length: 0x%x\r\n" #string STR_SMBIOSVIEW_SMBIOSVIEW_REFERENCEDHANDLE #language en-US "Referenced Handle: 0x%x\r\n" #string STR_SMBIOSVIEW_SMBIOSVIEW_REFERENCEDOFFSET #language en-US "Referenced Offset: 0x%x\r\n" From c3cf4d47580c9c90359e60cc3e47af86d17db3f4 Mon Sep 17 00:00:00 2001 From: Qiu Shumin Date: Fri, 18 Dec 2015 07:42:43 +0000 Subject: [PATCH 317/525] ShellPkg: Fix the 'bcfg' command ASSERT when use some invalid parameters. 'bcfg boot mv xx yy' command will ASSET when xx is larger than the count of boot options. This patch correct the order of ShellPrintHiiEx parameters to fix the bugs. (Sync patch r19295 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Qiu Shumin Reviewed-by: Jaben Carsey git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19415 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Library/UefiShellBcfgCommandLib/UefiShellBcfgCommandLib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ShellPkg/Library/UefiShellBcfgCommandLib/UefiShellBcfgCommandLib.c b/ShellPkg/Library/UefiShellBcfgCommandLib/UefiShellBcfgCommandLib.c index eeee055cdb1b..142504a72dbe 100644 --- a/ShellPkg/Library/UefiShellBcfgCommandLib/UefiShellBcfgCommandLib.c +++ b/ShellPkg/Library/UefiShellBcfgCommandLib/UefiShellBcfgCommandLib.c @@ -2,7 +2,7 @@ Main file for BCFG command. (C) Copyright 2014-2015 Hewlett-Packard Development Company, L.P.
- Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.
+ Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -1379,7 +1379,7 @@ ShellCommandRunBcfg ( Status = ShellConvertStringToUint64(CurrentParam, &Intermediate, TRUE, FALSE); CurrentOperation.Number1 = (UINT16)Intermediate; if (CurrentOperation.Number1 >= Count){ - ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_NUMB_RANGE), L"bcfg", gShellBcfgHiiHandle, Count); + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_NUMB_RANGE), gShellBcfgHiiHandle, L"bcfg", Count); ShellStatus = SHELL_INVALID_PARAMETER; } else { CurrentParam = ShellCommandLineGetRawValue(Package, ++ParamNumber); From 553e1a5738c5f8eb0423de66218330e99de4aebc Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Fri, 18 Dec 2015 07:43:13 +0000 Subject: [PATCH 318/525] ShellPkg: Fix unhandled value in switch statement This patch fixes the following compile error under GCC 5.3.1: /home/pcacjr/work/edk2.git/ShellPkg/Application/Shell/ShellManParser.c: In function 'IsTitleHeader': /home/pcacjr/work/edk2.git/ShellPkg/Application/Shell/ShellManParser.c:502:5: error: enumeration value 'Final' not handled in switch [-Werror=switch] switch (State) { ^ (Sync patch r19304 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Paulo Alcantara Acked-by: Ard Biesheuvel Reviewed-by: Jaben Carsey git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19416 6f19259b-4bc3-4df7-8a09-765794883524 --- ShellPkg/Application/Shell/ShellManParser.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ShellPkg/Application/Shell/ShellManParser.c b/ShellPkg/Application/Shell/ShellManParser.c index ce471cffdaf4..f12775f86585 100644 --- a/ShellPkg/Application/Shell/ShellManParser.c +++ b/ShellPkg/Application/Shell/ShellManParser.c @@ -564,6 +564,8 @@ IsTitleHeader( Line++; break; + default: + break; } } while (State < Final); From cfbedffeef8f5cc480429571ef84fa7dbba8b9b2 Mon Sep 17 00:00:00 2001 From: Qiu Shumin Date: Fri, 18 Dec 2015 08:31:33 +0000 Subject: [PATCH 319/525] ShellBinPkg: Ia32/X64 Shell binary update. The binaries of ShellBinPkg are generated with ShellPkg project 19307. The binaries are built with no debug information by building with "RELEASE" target. (Sync patch r19320 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Qiu Shumin git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19417 6f19259b-4bc3-4df7-8a09-765794883524 --- ShellBinPkg/MinUefiShell/AArch64/Shell.efi | Bin 387808 -> 382304 bytes ShellBinPkg/MinUefiShell/Arm/Shell.efi | Bin 330208 -> 330336 bytes ShellBinPkg/MinUefiShell/Ia32/Shell.efi | Bin 338944 -> 347552 bytes ShellBinPkg/MinUefiShell/X64/Shell.efi | Bin 382528 -> 392832 bytes ShellBinPkg/ReadMe.txt | 2 +- ShellBinPkg/UefiShell/AArch64/Shell.efi | Bin 887136 -> 873664 bytes ShellBinPkg/UefiShell/Arm/Shell.efi | Bin 769536 -> 769088 bytes ShellBinPkg/UefiShell/Ia32/Shell.efi | Bin 801824 -> 810496 bytes ShellBinPkg/UefiShell/X64/Shell.efi | Bin 896800 -> 907264 bytes 9 files changed, 1 insertion(+), 1 deletion(-) diff --git a/ShellBinPkg/MinUefiShell/AArch64/Shell.efi b/ShellBinPkg/MinUefiShell/AArch64/Shell.efi index d5756e1013426f55223d34615a762ce87dfaeed7..9faeaff581bccfcf17665ecc7e58545b427e2150 100755 GIT binary patch literal 382304 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 literal 387808 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�{7ePG*nzH_2q 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 z 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 K)c~;k`~LyIR~7jH diff --git a/ShellBinPkg/MinUefiShell/Arm/Shell.efi b/ShellBinPkg/MinUefiShell/Arm/Shell.efi index 8a7d7e5b79461cd49e52995e99316ecdfd233f48..695f72a3f1bf0ec12d0c63c91a9839a1e09b20d1 100755 GIT binary patch delta 140725 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%0A**x!=1SXD9u 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

mlaEpI{1^EQ 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 T1@;CWp>Uqwp>*5Xm23SMcJ>?& diff --git a/ShellBinPkg/MinUefiShell/X64/Shell.efi b/ShellBinPkg/MinUefiShell/X64/Shell.efi index e7370161693f522520fc3b3499258aa7b596f22d..e79060ca5eaccff4b96eaf51828009ab8f7eed0d 100644 GIT binary patch delta 125926 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 z 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 Rb$#I?VHiB3?d!eT{2#Hjz61aO delta 115297 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ν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 diff --git a/ShellBinPkg/ReadMe.txt b/ShellBinPkg/ReadMe.txt index 788922d225f5..8b7c9f130b03 100644 --- a/ShellBinPkg/ReadMe.txt +++ b/ShellBinPkg/ReadMe.txt @@ -2,7 +2,7 @@ OVERVIEW ============================================================================ The binaries of ShellBinPkg are generated with ShellPkg project and built with -BaseTools Package (r18507). The binaries are built with no debug information +BaseTools Package (r19307). The binaries are built with no debug information by building with "RELEASE" target. The following steps can help to re-generate these binaries for customization: diff --git a/ShellBinPkg/UefiShell/AArch64/Shell.efi b/ShellBinPkg/UefiShell/AArch64/Shell.efi index 056da8d2932a4fac21116b5ebdcaa12515d3e9ac..76b0a03f1010d7f34b624f7d4c9de78e80c28619 100755 GIT binary patch literal 873664 zcmbTf34D~*_5XioCM=@DBMGZZCV{$SgF*mtDKm+?wT=YbTP6#L+9gy}(6&s#T3eSI ziFK)#30O7L+FA`DRm%j_+S<*aRBKyj0xm68YXQlilHdFDJoh0(wEh2I-@IOVJ+wfB!Gc zi~a}xrRN;FzuvHch5se({FnSs%TCrFYQl$6!t=IItMGr!t6DsN$zrvo&u%~cXCAz; zG4ZOV`o;C+i7%0L9)I-A|BD!tuKN1?FMq8O9zm;5v!3~X)T_x)|6ksB*8QquSIDF? zzpiq2UmxfQn#hJt##B!j8rcvICAyL3f99Fcl{W>m_o~mkYi6**}JR3=8p(O)Noo9Hkm-?_Q?5F&+ zg`Ku(A9mLh9_+7?->{*oIScGG&(D+gVgKbK4|anO%fkM#pSG|&Y}$vNUF*TVko@KA zs+yxUiS7)~X{3GFTP*CeeOMOuZGPIqzQd+{*n!7A*irIVKVH?`4s6p|)qE6bANG+K zdvsU(uq^Cr{j`OBy-oYDOCI%Lmyy5e(W>S^ZK6B;i>l@!q8aS!&9J}e76?x!v6 zCY$zQM<4NE7n0xeNL6z^up>XKYX0|0{jlHrst0?p56i+n(@$I2=L~>dpYmXT1gzjs zs+zli9q0LK9_&k&c(C6iFJA|z41hg-0PL2BJlJp0uJqxm=8{tq-3gwX@?a-!@L<0( z0QTVnU>6U7-Tr_F`wz6M`7!zp>?F^h&eOMOu!+zSr{;5s-u%kclU|&Lh&kxXVU`Ot%YCfK{ z5Bv5n1=?g2zhK+OfnA3kY_;jIg?*<@d$0>r^(#Htr;zX4*-b0abJ5>c)m(g%Df06_ z&Hmm6UfJx)J|5ertNgUZd+h;uvA^H<@E%Qm&F$#tdFUt45NW?p=fCdBVw?}l!oJi` zTi9`%_W9LyiwAoI`3<+CpTJJ@{MU*7u$Nm|1btW*_Nji_!aj2V?Cf_v*uB77{yp?_ zHu}l)eG*w6jaF9 z`|tsFRLC-}$&nYJ! zIA)s;F-7v5WFPh&Y;vbsc*Ump%J|56d)tkfQ*+Y^lUs%{PHwJ>l~R6^t&_oDiU%V( zaIal{OO?}3o#gkbV&f=ZOnxF5Sz4Shiwee`d0k7;^Xpd5LRLe~i!H-UtNglKPk_$8 zzA>t=be!_UU~{v{%v++iQT#!_>>^uMoGD%+ymLuM_VukDYD|$|CzjuSqFEH)*Eh$Q zMEAafBe{G(QT^S8k10QKF1}%5&~*B|e;F9`f5!tO=Uvw`X4Uv*L9-)!%&PJ8OyJ5M z_z{4%SxW+oT6ixUYFgiie&O)>?b|{hhxqy){ah9--k~vHVCG#1&*m&&f$WPI$BdER zQT`_XDqlrCzfQvn_)4A3vZ~l-%Kv8Tc=DOEcMWiY!0Dn+n(^>U%CCaA&@+2guy98_ zB)%7>icQgu)yM$9ducRn&MP^|)XjoF(Iw+YmJ|fe+xDGR^g9e5mRm)_m(SzG^o7p85l8l(N`3*n>1i~r0Tam? z@{hhHl8a7T$Z{%@o4|ib_5{ZiMRI8~YilIXyDs^;`A)zjM%D%eJJDSbk!}Rarq4HR zNUrhJ`A**&GqYwy$my#!OA8!y5!fxz z5}ji-A*QSUYURgTQE0A zfq!tw@nNf+zNGdIsqOXkL^}9I{6wvfu4C+|j&w)k;W<0j5+O4!J~-M@N*|6b_3X~Y zRu}wr&HaAb+MRZrM%UbRO?HlF8)D=ypUeDo5qAD7Rk2Fa{<`YR;LCi9KJOcGRBvX4 z$z|wM;E>{8w;zqB_171AV>Eo(Y9g(rx)d@q*s;7E7F6E^(WT-@?(|cUOA!969DS}OohBV(Jd|{K_?8Ra?clR8 zr1Qe1Ix4GwybJx$8MBz&fYv^YzuYTE)9J^5CuiNEWW3VH4eW;_SF~C>@ zRuX%E7x>hEZ14KIlKIXk>W&+~(1|aI%v{!BW|}3%BjXFq%q02oktP=oMRH@u0ka^I z+ZYV&SUwv20j%}^`R10Av#Mf63$N|XOp4@s(DxAef}LPai8n-M8e^tRM`!%<=$Tc{ zC+ieXsm!a>bw*X}lXZ@oGBK}C%cs^ka*FhGKdv)A4c8GPU7BU7NRr5(4X>1Znx%EWKoxouXX@k$WQ#1?9QYfwx-*i6Sr48 z-K_H>0kamp7}-=4$-M!*Mh|bdZ1W!*DW^WMw4%8~L|0MjZrZ5*!Wz>SA8m5k5%V3% zH5_2hBi=KEy5V?a=34r=r_{7+Y#LKMrSBMYCXODdzpl=h9jgn>oTC_TvL#{cTYNlv z4y?>EuK&?lb52#PS?08-h`)j4V~}I za!hWw##LhtW2cs}^_)AlOvrTlzLp8eCo#FbQP1wb1lR|R(K(MnLp<;2Y07KejE(jVR2-^AzSP(c#r}~-S@11o|yY_uwp~-zf{c8rB zPR)}g?|+tgW^}5E`YS%}yGuM!etm`Ji_xiXktZ9AoZb5Eh{e@*S0W41DU}iPxI8UY_)?b4=RckB>=Rj9&HoA7fGv z+A)_7nrZdJHJ6P_9g2L!XUQ%d9Q8tRk$Imm^PKc1e0Kce1n<(5yTQ{IG&iT|yV~Ll zjPd-8F{##>p-1V(q(!$!!>H72qy>Y%b!K{?z0E8Nxa*X{)aNM6 zTo-rq>XBn6ub&y)&!mO>S!n+v_0?AwHvRnveG|?K@=bwhy^1x>Z^%nyLxa$H6*{N# z&(M#n-S<(cQr@N8GY(eSnAA}=J(v2*-?}flC+R)Oyx)6fBCRZIgGjGu&P)-yu<)_KX>7cN^Oq_F1X!i zVQL)x9g82835`vyb8U-BNp4C9X`?Ze_^5B%GsB}DKE8ZB3&10qMZ4&_lQteN#-=)f z_b+JPZ=bKM?btU#Yr|*l*y>*kYhL&aee&&7964=(M%IJ-?a^ZLB%8(L9cYuD+P|i5 zW;}~#Z_Vbdsh5{l#iB1^KjG0ilwW4+Wb)S3rAIM#sbid~*eR5=UTuxbk6Tk6TQ$76 zw;bI{Fh^+~YaoA!r~kS7)zz_ylqt`c;0vLTqAO*4HHLowMbpNpbA7~1ukz@M6qso$ zYund%S7uP}dg1B8hZNk*8q>P!Hu?KSsbA4HL)$pxUUZbKs*VicyuLv>pPsbv{U-B0en0R+C{J6xU>RiwU5uXx!AT5%m^^fC!HAsJa{h|c>K41 z?Dd`;C)hp$b9QEs`dOGd9sP~_F$VmlF2;A)-PP_|!;J$mMzh75I|@^Z6P?I^ae;Zi z9vHu2E@wT@ zz6WaL_Z6lZSsw?b8_;xKy~b`4wB+x@S>0zo)*8Yvjz)oJBXN}sI*`Ucj3d)bF?z__ zCc=D8ouy{57f%{SUFp;W`kmd39oS}C&m9Jj_Vulo>|5TgbhJ**@?LBLJF*}5%?T7} z&2E-X!%tA1QTUgE0<$#oPG#%^?43V`ck(VfEt-D_J+dotWY&gVT|=KX?Wl}N*8|v$ zt3@L=9Awf~1tL7w^$K@U5Da}7GEb&zOMn=JY8C-sQ>OgaS5eIG`)M{~Nr z=Gr&nh+g2A)x2F9>nec$M$`J@WYhMDm2DE6Ab%rEe&VglSnhE8&b#vBZ&f7Q{Tous{B35MMM6YTQU^i*~@K}|L2eGWw#MapiSyh zV9TDs|E_GMvj?6=fLn|lRW5t+d*G`tY1Yk>*$V1Z!c+MuS;{s3yBIraH=BH)$L?BB z`bC>-Xfsfso;--UT3aKp-SC3(x~LsHkWMwZv8Ol44_Q6mf=>A{s6zCL&bOs0yF-1K z{Q>t>aLcZG@-IxaxcmvEM63F8fNiS#r7ItQeZ5=pAo{Y0b@>Ox3eJLFjm7b_#n*KG zWAPv!j4aLIH_FFaf{zh}-uPf*thcb{v%biQv{igH%UmhE)27L<8k;(vIO+DFwepd$m_Dl-2W~T<2cSogO`ns1NCVw>cK67qlLlPaqS1dCo`dAu$ zmmhU;5KsKkV)%i)4pts`u0|gc6eNgCi-s z!`!64i9X*?@ok0Hj~e&U?|s&hPH0?xp0THKw&`Ha6YSgly3+Zb9XG4A7I5&7;pZy& z@-}o!9*ou5E193eybE5}cRuSR(5acgO2b?6Q27D!wI=F-{wWqu9pg1l-+);y`0xRIhDEth3KC+}lacyKbi`d;&BNO+^=R43odFN5YzipN#gN;nI zHaT;xO;rCFE8Wa}-I_C#w>LQ>DU0{@bp{Kf9n!DYj2$P;k(ryU?U0?aw!^m@-5TgUn9R@s3!sqSWk5sEZ9uFu#h{8*|tz=3C;-v0BJGz~gGYJ8 z=v(K>*2c58RbH31@vo9U6?-hZP_FvWw-3DX6=dVHA?(D2Kx^$#Yv1whzsb70c&J(Q z8_|CVwgp|zkpDCC2Lq$z`X*;P<81Y76xtfP6oiOdR zcFu z2JQ~6$tHXmo+1x3RQ#E>)zuH}rAUW9if&nTU3iIf^JzN<^{z8L;#a?)aWiEazfqWL^l|=hc0lI>r>b zYpot=SD)p#E>b=8LF=gobRo&wLgOjU`_Wcc zu|`0zGK^a{?#Xi}ZL8sZT(%ecSI_zc-Y+%SKlbM9sOzqIrg?pMu^u}t-cF*QYU{RR zpEZNsj0dP|^|+69ovX*xi9qXzq$9{)^Q&UWnkNmu>Tk)HOxFX?w_E#dPR>40 zn|mu`ZImP1vTKH$+)voQlFqGL?D{vkhi%&oHbHTtBr<7uq_R2s8{~I)W$fFOyK9rC zCg~;1PN}N^q)&~O}?dbiCL?m}V@P#K6oVB%0I!9k7*fuv? zoYIF(eUoz^Fg53ad(P?<_V#zIf7&Wz3tYMjQ)BR>MBD4s(R`|U!ZW>zeID?n!4W6M zMSiF9r;-0n@{{C?-#S|*{2h8i`$Kx7>+byS?!Wjt{@DK5o??0*URA)J6>B~Dh~*~t zMN7AV?gtlnJO^iW=|ij?&TQ#U-c}i#Nu8T0%RI>{W@w_j8a*mPZu6|H5_3%F*%nSl zJjc$6?w%i4HrJos(w(@aGIlKG-kdVZom13@UtI(b@b?nLr|vng$q9!T!`K(*_FRHk zl==5Jw%t(Bh1l=0AcGBKC*S*A0gvBmrsKg-N9 zgA?6{s(90nL-7kA@H4 zn&Jr76k}3hV9NH3CwoTTcdzW3-sKMvu?x-h<^-WVtRaQJ5Sg|<$d$bKqzXAu8u;HCT> zKURD>zK&wKcS4)`9;Q!YIOFz;pJu%1Oz&T98ojITp)b)(D`U#Pnf#th(f^Cl|HYND zg`}llKEB$oR1(V+zM@nCbF%vId5d$2kHg}8(ob8Q8*SRh*?ysi^Q+|7T*TZ1&P;P< z>}=BcIJaHi-^T*xYVmWD#d(R3!{YprpSCzx+q91}FxSI*9{H>1RyLPh!up;*Rguoe z*|;FDpJTm#jgB1)RytD`SU|&c_*Q%9r;R}_`S#TQqwCl46;#@H=ub+uuQp zoRU*M&X&_WoPVQT>FJft?chv*sWSG<0XWy7Yy0&UA541tBa8F518^QX0H@@Xk2722 z;Y`zRd2MBL;EOHY;Y%uG_Yc5XJ2$VN%n#Dr7K`(d0XYBdr!8+Kr+l2zSsuC ze1bD^L1ipKI$wu2qig&7$y}j+Hd&mv`#7vTxA4f;tw?VSAr-Re4({xUyv*z>tbcv=}`Q@LlbXJ^wAdDIL<&@Q;TYkUP zeo}tS{H$_hN)=h$yWNkE)c3Kym$vl-f$Y1Lp zv436UuM2O%UixdJiM9BL(B`k3zD*ha%*bu%O2f^Q*mDS!eTh8v?;Dox$v!RUYZ>o~ zJvYp#jI|tsFS9MsdRDnv-L^&ew*9fL9D8yfUUdrl z-GA7>-z}eLCu={g`@DDwXE%wJ?m3@zNrCo^3sc)e#5X5+eHT67KG<8EBsCMBt9YW$y6BusFMZg}8J;x$h+-7Xd1Zybx#?gtM>@2PvL1Nv)3At`+6kiR ztjWZ{f~hj;HtWC(*e{U&!slxLOiU@ZqvR;&zpBbuHRbB_PvDni;raILbAU_nl3yzy zdTiUZEwi<*ElRz3ftNq)lknG;o&o$Y@XIS>M+iP^`T)8dho6amH+pe&U<{0#JcEr$ z6F1pJ+^BDuS%j}UM{T#!PuV)rw8F*%#?#mEyN!+?^U-=EApeW{ifOoU5Be`XmHfSa zjZQ^+7C1$RdGb|1&X#W0MmFfYfJv?#uRV9#l(h#{U;5^|CN5BPY>?uyDN*H zZD*`&{Hw3%Y1tCnSNOJ0YZvKX;!U4_g{j&BvBbsjZ#($5fv*RA(nI09fITwlV*i@* zH+K9y(NVa)(edNjI?t!rcHerlw4Sp|eUF=^l6~I{lWQMhW@v23v9rgrj>ybnJ>#8) z>YPYAJBx8oEF^4*QB#&7{TpHnnG;Q}gmq>B{SS|Wx8yg-MiAp!iyd*#YayrIb*B?I zSXd0e{XbDceM3ERsU66Uwl)2Z%m9zeU|*p ziHu)(@)H|#j&qg`J)fR_c>&>W)|wIi(HG4pzy69>|2gRXHvCS8Dx0Y@Gd$8%mlT+h zvlxfz!_1tue_9|Np1tef=wrRmmHXoYCuw7HL3A(zylX}(CZO{^^Y)&_8dv3SK%dUY zt)Z>#zG8TWwM)Q>Y``YYEn=FLlq^$c@kM7e<0 z6zGm{Czub3t+gtKsxg$=9BA!BrvBdlM&=C3nDugJ*D;f0hoB1)#*5;?l7l<$IIp92 zown|M(=~s1Wi^wqCzL&6%j#KM$rewD)7LeD*0}AX)zyN2ie9Lir}{AFjb)?^NEgh!>h>R7t0(z(LMrsL2O zXo45i5idmZSn0)amCm0ny$R-zeN}ljmbyv$A1uKJu7qE~%Ghg^Bb)AnXe&H=-?Y0r z76Xqvr_i_Kpht6+Z(DRe5E-U+);;fz)xH&h7sKyWH1BB)b&NqLch&`n2XO}X%7Ts$ zuOHOWH{2|`96u?8PBs$<_`#D4oHV#3^8orH`XlG`u8-`fn0(bUjm~)K^}i~d>uSu* zW%~}&Ui{2>5B}1>Dki({riB8IFov4<9|lM8@XEqPU~H}fU~=a zZt1OfBRwxjXk2pU8oHC<4gh!bF*cq(y?4F(R>GKB%-)`2Soyjge%yoCFk~j<6utS} zOy|6FptHv0BGuTSry3_qA0~!8c(>VphViS4(61N$v|R_hY}3e<*g#RL{x$XK(e4|_ z5B{~HxnvsWOLtbp>PcU3>t?7Mheq10T|KgLa+ErW|5U^-q&)dVqth|k!~Hc|-^cx! zpSHNy*|d+l<LlN-h|Q!td!C2) zJX_bt+vcY&-n(tu$J@2V!+SdU4KGzRXMu^X#3quy^KuX7Nj?nA$7O!n!dzj~KFpFA zJ(yF--}GWdb94s#4d}}V(oM{X8rSKgd)Hq8FaL>cZhySdiSR$tmW6%z7GI;Ew)ify zX&+zv?>&5@$*=hXygPyM`9?)-XC?CxHn#I8jZUIq@{BIzmVRJ?b3+Zjhn-^$dQ=i7 z?h}b_7;;Ke|YdOEuV8{T%I=fkVrvwx~^LiRfq+2UI%O9OX;%?pGh z8wT->JHCeYSw;?F-T&Z8rcP~t{0*m0Z4$KU8*COGr`WybfZ(w+5@&qYS%P2U+C1o% zZ|BQ!!hrrCGqC^9di~!@yPD@Jnpm)p?t0S0{T=cfo&t9b`u|cztckSdiJCjB9IeAb=tlwiA^Y+s_R7bdK_3pYxWDe> zvbfj!X^VSpk2H$zT3NMROOp!+)xXol06d)zE5jqff%ygdR1bL(k>oNB7?! z>G6HGkI&-2(@$Ic_t^A){EvJ1&mez!Cw;F4|L-bdpCK)L*TMI;gZO?09gUmtjPtE+ z!^yB!C zY)^)MIp#gTdVC;+wZf$fjw>3Hot-i)NM-nIf z=vPhKUgo^RY#)nmp`O-8=X>^Y)7uqJ$yxM|vGPs@dPTnGnc{^e7YK)DCXjW2`N`Zz z{z=}v`h#AtZ#9;_$VYwE8}a=n7S7w7hQ_q|$sDY{>3!Tw!H)P@w8ifbtdiqBI5R9w zap;MBr_m`s1HbAE_#gNaCGdDse))}*f1dK$Uimo6kI66pHsvwO!Kd~o2Z>SSm)}6S zp`890{BLs#Pv%;Uza;pjx0;JHYb%^a^hWh=8fDss=fMas2S$O(C08^$zMY7}=P>E> z;d6#Q47L2nhnUt0KYjQ?^rwVxtTP)bVk^nl+Cp@`HH|TB>jA6UECWXobb8-)biPix zjg{)Mwm+Z*}i-=sXkybqi=`e~n*rd=g8e&5ywcXizA!0J~joGjlA zo3$0OFH^4km#=Gd=tF0F3G+AUr=jBo+crYmjpv)(ChS}Qy4*D$V`*ny6d$dI?>%bq z(@w!pJGBEpuJy?)`gME8Kl-ZUH=fyXKQSKJ^i$n^|4(n14$a%TZ$xo#;L6D{opE{f z1J1axZ{(k8iGnkF#bifihPBv>ww!ocwbD9gZ;ow3GVxC*Z zH?9+PHi$Ty&OX$lAIfh6*DB(3E$DQkyYJ0+Dxw#<^)1^T#bNMSuU1R|zj#F+f7nB1 zy#i11)lOt=$I(lj;ZvVgcL{aHJJ$bhohWBM)n+nv8>pLQofqQFa+3E(&MmJ(uM))j zl9C&F?fgUU3$qr6mn^1TP&WVf74Ew1`|v?D8t7-8;_hjc5L;O6?s*rb7DKOhMnrp1 zg{iNWn>Oy4DJs6nI}@UMoOP>~TrVF`w~@Nu+Po+woYCJ_5FaT_XwRFXa0=ct2xa%p6(^D~kK z_^T(tGdGUy#@+(0m!J~~&hu)|_22MN`xLgk zl0KN!p1gC0iV5nh$$U#ozCM(0!iPHse+$2;hVn~ooxVJsp-!xwI^kd8|5JYFSqq%$ z{QKXfF2AVJssGdQ?l{>@{|4V8TD|X5#zE&__ z;0p~QefOygoc528cZ5%|UE~k%u^r5(gYe74KdXo(na@OTQu)Y5dj|n*n)EU-8D9yx zgo#%b(=UDR;@TqGXZIfO_%H=4{gZxJzI_rbWIRXmEI9<-0v3AXp2IP~HuSL(Q)57^U(6Nr(2DbX&)pq zeSwoeE*OBKaD;Xj;ybhdSPC4y3w8}_p;F-NPqPnO3aoa@lqXmd@mJb^dAu9r5IjF_ z;+@^~$J4JmicZGAoU*{ZTTEjs!uyJg#Y6UAuycZ=b6JLT$rH!Bv}q0TlI3F<-CT9C zalfINa7KUKu64&dap9$|`YPRv056W8gq_`?yw&K3&a&tX$}fPJ%pr`w%2XnBk0hgnZ@6R|_Wk^CG0(GoF<7 z{Lr+@7KXm;l?#@55ylsfbn^Yzxtt5bmZH;F`eWs)VB+2oGI|_1I#VeeF8uG*bnM63 zx7?5_aYnS{jT^4^$#1oAwH5i z_S={U^TkekhFE>o+};8{-HFj2p6qB(1)1&Ne^kEqAG>7LqX7MD24|zEf1+vgah^@nxG2>A1$SjAE|>&o&+XW@x%B^gtpBO!^~*og z{8$Hm$_|}d`)Jex=K=gnf8R^z*>r~OP40^5TXqmgob51W>;Jn4&@tf$ub7P6281Mag&Wk*Zy?Q>(6Wj7UG3|%3DbF9v z6I=4!MC!7xU{AiAI1KZb$qmBp%-0ipL;OEik}#bd?sdO0?D_s+j=D3ZYJ+w!XfkGF zGGn~6w=>B53-I(*|JuJ=;V2HYSA4Pj7O&Mu@%wPWtMlRp7nhq>;n)jI+08n5D*9T! ztnofR^&D`LMP_XscVoD+BwsPJfw0wo!7j*$J>k<~2d?m7{~S2%ORc?Xln1-z@`_l> z!j69m-R}?=65Z&Nq4 zmkIvCz#rkkkCK1gr@;4l^K?FZc=O-j2O2#1mkIt*;LA^wT}X zE!~$g{w?g}r^xkM!JgL-TYTBen8}CTaQ7Dy@;=PZx94c*--Mf+JJQ zS!2teZMB{bH6CkP)sOM~Z-Y-d$07Ycfwaaz^a9}wr3L{ra)|exyIbbiew|<8>|_0( z$iwH$TKJ-Q_>$;sBYv;&30HpK>gRZPb|~&}kXc)Js0Tk=R}p*jf51OZ@EH&4j}KqG z+csb(T$D;3M}! zzKaq3mM>H|>&Q#z@h2aCj<{mx0*`)Vy0#Jc+b$Tuo6mc&9}t~+_7i`mXp5D5%h?sq zeU!^r(i|XLmoJCc^YCP>9KzxgxDw3MNAT{;{v_Td`|KGW-W!1nZ{2xF`O-Jlsk6AV zr&q+jIiQdExYNRYNnRh(fo+!@*vGC@J^5S-9QhjlT1~#}cKEpcbnHE6GJ079X7ozDqDC4-=>U9>1=}P4Q5`>(oS`>&fBPV=t#K0+${bii36xya9Vy|3`8>b8aX>jXLgg3u<=BV=+QVm+pX-;y=L5>2KY{$!j|gjCcMgW; z1pZ5QMX)u~7;ODD_fQ$WAJ^Ww!8emXqdk20UH;50`#uub0sH~_`|E)>MLq6+@aoYA7oOKwuij?hg+i@K>aibvV7+{Js<$oJ`UCZW zJAPcez=_l65BVR7?q(?$tXrv*>Fw)O95g<{wI7|*(?~CUhgQQ=eq0iM$~GtVkWU{Y zdcr?oc4|IIf8gc2Y3fCkroEd6UV1la>LtW?%F{fxZi=wiq8LM(GkT)oB%6+qZm-nX z8<%j)|MBu&_>!xQ)Aa>MU4dNZ{F3utkv_h&hxYS{RcH3~ zt@|$c=7q*yp>>q<4Q=#&=g+B28&}WIrf#^eZ{4@3n+=-T-1Ftt7jEj0p#B=aJ}_oc zKmKmtx?bu>LuPhyC~yURopZ11=vy7yO{Y%eoxXKj3v1V;gS%nk5o%K&?MeIwIZ=!Eg$M&vUSqOak z7U$bX;<3}}pBO+RW%)EtvNQ^ASl@k7o-MA3O_N;_kFYD)+c`=2*%vfd#OXsJu^s}> zMK80?Ub?oy$<~Hi!$VlJ-wtiS(fUt)OY6+bm4boYVZBvs#$18S-TvvE=^$XZ?GgvJ z6HoSlPdpLMe4boqd2*8FN#Zb%ClP$on$ilV{Z8VK<11q0C}&+&w9@Haw^MT`dYojg zna18w;Gy}>#J^4Dezrt+4Sd$R{xcQKeP1GeBso&|CC=@M_oWt3hIN$sh78vRi`lok zoAue~idf%gh;s%#`te(H?LDS-bt&ieirw`@PWqlE(FE@M6mpy!D-4bEoHJQPGCIh|MXX_BAyCUFkI zkFRcU*4R4qX{2JWIRa100vX@S_!?3XyAc_$Qkmuh?634jaWjqad1rcK z9G+KaNdJWX4~7nGt~<^phu;@@y7c%5ee2sS{uay2ao|qC%bx+?k1P6Tk98h76B^99 zEbk1m=I@ExD?8N8na4YEa5qLVh`uXEp_s;-hnQ))M?mp`$f^d%k9+KtFM>b0+dV7l z-SzO4)iK?D#kic7zQ4h_o;-c)ml%dlK&x~hj;wyb+|f1MOEU)Mlze}_qj6J0T+X$9 z)J>op3F@>DYzHjCQM>wE4{VoIJ7kdtJAzD-9Sar&4D8gJj7=j)u`X)Hyj85fH8 z>P}7RlwxpM?jr5$^s3Q{Eh zHQ14M=-%|Na;IK*hPxLd&bNp^_tWL7YB(sD7hwNoVKBUTB_0Ix67T8>JRyG@&&UM*i+}vcY10$#|}?* z@1gLAE~U>O&T!()iD~wU(^t)RrsnZDLVB6yab$#o z<<4J#zh55Afy|e!&GPePpC%Y=RAK68miHO%uv7X{n`WS_^!Aqiw$I=j+fS+M>`VoB5dZ7hLjN zrPq$EZ^8e3 zdxn!n*I0Y3^L?eU;7U+O?Nry@^M=;;-81Z-_h`P`p^fe(L)Ws%nmw=mKDf?S?1JWZ z*}Ii(&|dD+Cj2+XnflgG_p=_|*FW8%JGM*UYvS|s*&7O^de*?7M#C`i#zbVBr>kA~ zkn$6a_GYjTlHVrwAB0EaHA+8Kj{dP{<&9UJDf%4Ww zXTaa&8}vYHA$->Jr-eM-d$Dj5~NAljD8t_(@M z5GaVccQOUBInvMR&~7+GBKVwPp)AmPBshdqXM&WjwK(JM{fdFsyP=W37Jb0|_Iy9) zo}qHjHK2=X*M*K1(udEmXBGHhhLc3M+N~VrKefmmmSHX^)G2fBgUE2fw zE0JM(ak=vWI#x;_1ha2hpd)gHM@yJ>&^q|0`iy_(wdg18WY5#(%`HuQ8~sGNb31h# z{CNxgCVtv_H2%EqMr^>>bLTUgAGZ0KgCn`0L%Y^clC{6*o3FRTojU_}R5{|O?vHDb zoQT{17P>XoBbY%mX6&8UuFNo+*={p>uix?gx`h_O0Qm3MVw`n zo2PY2g8gCHxGrp*?)P==7W<(t&$!dxgQ2r#UYn&>cV2=P5C5ptvGhe_?Xm-SSNjRx zEninYxrN^(O8ktuhPv7Bi5Bi^R{u z(&JIIQ~FBqYOEx+B2<`1paRKA<{2I{o9{J$?2Cd4Y~7{A9+vw) z@E#?dGmtHscT2#%vx5EX4VkNsn!;E+xOmBtUr!<*=}S5^Z|gkne=1=dCCc$bvDG@? z8>a68?y+~*RMoOa#ark7F0e>#>Zw}_ye#mdCUEd9;7Q&s$2I8u#_ZBef$P`mdmO=E zhHWjtk2B-UoX_wr*(ty%zz#nE^S zqi;jG53tZoSKqd8<9okQuyr|hUv#n0*1h!b`ObL$&*qy;SD$K$HL$+l#9heY5cf}U z9nhtmA?U_5WFH5?XW1i{M$Ul0UB+*eC>D3R=LhcL+>Gv3 z7fliT+zjO^3$s_ay)oFjtrl1j`M0`jCDA=X-%AtwP+xn7qQk`ga`bik8tSg_cy#Yb zenVv8(q8fE!^7q~LE7+JAUVDP%_+7fds;f!%!%55zjcAv??%$%lYD~uC*jkQxXUBr zY3m|>U0{eueqHgjrJcIKFiS3T>#MK2UvnUz{ziOL-;=xh5YX-O$~^}My$AB@h}8Xg zyh4xHihjdb(tZ=?YTdX<9GEk$Ydh{r207zZ4LEdBOFKv_^8r6*kK~ zJHz}bdgUMK+{{q;>guNSYK(9er8>jbUNCR?XJI0=(f*5Y$`6{zSY`YJQ}dn&Q}FJY z>)D`9^gl>_gN>Mp{f@vh+1*3m)_tf(W5E61uZE}U>6>i9R-G#N?zdO|0rwo*ID~5p z+;53>_b2!NL9^zM{5AZhoA6DRad*nM%AHNNPbYH6nq;ec>m)n(94vP7RLP0waA+;& z4&v_)VSJDtMtZ;Pf55Yo$}jNq)7*c4cfhrc?zs=jK4#wA-)16Z*p;2q9m+oN%hYZx z_b&4L49fqvpP$ry>Yo3v{D0=>7cpmQ?je7>pP!)q6aDwE9|T>7yOJMcKGj^X%JK!7 zxo4oW*yT-$@>rmSyE(2dcfLWn_9O=KLpWUBa_`vM{P5Buk3a8&S7%66zM1!s!*|G~ z=0(MCynR8|&iILf=keD2j#YA9NKDbQW%z#3HxP&9@BUtn{G)fdSGiVe&3+#~Q|-;0 z*%8biFf>-A&)G4=&9EQRf9=J%^DFu$onPV0 zAcG8uon*C!Bu)|TZF26wK1d%E`11a`XcFxsdzzecDbw5}UZg*0a(-y*rum(oEaNiX zU|KhR4*tk)!Pn;~*K?tKBon)j z8*?agiNP)^&Je%albQGxAKJTq_Y5x<_uAgb9Y?%X@A{SxS^qIJ*i2jO>PAuO2v^5O zrM}8jF`goxp8WW}+16*QFN$g|r2PE6Jih05^Y&olMf1I^x4%sJt+vi~_6^@qEE7I@ zceadAWhVsjWw|TG%yMmH`muR?MROTrPIc908@_Q5XNL0Ys!n1Ed}z`lIVs>@Rt66B1UbJIl(|@mb{j#77Bf#0nSzC2xGgEg)$BS`K-z3+E zcsIyF?NsjDb)8Gti7!_4ao^g1g6q@fm7R6|y$D_`ST#~$p>ZJLiXwv_i8x*-|)`Wj~5knCK(L0|p;H9%47 z0r=pK18C^?ZT&U-QN8Xwx5Bi}=JWhGy z?RsYn`SrD4{z~%Gw%wf{4w(_zQSS)YVXfwIv1%vUX5I|4wUcX&6~QTs3`TZ|BXI+9YG#~Gf);g>((7$FZNA9|BfOS z47?2ET=&y_VE1}-zs9rhrf-s`qjRBMGWPe`CV)fw5k8U_GtW3{$qege-NUz(wPch& z#s}Q(eF`vw?%m$w+QL!Hg&D z=#b&a2@gotBm`V^e$OulQ+b z)3+yowP}|=>zVhp-8wT^qq&S?-)fdJC~R;nO@Qn-N+FE@Tx4*ZJ@`&3I6`=B2>o z8BXYo{&MN?X%-iDwR$(SeAlMKmX=#>+M|VdQ@2Npa4$ce82={ta$LDHjW^GYMciNJ^ zm9a0n$NF@_L;b${C4Sn{EnZ1KeY)F!=g~c!{7qA!`&nWG6Uv<(M@r_zmcb`k`gYN^ z1rr!Yd25uNb-#7jCC|KA)~tPy8@S`bU)Q_eavfuG&m6>>-|qYBw?_5-&L;Mb);(13 zr1=)~LgqyIpi?bf6vA{>AU=7tqtqZSJo$;qUQ(5Ms_+*-XE=;GH%QnJBB_= zU;e_JtaAO1t)5#+Gf%mGtNf7&u>Cb>{u+?A75F_LM0NbN;C>povraTz^TQ@*F}S7c zf-gTJZD}#YW|da{H^~!EeR|j1IuXW8nsV(+wYxD_&nBQ3Ydv_}S5IAUJyevEja0vO zA=@?dMK)HyPvGNjq+GQ8jXVS01N)f2-b#nG=kDFLul>_$jKd1)<&Z@8iO4BIA7x(? z&~*!IfEJ#Yy0T<{AK89Kc|0#r9%m3*_&z*r*q0=&zDnlxoZ-kIYsHP{*)@F^^XC_+ zvuwD@Nk`(8pQSV~^o_aFrzx$r=tM2=ItQcufcP+Qqd)P{UfG?b% zduIv66ZK2$3E2RxAGB`JxdQEt>bz1y-(pj54z@3WObpMQ*5J^QILLG^cje1Hl1F&o z8;id4(Z$zE%ZAa<>I}9h3H_@_u>b!aZXfu~pycNLhLZLMv$cU%t?iEf9B>bo55n61i}bEyI0-n)`=R<zr(3600IJ6(gw+&f9x1 zF`4be&|Q4Mmrt-f5@@YsOiKsda|QBe(Af(GA6TbaS!JYWtgDmIw7Rd%$?ju+`=4b_ zDdox^&KTCy^=Wy}f~RMd)=5RFN@$U7cwGAe!~q^;ZeWgg{UaA9?^)=Pj9Ta$I+bb^ ze$w99^7f=OXEYI?Q`|3oxMFlqxO-EwlUlE9oas9=#n1Kqmey|i{hR>5gZd$3axZ6o z+%-FUG%ehfpflHdBromTz$0P^*TwNUbO-5&(7TI0Kkk`Zc^`g9;=^TI3ZY4JHsj76 zdun62>!Y1E%RelOwU6cQ!=5tdZ-?t#x$g7h-v5y9$R3+ogpD-(HXr&kP59zGKZMs> zpU*g{|2t&Op*_E=)ID>=UdN~YW#`c%`9{Dz5*idQEpg}h!&8sg@@n)$-=J?fjNfWO z=hN7YB(jn$-(Vc1;qi~5Tltca&iwp_^m1Tjw@H7vixxf57)bIxPS^9g?{Q4(B;ejj zERDXpd&HTq;iu!99U)w_clCy}U=|~H*`ze*-s%~*x~Fmi>;DXE68W4eBZgls8=b}u zMAue2-vV}=*pl)b-eoh@??ZV{vJW>(-$z4RCw)$IPx?_pDVd#;4%3xcg>B`tn=JGUi zk@C7WRyyyIjwnrCe5~$z&J32ZcGTR^z})Z#GwLLU(ELo$Q0kK zFhwlf{hiUTq9-m-u(@;5h2{S&n;bZr_~jqV9G~8^s3ZCn|83)L^?bR0&B}Gsez}fH z&Eb8Q)=X9=->@>e3w`D{57udI^c?$pnxpl;nRm%tI(j4Uq+^P;`~H@H{?WgWE<)dZ z-$gp1czJ^R1O4Ai(pZ%Jtbef5{q2&$lCNvW65TqtuKw$HH133-(wX_-Oi=FIx09*! z0Q;HJtLOuj&Ii=f?`Rb9jYX;Dm%FzrdxZT)a-H?b$P? zwnJl7dxL*Pjvntur)JQPt6bZ~-Tb^~p-sFjamQ^SHOcZ;W7n7M+s**}L|8G_Ltw zDe;wWnTEmxjky=#n{+Yat_?o9-`vn$HaU9&_U*|s=f~9b<~w`<_^Z9;6XCJ)g8a6O zpEsR6mlnGxu5YWghdUnHg)7OP_#+l?Sa>PRpbNfSH~pb(a@UER4_II3+_WDjHWi#& zL;T3LrH$J*3IBtvK}$|*=}xaLbFR;8XNg6KKZUHF z6Y!OF>Fj&ZJL#j+(%Cnx9vb{;om+wSwOU_5hik{QKOp-sjkYD6L3aH|+xBh?OR?uP zwv};xrN)yntK9GIeK~6Ud1shBo$z9K{qeiGl}!%1wKfS{KfV(LU)T2O&Y%iU_l|PM zn-|kRAAW1Sp5S*Z2DT~L*54+HomTlM7e--fE4)q7PWzLxZ#CeM4*xhWuYtTkb~<`h zlzM})(NFv4hm-7`>+V?5@9VE<(cJ(&gSdBbS`#r=(J0@EyW$$ki1W!ukx$N9KgO)m z!3Xd;!0+c9n_ts(U_SQTtKU?{xyb(d3C6hKGz_S(`9%4v2h=y@BgZmtUO6!KcR#X| zoFpH~PW}C~{X~sjts(oC1^KQ$)KQ;j2i4ysGE^MkWUEgJcrBd}%#Yx)H^%Ip%;RKDZYyvUr|`KSE$^dZT( zS-zfe^Htj4SLQro+eepFI$H1c&|c%m|Lxe!3eL*0=lnU*Lu_2x4W!;e4F_@k#`0qfz48#ZH!N?PXyZ_)4x;CwY9W+jrUc= zh~oIO_uIZO2CLoqTlT~AQ#)%OFN@WG9s6--nX^QF0+#T;K>Ow36o2KH-||0Tl>P!e z0!CzInR6NS#0#}^_p_Fp){kdlz@qg6x=lkIe=&T~Oigt(*npGFP@f!bDE91(Ox ze60H)IJq@E7QL4F^OiEFN;v74`nVeTtDhRzn{7X%{{zmZhnR``k?RG0^M|2$*$WYZ7O{iXE(hBD{fv7SHa)2zAe2Ivm`ul8-oOzoGKIe%As=*n-u znD$x^;Wy3>pIGMHYJGOmah&EMF+hU-(|4x*G_x?TcWJ?+v$JX-ep^gP0@~`a2vmm z$?w6s^c1CDv3SuZ_uLnH)VYs5ouR8j7iFuH*v(JF%YM{4^-XQww{2MO7PZ%CjtI0i z!6Vo2aMG{d49){@K$Hql)s$cDD5KZ~($sYO;WgcQ4t)5U2IIr;}?pkNL!DCTgtPxPmKrub8s zI&T`~jGan&Hk!Nc6=&!=e!A;_Zlhk$7So!B_gcew=R5J|kaxa(TZnfF#sX;4c-zju z+W76G)0y)pYW#R@GssN(Rn556m|8(QrR8UFCTT;QyVF^-&(vBZj2<(O%v4)0>Y*>X z1J4xArax!Do`06q*JqD!ejM!Tx43%@Jgz;5e;48p=-k2WmXC2@$}d0K^6_=c$1pm( z{Cn)ltinDnD04!T9|GQX`XwJo=Y=#E>-$0RRPi18MEdrpt7^I38L%6T&gop#dpU~Vmn*jxI-k zJs)^f>W{$E7(Exh8GffQNm}vkTgP~O?#mmiHA|SsHgLYGuFScDa^c&*|5?L0jZb&a z`zQa{=71JJR*`i?JmU{J!6C@3qA(-sr4gD&K8KlJ@!+T3!ne_1)(&DkstT)1! z_PNjpZxm}0eX27L9*7@)y_PxC-Tlf0chDQVR!~{sc>47t?Fr1CqgUYq*0t=h>FhHxflk9WzS$Mx)1zO{9Ah@b4>4oC86KOoxU~v#!uTmhx4;b3mi{IE$CH%`dR8Tm$>(XZF@fMtX{d#5iGx60N8%L zdfKpeztpe4=GSqj^o|4T=fjmf;jDrSTQD1+1ODy%93QsI6+7NHq_#I5nzz*-FM8Kp zrl)@{`@cOCztFwZ!IX4F-<^iwO0q5?Zs;9CSH8`nP-j0kke?z!+LOKkQ~0!Y4IJW)C2y`SOnsC3 zngjFqEkDs_=z(pTKef%19aA4_bl1O{Q$DB-v}%t`KEfFI7-!tR&fbdbqt3l+{*b?d z{p!}4DaBWb&2%TtfqqXHevdomvA^*0=A*$ao1}R|Fx6HtS}yVZAMadSQhG%jonP0U zTawuG6{Fnv6?@yGQY*-F<0{l?1g>Hrg14Reepv(h+;yRR0S~4>?;p6&KDVFNvXA}%0% zzJETpeC>+)eD&bS2WeVOjF>pPU|){S~c6 z=&bDjLB#U%V^A&Uh|i=5$ATD<1a2Q_rU!%~=Rf2Q+Sylxd8wV%{#% zx(hytkIO6%!#3ul-$)lsZy#ZdE1T$PK0imhauK{$_$uNlwt9~Gy@|CcccH)E!CF`8 zUumt{yX+3}(daz(vBZKUL(10Ym+4G)HSulqO=XYfl@%w8m&lKOu)y<=7ceZM5YJrvCr^>^g^+<5Pz2xHi?a`B&@36O$ zXS^ZMD&19IWY4~jzu^1XlA-)+t=F^%Z_?43#0sk$f*OBXn+I>6$G5(h!>7=(#M-L7 zai?<@@hX#xPe*sjS0BTS|M+yq=kilKR+G-suQ+*M;vBff=>9s4&q?$%4EzG%NOmRG zmyNKO)J|KCxrXD)oQ<4syN0&X-zwsPSA#E&{EE$}9sh7;SCl%Ie9_fjW?DL<9xSooEe#GJ^#amKRI9e`xid{O*}d?$(kk(z7W1u9C>MNBOdv(*+4u; zyxPy7aG7&0{1IJmDdu0m+58Z{bw)bO8Q6SSvPr791sKu;(S2YX{Ylp@y7Xwip}uHJ zYn>&U9FHc!sjzhE+?vh<%U&AY5r)lzhE|;)z0J}ZCLWzeo*LKRCC~MPp<^zwOTl%| zOikeX@;vy4?}55p9pJYgn{}p@eI?p&V9GiNUZ*Dbqbf#JT zyvOb5sMKAyzXz^2J^$SIUG_h9#wPC!&SUuBqSqt>trr8w_0y4k9eoO$WOqDha>=!Q zPJFP*MgGil82*paoa=C(N7-koeI9LciB8JPsNchL`2QpB&Euo4uK)k{%!EbO5wakl znF)}YM6FR0Aa%(kpmnJ_LR?z=F*Cth3tfhS8pN7Opmj-Y4WPEcelr2BX1ch68tX?U zL0enw#{z2Y>P!H&(pnK0f=a&6*Lz7O5x=&dKYqVI<}vU0UCurCoO91T_uO;u8<~2v zpEIsjY_0sI8mnt{ewaSo=CO24L_GLSKWh}$Xj`e5FIjYA0IWIA0I!s%?j_l}9(*T~ z1)o7Xyu-uIdJplgGK+bhVLvY*e+@iqXN=cF(*<^V9shpHMaUPul?RMga4}(M9jw>_ z#S<_dCYkylIgtLZzw2ap<|;L1i8zed8OHk5(uh}fiPoPwTQ!Dx?1`%*=J`{NyVR11 z_hQntwr5T>?m^k{;g;D0A%j?YPJ zSTC72&B#&{mo3!006f%Ifpt-JB-?Gm=_(YR& z#{Or);ZfR*^UFu(Mej%X*4P}z#XHdALuk{#%IH(xZ}CHDOry-Qg; zpK5R~IM3Xp)Vtc#>d%RHN$u=3U)CJh>#rclC6)ug(Rg!izb#K^x#@@bhDXd&;CM z<2(H!$qDlf<#hj$@^uf6J11nW8Rf%DpNU<0SM^FC>)^~f{%0B&8K-fdOpdYaX7qaM z(ulW;Z=54rJKeQvBfb#%tp)zVg-7Aj;XmDObea1J?N%JM?~;hupzMw0_mh|25b8?H ze@Z+0UV1|F#VT-MpCwgGS@6-iIK7R#!N7L|<4*ENJLTeA{{~>FuFqH&!akAz(^q7a zzr#2bya=|N>;%_wz#VmdXVHO@a6+=mzI=K)_VAcg8#e0L$aBWD2TnKEzs3J-$)6Sk7I7KBdjDh%)NQ2I=s}CyYvdd{-MLM~keFv*8;fOrha4+WW zLCL3+=cEgd*|e!Ks5Fhke^7QCGO_UmzAt3xo1NBLZUO0%#ZVP}MouNO?whT8A^Q9d zw9&aB#^K5;=q&o1@64Bq|JOY=p;E>gd^Adp&AOXHyfw!lX$Nh&FgQo0zA{!<8Vyq? znPYLBYZ)?Eo0^2pmpCE(4!A@ZJIB%|vn=Py2g-U~%ewKWrtnRji>#}hcy@^2BxJ<} z-g*~rUe@pgQfcTMx2=AKLT0}7N@P1-KfLP`U7(dbt2 ze~x^;Yg|8Q_lL1ip|lw9l2cP(FrLrTSR%a@+fH=dM*D>~7|ULo6Y(C!w@h_jTC$s( z9r22mu5@*!WcD8SBJLeBY7O46WgarnD=GBlMq=Sytk*Ptx%0Foj=XNvJ$LAh516Cl z*UxU4$5=f8u8#uqo1z{1j`4C);bq3Mv$-eD|N9cJ@9fCDs9|`0H~U%){1lg*67k-F zUpF$?Mr(E(f_*dXR08{pz|72N+?PeXm(ySIR_{LE<2F5fV>ly7TKuGlcOhvy1FCm} z_e!VErOa!xt?)A|Z?>IYL)n*3jCd!r4$Ia}%*Q+S5GVCn^0&Gt?|bxwi1+VWdyTrF zb2s{{7yYF<`!&j(Oc~8RcOH)%e>2p#T;m!&w;Ua*^x4vx7mn}LdQmz}`m~pPN1sN< z^tAc0?I%Cy-f&>lc;XxLlGALMeX^e@`)DxYjR2SRyeTt{hHCP?k|WZYPg)vA8Y>&e;1lFM1B`>nX`wO2x=)w1zbH+*4&29!|7e2 zE}daq&Ain7WJ&n&slbw*KwGkl^NlGjUD%fR0*L3){AILkS9{2QqdRZk^0jxg$zIX? z>0=EZ*O)~1^`6i<=%w@pzPaIjjgj9nA70hp?AlO-{n`s1_gp8RlDnnR$l15RH~&xs zylc>%vTxk9U1hlU1(}!eyKGl^gEZBlOsfZ2*tI)q3{Q*7*8xNRqdhzq`aCa2;;s#n z1L<$sPQo+2DAb3{tj&x)zY{&!CmYLypHa39@qh)g$GZ7{fj)~4jnDy{%;&Ga%$<_x z@-2+l>sgD5PYwLv!Jffq;iKlyG;uxBJqgwsHIJ6Wx|c9NKT=XwKzNt?nuNj*0)M?Eq`3_ptdIX>-nmh*z?%Z?H*sA36T<_hxLK)=ivITVzbM&WC6m zkEj0;o!v0?ueDzCeV+BpNTbhJ%RlQS-$nduy>ub}td~N{FS7rOjXvW%-dQJU&6K{P z-@Bs6RjGB7aXsm*gLcygleXAC5qtm%_)-6}lCo-@PrJXQEJgmGvdiEHu*<}vlnLEe zQuY}6JF?5LE>)SDpOu80DC7G{N!c&R*P3g%e^+Y=W4slUpfekaAyR+wp=@@OuJy)o z)V-$ORq6CSq`uPk$oW>^d~5jE+ON^-Q{)`}MU%7n7ftjIO_aXk6#k)$Sw=Jgr=jO8 zo;3Y)T6?|wPQCodt@@5yFMH!!e{{I{9uNMwSu?dhB8KW`72X8$Eu0hZ%-L&n$uC(L z>bsl%Xg;~crjN7d41H?r=Y1yDG?H<%sU&t4`3Yd}K~BsVZ`$*BR@i&#md{UZNRA!` zW;bgj&B@wFQ#?wVaU8ST@NvFNXA&QA-kEE4_E3BhuW7qna@~p}u9;F2s~*i- zti2>QpLcW~s>ztdZ=vZoGw(HU_T8;>Hu5VkvSDgIUr)TX_*-+<@n!NIcaMc0KQ4)# z#Lf{)Zj0ud&)MZ0v-U;Z-z@QF_||D+LrH9=+6K258PgHQTL?M2mi}tbPS4AER{k>c zpKn-E&Y}z7Lv!>5-^&~-XOEk{8R>UJ@h|W;dp$ZESlA|;{{l^=mkWu{$d6m=#sbQB z?Wy-FE?wV~@OjVy+gz=R-+OUB^Fg*eMCG5I9qM}@ z{l*>1`wDz_v1TMT-t0#~auWY)+u+=e>`SK|wUG^9uy=jX|5)`8E6nel--rK7JoSCh zUvBVCH3K*rQxVx3$jW=H5kAm9C_2DEmqfw8jW{g%*LQD{uWKqYm6wz}cieGgS)#?yPrxcecghM+AOMq`h`vo3^RlPKp=|wKKd8;i7h;YX{p|q`PZqKY)#E(o`@Q z+sM-vr;YbWv)af_9^hGic+1x~B`LkqhJJO*?#n9sI?wCKbIym3rJnOFpO@luB}+$< z?t}LlyRu)Tdxg`>)K@<7)Q>s7V<&E1x_mHp-PrsU+6md?Kjo<-rpLOoQasfe9QlYZ zmu&O=CE67q*Eqbh$Lp`1cYC~Ux8D=?c=aC&n&b6)(t8dCW7UP=+*}g7ly||s_W646 z8rl&5P5O}bd)_4<5zd9g8BacJ{BHD2wy%2@>%Z>r4D#d(2M-&s4(Hv*>t6fa!7KW% zg%<${>)r1KV^JUT!naFeC-d&$A>AarIKx;VT=Rch@6~;UqVuKMIP<>A!I|&!imwUm zX!-o(MdliQP73_%(S2*klYd@&W=gBcN>g9`je~tEar$8Q>1)or-KUuS?)0hqO{-6Z zq}Tr|80+BMjEQSYVjs$firyFAr`mY$RG)Z%!t76W9E^3Il)Ieqiw?#rX+DrIO8Yx6 zfcFcGc~=%b(TBCR&Q1P~euK}JjVnrG9YNavR!QtHx`%*qJ`&lK45hGzG7nniyD1MT zwrh{ZVEy_L>uk-F(t9C%t{o3p^s4YV z!>$*Bwx{YD8(7cdRiCm=*srqTgqv)R5Mx;R5%k0e(y+hH`POZYE6yh|4wztaL-39H zx$9l#2=(oG@Yc8q@$S@rmo(Ln*m`Hb-c7wTIr%2f8o%;UYYaPM)rpJxHnde7ig@%= zk$Fen@eQ3p@?8MK5{ngS8|DsiVHO+O^I1o>*q zu_?9{uomO}U!+sE^@rf9abQqCS3Z35UMJ7g6Ffh`vt+#kJT*rLj!7KX?~! zGG7#(EndmLv57XT?X=x?nT|h}nPpz#-6`X;)Ba?a8Kv=yK1N>3bx%Qpv9Yln+p7S3 z`?8Yop7B;J>NTX}bKky+bAqC+{J0v6*Ok+kleFK+yh6mo6*`KWz771^rl0KUNRx$C-9N66mEK8y0g@c?x|9ZMLNO zH)(TGNttUJcIkyB;U8137n;e3YuyJxJS1@RUUS>cWkfc)fVNGpe*?|O1e9UAY& zPoO(ev|g>SdEL=+l6M9DQMz=g@1Ol!G?%EZV-Kjj##4s7v)CY8=;wT&_Bh)4?ucw~ z+24-7k!_&3%L9uny&s~U^pRx`Jl@%e{4YTM_iS}lO2)JIMRG{j`BEQtqja+o*WRFY zm%qk<_Bw8%58{u5TQ2^sU(yEa>V^7#mF$*jv?m?hdx6ED$WcZG?X}JzU-xlXb5}v~ z=cifoM_l8GF~eA>ZFEoDr?DhB>NnqJcueCcTBC84o7|^)0C`bbQ;nr}UR4@;8Xw)l zE_CG&r{de=JZd4nRKc1u*81+HWOp@Xbtj=>G1B-&gmW(RPooEoh8u>+>Oo}n7;u=v zUixRVzGNCeKdDk7q@Mxv0;kZdg z%DAWsIgl^hm{NVc_J8=Gk9pTh({-{%@{$K8RzJLsdXj4cT_D-xBC5?ZNJFmrg!^`I zHt++feS^FV?XPy{ZP$0(wfCzzQuRIqZgJXHTuOwtbe>b+Ty@3Q?DQKc?$NU3@_zDs zGgEDpnWHlL&e03Br9S+bwls%|{%TKpQsX_F*9R8;+VJ@S)3<9(6FZGZKyo>{D^!Tm}4p|$Hb;IFk$E<30IS%~laCiK$tkAZ2~ zAGygF&bRbN3fp@R`)a1%*d!Uzn8{7H+HaBmWn;+fZwGaK@cvx-CK(99e?MzWhwt;~ z*J%1Idi|cdxzyF!Fws?hMYtUHzhSW*x=V?rE&96y7T9$i-=PzkH+EL%xzZpFE#Y^^)ctY$wKI zZt`HR_=PQPpK~zR-m66aXOD26c`*J_Hto;3E6-f_VpBx^aof&lbKODX*8AVCB2FX4 z_^&w{-(-w6)zKxfn<%Sxu>*I=2P)b){v-Ej`JIS$weQbSe5H76#e7-!K&<_gwtB~x zgrh516Hh3KeQj7>e%U$M8&+C%NCU)Oy~Tg_u=>qhkbn3C8< z!`f26oVfE4vD7P`FuI(6S~iMB!*c9Xwe_V>X{%^dNw~X}xp!1aY|h8qDs}rrJ7V9} z)+A5mkhYw-yM=XLL-AfCy>mmK(%wc-N!Yapn<}RyHg#Bg`VN)k$BY{#);@9;ex?iX z6MPnXk^Q1stcU$K7#kuB*%R=2UaTKIV#DGZdl{}N-w#+!o^`e&C)s$ophPmI z*r?$#(CKsQ%rgz@cf#YHD}Aqc7vt0V|3NTZ{XP2sVKDY5?j9T}v${W)^`E`pqA{)b z_XvIDD%!EqN!RQg#3_4i=zJfC^@KTQWb;Jq?{U;@3VK}=utg3AWB*P5AM7&e!To|Q z^?kuIKV?Gi2VCueee7jE}$~S)2=$n-Neg^A#_@S~Nv4$R-owv~F8a~yRI-06~S zcWa*B2+s0HOJ6wOMQYv<^hW*Yhqr<;{0_uwhWfN8s(mhZ&Vo)qyw7~a=u#|+WL)`f z^0ZEKcyKK;7`XsBgdRQkPIc#qK@8EgwhV3=>E7_t7-Bw=yF!n#Z{tzO9D8njr@Tw= z8T6Fu?t@s9>GVbY@ZS(xx0m_U(G^Ow=B3=^ zNaQPJ_jfNoVZ|h6XhSs6yrFX;7i7suO(QZ}0nH8SzFqhnbOne9)wWEw3 zT%^nWx6_i_8B3YPp{^$K64;WNZP=2;iKwqrgeNo<&9;nmwdh+dk&$Qf4Fk?>gQM{E zDvml^mWpl(daEZhKK>Sr{e#%5U95>4M;Z^wKI?!VP4Hjs z>R-0(I^^aK=B+rmD;BECn7nWH?d#gsVI#!pr=#ndDCcKyTmEaO%yP!k5z1_DI?I|< zopFB}w3B{w-cufY*0xUm8#oI8Y(3y!O&_MSwtqPo`z84f-F@gq(cZyH`X*wwWyMMt z+3gJKK;1)U+ehYo@DdVog?sFWv ze^R*waBFr2y?(w=lzu)KTPZrgvlYP2y&-qQ`uA?!6`y46Sb?nS{d+b{LpI1I)>z#H zjQSVQm#5;R`&}@0HD#jB=kN`(+~oShHM=wy^^S)A@J92O;z@d`Lug}56uq(d2@~(u z84X2`>&{BGZOvP`8_K0$&>zwlYX585?VmB&e)Eo?w}ZH~)Ng{Zv(-NBsD0^eKQLT5 zu9j|a(7T)YQTdRs#Sh$Xk^WQKy*LYY)NPGH(PtxcafP7IuY$3YDN`?bfJP?04fj}w z=8}8O(KXDOq_x(&M|b*jjH9DHMwj+%8sS|l|B;=SepT(yO|03u-tF3OCp3=2XXyj+ z?pER=Bo~r}tAUv=PPK(b7;{gw@e7IejQ=S8S06-AlLyZQ%c{>rzPf|4QIw4!57N^{ zL*b&0z>D|zT8bKc4b!svna#tE&jn*ms=qZDdtbDIH_~BI_#>HfT|MXVm$)BCGD-iA zmMm(YKx01r{%5>rU>{R%$7Q4$8i%rR?Yra6v1s2H>DYZf_Bm8n`c}Fv#oTWBat8O* zOMo@R#=>S@H_Ea#bXURak}Jk_T61>|wg>Sf8-E@2c3*&g?h3}9Az%F3y@}X2%?11# zYmCZxg|$BPDUJ7+vf!i(Oh4V0`d>lM3(*gc1!Iqpuk;sKgXun`5bOFoIKP@>`VRBV zv$HNE)K$e@;@$AZLB<21HiN z;n&@k-6tLRppBPc(YNyY^Mc`~h1jPL2V>tCPRO{W@2vC4+LKXyqiDRxLkzvi2mEsA zrFP=~HJ9tV5mQg1ZXq@XYjCZTiQ{U0>BB3$(cZd-YVKaGLLZ?wYO9dJcqusHW3NId zxyE55pv$VzNxwr*k?)IK5k}Nia8k4_@h6dphhpwJv9#)4K6dcW$8#CtGJDOSSF?v17hU{X{VK!6;+>i@i~A znxF2ecn|(v_Kz#fd$DD2&iFk0skfDz=VfJUggkuX7CO3o^DEQPCyM|5WZF-;(YrHT zt%bXDDl_<)JY|yQ!T4{ex5bHvv$`$o8uRE*0fq<8uJ*- z@c$$HJdHPw>XaVUd!P9}rZe@2sCRLVyS2XFZQA^X4?51Y*2w;xcvl?yN*>bqoEDEc zr&Dvc?m-JNMx}ddZt!fl@&?xi&58bZZro+ukh8&mgL^}SwMUdS#b(-xur5hsH;G3N z>YcR*G}@y1?+?O*e8nNl&T)IB)3EcwA=2Y+@fGlWl#kg|_4ClZ z+!+wREf~8>`RsGtPJ3FrMcoE__16ADlkQ$armuZI>Xi?}XK+Srg5gaeKT&?NVT(?n zKYGT_Eh@8~tLEANr`i7@`+tG`f42SqdHX+X|JPdo<>dzUWqe^haH}6Qy7XVS+5Ugr z{(sW`Puc%oPo>Ju&oTNoaYn~{9&Pk_mfO$cNWaE@_8NUN#u-+bT+$ot^eL1lmdmWm z8gKr0?PnkHYQ(LX=`)cX`mJXJUW9^%`Hfr`b3}wR;xSA=n4Zg#jp}Ej-glpldOi3~ zS*I^+Vn$nypQ#}p?Shn zXP#G=e@wnH=iJ#qo>OMnzkGL=j<9@a8k?rC1D%lBX6>`E6g)3o*3{;!4JGF zoGd;ukDK3yN-)1`k3K~^+TW{Z-C55b);$kJxliG^gCWxOeNFauD%+X+jhyzjI@YMS zFptz2#`bz-T|8^#pZOyhc>+DU*l4XY{Y&V!uhF*I$H8xH2&S`_XwqR=A06Bx_yU~% z8pIY_cW1bgiWxF}xY%MD>^sr>)Z@`LtF7k>o>xpTurX^o-}!0Odu0uFIqT&}K0N!7 z_(|m2ILQASh8T=7fM;hXo!#5_L<(zzCv5g8Rgt(uRf?xYC~s_B4Z>URWE6-RGRk6qn|A| z@95mc8!HrmaKA6l+3@j@JE{f^QIyD&M_)zr_wcxq~oq zz@kt34gSZ_Fa1MHV;}#M?0@KJzE8FPkF)=atp95m8=|ej{Gu4u3BZpOGY`S9rs6?* zGA6oQhS8<82tPmH40PpWz2ld1jm~<p{EWE|(eKIG zkuHdzzI)wx?r_a%JAJSjW&u8_wL;V%)=LGRLSijGUHxS#u8FNoRd8 zBKN|exmRKCX+mr4n@VDhN_!tMT7%%6IVsfDv?Mw&dK?y0f4_N$WVQ}JJn`s*dkV&P zYJBYB{N0|(o=(a69>#`beUHY6v}5qdO0ur!)D?`(H8oq(9mW#`{uz4^=TX zBa-W;gt~f+tLLP@BEJ&;TW@=t$|@EvWGr8sSw?J&eP>0+E~CAIlz92X39;@IOSFD%BkewBLz;5$aFIpahHqf^ zDUL~gK+0}uUWC8yWZ-{3==~C9(*5l_FNLS+It#yV4XdX;7}e`p7%c0+PV}7@^j@HP z#0$^0>!n7fDz%q^om%+;IANQXX6i!he}&dD@86n6AEg`7&k^i}%R_yQ9=@wGx%yCV zo#}Vo??UGA$K4tU@xI>JABPV3W%qZ?H)=U(&rufQG5E2U(f5+OphfMet>NtyZZ`HC zoR_;FnJm2D*q_!ju;Rqy7sieK3F49_!-K+~QI6-r2a#F+#h1c8#{SW&_q4HpBXKj_ zO}#&YpQSKGJ@(_ZzfoA`+HYVJ6+Yx;q^C*eUh`j&zTSP!!(FVS*SkXxKW6?nKD@>Jzwu$kBdvFT`(b@U zb-nwBhacd7v-`5S>)qEqoJYLXI^*En>MGf8lS|FDX_0YsW-03w?9JJ!*)6xxALSol zpXIY}eS2*b+Xx%8PrjK1&uRPle*^0q)Mp+py%n5(!SfdE_?vicc3-o$$-U~~I%J*@ zyf(=IF+e*w>%ISK_#`=~W=(sy$F<>;oAtE0+P(5&+0>f5HyQKhECRwzr8AiKan|6zA z+9_YO`y#Yk;f{A54eZVQi+&Ex{xcXB&CpfAv1k@CZd|MVXX%KD(YW?ruNiN)FG9>_ z!?^jo?lt05BgVJEd*0j#I%Dy{>(^>by@TIvn-QD4*l2wC9Z&A|8fbbibu=an_su(- zZVauZ{H;na^oI6}7m^X}OZgtGJ5-Hqtf!0{+g&kurcZ80PV4Spj_=&N58DvG&F){G z->LGwq^Dfm31qmp>x}2#efVvWu_$;<=Wg-yjp;2njqPrGEoW5AO`cKPea5Km{q$#) z_olXXbVizQXL8PRNnB%^eLjP8g?Dq7^2^v^ce9`OKO>CR6~>B(PXdqm!Qh-3L1V5b zc=nvd#x-lxi_ts4nqYjt?NoETT>HP0{jb~dD%$_tragN^Th<@CX6@GlL2n$n9Yue{ z2hn39KjzGZ|8sPE+p)A;@xL2yD>X(~UvbvL+Pl&?N%OwmeeJ_)FT1UOV$(4%56ISk zGPWDC`uDiqKkka%teDF;uOo(t`GB~HQe!gbes;5e%=?Jbh{>B~wC?@0(e+E-NAm8j z3RQZFg5FUxLX~Ow-aDJQn6s?zQ$v-#$1@M_=6Np9GmI|xZ2qV5e-i(b`9GfjvHa67 zS0Ger$(7O7jeo13m?QPqq3b_^{pNMVPe2!EEQJ_v>~EO5EQ&7E*;dKfWP3a+U*mBq z<1u3P*F`+1rOQOu1o7RYyrIg~#|Fzr8ljcKW5l>nrP|LK9jas&uS|QGf7SLkjlMsD zQ%P3){|UXX%%b-_Hoa%E?;SrFTFY8&M-}td&FDKuV{6lhp!Y<+?X9_}J=ePPB%KrV zj&Hc~pm5ph;?7Oxlhsp#G2twH9ULFB={7`8O#DNA*8%VUHLs@8lbVl1%r(-d!{u$f zHyFO^-+{qgs5x0M&ZPViWp}rybA>HQK;%;kb};wRuF zc>e@1?X?W=`_D%Q`E=dK({CHa-tH07ryn8hcMk=;+NT;0dpzkZqCb`{d`^5Y;FTU8 zUPpQ7KM?Rb_EOw^?c3F)osiq!CY_YQZj;SdYQ)<%8GMY+S!Ft|gR{s^o5>$~bnNY`Q{Y%o_=GuypP#uIc-p<*o_MwZ2e%r`~U7F5T|G zyRFbQdjBo%IjB|_hVW0_IizSjjgTdo;OFew~e;pRC*@090k5Vca3X#o;m9>?%jFQGcnojnXqp( zu`}x9soayC7?G+JO*XkgmFkPySqu-<=3@A;*cfx`2D?3dtK&7+T>adI)WP1$^G6x2 zl8tuH#C;{atIfZE*uUj9>i+V>ev?)X?yET`CHObnuwL^VmHZ3v3P+6I-+}HC-^4SE zcJ2+}zU2dKhymJ3&j7cpbYxcP4!%K zLabvY>+shC-jm5cKzZ$}rlEuI)g6Q`Vpi1l7ifFF4a0|Qvv%}0T- zADIsw4uta?ttUcGkI04DGi>;YKrBkx)Q5qxhbXt* zE}OFbavQ;|N%H+X&pS|}De?hYMFv+j`3)ww4U8)2Vx3OcQ}k^X6H z%)EN>yqv3N%v(&KbPiDc=p|irsLL@Pit{|<>iT(}tBdA2`8CLj?x5LCyN$@N%G4W1 zrC{jXh+y=4M(@}wA0sqSxuSOhURQ{-rV|Sfrtv%eH{WeeaQ`|q>`S3v4Ieo3uRZz< z`5~j~CEuig@+%{TZ_Zl!=7B#UBRJ=4@ci(o>Vvdl`g7A>tDM2T3ufEf#_kX=9Ql5o za^gpN^--w;k2$(!Xbn_Bc;Z&mW_hmebR#$LL$# zD)+BhCD=nr}|;#eXS%gRQaD$5{r(U2Xk8t#O?GXCSsoo{p#7Eihqif9fCf@yuDKd;VwB}S9OO9QoqMx-7 z=1$&6U(jz$)n8}M+W2}PoMApqy&i}u4#$eepUj*+s1x!>b5GfPVsl5)*HPF$%=Nt6 ze)uOl7XeT5ZN{b0p1Ds%TuKY@wxYwc+p9UTq^yZ??|Ur}zMA}Ie#%dyBNMDA63l(Q zuc7~>M_vtt>&Rc3U1p?Jrsp+u8D-LY0^v)@$4@fA$CMqvT~r(JW+=nF7(QS5hl{-p z9~FBQ!yuUy&#&ZL4!RFYbn{`S6?j5j%fX|7v+|eQFcsS-{Mu{gn(=eJwCNfHj7%Ur zmoiFUjoiG#9Z4Fm(~xo9m-O_cMTcbDC>ggaLhr( z_-D1l`#?K(Oz+<*FF1qnbq(bh84E*T+Wpn{ zOOMpwyewF5VEN^@|7{@rT^qkbVyz{=pVaTWvfyU-yWdV1pX#AswfyeS2EsAY+mUbK zXu=)1Q++5s<#TiJ&4%mnO>j3tN7r2V^GqQ8ManyN%OB_yXCW48d@;9I#G#4Pk0a6M zD!VNo@+=v^*X+nxdGqg~$pYxxLmwyyeLG#qaMaB|G8RFu9oop|^RW)M<|yl1d(yKP ze5^0l_hBBj)76*W-vwg2U(?tc2nR?P9xsE3xzDb-lXuy(k}3LB>)2+epbMr@ZmaT0 zSN?B#x5i{%vXtj+y)8M@Pj-+8dttueX_*O~3Js5W2d>hY8yDUTEbJfiuI@bn_G&yi zrK+cSez9W5`27pm;*oTw=56uQkz;FL+On4>*!@h|HgE5<%uU=Ql=w{`_78kI@M-4( zYy^ED3tH4hua7iDDQnoa%MhNK=gzG2L4$j|%x8iFE^1?o_IHuBjP%d10{WB|H zcJ)T`UEDDce~EPiX`NxLRQ_Q6fD`|v_#|r&U$Mtp zXXsq7?!Q=NdE&j|It9~BJ!5n`SeBgw={PJ z%DTyyUt=!o;Kg>nbio|>K>b)o^*6JIBrjysEkb$XcsD10Sw@w zt@%D|zo%(yYt3wv?>&zNydB(~lX@r+JCXbY_;@wnpN&nhz%JkDHpfAEGigOnvgW5e z_Eo_QzH#&#|67DNaGGYsce2-BaLosj2d$6tlYZ#0v9}c%S`SFqu3x*ZO>GIcb?`WZ zuSPz+pq(a}*@#^tnK6DIh`G05>oQM`AYXFwG;Ih+Jv%b<25Dx@6Kz^;7bN?#^x4Ko z0%c9Jkl$n=b^u?3$~ff}3#)Uyj-241DaTIVnOYKUXxAPK_nvZw_Js+SLgF(IE*qw@nev|gIbwl%gfpGK$^v}J4*mLB)nw2lz&_jNc^6v@6 zo;Go}#=&pFS#tO%yFB=rx}yHRKv{-)(+5qZE99$Fd&-xtsJV|Z_?ban!57yCbj7co zw$T;2)Zb>mr>X1cilUz&1Jw5=0@+T}i#+ zI;Jj5cB1rY%gBNj$xj^l*{C~np?i$oT<#t_1|CHJ9@M%#0 ztYhvy75r`s#Kx1Kt$$|P<%j5>A2JV7{$u(FI43R?wPb@{S#5t}%kT2QOISZB1vm=K`(p#GU?eSXCdmHoH8PI1K&Q$o2FadnvLu5Wb20<;)XrLqBt^hTkdM-y|FG1=$4HX9jklY(K~D%U-|S zZnqy*8S?RuWpeA?>~Zq4?$vE{ovz_@nkEc^PZA?@cSpS9bsfsWn9 zw0}z=Ttk^J4JntKe9A7@yAJ(Nx%kb2FwV5Qj8&F?zl45YXxFi5ZP|Vse}F9!p#L`o z!Y7cgekG8fX8IDL&T5|3H}y$(-EcN`|L(imr{b$z5<#xu%?|BVsjuRT`f7c9W!pf1 z4PZJv$+pFhAJT`($=e)S{{%lY<22G72#=zSzNaqPa(E{jP`vB87k>lgd`*GyNBFIp zIL9Ozsm6a1(KGm~?I<>1GruasZTVN}Pn7S_Yd@hG-gWTP9c2e>8FQ1adfB$VaT@-} zHLi>N{8wFRoo6)ShIvnl`ex>HZ%PsQ#ELJw8rt}5eoIE*0%w&m{$gAt8FggAsb|8a z-ruQb-aDV;vhHBXHI}7sveq&_)>C-KCTM4^Q#6c}|a8PeTV{7lNMppWZ&jEizp|6`Yvtg4(rxhC!~tYY73Bm6G<8vI_v_z4HX4U}Cwto(1V znWEgKs`B?!e&g4$K`C!s$ox-P>AvXo*EGc4c`X^*XtwJMuL$XdA9|Kazfmt%{T=W> zKM=lxGRliDshGzdYpv+|fvV^8(=uDWkk>JqRx+yWnTh z8rMbI2dlf%o=@WFV)D%SMrDwjPnvIRf7s;V^G*GL?P1@I!M=!fUy_mh+z@>8lDF9S z_FRSC{}^(8CgYznrw=JNImvzcX20sM!j__3Vgdet$|U9v+8$+g9m!d{?RRoBW-^rb z&1d|RkFRg%rX_pkMcg?p#2%D4xpTHx5eFY7trweP4Kh~69;sp->kQYD4)z}m_DyAX zL=59o?GDYC6Ncd)c5tu9zIp*W<%~f1jf0vmQ#KxOZVrnFaJRMpACe6tM>C#^PIB(&V2c@-HtPUv@e4G+p_U; zY^2wa?|Fgn=Kru?R{%rurujrVc57A}k+)x&=jhn_FG9P&BOm2~@CM36$ur>Pz`O&U z?0Kj1X~wJQp?T-0Hav}G(dGfhX7;?(Th0F1KIG$+K=?btJwG&0^G-E*ebT(+qTM+C z#*ecF987zOGnXsb4=UHUnB3TYO^jcI@B2t!`i*ApdS@)aTXe!opIyh`J^{_w&13nN zJbGNR;{p!zYI)U@#*?~*^%by>ix{0iWt@I$-Cg;s)Z1^UFaZM7coUuu;(fielZ zt@g8w2DR~IRvX_R*2W{WA)jvaVypgi>O-r|uF;{D^rxaQ$5`1>YxN^98+Ne;``#?r z*A0Vxw+*`kJuUp@uglnd&Co^>^hQ5dh{oDumwZT%W$V2ItE_#uS+-nc?+f-Ge|)T( zec<$k0k2!KzjwUfqZh?T8kO{^G<)98w&nULFI*+p&ic5%`1n{i z_X72cx-f%oO&Nx2SRDh2CT)>+mAD>03 z`2K6)MQ`*jiUS)TsoFatY{C8A5#aXvj*t1LLEi-dZ_>oqf{E;x#-x!be(qvWebl`wi#OZ z6+09eOjfVo}z&krM-Dw}XR2 z8!H~oGjM)bF*+IMW!a{k^ntm0-<7Ow%=wf4wzF?28aJ=Kv+bjIE&a+K19~ryIzxSg zI)|FwKi!Yw#Gu@2_eXRe(B0UriepKACgA-F`N$>nip4{x-VH~nx3Qww8)YxqI5FV; zg6c6h4X^i&Bh>4iUF>br9dySByyvMNI{b9mNz4_)>tAuC`X^H#e`%;B;60Um>CrvV zg7MWdy#578s((_kx0-#_P$1wv-md>R^(AM8AG($eiMg<2I8HkPoQ)?!w`1x5tbq3z z8%{59w3cCH(sllGs39n0RyW`Z$WQp{`p_^URtH)#;} z#JFYuhM1=spLwUK>TaZ-aN38={6H|g#{PF$f1qzmhku`9P=61`C%p}B!^d>}Oz1Qd z`I;8+K2QGN`H9vVLrvUK7vVesc9P|LITk+}Wg}Aq-lr+YxGt4^I68~{BG_%xlRD3! zc}D9!r6)+&`xkiE+}{U{^nRxDxf?MKjU7Bi8^JJXWXsTaV!`8Cy7HC7gZcp2TdElI z5#lp_d{5O)+sv_CEy;JV?YIl!D<6p3mY#?W!*?omR7QPvVzol71BBz7%)yQ=PVk#` zk2m-lUSr3t8hd=JQ#w@k`Ch*1sWuYurq|qK=8QLGUm;zvhQ|zafT#3T(>UTFy-jU@ z1P{kfG0$qF@1^%YpdH~ro2_5xS-7UK=bbgdukChS^y?;mmQJ6XRNS`sq_*#*p0#hK zc_iDHDj$(`m!q@3ztEPC_AFi3^X$oGnTwE*Q33A>s!& z4)$2y>B`|Q2g-@I*>O;MSNxgqlRO9(dT6`)2+jI{Iq6#TB5R*Y<*lVJd~>u?^i|#a zscY#SkNJ%P{K@7SJ>_jBFTwkfXs&qcI_{;@_?CPu;$5|Lw}X;d>cjo!{?NaM$1m<#Xis+Ipg!(c{1x1?5KkX^54%- z{1X2(2fl2|i)Bwcv>i(sjU%naMZ@8JGFH}k>-lMplPnta%ab5>y8mReU&8At+BbC- z^S{1h=dxu=y33sZ?e~N;|99B)KlR)jXT|)oz50s1t-Sx#hGkGUaZR09?NM(_(Feuh zYRVZ0i@i5dMtyYVvFM6A#S-^L>8Jj6|IqKz8y(BD(uq-1`m3b(eyh$aTTXU*&1l_y zRQM9|T2Pdo&V4>gpM<>DFUu;=-9bt}k@QV5@I!|D{3L6Ofw>r%i@DP)LYW9l4avmvZ^$0TzkqB=CM2g3#>FN4$Du{~os+%n6KgIvQ-guW*arfkh9Pb9Q=ujvaIEIbzJYW#e+k!?4(M&frpy`>`iZ=uC6>1n22a@8!;k z-MVjryC(K>&%~?TCGpx^-V2DSFZ6a!#qT{*m#Q+ftX~+E>HaZ({zghkm*z zRr|q;4UBT{Pa|VXG@M||TpIZlofFWw`C9zltT&A70%iLSpaUi@=zu5Z=-mQ5}deG9_(%;u22Z}p$;<>P4mfgYlM-FPSMV8&k z9=VVE67bzDyY{S7Z{*v7aK3S8+X}|{wam|Vt_gTK>yqn#>tyVryks-|lN`H@fHyJ0 zsEB@OrQeX1p5_}E{`al)Ywh$*e{tAHdgjkoddyDu11B<$@;3Y>b~>~!kLR0rUQQBj zjPY7%UCtej%lv$MVSm0}%S3@Vwr%pW8)zGE;Wvk6aHtZDNDPD64 zcTYpN=I?VC5cTA%yklW#W%_91*hy#JFwa9gI>DIq${1tWv+VV3@ywf>a8IAq^KP-e z|FYEgZgJS{ZEj1rr%lrPHr`3|-t%5@*yCMI`cyMLL0XP?O`8kc)Ry+WUKwe9kGu(9 zDouCB9z{Pk;xDTHpx9f(U7zxEAvdL&53PC?lu_Ac=#t&X%+x^mGxW1*uhq|E9GU~i zc)P!REO0dL{)Nx2AZ+Z|t?_~#(m}r96$1Btc{?l68c@+Oep&$*r;zRWkNlMO>Qn`E`)U~xEyJja&tafVttq#T*Pnmu~y37x}X z-eT>K&PGRczhCTqU;38%p3mOAP-jCMeML(T<>{OE8A( za=gp@q!n>rmY+UOr2lo}f~E}B`GU(N`*q$arcYXBqVE@nM^Z-5)$mGm*K;?|FRN|A z0gsQsUC$kqKg9D4o^^+;zYl&>NAIpf#oq1I(YJx5W6ZN_=;k>g>8bpr8Iwh9)=I|E zaoS5@PvS*vL5;1cyiei%s*#*+W$xoZI(sJoP`|rAHLa3_-9L+k5|KD}aqkN<$RT(EvFR|p{yb%A9F^o0-_khQ4>a*T$ zjUvyI8^y&3>E9nYKZ35(I*0SW`N<~oEg5ySW}ubID!#5BSUqMLzGd=`m97|kjo0WN z>%E!x2sm4?3X=ZPfJt|KlPHt6+Lc|Rvm#dl?=|pxmDsbrwCmuPdD|-YP0E?_Mm$`f z8HeQD;XZgDxnnoY!A{aVc>-fW{HdouQ4>yHa{U>`qV+|_MVA9Fj{Ov$keX_o#@Z8~ zKYQOTuMjty!gtVfR_O7L{pv?vGE7;?f}XSOA-_8iJ_k9_{@YA^@Xe+@lT+%at@)BE zWd1vE6?^^Y_D%mP_ST`}>W%NTRq?+`>HKCGtJ|vg7l-Fkeg-g*y_Ma(&sP2KF_!?V zjAxA}*<`Y>oO!bQ?P6~UxFy`&Esl>)XK}bo)EuibNN+DP_WK#D!bf9G^^dj7XDaOS zA**~rR(X|0KZTvOg4b?ebB*gQrE^!ljmuHgldg!)wsi%4R(%iYTb=gbwAxplkCk`^)ro9lbH7Bu7tF4Y${sP6tOMlngFnUoG`5n~X+!OM;h3_+zG3f^n9r_W2SJ1!B z*dduLf9W+{HOIqhRt#w9J z@l!!#hr#y?@=n7Zf~S7s)cnlR8XsE!NROHEbHqJJ4xip{*$LUcgrYL+q;IiC#dp_1 ze&dpghP~8XGbXfh^(5wA#&+|B(8><_rSYtO>0Ib_c0W2^D-N$PaUJTH_Cq(_$!&06 zWiZEe`8`h^i@k-%9Dz;Uo1j!1gQs1S{RFJChg? z!Q&3_Cg8zG?-Z4Zd6r?H)KiUG(o4Dv4ENrXG4RkgPvtg z;1HqAm6Vq}I^{GD{5EXaOWk^h?}F*r;zhuaEohcS2DH|`%5L||z|_8l;C1XP4rjNW zOTC$V>(0?f)o(Jtk|ufd|BL?e?8uU0MkGrw@-KPv-yW)zoQo$e_8%(ZceME#|NZFV zxO;Moe^MZtz&M^HL(n}NL3w;Zq6)`b4LlfDt9WBM)imTJ}nz6w*Vgp6d9~z^Iix+RY?e~{> zZ>|YdQl_E_nyAbUyG*rR=6AgNd6vzl{NL~%KbNuiKiG@V`hM(=%uU5!-`SCQ(B131 z+1FyQChC5p*eiL6ZacxWX`}E%^3X)O;5fQsi`ge@oEDwUeSSJm0(~{!{xI$&?+jmP zWj=hK$vAfbqm%aUfQQkp;xKn!?lN^6@OmcQ)wYqm#Dw{~njW`xot>_@_+IAOJB-Wb z)*#Opb01m@uHEK7_~fKxcXw|r4&Nf)FlV`t>+kX$fUoeU za@G`d+jMjr<5qf&aqYcPeOvWpryIFYfBg7+()dRDcN>*?Z-Eof9gIKGV>vh+SoO5I zK9a0u>np{&OUBC4L%I0kjB&<}pI}!BW;<}i^C3EE9I-UdvsZLfpzH>n9feU_{__MU9o8TW)L8;t6VHYs`!ot=rHG z8GhBkl3q~y?%rbWl~d8_{GUp?WKZeR9dpe#t+8AG{g4^&n0dH3d@?kXebJ0npes+J^ zg166xg>D^y^~w=o{pk~6nffhj@8<6xaL;{*1^a~~;Q8zkU~d}+yXkKho{Beht+rrw z1ItC9)!%OVZT9mBupaybSnMqnsLuW5XNyjbys3}ENxJVL z`X?PH{U-UA?R7DDt>&Hujk{{TN#Q?@xIpw>5c$*dJ=mH}4bg)g_-C}I)%{oIf97|| zo9l1Z7~jDAi^!DZJoD2*TjdVg)BK#RlQMS~dw)QB^yXskZ6-ceY@xI6k&NUWDE2;z zujD1p6RGZ&8lzS5Tpi6<%&RhdOQqkHUP+n<{MBdwpEcfclMUdaJS-e@??m(Ra6Whc zq&WNy+OA$>)wzTDW{F+z6zZ{--&aqpSN)P}=DA+6=0UApW!LC#7r`G#xjfp|bHM-} zd8PiBtn!yo_HUFef`-wju-CC4Si98LEwJWL*Gt9T^TDC%_Tun){LkWkvYFgXHX}!O z1%)cBUo7^XY0}5yS2g9uFY!%0I|KMl@J;O#V>3wq_CfkrP~ZP;O9!4}mbZAJ_#n+Q zHM_83R$2Nyz7w5{jVpKom9=#mXI!9XZt@?e}={Ta^THC=DPJXYl{uyBwsuY0AH zUZC_Vtn}ZK4vd2S)vg`-zFH9bG=NSoMz;^|^XuIA8pMWueLnx#v#+1Ze;NPWJr~5z zeVu#fg4naKbLU);dEoVF{4*!K&Yg2X=7-n0bI#9Pk-^^e{|&SjL z_IWlf_ff8Cp@pyZ@f=xhx?_-*y@&7%eaq_KD`t6%mN!#Ao(xqsF=r>_Z$gK6{7-Q> z1g~B8I$)Q|+w^>j@}lPtMbEd4{oT;B`4`-~{dH?BJ*%=0Tev(zS;>%ZwD!xa@1tw( zO3!e$&OruT+z+n(O6^}>%6r4!e(zhX)y2byfiFFq;M=Y1&noub!FYNRU#{~0i#)!G zVveNxxYa#nA7>K}vF@+U1n_w`L>jn*)s$=h zZ=nr%{Sf@sMg%yr^GBNh2In6ON*SkSOoz%P+*PJ;SFu$puXZKdJA?-Hhv5MlqI*&Sb~xcCU`aK(QMmh1B;vma)(UWm_BZ8$!C?KfnXpJkVC zy3{H^|5M5z`__i|TSqCO1dmoa<{JUj2-w9le9o@8Kc|%nKxn+G2#dqO@*7fkV z2YIf$hcg_k)sSuUXiieT3-LmB$YgxoqU&w&h%uK`dK2@+Z1YYpSF*9Uu)(oK#XI@x z4E8ZJuecQ>$y_L$xSMX}9@=U*TuY?(?M=fDc_6PmkO0WadoZu~%6kTX8G$%XhZh z78@hBOO_1aN{$2rS*;aMeC)|e-iU#y3{f{ET#!M@dyg%5s^{TMvFf@gQx&)7af9|0 zlWnG@hNk%&rcSCNmRa#Es;6^Vl6S>yNjD=C<>uWH?Dys!fKIwcg6DhQw&Z&+@-10N znDRX$i9R;@p7x9|{r}>*AN+gxA^)WZY#l1!qGUHR$zWYfOo5*B_3W$-KUwDS$D3_z z1ZK5KoA|=N4#3S#K0g5W)5lMq4a<#Q?yzAg*4!D7innAe9$_5(cjxfFyD4kQ_=u$T zo+bYqf!l4vRjj!MH!n%--$36FF&?Cw=zr^S_KH7F1J;nhi2^5GX!M2nch<@6Hq2ug zC*qgZt^@HvTZyUp0Wp#MANmJtN69PW3je=(UK~BQ55*kjeYNn=;@ z&2X9gudFt72ajY@W3j_-V`5etF2S|O<6+AFyW?>|7Vh0PT*ZGoV`!gX9dQi(vUBhJ zL4Lo>bK-l)pjPXPqfJZUwsj+?_`ZJnX{QYC>N(4N6)9x zogL_B@lI!__QJo^lG*btJ2E@g!}>1Dk?1#`dd`>@42OPxdtTW((9gW&L*zU3`-PtW zO?~zb{!vp`(64G6Zs!2p+~kGx0K zSa?!1uW*t0vI@K{dQC|xevAEdWVRr=M9-7-oS*!Po{{BdV9Wkalp3uU?UUYPziFBk zr>gV!2Nn(TW%zu5AGkX-^V>496k_ zI_n$JUv}Q(z>%$YqYbx4y4&XKY~Wh=R~X4D9^*X2lQ*_W^v*F(p2?jmK78)RbmAhg zRVKif$>?Lr_@mfG;+qd$y`1|+d#4ujEyKyld(h4D@6AWI>s|C+kM2DM8%WRNMC($` ztNF>_17nY=g9|=^&QEsk&Cz>m}l3kA(ZN zz;JM%%Cm!e0nd^jH++f0FU<$fW#Rr5`O;ZY(|?hd#6NIXlr^aIukJ4sPaOYM_8k$! z^)L4j543rRXSJ#J)UNEI2kbUo`1&RPvj4YcwdI`muYezqA=GoCt5Ap2q=odVTUV`&ep2f#z^trQ!j@W&QrpnAU z^o?)8qk7SCTJjs}TeF_0CS`x5`8K*_H*$%wGJ2Wj^C`*Glu{>7Y^>^+QQk#)#fNtP$%0u# zK6cr@CinDHqzn1J#nh%h&GJqs-A@}nd>*{henGN;G~pCyjjDH@M{{w%YE!H@HesGE|wDj*N(wUpOOuot%Q;fmV`JErE zT7b@V)>vKG66m%W26u~C_k>zJw&v&0!4HS83wU<;D*wO3*E4LMiGT9{J3OApv%_QE z!J|1yvf6FS>KoX=;=9(F;-6xIGn@2$O!6Sl>Dk;Bj%>oU&&hyze&zqhT&-0T% zr;f$*{Ny8)cX;mKZo#~leDOSL^L)0kZffSYv%Kx3J3QyziB3ljki%>gFYHS6z4>wRzrDYT1mAPfC0~JVSfXPCSXFH=Xr_qw}A~KkD%7 zIi4LI`Wv1d-u;Sa@u{2nt={I{DtIS;W=@x1p&+>!{1VvVM(Bq-eMaJK=@zYHExlTh zTmwI`*(sZ!yi9!omL>c7$^TMcSks_)6&JnI@VYK4Jk3~kHa?(kytBji92?IvDz!%~ zU9R}B5dRvd5&lQvzLF6ZkXx(tGQJGKKOy^19hHY=B z`>3nftLR*-y!>P;A0l0CMQ2&%XW8kIfwpp!C29+}1LMy8e!8m&lZmMY`&TqO+d(m=&+RB>0N};nee>wM8{yXy*{{MkC&&_Jn;!}KKKQ@Kj|Ra>>`XtLU&@2?r+ILmYvEjO;jDVdgY)M9C7d03aNeB<=bb~qdC?#^ zSLDH2nFr^kd2p6nI3>G=o;P`LF8dHT!}yDJ=K_A-efa)rXRf?x<;80Q=l_EFb31#E zi{-;x5IA4@<>JCY>D*%^{j!KVC@xm{3Sw+oLoGswT}PbJMUFFV(dc725A75WTl}>% ze=+*lvH1KZ7A!vDOx@$qo#*>QpK#XTjki8*UH^4UAI+^7S-Q0{M(Pe;*W%YQ=USsVPT@;UaP8fYI~w=027euM1QQV*_x@)+Zt%4035 zGieUbeq4}8L(gW_TFtj-eBDzF{d}9{XrBFfZw$}=7#d}1EP9XRSz{ohf3lxK)Q|r==W@uCUj7#KaytXfP4FW0hvV;)pFFu+c1v;k zLh2-_6Qhpoy!?7!_31^rIb^i^P zK26vzEf)9BTigR?-OV?rfyMB_obMP|e+~9WT$|Tc&bD>tptj_<{-3nfnAa9EZRYmM zL2b!z{lT`pIcva{^KA76mdBEVI-Y$w_%hGFtjw`}=FbZwZJ*veTb3qvW|KdE{hqak zH_w))iU+XDT*Uw@wUbdHIuyUIHY)@glq$I*uFk4oUP zQw$xxTod1$zhCFY!v)e)V%|Q4@TnT%`TV3`6a(=JvKD`<{LH{v=j^WUDnCjA;JEbFw5K&nz`U2G_ZMv#e+6mi^p0i0<4#{j z?0CzcPj$u5rM4__vaDfCSSPWb`E{kcq(8lw^iq=^xTDhDfIh#7Jk0|dw;#U#7~0Od z6TF3+WcH3cdbIV^qa;0n_JbA9(b8KfehZ+7u|-Fm2F%6jS>y{B>7_9Gqlz_@(m!p} zrF$lj-tv1-C!J~2=CyxdRpwBo8l7uFTr}{p*Y{3Z5t9a{^_m4Wh zN9WQ!xC80WiYNSX-2I?)mHGESgut772gxDm<0#5_DtRR6TU85|vKC*heZD4W<5OXB>T|7Oo6r7Oq@2 zwscO|oiJxvFfb~h7;?_G==t}OgKB5gfRFNn`!nzK`^$%=-{M&?H(|p`repkm2_BwZ z!TBcWEW1K*-vIvj=6D`#!+Ca&&g2ZXbDpPtU-vxAv#)!e=GoUhPx0*Qo0p|0Jk!|7t3WleD%G{xU$+35~ThGO5-I-|c_kCFAoQ!WH4Xsyx+K;xxwtt6nV#P6?AuCC9o^o61hw#5XmYn@JWHeBf zoc%KY$xLFleE#7$>t_9@z)Sy$#B9ZFDbA?#hDulb?0FU66gFN6e`Id8bQ$qTq;;Zu z62>3t#U~vkjtANd#4644Xzj%Tcy_4n;K^d2YTTZcN9XC5&PqQ+W!TTwv-U-@_!{** zNzW&8&kw$hq+QRvgug$4kHN?tbbHH;-;%UBpUeE#((LKp-vKYMdbTLOmLPgrzMOj2 zJlgwSPRw7o>aq?Gu>Tz=Hn1MwuI!gE?*TnS3-D{!UYWUHAR1`aUYX)$lF%ZympPPw z$>67WUNc^E9C!X5?_BBG6h5ErnuB;zjm6XtJlgc&w-$cF^&Osl-TfBN{@DA6$`FgF zGOzROkHc4$ewx$UgpJc;Y4dZ@rpD3+SRXL7DK&Q$;^Vlo^Sh!=Njd>-m=`+Mq@C%S zuacZYSNbZO9&*^1AYFPVP8mZpk%cQ#;PjtmRlMd*bk{1!RQzei8_bED=^lmGRBe7-k7 zJu|3GmD-?;DQnwNxqAndtN)O4cMK}m`61<62bIfxNVyval?%X+q2T+`pmO04DYte| zxvCE-w`x$i`VT4BIH+9bhm`x;pmOzviLpcBv0zZST*1)gW)CU{zXsa7)Z@SS)&~zi z`ypkkMDsyq&-#$E^+S|Z%!w~wUhJ@US4}Pctt90+D{^#@y?M=L8(EwAW9SRy2e6yu z6Oun@?8}UCbXdO6B*Zr+g3^iTx~^f)6vam<_FcN{yLOMJkMXTN+Wh-dB0sO3)VV#m zD|1t&`vUnZemKvS{mK~ajWf5jG%dte!QHRS^H!7n@%v#dEluyu}b zrfBRZcz%-gqS}AV;+7v%)%Dkkn%twwUD=J5?k~s}&0exF%(S>@PRs4_=9|Bhmg0=S zufRj|il<+S(v|SS)Ah`$=-^lBQ}}AFn%%>oaEZ&_sCF#-q{4Pm9W!o2S&p|`kQhzXM`82b85!eJ9W?$%rPJv(S zv0rEV&Z1xA@DM%QvEwI|<{N~e=E|By$_Lf~JNLJ3bG~$;+gfv>D?g%mpnAGDC2`<1 zHxB=VQ=@G+#Mzi)?oGMJf7f0s_oHpK@AO9uE@zmoh}J0mYou4Nj5Y>F!P_5K*39Hx z?YDmMLRWp6`&k_Pytbb&`|a9(e(Jy5er~q!en0igy?(wxdT>Rwv6FsMKd7wvDDUbg z^0|S263-3bbC%z(?PrbuZu_~`zWe=zmwNr2PWq0e(Z=Lx==8nHnxlAEKMkK9=qHo) z`cZn<*#qg0rKjkhKX&!*%e=m)(Ekk;&ev(Y=^imR557L`Khj-t58J!My5MW_m)L^X z4*R;8!;ynNIoeI<5?VGAN zyZwiVH N0*HaHUB>&{_?8Z!W42OG<;!39VvZFH`cKkJ=r8fjcl!Hs_>Pv&F1<^h z7kgT2)_3D&m-0RF6nU2;HyYc>OaC2Y59d6cDmzbkhPU><1hYP|_sz&x=YLZ~yj2{- zyUU1Ofet;4gI>O6c7Ql)o&EWI9`90iEHtgItf~44W8s?0#*@gewq<7IeMh`{P35F| z$~dbl8_UU`Zp-Y+yH~8?+b1<9DU-dbvayu>@)6FP7d0(Blp5jG9y`K$>LBu}7+rmn zd-GR{Zpz`m)7m&x;N6vU3j5yIe!1u-(MY_^0eAN_$9$7C2`##bf$->8Mt(v1YSISi zS(aYO`&A=2W6ODpEd>+yjfC!AzWOOmZ@Q-Frb{XFK(LHEm=yy&f%Ng|Zywgpg!I>V z-@-RfUPY$%Qm-4oqE}wuO)N>@YUa8r#C?xjH-ossHp*Q=o1%3G|G$LK{k&4#$+B5( zIs-Kjli;1V(-<`C0rZ#j)dAtFzM-jfhkrL^Q)6XKfV&<;ODh{Q&N($Ex#s@SHXICMVpClS2o^GzP_EMdNU#ecW+%Rc*_GV^6gI{ayGe%Va=j!!d>=^o0(m5o>Mj=r8v zKlnI`bqCJ+2zGjNFep~qM;OEBx2rtD{>)tT&0lz@+T`!5Rcbapl{u)(t zg4Ut`>VB^Ld0~o$OLE}LZg3H@TZ~WPtCf?ECSUWy0nG>cRyE(KMn})~zf*lc{s4We znt36|ypUpE2o9PTLd**e^MZUS((T5tkqNB}fdlktFGHsqf1T@`|6h#5Wy}Mz6{b@* z-ryXqxnTl)6HjBDC6TP(mhIbg&sh2ewtMiM`mh;z^1h+{f1R(sjC@J|yusX523(!; z)i4e?vp;be`r>o+ud~Wcz}b0)=a>2nX`%NQxUvUi8|wUlc%`#D31rgTO>BHiCF!w} zLu`NnIrQ!!lkZFT{)x7HebIk*f*VUZLyZ6PD<|Dfe&)~u6K|_Nf`z&R&s&3Rw{>I4 zqVE0;S{}2WnIcRInnRcWza+g$2lCG&_FE`Ggu)F=apLaoGvR_L#ql zJ&1nWqiZ|ouCOCw1+iYf0nZ-DG2BI&*wsy)uB!rk58ksuv+!diFsK~gjNi4Faw;SF z9nKwx8LOva|LnV0vi3vpy5LaX)-3HGHWwWh1F7?@-nYnPH;4{rp5@ttRe5yv=a_~Q zp*=b_#h5;x{4?{)UBFD*IcTpjmoaN@Vg>N2rMQP@ zuJyg`To$d-{3P6#jlFg=wA!b+LU*$1ek)IxmvHw$V%L|bBR(aDIqg5)yTCnoE%#6H zF8b~LWT3gbVBEwIbkdphzA@!JBar8pG^atM7RvZGdlH*ZXKJN0G)^4u;oQr=>UzAu z_NOhiqc+UClQuGe9%x)-V3|zaBjAhd8o?$%VhmY2mGrmymrP9L+1uYQNuS8Ge}286 zFNgW{A2hbP@k0R1o;?F&*SFUq6Hb_v({~Z-Dr+7j|MC|W=zeu*z#aPUB86%3Q_Vx6^4Bp9({qTLvEOPYs48fX$aJ!=|^etc`g0$#q_Ln(kyVc8Kao z9xl3j;UU418?j}4J!A1{>M%CxYv7EK-ZKRYO?l269LgY*-ORg%tlPqCPjefL{wzm- zdh0Hgjl-t`S9ARk>D)~-RC<6h7aF2`0J;s89^}r@*r4(=z=@cnL-b!89QVO|!4){^ zgY7x26?KkLXF@5{AzY-_0^r!(!@#(#75{WEh2b51 zV}Hfyw)pU#t+CG|Z)Hxe{A!6H_g>L{5Iw0eD0@zJkz%eijxxwg0$I9*vRX?^h9bbx zL|X0^&3z?l!LG6=?#YvH%MXX3(+fV~*`Z z={qb;l9h(BO`AoNYRU>u$*OoQS@Go7k9B#lO*EJVAAH}Rc!J)p6)hAS@(y*Y!9T)2 zmgeH+z%E_c^P&g4uT%B}1O0YS*QfDaeFi-kt8{l$Za+HYhCt8O{fxWGz%IQ|0qh~> zmK1Y}V4VZ3MZl`{p3x=H&9~Y7aVFd(*NoX(Z+;J$Z!YJKs=7PII1Zqv>Y@3Ov@O1< z-75a2^L#&{Sv%T!n0cLX>wSa8<9i@|B=~9EW@!`Vn)Rs0-Sxxyb_03ho8W(&xlZZQ zZTT{lA9s@Zh}u8=j(5eV^*~dHu^7QeseKUnZ_0o(3p}lsuG{nM$c8g3-Q;}6>=~8r z8uH`t{(aV%vK?-)@GVT;9oay>)&j3|f%Z}xRy`)H+m9Ob0zTT3~sg`Fx{(B6mWqD z2@JBihoWI?w6Z3=1Uss{(v=Jdrl!#YFv*rUy&qnucnW&0nDKi#ym*H3A=(zhGj#Sk zhj@%~zHt?xPw{FD={oDEbB@xpD}a;zqJEpF6WLxNo|0EU*%WP*XUkU#@3`h0Gp`{t z*4HSWAHv4fJW>l>fCkn z{>zCU_S1E@%G;Y3xSv5EO4cvfxWLuf9N(YS0?eLWZ0?#hHl_TRC;R|?ciw4kFEC}0 zb%!-d$}hVpVEnfAUp&nfO^40Z9IIF=Z*7wzO}|Uf+~yQgrE+E(sw!C$(Cljx=Q&^)8+uKrL2vM)50}* zgks%F4R2MR@rAED*1PGt1?+z~?Qx!&tC>$r)6x@?i4=X#%^QDOr!KJXDdRgDm#%j! z;m>b&jUv6z!mwiP;V^`cI?d4AvqJ}9*iQK@{U+!?)3m_wIg5_0C(YLbIqae&?=AeB z^yC7!g|Qn!9+=;IBMY?7=Km7@NAlmu|7iX%;@{86Z;QCq4)>^UM)B1P z%)L+7uUz1!g3ypTIJbj2ZR{m%QN33t9Xrar%*rY%{vP=ib|G9yFOE*}T)fJG`r$$}6T!_C(bUks6hm zPno7e6_dh~u$|tmaL?r3Z`a>1bMyF+1dg!dttlcrS7Re+U9$6%1@0nrf1Kw{JW^k=A>fu3H>WO2G6?(sE_oC%Kl-H{sg zwZ!zr*hk0jL3gLn-PvDm86V?5`pJtHxCz?O_zqD|w%7ju$Xn0go7cTFDe0UyD%`+4 z#=?J9xKC1M>j{iK=HLcm0n|o}`l74m<>P@(_#Fejdu)593m3Rq+R0Fs_BtZ}sF);s zIQDvl`v7H>9=OrNL9i(PN^1gS2cL%g7`i`R{vvEXY#Mw?8|5?cb-u>BSr^zl2^QLQ zhFJ^otpPJXQ{I`6zePNU_wwCoj_zS^=^glg(AxB}OEdHvsPJ$TJhHcA@ELy!aCmzR z-+~_=&cH>S*?jQ5p>_f5eyzKh&%vnxJsIEkF|*hG5^cnf=-H}tf3E17$(`q~eaz_T z_-u_=Z=7W4Q{}TG;XOVc`J3)P6kG56HkFqe)^qO+`b^N?2xxA6q%QZ|vKCg_0p?@* zuEr>jdr370!^9BZ4XhZF#{cvP{L^^!=E3o4^`p5cW%;>1I3E4A@X$o;F_qm5{vI!m z`9N94uWzC4PQEvxHbl4G!Je&xg}tAHoFwdCwpQT z&*&O6_g7+X48zV~{wdZS&OYz``ChSj{`qLNp|VQL6fAsZ=I1@WEP}q*GKLl{M&5{j zlfEe6zl$?cz1%CF{G8Pn_)S9O1$nQwzK_;(c^>EKn`%8HAJRSXbG$lnWF|QaJ&A9_ z`5CmPukcyk*wQ?pvE=(O5@*{wz~a=fH%vR|;@N^V_Zd&eB^f7G_PL&NVRW5f^5>*m z=u3C83a3TF$?89y_fk78Gre|9-BUzM&b(LWrGZO+d*VTW`~ zdGKmn1i=YgXm*I7@b54C1+S0Pj6B?89&UoipF=f|Joo&7p7DM9O<#_>oqu3m@kE7t zFZroY**<|IaHgjl{5e5z$In`T?La#Cw&44WBTIipmuRf&ISc*tpTTbFMYpaAdiKFs z@HxWjd8e;$s&wlYc~6vr7c>kxGoDF|iS@otoy6E!?`!%WAM5=a|0?@3|J;pb?F1)+u(4+EINTbf8RpXN9|* z{DWWk(d@r~$Fx7(aoP4@>Avh}r}lfc-aQfLsSx~1H7&fa+$mdP39xbw)5gERh)j>~LW!4&_Pr>~oKRy2n1LI3}@ z!u=BY-^ec$@yaypte8|qnbboS?%8TDzsw0O@IExpsG_^$VF=$*F2f5kT`R{0C)fB7=B zw(NjEKh?T~b_dp$o-ZV3zg4HXLb89Fl~K*li+L7bQs_dpeLL?7^k%JKzbLIZJJt8cLsd6xc*a4mv1BbI>@oOsco&()aOC?DqF(4bBw!hY=6kG|TcGuqR?(MI~iXRAB$<_sek>P$D{q|nG`gOEQ!?ApP$?n|Mv>_2jmU# z!S~5}@e$(n7F!p5`{M$;UL;=S8tUI#;a*Mt{+;v*?IQfd<2CFx$bP!uJ@}8$RlecL zhs-?FA1n6O_}+}28(?2DXyP#nr0+eK0Ca09qW~S4fu;X zxyMfahlBV!(S7?KBfhCYWk}P$;@kXwjgKe}%v<@%rg$3v!AAV0Ds!&Q6MPwP^x{Xx zrIX0S)wWR#PKEKR4QyX(DT_9Lr`6v95pADOod)n21`*9ZU?0}wc5B{uT zQs>j?-;EXSp}+b*zf$98kbe0I`o)~TKtBFNn=rjN%kvXFhdv!~55RYgvk*L50-Zct zv^2e#XZl>n7%@K0qrlVXS7<7^xsG>=<*)pReOg1doS<# z_^OQV{s~ze%^5~;+zSrUW%)REZLFBo@+^L)A6B@X{Wx;YU9t|2U&+JqdfHUm3oM=l zqnY<3fIqvo!o44Sg-7ZLr~Nc=6z;M!PvJQQz9k0VlJsu&^hJwQPhWcnyi}V}%E-?3 zb=q;jQuP&`uP91?hrAg4FL%5%5PyFG`sMj1Q|QE|i$x#r4#f`Wp?+B(tek=GQt8i( zO_+PHMYms(UtjB;S!|^33~dXB&N-Dem+)Q;oU&o%(>t85Md`WV?90v>R(5_g1YINF zub7m3f%Q{Ug}bDmuAYxdbk$vfzU<7PO=C|ZJ7@8{9C#9(4~ZR=?ZZ9Kifgg+mUj-y zo42HMwHET@X*7P-mv}6FmbI~4t+!V;CcEJ0>I(N9@)Z+z53)8e5AM8eGP+$pVeu?8 zOk=w&{afhl&q)vP%srRuM5jf-qj8i#w{O&4YLxZ(R+_FsR%x64Ud6v@ja-^OAA0A` z5xwy%AI8hlw9a80Ibkh-mWBN=eV3?kb1xyED=XY%4D7^!oLyNHq#cc)5b=#__Zy-S ze9p&duuZG)OG&QL*=E1_0Pn)j_g_m6t|ZMHr^V@7+VsX4-;Xfo*L_=3J__wAd9e-J z*Ap*C1D{|Q{e2s*^{NWDejo5(R^h(-EaTMTm_Oe%olxl}DU)riaI=&-#Bb0z?Wj&y z*0fM2b7_V9Ecud$z%db5{+T$uMCWb`Yh04vxwxX{0@5?k^bmZFOHY#C$C~|k(!0S~ zYh*LVS*w2)oVA`uCv`02Ou-7uPldN}zGa|ql!O(>K=}i-F^2lyIMrAyO*ioFyw}&E zvI$@avF0cO4nsHEzJN19(6v85%bv#j_&gNfs^@ok*1a93JmcbA%4gs0>v)|sbRoWa z|C>MFK0y9{m3#-Hy=-~eMJhjqzQxnuLTA}jJ}-~(^*eV4UyhBV?+(QIwubPdT&?IM z9G^i}J^U0yTaum#elc_>`1RB9kCYiqLvvRTG;}Ci4-GZOOTi@t?!vPZJVhJXIeLGH zci9Ji*-?~bt<&!7^c3*_85;aA@i%d3!vC5<_&;vtE^G0>T(-Q$zlyyAAO9N$;r|-% zgYp025cvP`Jx_*GdH6rW*$wOngMSiyC7a8j<7(9RPsf>jyIlDbcqi7(=ya_C1eat} z>xnGsd$8kz#F8oPXn2$YPwhu(e8;=k7hD-w+Npf{o=hDFeXKgyayNwZf0Xh*Y`RP0 zLgog}x|?zT-X6-6Z}fHlH~PFWF8-(=Pk-Nst_`N;3uGZTG4yKK#J$Q#Si;$(L!8S} zEV}Udr+maGJG~Fkw!ww8`*_w|)u(keGLVE{SD5*}Ed2s`K8y28W_CD4(wVVw~E6Z}l$%y%F8?n0k8e|+y5@I#g+tch(1 z;fvRIji0b-A#7{;)}OTR=!hwzSIhHZ<8!};^y>czHzw#u?I9nXdvJLxZTR)sr*cfY@jrd8A| zn&$VXxb4z(h3&7#Z{PN}!GE{?ZL;rve=WPc{>~=7`sr|EU>^8QuW+Nh`~6i+si=ug z@%!`e8)^HS;{r{FqGqu7U!Moqz-bocT-IM(O zJp5j_Ho!Q)ecPY-AfEdCTWH_?{#yRv^*4s}>OaCi;dgq4yN~gj7!hmBju_5&fAt;B zvUFkuaY7?Tw0Slw_ig{VZ_|ts&c|m>sQLuD!T5)(k)1F<$yfpFUw_RzZq%`3d*Q?Q zqny)^Ehs;I9%X(eIV)i7AK^?1|22#rIVQc0@h00UhP->W^D*h;NdsP^Pjv5$bYL7G z_66*Tr0kf^+5S6-F;U+^tr=ueaW^U}umr^SFtF)~UIjJkS#*oock_tT5+i9H#1|MIQ}uWU8eDo=IX zo!GpMnCah;Ke!LIr!n@_i|9mX{-pUo+_yb&{^Bv?YwRm1d@5U(_|*Fa%oQ7sYN_w-CtSb^mg$r>TbS8y_auMzr?qwU*=oXukbDEAoFH-L1A;Zz70LIpt+lUk8aM_ zcJsZQ?xXnslCy1Z*-Xwz1^CUPjMKcgEZBA*vMT?UuQT6gKc4=ZGX?VJ{)TuvXCm?D z&Fb64o%?5{f{C$yT)bl9l6hM4a~|@oaglGgH&s?N zCND$&$5*%~lRx+y-QCw}?OQz2TPKuEybe5Mw=6TVS(IL3=u8}liM{-@_2Fv0<9*ZW z<3se>6~T9Td2&~(w89-je*fCd^i`DZTN7;iTaVXIY&dZP-Zr=A}3jVPbt}Ov@x0a_-X2&0=-*utV@`01rKuDE+0^Uv=>PG3_rfH_+}Nh2KNzP znUXBx%U78Y@&W1W)b5DNk|S(|9k@yVg(af1^3Iccx8Z_V(w zc-X0B-kg}w9FEQMGV3kz$Dc22KgNFLc)nkF0`^p4h1-pd;LN>zCH9pYy3PBB;Vs~a zO*FRa_aDV}3QYV2dVKfF`EHzF7yDTC(8YoFVQ5n@Nwi7q3Ud!t92&(n{$~c79rFA= zHPJdWv1hB=?EYo!%HZ=Ard`cPS>7GR2c5;*cUE9&vY2=!=4@an_TgxK#DilTe zw@&&NFUl_pERCbb|0Wzp2bR)*t8ElL@cH8laJ(w#v+r+gx zd_PG0;~Gn?Z$%qBJD49{in`ZPR_hb9r+`hCy(Q3m>>>0M_-wZAnEeFeFj{X5*W~Wy z&Vuf!yOO*~@bDh?q@`EikuINxPCz%Of}Rgs>!C;R8z?(rOAH~*_|O3{Dy-TQ$5ZtdOe_MLI!tsho;_UE@ruf8(enEN&J z?~76Q^SsBw%ZIt--9CKv4sPRtbEKaC{C9Sq)t!Q}8-hB|=$*A-Z8dto){}~@==ZBk z{I+<_yYTt0a0d7M{UPnO$MH4nrHsRREzFqHp196C>t5F!eBql>=eR&r=VXZDY1Xdn5*15wu|8K+} zI4h4IJL3*#=_`6Z%bAm4PY&6cO-#o`criQ9I{J3zFX5uL1>0Ku5IVC`rL%~E5fk(2 zzkklwHqlvgeD@X3ww*j{?d+f7)_S>nnX~O;?1mYR)B6-Szk?m9GjfW-%1(27Uz*|c z{snmbK8?KlW9sRs8+f1f`V&$2F3LQSSFV4*sUutyrcCztQTI0GGj?|2FMwygVQdtg z9biwnUFWv7Zza1(F{|VGeIGie(7T}`&IvG{x+VvkQ;bu=k}Y(m+`#xsNG~IQKN8J{ zCw3`bNwxz1AhRzv8h>dEWnLg1`t>G=P0#+AZ>(}|H$L9k<`g>TuNfX}<9^De-$h=k zejEM3-ROer41V|yiuDY9>zDKF_bqre?$&|dw@Kf_+Cuk1#EJEhpDnkuYP#$S;nD?f zmsuV%Hl`}=pYXMdb>lea*mVu~y>xa^>yDQNGyB{tEM2q6a-94W{Hp#_bW+vG6 zs5_hdaeY<0pCw)Ss^3bxmptu#gI;M3g(uZ0{ae_^`DMPryI|Ns|7G+~4DXvQoT*Qc zCc2&pUem!zI7kLncBX|tMGWG7ygRHtL#uuc9>ztSrXiO9))b4tjeG{eG>y^Z8!<+wZN8_4a-T$2ne(TyNqh zTf7H9pg-pNb;!1;TUE;b@10TiFXaCtuS~-3_w2YYT2oJ%_^+exAIQ&^&vzZ>mjrZq zxu9%fVR5X@_+D+@`^e7%KRh&Ywc|ndn8#87j;Q;f%8>5Wt7>BpmNlE^0PXDztb_gi z*S*AONpA(#2E6YKU*z5S?IgUIe634OKKeI8IljSX?gS6vPf(ubi#H@&02E*$E9bP8w$sryQ-c%`66{! zhDk@S`)RscgKv|XzBSi$QnntSh(lY_|6%+Ws;he18&sPa-JQ)lbLGTm_fr>G;><;Q z*Lk&UK`5P6S^O^LPVv5O#)sZDPo7Ge=Fa#Dv6T-{R{LxBat^?Uw+i2?`qo@6n^)(h z2KEEIb)1i+C`keZ|qz`&+Nq~FO9k*(gXb@no-41-?Xh(cvT+J5F zBQ3tyk}q79{s!yV<>0z;hjV^$X3Dw)%vZuyb8!HE&p;Ml1!t{YeHyS&S}XiThyMu; zg#TyZ!E%0@i&@jpmW*KMP0SUHn5cQ-Kd`^Vrx1Sdb7*%Ya`M>`&Qz6ExiJ5d?Wb(H z6M2te2WrjY!zI~}ENtlO>+sw7DEa<#hPlaaPyMRBhirRU&TRjV@n&Gc&!D_>;lFfO zwP^Zi1Us=Py$+tSmTOm9Ze6rSY1fg4echg4SNCdeXTEvN=(L50gimhkmhmmn_iy04 zf^nb2zt935WgBD*MiPhV$&c>T!wv>-{5^||56s9(_9*u0MpXAWsV&cYlDvJeo$?;;3_^zlCep^Pjg;#IZjE#Q+_e8KP1!DL z!?$1Z?Uq^CAI5gMls!k*N4?lAik;EEto;4;>^t3tPu1{Q_A)vw3mt-+(2WI6yAuBv zb^ncg$rN_am0vkH&&@@H%~|w%@M_B9>x;3j&wduaEBoOZXW5zfV94)!S7)Jv%>|cu z<>HjnIR1g(ALC#5aXsn3TYG)CeNTD3PlqRX_IeZPJ0^r1>kFH9WfD<$A@7MRqi(K` zv4L$1d`s$)w;2V_blIdKXv};zJqK(C-oyaBhmaAC%lZ7y;uk82O&7dyircG?v(hF#Yye<&ru&g zp)oh2X;*wz)IEj#EcIgr&Xo&CID96zuT1eh%;o!jFWqoyY+EsNa~4?@F2X68hmU+* zt8E_+bQB+w_B{a|bKi|lQrgE!OY!gRx$&)O>>g|{@BA9;LycFBpRd|{rHTx(3;9;n|n#q--PhK#S0W z(nAh;yRm_E|A5+59dG}))O-ilj2~duxpe0$iDo=y|pv>%*ct*Et`Y%I}R@qQlx4$=5I>M3mlIx%GFu#B~2ocSmL zT>5_Fa`e0K7Cqj@w&WbuQ~h?&pH#m%z486N4#A^2E5^USZ~4J^5yf{7#EY1_dY<(3 zQ~ucLTE=}Q+wn!lqwa;|Uy)bFx9_T73%g;;#1}^0TJq&T5R5bU_Gc$D7w0T)=FjuY zoy78Ox8U1OFt#%A+##NK8Mr6FJHfv4>5Ln2#+EKkPknNpiOnpSf(#(1(rcnoiu}M? zk_+NNIU^S$U1LW7%2(T2+Pc{vm&}z)TT4G`r-^^r?!LTDrtXF(=HYwi8}gJ(;2(gO z%}4da!nsQJn^ZSu`{0a?Ih%JJb=7tZ{VrT$7MB#bsr=V@7e93d@m*+>6l}Dec-vd! z1VY}sU{_vfWQ;i`xKDi6J$o(u%Wr-G?a03)xYh3Yyo<)-v);d`cl^f#c5Kr9S9x(uEe|3S)D1iGWjoE$FR+HW=u|guY5W54 zSi8vVSC?D(=>s$RH@l+t9a~ID=6gNKJYl<_a4oC_!ZY#d+$7#vm>)*|4-%l z4D_7h-*i4k`mP0@YVZGA{-uX?Rx~&7R5t^ToZH+g+eLAo%!L!DVx#)n2z#{Dk-d9SkafJVV~f&%VhvcnlDpf`<(dNor}X|~q-(y}S%97ThVvA<%kXr> zJK#WklFDU74`fHrW}eBrH(z#`zRlKml+*hdK7;z&5BeYspEJ=KjXm?+8Lct>z{|fQ zC)$5idT>XyMsZ&TC!Td5jGh~IMr)+6^<4dMwB}7e{gJ4vyR1x^N24|S{O8|AYjhX7 z(j$*WISyx^;gjw{SNe|MM{D-j=cdP_H80rbF8o2-uP}B05G7QguWXi;1IbVD{ZLIn z<9Bb=javTu_wX88a863J_%3u$ej#ekZw~%m9sRko-&+5G4+>Z$@3%t-t!*3r6m_-6 z>-tl)M*F@^PextQL48TajSTmOYU+=`M#|F8AQ&>Y&vVNir#EK*H3l;U?5T3+)w1+F zH;$}e4|QZ(<{8*_)Sn6r=(5SDx{q>yCi2od()Q&repEignAH7Lt$U)4;iJ&sFGStF ze;l~8s&8lDsW7nZpQCRN6mq8@=WDTxlF(KCf8$+eBetN4Z+lT=|KI0>-zv297_oya0U4>l3+r;cw3!H7QjdHf_o4|LmqWqxQ-%iG7HW~jV{l5*}bBDY;utd*a z7@FDpTj8<%YNGA_IkTYCXWD%FDPB%8XZC>6qn)DPeNp5jvFnet2mjL0)WphFfluQ5 z*a+y^z^+q_EERmg(`RvXWsG?94b4_2$7 zPX>z9D}hnt#PEpvZ&2?b^MQOT)wv3#jyDv8QmZlf! zpZ>a{TC=eZT2t6ofGs0xZ!{{Uy^b=h680>jsdg zN2sf@m*M`_uBefF>XxRj?uV%;9kVcf+QOu}Lv$t~ILothWLsu*o|HKvp?DliizMy; ziuOgPgywb1@y(Hr-%7vr_f?#(r!T>vek(1Uimg(6=%(p2P6{q<8Rpa?o71_&V<|RN zZ3bPeIDi~_R&)>3muzo6SMjX5M$h#;3!ZhrAsWY7w{-CzctUZJMd|8(8gZ|J>09@5 zbH}CaKm1E{Y;kP*uz0MeARFr`j8}1oc~N>w9(`m_AC%7nc%A#OWuOiII1?M}&zG|K z{qLGfZj(ppUUl71>!b&NPx*TGrkoYX>mv5;@Bg5@s?L@_9B%V;`R~@|dD*_Ftj&|W z*|T}BCq44>P-Dwk%pdq!FXR0Od3AL*Hjd0HHjug<)pxP?NZAZN)vr@d`Nc=@ourlX zT$Mq8Z!4}Tp0M$n*aq?U`_Mt~iRPkzU`%56DX)7n0N>iXsW19VX5!Q@wDE_}Jxbfq z{TI~t>xQZOm0M4$nTsF(7<_l*X-8`$$y1rTX>$qf3m)n3u#?!foqMKOkk%HWv$}85 zxZ!N~wb;;%8SlH)Md_{B>YIbk6XN0bWVd7c1Ms(b;o`Mct!8 zaQ6*SSM{`(SKXUz-3pT7eZsaW{QdhftG7fNtG*BZ8`=LOe@9-K{(BvN8g=U_li3h;w~+tz z!g=oH{KU@$G}*x~;FPU%t}eSN439EF$BZkj^|VIQx_dnM%Z9Jwy9`Ov%0mTz2|Mte z{l>|0t=*4F|Hsq#8!3aln*AWBuAHI(P1X-6VTo`Zi1-eSO2*wEk+@aEe)fWy+b`q_@x|`X2ciHP}?xLz;`F>x5UF zvpE^~kYm1i16st6^Uo4_cI|ESsj|<(Yn2NWCuYA)IWzB1@azl8?l^uo+p@yF9=>P! z?s<8Ev#l#4%3$IQIW!SCstY>fN$$JF1hEg!Ztj!dEN~0= zpq|G%9(~Xe;X4g}8?$Lc`e?bqi94+=PDSSbnDo*7ucF;9a}L4l_cOL%zs^Wob~yji z9h%QYm!Q(&dv`Z{2iLBhx>HVb4fo;0d(l2*`7WN+L%XHW&hT`!_+OSj&&TN*j}{kO zT7btCpXN#GEwc4O+y!Fn!%q@hNMGU;dmQO;!2D_3R?Ba_w)l{q(XZ%~{`x!|59?3uzeM};kE?!;`W1eC_}m4ZtD&!8QrYJzEB^X2 zdo%t_$<9ss2e&wUzmey@Pddb*mZYa@j-UaM z)2lJbd;56tjCyg}(7OXHS~qXRCg7XOwOM2#zn||9(T~~Nu)*2wFPJog?ykNfqkjf8AF>`(Q{M#4t*;R=y<(GYND z^YB0YL-2nd-<^+tsHd;vAT|~-H}3_OjGgxnpY#2D>mF*WMOOFzFkAuKf^4o~Khye)^)0Zf&+*jp{oqsB z$Gy;hXAH~VU2or0W=+VR-6`Ih&?UX;)KFtm_osX+>i+#P;vI-v_4^ku>wyg)-oA5? zU8gXy%N1Vq`5tA}r}UkFcDSKBT2s}|`tp-e_j&S7%og$fq0y|h&`(ZcVNc=+#w~3o z#_$h*F9U<#9c*BotJV2{2z|((^bU12FPrrqGL|n(n&YI4#Rt()-@wZT=DDxap5#F= z#(BShpFf9XiJwSto)cZQFTgyO>aBCTpluEsi>?JXdh>^5$MY{1r{_x_LiZCT3&8d+ z@kN>=y?KgtA^mCG#SVUWTh9B)0d-$jY!Wow&cEQhV+a~npBb$QKLnpY9(BJ*{s!ok zf<6K0(}GNhZt6R6sLtI)-@20~pDuzmQ{b&P)raB-@PH`vl_r>3-b2rnT zeDa6w2N5Tsy~X|5H@+UwnMlQWYK^aNzr2fGFMskPOC!yv{`$0Ga&%JQan@%iM%@_s z^YY60d-{~A2~#F>Le!l`{`t1dn!IoL1ScV{lu1=a-H(xfjxFObZuTJ8S@uy{(8o=u zL?_i#E?yCJD<}g^dY^x#&dhoGPRts7#%4blnre*3(Cx$R7|lSNL)aIo$vs;W=p4S) zv3mymk5lIq+h3M(8K+K)xvt@4aQh?t4@cdPkk5QUtWsjV_@(_mV5>zrwKtGny)xdj zCm7sk;uMjO9_W0`{?)ttCVOke++=U;ww}hGFwb4x#EjF;uSr2|IU*U;GI$r+#%{Y&YHWA&={d??sBi( zZMIzIuyWVj9a{W}9_2tiS4R?E$HuOu9ZmU!t`3|armyPx#yulCA)Yshjd?|y`G@7cTYhnmC$MhO;(FwuU|#~+s74MH1GEsG-Az10A9DN(cBqkO?94vL`DS<|=V@qz_2IUH zVCalR@Q`m)-4!={9FdO0pA>Sh^!VZ{;qB_X}4`!))_HYCTI zd&`}IeXX36c^MoEkjEvYJqj+5@FU)` zOmgQy579+5i2ytFHEVLomrsLRpozg98VGmpfUR8s?xMM9ExQbxuU2ps(3aL(qHPwq z9N-atF=(WGts?~M*Qom%`HwDM)bqJ-)DHpc>bredeOzb43$-cx%5OJRFm9T3aQv_~ z<3qF=?|BsZo&AkakLYzct>T0Fr>vn>sAmzhN&xE`$pXBRY}^m+apwM^)XQvNG9#OjaY44aj7E`9)`n^JQe+3UL5Tay~MwT$Z8b+ z1+5II4avYOv?m#Og}y$}2K*Y_hGanZ3H<+{|IhIIY$A49I_w$zBhv5UBl~N;NyRh+ zt8aJeKFfhKzkY0(?u02Yc9QQ4)}0cXdv%`T-|%s-L3hX&=(q0?f zH9uo3Fkf!Tn=ga=Ba_0E%f1$I=Tc_RuH|pVjNHHRR^SMywllb5z1Dl0&l4Zv>E#FpIx-aVVZXqU2-vF0Qfki|3TW&S~k460oe<`77$F-zlC1~eOx5`qQn=G->@<~ zpv%Y?Eb6PA^ekm!&?7Fs(w?3bTXpyve_$P9Y+$XY*bkLILif(<+j+&nIhcp7`yy_q zlicOJ7;)cx1m3{6z3>4V)Cvaip&d9f!Qyq^v(vjA{KwM2>^j*U#@7RnmXH<)r$e+O zImkk27%1fag6AXdv*at?y92DOKbC~%)@fhjyhrSvKl7`=p}K8gui}1u zF!^{n=H8PRZGW-}Q^4K=zni*{InI{Eo{hK5dYYmGW#dt?eXVeSHOOT00BZ z8Q8_5T}tNoT5MB9JgoO3?62k<u}NS5X8UsR$LTy>eqUO@t1rI|jic~CXYO9JDva&X zbFc5K+d><{O*9((?U#W0mWp?`mGJ@e%Zl`vlQuH2(`jxpJ`r!c?!b4ZvMF?k#<2Fa zegU7PSI{9QCa;M;JECfU$ft>Rxe$QPPnP3X&5{+_gde|a(ZYOEcYiOk`X zk#FWc>dUWkMWW6fM>~7Ql=p04Y;TD;Zzkch_V1+MlKAzq{W4N&Y_NRZmOJD2)q|79 z!A8!EEaSYAbhM?u3%PM2wNgcJ00|?{+@i;(^c?#O5&~6>(O89>umw73cedn%362G1|>Y2A9{FJD5)@htMF9B`cJ8S=~d zPf*_cd+)vWo$<=&DH&ilod zPg%_=_!QtzN7uFpJ`C`_pKmIVuXOE?C*a-n$d2CGr|31l3etW;ntT#!^M^cZd?*gk z-#Zko^i!OsWM8uG^q%Z$9%cM)O6V?H(xe-{ytvN2;)*&qfjlIThfe-wpC~4^{@}@m zH{8>=ReCH-UIaQR4#D?D3Vy+{L~u|>F)JI9Dcu{V^ovQCzVOGW|9va*5}VOGo5C8# z=eJKw`M$$$RTLH z<1WU;3D`Y%M%a@82VC>xa;S@*VY; zao2}<$sRXnY5BJ7j@!8JxlH|JzFO!0#r7*%G(6AW3%9h9UmLm@nGr1%JLS_vI$JV{ z{XWsyM~Z7OzBAAEll^`_H0UiDp6)q|vzh3>W{Xe0j6`mUxaNCue4pdnOxD^} zU9FLtD!w@v+Y)gvCVx#{nT##7qct+Ao-(1IN8APEUvA56&*MRBYs5`b#<@A-&LO`l zQQoL{^swT*oT4RB?!wdfyb`puL z%@Ox3^3~1*_*o>U>!_zQ)aToJ`TXqK3~tnm-xzT}M*gZ+hrQ5}^vcVeE3bGy(01i` zr}rB9YtUUAzih`oJV`JHV(eSXN3AhF3O`+(7?d+@A2H1>lwn+SBrd3958ddm_6Anm zoimZ2jS+V&WmP6ad-4f1`~umkWe%8A=l=Vv-d#XCx0>WVHM`Djv1yT8BQ-hR9ezI} zO)?ewLY;d(?}unJ^Z7dWWGi2Bo=@UgvSP;P=jz<$ylZ@9*h@^&zs7MgZ!9Ap`~JvW zX39gqJ8fISHBP$ZRk}<0@pJ0jh|Sk{&tGr8&s^=ty`_LpH1Kq-{ib5St>)SEukP^R z%9okQk0NeM4g6UbaUUf=JFCw93OMZtPk-FTNSk4C3URjkS=&xFZ``)7i_~TO z@vnBkTYSscVJUcZIXWiZ8k?R8I@6u$b#8)R+ zsWlOIG5L~{!8$*M+#3DH9)a|mgFco_WTw@*H{1TSFCyCI>;4S1$P{SK_0BnI{?fer z4GTy9nl5sG`J~Qz_RK782`mD>%Omdb zRewZ$C;l~ z8n3jQXh(~jf#$Ld_^Ceh@zA$Sr$HJ>Nme%dgLOa6S(0L{XeAYb2( zxLuvd#mRN9OS@W6sqGN&(*H)kFc#mYjGpspR(&Zt_gm2al8E~h`TO$ASekV$kJQvt zCbcBuK1O~A?P{z_21NrO_c-(oVJnOVSEU;n&7)1o#1x{ZPN;Kxz(;2~kjKMpkwk^j zP17ZlVV*;>fqB06MEYcIT8NJ!LVe=s#_z>{ei8XGm8mrLve9WFlaJn@o*9HB z>rQpayy%4Q0T=>p#$I)%?28j;a4x>0>yKZ(TYDJ^bWM(ZN2Ql9p4x-Y;OLFVJ9FfB zjg$90dEC?1yS%|^Ucx@r!T%FNhD*vwVu;qVd%WGd!^>5TWV^g-{^*rAq zS)#9BT3Tedn;^maE%rUeoTvOn7M8uXZTV@`##-7CjZ^f0gRK+dTzsmi&RuWcQ^<9Q z_djrlWCXeUq?O-%9kXL0@;eUsy&&R_BVTR*-u5N9zc~nxuUR~_53c+My|dS=dJB0D z71z0EP+#=O(D$W2Z2#<=@|@s3+LO5$b?2!3ShIHP_5U4oux~rcp3aV`bH7R(va^(z z#Qu(vcAVP9w(hs9;U)7|NBqb-ced@5d1`8Qbe%hvcfqrPfAQxWOT)?Z?|(PaVLzpi z_bhNpM-+{8dYw^q?w_HF;Q3Er&xcLp!_Eg2U&?s8!^{Wct5$IUr*_8$=-YMZpU*|y z9pq|q_^kwGz3q|Qy*=v^Wd`I|vq|U9bi_}P0)Z;T@ZEMzCnL_rj=N_K!+d5}F zAYL7QAC%UHCPo%}#jFpx4@T=l-FqTGYu}oJwkPOUv`C?krr<}BfB7Ev?XVf}$&{q8 zVEmM^w$L2&3S~8)sGnkMo7N-GGi>~m!ybX)NdTvOls|`7UmopD5luyB@%VYuhWGp| z&yth5#>hw5%&_xniwG9 zs|BBi`Joz}`^e%)b6)ZCf;HHnHtpS){qo$gV$%-Tw8(kP%{J}LA zSfl6ct8>kqAQ(eSJs1zg<;ZsZK!|An!)8oq|!p6i~WF#}$i z{d3(*ZM`^mql@=<^RE9|U{tJp%QxdaLHtkk$ckdEbx%x$JkjMSi+8@=82mKx?kV^` zDdN7q-SfAmRxL9=u@TrmiB*$(blyPc6D6D1KK8B~M9w9{^3A$0(m#Ao4|g`IUI@P| z<9haJbb|cHZ_%da0*z&V&DiisZ1Pt86Q@MnC&^DzFG?M)o8>QyP**bQ8gcLCUG0v74hi~_pXMLHEBILNx2u2T z-t=E!`+j&(-y;U~J!(+j;h@*|{nXnLEN=|o3VxLlca!b=b=HZZ<5uV>AJBdDFa7W` z>F5f0#l9EMp<_>W9ppg#l74&}dM1b9>8~g&nb>UM6n*_Qal>hm#`<5mb^LB3+B z6024io~}nH$5&15(ODLcrzPp`Z9Y$n(kgq?e~L~kdSdJogrLh$S<{GCYiwV8@@(qh zsqnH5`8l5TKl%04^JyuX-$`BZveDM{d3lfjZh5)YzWcmvIe5GolV2mfy65;tA{2Ky z6C&nLE}LFigxV046+0c?Po&g!DHu^U;A_>W}P~!7lYQ% zJ~r3QvX}7OFlXaE#NcJVxuPeI-yth~&bib?uw$~KXMvCIG^^%c{%+3fmgx>*b0075j5hLGn*M|- zSDZf6{O6s0GUrRYeaQ^AaHsM4K4g5WhL%C?C*ZT@8yN57R}q||Z;^?SP3-C=P4pE1 zmIG_)T1Rrk-6Y<(KjJSTx7fW|<|XlaobA7qf3@TJC5qFbN9VeVoAbxK`0ag%##=`V zHs61md3dh*4(*G`RR21LG+(bIuo*S)X5goM0g9hPuM!LC`EaEVQ#;@t^%a*QIP(3= zem{v$uOI0Yzn^SouIpMI0$)u(*jMOIY;*bvYcGxVKS3G6;QP9thfaFW_jUh;G~brq z#dC-;>-%X^56yM&qhIT9oP9Wa12L4}{q2CB_Vq|tMYyJg*tb|;*u9wi>+hNC=5Aph zQ8ITmb_VcC=JXz5KTq!=-o;0y<%l8m?#C(8Trpc^-Hz}5JIe7Ro@++P-uf*Vy+IWNagtd{HO1*S&v_j+M1R2%*nd;8cldw(A?~uVW%6x=u957oQzkJy;&xL; zeEtEnm8~M$e~;(w?28JvD8Iw*+_V1ey4TEJz%KbFL|1?9=+W*@vo>~|Cj3Q#Hr?qi znE%zC?p;TX;coe(+FmYq+g^JVna5sw7T6>c@sXT4dgJ(-z-a6Vhxwm$#dhUp7B&m! z+=#-q9Cyp-h%wC#ON`CU=R6Ge*5|lezU!!2ZCytN`F)08L0bTrbpN~T#1Z!~_K<7j z1szn94zvD|JU&kUan{6JZT|`GOj9}O>(<*tZq<>AT_yCdI>ok*@{i`3F~5$(^H1sh zNZuRxmoK9TnySrK+h$h2C-PG0zhGO)O^#vCITUu+kgs&(FXnqIE$EBo(v$S{q=Czi z5q`?t`9hoRx>rT|S9^$E%ed2}ATj#|+DR}rrJuy#1AXX>^4PYjx5G7huU;EC`UcYA z9qY**rmYyyn)k%Rm}z&r$Hy4=jmKisZ!z{Ye0($Peuui^eU|@t6KA@yS9Et;ya|7+ zX|wYKZ4Mq&3xQE`DIWLl@4OwJlsgmorH`}7|1v-2=Z~o!Z}Z)U>B#RJVRth5=+A9& ztrO8n`24mBKlITyf9(7bU7kO7G@fJBQ=9pH2j2`&s@FN`zlYu9$e(8WK5XpJXOc3h z*TZhH`qr3bEUT|@p)<Q=aT(f*gZfQ^%oz6uY9-bhv;+I5Pi138lIHYe#y&Ww~O}v$!{>7oA};M3uR(2 zh27`KmyQ>0wXb7njDGfMynKj$U!l%mT)SQhPipxL^y><{50n4m5dH3;zfQ^|a$)y@ zyng4?Z?ZZzU475h^V#0>1$zFR_w2*N{b%sp-&^x^co%nt>=**3>Krhg3;kaVyIaWL zW?{;=!6U%ZNtx^mVfO~X1m6Y68R{GU>sc{H*zcUG- z;&L%z3nX(VVbN$?Dj-s=OoE7YsbdnrR$C@4YPH`s6c-kiNg`^+E(nU^!X!wQ(N;wQ z;!-9o?p6i&_MEp_eMHsUf;UA#DQ|GbRuwy6H5)H}cOo6EgBQm`#j7Ux*dBNrIB z((s||*aWhp{C}W}i&$Uy?n({$O3%14Eb=L6EhiqTH~0TK+y##gB3`lN_vu$Q(mKYv zEW}+mcOv5hoAEJR5IYNf$ae1ZzM&v~(q56nzj)oJHxI|2ZrGWpuLXwAb6)-d^nE$_ zrH`@XSDSHkpzjYD2W8UlhV667_wnn`=Rb&p?A+I-N9n6&6MgaR_ypftIi39TkJ8t= zP4q>X_}{{IiTXNDcc|ti*B|2fMDIDJ=aao>ABGo>0>gKY0>iq$g@=?)q5U_)c6agz z9tDO*`mUx-?Deo6Bwzh!%dEsv`pP>>Uz6Sl4++d>{$CB-U*hvR?kIhg14o!L)+=Fq zJ7xUw-jOw4e~fiU>327EI?rk2E8w{n_&0>@P2_*U?+E!pf3=i}tPk6-ksn7U2Yzs8 z#VE(Qu3CD}&30wT?lVm~nfe!<9hTqFspJ{o2ka2zG0OPXQpCMy(}VPkd&}`_#nG?$ z2H7OeCKmHQaSM0+(*DF(t!d@Z|3vQ6h5oB1Zm_1+^50yh?*{N)&~Muo!MOPo`98#Y zmG2Xnb}avq+X9z`xSRVFp365_mx&+3&xi3va$o9s)@99W!nW$Kr~Y*A?2}#|;Z9lW z9DF1LtZB#42laZ?KBslJXL5}xC-{h88y?SEJL6{U%+{sUzuOitT!W5Seu~vYu}_iQ z_Vhc6M=O8a>LI^=Bx?=#&s6z7PuXg9W}dQTTlt#sknlw4V^!FmNd8PyMsx13%f*bd zj56t!VS7CJPP}M{3ch|0leJ{;p?ty~t1gubzv&^ndXzTK|%L-d-12 zUnRhgb)NOEwQtVmUy|nf%Uruj=LfBM;R_-o8)i8(Ed0KT)w_lmcKKe_$1Re#Jh#UZ zu7CXY4cXu5^Y>btT)S1{SNl4n7|Fsz!jC<8COoA1YS#Zhv;LDm!j$K-Jlb^UJGV(oeF56${sx9^`^WzH_CxUtGR6EfC>730N>H1uc$(tvi(I1+`PkB2s z@(&~P<^Q;lv9yol4Oe&CS-Hx@h7iXMedlGt?Asudo`4V8$8#Qs|DT8dO_^-jTK)ul zNEz!f_@6Sa{|FyM@kItc2l&v5tz&x5lON`4;9Fa6edWSOy5>thJndELc_wp+Y;>P* z)HC}|N}tZNN4u{Z_}lLpm(JBn--0V!=bE$(_-lZ_F>I&E|Ae3NvuUq<8SqoaY6#n_ z$-k;7GP3*;Y}kUxNa1&i*59SvH_DoP7O=~v6@BbRzEu}^bayeZUG?3_$hwE9S8D1F zGWCihBTKXDZCAY_uim-T^JJs%U+Op~e=+cipZqyl_XxVxjmZB8!}dJ#mt~cS8Cq)u z{szj#7KiOR^8GofJ2#7FvgRaslsQqI7bU|l6s*|fz$)L;q;pIg(T?-_)ygC1^-0zL zu~$Fmi23WNKTQWt%}a;*Tf|y-EAzK7Y)8qz){M0S{Vigxql~qH^`HEDN;xn=`)S0X!bQJ^kXayhr}-oV}Vm;Jy1)8$TgVi1DXKTk~H~eg1`m8PvB(-#Obm z8<8y!nIrdZR*Q2Bl8yO%`%-q3eEm8rAv;a6;fljTj^o?mexoN!?SHQEXp(hfnD%#6 z=DBa65tj#gC!6$KAsqHjuF&&%@44MKx&HAdzmZ=P|GxIrqt?6Osv`SL?p+FT9;Obt zuDmD6>qXvu_}Wr@za0H+{$SE%Kja&{;vX5Nd9T7|&2E3vFG^}^E5XMdVf)`}+InA) z3{|-p^pH8tiHfg-q6fxw<96>3kFo=@(n&VKX(6&^(Gc5E0*82 z@l9+SeI2pxue%-kUj+TvhwV4Wj|IIuztYU1?)$3cpMBq%pA@uLta%1I~x4#{w|HcPG(T0cUe@@tbg8VpmP;B^n*yED_ zpM%r3x2=)slemv_y(NE4Mfw%uWcB|B>CD9}%@cAcfiF+*x)WeMG@-N@bnscQH{W^f zDL<@{;oKhvjukVhK7_|s`or$-?d?hSOlsfI&-({?LB{LGq0_!%MMR4k%45deA%ez-HhTWp~z0`O8 z8kB(s+Rs3BxclgZ<=SVGED%iyCy`_E&$8C*{E_1MEqt&`xSzO-ImerzeYHEv;Ds@` zch1)N?`99)5OS$-z@YLoj)3BVAp@={WtP=F@N#fBVPZs>G!YL zDz)$18?G$j4n5yTqB+#ueMB2-KYLwmnH7o#R->QA!gdq+Z)cV9*VSOTV}~h|m>9O7 zBwu*bynHR$hRqGXHmU#7(4c5c`qy-D8U!EA^Ge|_22S^oX9>^P(_gVCn<6d3w-4Mk zg867$8W_2o`D&}Q*7RlWeE!ki>F(9M(?|WparTx^0mR_=9actCUEd~x&U;5Cz< zn~3dQhWyp{r^7!Vr+B4#)#nY0>YIaV=Pw8F*)gxxdqYvZC-u%fC+jq)qX)TZ%Sh8* zDvGVrK4hG{hA1`(k|yz5CkT4R6Fv?5X^zS{wa%E|+d8oA_peeK%!AJBkMq?j`qx`)oTW zHVOSNXW|Fx!lD}4b@|v9qBZWvn|5qJ){B2lus0u^fKP;dwV$#6y3{_7dD}+Y zS3%4AM#;usnL5(na8-hQ+*96^vbN;Pnpk&!m22? ze{0H&HSOf~_sZ~XI=i_jXj^|QwskkS;JMnA*;3$@soUFTXKoML@k_(en@pKIOqmUR zy)u*bwAp1><=Uwqhoisp;W1?%?csFT^d)=jy0YV zz0#EF#<;pLt|`5|GQpi~cKB+_G@KG8c+G|R4m0-idU|DAzG}0pe;lx5-3LZ5G-bA% zz6RubW!8O3J0F3=nZyqI@R)XT^Sm;R|Dm1ta_z(gVf!q~H1MCksW^Jo?zTnYvEgX! zn1RvBdM4f4bZRulbKrt-)Hy#K{Ta`hv840iViyZs`o&!&D{eQDgEThox^Rnv(xP+h@U%uhDi3!fNR+2f5# zM<8tlX)33+KxwD4N2O=2>Cz$E&-{A!zpJaGx61FLI6Iw5Os_f;ca1~PNjc|~_)ge< ziTn@wi61`8(rwwftZC3$sMEvtO7f+LE0nz_T%cXz8Ae{Wq zM;`7Xijzf-_dvd2Yr49*bZ_B|I8S{?>KO~%sUG^yaOviMGj-83hilDV8_eI4zGF#2 zyG`Qx)kcd(xYt*gl#h;6}ZwpNO1^?F5g*~K0S&>i=l@U$@#C;2=lAWSq;XSjowm>?T@aNO_ z&e<<5*S8IR|FK8Ihnl>3a*PdBW_ZpqHqaRJ4z7r;%u80kRv1-mn!&}klOp?Xm!0F$#mRGz4@cKi zSM#lT7tFtA&h>4M9`IY3@oqM-y0HAGFk0Ie+p164UO~FzQGO}fKn8{1E3|ul>WwQ6 z+#5~3^r5z4#s4mhRu^CoK-Ve@o;E%IcVGmT)Z-ov4m>6to!kkQi-Dz*v`W7Z>ODz4 zt1I@zB9FE=|H)f7UHY!~=$mt-t3-QKm?P2owiBW6E*^dRv^`wor0r3r?Le^;-O3sv z{()|W`SqvfgrgEhU$+l+ zp9Kf8b%ix~=-R{^O)Fzw5(y6nU92N<(49JYS>yjD;}^eyyQcIbhJT@vfrp&v(oXpM z=Cig%Pt)H{?6AbwZNs#t3jYz>fZj`Y&h~xvx&xqH*6I6-BhIn%;@G&K9m<(j4U9S? zB3c{G92D~_<6FF|Xjk}Rj)zCcyP7he-B|RS24q~%yS({HfCG1K@Cjtg9_s-Q_O8LO zy>Xvoca}YG0lVg>f;JZr6PO--r2G*r=+1cIIFlC`ndu!E>EZ^sC65*JooRLKo!CN> zJu%L5xUz?}H(U0M*+M(iU&5M)E;@gDFur&Jv>9k|T=~;#>Ot~GYYU>vmnM*(V z-%K6#8$%{BKdwyquG$8!UDT!RXA;z_?HZX`4UY^~9`$4o#>iK^lfDm-KG&)Y#C!D! zpTjp2t?x{`lRC)5i_#BTGu^%pgqn>eF_HwoJL}86^@6)^RHUOA(XLM^$ZfS;jjs3^5PXdR}nSMEwGA-AhI7_%%x5tT= zoe55NIrhEecdi@%H~qBG&(Y)^HoD|pVy;JPbGJHnXL&bNbVj-NUqaq-xAh_eLySGP zNv|TeM#MMCPKZzU=o$L)=()ZlJ;&?3K5pOP*khoZ&h*^Z&~rY0q)+4igJhxo8tbR{ zCjwq)ntmDcu*MCAQN`M%zHsczNtc{G2n?!M27O(JE=Zk~>07-%H-75aon_~@$m0Js zb;8v7Id#~hZF1Y#?nINO?>Ogil$P1%*vm{Bv^G5R_teatvnSYF7nF@0^-XBnwnb$l zw?9}mGJ#*f;k%#Gk*m)iU!QDj@@bX3vO|uIi!`nQ@faW zDDGL0EI=nYEDt3cwccz7&dEV+Uf$32$JpXT>wMfC3m*wz87KM@Y3xBa3AVhOj)X0s z_1?(+68iS#?(_7~leT@h!=E|P{|5KEQ3Grj?$rMc_cGc{zd($~@z%6g*-s68>>Lrx zp)rjH4#DKZvWR+jBZnuGuKfKx*PCbA6idzXPRVNSl~&!cpE&l*A33(lPkr05>$BFQ zdfJ;o*#-Ff{q@B8l}8s{{&pl?+(dbN{~j%U=-AhQQ~AdoY@s}ScP%_Of9OP|tM6)y zSA6je<3!I!w#*En?`kb*LPic-iCm$~9(XUnS}`iu`hJ2u$*FwakE4$e--4E$Re6=& zL0RSDU;4g7{e>sT3*vRXdWgQ={dQ#Cso-)6@-3~luJ*>!ZIfefqyF4i9J`gW**dE9 zgL1~C*Z{$#wnQ)Ccbw?=8Jm353E+Q|zITV>70rx8JU5E5^tA6SSc|Xg(Yr>^66~=l zUVmf%=0vyQ6YsL&$o>Y?S8w`KTbmWrqrTv;+tKZaA1uXJS$g^*beop8Vd-kw*V?Cs z)+u)jWwrs2=5%1QW9#nArNHachR%U#JSsbZvRb2$p)Zx!+?PNbe%UURJ%f4QSy|3L z`)K5NWWWE7AE$?6evKW7ZSXKQvF0`Kn&vexc@uLQBd&7i#qM~uUUje!V(3qTGkt}J zkFDTA@=SgEdZKitfxwoAM$)rgJ-UNFOdGmmr2^eKzl3_O+{RXs-XItr0|w1Qj2OZ) z%1xx)4HtOuKx-Y~@$Hq^1P`98QjR@$HTq5`dnE--8QS`9_DVuH?PRZH8XbEF_~~Gq zWa$Us#-;l*=tHq4f_)^kRLeM=o2`BtJ3>b`%Y4n1^1n}hb+`D*e*Q3g+Oi#_AE>=J z@_yIslxz2_wDz4jkn+OC!k~3gF6F}Q@7;INeulCZIGnWJv2(6znK6eLX04;bQ??DF zwOe{9-m3YbNbsu$VjZ9-@B9J2g#IrQFSE04)uYgja4z|q!nbsUy`uYEpc_2L`>Q|j zbb@zRcrf}pLH@Jm-RJ~;%zMJvEX|WWo!}MfO`1|zlevnRq*adnDDSar3u^?c{LM?y zfi)KCme5H>%TnwZ^!WI5o=)(r=@v;!K@lMxJ%-Ka%g#7WG_xg1QcM zA4P9Is!jkNq!UorrbL(c)IsJ28MJWYuLIwSet(l-_%!gjX&m5 zbSC_kU;RSzqugtAS)&u3%viGdr7vxYw^y5b4cD^%vnFfa9j*VSk5o_A|Jw?qW!Eyk zCt3eVUvBEu{&b-IqNx*p!m(4tI|_!?CM^Z-Bj--AuSz=6xsNze@v49Ca+tI~n{v|E ze`fl#=sTvpV%9O?w)_d=7_LKqd)%={Qbz4Jj~{4%O5HSib>!>`_W8Weeb9-PVDqaF z>24}lJ8q!;p2{Kr;(VtmJ#vDbsT!y=ru&uu7I~5@%N}r|zU)Irob1cAcaYca*)Gb~ z8CVm*_bf2wKkYO3kL0d0$h*HKTgJz?yQp970C$de<7b+z>!{T|M6 zZ=MD{g06P&k#giOw3lYCuB9#Up7fuHzN1Bd<&VLGyKdbK{gzJlc~N_dz#LfOM5_$k zfiou9nvc{n#~#4=^Ijb~Z!&uS8N$`<_{=WgPw5(qWbZGzN$XhhFL-S%MdWL}`hL54e$dAbl zj-3na=wqd~UDG;ai52wZNW!tLSHttFPiL3=C$GX*z^3u09pE|*ot~hsr6V>=s&mW)GG>uzh)L1pn)Xt9Myhw9FyWxdS z^jqY&_$9%)?Rx5|zRp;Ads=?15a)67z4@2Fc#Gr$GC}P_=N;~T2M>J9cHe64n*#qP z^)rXPV)1@C{9H?U$s}vW^nI$YII;n^xntiH$LAw^n(=IkVY_X7-rIjXnm<-+i+{Ft z1n}$3^DWPKW0B42$NROs<S;oL~(rk6{CG_9C*- zv4@jCm3iHL>;%3WY$dnCSIBMG$DROJU8mslKSsEB_qQujv@JRB>l3lQ9^Y-H-=)l- za4K37O}~pRUrO6*r=``JU$*g7JLh8Z@E6BSJ3|b7X~rp=nejH&&Bs2pf$tBFeFFKL zx!X;7R+O0QE= za^I!OdHIb0nvQTfCr_{|jSougZ-c%x=A0AS^|yQJt2=Ee7GOL1DyK572DU+t$790H zU6j?H$Ck#4vtr2Tv27k*D28z`bSIso-B0ZE!Sn97A^d%SwmDsv|LQ%j-ltESb;tN0 z!v?Qfhva7*Xx_oE=YJgN(bId>3l1u*3FFI4)jRexydPe-vEwr(*u=Lx_C|D5&3hc1 zJYr%o#8(-3Y8$%kpS1o$Ly`r{riAVF@R)E}#lJrvmoR4O!T(v)wn#ok^(EfNzfxgA zmvt8vMjQGm-pH~4K;C4^C>|s8y+V7Z@uf!?&(iFA_{7)!2p=YUMX6heoglB$)C<%9 zz34iOdF61P)z7}13A)2CKf%9X9YcIW{ZU{o2G%maf9#Zc+L3=lZGMX$;_?9J4&-N8 z2yP{J#B+L28(a(4G<7zEv&HXoeiT{bj)(U24NQl-4^N?w=9?V*L&d`});wtJIWt!2 zM~WxQa2}|Y^;h!xnWN+p)9=Egz7_XVNB_Ea=@$AFoQkFP`_0dZ?B_$ihi#TE(C5Gj zVS6<8y5>u?$$h{TEvz-~nR=&EUbL#a8RIJ^&eHiL7dG$~4;nv|yZ7VW)7my#ekksS zxFYDrqiCP%B7-BrBN?@b_W*MrBj&Xlnv8U}K#!H5La)}|kjg|U#}78?btmBO>c$!{ z&9VRYDe+=YcP%M{Zgu~raCyR4@Cp2!L*Feqf%(--PUTzZ@CWk5vpc+aCH6vg$i7Zv z%XOuGD`g%n_Vy1|ui@cSZME;$`-1*l{SiLS=WPG?I>9}(1Kjz^a5oR`7V53*R#;Pe z9Q%IPIrduKQ{X0m{1&_paGef*1^=gCc7(n50S|Vqmp&W`o)vGE4gUwv9R>bH9pQhm z6Z~!dyTN--XZQmi{3`^10Gon!DKQoP=l$Mo<6Rydm@}Y*zg~Lc51`Km)3#_)aZ930 z&1WO^8}x1F$&P&sWg?r$+gEYMO7#X;JJG54u>Z~XG%e(_Xx?HTtpVVQ`_*H_FuUy) z^F3Pmz1%oe_9rJgb~pQu#psI_{pefr`6cinI`!@>ErZ_6mqYvWQ#pLoI4Aer-B+Bj zeDCBF*%LjUJ=|2+Pq?A_G! z|2Xfn`G1oC>HI&(|8@MY*|9r5u{9oTArkS`p(ai(su7_spuD6Ss`%9SXAM;JLTzCEhjQQm~ z1EOPTLt`!W@OIBc#yjZ}Cwjhp`{GeN>t32JY2E2=aYs$OV!K^ipmnJvORtziKbjNK zsKx#NY1*qNU%Grc$hT~WpH?5T3&rzFPmzA#>)u>8xM`9BmU}O^zOD2jX_7np_&*Li zKS2yb;79mS9qV1KIaUsP%IIQ~>BnzhHlgZ%VCt%kgV>X*TRYaVy}G@U=^%G95aXwM zqp2_0G^WnD^4A;T?EH@v8?tu!5BIVz;@fj|ji&K-^~>Y!t?=4X2!DGyiBOwMQ#hS76Qq56bvN1c4eeN{+qS_7i zcWl4iPffdCe|-=4_mN3Yebcs5d&_Cs)VCX@$Gm|~7drtR=4>}csY!V$;{NWycP5;^ z0bCClnV}el&-gZ40@+ec|Ekj!y+i+eKc}LSa%~rR<5HT|@JCEt>sV{Jz1dsW(#KfC zhyKNT&Xz-Urx)6pq3CeK9or^fa`z96J981ThQ03J(x=kyA}vin#ik8#F-*K6T5UYb zsi_{u`Z3h8+y2b?UsFbUn95|hr%F5&vcmtOd{yu)Ct6E+=M44}DUTng$>+0B?wqd` zPuljW_0@UZ$GG?D`+03a=U>gt&qF!AN^i#3DZE{V{*LZmx`pr8xZkm9MRx`V=YX4A zz>~wj=)%WMUvMKDZ$ign-9`7p20;fCj;9%TTVf8>)OEl zE!^M2_Z9Hp>szONO1pu_P?a?eyqCfcE)6RVc@;2zC|ws^0K>{xRzb_~sPOwFu)Pmm zq}Q@9gr1RtUt{cX|)#K59CPM^yD?BDxG!xz$jPscuyybHCriap)Dw!i%w z>>1(8VjRV$p2o25(f@#Ye1_zxLZ ziai13+jY{jEPR-uiv!c*_!M8u8_?snDgEDIUK8M>%A}- zS#iMqzj?(z(Y^3{tP|bII{g#IC4a8gYx#4>JXR9Tf#&_SQnPW zDQn;t$u+B+)zmy|e1}+6;VXhqDs_jUk4H)3aY-;iAf8%Jdtk4N{XOdPpzEBTU9jXj_X{$-2jLl=5hy1u=l`=w4I zEkk|QyiKfaE3tu-Ut*_Z;D41{mk!y^@kM-t#*?@5AveDrvMXeZ5_4NSz2i7zj4=`S z#yIBTqmNPX_LtL6jTr;;I!tyN<8}A*HI`sEXGp_1`1{+CeG%otZ+dZW!{|3gzs-eug7stO!fg|te39{>$GY}vIcNU-GVf5v!v(RvrrsN-9x%Ay{y3F)=_$Vf zUg;wz0lVs?$Y0mB9k(x0PCB9=Qz(2tr?!|s;bf1-2hM*5ETR#mU&k|JdE+zACW}t< zs9*Me$UaDV9GR{%&F_Wmy{f~rXsC>L!SOX|#Q4si%YP7^x7qCF&3OVl721qXapwR# z7F|!VlJ)qqu!H@*$2jvQI=}rNA-l^TOQN0k9vkp`xO<_0w`S&bVV#G@8#ed1qpWvY zLtNSL@1p3%yo3AF?SGHV)LPKWIJLLE1$c@5-=sC>ns1RuXL)N+20l$NcT?{!iMFDP zZlkx+xmS*O5RRRp?-{0jY*GF$HgMsTFEg4^fGn*=9)#h{r!O{`sf%SZFB z_k6u`zDBUFX3aUgR=MX8UvYJ0`Foe3W91H+c)&rf1c~M3+fBnp&nP%~GUwwbpJP?d znPN?2&#J1NGx_DbPaHs8Kkvf-ZQ$PA^Hm|+SGtb=cUJ1V%3ciG9&j&R**$kB-J0*v z>+Ib=^zoU<^u_!><6AxlnX}5{yggM18`P&wmw%z10WLjp{||GlwIJOtADZg+LD%>{ zto@-Oq56U(-`+3*=>&_hHSw#oEgl~55tn_?z zDR?)2#dupZ6ehk=JR)DcY%q=O0PVPItzwDbwdc)yh_hCDZ-6$}`)Qo5m(_k5&o<9)>=@${jf)4+=V$7CYAw$y7oeOw4%&a6wzUuB!{>}2Z_B0=oPXzD zWu0x(UJ(4DxIlM(6I_4vVPfx7@6bopYSJ{Ojr`}+|9ix*%CES|!JqHNwhW^^ z=%cjb**Y)wLi8*DyUvdK-xZrdn-B1-*4ad8x|%r?Ux-$Q(1IP^E96OB0FN;bIs zGLmb~!y$Vx&+-vUmNh;Uvcun$Z5FN0K}Yq!zZ(+Vz^HxEF%N~<6ZZDmg)8@59ph%- z)SbV$_=EZZqsyS7<4$a;@;v#L&^&H&o)!dYPL z#jB6z4?OvMjOhd14HM7*z?5CKsJ(0hvRw1IzQW1AAHx9M{{&Cs;VrVzs*-mdQv{C)CH+OTv zQ5stv8P&Axj*ew&H+p4m&MGta_KszmH+XY0J*&*rxgE>YuJ_ux)|BZm9&p3=VR|>$ zhoWD=D>2UgOWubWk8ITYG*)c7l+J7dXDemouTP*Gh3i7m&vb2n@Fwo4=X&thHZ3LZ5FCFIXx58QgfsBKa<~=dmUwm$R?LA)O$x5p z|K`c0G`93G;Q1$eUdX8ZZO|2GKcZu=84#6kZ7@D@!J_?8?Io?xg5xsa&>D3ncjgmU zM<3i*v%-tNIg>V7$A&$2$$+T*EE?R(ihry^}}7o9DrsW0oHpN~|3` z=jko_9*gkf-FLPif4qGcGBd;8xWl=#7YDWzHB3=DsFgFJS4qf?ys|Gcd6Eb z{N#)1fJO!?KF7NUlsjq#quTM-8$W*kIo9EvWz%_?W})d_bA?Ef$r3OEM$Mg?+)f5 zm}|XT&9mm~@4P3Vj|ATcxu4%0lON_;`J0umxqXWI{BH8=^Q`4ze2Se*o8pf+c$c2pg?m|Bq5p{6=co@F$WvT^e2umGj^U`t{sQPod=q1ChhqQC zq`xh^s}0pvdku?Dv9W7WVeOv=-$}>YJ|eQeY1NW~?M9#0d1(2WbbeTUU>~{gH;+EWjWhLO*vcM9SJQtA zI?`CSUdJ6_W;_A(3}QTnX+Gow6l|^7kQy6My5FJ99#eDV6gzu7f^ABp_dV3uzHzqh z07(P4+WG9n$c`ZLMD^#o@OpU8{Qea0{yoOzo@JkP<37O_gBGsh`M=@gy9O7+gYNXu zU0i~@1$bp2_9TuywQHQ+*kwE_CA{PC!>1cy|7ZejpGVp@aLpd^nlVeD31}vqYh9+f z`i`L)m6=MMn9Ag2kDI`Ay(=Kfk5O z??J$;bs8O?`R>Jh_xvw@!j~V9%Ec4AwKo_<8UTGadR-KW(CEWM}oPoA&AMZ{0^T+tB60UP}u0GFR$P{xQGL@ZgSpN{{o$ z(8ikPj)C%ucTyiYW-KZA&-#@6Ewb8b9&n0F+u1y*_V&7C=$+gwc}@93cMQFg#f)Jn zGFp6j)8EJ0YF~V*d-?>Y__CFMe_m?i9&g4BPo`KOt9jN~%d*BP{?i?K>MKZJ(mj{3 z{%cl3{2W^v8+@ha=yPm# z-yW9@9dYfWyyOX#m#lJzh3wDd+u^xd_R-LG`)CB|D&yNoAJDFNS$heZ=Xc2uu&(KO z!$EHyP9qbaeSe%C12=&_TF<$M2pN@tzEo}_Z7{wH`BbYZQ_Nbebv!~D^`$cMt4Tjj zQ_gyN2{DhvNU~OB-^t;fb@%R`bM-!O@DcF%ICzXUcy@8{80kmD!JB4$*6AVp5uSY< z)bYI+-$vY%?1+PV4Gv`23)VkU&&NT%!2x3(uDrXd=rq zeT*XH8dnco8YaYgkMXE_5cI( zBNIdRZgkb7#;(Jw+B0$99_RWZm;K_%^K5h8^<+jEyqybvTj|5qBe~zArAPm0ZJmi- zFF~$eSQI_wZC6(>)jmt}PqBS@m)}G0wP%H*`|xdqNXs*6nO*(t{qRZwX=*pZm|r)2 z2#4!V>>q8eXM8^o4OvdQ*5P99m#9Bz-id&1CYWuZb4iGG~OMIi~G~ zQ~TQ~?jcwDA#4owhfXled1aivu^PS5>;nX{{F|c~ejhB=+rIfe;M@IQP{Eay?LEr$&bgMmSE=)h zsXcAtiPDYSDfY5ewn8)|TxneuZ|Qk!Sx5dV2Y1JkuRPcOkB|>Psl1Qhk(ALGY8k86 z`i_3NjYeO8$@LS&FNFyOH&unD>Oge!S?(`rne?_+r1BYW8|# z=Y;I5ct0%bW#iZ5I~ozPXJJP;oz5<2p#5#EgNl<*E%9h;;AMlN>zPB1N8^-S$<>%t z?k}G1aThqa+Q1XD*&lD|7tIix+FkR_*@nO?{p=^-GUEaMD@|F8vpT^{zi2bx3ATXg zY|^KjI^x?)!C6XYhiRh>z3M^JMqpJ5b_TMC^!rR&Tzde#SDzA!&Npe4@zTx+*>932 zyas;D-D`|5%vgpEi|k*5&kP?WbmQ(PZ*myxkAT4;U;M6dGoPDsDXY8-4SX|9ADIE6 zsAJAUO*d&;D^m9w{EZzHoow)@^})yCv&i+4rmfniO6*4sd@&!7?mVOKyMCd(J1E; zIpgd|7LLYu!jVOtIPr7xZ5$0xZa#Wf9_7^TI&>n@en;OC_s-oq&b@OkF5Q;BCF+6y zQ6Hr6)o8Ao=DB+B%!vFfri{j>GXDPmqogbLZZdI+KF?hVPE_vO$Duj=6!;_O{TtpF zT%C1Z?azqs#_%m7x6emA^4&iF-SFKv=H2JJvV_NXPmtb{=vNbFZ!b0=WZ%jA{?EKN z6Mh>;Z)^46O`F@zyWeKR!(N;BkzW2tzZ&fqroth6I`5r%IUd3vw(0-o!;S`G_vOxrmO|uH?Hd! zEh9Esx`fM%%;(RUduYk!Ve#}&MGMfD@|(96MgL^lqRcSoW)IF~-)ZL=pI^2k=kraw zfvrW+`%S$#eh0U&Ek)7Iq-hT0^p~3Hwe_dgqUgZW2DxVjvt`(3+7mxknl>|CLv}s& z;hEC#BPH-wUb6HxU_W->s@P3lThf^}o-!!9)Xs_BV_p(FZ;c4US6fj9&m|Hw3T2Gw;$hj_*)4zC1Yq)qRkhO;0Nn7Ie ze=qgsJ;A(}KMP$bCi{et{TAsyufGC}NAkLNuJ@O(c<}$jwBs0l2pJl33_p~ZclDz< zjqqHLA2v~M-CS&=F37X)p&?K4ewZKDv$nCmSt}~+_2|5jPHS7U*0z409h1Js!(EpR zMMtb{moQeH{rb<7UhLO12G$7s{Ebiai-vXPqFZRlA4$JN^9t_-{@Bmn#abnvuo%Om zrjFnbCi_JLtZ%6uinr%C?qJ)h2zQzaZpq@M^dnxA z{h|J}PVHrFk>A0k6UOjELnj^2P_8-R>{uInk&k`q(anzy%s$=B_umcO+-u%_x~ZP- z(am|J2e0o}Q;SZNI9Ozdd4KI?ug#Hu8-^Bd_TNpLar5rC*<9nb`90DnP3z~L!Ljxi z*~jyKm==j6$zWF}9B3)sYsV92gLOtml31YssKy%HPczV_V zL(kfWYc(=T^dMd7TI&1xbNQBzA7`ih&Ct%Zl&PkS^p(K868s~agMP=m&s_BQK5!=R zJ;OupJ$$S1x4AY0_Q0u+G3V|*e8kW3Ucxwcvmc_EimFrPo6Jw1ne=3F>J;?BKNUrb zsT1S5d71X-^OHrqv%WMv&3N|Ep9QbwktUzmi%)nwvE1Ml8`6zCZ@^}$`&W@2(Am(> zi|pIU*B)jU)gw+qd*K0e62Y_tIj6is@?(&v^twj%-81t?WInFJ8AU&Ho?Z6H96(poDF=q9hbtRPe;AL=Rn$MQGbkKo*Bc8ql{tFmLj`0 zk9Dl2$R20L@Lm?2Zd@Yp{mP8tt*pFB4|!wwe`X9{{mUCenmvnG7>7%T@(ob`USPOv1MDjUdJ--M&LS!*{?f4IR#1e!{B8*{|nrp5m#iZ=8@Mt)pm zpQN(TCKJ~t=*DS$@Tu=3^Y1RQmlC_Gv#%PnWJh{L zWPjs2;bh;c#1MP~{~ef_sNDPxVbm^<0Iga+NZtQ!Ry+;# zfJ5>7hww!TnFKcBh>1@n>YD2amNfsb|)fA4Bi1j)$J)`!jY{ zdU2XND_6UFDT)Ee-h)&efW~tr>(Pz;4(8-0r=W|rjkd5y@fV6lcosjkjUxVt@wSb% z_G|8<%uO5mvE+t-Ca|ulpIv(j@@Yen{T=ehn)yYJw4WQ?SY$U)##&!w4w(>m+R6bIVLvlbM5$eJ_Mw3n8CG}hIRn(AmLT+04-s>rs%K zOfZ71uy)jPUx(sU*st3(0-Bb-F8$im;d>{~Gim<&tv=m%wT8zyE0UR36pce4_(@ml zy?R=aeKYTt;*9BUI?r1Bh)djG!!sBB%oEP;cl`u?lGmv$vfZ+J&Rc?>v9LJ4conit zyD`g^w+E&L-GCaM9a(qW4o2OmB z7WIV3V(3G<#GVtzxiOo~lubdq`iA=fVAgZ9iKSma8WZpCPyG|wCm-y2@MW60mroY{ zAC8cA?=Olmw(hhox|rpTvmn`x_nGc<-()V&8k2ZG!1L9>pgCB`H#I+Co`kP{j7j#* z24L9uA8a__$X)}aEBy`K;13%;IT1(Ztw?y!F`l0?&uN|$%uB6{P%AD+m1BSu*D@MfNSUEuB08&K>f~S3tMqMgCl5 z-$>pTep}R zRA1|X;PLA>Q{OKu--h~9>{$zC^3f=Ta}1LvJe(|G7#cV36FjrV;8A5hL8&yUS` z)?Mzw6a^;b|5@ul@*;trq4vt*i7RO@JhsR_0o-tIrs*u%##wEhZQ7bN-fQcJS-82j z)7WYm%ki`)p1F?s$sVVVr((YQqw$>92~QI`we^4D>Ecd!QhS2AmtdoB&D-cs?InOs z^y1^afjtMm>{*@4RwJ)eR`cSQZzi@V%-DoCzrS73w%^9!PHl)zvisBc%P&R`qfOP9 zUE7j(_-olt zcyGe%ZHwgB6_4G?b4=gLr0iUtEuJ<0rQ`{pt>_=}bx5acMOX1;bx!gX`U1C28{gt? zecD%lI2H3Vt>|EU-$wVSTF}(9w3DGdwUwc*zniu)w57BrwS%3cJ_XNa@?*1NGo(wn z^67Q_RkWWipCn%g0c#)n^XqLi^~9UVX_q$x(ET^aPSw?Tw$KN$T*%o#>8{u4m$VJ9 z42lZAR${wah&?N@tc9#orKyj-nA}*-!~>cGwb9D?#Nv?rVS&;u)ECZT$lb>t_vEo+ zFCXQZxSM37{+T!BFHt`0_k-XoJzDyVwQ{jr?!Uz@dEfBz&Ny>-ydT3(T%pci$i|rk zKf8AllyFza64s2Ijygf`-hM-x@s-Bwi|kX#w{i^qqI;wc6xeNZx^nk{wZAXl;*uV= zpEC%{z#-$Th!=V`VJUkXlIhZUv?fJ}O%6bxkq@ivR`mL2H-3*hMyT@+GFLv0Pqf!Z zdF0fZQN-te4(^I?DYDBhubwfSd~2oVJ52r!^81o@*uJ2y;;+=^^`?#D@3yz`Ytk~5R~)bAvxGhs zBX}G8Y@(es?H;$mYg6+d()` zcU<7=Y_wTrX@3=Z)qJ{oXFa+iWr=Cr^a6hT&>uqk+V4{7lMLK2*p^NcM^BfIm!OZ*xE8r7O>U#9Q~W?VOgqNQgpwkk=O3lgQWkoKe^w&A_QU zrGy`MJ)InwKLlJRvF?aBwWxy^EnG`GN--+*|S;U>mWX%CFkgIHjm2b0PTud66BYOn+0($tp*jr(3ps zD&J1woNx>sYwyG8>&pZOKRB9_uL&FU#&_ zj|LtSf9`}1eH;H4aH9ARwcC|;wRYkc-IU#)?tyh>27PIM<*Uh69b`lgo^|e*x$^eP z-7|n24#%}BHq*B&bw+(cvqzh+Fiz=vj`8CjmxW`+Rh?+wnGbhQp>|yX{=}y@y+pm@ z^#wHz70l0NMfPIeyK_&6=zT?}Hh25)%$w@&H}8I%nYCV-LKYD=mBi?DBA_MLDcak zRsrYFw-rQdtC;hPitH)my&)VA#@F}Par)t zzlv{HdcHU-BKq^r|50|h+RBVAiZ;LR@6PE!sl<1vpVk{ zXN(oVl6c6Bub#aq`VcK;kMCcvv@OD}#RWwy0Q@gLj$jj}7kl;Q)>6;dlRi%VhdLO< z?l{H&=hA-*a;=)@=kR|D4#__Y{VQ>QRr@{3z&ez&vJv4E_SrcDa4URo+LwHh?`k9M zPpAEx4LzlaUE+Jvt0l|sMn{(IJ)HU2MLWd?ukPL+XY9dQRpSLkLjpeqzvmX&Z4WVj z)Vo#nT;Fg{;~UOT_CbFUoIc-3kAD4-;TxXE(#K`M(UW*l?Imf>&$_3|Ucz@iV`og9 z6-I~u2fU#*r!jQ1zT7mh26@H&`TB%pRt4h_Ofju7wEGF| zs{Vb{|DC~|`hg6 zggHucCzJLlW7rMBn}PKt&(EiK#pSeIfzS7sUV02ZgAOaujaF+vSbP(PZ``uIsUL5z zuXcow4Cnsbbn&m+AVuu3(H7G~|vAJuD(w!F$VW^whQ7 zCtV+ye~|q=(T6)u%4nS8YxT7oJ1m1P(tu8sS&PkoiWgtacVc&31MiINZq5G!y1LlF zsJV&xYu?kLnlkQFv(6}ro+`egKDeJb3cstq|FZDFoXzrwy#~GP3R?RQAio5gY%&*@ z243wU%r@;?;6U>>$Gpd(=Z0enhbZlPq$M<7bUxX(qS0!6HHZBt!@RS0O25LS%ZAlm z`{H@6cWOuVQ#tK%>F!w$_YAb}Pkm`QbfCK+Dt57^!atjIN49XbgtH0S8@RoVdnQQt z{g}*SmG+7AmU;5dBJWxD%G8FtmjFzHf&2TtbKAU6SwXxV^i$0khfq&-yuDd3);UJ} zsekUeg7GL0CWdaKawjtu@#}f$e3RJMSO?xF&hYj&CUf`j9G<7x=gq2R4zV?7>U_Cq zsMtJ*k(rt!|2{0WDV+G<|CKE$deyowzw$nGJAGShKW9*O=j0}zN5;v&{PKey?Pk+O zuy;{SxENh1ToheO{!4xtY{$dC?sWt4H8qUd7s5A!p$t@*oQE%YS&;%e!)+^M>* z&~7z4kM;qizslcx@r%%e^y#Tyxn<3Tb`E-@)+Xlgur2ceb%)~LzQfc#;eR~1S(Ao8 z&rj`TmIUVCihiK=D#F~A_0_&sUh?PQUN(lF7xr4Xcq8*5nZKU1{QBp7MMd~TtEwOH zyjWdj%kQc7e#Kn7Yaj9&9dKqGS?$J~n!YB}m)5Mv@s^vPBCe*Pr~1rKmeHqp$6-w& zw$k<4o@3IG4^=9&6gZy8&#AsD=}TuaW_PpZ&&lb#V?e*M=Q-*3+1 zH+2)#3qe;o~Wa(q* zGAeT&eZEZp>a%tq-%|Ug&E12#4HftWe(73M)kM-Zdv-H-B%saU9 z;%lz;^wtB5iLbe~pr-l^_^(@0^h4ec>#Zf;Ie~Z%aR%s}u}*qxGkDhhA37(HzQouF z%L@<3Gx+-14Z|#xP4f=C=khIT~cD(f!Xa1{FKdQ2qEi1I^nFsZ)IDhK8@#ycXoNaye zDs}z%|94E?W2u`STV-!tT4+x;b+dVQ4DeTy4kGiz(6V45?sC|p)EEEgy^QqA6$Q~H zq{$}Nn(`3OF8`T)?TPs1t0}+GlvVxagM8D>ir*7LA5BR&AuUW=Ki;3i?swNqmHSz- zbn{I;v&)gzgZIBsPChf8mwJL{`7-f~;HS|UX!Z}0|I!B^^Ytp)yBrwEFYT!3Y&;yJ zEO>`9cAYVH<0h9_BS+mG+82I-dP^d@XKc9Eo#qD%qgEs^e<(EF!h1Q-6Y*_`7c+}> zMlhH>oxBWrVe-%=c1#a0DbRb%62(U3CoiVW9WEbqjvMv9AMM+K+27tjP&U6cKj=2HWo!oI_+I;+Th-&m#;eyV%*`@8(iMQT*bNXcSD;;mofGa&O%3x zj4(C_ZB6FBOzDw6O{Zw5g|z}YVLj)2M9_%ly4cWmS~NStv+rB}Q!u0qT`Kiuq22ZX zcq4r}cZXx+uW6v%v*?^=ui8Zw}kXZ&N&HA=~&oW zoO42tM|avu{|UasqB5sbUug%alMl}eChbKU-%2uU(){-;co#3mI9m|I*IxU(!syQ) z!A3QEk%8Y8+CSml;@!!?wrjNJPh!j&{8>3Ma1L&y&&7_j_*VSB)zEN7j5}@PUD4}^ z$rtVY5xhdbrMnLz4+SshO&!)8wHG)GeUmXdv~eYH3WkQ6g?0mdCfFB?)BaGNMgQt+ z2+yn7|CA4KII{P{M)VTpu|HNv{`>6z$p^ZTaaG?Wy6d0(J$0~0XL@^d{gaa@w;o+i z?R`!Cn@_a%$ABe!T&m}fOZPX7<1UV#Gpv)}7JV{?1U%Xq{u%plFJy2h0 z%U^?BUU?QiQ^w>7G@#CEekAZ?1)xCB3|T^qUm>RP5DveZ-yW_oKdS z9LYw>);{#-guU`Po%q03U*daw3BG;Pex}%4Z)%TajQEWr{OcP(`d)qWFAHtS0oi|z z*t(L(@Ib|K_9UglP5P_8G$jCR;))rho2mMw4p^w(mKYktQU3Ig# zW0N$M*+jbLQR!*?b#D4nYyO)mkA2k(xaF%<{<;~a9{C$gzS3L%)SmuVlb*qj6Hdy& zq2yDL|41(n*Ez(YYp%ry(j#}W7cKu;j5)p*`e*}A$v9vsRoYb2^lZMraQNGs!h`gO zRF3r67rpZxjNu7%MDbxic;B_NjKAvV{<~SDCz*F>%Uz=b-|^Py9;7#Zr=TW0fLO-A z725y4KWmK!XRj;)zi(`3i?L)(J&mLBGW=14n9ElS?G))M z4}ENUA3BL)dpgG(dS2wk!b-+w!*mreU2OVMy$$ zab??24!LW(cjp@Yy~bP#Hnl6-%`xq!SSN3I$;eusCFjDE3Zp@Ih(6u8kA`Y^OExC= zl1xR0ZsgugC&wGhdc*6xfZZR5bOrSznv`$%G1_;(=?I+S!(L{5n!ou5u1^?;=-=fl z>gw)MmnQeO4NtXIx_b}0Q@hplmpvCb^tVNLID7|{@1rHw+x594A1-1H_&oSl@bV#y zP5Q%H;&b+3XTn?VnY+)p(+S$Bs=iS2xo2{aDJR-%{!yVVADYU#c!U@I@|g>~@&)88 zPjNq5dvC)Z;M%d!9yZHN=_+&h7f#;fK2Nn(#y7NTNvl@6xhv^V9&1shKZX~OZ$bBt z1C2#vke!(hS={Z{C0UKUSj5~o&}@8D`S{$ z<&{>Vi{5~a65r+3-wOWgJGGId4UNgAd32)d=~Ft}c?}*emA6u7veEseQ=>z;aS|Ey zEcqeRq#Iv)@(0vC?3-Y}I6#@5)Df=?HF>f#-g32%OO;gfLS(f4|JdAZ~TjGtHVE`bl_zYi|)aGg+0Ebj-;{Nyagnr57ud$spl+S8b4Qcv+$ ze4Eg{K_LRaY?! zez{vsInlJvkf<%Si>;A=PBz_=2J9x@VFzcBeOz42`tu`LcgQ=|Y;>Z$DsOr^`8a(L)RwI_h*U zF9W?>R_$WnS2z)Qo{Nur0KYW;B;j;4?dH(Vqr~g$UJL1}lH;B|?D4&1x&w|}oI;a@ zJR_&EB{<^+KgJm={v5ZR1isI8*i+M8dxAJQ=Jr0`Wp``=r>QJjwtzi>PfKzMx^nLv zYANw_(B;feoO&KlmmZSwDj`yAM$bGz$1Wm@iK9`sMT#+^X#_>5xEI}}{_x`w`4l>==I1?~p!Ko1gg(+4|Ve%;s9hZ#TZR9!C_(9h##`64EPJNG_O z@gwh&3mU)Dswu0qpHN2szXLX{*R1D@6`vtI2NK>IS4P_n(woehR|c*_32SB}X?{DG z(6-w76YaT(Cu%;{dj$ej##owc!guT*CnZ)$Mns33Gc%iMW%krKtptlh- zQ;iKO_%dx>m)|J(kpm&%bbUYEMI(4?lN^d#I)0K_|ABt7e z+EezKH-1O^f6%{tHOOuJ7hViY%B*WA5wrTG;A4zw=>nt7I)6o>9UcYz|F5v-E%F07 zk>y*~%f{=Ols`x1r0eM10y?d5U8=Oc^s}=FnaIA|cyzZkF<9_PlVCX6gQ4PU=;6aB zD%}`j_H-(sr~P*{c`?L#mR+DY;yThW4wDmwd+|U0#nJoJb_|(*=n-&9`?I7I>+rt ze$4V(`VoK4#l9%F;)}POjl9NpCf|tGkaNHF#vTI?mB@ix81EM9u_m6Z?-;1AVheAh zu58_Ztd-s}X1UTG(k8IS5zqBviBiDO!rZkk^!-19Rf&(0*N4;6$jbCdWh>+xlno-ethH7CA-#vcYO50d1cTx| z8{ZB`)$cW$Pa~&$!6PHYFTf98R}Kcp?j7FD{{WuFQ^oE-_fxt5S$AC!qjk{T)AaAB zd!hYX6Ky%}y-8D_^W@R{3%xmUj9;XW;S1(wnD#FEoA(6#D7~)i(Y{fozd^m0NBh=f zh+VOMR9N#k?}zs;ut8)8I`2m97p2p7+Plbrk8Ri#@{3q^dh6cY*8b7;X6+O0`)l7A za3cF-JF@E)aJJmQD}Pdq@ATHa-Zxr3fq6Txu;vc({z@6yvYEg1wRcEwg5E5~@}Q~b zj^ow7(Xz|gqa0mWGmCVUe-gQKw78k^YOl_Naq6eg$x&eJ4~&Z`r!}Q^4YGpuJW}h` z+4v9Yz#F11e@r&ze{bM~<~L2F@0J`dW@d-{h|pxZ#EY4+=2W)F%mC+Aloido^ef%z z82F_e-FHm|=_3!)I+tKxe6T!a7l#LJOeD>p%MW+@#HD7byCMoG}Wu-Upy%p6NZr{7Od3M--IV-Q)QyU?8FK??uT$7u zgUN3p?pyRNz2G@~mNDtOmsh%b4EflKE^LPGx31_P)&0=P!?saiRYEIUN|kS*+wNY)1Uw%#cCF2MH*yX4)+ zU1NH_^`1e8pXb~&mS>A^61sWE631cR=lV$_^of4D#^PPydvs+j{3`j{@DgK$H(VKo zo+dm9rcwjrhw$i1$+#|OaS(Mhl5M(RigCy2@TtgH1^?Fkn9|CRRCN4@n?uw=JU zMg1yZM#psLnEUrvPRfUF`m(m1TxdT4%(^Q~xcqozr9CScx#wWc(4=IDE9+ex_fDQ< z=H1cSzU z(y`qeI<>oO@saIzqg~lX%OB+5jDNnt$BXVd5S)J(bSV0AcDAib{jg&nSDHRHE^4Q* zyQt^$`$+OxtJyy*NA{0K_MeCBAH!O3K4*4<^W_uq)`#|Q75LvT(Dw>-7UOJW=}vsQ zb?gO|P43IuA55P7|1tLN@lhAo|Nnb8T)n;_x7|&IO#m;kDlH(Qwrq%aX%&`$_x8gk zfR}1(5Q=!IY(P+pRilVXRW?Diq!+D%NWE=9)T+G*-nDg;aIsRas3fT5`+U7;-pLZ8 zzuzBuWM|$pXU?2CbLN~gXJ$ly^tu@1D7ty^{C5<)D;WQ59q6CvW-;>G;EAfba9s9v z4s~Pr!keCz9+BJFfnJejAG$fE*r43TuSmy8*B2W9+Ae*E2b+2w;(gz#@1(0P9^|Dz z)_3kGu1W|u-igq6(zWvq{O$U_oBHz&{8oJ@-5fRW-_!SY(!58j`tRsF>5`wD?{DaP z8*xbo4D#S_)_2nN#}s+#f9m@#+TS(UtN)U|lU`Rk+136@HFH_#WX9z!UnYLdNx-k@ z_X+qlq4&)hcWAjLbF@!O-mv>ku@?)MP0MSbWd>ec2`$?gJH~j^;DZOZ{g->Hvd_>o zzdfw;J!0+Krzj^oW;th5s-&B+mdaP9c&z(NW9`xlbta|ctzq=Xyhp5hFVw;FjQw75 z){VukVpg5@;`mCwzoRvRIWze5;M`LB9lX`4I~@EJFSpry6D7B?n0(FeByaDA`Q3qS zq_%Iwrb;4jr9Zafn`y>hR^sHm6lN|6r&iXh6m*FmYUnba@vLCI5KWG?vQYE$Sm=^# z+Z@T<&!D?j;lJq!=3qy2&(W>PWor9wty}z`A9RTS&TFiH#q{@n&S(hVB;%oet3Ml| z&piCbi6Cz#K(lMKzLjK+&##MJUq<+P%9r4j3ofE*(?5oBSFY}uP+VVrqt3^n18-6r z_5Al^O3UqdTuXbh2UJ(IQN8+?yT(I&6POO)z$;N;RN1k~K!5buH7)lRyY<`~75iUt zd@SFJpa*tx*<^gI(fud8&wWtr&YP23fBMX7)8AukKYYFOazAbD(m6Km z>z%d7ggw1;82P2cu}isUBDJMB9wa@ByA?#kh!4ZsxI39?y zmxc|RCST=0dklMoxRKM~ujm1G{#;b-PNSV{nQ|fcRM<93;L8`NCmJ#yYwEwQ#3sd# z`JUl9>nR`D)UeIPX?fcQ*7OnC0Uw)Or-*Z0g zkB=+0r_$a2cW@$$u|tocT) z*ruKERq}&McO>H}y0-jkIBPbt z7cGeo5zlTyZ1BCRCW=v`!Mt*l~bLegH73nuR7e?$pJSV3CHiwDtlp8 z*=G+iWykHN><=8?9S^%VXO(?0tL*e*Q?{k8!wqb6+$g>f-6`nf@O)O;UPY$t{9V9( z49WIfu{$@bY+uR_v-sX0Hf2k{>~QN3aa^Z3?EWIF?Dj0UCxuMe^`CdRC4B>KG%p;l z&MJF-R@p5Drfl`j4!1myvbkaRY+Lpe%872Gmq*`xQ#SY+IFtrlXF%9Jow7lA=nH&{ zT064u)^tA7b86;%-yYWfgBd?$@}@m~%iFy1=ePdvocy>K+b=&p`dXd#w7k6*`>wU# zq;Fv#@oV;6+Sn6g9_TE@rorrq`?3G;Fn4z4^lkhcePO(Kjx}0yEQKDPz)w4v*zaDU z)2^z*UeO-aSMYNALq-Ss4gBoS`61gXUGr9zxdR{p{^I8(>sTv(YQ2Y*#Qsb|7YBcp zV(V0JpPDKQi@oH%C`}hqw2>07tzm za}_q-TJ}nNQ(kX<>7Ie8-aRL81aM>nJ$sj#XBrD=+_^97$M7kx&wm?4I<)`Rmv?Rg z-FYkY+sd2tdI!wcsYTNT;0zCL+KNsu*wXEV`*dPXbOxg~PdZsI&SK9YbPM!ObGE=~-wr*u@eU1dfRuUm zIQ?$Hzbqb`-C<(En^i_K>FU@z4;FDef|bN4uJ(oJ*|e$l-v@RQyK1mgyo2*XS5=|U zsg3v9L+Gg;gGYYj`|!~@S?&4#@?b*u&iLdJqHj608wc-pz1QU1EjlCir$>z3Kjao8 z>!WtfPxxuO=1;e2c*yv-KMZ+#L@xO)ABJj5xWh2{U~&ADn~7=VJ_zx7KOcsL`4c~F zVNUD@v;G4Ea}O}a?Ff1IB4)5%-yz-U6GMk+o`xQQ4f`>=Vvjy^WW0Rlsee>@w$=Du zA$J;d*V-|e|Nc5Vmo-moT?9Uj!AI}Xj;~83dH<`$MK91Dnb=i-<=be==uDf|`F~jb zi+Qw~c`w+Nig8R~k0#~Ec+s@&*>yWZZcewgOL&|^`%z#fo-i`WKgSw?$2DJ?WgF05 z{XNBQko8-*`8=hVbe$1MuKVt~P0NbioyeZ-x{_7m!*`IAf}f->S`T;H^LgTnj$Ehx zP|F)jEnR%xc*{@Qas0PU`@B*0t{KOh$PfNIRMW)0sLtKR@ry~nP5h&Hqt=IEdE;3> zZDGD((>~0mw+zfH$gh6e@LOVOaeNBt#9#KNf%=L(8-z%6CGY`iu4zRYv@GG-c@Hn&jF_cj4P1 zPfu3Agp>LyeM~&|40!yIdOG(x)Z!3>#+kn3_PIkacr!K-zTnj2;`pB58XdAaSj<^U zWak2>Zi)B=zVLB4khC8=?Uz|hp2k<@+TkzV^Sy=iVc^n-KdsrpS3~ip%^^3lVMQ}ez?-rJ78Oxn?vbS5?bhPff)b$_A`Avc@es^om1+o^ylkDbLt!l z&4uHOkMcj8ud$(oo8oR1XJg`2xZ8m?fYJC2ao+{_*tFKlhSWTfY(Go=#^!nznh4K~ z=H+0sUmm;#n(6M{TZ(J`!uK!8m;KudIM47dbL{t(Uc6Wf`3~*)Yq29;m~y+ZnW|W8 zqrHfA2|DcwexqAnITqbOdV%6AyjV%1e<-m>*!%dv%4S2q>-cldsh&&!-01J4iyiKu znGQ`qXU@tGA^T496#7@LW*&OH(ZQZJW9#St+2$wM>sB4vmKpf8{SRgz=_b~0KX33K zO&<1BUN6oMF6oW^XUl&`dHH)q*L>|~(6&ea)y~X%OaEHhf}StsQ2$!<8~)z6+!cJw zP)<6@Y<@4tPm{TGd1U8c{IG8i@l5l(M;s^c&ByU4{GQi`bBFZP!}Y=CkynB5{XT4YnL!I{+G9TEbc!goymzdI$zJ*eD1f zu>3y#*8J|VPmB2G_h|vYi3jbPAI~q3$hYD3>H6gnt;Z8@GPtLaU$LphHRGNM#hba? z^JwKGQ}%vaVoj$_nPh%vczZI%f2~9Q+oWIRj;bJiVe+wkOe(YUK5 zmsI9_rzYxViXHMx9$CG{Rq-iAActIO6&1_0FWmD~9g2^8~GT zxs9h{(2M&6quNP zpN4a!66EbsuBj@tu`;4MjhBY-$tW0`_0GcHgp%s z7@hM{zs8?j%==fg$$!!4?^$g&{nWJiLJw`Wd`Fw_bZhf7>gznS_C?-cEgWA_j2`CX zrJ=`QC$eLM>|slf-gD=)rKTAjc$(G2rclqdg$sp*b3f|CljizBV?WY5G=Y%XoV!F7I+DzT^m$74R{hnC zg9DE!eLLwK-b|W*KqMZ(29YiQ%0ldi#kL%GI?GRy<}T9p#uACkrK z_ux3j;+WAJKH!*QueKpp?3N#&+%z2AW{fV5r_Qc)Mf>i0zs5oIPp>g|@zfq``oW%{ zk+Xsced_Zg@lW6Z(YgM|rXQni8Oa)*Sz=74sH{)txa~t)v5Dj#uRin|_egc1i^g-o zzrT;abY?%r^Gv0HT_w&1bFHQRpU-EZjm%(VZWAe zTHG5uB6UWkw`cPg;I+_>{CA$t4=(3gTr?M62bRtZi;qi=D#q_&U^u;utkn4b_iM{j zoKdb?V)i|W+p27}`7!q5o6F4HJ(K)@+kE^Cqe|NJZWQ-gk+TV=H9pt~_ z!zVv5PxoGOUnlu5`S5w`EO59PXTjg-!zaF>_At}#Yve!U!{-gEz%6FK_6zcP@7ALy zd^@WAP*Xl1dOhmH$2P0)H`HraXPW=y!$)2wDy*Fi4Oj3DUeWo;PFZj!dE&=n_;G<9 zH?2RfI?pM{Up$ct<~z7OAv_{Xtx@dnb86{S1y`Pg~*+;tsyo^A0ZzGbBL zeN)Ja`Ov3{_~&!r$CZ&{SNpZi5kvb6ZM!KeD{6O#qB=rakA}$FDHhp56FqqOc#BB3H}{7X3b;a zkDQoagq%1Hzgu2$&AWWpoYdU(5B7savoiTKy2%OIDqDGXQ*vT^Pw+#~ zhkFRq1Bz>&<@;W9ANc3_@R3`dzXtoa8Qh*Jb7ty1PYXKwdgRWQN6W`>uAr=SMfsQt z=;6HyN}U9K=*?ca&P!-alny8j&a1hH=NjtD->kKLUSDTs0{QfW@($*1CVr2|amGkT zj^@PppIfG~Iu9yaPG+G47o}`J^8aM}3H?TvUJ{CzOr(GN71!KEzU=j$&(ObQ z@6ho5BKXSfK8Ma8CXfp{)AK9V?$`4x-L{fSH|99&nwXnWWZyh&tsrNcN|1*w2O}4A zkdGJriV!08dF<=pvWB>OL_^uf2CL3`G;O|32#GQRo)NXoLK(O zwPXl)j1fO2_|HDXSnykZl?3xN@hy8mCGQRL}SaDowjFv(62{QwugPWzk27Ld_L7#r}4x(i>Cj(!N?NH&0Nl)xsXMa0v#+BPeT~0Vux^K667Z_{#`l#jdcVjW_I}Y` zXE(;sUIy6zqRsF9(a`UnZuEQ4Ph0x6+H{Js@#uGmq2F!fuRkPIQ+_G*+g?<28RnujYmZJFPos--YX~_z2&O;aRWrld8D)Q&I7RC4aj(+BSm+z79k~g|T=>~L# z5zwL#+-0{3UITA+dUe^4^?5l1FXR8-G@5e4qjc*aul?7*n&i&?c#;>Fk&Q>v$dS6^ zC@;TGfcY`Mb R#@XVO=A4bbhbZgg)t~Y88SE?zl4trAGe(^NL=Vt}{kkb3*K47M8WLpD7uTnHZ>h^DE%@ zC!UV->`{+uo>)Gnng5*kn5jE3GuJPV2=`gUnMuCRr|p3YCidARvlsVT(LQe;E~Q`Jqh5ygc7vzdaK7nyED9XaW##65>5^s){kgM< z`m&M#%{i(7`Pw@e3Vj&UefA9w{a2AYgTDoq&Z6ra>dUXAe%5n`n)+SU#+i5izb?A% z>{#o7lh$9Amn{PQmt)!a=w`IePSqAmB=UJPv$+YN1JyjT=(1+Q$m zGS>3U1aOYN*|SVbY&G?_KEJO_JBIq=Tlw!6LSM-yUoP1Kc35MTI0E#G8)h3orQ6Y^{ITT-dHreX(7Idr;2KZsq9Ppj%S8( z5*mpc%0 z;jDqRoO8@={64;fD7uG!AI#jnAbabV znDiQ@k=-RW{TI@Xll#)(k>S2aG~D<>;XY$`x*fZt=woc%zI+pX z-tx`+g>H8_@I%Wt8u#0|2Tt?2X?tNjdmef7czdCn-u;PNoHgbp%%MfpDS7t0W$U7c zisCCD+I!pw(=Iw)*F5s>Jur5Lw+9Oz@^}9lnmnVsa?k<&`%kO;vaSupj`>rOdmi6q z$J_vo6~CkLQ2JG$=J+`-rHtPzp2d9@eHOX2MzHFz;l)#;k=9nmXw%>W0&V|9ck=F)gRb5>3QjY@N#|P} z&P1IeR)dhKS`=5ZE>6m&K4xL+H131X<85WIu9yUdnh?HHwRe!GcrPTeE6O~1V( zL<7nw9z?i{=Sv?b8eWo*oLN!i?hh=*BzZKk->UfL@U0i$^u|-y96^l+Gl(|#cvp4eC{i9n}P8af1PFg z@%b_mFQH8G-Xix+zWd|zQ^qI58t>B~S8a>#p3Gyt<9~MSpW-^R`;-Az_dc!P8F8z0 z-^#Kg_bI-sPdmUno99N`KBeHfe`e!rd9L9D?h_jXeedFZdA>iFUB>ol+$Y>qMw!gg zB6kJf{XQLLc}~0*ryb>gh8?J}Q*4#;KjOdorZbj)-zA$op6k}>$B4XpPkWLN18ijE<~{~%k%yGt$pzTA7uPg}Y7Z<}T= zd3Hh7lSb~{M1Jt8!kQBH!&0{txfhdun{)qyS?j~Fvh-O$ZDGD((>~0mbq3}YiDPYy7g$@;_e^p( zK3(Y9Y0^iIht{$)2GNyy(rVSVxL%}((8(9n%KY0TwCO};s;dyFR^Dz1{JY{1M8wWZGXdFr~Ybv)16ZC zHI&e{|NZCqlT+wm(g_ok30&;&EzN2BtLkC{dig)o+sFpyYVwnujZ%IUXJ!5TKa;OB zQa=Ee{2NK+zQ(BG%A(E~`YC^a-uT6YkG`pH5Io0GXONX`=oj9b2LGY|k{R-u3SOBn z`;g~~$@j*84*K#2r|w4Nc(%Wfwrwb1>z&pX{Vtu^MGv=I z8R04X_RGp&e;IP!=J&GsyRZ$3mo3y;fF$cLXEiIer_f9r&EO{a5WC#YX^k6v^$z(7 z>`o`+)GZ)RNo8u_8?68gVxo7bGOXOwZ#TzQ47ytS4^r1PA@1jke zQ-2@d_H778oA%_<{E11CpOlI6ld5orA0wA5uQ;owLH1LAgh%r!tS)GWu4# z-l?0n$5}OReqhxcd}l{l+dF}LoVVT?Bl}VEJHc4C-#vap z23J{rQvUIlt{IIN{Z27n!FLL4n$AMM7+>TT^1Yh6nvaaX*6O-HA@@Z`hcm{3lZxEk z=#DY!Y46}m@h-ScB`;g*5;z(ijmBlAdjG&Yn|>6G)uirE^_ETNhF8 zy`Xa?ck&meBv)*#Xo|T$)N9woEo#n3NsHfWUHKsL8<#*sokz*fbV#r9&H#yak`p@r z6MK(XP|7`yFIMs}{hyAJ-P_o|TN{1V#(vz*#vGEJFqV7Hehy65m`&=l!=3%IDXR`J zILxv*e1R?66An@BtAoRx7KhZ^7Ki)skD@EwHs8({ba%~1hyB;VZP$L5K)+}hja)gI z`9GZbPdV*1Wz*+f@sf?}R2y%S7H+k?>!9@M;1+!Y{fsfxSo(YA3C6bj+Ud(H$)(ua z9mp)F{a<^y2c5KHraj+m);%t=|76dud&=k!3EPjTwLw<+X={T#Xwxa$)_zC*nZ^b= zi~MnCVS`}bXTD!lGlF#NsC{jaG%_!F{3LhS0mcs}*)3gl1b4Z3I*x^(t-n;46%DT? z{vdixQOzNI*Lcd$%ihow`l~xFHVH<0^dxsi{~~t-eeJHdum21KcAxTF^TUTZvK!3fy1{HZ#lYN7z3NkurK0hnMe%1zcb@-PV9pk$W>0Y6#P<2F zvqkA6t*`Cth&zqGYu%n~$3p8u6=RSgraK3^odzv8T6}XUlj_I$k6#wX%Q-jTlorKT z@GV9eofjzw&e{i!E|xlclDoA%;`#D4#{F%X63YCUG6|jkI1D?rEz%<&#K1u~9hOxu zMLpIH;p?4Onypv|&MU=+X-`b&f{=~iv6OP#kW&HqBEN{Zo{v3i&*TVT|5xKbaFTb1 zLwpj@+hN4dN6}Mbx+kR6&}bt*l~!AKC+(^)qESdRqOAmNA*(yjA0@B><&&r{FRX#D zHpvHjd(_*r8#6EHw2$rQ%>3{E*fIxB^3LNny!->t?oFkKxQB5kt?<5pa=KgY0p8EN zkUI~w{trEAaNHX!&f?a;jb&aj*lmKJEh3o(AzbykmNji;%LH^B z&UpROmeu@9KVbS#*)@r_xbbyFnLE4>qj__IExUK0if*``0=8Q0z9{c~grVaeu#-;)Te=7Oag{%*P|5e02k+fvC#`;*sguZ%jYINOw{KTr+ zAI7z3v#B#Cg}9-Pv4Js3@Cp(Kpg9qv-;}9D7v#+mr}07PJqe%F7x)58kd2~Al0C7r z+T(5^bM_qW>JnY=rJS*8^)_B!`* z3`u_&ao<4K?@b6%;%{?PZ1Ye|EL=DR1~4rDKp^;vXw7^~ZD zAG~oo4EZ*Ia$6(r<>agU{opA%BAaGRhrQRG{F2in@mDMy^p=t7&2g>Wm8JZ_OP(*a zmwe^e07>{(H2R^X$1Q?M>`y(h=+36NTmDOJ^Aek>^1yxqxSZGI4Q_NA>Z>0K&iM;Q zlCyoy+!v`hl&b$w7di~3E^Q86`DP@(fijZ)9{)nmoyc-@+&sUGbcq>nMB=U4<@o(y z%H>=9F0^AKc^!Kv?rwc85*H6NLj$!lEvxQ3)ay$<JZ#a`>c=d` zS2D-w)^=}B=d(N5r(u3Qg`C!0ILeNTzn<3kX*<7W+jQsr`nVvjn1mtZw|rbs6JSkC zyaQcH4+WQ&X--{hPOmbZhmO7#ar3@yE}*|@E+iRGkEZ|Vc`n?mzEO58{n1(#u=sdm zv>*4==Cc>VS{ZvI;=TtDP84m4`EG76a4WL-Zztcxi(Wr+3*%Kful!oX-9*01H+@s! zj`sNsSrVl$qPM=4d|eP9Zoeh@hFq>JM8EmI{~bOU!QUJAi{{Rn1No-5>R*n#72G=_ zo`_-7P2;!v>hsM7^eyV+%e<6d^*La8avOalNBp(IsXK{r_4-7ar}>^{jPXZhy^SBO?WEn_Y32$+Y3G-cLq4W4C6}U(GYogxgrX zbM~Eb9J)78!yo;8#GQei(W4w^u8DV3PZ`+5)nRTJn*#6d)y(>cTgo@Z zb!d*1(EhO+dvHrXZg3mFI^z2BA{)2o!A9(Mn3yaZ#XI!V33$T%&cO`Q#nK49A1$~fwM74f_J z>d&Pg(58IA*<-q%yLBq?V=sW;%{zN0hUZJ>zjS*)Uj7SWM&#>2_wd%Q&FGh7QgL?& zdAeIPMOwbJK#sHc<3(nVO)^CJI+v9SI_SejqkQv&v;mK;ZUC0_qeP$Z;&YtPOD)0Nmx4LL#V=gLxipO(-|nGo48N9s-_36a zA0~2pvEoNeJG$2=xACW}Q*VHi1C6rvUH|-m^3yrGFX|~`*$hoQy^Y_BYf_BU`S7=N zw8^?#5tz4Ieor$;%{}(HjSXFMV$^*6aN0|dF4WK=T~BY4@Lo4%K9bLcHurslWvv&x zq47xM4{`nXM>Q@wN4y(c&WES3T?>sk^RStCB;h1n3mJR8o$};@xcla9akqU@+>4ct zv6oOQx^q5n$myIH95}?=gVcCM`?an8px(?AhqG;tH$DZ8&D^h;gI}@4lQ%|wJFE-3 zcabQCKC80JYc1Y-`^l?xCuVa_Z|JEzvkZPw>>BNr&BA9Tm@6y}nVSp_ zw9&cNU-F>Qk4Hl@`Ai@4=1E>-e|WirGa!lJ@@3lJCFTvC_LI*#c}8yy%sPp&(49{7jhtoBIq(k7I_hrmlT(I9kHNQ+NAR|HuA$veTlx8oO?S%Al#!o*BtKY> zZg)6x{+>wuM$)?(f6=|(hhbrE@zWOO`!?;vY`WLLyp#Ou`wD8RfSJBK5}!@FQzmcV zE#?)0y40-^S9`ySp6)9@!TMk3+jZ^QE`8CLKLeq$&UUR{$oV#CImhB68RZ}0U{vDC{6uup)GsdHd=eQ-}KF+!+TBXEu$uzd zD$d}d{|g80S*UJ+^OyJAav8;SkXH`BO+=SU$o{)J?v9@u@q99>m(3^5tP7JRQ^DNox$58Zu$4n8NhD{-#uJ`eH^gGtI`X_+q!%1G4fO|){A|8;ZR@TUYmu# z$_8f>M`z0;G`#X@?wHZH`8g5KKOtBv_*R;Y5B$y;ubzK%q^9X8eBz5E@s6uKAMvK@ zMHVLWe3Pxc%JBuk@&~d_wZc6`1tfw-@(0pek6Vid43-~8;bne z+K79aEt{mQ@LoSZ;%Z*1p1zmc@6g^Gi@=_+d!o%_97lO{ppHieaJ~q9v12PoT^e_F zes4Yaq*xpLxFvXG&E{ViK5X@LBx46or_4;oFTsDUjRDrk-~P_b8;!B<1{(JV?NvJ6RJHXY%IR z(tDGeT7{q13Eq!&kYz2?xX)o*soM+r>&q5zXx2FCb%GrN?k?ofC!RbiXxw@o z_#*4HuRmsb+&%l8xVsx!d(H)M7k|#0V-IphNtdOMSEh8g&QE|xdBwRz+1r&&ZowBg z6B(rWl!X69JN2OjT1v(zto+O{UXuH)n`NTKz35|6>~3#tsiX1mWU+XdItj^cn|}g* z^uJxx*L)Yf)J`U+s4>Z%f@s|uss9PzowWAmCq~Au7<@&9B$#adH z#!_Rp8yibL4(%HX-@9dt+V$T%yVm#ARg|r~gnsz?RTFI_ej0bx##Z{F`Q8T@8Dw1Q zd~AO5)J}Ifz&cy`AK7&9@S&`in#XBmNAtF@`$x6Q9!~09!-GStE+!bl^Ixh*`55za zCgZ8KDaCJ{o7Ea4dH8`h-rx2{@{4wzS-0x;D+)ZFK>k4K0}1b3WY?XR$3o+?`OA!U z+K&W&(v?5S=m;77gWHxHe^f4W+h2?F@!Ou|r|r6No=t-%d#1!SUuxEk{^U1YYW)oO zZ?;{<-D}`*-izD=25km&w{|moI_8eUyvAKuYTlslv7V^?hwn4(r}t}Hn+_J1?W7L0 z8&wPc#&U?sahyw%=n&FnG_KzGqJyK;y>btKw+C|} zXQBo++#B}fK{;ja>Fd-f-dZ|BHh$t$y$iDxUz_mK7%KfG{p2kCE8N+#$;Z**{)i34 z9(Bi0c&6#I@T30*zwa6RN@-iZj(OKOGp8jDUM+VSyoxMdI&-ghZ^?zL7*lUPQC_o__p#&-%>sme2m`otgFZnT~n98^^dw-&n|a`+TFbnJ@Th z%Qr9EwBZ}xPdd-=&DG?$oCn|V211H^PR=3yH{w18v&M&Eb(lx}w1v6WrhS<8XB(Io zkU#DmbQry>a2|FS=}sM{0y#Y-P!~Hp;+~Bi)T3RA4(IuQPcZYgchw+wg~xMy`wcSp zLqE#Shpx{;!;>sNo*u)SOfA1gk0Gu-!yPB3e0zd2is>w`E^rsIc6nn%Uyil))Q@r3 z;A<$tPc|ju=991TO>4sOt0*7R{3Tt&8`yJ5he_-0&Y`)S&4X7G#~OUMO~NN~{vdaO z#o3oPtHIY>Zv_Kh%t!W9Z%t~XskiamLGH9}bsnUS^qk*V+*ObH=h>6JsV^I2HnOB; z8gKlNFFv~l-B5N%5*eNTzQu|Bjb{zo=Zf1DM(tPsQ9rfjW@Cw;FEjeNAp-|af zdkj6aXRh)-?C}%eE88#0AJO?I)PDroC>+!9!=sY3G#|?R z92;?KNbAh6_YMktBs+Eiaz^yNR(Oy%o%H#Zw%T_}v2G^(cb9aQlKrHelkGW5?CMzq zf`; z&N=Jz%;)$=GVlGLFOGC65ODhA-AAFV@H54uQPJ<7i7d+@+S^ zqP*{%*U_=oi|e{99RCIWuo!xv(t*pu?!~0j>}{#tYTBuS?l}qOI`L)FGc|q**YxoM z@@DL}Zy!I0_6z8z&hl0>CxOgGcOyv_C5Dq|IWO}&}bt(qw ze>&-X*1w?<_fBk^?_B?K%y{(P6OQ+^{zWyPSpU}JU%Q(zxz6IF^)EG0atr@AYjCC{ z;#TwRR`DleQC?QyK4c0 zfI8Xhjb!^4VE+u*lQ}alc`JOw>(m?6`7w2Fw&U-wQ@h~hFWV-%r;{(d ze3^ci&o`Vs+wWex4sf>4Tc5BQMUSd;3f#Nk`Mcrq+0apYqpUUdKHE^^yL)6e5wrd9 z*}G#_ht!($EIhyR<8Y_!(3+!u{TUqn_K&ytyldAK?MF|wIAu87qBZ4c@Dk4b?6`^N z731*}KW+JQV%E4y*RS8t@aLW@;LrUFYHCa2&jAtl9nxA;bk~WQtND!|**2EgHRYeA zpJT3Rj{SeFDIGZh-t!9}qw%vLXD|JonWOL0PWBuf+zsC$d*REwIK2(No2a+GH)|mK zSTSVpL!_hJuOZp^d^ec;b%S|OH<-0S1M?~BmFBSD#=dOoph$cf>CQRI8liVX6Z=Kn zKcl1fI7g9t(oxgf4F8S)Z%OBRmpvawYiud|R?>^}$orkeS92o6yBF&ZH+x%2G0da zEhU}%TE31m5S%91cB;NQ#2xw1iSByaR$$XaH%)s{*7sI;6Z^{Z(Fj)WSoyk=D0cZt z@=hq`^K7aMklt9rfPtZvi%R(-+x zP_{e$E)PW9fJ^B*2^T3JDWZ|{)8h5hl{L{AE{7pEnF-h8X($HCTa(Mf%`WwC56)0=4WeI3F1q8$-V~l^^6Bo7ynZi=$MW<>uEWx((-z()adM zywu%%$KLUji_l4~=iNWWIQIHF?8R`5Bc8H(tm7uY;}`J#1>k?7Ewg2}DO372v67cN zZmRVVSNG(o%!9Vfv+br#keJJ+m5!SxeZDQz*Os}z&6H^&p0fN&$BiQ2D{YzWw#;?A zOqun>Q&#;4IMg}KhqJ%IdHR>8OoQGx`5$qal!@6g&s#VrePPPXC!VtE`vEt(D;ytf z%N%CQ4E@}csV1JX{vVWiqa=Q`j}LDodi2?8%8VnPvV2c~GoIo2Fk9vn3unuxrc5bs zom34Ex>3p$`}kNm&wgUc=#7(-{{`J7>qstTG=Bbl1sd1P^Ak~BWv7^U%r_Z3mFXUj znL+O|dwA^saNbwve(?uvTKnikH^aEJSo!ifXB~5-@19fIx$l$U{xaQho{x|6ythzrl;)_wP2x9{BS_?+td{FTQ03aViVgHO>>Iz&*+TsvNy_7E#>OrlHVVI;`;4+P>tG<;%um z`v=hPxYy~c?kVM`&=#3 zi5n)metT+5c#7YIs~PWt9@`h*YClF?TKbWRZXtDKLk-Dle>=RgH4`Szys$C5{aa{X zd@%=}R-I#@q4cuby>xElkv9F^eyPV-v370}oitu+?wzQ+=v=aH(kA-WLl?bQ zFbw%${=HIH{DW+6Oi@ofiH~tdIem~W)PhYW9mgNb&+&1HuI9Z1>_qC6l$E-@fhD{J zOJkqHh8RJAplxIM!EI|5XD46W=kSi_>#PXWjjS~`d4fKwj)`9?f8 z{)o30gYW-|KjF2MY-b=2~PwB~1tpLe1&vl;*7;T?uY z)9AeVzL~bX_W51lmyJ=suQNq&0STWMg%9m$KjHSeiSCvS0p=uesPwIN6tV-lWY0Dp$Dk*PB~f19eR!O5Ggod7QwUyy%Ly1oVp{dop9;-64TG zbo))Etl{u(Wp84qMPKgYS(`bse9YkC<{rh&Vf?1A@|i~AdrwBu56LKxUoGq;bv0*R ze{6Xqgzxqp^^0#A=&!wc?I(y9kL)pev&t!bllqN)6Z@=VjUTUfJ$Y&7h3sqbOeQzE ztdloAzlQ(T{8Ovcrgt9&Jb5PL*TQ{}W66_Vs<((V_EVj}CGry_@dr07n&_7E$2?vW zV-78(??d@dzcw`;QtHXXKAz2<*O;bH8OCrY<0BrEO^mLySDljLQuk!aYn)Ub`?gb7 zF6T^VEAJ9=&*X01aVh&(W9-|#Tf93IH~ju-&RgxAytmzZ*IkB(`u)oAWz^cdKk?JP z{%_OptvO%Sm>*Y6;-1;)|9{A@2^k+8dgHZ^X3yW?s18o`qN_kO^{K!kW5TH8jjCK z&NYzM-a*RdQ^w1`$L24y`3al9)aEa-`B7jB&aF28W}Ba;|H}W3&A-9s?}R3^4`^E} zT31~=*$dP< zy0bs~eb@LlJ#Rd(47;t=$sUWzf^i>v&%{ja4KuGX1WfJ03FaSwskQOkUTte1#m9`y z*pXqr)iT!GXg_hKX=i1_zHR&s_-f}c`l-2^qMpOr^bEhZ@H-=!H)EnJ8R4&e^-#{-$tuspXl^@zB_~Q#V=XL9>Na!LR*>hx;x<&=*?Rmk0oXs z{3@)zAo~0KSPy=J^WVEW?i9Zjil_OmGmNu&+jpZ`o4VZ*YJ9$ui$l>{xa(lbRDPdI zo#~|eAy5B{Ts-1nXVh}??VKm3R8ybDZ{FIei+J^I!bJ+~gg(-uRn&ck}-yx*epo zuU`V)hE8Fg(I2fH8hdjGYC+>=oI4V|Te%xH7*l>hqeJ>QbRCB^D1o0ehVJjp!JwC3 z9m9r`4w&SBg0{A>{^@<)`K%*;{ljg%RI;yG17qla(%B(rg2k@e&10BlvH+=#xa0maplUYyb!*l$PA^%51leAqYq$~P$ng*1* zeYLg#dmFl=cYiA&Dkw5N={F)Np1CA~UyC;zTBjYNVlYJO=O(PY?3@U#l%ge&oOgu#>Izpu0Q^q zdscQoSg)yKmqOlHthD{+ryMme1T+S2tEokS7X*Uqu7b@ z7aY>L&d3&!y!iud&^NDM?K2_w9_u?xQtxtnJ;k)`$yUbgm!zdXODCTHzkFA^;v2uv zT@$wcQz7?s>T5kuqPu>5xfidq=^(zh^E-fDB0NrhGURTpI;3-NP`KQvzJmKJ=o-T7 z*A`~^%Z2gL7AAf1d?bRgb?PDR0{kxWGpas*-^#hb(Egp@PDP)t@5rgj8oq1pexJD~ z+5ajy30LIPC6dz_^kwAjC3C2ku^y`~-6} zN?av0YTv$sSC`M`t;Yqyx~ z?znUDotAE_8?&&_CUZ`}vnzfgU6`^HjjYK`rY>==f*Xbo&k^h0yt90a@ZQ!DyRsJE z?~8Awgg>p-4-zBMgx}#X_xeclE>lirf>~u6Y?%^wexwE5rd<{0zG-KjWVL8H&Rwvq z1s%49wzopJmV>d=@jthKlXS`!>~@Vo3%IuQr5t0D53OH77Ch?t#!PI>74%i>%_H>J z*RLPqx5j-kTCIB#;emstRhGv^28+GPWb4PCsh>nUg zoBu20+xr7+vF6WZ^gk^gnHH>TsR-8fT7palPC)OeK&zz1{|Fyni~ps5+Tveh)1CNF zF!&E9zj`9FZ-4Ng6?VU#*>UFx)*RVuU(F7?Z;ix9#5gKmr?ihVC2wBjcg>7r@yxIr z<^3Q$YU`X{&ZNOlIx|mYeq3{YqAkk%Lprk}UQnEw`n#2NRPPeq!v2b6gcpBC+$$`& z*y#m4%8Ngm3r|@!g}emvy zMA-#d<*uTf?7V+y?V*hbG}Ye1-AY5t0`ZvE9c0$SJ(w%G12KEwGa8BkIr@OzyhUjta!B4jc`e%lkwP)k$UAB+E_6!q$ zQttVyjC{W_3zvoqSa-C4nFzZVDIeK7fpN+dGLK6qx_2VWbaqa6(aHC{@ib%KXq^4A zJrMZNyE10${f0X9bIpuX%|5>B`Tn{R#^nOOYc6%_->ux^k1q+?z2mxusk_T*OYl`s zdhf84yL4>v(x<=Uj#Tl(V00yT6dPu>em~7`>Fkqi|DEr|4u;uE51cZ>n$^2 zZSvz9I&!3Y1(3VFkikJuuHL=G@PB_xAIVSccc1R3Ew9FHnlUu;v&`^nM-BXcWPVLO zXLB>v;rP3x&*1!)Wb)_y&Yn}FyTLr68_bf!4a^UyxBhVa37oZ!CBpINNq6%90@hjV zJ?Cd(_Z@5&wG%`Cig~`xPd<~s*wep|1)2lt1I#!L^*$#?fh?^3@K&`Nom(O+e&uR?yt`cHH>en0G; zCmm?(yu^3$exlz*ck6KTEthZCbQt`X*mAS`qT36WYhYc+n9n#S9Nz%m(tFg_8C z;RWye(Pl4Syz9@sqv@BYUs1k<@z+{#Gxa>1n!Iw-zacH!31$`PMWnU9cFw;Q#-=_8 z8M9RD`e@#%CeB~BcW0RmDwEr&wQ>UGJRdK9xMs>}&UKb+Rk^~(Fy&6790Fyv?2r2ac$FIzeTzn^BuUTypGp&@}2xuF}qDxEX+b=?sXD-FBFyODYHF~a{0|3mzb4GG5! zls_cw=J8*9R{A|)xBQDwuG;*`1TO|md=LdM?OEx36?10HHMbjH``=||9%;Wva;K1S zINH(+J{T$A;ty=v$Q{PMuaObW)NSa?8Y#W)q_F!m>0|KEh-R-_xV|h4cY}GzUNCbT zt9lujFHDhxJH%`024>_bGJW9(|6i8}d0u;V+HZ_<>#Pu52EE zZ8&)ubfoP2#1e!VuSScnXZJye24rj1e(=W+!|n}y!wH0rWX_k}!umrW%h0d9z3keP z@&8%dB8F_fy+it$DZ7YqQQ76tT)Ou@dvoj`mx5RGEhVmErA0g8Ej@O9$suv^Ry(q8 zmZ#U}Ha-cy-gAwQ{FF@}Z9d>^P{nbv7a-X$Na^Ly48H0^|y2ik#|2F!hHSz}f za|5*fv5yaTz^osXA8(Q_eQY>>1o<_5*BX2tdZKimzcGKKZ%=T0_cA(NV3>=`7s%x4Nq=+ckNVP76>`tBJd=cHWT*TZzVUoqe6Mc} zxs~?2;s8~rITdoxuz6{C&)H9e zhw=A#7@4rz;S4kUGRk>s0_+aGY9t4_pWMp9?bJ{F!|x|L*WqU0Q*HWmtE&a;Ztz@eP`&C@^{t>KU9s6+y#Qyvpu&U!S${$)B#g_6TQJQ5UY9yFJbV)0m5&Srcl5^#9dL5;I;cCv!kR5u)13CIY*^C_to4UM2kB@- z!^3|hSmfvVur9H%sQb)8+@;JoC!RF4(7B)N`O$Khcb}>^5B28T@?g=9bOc`!^=dW0 z{yM=8(ci>Xv)ihXld_9NuPv<88!Rlz%6|a|g?o+4ZD|eGwGPRt3#LS?@ z3BZiu8>%hDpRm^8)7lN6r-8$S$dj(1cB+3@gfA{owv>G7ayoC?jGiTU=sP>A^PDLs zvTlU-rP1n!!T5T3D|0v#&g=W5<%+JZ0pefqk6MNZwe1v&Wopci|p(SX7K zeSAXlcel;yxbrObVZMZC)W3It?a>Gt%Ri)hNhG(L;mhRjCwS+hwSF?LtE05DJ-7d= zf2d6EX{$8O@)>8&cUEoPpP0_9n2zHa_skVWuDwH>k{g-JNE6HXhSJEB5cCobf9;0D zW2B|43Wvn~`{J+-9R8#-7Kg3iAe>iZ*}f6APyO?TaEAeRUP*U%IDeOcSAHeg$hXW# z9jk@ITk>Vn{}_FIShz8lJDAtHv$D*Sqq&WZKx zz7K3sIAXJ z?jS#Jw<%ZhK(QP4>oNvj-Ic{Ix>#kd&5seY?Vqn|`ZyFn(B|V?^4hBUIK;j-_Z9iD z8C%`=AXw$Bvm^QD*l!u>>*P0m7;>kOzZ?C+<1z9Zp{agr?AO1T7cUq3vT?@9(5ebfFoGKA#l2!ybYjtoPaL-Ju$5>i_aK z-;@*jA8 zCw)0-`3jV-BCWP$>yOUXZ>Jf*z*zZV@I!27uU&mBr2KLFlnXVEvgQ6pIkly=aLhjC z!i`7Ta?eoC$Dz4@D1I-r(*8Ja>FFGh-qZ8?B)j{jZ_NDp6>>}ctEKp(U}?>22%!Fv2Ja` zUcsNA*ND7nzXE!xjBjg7p8I#N?3}!A6}-I3?DGd2>wji^1lr%Y?; zd!0e-nAc~O#&8+)V~F;Aka@yMu~J?v7xB#n;H5fKB`=U+SFlIZj6X$jXcyx{mRv-} zthtIew-qZYUXv}b0zb&d%-0t$G4n4bInejyecnE4$b{T_`D?zOM*)_lJ#ZEpRjBjUdlI7wyrByrap}?}p|A*ROj7d7@$K?2bG24zBva zefnhq`XGN$HT%r!hqJq5^?erKsPJVyQ{RMB3Y^Bh6LL%N-8=sd#jm8C+ToDmsM2%0 z+B(R#@8cyr``f(roAg#6_f2K>E7(K%Z|V%bYr*#q!WTSZtlw9B2X57`hukLo?a?!kdeLX*v8QXKbJ!ocdcD`C>^#kj zE$9rb6~Q`xPcqxalMSdfe)&z2wq5YA;3*bF`bazV=A1miyO-qi@e_!(1kQqBT`;Ct zkzB9riQu&SrlPjrp@)sVrMRsb9a_Fd`2?TG-bgd2<;RroPva?BUY?1XI1S2aZfoB5 zSnh_s%PDT?>zq-I_jJtL+*A30V|=7)AG@;hyI|Mv+86d$z`h#T+NVp4FDIk>>OVTY z));4yvs&%849TghZ;iU4@(FIoyaQI{oGv{fw{gnE39jb1lcT-ooI1VV!unC!i})RV zPujjp=S21lTu4lU=px=&(3jX!ci}S8M>@x)cfe1SOE51Egioa-%4RA79%U-47=P6Z z5U(H`({XE;HG}U3qy@8ydd=W{0XofC$~E)z@ALg%jSD@P3x;Er)$g1;0>WqRX)kl5bcu8?Q`@3v4 z=}O5p;Eoy zdH4wQ-kJCzyWhhe4!J|Tcq%hy9jwvEWc9oE^x}B-clG;A%B25f`wcwxdmQ$mcxF6( z&*q!0*l`~3VDC8>&1m!aM|O^E!><0#XuHJkA3Rg>9sPTq_IeLbhL3!`L^7;p8uNe6-txl?8{1$Xy$pFz!GC;iU&+kgn z%kulq%MHJ4UJ2G@=9~{-WmIqLon10(1@N+E*4Qjq84F9c{>e8L#Wj}1&aZn-@|3C0Rd@0ZF@KUv8-UxFIVrg$xn}03d}3yv4WpelV4!Dr%Ak!=?u($F zU#6HcKh2tpD^J;*S2Zq0xf9&0>O$@S;SIcJ7!Qp_HRlzon2(R4i}~~M$pI7Gp*9Xv z@5N~@-bJ5OUg^cq+>Q>=vG zRb;_h0Ia#XdlNV%;3pk;1@Hy|U$EutKweZ<|FkgvtJ;wJ@z)0D4&vdW$&j1x-ocy0 z2LG?vm(8&L3jgvS6vwN0kC;1(+M8=b@#el}UEV$~6n~C-dQVKaOv}P00WSVtSAg+A zkE=BI|Bb_^Ujd!j8%0-6=b#_5$0>TtHuukzje^c+@wbaH5Y6|n{~$kh654{(CG0Ej zP9v*^Q3u{GYh`Vgj!!?!7PI~`7G<@+HMR(RGHMBNg1R3}F?R5B*`A^<-MGu9dTP}O z+7b@={Fm-&_F99DSCH1b0K(I}9bZ6uIvbK(_AlF>X!jg(7=rKHY<|2*%APyiNq;=v zq7A=~&E&OUBdRSnx+k0S{EEXcz6b3Kxkydk9-&wX04yLFc;di53_23fjN@=;K00^W?(us zq4)sO-FRiW@=o)6!NBFq%pA%s8^9bI>h~X+a5K2cj{=?7s64W#Y(C{B z3-IxkeT1GO|Gi{wDSwKwIu}07U<;&L&TzM}E^YmAaJ-do!s~71lKd#!?qmG));qsj z`7PMJDbpPv=|Pfj!ut!_oCrR%?fibAM)D`Wn|$l?jm>`f3^$iQ&262vlO9=%OqIST zf0z7R@*8?~|BX>Mjb4!eZ^^>%)2Ae5R7Yi1M{=v_GNXG+hmpU_IY9R6*w@qcoO3{L z6(FPja=GPi>Pl~|=6~}qqHeES`EKhasi!vl?^O%!ch(nud+n=^)#<;TVfM8ZpT~TN zk}p}3Mwb)4l_$T%leDLNr4t@qy3X+VGQWAl8Lnb;7E(|B5r6o8kEZo!cz%!asfG?2 z-gj}np10XQQ|`T~-E@X~JAZmx&4(d+3XW)``7B!2&owYo*ox|(%K9`^+4^gJ{oR~N z^4roLZj`cny)UNq@~JbteL{`nYy8$&ESCK^NeIayN&dhJg!?Z-4GjD_espYP3+ zqi!yGa7uMG4wlZ|8kuX>NS{{byb1nA_KKu0NmpvWq&Is(eO8_K8$;_CFW7sHI1pK5 zee)v~momVnQ+ADLZpn=+KTW;)t+_QNdh2|A$i0{JL9A&Szct-pw)tthMtp74KFsor zf%ymWTQa#dwYq0+T*$qFH1w$)!e7fY_Esx6cM{_q2l{rRr*kLRXI}ivMk9Y#e!TBn z+K1LL-zfJ2@gQRutKV2$q{~DLi9hO-7Y`KE{*OZLMSNRL8Tl7x!CQCTWMtgM$T-QS z>5Rd`|Cx8U#S_xeHK)${f4seUeALzT|9@u^76s)kGg(+PGXb@t)l>o!wK7RSA;CI^ z)TOmDlYm;WHWZhDw3)ED6s-oZSZvD#+>+LAY>n##Tua+eiA!5Qtxf{C(OLzU1ebiD zulGWRfc^CIc|3ly6dGp5~uf`SxCvX1v9q9w}$0g4EF+T3h2j2iMul;AfkY~+#Gw;BBARPXQUQ`Ka(gOdk;+3vh(=2;Z&6KZctb=s*j zf;#W@tFxYb!4@vRqkQC?kfrsFcq5c$s?v9www2r`AQ%z;dmE0l_o6$O`0X<#S_?!d zulJIVo$FcGCY@Mw1jY%RNzwXKXHzEg|MKvA)-=8}D%#5&(TQ#T;UHg& zXxtSrEuzyd?ncl$;4`9H)`&rrcUHP_M z$zH}Kw5@m@*_yq*-2Hu;>3L+1gOh9oFGi>AuenyEz882>esneOm%Dg3%a%XNOnB+; z^ADW$lwPxS_!mR=J?;b1z2Ip3b(zPuK%=S}_$|p8c>3C_u6(xhVt3gd0axb3(r5BaSFNCO>*D?{Cd0lXS~;ox(Q}D3dD8kIvz}VDAF9 z57>%%)t+EY7+)3R_WCUBm=)(+1&nnZoOh1lTvS#bK5lrJb-!%)ut{(x)$!x%{|E5n zF6i8eU2y+3ocVfcR8%}L8Qy}Y4)_%Re5cyZX}y>J$cBh8p7-b(7+vK~Ot|!pbeQf; z_c-{fTI+KAJ8P7eeMH{I z@6wi@y}b#o#l*9H_a1V;2;UL&)*st$b!2_KOH*(Caf6q3=YfT8I_a%He&x&qCy~GI zSAjYo=l{~V`O$%-Z*=v?aUKkJ{So)lE=-M+WW<9Rf7pQ;B;WswKwTV|ks$W}?2NfZ zG-SLI$K+cBSf?F!Zh;<}TSAPn8w2!R4W&1lGW9Tcoc_!ni@l7LN!Xe4LweHA#tCYLnLPPS4ig;h)mU)eN$&3A8 z{7`ODoHFLf{GtjBpM;uQkcqKs=o!t=K2&ux8z3!&nwU6U|G^9K9N2nt^ zWF$DScscNmjA}iL21l4pibWJ3E#*GKu5G@i_(Gj)4BG1+-SwVApX%(Ma4#4Z*;CG* zyZjQ0k6vpC6tkrLJ_CE*a`bY!F?6v5`F{oTk-C=h8Y;d?n+ zBcIW&Z`S0s{*%5wL0WWvn`hyd_@H;AWYwEfdJgP&J7?uJ2TozXI|;tf%%*dKzBu2m zA%0>eYbgAi;(x7yry_e{&9%Us#eRwOL}`_~9_%i#*TviLsbn#p39YH}m`Bm)b{qhB zeUW)kcAM_cDF=qi=^F;AEY5-q(R`OhEXOui?jCKi^#}JF?JM^+t%^JAbNK@seo(;u zOm;jodWCPy09)q+Cfw4eKbF#e#TiP6EL)BaabuJ;r+#(^-v|+nXPj@TU+5d;fc0Mz zn)yOjj4_v8)WsaUHDmwcK@+l`N#|JuZo^*BfcG}=ME7H8UvW88fvq?a@%rSU1>FzO zZ|)+pWnmR~eUo_g1Lu3{Mn;$2oQEI$;PX8%xiCMu8Q9Rh2$=E*h$fw5kOh1UvPbld zMDb`d&))q2;xVmfzYHHp&P8+8_3C+br2AwGbpq=(+L5fNAA0um<;B3b*wx9RspvVN zF)y0s#uSU5t>CJ?SLtn)S&|W3x}JCNAU^C;?v*QJKjG;EdR2WXW%^dv@|_HQ zH!6+&>)bPx)7ne?`{Uqcz(wO~E|kwGr}h3t&e+Olv;rFCp2L_zdyT1NKx3NTTX0}Z zWjmx9Q*(i1V+`Wm2_3BO7CK`pINn@yojnG@)_ZAJD=?J$+sWZ z{VDUL`k}HLpj(P~e2+&T{QAh~oO$BWz(HrwPNDtnY6m#_hF2##IEz>>$xjmbnd#n3 z{S5eAOq&|F6Q0Y94)}In^gh}U9?9X6HtDrZn!~XjVmwQS7NW;DR+*-te1C5KTJjf@ zpKx_+h-c~4Fn5pLgHBa{?06@9iLynGp-&O}4ltL`Gw@5`+Ymk}_~qtpdC@sn=h{u3R?XZ+>(IM_p@*eKQ^1-@rX+&)N6mXrIZ~x^iNlewEIMwdD~bNUYJc+DUO^ ztkA8Y<;E1eEc|BEm-XDII^7UyQ(W5XYX`TKWUU>^JYO6e>+s=j{LDLDns~ezrZ3uON#BBB6xT5y6H^Evm5oj4r;KHH`FTrL07?8iyfc(Q6QQao>)UHah2`&o9VP89hIJ7s$V+dd@FuI!GUut8pE!gSxrg! zMgAA>ybArSilKLv-+bSpzvo=8k1$uo4?{bM&dNuspLEhz7~BGAc38& zb6FSVoNtvgUO8Fk+rA_dLe{u%F$6CPuU!G1Wf|$L2Pm&^@FjVt^{M*!)d2ex8FhY3 zo^TjTo6>)sf`Ojh>FU1|=%4zcIrJ`Y{t$hx^nKK;g;zWtku7v9?-hTi`C~C>;*yHf z{Wfdlt76@qCOWYb{!say&qmsmr*^ro(7x+qFMQ#_-Hkq2k^%cWz$K0)c)jA@fM>3{ zzB^^2XXsp-+G}7sXZJ|cS|#aU2S^cLOiel1bIuJ0be94wkAn1k2T55WS5 zpy<2JO;2}a5x%zJ*mMMr>Su9|DMo#4Et}S=zcYg#r-DPN3ona#Pwyv?zLamHUbc6J zmB6QvImVfIdc0xd>GFo?(7%pov=*9tl0l<;52DfN&!y2o@cRq63$I%6*0_3n(yO&T zbo2PYM}O7U+3nBBV^`X>Sj?URyYd3kXa?&Xs;>ldpgb4jsIedH747T zf%U|eF3D=rH=MjSUIG8uJH1=%xH5QV>u~HA@zhP?f%!THFZ?kEeFRPldqJ_=%@9X8rkUhRX*YU&+psj!(F-#G4)r@s(iwJKkCiE?;qB zdc0LenniK(oY!VpyXjvNzB!1$GI2)tcPl9Uv$kr3|)KK zpO#E!(se(1|0!K()0a1A(dOsy;$@;cxJw`Tp|i%+_qlOnS=mjgtXVJjmOF7{nP-$g!%von-Jtcle6;vRibEp`to)rb ztksvd#9w(Q#bQvrK_D)#COd)};d;d}Gt-rF2I z+BqxGcb5hIb^5){x%Wo4Q~$XAUhIOu;NOw0G7aCbY>g1Ip)-2Ry|n9Bztc@8U0;3k z-r-U01D`{F*}ma*jVrZRmRB^2^zH7M_wgPK7v>FK+J(8$O?xnX?>aC~B7fbx!|OVM znVyqZG?29DC7ZWv3H!jc{-#(w&l-u1%v#Ql-`;X3K8x3>`+)ra9nLsB&G*pDX+yf&_H`i7vIBm= zc&MEs+V}!|viEX_uIl5~Kp-0bA^!hac||+OA3=TXMK_y~S; zhHj)KOLo1Ba-%-gJIi09bhtP-`l;6XlU+DBI&k9SbE9WaPW}E!K5DgDm1mt!p5*Q# z_(tb(WW(la-<w@iB$ z*c_p!oN`b9D>u5$E%%6{m)c%GH8<+XUHT@|)}X!Gn<8ymb1=_c-S`1>=#AVNr}<;O zzX`ips-Tc3VyRG$j@sejrZ!v42$_!;#-roO?3S3Fd@ZH9IK?%e23 zw_nojvcdnt_b#;us_v$ePAJQ>Qk&u5uH5Jnw~eUAX?djW!7$$j8P?OUvX|xZN2c8T z@Ydedr-R3cq1?3yEjr-`;be?&oQKbk+0z+4#7xjU5&J29u<>{IxnDmH@;mFS$WLat zcQLv9*Pr%ouACFWCC?rX{_rU(&jUb~>(b-q-UDUi(Z6XI($nHrVF3=g6|hhFki! zPK~i9cAc4LO3erqU|T%v zmf1DYDbvOGW||wbtk@ZO){}0TK`{r;QxlvrTle$Ll@7|BnHSycmO0Tab6>GjW*y(8 zX@8e8)Opw~bDmpf>3FBiV!laJIwRXk73W#^xn-_&%gjFADO1BYX~GM$tr%tQb<5o1 zmYMP;r%V~&q$zzo+X_);gS+Z@6W4ebFh?#rI}9@1hKC-{_VZ6nE)!ic@Cmd%)R6TVKkvu64_t=$5(f zWT(u!cY%`}WTpOu-`y>9o?B+=IH%0wf6=cG23v{K@~q3;GFQ4~W}oDgsd)$boH^Js z^kJr3<`%cilrK1C%KizQZvp4jJgdSj^PpR1?1@g9!he8I#8~Ms=2@j~nP=TH*(W$< z{Cj#W-*~^3pr4Z{Q~JBSXo9$~E3m`5#^NtRE;I+OSYdF>I_Ew0&o|cHd#l+)zNwV` z59i#ccw6(0Sw6$vWAoYm&ImH5`+Pk;bT9BEC)ywDtGngkJ!#@XG&e~$6gxD6`+d0Y zr>S_L*|_!`^Iq4LzNVEcexz8Jj_gzNEZyllkTv1c{HLytPnta1yjM1q^Vp-Oys+e| z+DYZ9f=T$5R@l#fDwwp>+&r>8O`g7UJlX_mu|XQH^35}MEgKoS>WoQYd}|GyL+7kh zwc-b30|U!Ld^21+UFRV59hui_eNAIcAX<3B3_;$3y-WLB8PD5$N9JrZ)3?-jVVM8Pv(3D#n1_t}4QA;O``$2O zK(${lntTLpw7+!KWsdEpIV9=s0~c-zTBXNgSBLVfsl3;mKk=FwRzCMSrO**Re68wR z89LPd{v&<4?tA(7hPi`wunRB5ypgzihCSz)NxCB_xLn`gOQMrBcA8ssF8m+#hkc|D z`DVR-IX-#EZ)^7}WiBkFU$e$K{R%CLtW=*AkGr)O{CQ{oW-e5`t#RKaj_KR8Wgddh zd@WbSu*>f(X~>?mM=avkfFbink4!A6kG?VoF~WS#Y2C{shurv%h=qyjQv=vf#(w`*EbNh%C6rtFQFckp=7v zIq***Wtl;_CHeYWqv zxVzy6#h2-O2|2;FYqb9(J>*AMh;I~6{hO~T20wRCCwv7@??`72Y6@frmd_s;+0oE7 zdVzRdd6I!uqzC9Xj#GHrVW#Ld>XqW+~v6 z@0wNLQ0JRB+nTaaIIGVl+w72>7j$R6r#NHTI?`b}yQ#K^kWMU|Ur&66z1G7Aq3_1q zJimgr8t^Y?;qMJm_F%pIcnkIt@fN<8myspOMlP}>y6KFH_mAjF&{zb2YzajjXeUHR!eDi{@HnVwF9E8DE)tM^Y zb)mgI$vJY{(Yez($FS#ntm%=vv0q2-3-I?1D*a7_Z)v z*qDjxE3#c8e-ZsJ3E|62qf#QVs zI~p9{L0sd)_f3xy-B}9>zQ$)I`ZJsV>lI(a-lg|9bBO57Bfi zc<6nSwVL{8?@hyl>uF#65Ni7Yp7pKI4?j^nYru|o5*<7`r?av%?iG2gMSQ06bEu~_ zUP2DEUJto`mwaexr!C#gZja2jyo_nQ?IOMcwIX%6Yu0&D@jAQsxkb!);sr#CVnv8dJwx_``)D)<7E3? z(3$ePB+qsHF047N@`&SinF$Qf4_1WiO22mCD`|%2t6Y2;tEyyxe%>-Xs(bEZZ|7Ry z;oUv%xU5e&<1ATAlsj#(=CrmQrj0z>xRrV{$Ir086XrVwUoYbwGQ{L$vA6X|(3%b3 z7PfxO12Ip!3H$)+8@4+boDNzju=FFLK(5 z(1yybp?_aG%B)J`V|d|Y2M-g1zubK;)eF;S<@x!kUh3=_mex_C)dk@Hx1*^KPtJDx z?o)gnY3g;9lc({X;?hs+OfN2QT~}^hoV%_g>0B$!d-3Lzer&)pn{F&!g)6a+jsU(UmF<}e&4$s`G~`cQ5ab;GNo1zRGy@R`D)dZQ1M2Kx;AMB3=_6{|pb%_BcoXx@R=GZ#M9y z8J3?r8%uAWjtvrMz2H)8gXPohyioBBtCDnr*!jCZbJmQV$b5{x7;NVEYREg%v4ff)zT&NvGX(VjbnzQNES`R$qzaCv%>f?8g12@Y#B?eww!wTes!sx7+jA>N_6Z zD_yBMWG(Z33jU4p{b+b`kMy-*4%gT~PwBll?;_~FP~sci1t!ntyTU&Xk2Wj59RJd_ zl$%c(%^%~FW{370-e$hl7}>V49UJDv{t33``2RDWBM-&%n;xFL>yKyGbKuFhS(1Ox zjZP7sl=|$LQsU=%-^@o__Kn2P!F;~?IQWMB6EE(#=7fm$aZB3ypJjY|e8_3-IARp} zH5mV%M%vz5I3p@Q%T|12dCbxBLDuBYu+m4G;rox9vSH-VMH^xrQ(Ho;&)TVHu$NZ( zeaqv-*D@wM@DuKN2)L!Axd#zhyA*u!yKR5A*Rk~z@T{R9(ky9b6t>GNoln*Q|Q4%#D<}!OXBq zM@3f1XWxyzkU|D*9UF9XY#h8}^u6nt8J6&me-8dvx%gk?;x4;gwpb?aJ>Y%=xW~b_ z@WuS-MZ@~=tp=A87vGv$4!-JFCcc%FG3-Uz@$ezW+r?45t9>Gyr-`{z%&iymsCVLP z>4g`DI6kcyG1N))&nDz9m?V}MxqIRg>~>@-vCiy37Z*1!{sw!%Ikr8UcrG_uvtf8N zJR#BXBg$zVwhB63fi907>5PjH+fmOApZQuE=%X>FM`^}_XKcxSeu(*l9Q_mnPK@z= zg_sxVAnpmX_Xt!sLjH@&M?da6!kH6Q_P^Y+!Xs11cx!O&`^B?oSmI%=!C#`^v1>sq{g9mT$Qa-daU|2zxwW0^0?5vI*>&U$}P7cWFy&`5WlBbPj%H zd*0NVAc>vj-^w@QCu4s+nH#O5%zD~r{H*i^&LFTx&1-D{PVHSQ*X%;4`&iQ?c~3w0 zEJkiR7mlx&jjy|y)qd~7P`%oY(Wd6=OWii*JMiL!YM#t3YLB4b9?gwTxBKRdFJ)flmP(j6)Pj3Vg{PiIJfoY7rrUBu6z7b4s?k5O6`?aB|RAh zAKQKcUJRQ!MSFs`^8HH7gV`**0+=xurtA#0>(4H2(cE(RC&c0NA3HPBqqXeWw3A|t z;(IHt1U~l-v`>t?{VlT)eJ%voh%wufB;_LodzEBX)h%? zbLYf;_~f6$`voHO$y_S}4F`Utm59sljJyx4kUh(eIF$E#hCLNPwOi#fgpS^}& zNB`RIVo!#0!DVJuVxZ}X5s$m!^-8O89ex?+27^4thLcZ!o8Wa1|7K$HR#0E^2p<*O zdd5)RwgYnP`zq7xa-&=CU~O<|qT?FMdSztWdCvx$0Kbh*lm7ZicCFT5S&CBp2_hmWutubrYXs(LTPuaVf`bz#aeSg%v zR%sO^U7HCXo1?FP+Y+W-*=Uk2{31>IhNLHB`gY`NoJp|P*jJi1;j3>XC@#^uiT=9Z zDNbnLXj!iH)Ks(TQt;?m2>*@6udDK`x0B0qqmT1WytaTo3D0keMz1gqtii?GzK4AF z8oYr281t#(5mo+Mlpjyo%r$r?ceM#;dkqdg;-*e|gn!T0TizEBf4Y^hVxlJ$5jf$_eu78a_3Z~B1X&pbG zxJcdey@5UBR3bNetJ^0gpP+eBdV?4f@E1PcW=*Rx)U(b>{*>P+!96R|a}<5D{fjz( zGg<3+_PDnBnttu}L2Ym3S#9m3tw>|8^)0)toYs@5n@0Bk=E8~$hW6ASqx}Cumx`8y ziGg*VJIbJw`ru#cZ}Bb7YVj}4=6^s7@qKO5k2T0ZoW2;!Rl-{uV~wZBTU%-8D|Xw# z)+1>nhJ0`QeWjIVZvWjy4&SDckA&u7`tL(NlE`BMS;VHZ zWe<@P=5*x^fL7*{-i-;;zCTnJh3HcQc7F)H(fC}YC0nr+9F!K`KcbHA50U;!J?qeb zGtC{MgJN^n`6CNDUt3#+{-5i^zs0yrOx~Cq)%}~L&oF;{Qu+dPsxs)Y&76T1?-f$_ z#;55g%@T8f`_m(EJ!W2z<}e;qMtW+UGcSuT0q zbw;E|K1hS_<^}ZSmC*lnX!Tk)XC1)h0sn~Q&#+H3uzpN^t@d8b=sji-wkUR=^xFgV zwe|Yed$!45o;ccE$e7Rj1Rb$9T~MDj%-0eeLu>@&@DO~!*zZ^b9b{vrNi(-ysPXuM zO9S<-o&2lmS3>#=8L9&3GT{G+zTo4|Q{MUHalWf>zXrSa3O^I|XI>Y`3f_b#kQcQ_tgY`w*7~bn$oU)U%P04BWD+GPN$iMod@vLpDv}!3o zoATwI?$5@-+9v*&#dg@ORd4c8`5$SIXC}p9f#ty1xvA2c zLV2}WOPgb9uYvZ2ce9J<7~rVB#$gQgBfyNfebpM#Fuq!2G2Yd)>tpp(t_n>ujG^pK zXRg`Y@_uWjz5df#Q_V4&Uo_va&}!|i#Mg_gH6m;9>Ba)&Erji(HNX5mu@UGP*8PlC zaq8>2(UYc_RnLHn_^O6q=NLb}*b%K)FR){uG zouI7lTTjB@_INX{x}yTRb##pgS|RqQgu@w>$Je!4?UmEsThuYx$&RJqB0oh+yve)q zw*Twhy=PK}IW4I50;MVhoM>|vaS1-$rzR!B%Ov)w-74K3o_ol4G$OJIcj7@?$nYtSjz)d65&GZYN zniqjC2DvvDdXsYLO2=+oM}O77EO4{Wq15`D=CkhEiGJ9}{g*xUtQ*h=v4P!NK4QL; zUteu7FK=w5jWGY~Xk!*_i1xY<;fh{o?od0jM+<3JK7FkO5>3f74B>OWLcedr9-D`wPaS!9VT2lskTg z{@Cj``lf!3=e+1M^d;qvVTa9A+Iz}?eF5*&({*~nc$tiBk?3YF`IYc z$-{q3`ggW1jr{HiL%T3KQvRH=gQaWzd%B>rAKhMy+)lk}cKy_=!u6f#a>YNEQO7^n z^fM3XH~HqwNH}^9L);_^%Lt2JTr#p#;Lhh4P!cie#PM9hJmI>ww3L(U~E#1 zQ_SyciBV?XH|Pid@9}><<-Gk0Z*R|zE4UT?f&G6y>!^4k{smwdaMk$kL^sArZ)Bad zmbo>_+`5i2m0cZ!=Vg<~-{9FLDe=^4*zOT@?6{e;5EYI_Bv)hV`Z;>@ncRrTlXaTTYW?E#UL{pFZr!RgK6++yi9vifz}Ri zlW*KG7B%ow0=vy{ZisoaCw`>aA)HE$Z@GM$&qIqbCbB?%fHxM1FZMI$7uARACGVo~ z;>D&V$$Z-1r&+qF($adho&JWwLomZb%?{y{KGE6J4Btc<*2m52D|p*wXe+bKK78EL zwJRGdt)cWob4m=p&h$6_X1^297AN2HIW8eDhCWgrGfvL|A2smi-&ko0&Mtg4SN^cP zWsn)P{YAz>JP|(?J;i)gLtE4@u07859K~2^y)HU5fPal_Mfx7gb-s_1=KB?Tud>Dr zTCRMhPqsgU6;*?{Fw^DaITSy`9R-U zD<{5PX~*9LmX^1mr{9~#zGZL{ePfIofg#$n*Hr!2nU1eOd)^818^N&|S@C1XH!_c4 zGu!r4;$-}Dxx=IJjzq_=siU%z7p-sQ+X{n=()`0)e1lT`hxanqqPBnVYDb3Sh2Q{Q zVdOM+9D0N22;W)WK|RU0wdOKzN%dfsUn<>9>SAL6`<0QW? z6X$Y>{C?Aw-#L!_4i-;9&*T=L*s{0w*Q^C2$RTKsuy$MT9;1YzjakEfx2Y(4j%>}clwzC*YRkLlZ`)TZtr~vPM`LN%hrXS2 zUulW#lNjwxVXS6{uxo(37@n8|j%!WUp4)(}d2=Q3WFs5!@zodB|5^M(e-e~SSGj!S z@`xv|hBmam8!Y|3KgSABi%qKGY;x(X;pHLxpNbj&Ha{P+U}4HmUgWda8mS|5qgR%i z;0wG{ADp@QiI(OI92pxgx-cFIcqs(FHPCyOEBD1Ombbi8<;cGLelgyCp6n-wuzvsW zm}oe!vEw(?QCZQ?lYPn3lZuo3VdI*0ES@pItEhe}K0@Fx7a;BxpV)RPk(&DgHw`CI((ZRB0U`KjOY&peZtI-B{6 zIw|JDdq3q4ZqkxL$&_#@?1#fk)Crx1Zwwil%$h7xbANf8a;$yWF9~@2Zfvne_%S3uIl52tT062B z`XI+jQpfWfo=08jM!k<{&PO+0Ke5ufQF;eCmhF}cKWV;6LysWkYq2fD*zVdhPkh$P zeN!fwq?$-(;Xk0_Rd4H zJx_J!oEMo-e3aGRet+E>nPBgObQokL#(i4Shx<;cwBn2jdbv3LMox4Z^euuWmkl(l zJUU@_Z;aE|G3-ec=A$R_<-azq<+uC0$B;&^^%Rm9hyJ32_%;shw`9;jkY+g%D3doc59W^3g`_VYv0AxSp`1r0~?ozjeoiJ zEIzQ55Qw-=pa8}8b8msUHaU>`UGAtjs z_G(V_Lv+=2%BGMF;c`0dYhG+8?K3`X)Ie+alhT! zZLi!tOR)LGLksA0Xi#Yjve+cta!elgrTF%YK~@U~p_j2qWXt^cYuGIK6^XkhP;gvvU8U29+bCz6S~$9zO|H%LH{_q@+rm){f-@wyN~& zyUEuJ>gBhI15fQ4<^g0zG2b1NO>j?ae{Z$_rnqhQ_{W-h`M1;$A3Amd{Sfb~o$%+> zPtum^`(4{f^`G(ww;N&yTx;geEMMgq-Z$It2kZ&+o_=)Phb+Y`XAQL$o;8W3YqXAte8Kd*1#J`b z*S@Oi)7n;t#lSfHN2AjIsP| z@~b^ZzWf(mj0>{Az0IGyU3>!X>`3F=DkJ`XA7haoG-A8<5$2=kuUmY1_bhm)`mR-L zJedyhJ=ld&NAK4n)67Y(OpmtLTmGLhkNl{yBlToX^kZbUnzHK0$Ff6_hfem5#53~O z#g5?ntK_}r&)Ji2{M!fgmaatSR>v~rDcg)#z83zGJT;21`R&RZ-0~d0B=mdFuDoe2 z3C)AUkSAb;h?~vM&bIk}DKhZ1f57sXv;W&<%z*8p?N-{5zg_a0xGGkk*i}$3U(s8% zaX;lHGiBL_*7Kv!()j)&$d##&*GF7g_>j62T$-pa#QiRmylj0G+a-y9+maI<&igp{ zi9ZY6*pWh$zkJF~_?+=q7;usALb$HNK1<4;(^_c=I)i-nGCHKw*pJJLe^_D5MhJVn zy{Dom#N4?1BZv28!+ZMV06!n(`*+T4MBcA(_S}Hs`NppMxWbt?uwfFkWstM<08<>< zoMWALj_y}rEjEPnq~LO~n@%6uz2zm+y3;a8_Qt@{mhn9m)+S_9Yqz&3*9%Qjte0o; zjJz%|Lwy(8Ylpv>dAG7hk}6ECDKKVlGr9=c>@9`P1?I@TNzSjtgaK~+SGbf=Nb~+Yb#uZ=ZS89g!pFRymDWKbt^c_ zhI@>68pkmFAYM2Qnu;D_^pS9hp=Wf*T|W8aDEl6^Q2Nu}je>d3`;KfF_9%s?S7#=5 zV!z0VoxpX@DlSz^;(+_2lM|! zF8{N)iC#bkY~Ih=+YIk{GLU@L8FP*MW!N#oL2>z=(5;w0DQ)|ENC!#FrZha;<4oEI zY>i#tIgf1zVpEbo$%!hK;{vxYDPkj1l%M6MBcwOH0-foTOF!d!(Y@+%S;cmXu z_BpyEt#vK&^2bq6?_astIR|$kuo|HOW7(wdM5ALirT*aZ2KoSBq`e=VoR<@Q5BX5t zr46hhXvaGT5{52~tabJ7dGw6>q~{20r4;Qr~eWK8vIo5v* z?unf7B2V;A67S#}%ea`xigw}?Qa{MC-i218>Cb_uGlQ-CC#k!ce7lZx2(X`V)7nSW zx>)VXX8$wqCYZ*KJm{i%WrAt9=amrUwU=KFT?(@D?Dg>P$U`pr=9HhCd7ex$m%JT8 zz63Ya)4NG`$7>yNa6I4Bt}Hy(61pSjpmo#tfi2lG%yDKwqGOGlP8`v_CAhW1dI8)t zb|13F&>Yfzmeapez)yY>Y?119)cK}(1NyGzS$q)xkngrp_a`?w^5m^SQ^Y9zg|W)x zT|RJiKjcj26UDS@9dp|!T8rfGNi$D|Zp*Q1fT!_Gy7c^xn?^Tqh9=lL1G;OT3NfY$ z-ib~Hvwibo$gB2T3MTpHA+OabaDN`$1?yAFHK4EHk!snq1;6#pOCYxeyC}=Q))<04 z0oX@~S9tys{nK18pNZ0^@-DV4CweWg4#@VXz8GBZUOe5opJ?o(xolc*Z~bJqFR>hl z_Gh{2bg+BNgv}M!%g{(?xjuq#lHmU%7ym!l_~-741UPHP^O4||9*%#NXVJd#ZHM-f zy)Q$5jh}Q{h%&vbKkfS-8grsUC?7ka|fkTgx&`ExkztN`lirDY28o_x!#b=M_HyRxNitLM4E0KMD%lH!ef0RA$L+o+K zz8=E3e>cb4<@S~Jh&|37_P$!0|aMO%`sf4OB$Z|{~gcwgwImw{^oc&FjbkIBpA zi8nRQLw)lM@5CD+*<;zhdD3A8xBKRyBdQ-#nWesYacr|Q!QFlbkEAqj!6VJAtJ3JG zNxYN44H^_jF3X8(jk%v^&FS9R?BCNb@!WsGH=SAPYfkI2Zl3hb^W=+0sd+ipgD(Dw z?p|AWZ1MU>TKya0rqB2K2VZY<`-iPjCB9F;-&?KqyZV;qUw6!9@^^Y)Z}mT29{#RN z)0_C$eJmQsdN=O|{$tnT{{z147}-{~9+hr6xsT5kYp$4^zHbIR)-p3$Vfi_er8%wh zlk=>vE~~K5#k{z*!jkXsmKl;Icp4hkuC1`*g^>~y;(kGN>;U%P7Gu|y4mIQBg{DN$ zWs9-{r9(&C>1N8;5PMK)Oj{$*i?b7Y?y31nh1JM&65B}g$2!u2KV}AN^e-K2$##nI zE|N|B2l?zfHtpp6md2{F=vb>^B>Q+jmTkqiK8XJi9Pu|Xi(As1&r-}}u+g7p6^L zlGvj~gH8%vnPWXrVpgH=HmB~W;NC;$e3$f4;{Ee1A7h{T$9dL&GcMTmo0GR!Sha2$ zWNWzk!`wNp=0gl|sQ@13Az210R1>X^O z?)nN*=5T(RuhGBLna|GTcMP;IPE=Sq@V$64$?s3BkyD@cZc4zz&HN@CGq)5ylen5R zKl5WVJj_q|jp!NhE=g#ufDHL)lQUR7$K$Ubb60r_>mS+gCI5t$Ika~yzu~mmNSiV4 zEFFW--_NfB+tkNgr*Rv@Pw7V53r> zltye;?qFOpDbltKe2mE&l9*)LvK9>(m4IKghc3IdbdhgVY-syP-|fCp;h|5DY@|#o zYu3wC8r=G4Q=dNA_0R5CpLNb5^(mwJT3ZeLB(_p##-(Gn8Z%C78ThBF5L*3(eZ4ob z%(!&cz;WDNkA0x$LF3N-m^}l^%>QZZg}^}c^i37^eZvuO4L~Q~i&I+S`19o74dW9I zz*E{&Qk>#=_Jee1P8{E+c&7lqTMXYBd>X45*H4g{e^xrSZA{~ZPpW@ROW6o~<9|zZ zBr0>PXDRDvtXAP)YQ)ED`+k9C?~ko$T(jjP_yo8fd|b+teMfN20CS~RW)x!SU;|w z>%d6^=f{-S`Pp6kXWH&@=2-5kT%h<^&0{Jvf%Tx~Cv%E%d@844|GMwmsW14l<3a^F z(IZLs0$;S%yrpxlvxi@_KZ3qq#5;oyU&y~~-qbDm(SKYZyPsIbFXvbvBfGkjT((0( zV|$Ig?kGuo*jude>Ceb7;3;`t<`OJr*qVg|J4Tu{w>H(p>de*Wg4IQG+@ z>z%j&+QEJbw639?e7fQrc%n(MP>fAa0{^692@;EE{WeDIK#X^bkB+qH45sR-pLY8h z>q`3S>+3r5Q$ z&RkQCPVnZNRo63bQg$Nrx`8|Nx@ku`QE}FhQ%!NrDk~a3l0CfBbF7zn_buJCcN)5? zEf76(zEjq4C#~}Q^H|Fabz62y3y#7WCz;)Ln7sLbG8e0G=rV9aAUfc!V0203;CWc>olm>cJ(;+uO~G!b-u~}6{YU2J z>TG!ef2iK2)JOIKo|CRPufiJe`k{2#qB5N2m<}DxxfRy#U5BT`Dc~?Hqu+O^kMt#p zpCB^D>4WYk+uaq6jwwC3564nhxT`Pf$IyQ{__BU3-r)8l{$S90u75vRBd8xgaB);W z(vb@5>DLbJ$1;^+%x|L~smT@A{jVOrA08gv*Y$l@NaMH?JT3vovW#&nC4VM)33uFt zi^_h5JgrGxdheJ2P48w42bY$~vmBbtdBwpa)3*96ZA<59FZ%g+99pEZ@ynd)(J`;} z{=Xbb$L-V;{;XR%M9WdY(DV2#Ga+=6&A33^nam`{zp=#A=k|76#r1}NPMaZ z#T|^Vu$FZ=ZK^F_hD-@}+4ZYw`)cazImmbHmSnqYTh1%ZFL3Nm6QZtb3&)t3q5na) zaIDDb-x9uql}Y0SuuFh_9{cbO!->gejD#orTHU}sdCl;a&XmSy=0~wDtKi*noae;; zRs8x$?r#~=I*S~Y0?g2@39Dk$ZUwjIhP2ipn)$z)g z(#Pb9F8@7)PU$C)CD3LF?fsA#*mz}rR58_qzXBhU);Q@qe1)@>?;AIive!W$@%QzN z?G4OnD*t)dgNo|k^c^^rM#`|H-6XZ!6p zg+JeKe-htfQw(d_+ra~V`!41H`Rz9xt@me~=rBVn24Q?Rqk$XkY;`lM`p=)IUc+4n7sRkAl2edY}8ENnH=ISdcW zW*eKBwO{)Nr6*vIjW#`z;yyeyrk*WRdi?*b-O#7O=tFM1(l23bYrEYd=T867C&6fv z_p;f-h2Rh}J)xq*;~-l<^>NVl-xEpKb2;^Fexsdtbr3fL2DuJ^1*9_{MmWJ+rMWz zw9=h=KEBhk0Uwv6o~UU|Lzz-F8e+gF4mA{rtcVr)wpKh|?4jAN0~ zl2gUr!q*4x$I{vL7f1B%%Oqs`U&i_{Xy&DuN6qZglE`rUOdkZJ$AY7cL$2dv{-T?X zk$wT#6Y(p{=QqKAcKpiUw`qaD7GK^(%9~7oGJBM7vOY}Odz86v`-b5^VsDapu{x9^ zS;7Z!>$xo_fRFa?m7cOnHmIZHPoclUCvsHxX7hf~Itlo9K|@o7&4G^AT2Op7@&-r8 zB(Qnqn-q>WQ|=Y~LI3G~#;f#0Z5ekD;~h8c?O{Yox6_ul7a)II8v1Qz+`4)9ByFW> zKYp~chYag7iDb!HEH4ePmM2oG4kIKU$U|HAI>}()BeS?!DtTn+hYYB z-B-4sdrIX8S9$4Nc*4E|>*Q-#Z?Uf{|4}~Aw(ezZ6IT8S+8>Fm0I!MZ)?oCn;Gp^` z^x!J+#=sA%A5A=>x$~*1FhtUm!ndIy=b9cuV z1e3J(Bn)|DN&kwnhwue{ft0&=*KFkVWo-Bc3YQIs%xYl{YWl4NYUzwa@kPp0YbQ^p8%_ z_abvzbJ)vF4e8TGu_3Nsi+=c#!7|3(H``az@ELcWLB~wLh;&sNeWG=r1sr%}qjbn( z@Ql40v}(aK44zB&PiMX`twHFb*yY*KBY`X}CV288yAs-tV`z*n^BzjYcOiSJrr>G?HHa@!@IY<42(1Q$)_M*dtu*nt8Rk$ zEq4!bFV&+d*PoxBgNM>CKb6V{uUH8C|H!>*_(}K<%09QnKM7iZ!x;39bWIxC6he!S>MZ(pF=XLeh7EbU%X=LdvL#_ z#02jLMvV2A1koMw*M4N<7mz+JZk9w<5q0Byf9I}~C;@RHcALPu7Ctl~wL1E@` z&9#O&w>0jF6?fe55Q)wzQ~2Wllh1E{Ec1A z&005I!OvTRX&+DW`6t#rsdsueCx1WPa^yQWPBP-j&f#Qy8+F=U`gnZp*nHl6_E^jK z-~D^uPCgurHoN^yqjSaEzjo8HemYom-Sq5qYZ&h{dHXhayN$g6FL?W5`l#_X=;Qyt zdAs*?=A>T)qnCR0A!b2*@lB6Dq%(Q@d1OJhka+ug%AD=;#dml9z~mp{NzUvUtaCfC&gMUmva4i zQR|Nsc0n<9uv_*v;wO=9(5O9kY)#n)sb5XEsP{kG2ZLRnls)YG<@BOr>>%MKTQ%{E z=|w@(iXRK{9EPSo(wYM#n|(HC#{BazcRBLiX8FkDdFNR#aj&W7+iL!`r}Dy-zWwYm zKcD`;+RyH6nSNkD+eh8S?tXS*>-2;6vz1OVcZ`{VJ$KgVf4iUUJ9D&!kLmxkpWXGq zbjvqs^nbjceGUE^dq10VKB@KKjLmD)G@)1fzSuD*&~sG z=UL~&3lZ)A{&2dr&3(sM4EHB2WL4Lr=dSi2Gr$`;YYdE%5vXze~aEPVqf`HFrW|`dAJQ>ZkCNk4t{7 zf7p9e#Jt?$l&S4k<{HYpuyDH7yk@!`7aFFnjpx|U-w$txwkku}|8PJ2@s{iE?vwij z^ss#q*w6Cm`LLT=LsoTijy1Us*rXFY%RU^#PrfGE(>`R^hyAOv$n(ZXGi6DKc-CH{ z?jew`YP{Z4R(q{FTQQmVb@}*Z)2nVXZOWGr!_O!A5AommQ^te5cAMYW^XI>38h!*~ zkM?mlpK#8lu8%VK#Wu!%LfbqiRh~6~)~B>H_e08>y6M*S&|9!G_x+RpND22zjN3q* zbNt@vmS7fQcV_Ve@421WV_GAH`3aWp1k5$L<0cYIdoyL*DYun2)erEiE(4DUZOB*c ztxp7F8}wTbUNPQj%^`l0eySm_3_Sfj!zWd$vyHa2ercxOv(!5en6E=~d(8vQ+m#QE zZ=vq%(D#jg>zLEw$#=1_)Hmo@jGuXho*R!WZP7h~J2@x+S9tXe%E))ujI5~NV=QEW zpT;YWu0|Sr!u&K=o#^IM;BoDfCHOvz;6+%Ez6=cf#s}o%kp1b5J$#)*ShSqW_8)9thi5wm$mk%QsG30yGOz7W&#_d<6AVwEY@sf#v9@_HF%(et&(tLMPW$*zPhsw`6s41nK{Fa`}o>^!`$&1?_~c)>hq#?=Q;5n=G36oKz{Qz z=(o%HhAp}p`I#G|&kipU4~pJ4*rBl$>je;B=KJL;z>x8~PVulyf@pw!8;=XmI{M$2`Bjz*j>aJ~_|CHYq*d4laTYCP9 zGDr8sb@mq?51Grmb^nZkj~4G67F8@q>Vly4Bg)OE%qI3Zp7aOp`1BNdLG{4ho)4Po zs{yw9Fg{^+IPuh(@iU%n{dh~b>VJplDi2R&xj&v|?+lAJ$9xq-pKIQWqx&bjXXwn7pjGq6uxNN>qN9Xz;)VIpd^pNFJ?9U~|8F6~W{p!Q- zht#Kx6Q}oRi`GZd+Z*{_j^uT$JANTA{>MwxXT=W9b<;^VrYQWCVeG^Fs$(SiTfZ`_ zu9GtgsV@hkAC>m5zUsRU%wZl37iN{0c41!B4`ySf19JfRg)@fL(Z`O^S;1%*FtLZK z#_;RPBBlsmK&<{;>qBhr!^RYG=0Y(=i6X~VfBLzARUUC{`kBD+?D_`wc+!*&<1@Yk z9@$AdvXx}phL{7k&KnkOCtl2)5sbF;ZYgE7Pqg<+CywJecr5nC>DJRv2dwqL7hK7# z%Am_Teor~kRyGqlr)uy#2Yv#(HF@%MYrsk~SYpY9z7cl-p{n>&CU){)D zTMbO%wu?BDO(#va?|jfX6_x!1WfgC-*dN*NCstp1+B^9f`SMNF@RJ?(ZN^(`9q;{m z_q}r;pRegk-b;QGkCg4#y%VL3m2kTczFzi3z}o4?h-h6TTAm877#YE|)=$T4|0LMT zo>`CJ-wy28>A&jV|5(7SXiIN{ z)zZ71@Bhwrcw(B%Yo5F<_tLIx-07x0d22r1k&Sc6FB?D1j<<`A4c3h!efuH@=6DZ= zD{nV=X&2@~H|@dn6*(|ZB7a@cusR>UlvFraH<0uJdE1%Q)VVFIDSg?w*2vG3w+2Vv zOpYsW5BJI2SD}|DZ|g-*%1*@xcbXsHnTwC+(%4i}Tz1j0Xd^Lv$zy|cyCc1;PoPZt zCf1A4x`5cN=cUt+LEc)Cn}`Efwynw>r82};Jp}Khtm)SMEqyX6UP1=#_=jD(_%62kc_-r^gI|+Fobq$-qc6xre;q)qPu0bu7kw+Gew&NiBZtAQ z=GTF`M!pl14g~Ai6tHo-8QfSH*|d7yQ z);GKT@#NrnFYWT|AKbLZv+$Y)AUmM@@V7hYg zD=+P~vC&O?ZItFYZPb$Am4~d+hB+cw7a`r5bs_h9IX1m?M3AvL5n77J)aRWUI^_B+ z_8YJ6U40F-Y8Xe{^eLtqTfL)eJ@S+_yv4?MNp@4#H4aT;&_wZ{r5--q&#y9F4 z-E#EHD|d!lE=lb%J{n{&ku)IV*4nekcuV2DidN=UAh2Nw6p3Ev)oa55#XP-|m z#SnY|Otmc@${{vzQa{|zJ_tANa2)L5wugFMgNN0%2k77aK;3hsZF+Axl-_FRzx%aw zT)%b-`?cd6;Iy-Ydg}(DUxVn64+C|-P&@ShZtl%i{N6h5zqa|}m!IEH@x`MV?T@6N zpLuC_9Q_BiKeE;5bK3v4+V{~PA+8gWk zPmi{3!PVr~e0Fr5F9%!yUxB*oNZaFlv}w}#mT`v9?&pTj@2BY8=(XpL=TlzVZC~Tm z$7?yQ?LAKWH1V5(_T)n2l-W+>hfX`+ zAiwY<`pF&nkv9W%XOhlF2T1<3*4WS9^-omSAp;+}5Z)s0T= zI@z>oK70Kv^3l0Fzi!%g*P6CB=9;#hd`G=@N}_7_67sN5-ryVZZ-7_N%2J9knDRS!(!LGrY3?lxtY4s!;fv=CdEq|{5myi}-UY&)M*POeR`LLe#qT*La z;J;pAKaXh5#* zXu(!&O4;Y8IO~Cb)$^lWfE}#4@yT=g^jZM^^!MY>fd}ztptZ5n;m=LfE9^SjUO&ZN z3KXp%owd+`+1d~0KfSaoTkpAPN4ELS$*T^`B>9V9JG!o!HCd`7Q1o5W2W&)aWSvt= z4LR3p!oEK2nhYCXYqIpVY4#q=)3HFb92-t_mrd>2h$BUR%06~p@9N($M&EPs(OjF# zF~x=G)G$7e=#I~Xs|MoguqSxaNxYgkK8g#RR$YTwAC6T@uY*x zoXY~y^)4U1yG=o!z6Rwy3^%(m*4V&36|3>>r^^-WYz*$oaG*e6=^3e0Z95e?=g= zlYaHL-DlGOt274m=~uP(7_)!UcQ(84O!m+1yZk-5_wFF*EzjD~+iQBxk30PJ_?HjX z1ICpJZ=T9_)1J(hwmUMrfqGr-N7scd{C(`46iHK6dm#68;hG??3zSdLUo) zqwFK+_O4#R8f}q_k9aF}A^!PYM@N0b(ewBRzQ()Tw2u1-9h;o?|44iH_^6BP|Np(a z2_Oi(vq=B}$tJ;D>Ya-OFKn_2cy|q`)EgTj-ai!tl#7*3B3?f9(>4NXu`MB#*2LNy zprUO}h?ln7R*BYHZQUdww)knQfDl0Qd%oWDekX61*!J`N{gFrZJ#*&FnKNh3oH=u5 z#{O@3E;+iz^&{LsKhG&P`oPok>Z5MfNZo6#u7#A{^fiZ`ZQED&uj?!vz`NK3>LeeT z>`kRQ``6VY+k#z(YnychbZr<< z`+YLLn|0qi&_!@|&J?%J7JZW1S+YfUtk54bW^c~6^ReZujoJ1nVASr)+^l#KKgDqL z&v5jQhrh~)yA{0JL-X=pI-R-nm zWMlM4+4l3#WZR>yZ?8!JbM?=l!+Ly8lKd_F9%-#vlVV+KS>IYS>HFDs>RqcV^@P43 zTa(Y)J@r2OQ>@P|t9s2{%J1a+Nqs-EW+6CIJAwacw!I(zS=Q<`Gaf$Q#`nLidsz;C zlwAIX@i&~m5&Rv~$hvx4YM0d|eycwsip|B|%osQ8K;l&P*h1_fOyW&x)?WeEwa4@a zW@chhB^?)eBC^8bzF_GU%c|KH7)sy$!|JNJh5JKzoB9OyYTEl-T|2?K{U3@cJf=x7 z8@`*ZSYbzhNI&qVMUiCdR(ROH9$dhP4&sixE@R!5j{nyGNBkAS{{w?RAN=h@sAA6`{`e;LOA9d__yO&4eiC2esCq9Ws`Ksf`zB+yk zf6=MwZOHEfzrPQ5un*(m_xHh3!oSgnf1}lhR#&`_I&SN$j-CI$j_KmlD?UEGVsY2a zk^MWpFZ|ipHA*HVAAQN(Il}#_5BIAUHsX=E&*=mAVPo>Eee0F69)EuCBN|IjR;vQ9%B9G=v8#|C}_~Wf};od{s4VFjI`9- z%mLC}q=og(yyNH@zK7_WdB@QUd=J!jC*K-peD~v9d#}#8<~zu@>?9LsT(j--n}BCt z(msXY59nKS4l?Pi0cOi7_B36kxJN3Yz#uT!o z@te9vaU{%*)RDT3IhFoRP2)c@r2AS^(3&F7Aw?Tfr|}K4T$=-C&nLc~iTD*H% zW@9()z4dxyH~(q!;kNj(uIzfYc)m}Tb@xL14aRPMopLpE@J+Fw*gP-Wev0ogcNv^7 zrQsZqhV$q&oF%gj&gUuDF&q0{_c`2=Z9m3$k1bwk*5r|Il-obVmTu+@a0z>ep6yz~ z8t#J=h)-j`J37tS;xDDbb}VYvTe7#jwVLcJ`MG5?p9z1pK7SLr3u6;J;?kbTXaDBG zA@OzEL%KEFUPyXB@>7M_`}BjiHc!RQx0nApeE9wiFy9djYx7@e|EBbOd(L~|o;_9d zuOk!mujumV844|;>93L@aO9JB2Y57Y=el(H_ize649^W{4`)uceF^zmd!NG^%fI%X zMR|?WKM_&exyg;TYER(p$92 zwYNPSqW{m7m7huNNm8bHvR7tA({XS1UFLPl$oG+*Yfb3c$6@WR`aiu6e5^5&ljMie zo-tzs{+vkLy!}}1kCwkdKd|@Y@mB444!pwW><3o~--xCT@NuT`X=~#7c8L#PP8zI|F3CO2>ynp9gJ{k73Z>tZ_IFvNL zugJDvCEt19j50cV7~vjT(dX>RKwpA&pXk$@qbYRWpIm$%oyVrpnV&{ydzm}_DOXcI z#M!TEzMS!|da1Lsmiv9+sm?fRj7=f7Y90Um<1{sn{e5C0M8|V({c2CrZBJ=McD!AC zRF`GjkNWV6Pr_RSPOUk$*PS}S$W~~o>32^K&!L~P=_iL5)TgqMuZ=Ohm`mGFGrYiW z@^mx(7+_4wk9*t;VLRmRd3m@_0@rTjT0T~9tV;g=YnHjE#6N~LRwM`X>!v_Xn%|T< zm0ps4c=}zWNzOOIlZDRj+@_!Kdx7&ir|BtvOV1zfb20Bu?wyd~e`fiS*IM9u61h zH@t5b=Suh6!p12OaHe9}b{^k7I(|Jm9{I5n<@Pw%JgGDtUnw1b7H@5# z<0B(XpUwGM-#UIcGUxS`bkeiG)b*as-U%&B zL_=t}qvsp=mY$Cc_R0@$D*r*>I=f0dWz48O((}ndUYQY18#eS^=1O3HLVdgadR{t| z`tLzrrI({e`Sd((`w{K(>-m=&j?~Lh@UBri&_V67VBN33Z1hWm%gYFI*?tk@o-w?yRj>}-!(Ar8)>HpoBW(|MzMqcE zus7%9&t4JT(pe>2D7Pt-GVohh$E3qWsjUYoc3j zr(MomFe|#{7JkcaxYE}~PakhRE<3)C{qDr^+4eZ{FL7bs_r;SmoS1!j3oy~+vh5=B zQ_#CZw*9D!PI72Q|Mn+_&$+J@nzgn#+r<-QF1v^M;THb@6c)`ubw zipN!(yfLM=Il32KOULGaI1O6?8_L_uV!l&)<<7&??{;+T@TM8G-_yO9^V`$Cm-2h! zP@|tO;y1e5sn^pjiXYg+dCkk*wn)wtM>yU6Hu{hGeUQjM+rQ&m?=*>yQ_^spk%ptapTUu$OilkG zb2ZP_56`xL;nE?wsQ=&Y@jW(Er?Ht@fO6Z(w?HXPi;y9-!=| zDxV+r%k*6W`X)2BGt=lh>M;879|a73&x*bvYXN-X_2F!LHQ#rGL+|H`MrS@hddz-j zjA=fne>HB}W5^iupU%+kM8;Ad7@5-Co>^_?cFpUajd&)s-3nf3eq~N~;@{l0)b8o# ztyJBaqB|fpPPMloT~PnVG+SpCJBZ!Kp3oj3Lhh7qU5Txr?a_6+hBtG68|Rl6Wimg1He)1jy0_}{|=1Sd7aduu^M&9)tWy^*XKC2idW*3IcM{t zv(D_U4G|}p+4%W%?fdp)Pq;sO!UI^>9)(YPaO3Z;Hg>~#ZW}#Yq}uy-$IWv0+p`-g zKOT(B=_lL9lOFtJu#wmP*>)D+HQb*jTjV4Uhii-6?tQyB=epk>&X&I$oOz_r{>R|C zCEEMR%(f3r^w}bX#8`w_Uk9^oTkDuKTcn-&{)3y$-cNIztGB+=Ym3O{@a)HL!P6A5 zXVcH`qdz{Q9`&>IRbmwONA8fgbZ5%Sw%;X>IR2beRkZ79#+B@k3#hC9byLSnw;3D6 zziz7rzq3}OOg{b9;o5yE;`r)+Ze%lco7H7SspAf-Ya;k5Ujb~zaQU&ICCMI3^0(et z$!=PHbJ#9)<;QD>+H@mz$;X9$s3_pC-S{Ayz5|ae&PzHv7&=OzqZv9hza*io)Vq@TR6MKvG;Dvu{NS{S zd1cSbZr_Z$q_N7CbNP=Y>u+tG#(q$;;tX(i4!WdKvQD2jz5fn$&$66*blYz;XAPE3hwbV?52UkT2vs zyc79w)|QusN#a2Q8CJLi+t@nCnm#)?^3_0syPK@wiYeBp zT@U7PzZiQJfmr2^7TNVoL>I_>m zBGaSA=#hDqoQY5LWAE_Av*%Hd-alMyd3W8i7ke`?R15k+$JN89s|}s3w-%hrSt+hw zVn2FD^b8-FP{bwa;FK4TE{c3Obj9cKzMC^qww_L>4<)8WFOmDAOHXB|3 zL(+pS%nyb54*wL6Kg9P3>T}u6Lgd|MPlBpQe7Zjo<9 zw|t*(*$zqGzjAyG!ZGUdlT=oB1rETD6|SB5oUOo=Kjb4{JF!2K#ER?zpWd<$kft}9 z+m~8fegVGrrO_>ce%6HT$U-N!NCSSbz*O`x_RP-H$mhQW9~D3BysZE)qhFt9?}!EK znD2`^srz_r*#I&h0e3U=y@l^0wRW1_BVT8SXE`G(Ow%ZtMCSoCn;*h2bLbPb0F&ByPI zH++TP70ub!_?p)T$6GkxmU4r9aOLy;tZNhQ#-F2eP?e;KC#T8Yl6*d7>X4mUJ~kZpe7m0B z--8WZN?r2viQmGjGc*k@-oHsk;Wc|Vn>M2l)IQ0@757iGC*3{GR-R(MK6iCW5*?$o zX4Zr|+_Z$w-a^|Z{0ZXw+XJl$7j>(BR?ZyK9Q#FY!ZXh`bLT^5o}u$b&Psm|S&^-z z^T5YnVf-pe-*Id>t~~k9#Y4%G<}vYX2<!o8D@2;QItNS057u8rpJJzd$>j&*cKlk-pVu>f8#agS7WSm-;mZK>SL;mdr?VzC zb5?v5ZF`}gxg#O*!K_83EtdShFwjkVdDgR}ZOKv^cji`uFLD2@{iGS2XMt&pxAvK1 zhi%DX;RVQ*?k#is@jKUd4@Vw9&gYDR2kXBBPix7(+Ouz*ktct93h+4wI13Z`aX9`a z`D#xyXWtXUtVzRt?ICS(;&^LO*w-G?wj`!n&#F(o_K?<l)KN%d? z9zyELaQr#aMZeykNvA)PI|?|Ff{sB`f;#$DI@7%kB$Yejj$rTFx^+2=7XH ztGtwN-2*TyY3|J{w5+b?5N|UyTbD;O47_ZewPQI0{b2c$6VWZ4E1%b#d|)It%taCE zD8;6U*`cO}vC&1E(^ao<=$xzJB{BA*=d}e7>rTWe=P=gjvp@#p;?(HFm-3Bm)}{Lh zBiKdC^Ukiyf8MKagXml4;cugF8S9?SCp*yDH(l1RvAerJe*+p3At zmGbT^I~F}$|K@7U0QU@ZF}LL`_WJ!?Ykb4^2FKS$kl(f8_)OCOrai}tqFoQ6YovRB z1z)3yY4-9%Sv~uSN5NmgBn9KH7bCN#*>etN_3TUf^~_%MaJAwKDYI^`ZGRu%j=K&U zue1PZ?WCnxx23L~X5YWZwlll3>{{9(dH;%AHn1XWKkAlU_gL6woH*qlcGIx0COG&W z3&;P*O^do|>mCiqA9T~|4;Z-0N5l3w`nJX^&%K^ns|v?g-L!S9!|{k)&myn)iC{-tGy~ z529(No3^elY{M(3?el@HaMP8hH%0|}iHG-4_xP2-OpHylSx0iG1$sUz`v-eYbED=P z;7jtd?5JBt{^ot0T~&Jihqk?hbgio`?!u8TiT`ipjkZ3PUC#e`+KX7XJZwkKPfV&* zOyGkiCh!Wz2=g#!ysVtn{MLMhva6zpuUY0G zKOZBP6Tp!}IfpKOzc|zEKgg!a=g$&tw5k4VOa4UTFQ_v9#5%@LYBKTIYAajw`S@4@@e*lcE+r03vZ;I^SRSw(wWmZ?`zf((({#z zkFgJ6$7{Zo{Tc;Vy*tlF>DvHv?VR_sdi;L!yL)y^F8pf%ukL9Nh*oH*MptE>-TmkY z$pGKh*P;(=Tzk|tL)L9k@OHC)E#_>Ub7%RNm>;zNbFOIv>(-*<-a!W7huZD6 zVLNN|Jm2u`_*>;&Wf8q&s=BrMn;TPzDFWZp|>~j1!IYsJ+Z@av6@Cz3W znpdU+AGY%K&SN{cI>A*So`Nd}njQkz-RuSJV~wWqDw?{79J^oRR&DpjE^;^_G0wDm zeOj9zqszpZDuZB3`eI?dqgOvAU( z!$&OmM=nqD(`bpDV#*ete|W#&=$75?(%|q8Jbwm{zb%n3new5u@>f#c;W6bs9zXCI z{_r$C7=f48Ne0Ib`XrWyrwlyUav!%KKg}mhv#ZG8flop5nF~Lp7nGMeewtnD%ae|i zu27yu-g;kNf8`ZeA4|3($FcSXUn}{-sqrlNm#uspb?dukK#r~NZuIekXP7vxAA;k` z!fAG2<3fJiM1g73@?WAG!0jJXL&5uZ^@rpOAI^*LM6{?bPo7kt{92wY4WvG=F2Q-S zBe;Xm<-mDz(|Y(ADNtGTi&uvyCo21qSC+ojxX`$%c4;Ye=@wjv3%A|H?a71UpG8l| z2m3a#PTvFT_5A?)UT|uwzn_KsRp8af>*%X0@HjB^iEHCJ>9xLe`6bo2f?w}T*BqdJ z4M4wew34U3RlQ!H{)D>pUAkbf)2IKfcHz@WuohHoRX4t#j!t|G$bfYHm*|5|@;g|E zbm|-!>yr}f(<#`wN$&9%Esn0iFQz^af5aPa+)Cd_PiYR4Encu_WO!CtVBXfuWW`v! zbV-VG$}8cW6zP58l75xGucUp_mr<8@rF%GI0Ka6TT=h}+`0L<(Wau>J?-5PqPi8rO z{B#*!0Icj9wUIesQx0uRF;D1smVRHvoWUEao31qLQN=m&cAGOFV{eR4O=Vp&bHRT3 z@id=S;X9PvRzsU3bLeVMHha?0)sFs_%yBoW0|y@*od$l7H{wexZAh1upC0OdbdxJr z>c=_X%d$hPy}Ul0LYoT6KZ|y41%?kh_k^jHhhLz?>=z4!6ExpaW=p4zFptt@7(Wt>d+or^+@Bp z{3_`MqXwJ!j;Z1J)qKCoc_Yzxr-#GEx!L=6ac*(HJ)G^s4bGcMuNg6TZU8?{eJmU= z=euW}gY2|dalY}qu>ED$B7N>{A*;^$#zRvbTjscLW%c-xWH(BlobivZMSJr16|=X+ zoIcg1M|NQXyRYE9!SQO=ugNLl_*n9YL(GvpUx8eC>zU@RsrGS?WX0D<4PIwG1I)#O z@%F#=Pqi~wXT@7x7{+1G*lmFZ&a*gp^BJE7lyl-@z)`~Y7{0|z)w`}ZY~PA)p}wZy zCsbl1rI0<*y9Gb2d`W_54weeoRFm`4% zoE(m?;|y99f9VonR=IGC(FG~SYl3|d;3jl{t6gW+P72583Z{?#6ixpA=&L{fXOfYt z`q$N;>F$kH)Q*MTQQJ&H-eFIpu2Ix-gI zJn+%`pBd@)vr})5HU3ThwtiyA*NsYU`!2M~P6@O~c8_Ul09Pu*+Pn~2)DQFAHjH%J zP_O+X(r+U@K%JfZ?id-KE4hF3B*}etQ$D`Ygw{#_ zPBncXT9ZSq@eBBy{lB~u$oZ1_&{|4*evZbf;ctC^XdP*2oeE9=B;G;1PHKJkJJWA- zZe^Uh`~1S|>GkofS8t>5W;^|r+cc5#?UYrUwhqjVt1ZQDn=;5t^rKCwyhZ74I+484 zfWF(LF`oMMRQ9io&d9v6cYI6l_{aG9(4uwDk9<5xAdB1yGrn|(9dC&wx1H(opt3F- z`i^mE<`$OC33yO3*^IX+ZI8Ze+P-`?bB?P6y>_2UJy%G-xqUMZIoe&^{ixZuvksG? z1Txf28=6}UKCc}w&FXE3*MA*iSnv(eu^r!LCq9hb+(EJF$*J6V zn%Sr`J4tM*z1OfWUzO2#aB08B3Fy$Z#Er|Z(H=dSDjxuiS#Wa?i*%n z-&^VJfv`PkW@5kmB-hZl!gU_>Xn(gIT-$jwz3M{zR^Z!@54j+R7&GqQ5Z|yRww%CT zjA%cea%!{Y!}YW=_dxe}i+0M^O>Q*&D32e>kH>&j%vZb9Rx_`^z}e&*g0l{kFxS@q z)RdibDeJ;CUOwcO-924zro`x{GU67>>8q)Y^le>pNWSoAd;QqxxOV1~=Djgn_Nm{G zeQ;@p*Te(mFHTJx-fB2N4XU7Fc`mg6ekL>>b$lYk>)L)-s^ipIj{_DRV9dAE| z*q_~5@h3=EzHEwjren+HSRbG7+B0wIo4Dy;(>KkHQ|%2?d;QtpgO@7vnqWp4nEEHC z+RMv({n?MZF!}V)_kpWt4c3mlU`sfD#>K49_S3JzQv%F)fUy|+z*i_{S^mHPzl+(+ zLnjuoDeTlK*oT2lGPZsR4#j`S9{r}NNe+Z31=CGA7Oe>0%9UW)u$!Mqlj2Y+U$trLNfJm1Ct0sMc2|5`&o&HoJkt3A?T!}vxYRH*IM zw5yD^%P*avFYbVMc@gVl>6fFxD_?SQ%~X5NS-tDghrn?Rz~$qxT%GyWRxfxW_|QG0`;k-3a@p_Q|c|1<8x#;P)L0^)zk z$Ybn-q6a<08he}He;ZZ&`D)f9XPPmrz6$u}qVHeT{pc+4N{05JqZV>DMC;W2n-}!x zw0-VgbhoS1%7L#$=XBJv#=RJM9CnPIK%X`fx2Cm|-b32K+nL+3PXg$l{@m|dVDlyw z_jR;$raA>|!#Ahes>jOQ|8xwRL(cjjw5vt@pzi6=IS^X>aq^ib<9kJ?sm;_2AND$~vSvK}5JgVw-2_ilXQ zt|~acE%>J_Y>`0Gr@%OA6EA2heb1Epm^9`N=Z(hR{m5S!y8e>oys55xZF8Xw`nCwq z<}qb$os_E@XoZ)t&#L`W#*fnao9_^(c8h&jcP5BKUn!48U-R+GuH%y|TYJ^nc64!$CwoCFd^_bFT>VPgf_n|Fo4mAv zrEOdH8G2`XX+vUdvkw@!>%6pZSzEzp25zRC*3oTXX7F7#ro62$*_r*@UfH=2IFJ7| zzcppcJ^aXZsbzcuQ7`TI3)(t@VMo@__R@+jY-`9ga1*_>Q!i>O9bn+jaMKC~8JJV} zu9|#tpS0Eds+YDx;5^zIer0Hrk7pHQLvq!E%sD)~cj)xsAXC>c@{bs6_y7f0FgR>y z=eXmaJ{Sb7*9SF2P5FLa8hub2HuMI(H2R<;$G{!B!YxZ5Gz>Rz`@FPa=PS7Xfl{LcCJ2f?FfD#t5pYw+1X=>^KoTE^O593 z?a=R*?_gUIzo>T1zS7{I>ETB{wtm^*pYEkmXTfzQ?NTr8%!}J*CrsH3ytIjzv~8_2 zaAjWF#EK|0^74tT}U86=UsmuPpj*_FPl;OI{jd ztzo{YL-BJ?|In|&yA52vmqwqJE-`SUy)?#J!&eR5a4(I1>_{58u$MM@T3hLT25vBE zm8F-pMSoIeZ++nKansL(pL%&)$A266fS0DR@pXgu5NmXY&U>?`*C;LodD}5z2~KA4p?X4-uBYq zNzL~R+&0n@W2QP|Wa|&Y@!CJJHm07}lz#mAPI~Z3&W*b1FS|HOe`IiO<-6mjij9e% zRq!+Rf{;0t|G5iSg=}s8seygQOGCB_h|d$;&q(V_#)YTj8DwO9FF$_Zm4_b%&l#Kz zUYca&=O*ntUK;!;Aa+&tJm#fIAGesam2O(;i{|?qe0RJYj!(BvJZttV;T{|0As4QO zG~rs#_tswv?)0-tU+r!4G8eAlRRgzFaK9Jaq_aw2@5Q&!g_B)a^Sa@~T+$Ac4R@S0 zY-3KE)XRe#y|R*tw@f{iUYh2lKN@`3dTHXpy9VwmFHJJ>7Xw#8n!jGXGa=qLq>%e_ z+~u zfYr!fR|h_eGTtUx%YCc$=(SSLKa^Rs_TSLmy;(l*7=9SV5Qfgd24S7FmDu4gg4Y^X z@R}D2GdL3gd?{(UdMlsiGNGH+cBKjk(DKl4Q~6pSi5Tdq`cWXI0HzY=Cg(>WUZKgCGA!L;f5#u>~(`)B& zc68Of_#;^M;srx24YhXn(N#0c*>C z+Q!+EEeGhsZqAW+UuJb>4zkXw&&az|@imfz8)(yp+ee4jf0^|a{E8 z>79J5%tYF(wPhvupa-GVIY(U>tP?LUIgzumz{s~5AU@3c=$?n~#h1kTyGVEys}s7q zx4wno-62?)ofS6raq~#6TRPyl73;TI{!R7J_oZmAq`svmN-8OQ>IEw{x$b$}i{rEd3UY zKi|ottl|s%%Htm9Ehy{p7JbCt=|vfmf9Tb3?7nac*()MV^mwwd7JaUFonAhHz9t>| z9*$A({nVp2s{VT24dc+4*|Y;caWgdTz_;SSL95`lhceMeqZ}S6UwLY$+M#s8c>GaJ zvqLBH2W_u9bndy=`E8vOeOPyPiN|WAgJU;$#lU9|hj=Ysyv?4@FybB5Z#!uF4MEOU z&*+ukm+B228V{ z<)iT-%BsD!UVG_#e|sGo;i+`Vy};`IF8bT}9z5UIeEGh-^X$(zj{AGLEnltn268_y zw`(useHiqb@Jf$u;J@(hiv{X5p1YQYc(*b0)h=|K>d|+#eZo9n4VV6znX7bb;*I&3jD$N z*U;y{z^^);iRnaV5A)U03U05SbHV5N2TFfv>KLXvkae|7ZR~e+>9cCj2kyGB(^vi! zV7+-e6z|1*0_pUF!bPstIp{M%X+oY2Y0NmE{_K>H^1L&C5u$A+MV48T$Km+ zQ7_z4eZbXva2Jduu9m&Ds7aE_Rg_7=VLW3c&FUVvG_eFVtefi1&jJ|-X!&5xqY8x zqe5?{6Z;j+eDzA=F+yo`!@{@A?O#yOoM3dZc%U+cz-+Kt*Slk6vzy;d3~r3P?*X$R zr@W0ZJfkWN-`+RN?Zz~GwZb=gS`WT;%I}Ab=++mzf_!XeufA`Q@8wmI=cTVCJprAy zq=^PAWB8reE4)KJVBUJt>Y*pkvgft(TeNlZUwFLoxv!VoHEFbkuB7ghFY2LfNm_oP z@=w3GC;!g0{Fw5`U(%C*tD9d%y2GbQm$r%TwS4<&NjPxLJv?78Jon^H_h_9-eveK{ z^M^_grRevSzb<#yk*$=?h27JCfsM<) z6sqo+#wzW#V4Ex%UzzW(@i zdcN#cUw^cu<*!%1kKbF|eC=O|e(^e=^TcXbtIv-8bXnNW#Xs~^8oo~9^YMQJ`AL^A zj(lB{tgx&R&bZY6iRAR9@ai>>r@<9EaKn#)t4pgd2Hb`dFYM{Bhur)s(jEF4-(lDG zttHKqt7U0;)(el1?z`RmRu2z#_{Z=al{>$wuk(TR?1fri`Y6)tDSK0qRVN%b z9&gpnDbSjlJ0Y+cUgnQ+^6GkDnIV)>e!=a==KSz7=9Yrqxuw+y8v=ID@qOnVQn{kO z^Y)VGZ=34tbn*84d9=r#*aci-vZYvk>H3P{*kNji;MX%oy?$y3PHDm049(BG_$y1J zi^acIU{y}={a%YsdimNBoC(c*_2p>5S)aaqaSm&lK+*42-&CV-=1hzhclye0pv;D- z#abg!wBcmy%op7{gkNYkHc@TpFCP>y)r&~u39wwrF4>D9DZY?sSedGJ4y8~0_KZs zukPBw8!EfrU32WcCfIn_cclNVrro?b^yb&h*gv>56T2;h?<1q}CGZRH_iv0o`}VAG zT=l80uI{xJOTqOR|F5CWQdf2q7rA*>*uLLA>*KXYW5XL4{xQ+&TmM`D9>Ld4H}X}; z_Z;7t==8y!r##=72w^jMeQ=iYd}E@}mv=gO;Hl*j)y_u zbZ}JoaSTtxQTi`&oOLC08g=Z49<}fO8R2+kfqYc`oVEsED|uEl#VqSiXS~>tu2}|s z>%-p~c~kadBP*@Iz@1ibV19<7j~LJ`RkQ{F6Js&Ar~|w@%TQSq-6Gy8Pxz)?T>5MZ zoaI_$1=kSQqx)*VHF8Agal%9b1N(>i546B(@R&F|;k$dQRrgz$R^h9BI$C_w(?);p z1Xn-gzSiZtXc5gGEiX{61bNf=c?~&J`I~-&e9ew77EI#C=wjgzeLI|SVQpFO;!@r7 zw^?;R0*A^8{sZpHX?5Ep**5)?TeJZf&6B&Qm#~&8WlY2v6J^BXm2-~}ad#o_Y`Voc z|3FiJ_LkMp{n+bI+*xk3R@f4{Hd!ItRygIGl?;6Yyp_S6S9P~r4L-hnE2Az+{@Jhe zWv}V%yTQ-7$YSB|e>(R9+)-}dI1pcfi=QzS_SbQjuZ|%1k$80!^jQZs;qATizHC6f z=`H>_?KwKScs=!G4u~!`ya^N`Yum1)4(=8zwt^>4R9yB8_gfz)v?m+PU7>Og|KV>d zWmT@<=xDLpe;MWWu&xhAly2@QE4?Q)y)rn=;fZL~eFEZ1>B&~z-j~0~Ug_mcKWJ2) zqA_`6x#MH+bnEr_eukeXKED6i!+)5aEPp-cFm4cEoI3%-RW3eka{TX>a|TiE83o?z zU^cY#j-HR#uk?YpyVZK5@H)c}>0GaG{q*;@N>0MBwk68_xatd!{(z7E8ect6dG%n= zNmi-jFxj-Omk-FaA?DUC+4Q&JZ+^)7Dsa~SS6 zaQE=X$Mf38glFKc=B^_do;@@>d}33AGo_ifj6pryx06U{t6@anU6(J z(q4t+UUH;2yZVpd-mKC1B3h;U zoGGrQu71&Iu{UPwD7&2Z6m`zhll9VzWdpe5-=o>tlQ235n%%zqMPu7#*yG5cY;(y4 z>o$j0-D#Cc+?eXQfx1QO9(2n>m)5Pr*aNbHw*fq(dEjv?HoA10@tIu|11Iw5lvmlC zC^rW>b7ug=hUKQh#J35?kiO;Td&%JF!Jet$i65XNT8=dZ&W%u-cJ#sES z_opuL*qRjG!dnkpKIaTBi!xI4z<`=4KO^$W4i zyQdRtjelOcUGfsT-W#jIo;DmdR<-ZQxm&&UAo-zQ=M9O3?$+TxJKYxq9bKuCUOI;Q z=m_#Ip-0E_9vx2qmqLf>`|eoajn*Ey4Kf!I!%uv-#>x08<#xYsM^Dn+AbF6yinrp$ zh5?qNgLhtQh2hWQm+y(Si8qfjPT+5`C)c|!HtnB{E-$4_9n=?JiI&pfxK|HaYbc5tfBm#GI{ID8ks-vTdp1{LXkrYLe$O}#a|X{mWH zm{IU}C2}QMQv2_5+ujrVP7EjQ?vZ^@CrI`!#@}6M8QloYi%UnBw~6Mh$agL@CoYXR z^UsUUILs|7q!0TuCu@B4bK@(2FTVRKmnQYYeCQAj4MV8QrNgOfY+2hF@H^?QJ>sQ1 zG@NeL4Rhq;IDrh*9O-gl(uYKtSzTYiAn74hugFcuAzTYSLewX-u*Z6){_f9u?-(18!Vd5AS35uEkxoSN(RD?Uy>=6d!M6+70BU-{)*=R7O_ z1^*{ynE$MGt(<<0i_~c2ldTF~@2r2l`E@&WSJuqhUrlU*Qzz$a9N#r{%hnTa#dOc= zZ(@{no?xwa-wEw$wxSaiZ^3!}d6m$hJH#Tib$)|Yr?<@l+^4D-``0*QCYcUk*XVox zn48;PAx&%306bFK<}q{Iwvwj!f`InFBizrLx2SCa_U7+Nw|H+U+savCrK-1`R%Fg7 z9G9p4CaWp5NPDr_?q2ON4!>Ee?7B~9XGIq=7JImdM0-aUQC8o?O60Hr7{8mey{vN; z_pbh*&6yYV%~E*d*nHF%fR-qHyzoWdmjMpFUu8Ba<&ns(N8O&Z$DW4;E%?aj2XtBWS?WJ_x7UO)n<|!|}{pXII zI-UOa+XZ(aTgyJT=KUHy&Y8V%k~i6%{aA0m_aOQpIBtdNknE+FQ71U2M2)O4-?MkD zckpr@S}%ZB^<(xu1Ex!#iyqx+DB5;Uf6>tkny2J9Q0#~JB>Pr2miqNmcR#U!xazl# zDYq9vUl(&&5j@N}s@zV%2bH;zw%^2A+zsgN^_OU0-K-h4o)gbCA8Czt9_12YtL|@I z=upN|K7Ts@cQfC@)A2VG7aayJ-M7*TUS}@&TCWdGbku`eW#^n{)}b5l*>$?GsyiQ; zIp;--j|)tiC^*rwfj$mhYVZkW1Tg(wIZ=M0FE6VPT4HX#{AKT0<+j$j!qcx0*eVb9 zyc=JdrEFXH5 zas3wZ&mAky-9LrwovKaJA)S=fZ^?x7pFBUVKY&YTiab8WeEY6CtMfbZRZjU;zPuc0 zd4;@u^(TJRZ+&X|bGCby;=AMp%8kCWxHCg^GR9`G3GL8Xg1nnCHoPfOYSqOKA|Dme zV#Sd7(~I{TU$8$ddH~pM(PFg;p5Vvf{-+_)#aaihvmz6@&(*nCRyvIPCy=Wg{ANDi zz+pDa`o7=DW&OvyEnVGrSY5R-qw{v>nf657yB{V-+;7^XJJBb*-_qsMVSxdI;!6K3 zh(txnRFRb4$*u-WL5lZ2y#R z&hJ;CJ1RPAxhuUYRF|A=+b?0mCi=P;Z@xKKnE0ECF@Na<+m1!e`0(bG%jm-ta32%T zG!|ZObZMpUE0W_lm;I$d@s>%{e;{nvk;j0}N!>vVApOpK^RfCv@odqZrj89`ZF_xM z9TTbJA-CKnm9x#ey7fCunao1lZcQt55@lvU!&0|gKJ9;Jn&}JaanVry8TUn;Puq3A zxYOYJ;856J9<>)4fYM%wKzMVhw=2JVcw-Kj`C4Z~d-}^H;QG*l@eEFjS{; zC>@kJQ{yvPA-%kgH1CdxeD+b=Zz3+moj=}mafz1HUkokfqoJe3@OwP=g2(euF6e%= zoOY=`)#24w86Ix?>(kw)$@j|a%#pU;NqbaYF-L0qKI*O%FWJ-C_j#+>+GXQbn3=y-`UF2Jw`R&LFbsjTFCAJ41DoX{*k2 zDQ+l3b=^k$gVyE|+*OtrB6hHVIc&+I{T(snuQgcr)LzcC>VA&5%j}nO=*K?JkUdR% zp9fdxkGT)}dG34MNDLU|H&a$^OuSWQ6RK%twgt#f$ zdd~dXS+ckt8-h4aC%$oYrnUK0=qrAs%s#-l4xk66m#Z%7olBO}2I1Wfu3G98z7lxF z+0+UTFZK~@Xro6}ekb!bXE2Lu!IMcmrKj8P6fWYCsHdU~9;m*ZJ7dKk>?~Ql9@rhw zCs^UoTyP`s3w1B#!Pa8VgB$-IcPmxy@1CK1-ruj`{w41A;r`I9Rm27Bz8=X)N%atW z)o;q|L5!PG@J4Cv#1K#8Tee(;xLoOy_VwaVsOTZ|$o{sH#kyl9LBE^^PjnBS%H=~( zW0|=VH=0&%sq_!$!}n75h0jCtZoz(%E}?InvhZo!nlC7OJ7tr>{m*n!cFHo&kx(|5 zvd6e(D=E9eEgRvULO;FNQMR7*@dqe7E6Tsx=K?mDH^*c*ok%|=k#m(3F7E%PZ@H)Mv!Qm#CnpEd zM{hFLF9O#y$ZGzSxoxRnV8vBa7PSqxhOdx(5IGp#!(w1;XwBGD8$XFP@`_}QRrl@Lv>dNeP%4n_&{ZP6x8@4YSbk zNpyf_~C z3$94^v%0E>!53(LZ8Yc5p-uY?$zX6rKJBSwtiSB0*T6@$J)iRwN^e&Biug%M?g!7G zYto)4t$HiGp+7EDKT!AAsr%dLaANtH^La~yaj&s5j{llBh^ya)Z(&I@c31LoqX*^` z4~=)aekRY(_#=8=@aoqnW#-GaU7WW@vEls+$W=gbeeJMb~u{~`BL+>B01g$6WDg0B(U&OB0_Od>m!tr=2w z(tY%YWJq^mCBY*b!PCR{^DUfuo1*;Gq48FqFE0sxk6%Z-{QHUKUih~c-Y$fXKk-hL)aRyDt(Px>~rqMI4liG=AAI(@$yN!K3 zx@l!7dxfQTFjm@~*!JwE`4v{(!BM=0xHXU1eeQ`O23hj|DQVF=%k0^~VJk}HBkdXA zInMajSsmRwB0p4l)aVoOq8S=gK3j3i^tunLwg%`p=gLw&kd@V^hZeFF=}e#cG7pE7fmd=`cre)@TMmjyU1D5r}UNhB%P8m z=!zvR(#tNc%fVHTEl>-tyU`m9&>2I;t9dSez~jh4n%=-(L~l?JZF?5E5&q=S*7yi? z!H?p7v7mGBpVR&}+7BGI$F}Yv+_l8oNcHQT7mfLJe&>tdv1k{1cbnc2`FN}u%L(S} zxF>P@)eO&u;?M~ApLJ$&yk8FObl=dJXvsQjBz{PL{vsp(wqqmgVpF&p$;+=G(bhFwe zUFhlF9l$vE61#NDcAN~23y=?u$#<#8>*GJ_H{(%q#+!ySO7J&F*@M!WdKvF`C6Nd5 zshPgB)+a}%>oD1Ty>~A?Z}wWyC-Svw?xOBG&hk0$RCIS+#oCws>d5X#b>D6~xI4Qo z);Z>lJ+|*0Rm z-SF9vp1a(^^}WTYs#6ohjN-;>KYQSqO9tbjEMK|Qnrn`exz4F_0F=aTcav}wJD#u ze@Hx*R_AXir#t}j&<}}UubVz)CTA60bXwK<fL$llhaqaU!|M#B*R&A_35`NG=8i48K(Z_pFnT)@NuwCbpsberoKd5Gu^Q-+r}#7 zUbjaE#;Y%7{=A(xP>_La`H}LXT{-A#`K>Nc`!09!|6@qJH4Xnm;MY1-WvXup$0xh~ zg{am)qy<(EwI{e~^v(DO9v*5>y*V7WE;BfHd_>=r98U8Ba88H5e|mUt3fp5{91*Rb zz}x=JU^~xEV?2z%>Bg`VtNZ{4}VL4iG9!7)H>gj3F7v43_0Q+ zR>7)`#k5s(Zq7^GpTM_p=TqNf%mJED^%k+xDv3|*WL|Xay`u~dTCNYMlFa=**< zk(Z&fLb3#}Q}lg!WcXL;@8PTseUY~ODB{Ta$S{tEgeL7!L?d&|7kc4VJOcA6+7 zzFrJpH?psg7;nn#fX?-<{k;%4uOGh)yzTO){qe!^%Us^b&e)6ol#Unw)TSNqv({(B zBLfv*r+g=E;|=K^n`QGr>++jEcg8`H_BB{T%#eKikoKz&qRelh z(sS&!1vpDpX6xLX>}NOog!XSR`;LEp3wR%0G`aFHD04zG~a7)R`(i5PQ(_2pV&o?k5v5M zNm<=9r#G;Y^Z;_UwjMt$trC7Yo^G%az<<2A)508 z`V#)BFTH+@QP~QSIl%}?&!ua#R!5tn&}J1AS6^uBlh)LF#%_$0<*IT!2C9jwz(bmgt3 zw)_jt!Dw;En6S;bHFs3O%XO!O?E?3Xs{Q!o1^;6g&usVpvM2f8v%*>|n^63+xCdt~ zc1(@tJ?Acu5w~d#rMiR1n)&0q2FJGZ;JtGfh{h84f!sj9HGj?>=E#HiBw25k+;bO- z?gUBjo4u+!y(=etH6sna{|2ANiPyfE+iv0n7jyQpSah!k<^%2%@nE#pt@82baYK{S zXL@V2)|a=6ybe=#o926qww64Ptp(3$+xQgY^~OSLm2hv(H8jnk%-#FD$G>up(J{m& zj9%)jrfEAn|w2O^vd`D#*jVEMyAR4P1Iivos#eB(c!rb{2up3^1Ul& zkM!jGP|OY@(~f*|pI#t>d>>RDz4Cpkk5_*AzL4~PCEumw|10^PO#T~LdS24yk*LCrj3E`Qzi=RFv_gn9<%GwspybRWf9~wXgPN9OzdXqEbE?UAI~Pe zo^;t}nm-fU4Bk-m@VVog;ElMxPsLU2qfO`p$7VrxoOk<(HK<7aZp{?v$Km+ zYxy6x7T-0*TFm{fgErE>6uKoN!u%ADly(;bNcc3plouhMwz53?ojre$Iukqu{ zze4oHwWv)MatMM*@B&^_#u1B)`>;FzwJ7 zk`41(5M4#tfHnM8!A00N6I=^%%(@Tj3Had0CEXqcM~}bVSs$6$#NE@kG^Sbub?I;W zNQQo-de}eEoL~Q9-!fD{zsYtP41LmvExWVk{=L*%MPF~STKkrvT*{OHE4{7t)oNs- zo^~XVqo3s&Ihs$}oBXMM-T9^U%YOdzrfyH!X5PtGevoxmlJf9lt9|eTp7$wx2VB`}gEtnsD=#vBmm_!2OYTNGawmCp z>itF!tzEQTD^nu=*)>>D# zI)3~KlB4V3x7N<%)VIvL;z{%7zWeq`c%pb;7F~|)&Hl5|Q?*K`EHMN{@8(*ox>=K- z#2w^0$cXxZzTX_#XmA#$jq^t+E1e@*ob2LlaPNqo2z?8G8nbT$W+ix3#|Xyu`@s>r zPCU@<*gJFBpZ^|tAy+TS4yguSV`C1n#mX!6&vTh^R~Wj_;N1aqB~0a+Ag&oS3J-gzWzG=PPPB6pMD$Y?Wg1uefLud z_4@m%z@_IHrMvyK&)-ka^!8I~L*M;$GG){IiTjbA_-^&ngzr(#ZLfv=jIbCBp<%lU z|3yCy2mXut$?nZNqMwc;@89*4<(2QFpSoDPs@|Gb(@$-D|L6VG>p$0+`t*k}JNK!W zEq{^bl*BK%$6Ed*#+>HA_xbC_#@5=bPk%c0yz{=q8pHQFXZ89CJRiYtp-*=I9b>c( zwsOwMHTJI7*U6E*>-6qX@#>?9iTqX8=|jo;y~Z^2S@dkP{{N6W^7LIjc5wU-d@Wj! zTk@5Y)?PR`-b7lGF?v70Q>zUf$Bi3e*QSltC!s@Y^k-cBl`{w1*SPqaWut?y#IIcbr>@ylJf6naN#`J`R!ra{Yu92aNH6@%@m9?s9Z$0zCxJsVCn{telk z9$y}Sp7$6}!WU@DvM0Ia67r)f?byNbaUL$0zLKK{$4_^$49zp^?J7%xOE${?A$cC>H&k}wwspV9p|N%wMsTnJ^!`O zue~+vC$kO|p?jJiGHs3xJ=`X`i1uFQ@+p7V;P~5l$%?bVnP8rL8~KucSN-{!gX4Q$ zn=whdqo0=8)%2Uz7aQf5XAYA5iTIys=u3MzvtGGqK*VG+MBuoAA@|7yVtKAskb;1pOo0`*iiT{<^#mMC5TnNlC=6ya-Eo$*Pbzcw`R>7 z?C~ss?&xA856*hpl?k1-@y5YR_;Td)!#A}h<;aeO4M@yl&?=T6i*`GEO1D zcwgKcn)QbSzx{do2FA&2sfpS7lv7=T4Wxa0XA|Y;Qe5Jnv)PB%_+$KJShJSYV=osp zWZBikS0)>><~~P$CH+wVPb1uW8^OMw#ron2#%eu(+`G^e%4wd&8=VshGn$LB|0d)Q zPz;%g(=O$#rOxT^Mpwz^^4~K>A1+or=34IeZP%K2si8fe^#}AXPT0M7$WCEgX}#dt zb7l6d1Db1eR!+JkA6im3nf|Cv(;er~4`Y#q)S{R@3%vW7tA@d&1hVxhYY&Ux*2%mp z$9iTjHp2VC++8{owT|;f32dw>tih!-v}S6do*#D`TOwfPzFN(?iFs~UF0m1}&<3rY zg49J@!wK@#X2t$;F7Q#kL*k{YZQfY%+d}C)X_^23k0;Stee-1Bx!sQzLRa(L!+Dat zqn9WDDL-!ef8fXU{~gm@4F1o zHLfZJ4tbLtDjqEf&Z`+a2j^!v>kP%IaX&zje8mTe$Fd^Pu0x?r)@%KUSL@#tV83y~ zfaDgaj!!%=+e5%M}hqlwKM)ifQwQ-4Fu4nfm;XzF+{ zi?NSSfxjE*!{*2lNIaHV0}v3GSxvTT$tWVvd|Qq7&=n(rL# zQ-LxK7+fM^yYrNVZqtZ^U?d&HCcA#{KTY6&HzUqjI6LY1FV>z zj+(4Eyr0of+xz}Y5oHVR%Zgu(ZkavUjtj5WI(y@}6N16l_Dr z5GQQ}Y3eVd zy^igm{$B}BN5-k+PxyVhgE_l8z+VuwUD%ODys=aFBJh#};mwy!f;Z^mR$2>jn8E(m z8#;@+Pj`HhC*F$BA)eO%XdF!( zP;$#;JGrHG;5}^}#DKPpENfGra!*l{`jvfi#*kwBbDOH4##RJh1AIg#wh4!5NNBuG zG&*uQ`JLeR+u2Xi#w6+acV@*q;R|!#CgD+Rcsu@2}ndC=_?>b$6E9P5hamu&ib0I&-ez)48nAWKF(mV01T+3TY#Ow5TtqsWOoT?d&B^u~td1 zCrI~nyT+LGyLTsn#_Gz+N8ywl$BJouK#AXg|Ll zoc!mzI8w$Kr_Xjzf6kfTw02)Tj`|s6(k~ig_1NS(f30ywe07uNt}V=AZ=ZpEu5~N< z39Tuv&a!`}`QCg_sMmk)=zjC4m^~U=lWxBUGs+q#X`UNZ)^^U((T$9`iqV7a*(iAy zO!cVf!~QWMy`z|HjUDvX<*PUIwqAehr`D-4`-V{^&pGiO>`m&fQN7REiL4b|nT2hh zjf*^4v5xh=>@3Zb!7HWHO#0)bH(zO8-g-rr{bkw_x+=?V;J5NuktbRd-|weIY2u}m z7BOS6oAtyC{HZ_smRYmMmOQan9#ZHuuYV;U3BDO0j-4)9*~oW-x)R9BS?RLk*dn}z ze0+?vliY(mFR|Y=Js`ztwM*4C9eZJL;ARke!>Pt_K|;Jcmtqq5AhQP zV_DCTUcj0t$hft@(^43-3xJbf8C$)MJIve8u@%>^xXoabC%Y{LF+1YmG&XsFZ}2a+ zPX7NmdlUGms_TLO%}fFTvb-#;BAH|mF`}i)lGGqG6I9%XMXOe2l7IqH3vLZ=nIxbn zYK?+e+DaA|Lanw6Rch5CY5igCB48=DRzk)d>rzAk7yjS#?t7U#kHP={^Z(?N&%Arj zIrp4bBe}d%B_?;R%nCy(f!W48}a=Hq4#4yI;{g2{mQ?k*Q42EKKW4v``c`|roz-4nr~i1`(_^#eX<{MD8JVa zFjo5cl{z@OEg42%lso#5qAjwkI=$Jx&eH5@{AP5P&J9&~=XxqiFXfJV&fxP+j*2<# zp?jj93g1}cfcH|~H$rc7`2JrjdY?mlwVB_w@RL|zUw?ye!6;e+UtMpar|XKSSHEEA zmw&~d=8C=W-H>mMPDd{Bm*S)L(O#ZHC_%8G*e)wZ}{1Se0HY7E!k#A+Fy&oCV zqy4H(eLNTclPK)p$r*T?LPjOVwbi2uQj}T7;m>l?+YJ% zXENuPNx$=B?jWST<=MgeU#MeX(PVJK+nE-fS8o;6w)8)Ut90|0Y2}P;DO(l8ZEM)!uKS$F-G4n z?~chi@;7&f&7TXc5a{I(n#VSLv0 z{rpH3xae`lnUvo|TJSCbUXf?CTmbHuXK-$v_jTJ?r;dAx&H4=;w3|9s9B<@XbwQRN zP#<}x%!!rx#^PsL*qiWc`fZ-YTVg@V%nwrLe*BNun<6I_3~nluacK3fu<;r93(b~y`&UuME@T_a zzL3!MJ}$Biws7Tp;^MO#(5u+qI?9XoD_qg_SYE{N8~L)f)j%6Hl3)5*o@r#rxhK{Z z!D)XKoY9m=8N#F&=pcY|Mz%Dsx(;P*o=3O*v!Z>Kkd97TK~yLO9FVQUuNO;E@TjxZ1{}MT;GET_3WyXfBbLJYKdHqdm zqTmLz;%j{L#{h7CSNQ2)VZ*lvz0aP**>_^x*_1gm?whm2_fD8^gQ8b_Lp$$p)nbd1 zuHyNTkHaQo)z;JT4futvFH`0`@e}mhM|ob#H|CeJPPNO(*wcF7w1XYYH|4p5_Irun zFn&SCx_gjD9P2f$s&E zHfS+oO=}t$`;7ZS2j9at_4xXiNj>6kg-ve^-4+=WWUVarQFy$pyS8(_QR1;#?}x2> zpay>wPWndfypb`bW<>BnEB|xY%k>~nE%)-Y^DjP5?4j%5=z+3oOk?6C##r%ht6vD4 zn^{-b$+|*0>k4h)|60adV!61A<5K1);%9p3lO9(*CVb~5!sgsE`fIJHMfBN9S)$uz zlsAI%$Pw=phJqOUy&5Sud z_{%&(XxhAteLu~M;QwbB{Ex%-Hi@rKAK`^ z7-u>cx$3Of&#AL}o;Da6xC8INqv%zychs);8I(CptM?Y##FEXf_a?i}`A4YpKI*)L zI#(le*B!}v{;&Md>Wy|i8LU?{j|x`QyXq-4rPn0u`3^MFZtgmy^i%Gdp+C__RctEH zVw2G)!dARd{d!npxC5mbYHlulO2%GiE-Uzb-+JS0#C2Pgt;!gF1O8&tj3{ z_Gh_+4E=5E;oa`R#QU+A!=}t7WQ^aJd&@H;wua4{d1qDpEOs(6_W@qg?`~NDTDS(;OBOH!`*k3AKYx|qaw!loT_Q_5O;mW zQQl~ib zw0>%u?LQn43Dw26J)a}%L99dC`U}I~(Vx5%%RP`=MSo#q_=*bRilylB7qX_nf3Y!g zk5PE>!EVa@BjtGLH?d}8Yuh)6CdhfAsf^`YfYtO1@m}HZ^+G@F=|igz0(*vf{g8U? z@){LJcQ{gvFHBbt1D&MUd*A&F&iN0y`?p`&7<{6{u?^fW_ddG*oVD2P#Lc2}?iX2~ zkUou_H1N%5(Sf{|*C>6PceB~2S}A*Za$n1pnZ`;PkL6C1-OROmm?L-EakeuL5jzO7 zxA(y1+*vwEtv5@blUVxQ=ad}CwElJCdAS3x6+Ua>i~Y}*Z)CUe`<`tNj3JhMk0HZA z%H0V6EK3%}o4Cu0@!hY$s^7+kO;?Q{6kpNSM&HSjy*AH^l5AtE^v#}Q z*N(8-jd{|^zY3f0&?cvkG-f5x-P}@HXU%w(dqFK7Tv6kxsAimuiq9@pv5&+8UeN=0 zy`smh4V1}!V6&s5(*pJguycV4zF}mnkUUAhL`;D%dbO54w0ZYtbarH9u80zE)DmYz zW3e^6cz4Jsimizb5xr%szxmJTmiBVb*|=**-hcS5!QGFgkA}@H>%!)-_yPH*WEFmI zHtRF}Jx0Y`o=;~^Ih8o)73q)2BJ-`FUtq?8G3aqL@(bU&!2DT}gUkHEibu0Y&T2J` zK{4>eX5){BBh~oSV#-AK6+!Gl^cW&Gh$2e~b0#_C7U!%*A!YXC+=KW?Vyl_b{*QqZ zy&@zr_{7$=vE5 zZKC|^3!OdpB))~2vIOYUnRuaWr5VBBJldaLNU(Eq?1StEMn71jxf zQAPfjZ21SL$j{wV-l7%q-nFG;m;A8?WpkVF44c9y;HTZ;QDgW0;C-<*QjZesFiQXa z&?(2M$8tq4Z7DWqK)>6C(|T8Uyyye?OfUZ)>@IXWdIPrvx#fQElnCX4eqf{lnO{4bVizkAvIi z(|H!#6dg*;Vz6#vn4T3$-=xl4V8GUS5IGMl`&e=(^-$(jYuR^i!e6i%`f3C7=j%>d zy=DgT$B1?O_zyWJS%Cdh_icsvrp>fRV17-x+FF_rO{X?k-wr#7;2+ZEu6y-ELVek?MG zZOZ!6-kNEhKR}nVuXcISq19hO@A&tgEZ)r~{|URFu93A?*7P^hrV_gd-x%#v?HjU! z_1*GNoxj|mY>E3Mc96PP`-&`BwFZ0rpnaze@#Zy@Ei(7;ya4{fZz5;2qP1ez*d70a zt>4%-&c9ph3&LX~dixqae%s!ow3FC)8*Sy-c^v-jhq59i2Z*;HGR=bn)g3n*X;4R%%*ZU>Lcl0HEKOrs_{mNLC60b5pOMdf^ zSoKO3AJ&#)SBxKxlph_#xW%*h=_u<^)ug?QQPTG;A35FF`uWhcBV@ekUCleN@LB2g z4m3>P3h5`eqO0BW!;$!WVjbF#Mc@ha=L#?XKH8&{-(voqu{VwmDZ?6j4e0f;)rzqu zaGx~xDtt=gOShHy<7=?l4@2ZJeokUbvS?T$WldJ>Hac z7{)5@EKB{Cv)l(Ddu4LhkbLvux7hs7OTy+M`iShwt}Ix)Ms(Vk8@xaEt!i^=?={$V z;g!=m7t`)NtaYy943*PA{8s-MiO)0ECnzt-{&<^r2=+5{&#$OMDSe`Sq17k0ekHo3 z-czx)KLcxJJ+G#&y4*Wo`2^`RxmLfBd&&l{UuXBpN8o3i?dl8o*Oj?(x})@oqCIy> zyJ&slN7%W<^GE6v-uJR1oBK6xYi%&iiCUlV(>3q^ju^&ovHIMO&U z09!Uf=#Oz6xvlwtC)T(oG)$eT3!=lI{p?{6Y%2Tka-OE?2Gb02uYCf!iIXdZ+-y(@sF}2yz?|v#(24ps^t8z8RP$=0d~yc z+#%1LWIH+#9}p#G8Ec*4!!IFMa;)Xt)VX2n{E752YySoOAowG}zhS1)DfoInC^<*^ zk`>Dx@H3V>^Pj!gl9#*GWsfih&III=RFHNiH#i@4;84rqLpXS4;PrM z{cw*V@|-l;SSf2DHD31HXp2VRGR}7)XAFPmXPl1_OVDqu`sw~iVwu9}NjgErfvrbp*t#bZY#(I%c#&_#nJN;esy3MAQ`@H_f99H7lm7JSUV^7igwZLUf zx7wCnsXnkqDzutge`mFF`%#i)1ZEJgr>u*>EGv|kBlNBpddwKDd$&NU;w zU*c!rbs~0tK{j(i#!T+vTyNdO#M{gPT<|5R%GtG z^P$7j5}HwD-T4q35Vp>y^{_@1x9M8toHXY_BsOF`B&Hc+y%*Gl|C0Eo2EF)e%*Zh0 zVScn}s;jhPrBYy0v;R;WMpE#fq-ZGAcjt!5OwAiR)o5}AA zIO}WATW208m12*?^4-keySev8`jOb`W^6U|bqF8i<-0&hyPQUu8T6GHca3fTGGva% z9(%ZhsW+hRmWWbU-=)~_smd0u{>D3gAG234>yQ7CSPz^G$`PCF^?6!0S1Nln_Jx!^ za*kK*QEVnCXX^vX9(~x`^|usR_VyIzN!g?EJ0g$4Tu5x>8`hrW{9CJSPp?^g3)kbA ziliKoA>~dIVifAPsTF=gCpOqEG}zvCoX6aSZbepS&LQhIeQ_T?Y;OSn%AI54Q-kRL z&HlE3B`-#LCuwPiKL0BIe@xQvt%DcykOR?U!e;1HY(d%^{C`h8{M?Xr9_r@JYMvnF zz*}?~#os+>mm~5xc`bHc3V%5_Pn#=WiT`9>!NFf<<4ern$l8G0XU+uf_L*&Id}bGC zSij3>iZ10mzq5WIXZaKKp(g%iyqkzG+|B*E($_wDLgx1SpWQt)cwp8@`Yr31)$}v* z)v}%^=g1mEYD~Hpok<%8Iaj;#3-Jeq>m$hQ_@NnM1K_`ePuM~1CFS%`?wPjD$g}9O z3L2u_1J7VX!Jrvww95)X-dHfL!5A$ku{iVAFVXiG^r?p~=e}JT|ELFTxPdxt7%uBitSQPqT-J%I z-}*_%@I~=_=67NBu8GVKVr#M^#pr9fv?2HlPeNzZA^!91NRFN7qYY~Kmv>cvbiA~? zdLJh`PMrnJSQkDhW%c|#+svk{3xp1NHZYGo#2M7#(5_@{ppZT&`LaIHN^IDSP7hxn zD6(RN*m(Nv-OM?Ui*36cJh3@hLqWeAc2AbEoU_}MEqf%_QKoh08u<;JYZCtj-o}%$ zC%Fq!?6Vag_&o9)L}x!o78y5mdE&@3$F_^>nb)E(*6?NR{wPbH_B*hHwXJUswzKlHp8zgbK@z62-uNyzMF3~sxhwqre5{LrHlR3CkU zyU#^e^Pw*u%Db!Z?~%3G_sF1TjV#5MsEn-6({idhZ)3WZE zL#wSj{wY%*^S-j?>1xcAcT3~GIXj$R+1I(=WBc!el!L8G+*^l!dg3A3ujDL$5&JFZ zrj@>urN*?)w3n=h%ep}|^Nk0f^%Tk)0r$*i$~&3Hfu64qnKEWa<+nhM-J(y4X}riU zy3pg{l5aw0jPbN|X|U6~RK@oq>)u&^=q!9EWXgRA5-Y~&Yf<`{Z6U9+8hW_0cA=qq*x| z+6Z~ifc~xn;`=408od4+{D%{R?T4qtVDS-VWU|$!Me9!iKZuS()bYT-49?}*XY)v> zjjwJ}zHt<`VZ~Pm4{aE2m(@f0l+@=NH@rzZ;XfXxjsCy*#^7+)?|z&W3HiBeUhJOw zN_(dBjgmK-dKzEY@zsAq5kETWi?85q#aC~J#{1pzm34Q56Z^kl#a0*oGi1e9UHG$7 z_N8S_LfS8Gx1X%@-AetWUHZ;-+HuUQ=va?q9tKa&*h(A|-y{8MC~c`?8EHqUQzo&D z9>=r@jTXmv(Z8Gvbz&LEkBgm;HdfADHV*&I`xjo`H}u`&nHA;E`>2s|me^|#`=(*u z`;+zA*7}nA66QnfJAKy3*&4Ca>c4ZI<^7NuK#nl~4a^mq=+AS(qnwJ-hH*e(b2u~f z3i)rd*FO&!X9Eso@Xe{Y;H1F+qQgxKE^(-=`wM;Vt6?($y>ZL1S<)6&l%x8~3!R34 z`8Jt*No;fdPgJZEu=LEC^FN2p3#lJ82MqtxZAX*8nf-SsJzUZo?R0SYw!x%5&{%Ne zzHRxE9$3|v&LQ3Cx8aq)*fv1YCpq}bXGXbS-Y}ML^N}C(G9UKh(-`BTeBaH;+A+e& zHU5-UCw{6DC5!QMm7 z_+w*9oVZ$SS;|!Q>9y96v6FlsHfycPWd~cVa{R%Tsb3c_@l@Vz?F;V6U|+J*C~O@~ znIlIs7xxY-F@yQM({~_Nzq`KrAoj*{4SYPeG(0eG{_gsh_$Fl(Ta586WsCi>&RST4 zFZMyp-gRNM=^5lB-Y(&JF7yFtm(5SqH_Z>!S6R=2`lY#Hb1ATP76p zb2WRQMrH5;S=$M*zDT|DL-YOR!t0Oh|6A)#l-)BbY~F6fm-xWjOu2Dr=FP9Jr++P( z#-6N{zZSaDgTm%Ao~MEH`24r)ALkvCD|Q}Re$2q#T1-JPUsQ-^!W~@f&!tr^4m{o{e8fJH(gt`1+NV82ty8yi#5Mdt&bX zp8kVm54P8rRc66nxw4$S?xFo(4q5fs!8ELo3XY#PH_UFhSm z$$7#2myN=cEPV_mE&7J%Sv%jYXI*sS7=GpX8_M;pQ*9QS!W!iK>T<^Gy1QwwcYOoP z&f585y{zZ>e--A8{=hP6=jdRmOMFSSvia6?>^K#bE-d3S4%lY zF#n`h^!s1(7OV`L_dXIfpMdAl(pMiB9WakA5S^eWWGJKk{KSK24G89E@jh-3e0QUZ z8g$c-di0ZXROI#g23Yx5lP}|s)c<124BF3cBS%)Ik^dq3o$oO=y^GIysbox@_}eia zV~Odv-xtRQHhY2x#=|$pud(xrdZXMZAZA?R!RGv)_>yCht=Q;aS10w!3eFH%5SyFp z32rI@PE0tn*T@)@PhI$S=pcjsRl+)MX;%fY?@hy&1_7jxVh`h(L?k2dqJwdLq zWL!o^!TpCOO1hUbnod~(%BcQ4WE#Bp(@Wb)KdtUZ9p?Aci*3xEUs`|c&e8RwNss3F zN}dy(6BJusNV;LZzy4VMo$~<(u>Qb$GL#+rDYF;ara{Jp($7NXnZRm%Ve@o;0}FcU zyMT4=4AckSD6RjH=R=g$gH06s%jyz*<09A`HqWO0Wo{pwUne@6A+bwv{_*AP4=t86 z(LE1_&FQx`JRtALw9lVk&$nR_0 zaHQ=-KgC8yT`lq&@ued&NXO_at@x1yK1b-}+{H)8CVpdWNuaI@T}!`^_V-Bp+hy!N zw4y-Dz}LbrP~Uow^bKqX`Mvl?KYRX?_H3ys7n_y+6;CC)U$7f}@Nes*biw=e@tvjh zr3*^Pf4|<3j=JbiJv{gD+j=j1GV{mQ(^r;k=64|d$!Q1iakcObKN>RoVJmNQ-fJE_ zMgRElZNvg~@1c+PA7>BEles6s9-7bNTPXJSSW&RN-~7_@F!uN^v5SnQr(=T>Z;U1; zcptg}#MO=X8}aqb3pdIBe>i^ZtJH7B+r(z?`n>Cp0glgUF+BawE;hW!XP~dm*tOVh ziII6$$w>Os#ntth{?pEqb3tOu@Yv*>A(pj`?c61?l7E>a+v_cx#0H{XL+*Q8!gIc~ zUCe7NDK>+PtJy=7*yIc5$FlFsm^RZ-T)2w8e=qrMjPsm%Y6WgQg zv-MY?kLHg;=CqwX));Z+A4jt;+^_C0=w%@P$55BEcDB`@x%1Kbh5RkxZ;od`UCDjR zMx3^Dcm0R7^Mal8tUTGnnYPnkFYTQ9hV*s5!3iJP`_(M#MaM+ zN0fSa_^v~k_@d?K$;f ze|&`S6uHE%s==Qc3@%33v!lV_l4Z}c?#vtN33-bj z^!d?xgL)+9k0~Dmos4C*lpDrZ%enAs%9j37O8;>B-=S_}>zIw@~VcZj+oPCR@P-2CvGUH1c{xzAZ^C03 z?YJL)(KmYPqsZ<@o?|Hc255JA1|LQ@7`o8EZmbXf>xTNPEPP{7@a75iLMP|zhCqAc zzsJ>2gv55L&C;VomVFIqZ>xmrE_%kZB481@GZ^R#}}d*{<>Z+!M9 zVub@^N5@BGdNRvSV@}gcOj$hASbQ3=b+pHH%9OEA=AJoHCS~lxramC=_DjR&a?064 z8U6gmj4`8M9&tNm&?oXKOTLvgQ)KJ0<%;qvHsxh6u^QSE`crUAwEWMs^M}~j0CYwj zCK$|ddA}=PV#S`Ht617|(SrIo@vAX?LHUd5X)0}f9QIQJj~?zjDKQ3|E&anYdh-Z> zrZJ<$7&uU3Sf|g(dX3m#^=vio6kC=(%3{Vk>3_u!8J|7Cy`$nsdS-^l@8BLb#=eR! z-XCfsel^&$mTv+P6Hc6n9>k{q8DbxqcZc@dnqa*oF z_c-Ll$J6&c;^UW;Kwq=v`f|>$PQ*s?o%AG0j&yV&q zmJ~o69cZVyPf~np$g9>|iaAgENWn!niEX#vmlp}$%DPTVUSt$-?zqp7Vxv|$|C(4Y zGA;y)3B0g38{~qezO>8m8Q(X6vMK`eQQrbbC` z3+E}Q+lSCe-P&GRP(F_KjDqtNeq!n{WAQzd!9Mhi%_Z>>`0*L?o$IxpL3JO{H>Ca_ z_y(0t9n5?~+BnCU5rh{1P%srd8Mm(Dy{}C8^-#6}FR>TlrMGw6wD9;i?I=FWY41|n zbSQnioi?Sst=vCT_7mvwO+~B&l`)r}DfbTUXRV-cIr9|w6%l_J@aGIh-G|)&IONr6 zIp-MjyS^VbZ_MOd$ljrKonGVYM(Q+mfNDqSE1@knlw(g5H`2!9%ftp^UcQM;nSzI| zEW40AITJkfOk?q1D5IM8j`a&x$aj3C?!;b2Q_of3qH)UjhSQ=V@45EZckp8O*FtyQCDHm1(5XQm1y&~KCa3P} zzxV^jTsd>E!tdo)h)NZa3kNei}045nDbbU42)F;jqnhd zj4_T3qU&GSWy$l;cpk)W4*%KwU(*vZ*Ln);!o-ZR0Y<^EmlV&!w@r*Q=HyJTE3d;| z7xI6Pr+m^YKo5XGlU ztS7$9Fr__-b5|4Ndx--XXN;&ZL*_aXcV2~#*8-J z0ed^dool3b@eSH4@S4G!G`+MucF~QNkBeP2sb1`?l~`aN_^cyr^3R`J-fGat=Z`LL zy)A2&e|n(2Dw`Pp{*Wngoev%c`kBc5WEC=Ryv;Mqpllh3YHkaep^NNT_9B11d#zUd z

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 z z?|tieZ@cF1UtQle=Qj%uX#bbHzB2l+UAsL}^ZmE}?2g-?U3+K#$e+z=z5B^uKXu|u z_Smzd;iiE(*SEjux{>b;H=VWjf85k@@gXaEp1Jm%3%@gT^YiZ;e{jw%TXQ$%J~#B# z(w2k2dj0pmzv}uszq$9LR~~rGb&r1ahZk+mueq}CBe(qIH{V}!kQfMacFWCLF0{b^ zaz9nM!f@TX?%aVa#jx~6Dk}={z`0_dqqWb@o#ga)J2zSA!TH67XP)HHcFv%1! zErP4C7`?#;dd?BW$x*=mgbB`K1Pjy{VK5Ci<~kjzDClxUH17ut+w6ta zEaIEojTH3WEDM~ZO{x*@S&p&8MGM{EDYT6n2G-oA?otDBT;|Bcp+Sz@_FdHOqD0#Sfr8)^T;L3+1X&A_HA6(|@C&4s6pYxnero zpiL>3Z+U4`shgQGR2v46flIf&;=mW*{@K=#J@A>i*WdAlzwP{a{+UAt`&V7D@BKgd z<_o^tKl;a!-~H$#_cmO0|N3A5_T1mMF8zPsz)yP)|*~(;_vUDbHzS-{e!Jf{C$t!8&tC#%vW9$FAV#%V( z7qmatam`Ur{(j2=zyHRYKK-Rv9Q4-Luf6FDZU6NAzbq}Ze|~4p?%(^T##@g4#qEne zJ9gdQ&Y$z}4et@Xdc2N5f6^P@w)CQ|HJ5&K-68F3FF5qOTNWLC|33FNz2j|nU9Q6m;!39q}uk&|{WAz(8`|G`)>HA#s+dp&e$1hm)^wUdjduGkpU%uG< z(U<@J^uNv8`=P52_~oZoJbF?6yPlnO-DSsa`pDs*zGwAOUy=DaP3PxR&)l@%@XKGn z`lfIH(;atzq3x4D%Z;6|A$MK-#Xr3E@tfZ|@5_7MSKaq77cB0$_~vuI{R#`)>c?MW1ZE`-&qT zdCT*E`=1N8pSS;y9uj=6Qha{m9fuyY;DQCKuj;wH_C+19x#X6c`uCpS^WdDzUm)6&PkrlypE~aGJ@(oAo=?2?iPN^VzT@IWSJm$MhQ`9~ zW4WJi{=nKh|M*SKQsS~SAYB3d#YD`{Hm`% z`lt3U+?#G0RerKUE( z=LI(`eekgZPg!&8U9YTu*BjqG@549V@u9VgZfLyZ%KQHKnXjDpP~n^#9)Hno9{(%e z{H6P!Jo#VSuYK`~fejBXxVZnoU%%mVA9%9));D~zZ?}hk_S4*_|Im8-mg`%udgjw7 zy|T0ViuL>d^XFE4=$WR=ZoFaH1sCmn^SU)ZS#{3mKD+i~``)ngj;4Rw{;uKEX1{XC z+x43s`t~8e*miKk-4|`U;AQVW?=7GD=AB12j668!?x%7W-gCkw7hU?$g8nlu+^hAY zr+@XCJ?=l@l!<{y_Pgou$6D|B_shSty>sbNy%)de>>FP&(Ek1fZ~5-do@ZZj^vJCb zoEp&cLuXvPpziEnZMtm3X9o9w(P=;4=az>?j(qS94VPa$_=kHB{nX!{n)AZ1e&M#Y zCx7Agy=J}RH-G=h-_JhpHIFK@NYNX z_R$+&w)LL9y9;MryI=h+`=9yod!9LZU9Z~s>65R%Zg`HFz15=yxBg zi{axnC*QE-@vW=cKYh*5Z+gpDX6G-9&BxohWJ*i*k;_P~c;@W89y@XUUHdu{Ixhuzxw|Ay|PF1+mF`cLfq z#-ml&d}`iR4_?>1W#q*jcf9<@;a}{%$2I3Zz2%bM{N#Z-cfVZce`xQweeJLNex&8f z+gkQGrSqd)~ib?FSYm&7_Ip)mf*Ps62lh0p% z(+`fkWZBPOyyd+Ox2`{WMeF2iXD_+wy{~xpv8Ob?dGpuy*z>X{UVT_h9>4COjdw3Q z>6wlXH-ye483p(y@Z~Vy%KGu8Xf*8KPUj4t%-lOe-fg?ZE^uE75 z@xDL(@S_cvK6d!ZweS1Oc|W}G!c$-K;UzCVYh&P7c3k$xJ>K_Yk;g4MpYM*%&#IT@ zat$xr1-}dbDdKmr7mv6k7Eg<_tvAbe@fb**V3C-l0TMp(ROGfVlTje;_ByGp%aVLz zN@a9FriEE<8AVo!4U2(ZrWmX2^)gtp6f#;`FKv*R&q879aD4&7Hc2Itb1_iy zLv7&wmBdoc|er39Tr?K-I0@R z=SLivW!Ou-tVdY;8IL=}@F%z*smnSvGo>DkvbmH}=i3UoUtLHD3=4jIk| z@**}oIu3tk!;ki)?uR@k6Po-K@Q*)g`AzU%@VH(cF>_Eya64t@6{8BJyx35{m-5k@ z!C)t(8+B%-l=1y4=}5CU61Uu>hWNFzVTOn_Ww+@c+751oC4tUS<;CT zf*te$O9?<)KD`KZFy=BPovhm^Ly)Mi{Pjm`NDByfeFRGo<|^J~K5)O)S#~lWQYK!( zgj>dmut9?eXGW!X*BbiWq0D>nngw7x`{ZHthHt}?7+V}-Y1y`WxKZy)wPh|lRHXLl z!Zjpc6BYocMOm#6$YY22h#P2jwg_>K8W&*O2nO_W4cmMV}PrLrP#g%bFFvHBmJgC zh`!l_d>&*iaXfN_4)nJ}bD}65{X?BW)!cy$LuL3wbP#jKS`qk@LMQULSz4hU`0|Hc zS5U+uHSBdtsI%jN0rkoRNJHyfV*ZpyA!HirS)C20+GtJcw906B%~hWupChTdXedNd zND1tS^ORa~K{o(kAq&?jcD*2tkAqI7p}fRSQM&!ogHoDC(OGhtD}r{e{IcXyFR&~1 zZnkNTp0Jxzq1L@(hF&X|72(glhGwSUnsyd)lBw&H+!cuR5g{ zXPWiM7jjL63kT#E6eH|aw71F~Y;AemBHC_6ISHYKrb>sHmz!R2(U0WvD6Va24zdO)1&}U9zZS+L-meRXp)YKfveaK!lz(hpK&6{tr=8$&IFKixGnVT`|ESg=ZMk7LzRs}w9%}==laH{^Qa8kU5>0JwDRY*kvf`ApC_K@ARG6UEw zAZv9_Sf-l(maQC$6!qxFE3X_if_=q`z$PhNUtI-|f+0f&pPV^I7In%ageXN)9{ICA z*p~})aqb))shJw~5dV(2Lgul)m-VZT?68}Hu*`|_jtG9am-gN6#XrOH@n?1&mI)-i zcHbqFj#jmxfK9uf08~i0HmItEhO`C#mZv^dM9`m6psyV&S?|z<3}w1&D!=<#2c||kBD*% z&?vUDYB)TS?3OEUk#MY9{zxDHE<7)b6v}vut-`FFcM%TWvs!kmQ8JibtAWkG@G!DyR5R?)e~)()jZ&dWuNS zn_;@&8K|Usg|O@Q>EVPH(Xe_>1YDkMb^0x0|B)(|-d>Wb6p+1erbk^Z+_Yks6{f+bc4O0`&dYw=m|5czM@ZOzYuZ^M5p z*IIlQe9g3PS*-ycj0PsvSkgj|2}%svgHm+k}?v-H^YKBX3CJ85a>Ui3ym{c6p>k#iE9u9n?_Y; zAWT7xSJfFH-_^rAFAI)nV3oW|^H`b23LC+DK<6k_D7thQG_{i~>s{(*Is>m0kZiIt z2hXt*M19aCIO$1Ds(#r;c*CeY`_CXuJ>@KuEXbjyto&LI5UV1|6>|(hFurpRfbM!77o_i|XU_lr(D6EOQ8_LOMf7u%TZQ zd^N!w6O%p(Y7aHrkf8F3paxUP5Ck8NR~Tf^whjsl>A zDZ4X1DnsCN(pc2~V-|61K!N8QeM}IOshpKL88hh$7G=079_v;ucsfV#LfFJnGsc+~x)^uWGSD=& z?I=Vd^wKV%sKM>GW+A{#GiHJiRrZQ7#)IunQ!17ikF5igRI;Vv3Ii5uQfipS!&$O% zf<%6J2nf?KY2T)B&RSJikr0qU5=2*YOCY(m>dEL7)XO|VaN{CmIjWg`ga{;^i8N2u zo&}z%FBUGMFmL{s&=9t&dZl!tTHlwjZ$3ujqfXkEb!{d6XO~PMo*j;eCZt&J*>&P^ zcQt9KXLV$V^@2=GdeBEpL>$bOFnQYFNL4IkL^48IT8cVcasym(3KabkYm{4dgg0xz za+zji#ic2>bSZ6AB$LXT!pt-TTC9;Rny5N>Jzz8Dv0oy-I-~Y&x!jxTQR^t}YVnsB zX*zyIwZM+j$B<(D8@2$c-Dt!mg0*A`PWces7_aCXqls2g(4?Zb3dKut%vs*J$pj;5 zut(~hvQ#@6AyFJvShS)d{khkO5XJ1Ouodqd5#&j!tmEfQt)&7nsq)wfEi!fVfvx5B z8MFb&Iu$-9&)JU!2UT%gzR@K?qxi}FE)fFDphYTZ&Pc!Ol7JLU*K5e}jVultfzHvY zBSH0+*ek+`@oi0kSz@%?FM`euTB?nnVv1wR&AuS_x+>XH6ICw5e? zyJLA~HmC%2#|E9&JJo!ijMu7jtl)tBr%C-wH?4A|tJ>$eP7uy|gt2x*85X_ZH3T&( z+z&wsyj$)h2ay18MF3u-%qI=9^2eOl%hW&(n0q?fcnR=9nQW{jIy@%mka+iI`Og@1 z+%%`(PnFSOPpVN%CXq4##OcR6jgFT~$IFV8&df4O#x-Ry80m4$ktdXTfkCm3f!7!5 zJ4qnXh8dHFT&YVk$4HWVmj!TP)o%}Ml1!?ilCdp0oD4&w>54s;Y?(}Ui!hPuX{*Dq zTApAq>k1Hgbi)q&e(5T++fZ64WAh$^D1s6*9!i6Hp=0_+aDW}~rJLS$X%Z_+rNoq; z&}s2{Iv)d;I1y)D>dK6Ihensyh3)26|3^^-0}Tr(XnZDzvb=Ev-48=?-RjEpyT6ff z9WB_8j*Dz96`qI-J))pNM#B;I)|_5z(_}EhI&`CPG*mcOCRV{toFO^rU)eDMPB=Hr ziRLG3lZaiIY*5_HSVc6Z%A)ji>h)Xt2DdjuZ#V=$^j!6*kaXeO7z(ysQ* zu=?bVLPi{VtCZtek1NHz!ByNj!yy6-KeIc7>lD`sSWZ9{%D!gljlNaD>cqg4^k!NT zS-4UD8!k;~p)(Xt_4?~CWfSX|BWU_duZ&210C1^l(?51swAO_q7uvcuWdr~jolzxp*nMx2yy>7=8 zd3lc!Z;wz*0jrqNa{fL+jF>q9{{o63r%MVD$7fY0g`7eq4xvzVs}xn}uuh218_y_Y z?4VKjPI3K@OBvoW#w0SX1SUiC1WAFZf#gt{VETY`47S>Wo0u6biCfJdyV zf46Ci{V zp2HfElJi_84z5XoITXIF4l+~fW>`$wT;7W^1rNZeT_iI=nJSNfmF2k=3;9-yH;^ni zMXY#ZRBHTOI{T09unDvelR1LWHG@VSyn7nS=!VQgST}*rIy0B?Y zX3R`D+YqL$hg!9)83F;(7e3U?6cj5I9$ik*>}B!8oLx1`?nzjL5*I$?7JnL1dxQ6=S4v$Qm++n0+@M$g&75 z-4$I#xpbEs+$3m0942WSj=*u@sfr{R)yp}b#gwrK;^hkzXQYuevNT?Zi*QY*N?&yi zfhe)+YG7~#3CyV^^ITxTCS__W7Rs2{$jG5RTP4ejg^?E{s7VkDli)V+G9Ht8$V@N+ zK*}OUK4B}i8_-D1!1wLMv8k;sEUqIh6#WWh?GoZ-J0Gg?e+nY{HhAP{Vu7hcqK4gK zs&_lMH2Hy-VsqeSiv;&bj5=EIcD`t-UeW)0J?^f@r>?iS>n&5)WA1vacx@Qd%@Eo~ z9A`TPE`D_>)?fs>9)Y7nAPphJEbvg7&!^&y0D|f=mG1ibUUgEvfWY&FAPGjHH_^(; zSy%GX-fYaf*4wzFJUoq|3i>j9?pj}r2^SU7SbkhKSG(4iF`~C&%Jpc};QO$ z9QXs@d8&tFl`G-Z9#`i0BCql)PfTR>Aob*EFa1<*LGgYUjw;Ob-8yJ)&mUoWohhx5 zhCK{Ak3dPYhQj)C=x|ZbX`}- zbUqCqYBUo%Q`p~u282`qSASK59O$|w$S2ANTfa_Is9lxR|3*R%bsY7iqjQmc*Y zy-}=@tTCIZ3U;&5c8X6$I0P2jb zR0dh4PrU35;ZXZ*gIHr70#UnY>vTvAj%2%D-uV|1SkT5N?xy$NGKEi$5Zxehi}U@| z7@d@-}&%x|2q_+|R2%ij$b&uj*w z@i~pzss&+i5LocxA6=|P%h*;G`VD8PTX50n=&wcS@C?D!dgovA0#frdslzO()tB5} zVtw1(sHb7@YXFC=1@LSV1sjlfEY<)vqQ-j5Vbkdem?kW&k|vm4^lu z;4M{NehUV)K${Ea{H4w83*Lv83GjE_GZdz23;%OsADSzX)EX$j?% zhXqRV9K@Ry%_;UHq0Dq)PEw%3t0AJa=kpxjlylS7f>ek8zY9j=){tM)rBdw_zRs3l zbQG_K$+L^&(!h|y4@duZK|e2mN%3^HI2FiNLf)l=AR%_cTK`?J8m23kB*;|5dU=fd zafjGHTiVDPkx$k^drk<~>sfD{JpcwZ%MU0_f5oLvHYc0?f>yNJiUA}Pwlcdw6*86e z7Hn1dYLbB7RjMUv%#T>hM5P4fNoi(o38|z}bruyP9h5#iMf=`Ds7pbm^I&kqYbk8L zCxwzyCUL_MR2YELmiQZ%_`fMg_5ZK%$Nvk8vFMo$ibaAYFsSCqV5o8uo*ML_AW%m? zu29S8xkOvU494)+))0aiir#=g$c~kRTfhD~K%@;(8c;Rlj5n#yTqeS#Hc7{lvh~z@pXmxEqnT0{!^c1c|f{nOy zL84(YM`L<95sX&xoE??|Ds@De_h{Ck(eBLP^R9ndCW)zcRigG+gE^kInFHt*%2w)6 z!QqBQp`tT*G_J1(1z{Ui)tDXLgh}OtV;2LwqbOf#J3M)F_vhiLZvQo6tgp>H!!0?sClwZ zgM3!`saRSf*ZOU#d{YSl<~){EvL@F#%@j^|4Nd2%!E1A}#DyxfW^|NRVyP<;HGk9R zotZXxp+{9C?CEW(ZJ9|>a?)eGI&t+^Q|yCRxfHm4HA$gx z0teYDt&Y_LFySA2)hRm>17zgo5-L3YBIxTr>2_rkd@|lJM6zXq)?8;iD8o)x`ZDRy zVtpBUVBhK5B4%*}XKG@}|1@EP3^|^&bk6Np%D^usy2u}}m6)CSrf3VB{18v}fePvz zOO9DW@Q+KH-1{-hTzjfvOP`+W-%r00m`kJio%A=odz(LpaxGEE{s>FsT1$Ac00Gskqixdtm*!n|nfS0O9kgr1-QNGV-3=(<1Mj}sEGBtf=h zKwq>%c<-{HccQc6m8M$p?|xkCp|BWFZ5syBG~@H{$<=>9s6ew(||3HH%cC_I`v!tU>S z)C}+O&if&??kFOHKx*fwqvHGARU`ew4ya;aYi=v-84mf2zO-F#869AWv6Y@@>=)A) zKb`$nXOo@t?zp-hoEBY?MAc+c4u~kBvVBS2Z`XTNJiPWSV8@B^;1e7>i#%8&5A3}H za2)N=;{Wo-J5a-YQxL(JrYo;2h#*z_UO3MHlx%FbY^Xc!OcG|#v|K`bH`)eCQYj*0 zPTmZB9FF{QS0v19Tx#U+xA851AME~qw)^|%-Cq>$&0wN7?|c{?Cw}c>B;$Wr=KF2D zhdw!9!g6sE3BoA_y#EoSx76LcvQl#tKWs@uAOpxlo1U0^kkz~+y9t8A3Mu5tF zQp}(*cTHI_&R#R*j+S$RQgiE^2b{>-oGuI~Wt?y8sR8#ITy_X^c$DVlPIITmW877m z#ugBWxzM5hps$09;-l;Z6zu1#GW2bHpFfgK@T}W^nc?dx1Y|}fB{ew6&Ffk_K^MJB zy46-ym>v{}Bwsf}GFq5SOQmd-8R4P&Xx1?%q0XN%#vYxNL{FmoBJSzw$ijik558j? zJaud3<$yck*@thHh&e>0&}TCilzi*VL4tbwd(@}$D&*GFLo=(1#7 zW@9GbDLrNWHp%q8_3vks2ZRsx+~qYr;%<&R6s_J4{J;#WiWKO?usTEkS}W$v=wqAj zh8I|y@pwlO@M39(5JE+H=&GkaV8?($ovxgJN7!t76KLpKq)2zyP6l49cgWjMu{uXV z8-=kh9rU>9y-PQi#}x}%+AbUPCCs3hZAh**6Ls`p5M3f?$7)qrln#ZNz2Z^DOAuH(BwGok z^tYAG>Q~?#b4rd$u+z?K>m^K!T)sOofJ$tf#wvNghPcpDyT-s;P(0p2GU|L@+QBfFKSgU9b(?GQ9AGDY zL3!a&J9}Gd9mYlU037SX{2V_(;hKk}#%s9|+{ZH6`p4wOSV~7{L-rIPs!_b&Vyk5l ztW?gDHpQG){#6%9v}l2+gI>NsQHd;`;uCh{Vd-=%gtifC)Rx}a4&!Blq@xyu zk9XEg`F%@A%4^E+=dx$(bhl{nY0FGt}gqUJebdgoo(Tn+lDHc zcnHUdTk`PKBBW49pQw=_GkdiqT#s>E_*%GRi?Oiv38^l5%WqbR>}NruEQ^eRSs>RYtPie(#Jl@1Mo#sYh?c*KB+WRy9Ka7OUq<$0g0XEy?UHY$rh#_Uo@uG!1)YW zb+To2c9k-O?xh~7+2B@SIk#Gjfp;;LTa8DTWyh`k>lKakK^~70$but}l)Isk2;TKMET%N8MdWzr z6?PtW3`lKcFxJCiA!}@ zG%_RKY~In)P|n&%ahvY!@oS-STqm#2V>|HtWbBd*XXgE0I*r2b{+p}-W_v|j`#_r7 z3Uf;XXp{T?kX=E?Rc?C9S>SrRe@>%O3Ho-YNya%LYO5adVR#7buytM8Ij6bnT{RwW zd2XJuOibkmed=JMq#Ac7G+YTqRHdjM)Rw{&YIFNFDpUx3o#D=z;dRZ3()(|pDd~-$ z-8wJ&=~aihWgFv*EhFDSYO~gwIUxJ)^xRToy2c@>z;%}KzuoqfXZxC-9rp8g98K>- zU>?P?iGpf3Bixw6$SjlgA-9V1Ysb6vBM^cT?DRpM3)4$8RFzz7E%<+90q9OFffH_$ z9%%OwuiOGqM_Sv1?rwUbwP6Q7p}Lb5z1pDvRr8fx|RXFYglX(& zP~k;OewKCgBn$9xT}urqA2@bB(@gqYTs z5%*h8I?U8Y?aDhsL@%!hYvZ0FT{|z@+4f>ru3@QU*|$PKu^Gv7H!`oUHa6#PH;j7L zc-w)jDmG`hkpV!Ik2w9hrRU&m-sce4LAVP2nha^P{7AxLU-&zDgl z%@AAxd`rvG?7l*2mAVYp_}7Np^WeQwY`!YDyzWQ+dvtJv;ge}MFUB?xS_%VQhg)|V z1U2#1Z+R|v98Xp+K9q_`N3FSYmGaP{pB{NVIXWorZ2_e?E!KWr@ ztqCX0J?PUKqoKL=_|YK)f56MrAL@9-{U*iD0(QY z(AHbP^_K@iUD-i7pD}5)l~+CITWMc0kKX6I$lIYHgx;7Ae+O-T;Ig?P+BQS zZ$U>EaZWWnZtV`@u95vlTG2<!T1$uQh({}zlCl|G4gKaKl@mr6#)2~D^eox=R3 zfS*+ISSm}-@0wr9tdGKz)OqstkEJyA^b{2;kL5YG|K3_scsdGkXTh{~G@#S0oVT$< z-DTnegS#5Hmf;S4=t|94(t~Az!|_peXDEWi%W^&NwL4a7;p@p11$lsv4!0n;pt}fI z`p8!P?<^c+mcHa?AMg1bBkhaHD^<2Wgyecq*7h}hfF*;diCGOvTeht62y(_qwSeU) z`z-V^BnKA3wCbg{IF-Wg1u8U$;gl525kTgl{8e>8CbyWS$gY>p?#I}A3a*;0mbdoI9|TI>FGt`*HCQIS9gma-CH-s6BmD|i8R)sJDxTFqE#-5oqP9{joC#D( z11LHWo?+O4Q=4i9S5harvn*rFn=Y05fj6lF?_{3aO_(EE=z3Q2-GiVl53Dhpx7qf0 zBjB$Em*je1a%p*5-^t2&bo9#e%!^ihXD4XMdnxWvG0ARnejlN?*40V4TdK$k!42`` znWT_DDumbH8Pc4(RR`*F1xs~dF5*j2Q<)++T zcUb8sA(H#04EAW^e_DCTn370JzQ_Rfi5Xho)>0F@f&5f$$PL}n-n!i^wOGaPqv>vk zN@^aqhK@aL2C3EG8fGx0Wm!d+KLliSB!L5A2ATzCvdp$Eg1^^KbWU8wCRLr*r`!cB zvZRE~raJT`flwGE%fsAky-*0tU%`+Z6cjCW>nV`Htr>s^JXCbHj;eoxr8{65@tZre zLBt~vd+^zqruMVmA_%4}eD)fIo3bO4BP<8qK{Ve#h}Xik$HoDgsHm_VKVWN@+goW? z7f)NA>I-6mj^F(^Su#*zN0LSa=c25oI4PIhhtnzsin?5@NDbI24&b%$VsO@UqnFO# zzZ9=H$*_M+#ggav$5?P>YnGN>?HxXt;1%ER1Ps8>mG1_fbzXVB;<@R&S7Kqe{n6*Q zqwMic^aI?A`x)a}EJxMr^y!rguXdkS3Ai2eVtXnqw_{8_`&Ol{--I2}`GCI(O@wkt zhLQw|@w&>e{ygUUMckk7U!UgJd&T3w+kN}9*ktiWz|Cw|0(xEZvv~bde8vV0FuD>~ z_#3VSNB#Dv%hzuo|14BtX;j>^j{O^JAW-_pD)QQFpwZHjQ(k6CXSdaSN3Vnu9~F*leKTeu};9<6c?`ROS!hZD$@ zVO(pxo#YS9oumHk_7^@Y;y&A^@pqvIZNK0TTf{A!MsN}oHV8UZs=Hr4arjtwI}ZTi zRTUg=PBK8fIiGe4E($4FQNW3+Xq!n!%2LbaCy}n_Tv)uYtJ z31{V?_?MK+IkmAtrGh%YI66<&Rn)Mn7q{kxq~vPfhgD~8xh3f5W8wOpN&+D;QBcXG zOBh?j?@t`Z4!jtNRo_J1KM-CeFOt~gezg&80kTpEOn_u8LGv+Wn_77~|6t+#)*c;T z&Sd~9cs+$s47s9@N?VfDlhsOywR+p%x`aY_3vbT8`q;P%Opu%e2Etp6K}>aWPe{`R zh-Ln+Yp6){tqX3PT5gIy|G8@9x#oi24R~=rdP15r%5lTohhbEd!H>UpJ9M3U-M#!N zW^aEm??<7^hzuLs-6WMyD4{m@$H~OK6xZI2*Q#c^dQI(>3Y?#XA_2j)tB%E(KI&0N z!lqF&eif!Ah!`=icQxHlX=@K>z|2ZomfM?|vzHvQzP0&B*Pk5{hXzl=so|Q=SF3DL z#(w%ocjfj@Yg-6YFx4spTk$vA02G zFVwHih+_Qizsb5@)=(?HL=M|_6(gHiP$YCqgRD~5;~oCB3AAtN%(Ua|FlLpLSFJ22 zEs*!N+PehpKP$LNjuP(bt*f}zTK+XE z2&Z|=FA`ii_S4H`Ut(3y!O8c#iotA+%#)R}f@!}Dqwj#2Ml=-OEl}(2 zmft577!<4Za=Kot#XM<9Rp3ncJ}j-Et{vBV2-HW$#jW)h9SCr_}_WTd^3mgJ!$qTJnC_EIFpIF~^=n zimp^n%{uU0RaEb9b25}w(X;Ddb*BVOORZEs*HY)STH*+#+qRt6?N^ztlC_=7*ohWK z#zcZ{>;f2!TOO3NReILOC2V31h;fZ+N&%@2`yKmz(C2|u)$G%am#YzyB?SaXkm~8O z_Skhk**=G55xt+U2V`h1jwiK9>e_v(K8xQg2$J#n?gQFbS(h7gw3P|wtKP-wr}c-T zCBBO?jPY(CF1$3)noU!wNM*0oS*HfxdBc3nJF3}hr9&-{mb5Xxb2$3afzw_vO&dQrUB;-Bg9~ycbPZ7g>99D!P0ErC^miOWl_*~OMH{ZcGuK%YgWxNutGQSDg zr~LDqNqYG%abw=ZqUHH^S?(XqJHljn&MYTC3HnI}O_fSTGzls$L8fz{ZNbmN*)}ya zXMKK*xFaZJ_qJTWzN1)A(LlqVj8vL-7caapStRKA!cOMeX3*o1TfF<@;kWJ;khJPf z@BcSNQa(+&ZBb*|4YiZWK1#+-AFLfxM@ht%6OW;XkQ=%!da4-sRy>F7PCQUhXKUb$+6xDK^*OgV6eHcYTMO|!eQmg^h z*-cKl^SjQINb9!#-nv(K>#o!50b^TMK^B3$mG?e2p>QYcpao~@%rhzL&{o{)brj<0 z3vzLY7?9#C7RA(8NqSx`B3^@waG{p^Tx>iGT+7(@RP-j1+}Hx7_+~n2T-X98(HluQ z3uJTpw-71fC`A+PJ%C8=Sg1jl!)pjGQQ#Assdfw{%QPpdyd}01l zDnl>{^OP$3o0J-ft&~s_g5tdxPUUj^zZ&b97H5U0Isd-dnS*p=`^=vATFjjD!l{=h ze(`F#oMPO*3kjA}-aa!pD;a@eYEtrJPI32sBuKj&k+je&L4ZjmY(kR=4PKx2%>Hw{ zx)QH>$87oN5YjX#-`>SOl)p~bR(XFCr5=SdwbVwSimqsN@BHkBB}vp0y)nh(loZE= z@pGE4M?>L!v1NLc+ZJn&j>w-(XZI7WdUAb3f8@QAu1K%kNVESaDs4&3~dA9FC ztFnXQ_u<)+N9|5-aiu~|sHo)wC%g%RUZsV_zsP%Ht89VT;ivR(2@gUyB*}+=V2R~@ zk$h=jo}1mnzQ#XyLpadt`*E;%>qhY9BDgNc)p`}uf3<|hCb z?a<19pCF=CkrtqZUHgoaN+T%H`rAADk&NY;@*_PlU#m1xLNQN?uJY%#u#NfdmGbWO z*oio%Au}wEzI+FJ5}AuR@Cb*DKOYrqV7(d1sCpwP5sAVVLn5%i;tkpkrB%j|WNIZB z?(iL!Tt1FYlBN0exU_Bd2T8*}QS?`2YF- zC@#*BQ1YjBYJ1@71*)7g(;RBXP*v zA+na5GR6ctpRX+M*Vx44wSg?|yMG%VmiFbVTb=iHxj2G^q?d5CoOY9LGII=`BpWppAX%(|r)<%ZudzSM?^fj-mF;I>V<=gV4t!zTaH3^3z z&>Yv-t0;#>(Afcau%wr>SeBf=>7t|Y{K)8)$=>oC{bCRGS)h6xuwfCfsOID8;CeM6 zy0Y^IKb8(4vYihiO1Tk#KZ^hNlU3hq52*2h=X2aUF|pw4H(Mib2_ z{;`aS=j|+8-?gPIm%cI=l@9AFFNdbLtX()it`4a4+nmH+Z0rzGHMSM6scak@Y6;;Q zxX^A+It%9&k;>jMAJMGh0e8sCuB)_cIJ`V72_bIKL41{C&w7e8+VMIOcL zHv+oH({5R9X8I-)39$V4U5}Jk@xF-nb*3%-PAYXFL*+&V`-$K>FezMBdRp9gFz zRq)hbnHR1~YNRlv`d^+PUM_MmM~?9C0SjwQ%>D4f{|Lb$cz3TGfvW;W+GH`02&7bl z14IaB5mVvB^F!@uGr)L15{4U7i1|Ux;lfEm-mm@3NGjY`AWj+0heA0 z82pLoiral9(kQ~(ED=FT8Ejz0V4DwyS?P!G?h87CD=C*Lstkk1w$dsAAcY|DP;w*9 zOHLtsjJi|?g;VYvAqap26gYntcU+AFDA*wK;=~ngYZHI|eiy(ovdg_&W~lu1EI*GB ze*Y|J%~m|1wbnn7B;lf2=G+>W$DG_dly$dC()Hm)?{&JaYgyHhlvF;=6|tO8l99iW z%{SuzacGEatz;$3D0MC~X|gSOPmO&p zj1$|_A}v$m+8N+K4cz#m{g7P``9LFU5i+@qEZh2E;q;9PiPfH{i-|3JSWhVF?mxz)^9+9`O4q^)JN>J$`99Ep;x$wDChrtF+%s!I*hv zI{?+Um-r1;TA$=M;lHe|4x?)!tM;-URtMkG##L!j?}ZQPtMbvtP(7#HdHbS2#VfVN zTiRM_RNO#`z$O1Sk(RZ=L!3vM-#o=?%?taoQ@!@J_}Ti+?}nC&JvUmbb*de7p~iLw-f|1=^; zj;mw#TpVu;iM{QbC%}%o*zyaWy~>L@A#Vn--{yIqDqp2DLfu-*LktnB#gD8IkEFep1_ zxoLa((MfdPONgW-LX}cEp~Jcg=V{CKd8!H9UuOL8vEuOFuH2}j@UrN5@xp(EqqrRI z(@(1Sp_ft?r9X8Bs7|dgFCA>c=ejjclqX6ojcROk#XsvG0ljT3<82~(7`=G1OOm+vPj&v3n$hCbMt!#l#W7WmEYdQuW0-;+(yQ#z8H zb<-OBZd3P^;N>88EhV2*#+W0QN=4^Z$l-CHrdONM2dNsD-~BfkR%I~Rhj!K@3ST-0 z$Q#o~(zw1&$~dQ`K&unJ^|01=C$AEI?i{BwbuL*kr%6lm_7tG&MjMLhY4j4sh&O%d zX}>lcios_SwTkOw*O6D--r1QzKCux|HJo(=vJbwoc^n_TCCBBXl$OMB%^7~5P{2Y* z`^&D9M*?Wg?ducw_i?PqVaj!mEpG9*@kut@=P`nZtj4i|;vd}Q+*OeWN-TKD2#fn_ z=6*5W%`>F&0Z=;3s;4-^aIfm2F zSfWIwu}mxl1bmKJ!}tIVGx6-`+o8ig9Fj);d}vHMugVF9Bu7&{E5ixFp16#7Uc)N6 zKh`5!qgDB@*T@u@UJod#vr5iQk@@v}0yGLRlMCy2u)4_|Zx_z2-+^{=2erNSIH&dd zF!|hvHcNl09&uEm@3TAzH{sC+Z>DyhgOYYQ@0Rt&0k!i`WkYA%ZLVe zTL)XmClMH0Gr?^H^T_wWgT!|%`Dtm;zP#Sl7L_X{8Fd6fUL#8}wgl-b+e+R3=X5yj75l1FPf(igN~G>hVrjB-+<=E3+nMCN^tFqaWEMYr7@ zf)D#l^FCA|JQbDa{7V>|RB)$5>$*}*KL_<(t@#-`q=jw^d!>HQu%O|0<$52Ciz9I3 z`Xm{tS<6ReipF>o`aSrIMNi6)sFhl0d4nQcsfWa@t-BoWl3z*NXVV=>u7Yq|IqLsl zt3xx~_9bq9sYEc&Kl403Qh3xcER9$Ul*D$sEkgySp^wA`7wm0gv*aJ5Z z>p0xjf_Pp_qj1EkSDIJfo*hzLBR-kxbKayJdZwzKY!;HnX)I*aMUeTNwgvN9i0Be~ z#!?SM#!Lw-Fl!rvv|&sSt{1)FaUYpNCF5+Lw8l?aw;DlKt>I2qH`&UGy<%=@Hh2k} zs=djprDJCe-59r4I+&e#;Da}PXe%99DrOK2#0X<*taI6TlMVU^+I?1iALg=xxruKS zOOLVNA6L)mBm5lM^hFKL!|(o^j9atZq4|6H6!&%Fjjg(JL(l%p-<@Aj8)Ojd|osJZkf*WwO8mP|KJFIAFSBNkIx7( zGq(B0h-yy``sLGRdU=`4MN9d)T+1R!7Piq+c+yGtNo1}R<4+^g=5$JzMj1!X;(3h; z<{Of8Bsw8fS5p)si+LE7OR_tTW;w5gc*Izl4}Ae~B)@If&v{^)b_VJHWRiYc+rQm4 z^=I2V$R6k0JFwwD-c3J;9(#=bwTDM%mSxX5*J7-!dioV{Dv#4P8$~-!$zRW!&9cAV zV^~Rm@~G2?;p|j=Q|itV0AUE}j)HxjC9u4u=AF12$939~ar8DEYvuX7k&xaDxG2C= z1ZTC{29!_z`tWD>Fd70((p#~yfvprGOu{9R>T-CiQcN>M1sf7i+Tt_Bs3T3N(TW)8!~E51eQ6zRy0%)25suk4^>EP<*d?FE^#Ec zl&M59$|Blfi?kx&thG~+q2$m9_t3e;-bt=k7+;Dpj)NohPLe_G)We0d{#sA+=u29) z$Dpoco0pPvq@0on1&*yLn6B#!LJEfc>;p*+nm(4=7WsWG3_8UZiUBTyGDd zV+P97DC<=w@qy%q+)wV{we{0ghN@IKIA1<^{ zYx|_0)v-0WXE_xP^d6RF1wXd)@?=ex`jH&S!N0Ub#0*$IONg!8VSin$wzbFCsThNl zVD)p6HbY9wmtuzV3-HA?`J;Y8B4>B}G%vT~Q=a4@rceW~;|DL`2{J;fDb3a(Kjm~i z%(n~}clfpt% z3av}71^wS23@C$*&vJV3L8#sXklXX|!Q*gs!AAMY6?*zF%+r{EX!jGjspmmqJQIH!$Y zyzp=FpCIC=@t=b^KaBrKKJDD>ef+2R|6KfkGyYSp{FnIua{MPSw~JBQ@m^?%YL2;c z&ue8`9pGu`3Z?hMn!HoMd>l!V96%o!W35_CW@%~Zuw=(%+cNoOtiBoA@@0%AyREDd zU{cqTYztPK<@uPo&PAx-c7u2}sF^)VPTb7#q)>f=1R%~Nt#KR;91VR44deBCH9R$H%b{CYoqf6ScliV z*3N!iPLT7v|0Z=KL+VztQbJnjT1&KzmpL1f1f6wSKN_ad6H=~7n1nMFgPNA~%00p3 zF)Odywq?!Z*|CL44qW;oG~lBc8~^VDhQ~=rNU7l-*Ciw^ZMMN>SbsBFm^oYzCre|V zK1&{uh-b;e*1dT@=H!9mZa(naex>g~-k(Io7Pt!!{?~;IAN{Wj|Miu4&HsJ>{>z0= zzr6hZ(S@JLz^h&6cX8KG>Q5q^0n=to%mUF>EQG>F3q;T26oX7xe(lAb>B&|NZ>NR*KA-rP@a2C<0WxY`AR zMOl1nf(Xu%&e4oW&6J@umBZQ`jDe|%Go@3J9@M=gDd<;JP?Wb~W*X#Fy>(sPTNdE; zi_-yLe%>)$-_7?@EU>&CL#TTe@U&&u@3n-X=(H-IDiHchl&MkOgQGRfJ8eIP$=HfUkkK)&Km_Z<;P@a z7F}mi*>!}5DSw`Gfm!DimBmul=Wng2c%uFI)-13VRH2}#s%3*OVl*vGsba^{m;`)I zkNgB!RL(a?umUL0z9#{zUW773Tdw|kM^k7x#}&#kn=B6AdOzRVylF(M!>I$WznQXW zJS<$V`0tY>2LLzy?#swHiEO9X|f^-|M8 z=QZXUrhT=drRiLAoVE4&w(jG1|4rt`nQIy=*#}u;UjI2H4OwHs#M|Ec$A2WwWY-=k z=SN>gGg)VP8=cf#vSNt=V~^)I#rMOp&61=YOB~boQ&m8=wFuHnWve9$sjLUvaMAfa z=Jokx=;+h@=hn{CO1rV<+Mfu#x#(psR|>RCDz*|WW#*EPM?ja<_)+&|NS7mgbb#SN zOyPx0AqR@-_6*cmsb!$$Zm6TUi|8xw^*y)&ZQH@P;d03aG_yj!3|(7evm8L&j$*?7 z80Uq_gtwUntC=VoW>umpmh@(aO)2dWb}XROJ3b6WZMPPU?`iK+9~R@>3P^6ohE!lp zrCEdh{?t>!hQ{Ot%0UoAu*9bvz4qI3h#1&ygY!w^W<^?CFdA`dt}Y5uKA5<}2`QgU z?ydGEWFRD0i5r&;I2fwDcNuszQ~iu^kyxF;P~$3m;eI5AGG+~7w$WVJ-00+}j*sGN z+q(k6Y8I>VVhq8rmsz-K>YvR$QKCs*3aKu4&E(*{?H z>F};{jd693L-NK~Qz}oBXugtglJkjMjH`#YqAPTikTnZl;B-OB%X0Y*PK%B$?q+c# zOEfGR<68S;se!;-D$P4TdYaGW=Fw&aEDq!oXPRLdo4{F%)ZUs5_M_gocJV<0sSLeJ z+nF|N7Ka3;mck`yRgd<@{xb?z=4u>q_v*AQ#-9j!jZ|$2RyJuYE2JU>b3@sA2T=`> z+q?Tfl#!7bQ`Sx`d6+h#g$fBwI3xi}uoy>453&R2WKW<5pG$s`hgP;7e73q#w@PXu zQ0Z2E4p`1ZIZ!?k>2QFkg{9mQh}JVdkf;<==}4UtDpBviMznNQ_Y2ZN&Pd#6Nx!58oFriA_ocW4FE5LCDJn<2bNT0b^WA@scfF38 zKaxH{AX)3U!U z^^(M4H<`;mmcU&7i1N*h?KG^lh%Ia>6$xefhHYuSwtlOVR(5G5v(TW$*xkv-5lQYf z0abN zdwV$&=Xx6^>BEDi3@rO^Lm@8%9ncCsm0!s;M_!%N?`o2&dF0JT{DdNjYmWhRbCJnB z%lQpkoe#?Ze9${7CD`sXbAb`_$u~+`RpM5pk`a^Qevb0as9&~NKFppO>Wpw~?MTai zWEG1+c~IQPcGUzqbqmQwKQoSX{*W}0q(duNDve}}7y*i6MUTp8vc)ZA9vfQ;k8D}x zEj$A+NB_V6X#lzh*(>mBIVq}S|is%Ums!L7FVP(3A^R)&8acVvLOvb zIubt`x2{Z4rebU4gW2rSC4p-2;=wb$mNJrNgLGuv`iO?U$LE_px z$)5CufB|`e-t^#W)Rx0g%wy?#q#Ei|zp2-XvKl+7AiiI`@O;csujaj?UCrOyT(|%~ zXnrCF{BDu}$%pu4eqD``k`5W^!#jVDRG4PwyuTxNnqv-pDUJ3FTA2T8(j41Bf5(oH z8a4QZfJcOPInL1Tx-X{m5x^x&Djn=<7wHoq}syY(m=V;tfzul+j_1foSr0w{FH9JP7 z5uyY%8BqdD-_BIuCG=yR7}J9JnUAr5NQzKjoNI^W5G_C!70WnVS(D;QnN~gzp%XLI zND@kATzR$O1`=d=tCz{^p>@7{Wp?+v4C-6-w)z`BwTG{tSNz`#`66PV@8VbCBavqB z(ez@Qsf#^y*N1JBy$AMMbKt*;MLs>@iakP&@39vCJb6_i6ZHBGWoq6`9)Pdzv(=;^ zjqLgEO1xu6XTRXs<|o3ZLRDv2f(xugG3+c>pWUZqmsn8fnbI>}+__v9Np(ltjah(!o<+2>+B;J7GZjdyTj@lwvrV z_q{Ulh3p1zsR}nUIDUuA)mvKbTAyhAum#G$wI5gqxxsByF=yUSHDw_3q0V`b8|ed3 z>APkBTIFdy0wM;1#!wvzSc1-Sp~wsEp0{jZE3H#>bIG5786zj>TKYk?rD!6@`s*T8 zP_^nOc+Y7+(m2x?D1iw-tV|0kRQipqkMw_uR=rLVS)i}VRgye4}U<3S|n$!n{*2*N>XmHL?IF=$IWWCcrzB+)R&sPe&R>PQ-)F;_reaoaPg8bJNra#=0y2-Bop za=3-B)xn&*Mh4X)*e^SGfh%aB>b6=>5aomcG^tS(oeWUHZcp(^3lp_C>Yu>;U0m%J zWMn|PYA>}O-Jr|FdzKtU8;SA73rm{T!c%Q&FF#3FcnM!DIi9UHPNzN6`uqEVr+K*q z3((`Yc?>)CK53nOwyY=eiDgNBR#%+qV;f7vhUL=M;eJKJ)bdP*jK4V_W5NkZBi#4; zk!Q<%qV?vZphn)j|E8^7AD_g0;vF(jWiqeE(r2V|Gcbi8m7CcEr_7g)*`w=N#ldEv zwX8Q$i~HR)QVFVLd_<0UoQdG;JAzn3i9f8gDQ2W;bE2j;f-%KfyRx5- z({3Hk)p)zwd9VVC^dP1OPG4J4=9NHuhZg4%y%j3>`t&B?N3=zi;ibUjc*?0qey8^; zI+lbQJ$}*MFl5%$?7iExh0K(u=K-4OUWFR&7l95yay=}Is>NjG_0dY?8Sauzd!v|f zR9z76%%^KSUq^K$Br#B)aVKb((n!whIaHTc39`yy^@Gda(WA_z(~!W)%-w;3$1}C~)VZ)b z)-moQt`K{PM_4hv18?FqG#vTJiV-%jg$dc6Unv_# zMu{xD_7BXO(-8H2RLrUxlIkw_PjHcB@y=R3*U>&p18&RH7xAiMFZ^=-DWg+E=Bl|g zY>uHMnA#Uq9@|<|p`}<02Q&A4Rh&GBWFHhM%|4u|N;BhOU5U5TwgMx)eZm86p>jdZ zN%bYk#7J(I?FFNQgU&jzpR?6LCe;gxEJ!BkURT@$1X?o#Tgj@bCBQ99bbad2v|nX! z7BX@)&8a?A4i2-eWCNx(1;~{8$%eI@0Wv%Ye^n<1LMUWj$ZpOt(72W{ETAZl4)ZB? zupSvjJya`*=s)=MeGOD@KA9lF6F>pc2YNZRG*oC2QpiFrT^~92@CEA%cy|sql)(p5IsmKZ` zFj60Gd6?2Rex>>h_D|kO8Igpm&WF4}VW=hv#2fcr znPZ6ZQ(0h+DWj&B^&;_39a5^B;SHe=5s@?H9B1FF`#I24-XuxQW0kAi@wC>WMM?OtJF^_h-4 zWPYr%K2!CJ&+x9kThC+Qio;-=^NvwH7o)aSd3j&^s~X4K`@U7WzK8(8kO&5A*vJ0d zWAB@5msIk_`@U~D^OM7{ta8kpijKS|7cZ|2M&IQuT-io839q2UV-oKi1`n|jbM?J( zjHXqeTGc>$D8l(9|e7W7VE^VC?AW zP?*dGqM{maw8yMcxjsPeKI%dy+&ZTG*uHJ*TaSnODC$WtzX5;%BUa^uqNpMxhI4 zY->|8bQUDmm1FO*DOhbH5{_8)tRC&gAbUjST8b%?L#~`HRBB_{`d%GL7F>hJ@S?7H zCCPrYxZ|y?smuGXkOhho_EU#^6KmOq6y%y9Fv@L1c^o(L-P3oCAW;M7-xwlTSid4 zq7mlYVf>cPTgFs0rZL}}JmNZipdFF|eQr&;x^s8pccNM(3(3S!xYp#XzScgFL+l-)A*1hn8=F{Dv=)0Xva<}2LJ)3))5u{HJLL_7a)yNLLAJ>vs+$wh< zJ4f-k@)D$gZX&uIsmV!CWIY{u5idhcSubdKCHjZ?afS(Bu(O;{@z)El6+UMUaIb^I za(o`J0M8hf>qA)X1~!ixsz}n$4vQ!=hULZ#mRljwS_^O_Baj2jsYF{Fi_MT!}XH3_M~)?>IhEqic2~F21e}FGOA%E0sqYw%UcRa|l@CF$=M{=M|HvF3$A48itl#oTODmGON-gd?0v^e1 zo4+Vp!lqZe`}ojMjQ%Qvp#!XD)mlS<3fuBzPC=$hj$Dm0S4&YsaI2~R==0N2$(12; zA7m)^DCDY9OSM{innRW_wy#7f$&WeIcWATb^L1z(SCI|W6(zorUSJ0*#l&@0IeWPV zhU?S13=*8@>3v_cnq$44VyCB0edvle}luYCCOYeG_VTm89LXjI~$tJz4mcLzRSgd#$kOAu}ZSd*TXZ*<-w*GWjz3DOC>nfjSG+Qbf-8SPEMU>{s$7Ybn6q!{oCE zfu-`9GbQM8vA_Cbj1FJm6zd)2`9uK9`^B?f+e9(=oo6WmBT%c3Oq9cD)MyxsY(f5A z`GjPuhgnpBHlN3xK!8**Dm@44uaOK%O11kXcY26wYjlNEXlYO39+ENd>K>+~Z)&9M zwC2aM5c$L3n)6&a*+u2`%(U69hgD1_t0E1e5+aX_591qR*?L#iv>Or40LyoA75BOJ z+2ac5kXcns;G802bdgvT55GJg()3>N2k9Zl0Rl&Oe4;p#5s*Y_hB`Ic6DqLE&jrNK z#a|%8GdfrO%L7blXDDPcz$CtI>%VwnhYAoA#F)wQkK#=d+b84^9984i zIXHJttcxUmu7l!~^|3lHaJU+LrWk$i&&Z+KgA{P6tdV($X zEjtjg8IlC`8z_pxvZPd0Da}vWIZ!ESsQ7z5@K(kriNpsmCK9zJU*bfc(Vr;PBc+E3!6oitf{l%1=?B$N}kuvzhA{r}MOp7bDhbt>GKdq06jo zH-75=tsPuc5;%SO)rm5^`&0ba8j^ZO+g_08<6HS@$v+y1_5LzExprfJH`#G4Fxi+Q zL+FbvqB-P=mUYE9&cCF~9!HcTevy5u&tzz$f;%U(Q#rmEt3BVvW5$`ww1zj5(!YkL zG2#g2pI+gY*H?86xtX7#ocoo>{1{nNL3$@-5zM}c)t46L+UL`L zT^qN= z5c#rZhZ7^}Vms@y=L_HgtEG(o-`Nt{fZguTd&tGrpt~ zNVKSp+@-W@!IKTfh7sD&$Iz1yadbd`=y-=-pYvC!k_P+WU;f_Xoew7{AFuHuA-)`R z>x<2;geT6Y=i8xlUZPV8RS+CyhYD2W0x_h@S}>*c03L))(Y!lpRC6P`B2FU$lapQ! zWA03@5=Tyu-+AEPN6d2YPBAKMyQC(1-ur-CF;N~dCVEjw*Ti9c)9D`;p zt{tg2orqeF1SWNqwjSjAW+A)?rdUO!ub-G0wfw7w-DR>KO)OwUd29Kg`3Q+B(bK3Y zqb-I@5Ll!q($oU0#lVO;HXM;#7MLS{V9`4mg7k&ZcY| zyJ$&OaY*u^6@atFy%JN|=q&tVpDDj1+$zf{k;+(6378fs8AA{KNg8rxrLDL%=X&3C z^f2aC;RY`+Nytn>nByxHfxWxHeaFFyR8ZTxRLLTi3U4hXN2;{#5H-A0@+bZ3h?`bu zw|lzjb4ik0OMf)QaA*_0vCi3!S7rEoo^wmo$fCzP7d{Hkz8~!hH{$(K{3!mM|F%Y` z=p;LV7uQxQ$($lJ3^Wp>Z`vfkmhTk18VVga^-;u!cLN@d{+YwzrN7*WEy>k<$fF%b zLgttqPHDk2<*rhJht7U5S&ut0_eatAe0|!Q|8CIbIR4+C;JF*phFO;eq@JsgCpaXh z<2=vw;u>g1n=3ESc_XQdI= z>4V7Dk(G}on%oa=i82YFBn7;Z3+TRzmJcVH(YGvZD!Y-ikV&H3a`NDi(JQpZHl3bE ztt3hcF6{pOpa1j1h5zG!Uih!C#C!hl`}bcieEQ|(_m3|8gh+u-7MacPy)T4jy%2D| z5b{I|+Hv57MUg#L%T2r0MmVk9`dN_jFEPY?wFF`eZoCsf)v{lIqkP<@fH7gcG*Nai z7`+OAi2o`a;p9k8G3cy3Zye-$@HKOIY&cdst-)Ykg&K4p(bGZEK~?C%rS~S%^feX5 z4}eQlq2l}C<{NSImlJ+c1=i7t{&M~706cHUTx!Lc+ns|5*3;Ea5Jj4Il_k!@<4Ks{lXGJy5fG6aXsT2sh%)SV`i24^LD)S7q z3%isxmTyBiSQg^<2~^z&d4FF0vxq#fGAs+|v6M9Jyb$%&*W$0X;!F~AqN29~Y~`1xR}o{s30rQ#jV z?@fkAWceyC=fXDdODCAY>PT4Lnh1gkyOi)-x^e=Q%@Ik*LHhS zFkp4HOU~wIAYTPiK?%gTJo~YGntyYCpD4Txfq64HgUR;d7SWx4ZpAljp@z?W?J76Z z3imhTI-&^dW{$u(bre*lx9`Z2mcH=*HXT+zD6je5;FzkanV*mE$3HU4Y$5A$z-W34 zNegWq>HWA*HpUX87{p7J_~>fh#8T6vj#OXIM+L_%V{(wg_-8&Q6?QdQ^-|s*nkQ&q zSQwYenQ0(>#>OHkt0A=h>& znm}oAzGHyBX7h7F4CVtzH4& zYi?x#Q-&?`8DC^%^3uvW>wMO=k;c9P$#b695_o>Sv6g(eBDP#hQ+?oGjL(tR2!{^9 zX$3={wL&3*sKVe+S{VIl&;0hiMS)|K5dj@yZTQzJdKH4ya7E$E)K3w{Z!U4)wLICo z)*rkSlya=36)bEbwhBS4kc?g@EwKW!T56kb=|W5X^=QDkH8lxg;ouPM_5F1{kMR?R zWPY_^BIQ}8QH4=i9GO9@!fl1b(zis@w9D{#M3*r{#NSXCsZ=9{k_d%`-nL}wWS)bT z!)c7tQe15sjiB*o^5E(342SQv=JP!yF^?6q{u zy!}0FlOuDc8cdAhP#dpZy?rbF>CaSae%M%7JZ3_fa-;>G3guk-pp6PGvU;_lzaMEH zcO=Kr6Z9(M6)N61$-Y;^@U(wheEX=KYg=8g1(W4j;(B`zF_h{VSd*iWRStf@>bSaE ztDWFRMBrSog?Ic83A6>Vw2rULPbIa#j{C5?M^OnpIiQ{nuC0sI zYsaq{VZ0tNzP^6Sy=yghd!jW6p|9%O)Yx+kz#H}CMbhK;64vSv++OlbX$w?N!8XcQ z(H(|_Af1->K1y)(3jSJ?xf9V3vPgVdD-vVrW9-(Z>CuTq;Ibn z7q7;rd7m>tB(fIwTK@*c8IcqVE6_H5Qqj{umO!z( zj`#jJs=Iua+g23QR!OYUY{H9`K02}G)Z9|Ch@v%u$63ZM?^^OIS^v-ZdOj$+p)X_` zgj{LZ=9pZ*@GpVS`Zel7;mWO;T9*1Ka?VGtL|(D;c~D_`oOygnP5-O-zYY7ZF8sp; zwdHj!!cewWuei8dsYbqPJV8Apbu0O5J#6I~T{H*iHuljFEj6lCt&bBmCzn`o*%U8P z2^Cr1-if_-GRqz63MCV*!AdbZq=bT*XL-u|X|<#ye@uWc(<`rAYBGYG{NFDsUt%E{EbPsMj|wq3gGdZP6G7&1M^O!MOR4f@YGM#2Ld= zDNm4dBOJn`_>oac7$}_L?oa_Q94JJayZa2BzNtnUR5FVxJO;k$@o34HK8)~mgv8hs6jy_iZ*g&7RY*2sI36zwF7Xa*FL|-+&x>` zps=CEqYp)-1zYtZDLvB5k=B@+;ya50^L>`dNu?FnJ4w_D5^P`5lCwAn&(!&lwDhu( z_)GW%4YU|aPr`l(duqu(Sf+>O61#*L-dyh!__ z^DEk^(4$?UImZ}Y^n`XMrB&9Z{aBb=N^y=$;HLrt4iAd}mc1;bQ}nf3j={DP$ic07 zaV23&t4_eUE+?Xh;3MIfL!)*)OH9)1-6>4I8Qj7iLv>)HrR+{T7m}H^+^z;0EncN{ zK=LeOrmBNf(@wC-X0kZLGEGWKZw>56xJwDy^|-$JzCM*ef_yHJDC%W4@X0_?(x0+# zcpskxg%mkS^A)nwHHmL=lPr%ceNBs(Q(@19#Cy(^Cbe}b?QeZc+q7g%TiC#+ zF8F!;#Jcs{eZa5L_}zb#q1$q>3>H}Y#Ad6VT$1^m6$wclA)wD$5^AnW_^Mr(wAZ`( zLgyj6xD77s#qUDOz6mXJhuCvd42IScJy3YaB?t2|F{qK*4}*cCs2-0cigQ{L7DdbS zZN#!h`~HNjYqLUIN!4yRX7TmN##5q8D$0|(rZ*LuFWL|IqiKA6#Dq;`;bDSRtD zx^4;6IR$NVh+45yifxG8C>NUR&=6Xmg;HZ{+Hy2)ORLehLKcvSJ0U5*4k@8U{chys z*W*2}-V3;^-Rleg*_3FWu!!;XE)FCX#@@4;1zt$1fEUS|gKPg3bDJDdk46?I_0AW7c)=_KuI7&nY}1h@GaB$$hZ4fltpy zs82EDt-wq;uZcZ%HD8VRtX)fGpKJ9P3)F4x>TA2JZ-n5%tF>!i*|A&&JP4oCs&U&qyi#sq4|o{W~G>+KJBtNNMkFUH_9PjHJ#W6AqL1 zX#xQ%>Z#N}YrsnAd;Mr}-zRGd+0;L%1M@zef;6pwVPvXID{Qlonx|)kjKT_2tyhP_ zvwqrvOtAI1PoOjxzx!`er!w$QZtS;4rn+oYwLdr?3P0xNK8hzKNO8M=8i>3qVY;0T zUR%#saD_%lN;#h5KQgGQW6e4(TR8X}X zr$lH#utznleork(TQAl^(Rx45*v*Bs>tL3(0wnX1>r>Rw1gXuw;A!D?z(?es=Mc88 zYdHi(;NFg`L2G%y$!Z??_h-B2<9bCq$M#T_5pmM~A%waWpSXDf99pbY4N?{c;N*lWh%gq>@=4Cza==+4GrKp0-@e1Gkq)EA=mToQI&lXma{~?<` z=}jvIkK)s;&nQT1IU+euje(y1Qz%+KwfA$q)?6Hxh*vG9G61R)${l;Vv1t|3QK=^kACrq!g1~U^$c@7 z#Z{=F6~*JQUtp=69NiM8j1PZUEmEBVS{kl|d`XskWeY(oQ+=?Tfmr`dhCmsfwIiz* z)$0H>5&VR@lC?`=rJQoHtq4rnSk$+mv>~qT=f#D)6Lx5uQ0gfVSgckuM;3YgaH)hq zHgIW1JPz05PvC4~o4ERzBN88n+&w*|XF%RtP1nbfh_sjHc-4t2)z*&WC6sEZyasC> z>!+(&u>zFT$}uaqm#B9LztFrjY!U{0ilte5+MAZW{^y9Q&Uy`V3lz-#x1S*VZ3n(3 z^rXu4O_*pNtK{0IKC6cM-6-YWi0?5zR2RPqS5XC_?qvAaX~fapspN0PI4oBk#kF6b zRCl;%Y)1HoB5!N>mxIWEjbQFL8lHf}mj)$UQ?tm+Yesc2P-LWz1# z4DSDU=T=qM(-qgk<;nmk2%)LPOFp<*ElK0T;1ecH%LO{YK&Nua1&{I3r>*(d(&eqi zk>vW>y@|7U)WN3_G5<0*Stp}GLJz41cQC8iTEepftxxY|xi^^;oMMa%b}lLW1- zUs^Fizu0x*w63o_E3|k0SLbf#g9fpU?ecC0$+gO`)wKvZ>CV%*WQMKUyJ$wKOx<>N zF8K+jvPOCIsZAdx#15Uwp`V|e(K#Vgm=Bz^E+ul~P~HfQ=A$RT>+ z5bHJ0#ZzAG{HhMM@JKS48~HXy$PrmN@6iUn{ig{U&x~8dRYT1=PFYQ11oeARPZ8wl z)UrFtnO+NB?WMGgq;=>s-880c#bHfCWjsgEry>B;20L(QtqHX`3d6#PdM8>6FWf~; zM+wfsxVCupTHuft`lvU(U$ktswhtsUI=}mG((w~w+zxs260mt)Wy2DLrjC#HPU>?w zR;%wh*F4C`qrGzk*9IzW=0|(q3f-uOjJNRGg0r>9eq;{W@(h{h=KY3Cz2MqKP@l35 zb~;$AZ5JR%hO>3H9JPMBJ}V2nXolt4cV>`SH7;eWmC>qiIUggh@hRao6+Amw|Flrq z-?uf8`Tc8DJnZVF*+;ziS)45Ma-1*odi=f`Av$NxY{6v2L+*Yfo_lvCe!mibw~UjR z)vH-QkZoN%U`{sQUZrm8wuh0|MEe-eHn!#K617qm5=Qe9xo%}o9(Bu=#`Aon^t2T( z!Q0mQ=Fl5fuAYCpCb9eE%Cf=}`+gpBQ)hb8+$S2S^HnPFd8z3jKpgOh88lh0`SzZp#-!FI9`iE!9?L$^TEiw?YRzv0>pwEUMM*!x^LK^1` z`aNpvMwf&3F4K1JLYh1%i2L<&6Zu}6~Q{PetoN?O+vrF&eb7^K=>dY-x^y#5UMbUCJ6E3c?Rlrk7Al zV9KQL&3o3a0qd4Fp2@V)IBNSB#Pj|$Oq;5Fzni#`_rhmVUji7psFWUs(^_bpbIfBv z11*6fm92!Sdv%#_c}5Qj1!1tXUR!y3N7vF}l)@l&ce+uk&Fg7rxk5rkA-Tci7739~ z!sgnxD%irKM?Iqtq+dxzZ|I{rUY144f)jeIF;1U)+*X<3+z{qr*;tEpN?BT-XsNZ= z&1xg8Cw=-L%=q1Zlfgzh{MK@r#+K@8(X~LTG^0w&gTTkI=M1s{e!wjOXXT|*0EaLM zF?S_w^$zCksex8hE2{-_sJRu6%W*%+Fz|D3kOEFq_J^yc9`9BNo>VRM(4Hur)}X3$ za@(a2)&K2hEDO>(bP(OJ#=v>iWmC&eQ%8kDvY1a}6?LhGihNgWf3@3S!O8#k;`QCA zUDF7~@0)S0e=HAJdb9v-@Ft|c1ckA_pN2J&UF9_q9@m;j)@*Z!6DZWUvfhbq2$uei zESaJYpmO&$Hko48@{o_SYc@w_;}M&L2-*a(`Y7WDgHx z!G|B!r%|AKM5{4NA<^Q<@54aa#Y^d+6Ep)ygiP1H7UOE!lD%U`A;@>)$F7#6r_MS% z57LrB8ADJHbb3EvWI0w)rnyP%4hgKGz??pkJ5(|$+4A~Hgs~XhA4Y=H4AdUBTKPnG z98&s3hIUoJRD?6xU&&ocTD0cDIHE2!LSAWCq)w0^$i)34e>QiPGr{OtlH0ClD$q=c zW#D$^)e-F z)%$Qe!`l9v3{NxIZEXlVY9*nUNQKbSi5w5vuQeoO#y(V>nb*z|PVPPoqADw=fe0*5 z57Am;yNxE;4s_t9z#BT4mp@$S4-bx?aQMG;Z(t56bB&nBnu~P%OiyL}J@41Y+Le zp~|J2UTR>i`s&BKOwh*oNrcd?yM=D1#x~C4W>r7uJ_Tw?$6j6t@3^`R%FZ$)MmXoI ze3Rj069bRQN@rpXXeCtb11(%gxVA>9%ajBUSak{k`^%GB6^6Q=a~ztYZBD{G?`UDg zbW>Ndd>Il2)JHL|8ZDe+*B~Q#V2jWu;Bq`172-pbSiw*iXgZRj9%vrDYjI5M!A7iyOSdLpF zff`kF6807zX=GZpIaGwfZ-yL=tRD%eG{Eamznof&c-q^(d(36qs@~c-MWJ^%OA1i$ zuR)n~>C~0q3@9?i;xrBJ<~S)dL3UW5Li2>W=YXC}mk{x)ZEewa&&TISF#~BToX_We z%=lK6_(1aopR%q!t6;Og}kAh#&U$VA*T+r3s^~vQi4A*wonZ{1C zwTdyn=k%5Y+>s!)uwgZ^!*sR>LF_LQRdJC19X4a`7c);dapJG`UF50>*8TNHj_axnc_})o!$O zM%%~F`Evfz!jmK6(=`^^g-(t!O~0SA%<*Jph$8Ca^Ss`Mm9QOi$w84OadRG(M`=Vh z%+I}k{(oP%@PGgBC-FRNikD}8oHP!LP(Q;frFZiO9Xs_o)l;j{G)+OfHB|05z>~T5 zlOmf@0;mtyt`7n~_-Wq9!9{w1@ch~e(8D3g8_fCkbj!nC@HYZ>wA{Ub!0i}@hzE;@ zWT7*7G$gO)DC23A8*Qc*;ZEH%(4(9Q)u}k!5=IZ0l4q-582py*$$g`=sp`icMTkv^Ov*h(`N|uP;EF zu6*9QG8Zt|=5q&-VI<^*0BtvT`c1`>vS-Az&rMHmRlRf4r(3bIhqA$`EY48&!~lT^ z0)gpyJgKXl*H3Q7bjnKTmKy0bK*b#I#TYhYKF0`2<~G(53G#T4u}g(GnWq|e@qUX% zf$>nEo>Y-$Wk4QEkG7>z`o|5QkWBBH2I_wqKkB@}+WE;Z4-55d<$YYOI%;M2eQ%8$ zCVvO{zl{X$v*1!4Sht}#oF7B_=z?2a?PbdBnpmLvddnBe9f-L#`Z=L>Wz|ST z)b`w~hzilQ36YQ>6I7dp1E$FgZOf~-rxq3E$M{}|$r5-1x>K~O1Y`Ud1gZaGD&t?C zx^^zc(W}V)=O=3O@x()(RimFeZVQHZYSM>#)l2t-&dqFT(z|9V^baT~oO9dqyY;JqU@yVJ$mhQE1_B$v(h(U=ivyXjk z=(|A>PgE#{KQf)hFb!|424d_*Xy@s-OuNbhahP^)^bFyNiID4PVZizTHwz+CZ{H@% z-Ue?9QiF-(q0;AjNUc-&crB`h#YJn7mP7V{;NtRmc;elvdpCAulzgz`ugwV?~d_uDzEGkI>h`+sO0GH z)u1$=`|q{g`x8S_S^qewt7?(r*1tyds#gzIUp+kecJ#_ePlO`3tTxO2cZv1>-hY=w z!QcCDD;hULFg^%cXpx@>Jp1(gR#XrYgvDaQ+52t`@TnP|Vf)`ZvB+^f1d_SfRev1X z0W(w7TJf0+UkV)GoyX63oJPd16%msQ8wr_(&%))um*do-pHDuz`1l$=EeqUPL=SKjhgNEQ@Wc=I3Sb8+vov8%MwB*Lgpudli8YZ1? z_&Q`W99$-pM!3g9MEEkI`3cQ{s1CD~6D8WK!(}eA49^CLa+v+_>=~|FECLXUJ8&w) z22fi?svY8kxVd)4nKC(qY%T5*Zt44Wj9#tgW2k(T_e(v0Q1t@H%+7n$_}d+#Muopg zl0+vYZ+#F9=}yX-gJl`ojVQY+0->z3KM_)v@?m6gFUJVK-93ysW^Zrp(NJYsru(aD zLUmv46lTpftfO^f(o*b0>ldht=`(aS%xDtkZuaowe34pcQ#E#8= zIP=5F@IHt{h5FIY;{S8ATouJ-#Ul&A+~vyZ+C!POX7k2{B!)3;}|W9Db^5| zRYd_7@plQTtUZ7&QEII_)KPdO;phk2_4O#m`eRddsw463=!cPx0s^gOE#HrXjDEPE z+91U@$tE*B2uNHJZcDNAb0o4n0lig*(D8FAcNG)lar6Tu9G>OgQs6LmRluTb1=mHX z+B-esY-=C5^Kpy^j4Cv$csS}A9YJReN=&T#^Q*;^+M_DHFgD+ulqg4)t99zP9Citm zr41KQ;hZTqw?cDhJztx}B%Y%?+Rw1~{f}rMdgmr#tlU^v`upea=|${+m_^ycpQmvj z1c#AVTZgmEM=xXlBdj>)4}W%+(O(HW#n0vNH~LXs@kYRpoT^80d4`+CdseTYQI4i^ z--Dn7a@$KEeT40zB$lV@Q>#1Dl-?#}-+EiuI}DoNO&aNj5;EDqw3Z7|SnNNO>N6Q#id(Zx4l4kbq6~ge|4vu<@*vBMh!S`t}z5CIj0AAZbrFt`O^3fNuh7u6nfVWJ_CsB|6;lu$?g1lvs;Gn!Q0a zC0w(c!p3}=%43R2>XyAYYfI277tV#Pcq;7~+f+O#Rhr}hF()z%C%&9wPYN5UaiSdd z6sqmBa8HU(U^b=|XJ4hwU6#@wqiZ{i?u9hw!(B7NXf=m!f$_aWehpk{_tb%t)ak!HjqC8<|xK zO0Z%^`kGX7OS>bEIuGi5lLbA$`)|^AE_VuBbFoRXRT=Hs;ycEbZ&Oha%CU;rwklaW zm!&gdLf^7Cik@Pq@@-gcGW5iX>&_0p?LqZ%4};RD#j(oF*|9}t9xUQq<7Qy4u_-=8 za;#I`TAa30oB4^XytB#JCEZUCgLJf&os4^GExl@m_9|Vu@QWz(8Jcy8NgOW5lIJhZ zM9oS?L2@;kG%6;2{PyJV;89<%oe3NDN4D`@#V|9~`stx~S1z3|Cq;p?>&TMs3sY(` zj>w*FIsmDtZJMW^W@m@uPcX`OE#)%E4E@|*;vw-r_o-t6j-+vTj{Wb|I=(QdOEDx3e_u@EX0$M={AO5 zj{o2wa)u_XOZ7Sy{~3AM;;q$!C40Y){gdFKYY?|0?)-eJWju~7=#VI_$4{#(WIfAq z{||>JRZ6l4BEIv$lT`ra_|E9QpFNYRZ}h*9rwo>Cj;eIOcZSTydFi&Dl#0>cj$HJe z`1vR@ylqc1fBKJQB2#3KS)Z5p7{4D&>qoJId@p|P#;R3+QfzWyO#7vss(GF)yVTmQ z>+Cw~q1k?r*xeYF>P1`mMOJ_KW5kqw5(Vl2N-BF)J+VcnKSV6LE^2dt3-y>MwFj`_ z9d(82+GwUD)!RZzmU7(AYQ=U>D8`!(v>b~$TzVNd8{|xF`DeW~!2PI4G5)wY;PF&2 zX4xI64C(sfIz?c9D2&eWsL399jTXMaoaI|D^}xXS()WvT%}e0~C_#Fu{MA@2e?4Zt zIvtqegooe&p;&^6;$9UR8#XByZqZLXqKy-1R1Q1}uBcQ*>cR2vw(`Ii`1@@NW+<0+drOUaVu zOr6<_WQcNeX~v#Al8Z{T ztzk>ds{HoFb7q-$g=_9QZ-2DH`OJKL!Dme;w!Eq{SLos4c-gGIfBf#l=q<%AFgnMs zAS;#Ytz?YHXg{T4$RpkiF1XmbZ(O%GwWC?r)81;wVjlEm=|&PN9Z`qpr_d9xh!~B zL=RP!)e%ff3EDRJSnTFXEwDZesbxvhJBV6Xupjo1^ygj=D|RdHZ6Q=!S|0|rRLN!{ zTfG}$4+)eh#%uYeb^vdYu+c6M;IGiRy+K14cpi2H`$Y{XV6v1mQo=dwtOpKOEadY6O9xDv#nHVPG{HGm+6{UB-R!ZW?QBP z^B#4{7Ce)5Z zlk;e))rN7EgBgM>bAO!{HH`dS;OV1J*rNfpw$j38b1Z3Kx&}uLe_AM%uFUy%7<44k z$tlA+qJMt2&P`-Vy#`CL%a${_F+vUmO_BJY9E0!wn z#AbtYT^BbO#*&}#;URfOmXAnsS5a@t*PdiJ;;TZm^sAl`S#i>ggteuX`g~TE%;*FH zQ^_OeVXnIiJh4dn37Fw41WAT_LE^XXRLT19Th>z!_{8!WGH zVB+nt))L*f0~@c>y%~5BPJDjhm%B}|6^@Isb(ciqtN8t9{8q*Kqi~iFPp;&WM3RJWeP+`pHtALq0w%dA@vM1i-yT|LB=3Q>%#jzk)P-@@0 zW`)S>n#l(mmGr2e zt|!v%m8x=5^F)fb!S&(<*`aB_DU*L|!mX7Fq(G|zwJhSmdKtPljUeC!rU94%jg6O7?_Z?$bzG@pWE)9^g)u_04{ zXgv}Ivl&qdGhqf&d?_sA!$FeRj)5-jw@NyCdcReY6nG6>VQ5PgC23w=s=Uz|QOo5R z@xU8I+9ZdW=w}f>WH(83GX$*F?*W>?yMyNPyNZHN09Bq_b^5X2S6mTKVF zQZ@C?BliAF-ff8n-0#hW$O{Rpk^!j5hNxPqRg&BnnDDr#D?(IEfzt^LGt;C<1d+U( z>tjou9&;UNFGXRXXzZ*uD!Hp)c?({pY)<^={>d@zu$X0{f#Iqan5vOq0VFU2T# z0(0RlOH_*=3D;P!dpnDcdCTd;4yv_h9shnx3+rqnO%Qy`#lrJ1c-ZQtv>VMj%k7x7&^qafl2Se`mT-jT zKTe@nFx&GJjkp08UdvDXGgzx3L2oO32H=7(i}YSVL{PfcOgma3Z&!q+yK=a5DPN*Twq}A=pID42 zMDnfYKD83suV-ce*ng8D*8Y$>b;spfmj%+E0{O_&XNYU+@0X{94g1q42GzqQeq4Ee zm{c3l+7X@Ua2Tdlo|g*I+i~8q>S_;^`uBbFu;RSc2OdI$HZ^RTAX}jvtq5U$=GDc@ z=+mtU_4UejL_d~LhjwC`WSmnWS~HDVg^bQ<_608iFk_#rVy>UIFvDDv zBfdFhwrT2ahg;`RJD_e&iNe@?m`e?7d5t_D2fk3Q)@WG0VD$udK)qJ(Z|=ydo*TxT zV`)cLJ8vBWvwiwKS?IqWT?JnE18Q2hyq^h2pfC@d=FleGORq+Iz6hxZq|QF}((bQq zGc4@_6RocY6*53}$Xu=NdF&25l&1G4s!`EKYrmKpbZOisSa3k&>{p_PiU0++58j98 zxM(YV@RlFMS`N`q-J{pj#|d6*#Vh7#PZr^xy?CE;iL?Cfze#VkoWi(9U*UzPP_-|w zJ(;A7XUJlc5|0vgi@E)-qyAIE?kbeaHOIF?HGB?ce;4i%v&ZLcmi=HFKNEmlme6uF zbsmV8VxJ4!+r#aCpV5cYexjVUuPrX`HX;P4Nh_bg;CJjXIxIj3_t6h3dSfz0=8nZC z`_lVhTP#L_a5tl$@u<{av^|jL7*K)XQLrBEX1pKOU!|x=Q8%r}JpiRRpLg})88X6W z;~hwK(Jvk0&A`cyRWJD~2RMXl{!op~~kIeXyij0A{J0 zF?=pLy4YHLhuDUrIPD=jRw&Q_mn}PST9WB+6ChwB0G?1=6nA!y7&1ncC0ar4^T^yfO zj~#%w_#@7{CMAD3aZrceR9QAWsnz!QEo^i7X=NlSiww2Z`#N9J2&f2Oy-B;b2$j>x zL&?|m2_Ljc2M>vw-%az1CUtl9l1~(k;T3YjU&s<~UCmfJ4$%uxzQM>(r{- zb2BjqTBxMeDCWkN!e7lj=CM)|S_82!YD25GmvJOphO&o^87qX9!lH#V3XM~0eLO+t z78ZrHT%%MBiV=q-)!1$iPrit2P zS|8yLR0n76gfsqVN7~4g)|O(#fPV>G(5<uRC!TVLbrmqgdtS zC<+QF@5N?>kK!1h`*G&Lar`GIcqiroX5jgz*b6=x&o7w+2F~VV{ZX){9`#RlsB~+w zK~}~smOx_~t zq#(V+YtvkJLq7KHdNq%&pY!t`v-otWgIT#AF*M68TA~sR&Q|)Oh4ABd|IMhJ(Nf5< z!l8U=`QZFA=Y!T6o$-8#e%}4NY0ZU%u^mI)?T?#Vn>8r~d|BdY$DPx{cE0YDmA%>@ zjk`jkm3mvBUe5J-X6V3YkDJB9^;X>;i?y@S`)jR#9D;=n{C#*2+4r%&R`^Yo*Sp1@ zHBPV}`1PHow|;(~{20S;?;xLy$1-g2;Af7*&o7SPj zO6#@dm%{g)0)&60CGGwOFoOb6NPAu~tb2P$8M(WqQN>dyt4Ucxz45M=y1FQc7^6K! zx#cv5*rxOJCFwLb@V=IiWP}JSYkJd$yeUJL<2laAjnXS9%HuBy07)R0@##ZTIURoY z-=xFIfZ%bAtY+9PP*o@toLr5gIdWW#a=Jx=Q;%w1(%N^egePTvjdvr_@~qFN4qZn3S+BCXL;Uug@66%g9m}_=*McD6ccS7=c>-d$%1ex zt1YzxvcChrAAQsqx1|ZLUp+Xr@Q!Fq7i*@e@Vob1q9RbUd1zcpB@fm#ul}n;5dX zfhooPx16XHz8MrbY#r7PeguOoPL3#3F4wn=t(-#UHkiPANc4>r5Xu9x`#_%Ckf7Ft*AFmc@ExO?Akp%I7kMf=_ntthk~R%TEIRda}*EJupT0TjmV9 zM!P?waxLgU| z^4#BEqu1)A=Y?7I6HW|yGVmBPEcN-}w!T~JyfECK-yn<2=U-Y2kgPFP&YvddVJnvN z8SCCsydXK?5Rs>mGCthIWua#kbtE%OT+b@%KZ1(77MttBzRPZ-Z>oV>+dXHtH-D=N>-W7Snhbr{0|1xT*;L=8XBA0P`9Hw<+yA%!YyUjqg^ZW z^s_CRGFQ*xjTUK>gky-U9${>u@H+U-jYKWo_aZGeZucOx=lRgIHMjB3wA(|nx}^od z12cTBO)v*d)3=t+@m3_$&tzJOF{uj}neA%ZZ!t73wd6S=oY!jjq9`St^^%=T$Ja|R z3_+Tl*(=gWnv+u+)w6ulyjo+$xb@2vW zsA{oeAqV0&gudsO={B>LneUP_U-Uy0qMsf^{3~@ssHH zy_bTV9}4ofBWUN>rQlsYyTcTpv>sE|`N|-yk+|RfFW&F%q8(kD&nk84Ug9&ne5zW$ z_eM-nchkT10$taDX^9uwg;Am~ls9}sbB~W}*5uu$6?aTmRn0KOUP0#Iy*;N;F3rw- zz09==7O3@4GRH*jk}Yy&oaJs9Z90Nl=1qzH$~GJqMBRb$eD%z=VC4(J(AyE5Yu)&* zQWJA5h()E0)(JrtSd&7xbI~SFq)N@|c9sX=7?P=vLMgT?ZeRAH@;|N7fI8^7)iCQy;+7-35R>d{w3j6F-*2-`SFP#InMUxdyV2OM07a^x>3$4JRrZ49Km>bA1k^TIS2wLwxV19FGFVnsp3{<%(J#^s>7)(Q5GV@hkg!icp)$;p=c zc9eMH#rWWovGtlZ{6-(v&$d#amEqUo{#uTXEc76&mI#6}tT7Ly?(emA%cFhZA}aH@ zzmhI(y6R|_I!N!+a1OBKT-K{3YRb0UAh)`vNw$n0Xak<>A(v>a7iPnW8j`FNw9GZ_ z^O&S-+v=1@wwBMgwk>iu^t6Th-i#8X_&s+NdxB=xx>RW}S@7vKrS_({2bsSe9~|(z zgRW||V{I?j`CZ%agLFr?hJSzc?|t9aU;2CB_m-1!#Q#yVj| z8%FI8Uzg)Kd24PVPVNLq9FIe>9!B`Z$up7iVC3WHsb~(CxezB<#S*8k#3Q6kc&Ix4 zbg&spi@()r5|Z!}DV3qUJbX{g1hSz5+nr$a129g0fD?Gn@PxHGg*0)Y&k6^B`+A zGJn_Hl~MCoM@^wf<{rnRo>yD*Px;EI`45enI=l7Q=$s#C=DO9wd1aknqvo%TnmQXE z_&lg7jX!^Pe`VDCn1dczZO1FZX0Lem*ok$E?Z1f&6TI=alV6 z{>2#h;cyX_w0$kw{$%`T0VVmP)>AzbBw|8FlX79Xzw1sd?=6vg#JV(j%m?PYP60na zCv^(^Q=w4ogw`)g+oR7v)x@cRsa^{g`)7i9TF^HEeh!n~->sWih%{{5wy?%yV|5Z7 zmM2dKOwxnRNdgp2fxp3pw8b_0!v(}vF(+1oNQ3>aMwiY6+h6CjRD1kLB^w8|uW@-8 zDe_wbobNfW-wo$=tl0BRVaIes>tDL9K2!f*el_pR#y0!4kQ7^;{W!ffBW{Mq)ZHW0 z_U;hZLO9jbrsqbe-Ct*U8M-6Xro5R|j`Wm3Yf>?y`=Joi$NklT?0TR|sgX#keH>FfKxz{GZ*p39G z=N(yPhOfo;F4u=hDI79_C2GZlG{Mt*qR@gcij>h4!}OYBIDA~)$!Myr7Zs*G*RX@tDp;^~e9tUV3r19?mn{I23-X9NkB6c&d ztOfsAw1?S|l%gmlvDlD_(ZzYBIsiMRy2qYMxiDth!fT(j4ea|ej;UXhgJ@}h5vV!a zKZVr7dx5a4^*2Lhi{kyPgR|uwy%gTB)n{RONGX>(?m8R;@<^EO_k^|Te?d^p`jge) zGS;VtuG#odD-Bb$thgKZXdmeE5PsgW+u%2&Ce?H}j?2Sx6UUFEy;_C`Z7{>CX6~H1 z0NfB58ZF0&QvqB%V{p+QbAv7%9@GR#pk(lS-ai<2nY*B%I*tCh6O?wBsgJ?1Uy9mblRzLfmF%XxG-xv@Dp9HH%BNjM0m@TZsyW`9rn`rTT zDl8j`qA8_2lI!--)6p$i+fNTt+=jxPO1KoGc60EE7%$a4k4G6!Z(J-Ud0vlG^{ouB z292BZ(|Be%WMg}skMOHQv>t7_eqyV(ErFP6F_E4^v+3Ve{)=;zP13W{t@A&oMKADt z(O)215uABDHgQ$C*`4@>jmCb5dP1Y{-WfW(Gu(oQO%)NXR5uc$a2pXCL45~@x{7*% zR6dXW9hx$DWm1My%$cFm=_VZxgdn3}vs(0}=+bZ+X0s$NPHFSc+ruSripNjKBYxXg zy>OY{c$EtD88kB#ab`y?O*!xxY4*VB37v!33x(fipe_bJ*b*{Ox-p|V+ef_Z7Lme< z&|G!`inM0T7R1<{h#U{54Py4;Im3w$h@c-G=5h6EAG7Q$18MG-VP}+)C8g2cZB0Q> zJabBNMFPi79Rb=)IM)QM5M699KjJ};mYZrr z=Iimyk$6Hisgi6KiOAc)25Ol=u*52YBVo#G0fwPxY(WG5ydFjsdvq+$npYQwT@2WI z-X1$Gi?|+uUJmf&x++H_op-bfuD1xlFu@#-SmB$i19BQi@wHMk<#L}=Z7#0c zobqmRL}u6*hT9&<4y9(f{Nj4Iof#N-4R}|=m@$iB$(g~9+pv2IYL12-BogM)?ZGKp z`8X>U35V^)dx6f%mbas=i>ndLkq|1^LP;R0NE1d&&hybo!(0fIcfxU8$Z9^yzL7kD zmWQ=KSm03OH-_`DNMVg<0@ks}OrBYHOm>1|czx~YW*dFHRobyla`;8EL4a0}9Xo?r zKn0itC^u(dRy>}B;gw$XAmD+r2oAwskR#!q4Z>41duZU3dA?cE{+S>a(2swao zb>MtDbq^7zaviqkHABxwQ$`z4sz&>O(Bj>kj|`M}PwD4}f)+hhp-633Q5%?`UUDkt zn;N{jG4+e=PTv^AdH{`igx?c2rH{n;P4(-*n_>~>6Y)9Vemxot0Vk5PMGs=Q+ShoD zM`%qReQyDcn4Ankxe)(_;6oV~n%c*RoGc9pLsfaA7WM)1@ew%ywog1CE+?4iAIPJ)Vpqpvc0~HFk%s-_jHi zk!seUN+%`QlfjKo4mp!`z_tmw3DDW@a(@mZ;kO$&ft_0Rc%W2BupKnHGI%_#5w29p zwcr-i1OeqML7Nu`O}~P_w__Nu#6v4?J0DcP9Jj&l3M*DTa3PR67FrpVvcY3)@`2}s zYxmLk3uD7O zoFPT*WNAT&I|?CkLG!ZiuV6!BJ?w9rimbg#G?sG-OrWA;a43ja;e}7d5orffA}Nbc0+yRsEwN$J%WN<>yaygECc+BAl=Pq*Cf&D#9T?a0M0+|N4~}lY-N!xI_>G%D1XV#tp2|iH`)J zeS<-%UYR4|#ZcChL-L_vsa4H%3w$%Hs5pDAn+Ot)n@DwLQZTrDV%6pUZ21i*eR(@Z zfKnv{x<-zz)Jrc?D9ozpDLjf452k_eYG#LS6CkA5NXEb$`vkcYpx`>R(;k6tholnn zW@l$R`Qw8wB>!a!kvhLPgt}BgA`3mUkJ+sqh%yMMY1A#i>q;=2gad2H_+E(y(KKz> z&xULt+M4R;n*CS~{v(4wau2~1mcXl6ta_9-#2%h_bzrPoZ+#?WW?$f^IzASh)O0c& zV|G*wplpSsCG2D2r6~gJwHX@0f1PON;Cl0D=)2iw4z4$khSt3=%`73>!S&`s-_ zvbF(xQ-P0%$(mIfV~}`h=X(n%Ss^1@B)0aB&}&x~TUeYsBH<q%Q5*UXveGPVcDjR&rJPDJXB&po#9OPg7b=Ib~`kKUi&EN$lC zdh_`G>CMt+4vuv(3`=;;VZ&S$C7aS4uO-2}0pho^@o68HDKm0qI6t3UDgtLtBXa~iIcb*Hz+n#HV+RfJ#9jfi-w8HRgSqkeoC*FQ?a3kq zrD;9fb6vOHteuMuIcYlj-i>~+K?I4BeE{DLa}1z1U3M+Nl4>RsG^M4O#>%YBhW(jt z^1z#!j?1T-*%1FZHL)`!P}c-@ahR^z3HsKVwxUCJfxQJ3#(AJ|v0{46`+OY)TP~cKb+9rgjgXiQ8QUID)KMgg+qES*^ENU{{UunYgK?uAVYLZw`r%89!XKFJ!sUcKu_Mr4W=X4jT?W+Mxy`n67 zK?-J1&}Lre;srBg@j1_^XewU1kMs#y1(i1N>-sQug3(vfqV=gwgp_vz7UduB_QW&h zK(9K|FN}nKQQB2{V*D^r?41W=Q)J0Bw%7I<=N7kdt$~M^zKO^$1`I3~HbAQhv`Vm4 zdV@F}bFGlDI~T{8SVo5#|1l8y)vpU2-?gYEY5^XJhuKwE^d3L9F7Soe)!^yDOyxWq zBs1|(=_*vAR6%w093jR*72ia^MU8irU(A3~Wc<$2l?8+QVLjSEu(<6~G!OlRPEyzi zy%c>Y+|e#M*a@m(l?P0jZ?9R^7qcuK*Glt_I8P}>FfCa{20%5?w20agc-T$vL|C9q zW3?oRy8zk(L6}vp;w6SH&obLghY@WAn-z_T*rMCnhj9~yGIQN$@HKFgLRM3(6>g)Z zAPCV@c{%%bm~q6c9;c=vC*^p(CLlJ-P66FoO)x@IF?hD{`A}t(nv4<))kjm5b8+~M zncX6UQEci7O)U;L2DF6`jJcx<0l@EAmVtqw~N&yxf(?E9*In@U09=O zItO3iuoD|d4Y{8zLZpCOtPQJ-dmtWIpzlYi#rJELUK?~D7DFyQ!;$zWrCabq=SHAl zrEJ(#Xb}ILAK-~#m; zQprMF-CCC+)(+tziKaAt3J(%mXo;xF}kR z_&}Utfb%i=PskuEU*J?ZDH=iXV7(OoA%Q;|EdkW~8yp)UJGBP_f<%4@O?Go|=MW`! zFa6YjyPA7oKruJU1?iUqJ!*ZtgwqlIozN%)SxB=%y*a$sL$Gb8fVK7CL zIT38Nht%RwLCSodsE05 zSqmFxy`*v&3k9siEg&(qqt+$_k$fB4a#A?i21_ADHfoSZ&XYPIuP-~IO$^o}BqRp< z0}*W^b&1)fAPxiElN+_WKEbD7Pp07;k@`%a01}F&?OiMk&r^|4--*_z8G~#)!>I-9 zA;sEagd}49>tu9s0kLKdOB_}V!_A^L<>?hnBafvB`l;YDtr6jER%F8*^C8Kt*eaK- z-S<}HSz1M>5k|ORX{e5l#G1^hp~-Hct-vXFQ)>aQ4K}SahNR{;1dbS#z(_k=1@%{1 zn@MEl*0Fmx@IkxW#+Dx0gIZsXayfH&4xactoYK&_VJPceiFN{y*5Gi4B^y#d;)?Qk zRv8})j3JD+@4izOJRoX2@hF3cbtnwgXM+l~GXcSV$bxI_X`LUbVe~|K@pna)u;+s?82ml7yxyZT?IwG|hRVOm4^vFbc*~W>xWWOW%>Z&V z2v(nrkoDw2jY#faz?9P9hh=KAFt#)eoB|UpPVR(!p)`oLB$kUy1WLKUYH|8nNW@M8 z(AX2AuoQ>Ci#y?6Vm5i02t#wJRriZaHJ59pbm`EC@^M7@R=5;;@rtlfqY69I0br=1(7KeSXTQ0(iB-XK* z?erf4PrFP7!fE~BR0OdxZ~DDGK>eA)+sbDbIDI&f1Shs9aWjjH){ojmmj2)+HCuzF zKJspW_^bs&Eh8;`<)9+7xW7c^^bh6wav-AR{Pw!A)8vTP1bPnu+7&?=uZab5FoTJc zDnDj}huM^dhk2ClphySdupC52#jP4AV zEgkN7GKL*E0tD?TC39HFzp@G*qIx7V~T{@YBl$~v_EyrwHV9XP-V%Dt8H!2_F@b;Id$bSWuBB6 z@zhg2ElBXA`3cN7&!UJ3=Z1mW6d28EBQ3y9#X~FzE%LPva7=~FDv2$27nNa<3qoTA z4r_M1ZBT1=(Zd6P-I6~*kV!;2Cqq)Cu26xU6=0LSL0Pft@@D)_s<(3*C<;$RBLI`# zzc>&bXMqm3n07qWUThz%BjE}5Cq4yX5s|61i_uyKzrLx4*AA|{rKJzI!d8RL76)yR zNNtBI5xtaaXL~KwB5V`4Vq>-ZU5stdpR*%W^5$&r5KvmYG6TQnZAupqR6iAb0zb&F zKyoJ4Ot#Q(G9>I`BEBqqxEknT zl&CCYgcN=7Aa)Z2tTa2J3JrWXN+zzx_d+^10YzN@Vqm6>*aWbaF7jM8?C1?qXw(_+ zV6N#WZTVkC>gpi@2Rc#Cq{QH$6TL-W^{H*WaDhYv-fVURCy<#4_(KRm8&s%O1}=E= zki27JTC$|txNhX0Q;*xe&7swT+tDZwk?NE;0gGsEcwtf32Z3BJ@`0PQy-Z&!uQM9w zwj-^4iBX~A&4Fbl;T)Gvt$Nt4ZFsxg0?iDShuPOA-=ER8T=yHB?G$v5f~0OKJ~a?} zULVUrBCU`As_1sHxx_p!J(xDT$cQYs!&@4gOUEP8A&-6GW+(JSv}A1Bh89xEnvE!B zBQ{N`{7^^H-Jydy+vuR8?^D}Wpm%2Qo3MUx25~#d!`|B7BQTQ`o>uZL1+w?ig>@c) z&h1ou8o@~~7{4IvO`7(e3fJ#cz#DUD2NPoVJDWC;SZ?uB+=A{M-%RSs#t~0WIvJac z7$XnGz9bk!Cn{G}_tl{vOiA2~Giy9>I4t7mwsQrFd~6B&!Y0NZ7;mWF;fidwc ztg_<4WnH=x+$Lv$U+8EkIqDj(3pgB?{7z}I$XTvJk*-+-Xm^Z(ipRQhExwc0bp6z3_k>iOs- z`84+xGJ9IliCI0)a8EzBV9^Vq!x(1D&UjPmg<-R|1jqR&2B(&qK6nUa`c$y-C&O99 z>T<{81(%XE*&O%;zse%T??t$X*Gl?fy5;Y8_{Q+2HtC7FpA$HUW~GcnR&IsbWQT%({BBp}fEvmNl2x7M0X?pq8W zeiZu?@F+}fx8PWF)Lv_k3Merrt>bMmra5uwH@oo)m6Jh#dQ{`go*EC9^Q<e( zKqLXKp!D`If()4wJ{3u|=N8y$6b=HSu{#KeS0j^rus90hLE`AQJUln> z5!GM&<(`CiDH5bR0dKz$*#e#9smA0WM#d1I3%MY?K_l#sdyp>$!_vF^@AZ^w-XD%N z{p#PUVVwReJww6~-3fQpiJ>t*dcV#x4HNdb25~XKzEwJ95jJ=QjRD1Q~qH0hD4hv3YW4?5z`(0!bGbK(wTYPUie zP0~hv6H1L3o-(0r_Khbz@2=?<7NXSw{UV=KkMnr)v^J@jO*U6g3pc?kT11vOaCYbn9^fB8=uNIW+ zYv-5h!Ez?l^Dk09uSEaQxwFk60k6aW6Sty`L~#SjwD~LmX-PPs){=?|JOUAh=a-=q*`taDK*$I8t?`3 zY}Fz41=S&Xt~w-A14^9gd1EtjR2@GY>eDmhC`-rFOl=`ug!2{wOgDq2h+HB645%sF zkG>XA#@z(~)d({y%NT)^f4SyjWI}riOtnZ%3c>=)wEinYXX`WS{s!G}?7wHArvod` zGvc$8YVk{0cjFqb#`El|Rsp7k+t+lbQZ*2Tsdc&1uMO%=70qji-7*la%^lD9XuZ<7 z(Kz}?cTuzf)+nkVKA&0bR@?sD{F_Sq){scnco2Qzd znrvqM;{tHcq}fnA4YXc!8xH>K!_KAhmhgFCSUerFF%QOXa$frOG0DgoNw^$@z|GN2 zoP<}$FUMJD3%Q5Xn#kxXR-{?R)CwNLweN-ZOxALe&l1)lL(AOl(62}27EvbnP=GEn zbat~`c04t_cIhb6f%xT|;M?8kqx?7#rwPOf|EitwdIXOqT3` zUKlivHuGf6*Y7&`8q==(HPFqvUIU%QbknXc0a~x?JFxE8Ko6|@3G@KF&(xe!B&Xtg z6CPbc(;DdBY1)l`0^LvdJ3ejor`4U6otfL1&}DsEow4e{3Ytv_Q526lHCWnYT zDI#YlXk=UlWw9@EDl5F}2Z!k#Z4;n1QSN}@6-1={UmR4tlOmOd#Z$)9ln^V`raCoH z=!s+4Ce8eJ^yNadiOR;qW7WcLC?8@|sqi__1-CY->gnE|ENZ{+Ic|5fPcbgbNk0*` zy!SNAEjxog)OND?SFJl*ZnBe8`@03pD`Cv8L~AcZr(8~55tj{_>~~Du0*}b0CJ>Pg>zWd z5A^^G4d+;P>>k%DATUVSZ$j~>bIN(mOT3BZjzph$Z2kc)A40G8({Ki*c??A|omc{z z|3?>kyWYrJYfxWGtUNV3^iM&c$&z0e2?UmIPUtud9ss+L;KChCE)zk^GP8K z@ow8PvbK&LPSB}lEO(|#X~YW9rfu^EXsqu+={8?7j7&G&E>@_vPBo_W?{)4;IjWx= z{~lSYi$PdkX)e7|KcIYieMZ0CKXcgl4xj1oER;AO8=79ezfIEelvcHO=>8)?{up~R zi_ee0ry%c1UxVf*2Gl6p(v4B`nFFz)>{;NHrse^dTRIjhg%pFbW?D~*0$^?uFAj$b zH#xJ|$*is4SC4|bW-cqd(}ztq*uLGASlm8V8$AfdSHXyYbReMM(IF@G?$GH$ez%<&-*<1^fH5BJ84tSkbx^*&VSLm-(((2a z!P`{%!P|uQ1ZlV&)QVk+zc@>G2i*JYvqw&czHXe(gvy(+8g*X_+Wlw5_CJR`@sC< zBw^axt9kYq6Q;r(&MRP;lod#iu|=c?UttdC;x*lh(bwu};m(k`5(D3g;&&RJB2Nvv!yNV!Vc0lO$_y~P z;tZEI7x^mAnrfg1Uttb=!A#(#t*gPDd3=^oOTl?|e+p{|Q-kg>e=NXn2S6nm<$9h8 zQMo#-75&VR`lW&sK1wBx3Qr|ngRd~hpE(^^GK_VV*n8s0x?jUdCBn3-u0eO0V^Yxe z#+5QOi8khCjuhsTvD{UdV@_-hV87NA^D$Kyn%pPZi0HFL%tOW8^q3dy>s>Wm1zS%9 z;y@>k0+QZWM*>8BPSMDvK>@(^4DYna)Oc1TkdaF2o(Uk<7t??eYyYZ2cbFsUq(pJb z_5zwFYVd(ME$l5TV0@>(al4f$nz}kZH_8gkhv?&n=g*iC?1Yw)nty;R{X=C8Y7K6? zvK-LV)gE|YG&cj#t{3T>Yyl~Zs63{&?YWyv*Z9hiua79RzQAE>O(i?KZG-g@(5r?} z?DA&klh*a)#(i}|g`4Y#{o6py2%L}GZG6fh+d87SFm_nb;T}-uXAL4AbwCEq%bkx! z*~sYex(V)UKLLmng!kCmXChI4P_kV}ZtxhyIhQk2Bg=J^NHEGCU<{|yqt0U5v7htG zL9qtiVZLsFzf2+4;47MA4BM2mr@>wf1*RNQPOkRE5zwX(*VM)oPLV`&Y^#9RfEU=Z z_7%^7gw7NIVk#oTd@Byf^q-m#4V@KWEeF5auFZmfII>Ic9wi~x;f%TmOTfb==fjen z+4}KFM4b<*+>OpJ_x8ANDaE8JLyNf+}unsBQ?1qE_7C7 zJZikD9A`!XpHeZDJ&lA>vxJ{>Uu82kg(w|Dp;P~{M%)x4azfmaezGA?K_tN2TaSUd z7l`vco`cwrYL17j>~@UY^$>=-RLFgv#<4EiV2wGohwFc)dhJ4>8n-%hUJiXdi1XYx zhCT%`aU)ylIji$QyO#zhLT}?m8G2Hnh6_Z3{hA+FbI-V)ggFIqH$u$U1|vch$0wpa zjSp`)S^b&n^&CWelhvP1Af8wQ-ZVeX;fMpY`cvar^sMH=@@41_?&`ra%QA?5ebA1E5YQV@a;WBt7UeCP~lo*#?X!9PWt&|rA_j%t8pW*eOrW1}m#4)w%Gj%_GUJ#j? z+zZqi;$pb3hMQdT==LC%Q-f|KmVMVv_&!5iu19@$|6M~YNMDTsz8XVWqs<_D^#;B{ z4`%ss-H7i*V|wY`!9ct^=-(Gs8YyGYeox_;5cfjd8e$=BO-9O8ksLc%bL8&ttKHPL z3qG1?_;e`d?Pf$zNAu55&}v$h8MMFaCVWm1TPY+F#SEqVM^uFG?!V_Dt}^I7Bp=U1 zY!#UAU;SM}taPI~p0;8;Tmn|?tJ5k0MoLj_W6KUuTe1T5%n+;L3Mdb+SE*UaD&oFA zXhz&J?$SI7P5MPvaBR&|(|4$-=Vlnqn6CQ}OVPc=TwbzFe}dZ8WrA zliFymPwBiGL24q&S;8<(R6Y}(VW6mLr;E!!AV}h|hRBG3;Z)13Lx)Wvt_~fhAi@_) zhSm-zGwv!8uU{lEroa?L_uBN6N2!hO#t`~5K!IpJ+*9`fYWvl|% zw+zDkB@ASfR1RVn4s@`9#0YW;D>6A<0f`y3dbJeX2UfxR4LOC@XjEK zQ>3g(KYnKFi6nOWt46|C65@*mi%nGcG{hH&y0tsOCT)G9+g$eDhCaUYVrVP|AS*dG zfjkeBEtgeDCd=aXR)4PplN4vp78ClqP-GhZJj}}_#R!Zy2I|h6`xbT!vuFwNvR36- z9jZm|UAtkBUmduK zw}Ya}G@rM3q~{@SinPa05YtxS15o+lL?M0wHMa~#=_tYei*XZ1o-u&pUZIA5e=W`_ z$ehymQ=P9z+G&(lIjom~o6f=E&0>}6ENM;vnGkc|Q@nF#c-1am?W<_d{%*W2#vCBRgTd20#0*lHIpHoL1k*S4518qu~t zPd51QN{`G>d0`;0@TxawDtt{Os}iW`Ve&gHrW=BAbiDxUJFYTmb&b`oIQ&dZOb?yB zK!C-imx93LK{-?HA>5AY-W$Bf;M@Kb>OT|{n&+ZJu$tbF z#@=8L3~>m@a1C>Wpf^Sa9k$Ef}Ajt)B>-E{B@k35VIqM`6dJR8{~# zJ3wMjarcV&$iE+H`Uj-lfOI*a*3eLb;A3UTmO`59el5fUk3hXdouYzBmcKOg-`h^o zL)0NmB~1VA`g7q&rq zaTx9E1N>V-ZQzbys`Bm$OyLfCKZhwgQR9y|P2qYkF*RRMl)e)jN`^8=6u!`=y70{I zaF2`;V{trsOTjjJ2)av7&`vTeI<}l}$6ojy9j6)}#zsy8yGoH4NWNf8N`-*h`urudb8>HgC3*Nq1K-_&FIs%)#aQ?H1y9*WDr#l+F#7H-{K_k($2`C}TB@~uVna`P zMdiccC;#NIo074T1W*O@P*9ouzw!*cuXFU+)SxhDck5b6G+UdqJ?yoPD)k+#-p_jy zBdpk&c=kf9{N4!&r{V)`ccT6I&+fpV^rhW}0_!EMnQ_#To-?q2~gF z9}ir#UiGkcg+R#iS_Qo0<7e+Q$Nol_U4w!Yj6gP=J=fjGz5&L$~RhAvCcs1_V z=W@WN1>0}rR7L43U5C%5(WDpa{ZfUa=)paVeY&_vSSt^1bKUQHH%?I*JPDs&eu*D> zBgPDzy@w!PBwVW=vD$|*#S%`B5vA^@2EIEV{Pz<-+eW%x=x!RBD*{-PqDjYq%j!h2gPJm~~(wXob^Uf*Bsh^H!Fc>i6-6Fz%(hOkd z3Uw!RtZ?RCOITtz1nT_ON8=a6WPB6DXBXINae_9#Gwfw`+ez`0ySKZ5Ei;*}XFXo4 zxLJxAy1W?eBkt-u-`>L4W0e@lMOuadY7<9J>Vp6R%Hk&VJq1JY1TGf*Ck2~yPac;V zuB8yZ!Dxu;xEA>weY4>?HjGV6^C=@FN4j>^+8Wf#Ed9dzo6?>T)!0zB#+C_KeQyLbUK)$ zjdi6+ddPPR+rus}m&&V9JGAA!-0_B8hQnLR>L}X=Xx_|U49qc4WRPfwn2}iaGi4`R zLs(|a{oE>JdMohe4e~NnQi^((^Yk#;RyfROVN9DTn0nUG+=IOvVZ>hM5NvbZH0rYD z1!G0jnJ?j|SY?(`xw+T4#~ei| zW1o~6_dM}1x7ArNBwJ9Zp?CQZD3O_J<7&PMzrm{d8wyBkFzNvnp(5;nJTr!-~LMGXflV@w;`7kniARL zetU{K^@ywy9I>1evORj8?^I{cZ}%m!<(|Z==3mor%r%B0{=q22C2WgQ(|fw*Ls9RA zm3=h+a<}POyOHFnR*_GuB$v6MylUxUq#Cb8&vPP^Uv~zFY5lxXPG91Tj_C(}GN8*RFRi?cfgI5> zJZMwLB#uoLf8w%vO%ZNyW>|JYQOenn<8!P`ODXe!D5Q(u(s6%oEPY=!Zij|_@mRMZ zr;V~!_CUi4A;Vw;Wj>(HiK$_y?P1Elcwd1gEA2OFi?u7MaER1sNSBG&XtfA0H@7uW+n1Pjz_k)c=YQ^vxEzITtr5B%+~q&txg3iPjoEaP8uSkH^d*J~@BlhnhBPo=2U zEk%NLv71zOf4;45Py&8Fp?@kwjG0}$VWj{O!8UOSQ8OxwY#uMCEQG~cTM zy;UdkYFWztRInqnv-o71L8R?WE-GI0F$DAAF3T9SFjhzThTqnD)agzop?m6C;W}4h zIH@LD{0{Co=xK8B93?T45>LhTnc!l0P7+|@oTiRVsN;W> z5h@AJ$6)i;v1yw1iXug}zcQsldTe@Gb7c`DcqG)h{K{5Bug8@dU*nm)s;B$5Fce2R zRn*oI%xRiAJd`!)v4bKb^@Vos5lXLfd~Gu|c6tK(7=oJ z{^R{rXH%RaOxjeP*}gR|2cgoYF<4iP&2v+$w#J5Xl`5OY3t|6msk14JmaDWW9$QbH z%_*UERN6G2Q@Efbrj>4|)~=VJBb8X~9KtNMqq?_H83gMZFb71f!>Rl}U94wiG9YRN zWZwTeJxoVl49x40m`U<{Co=WE&kp_|r6f8!HU!gz5qk-nWySXwJg0Y+xFp=OgEy+p zVqwm@KUgsDlggOM3$X9tWhT_=Ig|iy4`Xf~3U5OBQfe!0c>1R~&$KRq9@i8A5jZd- zV9_QN%6?{enEfOu%iyW?f~MvGTnC>0?gN}nF}s(3Ws93|)+GIUQc_DJazq%qN@k#~ z!um5s4tc5{KL^e^CY#cYb~Jl*KE`|8f;?>(Q?x;{!+-Pa95sABBe-_I=-ud-RtdFc zN;4&@QO)3&R+-zm99+pL+zyW!EO}2`tNErSpq-Oz`4)rL(^wQ}c|bTATg^4?1QsfC z>#0<8%wD8{-fDE}aR%zLaWQt1(nq7N{E>K~mb_*3_0yWyQtN)Tyc0^xT4yAbPGuBG znGqe`3=CRnn5XXa2pcc;YF>(r<9OVZ{2_h&smK<*8W@>Bl~}W-)7iE?-}0 zGxl(g)?i2gW-y;^4vfKOLV})wQPBc8T!2MSIq9r>~%hH)J6(eJ8j>WHw(Z8Ib+YZ4< zw;k1_yuAAYgo{ORfHH<~G3f3&0*lycsG?RXW%fH2|IfA2 zDktOS@BXRU;bx^R%XfLvx<91JUx*L%rS_6ZUsKgE`){7nIr=3|L@lGPRy|8w`K)+% z)idCh&zz2y92%~Ak{;!gXG=8fS(sH%LyLTx8J~JjIzMemKyUELvF6O1X|$)t`g^0T zQKM|rYIz`qKk(pg?E$Fz`JG|>u2e%id3c(lK8 z%k|;O)=6LW?8)X?j@)X$oYHONH*Qw8%hCARV?iz7#WxsU8g!z{Q{+NIKjc(fKe$ZF zxc6EP80gMEVX#ihBGV9Qo3js7Q0?5;OUIOI$w`}pD*c!}p2O8p;g?s2kOqB9KsGM> z^}V(!gdSR;UB9Q=>6X@eaDacT*vsb!-R~*Ww5@fDNP2qxJ}AZX-N)VD$KLbk4wFss zIciN6RXJc>9@Nf5Bouu){1$C0H}!$AiOB$pXDDV7b@}7_vT3DkMi8OVAp-X z1Foe@RT`$sk&xnBL(BE{H-1(@uo5AZz*>sUPliG;SC@yUG}Y;jvDE4L9_kq5v0pEp z%=p}j9%KMJt$i|SVvN_NUys{zjsP34nsQRGuHTso4%HLm)$`OkX&I&L#vF1i0%v$* zYGjx9gSm&^F7`Z)zG14mwruf3GJ78eUe&PG;yG&m$V6#7w?OwGspDCki0(dgG zqLN?h;;7};Z7dDoE4`=Hy;v{t;kuTluXZGP$)Xt+6(E1@q8;R$2{m1HC4n?H>DapN z&`D5LAGq=p+TTl&`0Xs(~45){53qy1{&>igMF z2%7bL&}uVhco}(kmSnlcM5SpN9|LPUxYzNrmW631DAo2v6Hk(% z_cwlS3%i{b(|k$`yQXAj%zLjyncd?tFOXOriYYi@``EBm%LkfK*#y>m1I|Ig+HPPG z0kE)+MQwZS=~ETN#{-Ta{)q|86in{deTG4RNyMAjZ# zFMI1sTw19^TknsawHeP=&f4kRDLErwMogz|A5EuCXh7z(mXiHST`ei_^<#q`VH6*Y z&-3vyUBPw}Oixvqo(Nb^#Eiw1)cpHSHR!Y*AN9>+N}<6)@%?H_dW@3y`;rUIF5*Qf z!i9(U^mYd+es!=lJ?FRi`qi8-eIS14S=oDIO52_TowhTcN2JICeQU1I^AE?`yfbm7 zwK?lU1*;nB*?{+GK(tI9iU?2m8tbHQt6O^NwiWbvdFx~W*QM#BgBB8Hv2A0@PRUd~ z9@9^)Pq}(Lgbf-)qp_|8tlt{gdYl-ey^lEB+mPU+y+b;2V32AqH0PP$Hj|P^E1clt zz4wlyCDUnt6o0&eWQs47t6p!dlL1JrhL6l#^!sCMA0D(ARRMWKY?nvO;pY)^v^rWX zhqVs!Z{$$e)}v?q$Mq3@uKrG{KQR=JwVG`cShdVZ^7js_mKuuQdcN8OuUc++XY+nw z)slnfvL9Hr>@Xt0N6Xz^X z3(q++q~;C`mH`%QnZ!3Er$4ro=i*27>;$+ zcEqI9qrWb+T3+V)a$RV(#Mq;*X|-8TYneG2WvAIwU{;x6-Y4IADLQ~=9 zc@(K8H#L6VYK4gfrWy#KoIDntB~wbRGO2rGXp8M(UJ4wqge#_<>2qZ6460UBH}wPz zEn{HXKIC-B6eQ$Xsc_R1BhyM;pTHD+{`OZ=sb{cbxY8Vwx0<((MEgkPLm>75GQ+d-ETXQ5HU|p$W2J&u* zJHvxTLk*t})bLmHbqal+SPL6O>RccpD7+v*3nP{(=7Vd44p{-rD{bva&4yrCqmMnN zkjdNnqsU(g0nyuT{Oe=OFT-S&icOsB zd98Yno*ugAmfFmKMz{6ZQt{W+NE4)At1x^zszX`C)6TpdG=@D^{c+A?Vc@($ie`E7 zG!siNM|wKU>*es*c;Nus*~2yG1aG(u^T%W@o zQ}Q7*H;q?)R(x?QdZ1rp>QBp!b&{&IrtsSiZhkZJbL#t=4*I=ZGs+c`yjUh}JM1FP z(-AI~PO~h+>xL!?wF6PlZ+l#hL=I_OJvZ)y&a6MK%>2Sra?TS=wbx=erHA{L*5$l* zJJ!0krMEl1-ZM_Fq*LZY`|r8RDr@*t!_U#m=XVDkNiZdUpm*0nl= zU6sN$X}0YMBw7A@zPlrxWG&2AMLiWy#|9o#Fo+jKMceANJavyR47l-nqn((kn8Qrh zj}3Df_zO7ca5?oUbzgc+H=$9D)%0)HKpaf3k3~=3|bjDkS_Rg5mU+U4>)MFD1LKEn+TRT9s(1PIRdLKa(n! z@>&PuSxTeLTf$aj@&pwK{Dso0(1g$GM2srcrT-H{TkmO1d(DbIYHRApn$d{``N>e< zA$%JtWFQYWsb<~SrT$w+$1!$2Hb;U2tzH+rnm>?9RkqetSAA?Nk7F8{LyT|ogKC)B z8CK~K`>^I9B1gP7(rRl0(Q|95PdGtmfP#qJKghM%L2Mry6`-P^8vx7g@A z!?)^aiNWABWX=)HGATAKkyoBG|D-)=Ij_~XtByQEXbBR3q97wU9jnovArsvA|#dvTsFU4S6b11nVDlp=Br?OcDCEn3(qku#?k zBb|L6QKf4E(>(rUX) z>f#*BS#?@h1|3C0Qd2@q`d18xkzyYkQZ(~>4DZDKQgzc$E>li+6qhGyuf|MVzEwzX z;<%IHy8v#1OM-1x$|Lc%sT*izjvFV;dxA+tv}$xv-wuN*E#? z>-JfzChnV~oPZelG^W{lOZ%jcd8ECr z5m5j0T_2duz2Lwr;-HMu^azezz44+Hn;Lyf9j+5LqgdUi(=i&k7`f#-tHidQ`UvG_ zNSA^eH+>#H_w#24r4PiKx~p-ZRl~R(+(qv;gK)Egz=krnhi&~ggTZJUi=Cl;O#3t@ zV_6n&o4e9If|rpj%Xo5>@7W7?%Lz=)Vd?MN_k9Q1zIEmPf@&yxB-~rMsp!zTWxg`B zrq(h|)+VI5lVldw1ddvzF*N!%cSpiKI5*&gZK@Z)%iuy$`e0Yn0UoU>WI^L{2bil5 zXwh0%E}u^)ux#za9EHZq4oxjuBYfb^W^y^lI&MneFxg7Y1K-A?<{`Kp`qp{}`ljxD z_re_$UHMCq5K#Hgnykl!-TXug&j`vNGsChj4&NqcvIs;wwivmRbQaPCJdt`C;_)spcJ9O5+ zPcH5`5ygUra&mEhI~pvz@;&b@_aE(e=G_I$_g43w2zc4jqtTaai~dk9ZMcsNdkE&; zCx?3}*K8LmQKqjTI;RNhlnt6+)jfDKPAK5etJX-929|Kk79p?Fj>tE=OQLT`jeOF14l37=V`|L4Khxvv?r4Z>G zyenT7k>5B~O7QYU8ZOq*KF)XTW9_8Enl_+cE$v|f3?7iU`z zN*ft9CEkqXelRpI3qDCdB*3v&iy<;XO%V6$^}r(5kFxC-O>(Wre57080CrP?~`h3LJ~sj}a<8mXu~N;D_(VJS}g$Q7sGrfl7&^f|O; z>`1<<)#C$R=Irl&s?t-%(=waMF^v!QmN;R0G;1F(wP&5ySvPrjIa+~YE?&**NswT(`m>ILvhQi4zgS zA~&BZa{JGQdLcaU%q2-8?{ulEJmz-2V}Z|nB9cJs*XRiX3^A8nsSDJl-eHuvee9AI z*>y{d2ITR0z%)2Uw?knn=uw!(`DHan;_8>Q;|fIx!xE-wK^S@?v?Gi<-?k~5Bk&t{`ObWVV@7SR*fPYRXew-Ph%n8(4iSXYvyfo+kM=nU%i-KV!JLAEBlGUDdv~?-fY$j zaS656+MQRJ-`~C=Mc>_5zMl>$(S(Cv8a|~771$t6Ij`Mnl{(m39*FD?i7%2IeH~h# zK2Y%7>qhWH<2pEDQqeo+p_}`+Fq?1Wo38V>)~C|!({d=CS_M0IBJa<<4F-|fQ!P-K zTZpt1v%^n?%XE1tA(=Lwn=Lz94V2Y(UUr>adltPT&h2t zv^j2Ts->DLb!*@?{h8|_qJ#)z2Kj|51`6lAc+Em^EY3|sS3q-mfKfYnrr;cZ8uAns z-O{q4tL8KHq#Y;v(QkoWw^h@T_V(8nVa_Ltl4CyPv4H2fe)2ocU~0rHMf(fkFq?Ic z%!5qBL8jVY)X0~!T#%A&7}Bb&kq+Nq#0rLXYIx=)j{ z*3(x8+Mxf{J94FH)XgaN-UYn&O@BMXcv0yz9xLW0g##H{_%(T@c0iGbb^E1lC*Z)# zVcjmq_s%e0pNJM-nZW|C9rL`Xk=1A!`T;w4XPE98JS;h|FK}VdG*q^EUxD@e1Xly? z>4Edm70hOeuUWd1xJ_dNKaYEOW|$q5qs;2;S0={@uI1S)!C^?FmWAGkGp%fF2X4%C zzcC2~ZUsvFOg+j|`~jEp6f6HzXSXoU4DD{lt;b_7WeT6{1DMvYq}mP%%~a1ASLUOq zAl5zH947Nd^q&BRt(5P^5uD6u_>F$zY^RqMvQ6P+)93k!PYsX<+C>oe{EjYJftpCV5>3 zOWRAqH<#lnc;<3g|6{{AYiR`|hgDl&_By`Ei3Qg_7Q9IBl{nqM_BgTNZFB^S zw%Ez$X8hOK)G|NSL-Y3Pr^V&)5`Kr^PeC-FuLF@#9X?`N3EYim=7hl%Y)eB+w^Q*n zeFv)>6H-J4kGST1jQ7RhgH}VWZ_!UIbal%SwJz8RKGzcLDg8xlkZ_R}hYvIrA=z4& zqfRa)0e_|TZ0ixnTRAh-1TkLMgFc)1z9&O-3fJkeoc2J^#Yhq*imKA&q(PBHkEtdD zB!}`_ohYp1ls57jCu^KK*{lj2i@^Ak9CwOGHItcyITEAvdPx<-pLkxc$Njae`)K|R z=9%ziGRA#(ie6glcHp3qe=#u1s?OdA;48Ikrwe@L52r`!oBeU8X&tMB}Mvhd*; zlBEefLNqvr)=$;2z5nI-eL=@(>WpIWeovOYl>QuTqR|B%`+uh3R4jpRQv;j({6)|B6gx{emyp7V!i^UR>JGU ztA}|$8GAagy%J2q>%w6MC1PKQB&vR0U;J_}c!TiKNXMe&R7$8+pr7zwP=~@H(f&{$ z3+GF9B-5?!7qT#gGN@}MgX#UfYz=p~ZOtOJY#%Ga$5h4qLP*D{Q8`*L=!=7!gb|02 zFs`IoaUF2=(zuNGp91nu@TV3?fh+D-nmVuQcM92txF1(NgV9tu@|3`${KtyF?kQ5D zB&Px~@Nm&`ZCoFUcC>Qa0ys6BBS=usyrXIrJ+lgvmL~063fJA+DygTIQD!6r8I^iY zJTWviG~(Qe?nv!0ru&0&70RlR7`nUi#Ko`6d+I6!@eI$iPcm+oocMZAFGe4#;x?X* z5qK`rJj-_XsyPqWvi_)txy#LXXNTG?%DOSb5a(*$E)*J52JV3)kp)X(jSG6^@Pstp3j_>wP8}K{8^-qeCD)t|8KdmvqQ-jLcux!hvJ0x0bO! zH~hK~qqH5gAYFMWf)KBi=B~?eO=E0LyT8d1Q@eJ)Da=I*ax+kC#pSj;D~S40?o&cj z+EZymf;4OwBaK9HjHVK&Vi9s=+K@pU;_~7;DU1e@n>9Du?O3_DXyoyPkCSz6m57#@ z)}BDES85%t;9EBB6VW#Zz%34PVq59uoX*r&w+9@@k_C6C?sK0~W19n)Yq(s9)8bcS zw*0s3CADr&!f9j~%hXomeodYENa=qrAR2QTei^!*jcrMG!cABuTll1aIL>;6)L6Ud zXs8f`n+LQ)uMQks};sw94R95P>kY{YOZG&_=wtX%I z=Dqq-&nW#=Pa2||u{3H!sW6V^Th;bx%%6C0?Gz-?&^4y>vCuypp^?Umlf5rXI|_c5 z>2<1-r`k1szIV<`o43ie2i1C8V-9NZW7(NvF{oAhMQ)a- zT1H%rj!p3Uyq}LP0~D)~fW%|hrt{p>;*+p@E^0lczKT>(_}gDe+g?{gDq3MQ@d~C# z1t|cZ^iopyu4i$xZFFW^ecI<*vIpF|DXx39lbc|ep3iDr%^62Rd%`QP4k_qEt6%RbC!ELHtkZ-#6o^gO^(Rh*lqCNBJ zY4_|O_0O5auiIEZF-@>N-~08G(k;e7eX1EFtE=`tJLoAw>ZutNI6Fg_LDktfu?^D$ zk$KxXEhXjcmun}*tlsC-+ed@W^R9Ni0MqZG%_g*9i+cp^)b1+I);TeCqBF@{Nu4*Y;O9{c(nbIPZ%yDE1i>7=?W!hP{ zLYDeYye(M{rdqD)-30}Go}lrw8s({}mvJ~nLNePpwDrzG%L@V~tDZt}J9$5Jty`N) zV$%XtKR#4>iT*7e6P}^9-{-%UmpHf_9ynrR}LoH{&$!Mcd2z#R?7{ z-CE+{?GSJ%EI&>hj9bY5E2W|SPeCONjVhJ0`Zq) zJb9k`6u^sGE!H_6$k}{fTRqz+5CoII{gn)!>u{YhN{eKDnYdV!a^{o8LO|J92F_$n zjV49Y->aWpzBu&ypo{P|4Lz~P3hxC^g?o(2CRn~6p?1=Tw);R^7~;d+8FZ#!Jnu1_ z#}&OnwP(^L?bBYdJ-#u%Ji)8z*QKzv-J1h%e3LoMJ-Nz+KKgsw*UC5r*=xO?wvX@* z0VTFj?;jM0!|78#kvU-OH^PCIkFg%zjNdeVtT33PL)(HdZR4_5mLC~3*K#SbR>#Yq z^4yOuB=_B&{J`1A;~Z1E6j~e~UIW}qJUmI9sXeUp60Ry3#TCF9Iv7>KJ3$yumeeF7 z$w1wRyV}qQrK@fE3`ZfWov?hP3xq*E*KbmBT?0Q@1Y&n;lwsh$ojZ{$ml~j3YE{$or!EAS{V%ZzP<0O@|dx$YfD2%mC z=#yJNIVhNfHiiLSm2%P4T|S_E*Jc7O7|GhLf-%C{MKJAun@iGFJ&9K-OT~_B2c>rI zEtc!4qH}{kS}P=W6nJ^amYGh@JW=AxRYX=+?URF;C`KT%XV6Ikqw?jGlXdfRM2Y>T zN_pS<3K0A@SAMn4BvoyX#GIBQs~)b(E|~(gm(s&*MZ!wZS;S99F_#rIt>sahpUak{ zwv92FDjQ8qDzKD>xA;x%zzi0bo3Y}IdP`Xws>t3^EgNlokB6}=+ITo(tZ5UlQ#d23 zp}vzv044@s{m<4>!EN6S`&c|>?AroXJ%fzl>!ke3izH5R?9X(xX*xGz?Hbd0inXg@ z+je{2KWG{zWktWXb(KI(_geW3IQfmBGcH`MJ?@8reIrKWQ=?HvU!((|=+Uzot+wXc zSXZ}Wof6&}<(4w=p!wfi!S{S_2Q1+>>2pT8%`_%e$xrSM_nChs1>-zvogve{sAvH+ zvT(6W;3-}gSKImQO}yIUZ+|5@e#-dQ^f#B-ZebDWYeJwmt>M?brXx}ecijyu%9^ZO zvr$t%ky@Y~akqr6>GhT}hV_$p5m}01t7A<=ypwnLYt5GTNY+C4C?J~8L1eF%$>v;t zdi_BzfSuIq&+1-U!Z#T;X<2BfzJk=AB;)Z@(PJ{o>{EXzT2KLd zTzESAaW~>cSQ=rhE}aPwEP0TY%T-)RgjaPj(TxQ>JoE@1LeIR21a#~(AelVLo=x7F z#bHmi&#=@NDpLgF8*n^|3eWegA>K56Cu%HEk4zLOaf5P$$q{G}pqAdXzZ0aq6ph`D z!9>54l^mDZGi#_NPV_G2ydqXTXfWBO0cVd#zSc^LUXxb0qbV)a1^?V4J0}np<5!bK zL9U3xQVAycA(K29`=Lse$k$?UZJFV(rv|bi50s~54%g4tq^9Jif5HU@6Np|JXe}nA zS7r?JS8c2cZ*I3&cMd+FF3MR<3@F)CJx8l zz`YrF7kv3rQ_S2@`2ha_o?Q;GoUGy{fyKCJ-a+@n*6_aGO^{a(2RzM^7#fQUSl6v6 z(ft)UJ5;U?4N+wUIkav8M5y%#CG~?T36Q!~dI%7yz}K5Itp9nXI#c>A{==T-0s?VH zt*h+AfJU2qfDRJm&!kd18=Z93Cco(XVlXe16Y>h6WQt3lstKW9etRv4Z6_A(_1YOy zt!$MlG(sY6)*&&J(vxwy9%R5NW1AHS&|YIWlYA!LouC3^N4R0PtJ2_B?LDvqYv@{Z zoWPsq%V^jZ=L2izd{7qwtu?DOm}C6K&`99U#qEb;n$-#q{yka*QDz&S$Nh6sy6AfO zz@E8hAChN>$CMEmZX(T&TgHf78ZJIG`ddl=@XQm#=pfkjz13YRsQ+&MEyz5H2Vf#P z+hVHZx4JJssXPgPUL5$4DNm-y@Djx5(x!H-ss~6oic9gW>JKek51-=2U~UM#_Cs=6 z(Pe1k=0ODQ#ei$?HQV!W4x>f&?dvri5V21WySeyDSjR?!Mk=DA%w7m-Q1Xc;ky4tf z8Zm|Y1TzbRAQ@Kkjj0DtM`Jqy3&v*~9sa5thQ1(F%WPu2a`B;XY>|=If=ZgYa%xk@ zbj=1{0S#MDAcR`i%CB^7lzC?Z7ZFLpua4PrMk6APy)0pQuiK{c4oc@|M6Seq$fa0Y zs|4e7gMNK%QL=|80B@sNg58_&t@K&1gKTkU1ARa{A(o|9K6FxPFv2@Q{Mi@#JcE2`0yiBB&Z_YR*{uT9}& zU2!jxj#|rA>seM>v(rbbLwycC%Dbq~MZ#R~A^-81i{=gFyK%+RW64EgluDLy)eJd$ z8XcHC*FwA!Wz0VjS2M`Nj$7kvj7*b0btky|?XP5VCzE<SV%CJ3Kofghs zXAAVKO_60w(p7?@RWuJpQNd%e>gAzGTk$*l0Gz#GOFSvtOl)P_s!bo)*Imn#eszzq z2ZGLDQptFy>J6#5gY8w?nKu@F^Z2#Wy-GW^+GySJlg6CyDXG)>s|Po_%jmGa?O4Cp zxSz;BedF_F*hqbzjNeZTd~3P<-pZWIgGK4B59ycR@+)(gm1)x#a_cV+?uzGZYNOM~ zAFyx6M~-sjI9k+mqm6V0`n;%uzf~^(cNZ@dg2iS&95^49$!uXXBib z>b!(a;R3FHd!AONVK5HwTfq20968=qox=NqVKIveWw{r6bKm=h?Oq5gIpX-~;XcQW z9~jP4>+rsSNq#M#{y^Yb_k4N4;ove|27ckHULAq~O>ERWM_44BHK#4!!4%3>bs8Hk zQv%XCoa}v_6-d``9Bc?Hu(=Qh32N26J&#ollPAU>IpdkD)!h9$5X}=k%sKa7!E2k%W*E6z)7*|4)>gDWThW4pZRL^lOxQ=J~xJ$JmEulNH3BCPB6Ni`Yq_aW}r7r#-Q1m zvXCanUXfHpvzoqI)dDx91{n8_C))8Cm-?ohCRLL9dcj@YTVS?UcHXK^X&2esY3cmH zK*>ymw*70{K`#@)_B33^1ugYVn@wq=x1}$qiEXducr^y6BiV4OV4d7s&+S`kru)`X zV_841N7yWjr^zu&^$Dc={*O6kuQYjVBo$*m={+ZCL*anrMboFUfFzGdwQ4oz*n6>; z*{4QCA^!GPGC0gM#8_6B(bTl_7}-~tlAml1>1-1yF_GxhGxKS; zp1Z|OmnNpadVaZoG_j7D>e&-BJ$~;Hf5nvH)-SzhYwIt*=U&vUF%gSzq&I0~6%dx5 zvJK6ods&I>=P>t~H3qoj{rtZ7&QdtBX8GC0!N*|YM^lY`8C>f5J%K+TU=OTR?sQO0 z6*qW=vV-0Vr`G;CAx8Z^<#SB|MqR4`9oGku#2^RGa8WXZF|5mJsH{NAObpp>+(_zw z4@HNk1~W!A2kmMPG=)eiXxnJi&juZ}w!r|AN?FZ~0JW?vN0Los>Li1U%-j?qUtc;n zOEH+-lHiGx&kTIPsQS#B%svGSHyIVhpm@LHHNovhd=Cygz59V5Znk(O6qJHls9J$*%JzG8(@Pkd+0|Of|Y!5W|@%-{TJ**z?>F;NQ z0=z(wRky%v)&98k+krcG3g?@Fzn;^Xb=y1^^w7o#wE1j&++(Mq^}=S_XPllNdQY27 zF|5~0-`{78UO8PLlBC%Qy24Q?Q^ZyNCn*6P>-9&sV{(I0qFwXA@<|M+GX5Yir(=CHpHG1NiQZmRD{h_Q}2YJPolN%MsU}mpXn~nr!P5X zZO^8AB}aBXS=!^2wH3%D^QL%Qs5YniGU-K)$a;N9odOk5#wm$41}IZ}5QQzw+^Qap zKwC;&R~Q%Uj$ZbNX;uA&^^mzZOTcM2_iJ1S>x7Y7N;(udV4Pdc#~JX&WA~`pmyj`9 zMNeVB4sNwpTTan2*ClpLBxy8EH&T4qgM2Am%VX^kl1gey%NV4w_tSGQ>p5i|YE1Le zvYw|jwJm1<_9jg&w3@T^9taXC*>>Wc?ec4HZ6~x4Z@36sD` zNp10Jk9Nae9SrZHkKtatKW(M39&fHQBCS8!%2=zl>O1#}5t_W-5Ess4G}ggX+@CQ; z%S*zX(bnoUT9M_+NYmq9_he2g*1_mtq-UjMf=&WRKVq}47?a;tlgj!b##8; zfq2`y1Ic$?hi0|6HOCE#_VAfJaa>pZ)}zQ9b87Fvx{T*iOTioK;HE7NSz-xPNt|1& zxvl1zcMf;f9^a;x>A|&d+l&0`MYHnTzMFa;FBkk-*DIag>UqViEjM!nM_-L+iBgc} z)qcX1M0%2R)fi2U^m=@gQ{l$c+_Rp(Hg76gpQgjbwP}FFdfPqmA`udvg{7lj_doVk zGI1vRZtTW*<(VnkS(ELJCf<_sM`o#D$c`(kh)z7X=HO&Hmk#hKW8ODV- z>w>A;tf^(_b9k)g+#3HHZ^v=jbJjkJhMKe`3pK?j>4O+MOZC)u()G78pNut2j^a90 zLaz4CAPB!f)`=Zalq<#__C2_~=qcQWrmlOCSNAps znyInvWDgZ&gTJ2V5La36^d*{VmB0O!ET_zJ$X+ST7E9NT&yW6xB2npR;Y#IA?!*d{3;2Z$dDxCjuj8M44;j z9NK4$>*b)pJdWrtM^AGze^7OEET!E~%#P@Kt=i6J?|b?^zA^oz|DfLEv)IY|WY;%r z02b&}L_=3&NgHp1Bnyo7bey*u%gyO`Y|wkmWP>U7I49$;K3a3E%_Mb2+b&uw{?=V@ zd?_-ZM5Slr`&vY)r-L?AA6r5AI~PaD18g~{uTmt(UDp{&hp-Lyh4?%d%RQ-i*^b}m zqxI(^PTnpRFlPd@Gx1yakg09sNsh=a{MKCY+|!BC*@-c_5}(UK6=*XxS{^B~E}6NI z2QW2y9xuj-iqhO4pV3X9vwnZ%PPBb0aJd>|wj0@u=VAoU2UZti>~@D=mxfUT7v(L+ zTS&THSF@5qVzCoG5S}|RJGM+dlV&}gIb-=P+3+_S%QVHe%gzxgP+P%#jk5jIy+tyR zk;@?^+LdHykd~`K1NJ6y8=^ckCaxC6l@HNgKV%=sj=HK_dX)xIzB5(gwdj6X?_5I)%^!*!uPT%kQ@AZA< zQ~G}G<#N4z|NJc-|1f*^#=oz8M&I8m@P6dK)$yzUjlRGBr}e%2XY~EIKB@0>1>S?@ z`%w9QU->@zCv@M@&x-P2Dc@iElLcP6@9Uq{@voQbzgfN?{F8d_^>Y7DmgCdq`)AAd zTRyMnzxH40`wRbtp1WS~{L)YBy#M~T_`x0DDA&J!S64n)zJI-(*Iip%zwj4y{mb3= zm;Ps+|IPnN-(M-$f4O{rwS0fAdro&R`z!qC+Wk&}_m=spDo9Kz8v5E!0#OJ|6)1* ze7XLM<@kr*rt4oW$A6(*|4KRjis6^`{zp&K-WKBjz3b4Z;JkOzvV?8|J!o>j_W$!`on7Pm#^sf zca`I}zO3U5zfad6EXO}pj<1yC&z9rY%kj^Z<1d!u|DhazwH$xB9DlnU|DAID_E*&2 zH_Gt`%kjS{$FG*-x4upIe4!lwk#hW%a{OdD{$@FTN9oTGyjuEGj!%~3SIhCo%kh6# zj(@h$_ZQ0X_49iEi|-fzf9F{p|5CaB<#PQi<@oNluK#j5{>^gz>*e^{g&(dIc|BS9 z?KghE`givudj8*)<8xPa{LS+Gw=6H^_!oad*Z)m9{*7|{opSuakLvolyMq6#1>Wy? zhmJpAuK#E`et1XsKU0o>tsMXUa{RenU4N<^AHAmI>!m**EcpF&x&FbA>H6(*{Hs5v zV`<_1`%m8`eDaKbiRyXQ#}91l{zuC9+46n0e1BhQ=IvWp=&h}Hl<(i>^FOHbzxw~_ z#P^r;|N8rN{>$b5a=7)yAL!11zi|4sw{+*-;x=dw0Hc`(zLQckBLd z{qFAmx9a@Ie@}P*_vrk|-`k!4L7o5NTf6hWSLd(v_^_fe{(Za0|3A|C)4#KW^FuoS z<^KGCtn=UeUG4pEDRh3VqjMqS*7c5_Zz*){@e%a-zptMYr*w- z&;P*I+x7fcbp35xe{eYdLb?BKTYtDY9uBHMAO8b|VXJfZ;^%I`*Znko=Gt<9=dORN z^w-x-Pt(oxHXTea-@oen9b5nD)*spWqg#iz{#Yb(-?{Z8u_EnVvB$~LIREbWUw{7S zDqwN_?O!kB_Yd^#M}EGXUmSmlA`G4>DX1}{ML`fl@G=L{Cv=j$M?to zh7|L;e<6iyct6sex12xFoqt<__1W(Hp>qDe?#`FfvtMVs`!~gB7I3-n;5~-_L-z>& zlYdp?^kDh^_@C18^>X}QmhWFF-#_#fUH_@_{TIsjKQG^h{#RW$z25dublmg7+3vjW zpZosWlf_Q_7y(wp~lf+3vjU)%EUtaW}U9Y&rk!f2wxfyI(2i zpZI4wZ!7k1%lSY5HJ$%~(xKD8rYDbnL+6WIvGuuf{@Z_F=Ra5O|9UxZy3NtW=Rf}s z+y0ur|8jTU^!a9Y-t^fj^mMzX&mZZ|n?4`t&YM0jcjrx?pYP7QzhCXnyI*tP-}$;) z`r_Xe-Q3?pUBBGl4|M0+^2+neM#XeXTohI{!j<-uQgAJMVVq zzQ6nrrpNso-Fd@*>xS_E+~1pq|5v*6?(f&T^X~6&bmz@i@A~_K{{ux{%vYz&dDB^U zZEd~Uoi|_o>F&Jc?u*@d%iaG`&R;3*7Po!tEgjuT7_s%ia{inDyp_|>clXbYlh6O$ z*VL156+K}7`BFLmbN^ECP0z2E^QMF8xmD=-0|g(`^Q|47P0t_e&YK@T-kmp|bKifu z*r6}{?N;u-@ORa(L;rV+|1XvEpDX8$|5wZTZUCD!)vzl!2)RaZ?wV??M}AfJo9{kS z&i~^7-`@Gax>cTM{EVfyZgxpsnr0qLGn3v1ld{BRcbUr~Weh;~&WaHAGS+!C%d7|?t3uJSudjXV>wn8Av$81iP{ur#A}h-x3uVZo5wcK(EEFLN zA-4CN?|D-EHCG0$)w;<@9bez@6J=)}dJgv3E6UD1bPo3DPnDf{ zs1JMM-;|wsX!Sp+8MI(mcMZb}d**_&@brH_?9G2yc6@AMBw$ZpRQ6B8(KYsia}D)A zggu44g^x3g?Wf_N|5W|p;|${j?ACuMJ3h`ZUV*&}`+s5F)gLjQR?^ioA5vG|7u3A( z!gT>x6W8;&uKO`|{O{G(jVpC|*DK1-{E)P0j9y{awu-gngAZ|0L`iG&{^IUMlC*x;)S~*VTfZe&f0>YIepge;(nwtn|dV zeNAi6xP4c%t63PvCT+cp+wHJ-&_CmLm)4$fdt9^AKc;41(J{Dj{9muX@6>k$=UeV? zTWila@cr*iKBlD?@cQ;d>8eLaTY|p9l-S& zTwA!lh3gH7Pxd?i&!c{%Uyf>a`lX}UnV+Wdb0qqaep%4$9CxKF_mBNh_xsO|&Xc-- zTC-F44b4v7U()Q<{nS5=_OHk=LYkere_FFs_j>=-{duiD>($zqM#p8ndQh{g=#`)M zYx8HlI-#{^y?R5lvtDh{_A!YK*?!~beEtmfIc?k{upid!e-68;*`I>_oM!(E*x%9Y zKY%@;`Ry-ZKdjkPEA;`!3CXbcO!^8unva`(v5k=atr*)7Hg#HZ;55pUw}zJi0FWA+On!c(AA0_5O7B z{^Rxg-=o<%{{_uXKc_W2{d`ihGp}CI>}nQ<@s4KK=d1G#|1vs%{l3o6f5f`8(&xl4 zYo8y}KSRw<|7>cF&XfL`)9m_ub=K#@bBwM-{W+aI+IuH;wMnz<&ykPgoRP=1i)$NK zw)?R2dV~(-gDYIWfp(nl3eAit+Ob=pHL5xvsZ0JJ+>V`+So+ zx)b({_WANYt^K%p?$*}D_0DN_FFJZev-@F>Y4#-S2Q@qQFxI_J4Jq zYOnq@jQ4S$^=s{Y>JHySH-cHW{9wL!-VbKIdKk?2%mZM)UnaqPuRIQB{8(Uqu5bp- z`gH-!&k^1Pvu?TYeJb@WA;Xvft8WPzMi8vNC1e-ZW#_*DPY^XzSk8826HpYgH|_Zg47z|`|W zF!h`RfBgGu#J9moeBixmvl@@{Vf=GG8$K~QpD38~ISF2c{w{&}{J8vbWVPy_>&bw* zo-&y8yK{qT&;H5u7n$=Tvwt%CC(~bKdL@nV82_iijQ`icjDOefs3#f!vtY*m0+{jt z44CnM3e5QLff@fddsY98|A)bh|KniB|7&2z|CU?S^Njz4V8;LRV8;JdFyr61Q9aN2 zkAoTiCYbU64w&&D{+xQA@&62%@!thA{@2f__T2Ar^`x*{wda1H19QKxfVtnRwR$p6 zuj|mB{a>0^%lb+G%-uWcp9L_-dkW0)egvj}9{f$-Q5k^y&-w5?!T1mE zQ0*E2F)-)zAeifa|I?~H=kq<>XTB-p=iMBS<8wTY&+(2tp!(x@88F9dfH__p%vD|n zf7tQX|K8|$0WhB*r;llzcR1gh!JO|VFy}j~osWWG?$;hL^?VRaJtx7`^D!{0jdx)t>$D1k=Aqz^avDw80#YdgFN1Bgb3&HT5LN^Mg6wLtu_~49xLPg1MhBgSnr5 zF!$3HR!?$2H-fpJb71c0lVGlAoIabM8ePvtFrVjs(;wV#`op8eKR>^wKm54Q{>IJc z{Mym^^uX+I0H%N62h+dPpHcrs|9Zgm?+lp!odwgsyTJ5s1WfJp!nDLSV^E{CO z^E_dJd7fy3d7d~6=6T{gnCF85nCFA{!SwIA`WnakBlWu-O#eQry>C7NrhhYF`u7Z& z{=Eq1`lmmsp5*$sfH_~r7xl&XqrMVa{@s02?L6n}15*z_Kzq*jSup2ofjQsPVCta* zrXDVXsfQt$dT`IGk*EhBnCly-ch^nodG5ze;A`sxbA7wOT;DvH>pKqS`d$EYeHXx7 z-#cKgZ_TGw&s<*!%=OKKxxR7vf%Smvy8-77u5T@v>)WQCM>cL&^Wk^_F!gc}OudxB z9Pa{{;|;(ZZ`~JE|Mce_VEXeRF#UNDOn*KLraw=C>CX#b`qPc`4*j_o%>2Rg5aZ_z z?lXR_fSErI{H~fg^G6NL{Ba4)_mQbBsy*LFLSVj+B)}fL&mIRS@d4m@FkVNEsjc*! zs^HJxqnP`38qED_gIVvX54JxRP|vgdIWYJ4Z7}zD-Ir8*?(dyo?(d^u&e8;Pe_sW2 zf7jyo54gW!F!y&qnERUmbAO)&bAL~QxxZ~N_m|&y;{Lvh``q8DKU6d4{*t-BGq}(F z-3jLY&VjkVhrp~SPk~uaGGM-M=D~d5JOk$Y<~cCmH(v+yeRBxr`{tVMYCT>Ezz4ns zyd7+U?+0hW3t;MR&uY~l^)s%X>_z^jeqvxgKQ3PnzoN$D^V542Q-1+4^%n-KR)%o^ zO#K}OQ-5hN^_K%ve@!s;*8x+1SHaZZny;#nslVI7)ZcC}_4hq6^>+eH{jopluZjEA zUmr~U-E_YipZfEIslSK7)ZY_e>aPr@{?3A_zaE(S8-Tf=mO&F!gg3%<)cvIo?Gu^>YQx@yF@k?N&W;{5OzKIldS7IsPn| z{D;7d*AzI5c(uSe@Okiuoo@!`4bHa#=6qiPbG}!=oG(9r;CwxJUtqkIvHy&> z8Qf>Q-34a6JqTvJ9RxGpPJp?-aeDYw`@CyhygVBm)z8%3in$-NVD86BwC8@Lai9Bf z5%;+tt8kzDaR-?D5e0KUj)A!!r@`EhH^JPGaryl!&Y#qq-!rhF2P%pW@c`&*&-rK6?!~Pchig_NZ zfq8$NKM!l4FQmZKO9ssGnZMXS-v>GV1;i`QgFP*OUjef}{d}3j`GNgq!0hkvtXePq z)5Lww_ad14KLo3%3}YSs{uAzh0L=ZL19SfmfvN8#nEE~nroJm+>iZ0s^}QcZGhuz- zhM;+rTS-m4}n?V_kmg8kAPX0v;C>$W zkAQhTWj@7iBRr$lOMNH7)Z-~I_4qcJdh~u?Jx@J845l7aVAaYn&VZ@MA((nxze%;E z9>ZYj@ke0l@dB87Tz#v0o_d@GQ;++=)MFYXA%6lDXgG^7AkI`yg-Q^L*-Q3*Kj_r+F~-ddN`w z%lT)()N2b&y$-tQhU`V5$Q zJrAZ{r+;1bN4;(XQ?Cz$sn?@m>a_xW zgExUsf^P-C0rr92F4f;{;2?N2_$c^Ea2Nc2@D(uiJ1+iyRnFs>zEKFP^>hAb!HmDz z2h@GW-)=DDZ$FsN4{=`P^P6uTeSQwi=MRG!zb2UR+XjCe0W<(Je&&8#_0RapgBd?p z!Hl1s>s5Qk&oki9K%kew-dmN2c6?T~_ia`D1F#Ob^xskaBgteKHpDkdn zXD^uRiGjJEBVexQIGF2s0nGKh3g-NH{$@PrKfmVRQ^olO@&3p8@$akR{7&QZMb0mT z_MG1VFz3hjNzU&$?$h6=!1VW3F#SD)e9iO9`rlV0^SrVX%zV2C%zXP0nE5saHj!Ws zfwSPJ!8x!AUId>6=fM}iOW-Tu0(fehnr{(21Gd0Bz$I`LTn0Z0UIw24SHLfVtKci( z8hG6wsPXIIAh-cO0RCI>v*459Q{cY?Uj{!9UW51TAA;G_`3!69t z)uOUfG5d`ERLz+DPH6Q0(N`67T^xt&AWyCn4@^8T@xa6b6Aw&0F!8{|0}~HSJTURV z!~+u#Ogu30z{CR+4@^8T@xa6b6Aw&0F!8{|0}~HSJTURV!~+u#Ogu30z{CR+4@^8T z@xa6b6Aw&0F!8{|0}~HSJTURV!~_3#Jz#%#{h<82{+=71fA8P%MgF>%v#70q`rU(% zZ~e|=hqiuu|KoRT-SH=n&F|m(_1L%P=eO>?ch9|dfBoKX+;`7CvtQbJ_uYH%32mEI z_ri~VXY1YZ`21tv`sSg>zPo@2)MGpE-SNlwDa)4q^YhnpUGHPY?P5>XQ}uK`Q#b2Y zy-{!0TlIFmQ}5P$^?rR&AF5wN7<|kK*nOBT(`|Z8ujw=WX21-ZAv0`7%%~YN<7UE4 znkh4FW=zwx%!X+{FlEH#Pfx*D2oyqvNFi286jFsu!74Nh?LxQEFANK=qNnI928y9# zq!=qEim76zXce2qcClOR7l%cc<*|HLzzSIrD`q9El$Eh8t7)~ZuGLq+mf@ZPhi+Lwww$Z~aq-{ktJ<@o7+e85bX# zX4CALebdN#vi@u+8_g!N>8zD)WxLry)|K<-0=aN5mP_U`xkj#?>*a4VT=q zM?u-4xa^PV>`zB_$B@18S3;Gj`t_CIl(9$VYUI7rZ(u1TeI%ArOI9Iir7hEPl{_V1 zDNqWPBBfXE7tt+~6R27~w;?k8%^yCvQg=ED&Gm{M$qt4C; zWp9U0kI8bn>|IVRXJl8J%fpJR+N%z#A@OFU9u<$q>k0AdSQSU7jD$V+kEG$I*)o0E zVK$nJi?@e4*P=)K99V3NC;R!K_|mgvtJz)j7OBXg)hi7grFrdN3W`q|LAeALL$W*9 zQ@6XCtomvJ(M+Tk6V;?@F6fSsN?e8|GNTfkaf!~P#AjL})RY)) zNQ`zQN_*Bo_R=W1N^VhzS2W@mmBdPM(TF|cbSYCZOIE2->dD*(GJB)!aw63$u^K5y z%Q1=7L^&z(nl5J~X4?|8-EvRjc2FKl?7EiS62IPMpTuxrIVf=)UXDmC$Cl#~&q+~F zTJ&Q&aov>2ZZCHvx_irgC&G=2tKzPBB+h-J(?BICiVsV?M?w33htcN~AbjaSfrVWo2Dc7}}ZfA5mpWE5o&gHiDx)PrQ z(Vwk8TYCY~UN{@c#ct{N;E1&`Da zv(Rv=NT<+q>WCp##9s_LbtLN40n@1?El0VA=++~u4PIBTrc+T`l5+-*PCcShzmv(r zrKpq3l8#C((P*pGmKf_vgt^PMJ_Axq!lKfcXf!Db&4@l5QdQcbQCpj~GJT@Upi^Dq zqQ{gImv%O5IXblU=MnYU+KYaw-f5KY;N z>WQ9)q9$8Qwvuce+4`~7V{6A&PDgZOtH#!htr%M`QOTkS$)T21rk2#EJ}bZcKj`<^ zhZm>n+ciHTwcf7uc7?YyQePBd=Oa5C`9%>SQAAV}kq||sMG=-Lq9uyxiXsN02$v|r zD~br@f>Ob3Rm3H)rlgLUQpuW9%Q})}jYYTQ*?`oukYuTdPsdI6ubf#3grYOkPPhaYtv1Dgy?~-4tUP$VmQdDv&E!D4eO;f`q zSHWHIIwzH2A?%!0;*QE%a#HEYS;bb_z&WqDCENSt#1brqoij_^IdL?cGfT(Gly;tU zJLeX^qqvCV$GCHLvFoILdTBYC@uTQ%;AHjdYfjgjt+j~czqqK)bn2#3T3_;=tu|X} zA<1#J+R`6T+BlWj3j3hCB9fzQg;8Bp7V}V8YIIN4vEH=NlltOvRFo9`*tN_niiwL( zT9PYVk}JHDD+0NYXd^1xNQ*8k(M3yi(UnuqK(yg?>ThsF5e+%-P!-oxM9Rr2wkGVl z-4jjNmD`Ps(wEbZOEQY@mv%-~=NR7yPDUxIcvh+DWD-_uJClT*Jd$v-h~?yvuGF|; z+2!PrfU~PHCxc|1U2RJh>pN#ukJK)EPwi7`Lh6;BJ(^DL=sTIiKXZdgv$=sGpSR)L)#Lf2}BtpPhTbaVX=oWMeo z7h;PECns3W{&(fXJ6v=*86n{0gP3H4R6gV61AFKDII;PhOb|h3$t+nDCHx|lAO+*b yi5AAbxekBseJS<-FDuB4?TtoL6ydt|p7+0*7u4HuTFwae8MDK`6hh{w|MTA!{toE? literal 887136 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≀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

  • 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 EA8FRkS^xk5 diff --git a/ShellBinPkg/UefiShell/Arm/Shell.efi b/ShellBinPkg/UefiShell/Arm/Shell.efi index afa91c4d6caf9be464a61a068f90438028e0135a..4d95e0895184b4878876c43834ab477d90e670c2 100755 GIT binary patch literal 769088 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 z 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

    JCmWsDTgCqubQm}5@d8o+*~C+5GYy3pi4 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

    ?jMLu@CAhS4DfNyL*-P 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 diff --git a/ShellBinPkg/UefiShell/Ia32/Shell.efi b/ShellBinPkg/UefiShell/Ia32/Shell.efi index 7fb32890cf82024091ea29acb8d5504142811d17..ed018b9cb7c64a55d70a442929c2cbf521c18cd7 100644 GIT binary patch delta 259553 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

    j5lb!4&DH)oS}Wh$3x> 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 z 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 z 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 Q*Z_;t0+8M)7*>e?2c(O literal 769536 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 cqKBk0}u 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

  • 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 Vo#C|NBIJjC5Uy}~4{}dk{r}ufjcot` delta 140594 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�Hh9ULt`SRgsx^*smhsPgr{UQ&P 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�$`AcK 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 J#aaJ3{s*10cn$yn delta 111791 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

    ;3wQF|_!e@9KYUkrYT|pJ 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
    sJv#^ z5nbmQeScp2xR>l*Oivm8uhWjPdjvh1f5-86K7aS{w;1_-2>5E9M#pEodokWUzrj!V z!hA)K@mc2APVpe{6(6?&`TQYzoYe>5t**A7 zB&O;!=y?!*)>^3YDyuqsD}OJ(>^90XVCZ?A`{8#x>&vx=I5Sr7LbQ zicx-AXBbzB-jYo%&oT$`D~MjYpIfm28F(diM-Nx?P(0mzE=u-hNcZ>8tEDGn&;H># zZ$74(kG{U57!mQWVEXf+;kUc?bw#$rxsx8dmQy;KlG-(>F|%*=@3sN zJ5#fMu}yb>>pq%mpoQka{9X$yw=!00Pw|d^o7Knc-lp_8zYiU(-=+_gzgz9n#$~oI zIp$xwd4P$X^kKCgP3#^#T092@Z>#A;@9b*HYhYb(`p`Q&h&~KOMr&SfePnr=VXrcF~x87wXUe2nt!?@Pi8C8WK-OZ zQ!YfzvFp%G`_jE&C`X`{=kX`)JuyUK!s;I@!>syheKo8t3m(FTlE_-_P&#*5N!dvHhU| zZW7uA`e;4p9wKB^2L4jHBY{Ex>g7{SQDzWpwbt=CWrUB)45p0q<2>b@zbz!@kr+wV zisCytytD4R(;x{xJ`MH<2EPprzD4@pXfU31wHg0bnR^JoeHtu3x{C(ab)&&oti6(F zvg?IwAL{uun7h-X0eu~=yw54Cz9J_ooXh}sEWgDsiro$n2P1wo^8CI5uH?CBC3)`C zyP&qHBmZB#X@Dy_sZJ1@DfY6MW@{+>%{24%pQk+=8yOLL}rHOxdx_gcGS*nv| ziC6fR-$UOGCzrX~@NKLlt=y*7^@+IK;gcL`vSH)&x!$&+{th}el4zYv|0b8!9z(j; z;X&Fj0bU9onZ*6`Ib=wD;Q)7KdBmMezVtQmg27=#Sz?KWT{tu1=D3Gk>G#_-bb?{Y zKMZg;9Ee_M_W=S${>=^8spEhdwr#e4ugtyE#}$9V9l`RNa{1?k&qrkm-Swt^B=IAd zvR%zdd&s{J*_pX`#ICQRz&Ddj`05tN{np58)EtFXD~? zH;s#Itag4cll@E|mm?R0M%M~%k_{*wciujp?xFhEP)2(y8+t@c+_;&KcMfo;@GYHO zw0d507W^k#Jb`Oylo}Ipzi-pT@3Jk@^jG`wDqqN#CF*TH{&FuZQIaVVXj)T%t@v=l2^p*~R+-3cqxT64{n!HhEuHMq{+US}6gXP1fQ_9?DNZ){*SG()b zsoT*13h1+=zV`N4JY0Kbqu}}$^{V>g)10mK)EPhf6n-<_I=`6P(xEv~v*C-d`+`&V zsCY`W(z+^o>35jC;`ya_Ez8JPp6vhd=j5Xg7t?nwWz>g5>8sW`U;ik6b46>fYDo)zD+T*PuPT3x^KC3=aZa?&Vt;fHD2LDGpMxMFskB8aw zCpL8-jW=f-QlEs~db@W4y@##0WgX7yOe#Tc^GFx>G^ew}z-S#= z=GIvlt^3GsNA{3@l1)o%4?yLPDoc#8X_PT(1$442NE2P_CJu1Hp}Cqd8#at_f#>m2 z!Z+r8k!;o*nj-CzTcc8mDsFQ$LFPrF6+&(e7}IL-lzB+;|a<{tc{R8adQS6F(
    ;7G;O*e2z#npkh52*)?Zd2Y z^D@#2O;=^k_Wab&LMawU3q9QxeO zn0`e&W-cGd{M?8v;T+EmmPZ1wh24qvy`em^=W|=uVcrKn3@7S{jg~Hd6&cVo|Fy-{$=zrvCE(MS^{(L$bSeols+p*3t?u*vI7sOUx2K(B7g;#|9Q%|1ZRf*7MeQg~qv=6!K760_(M!UKrZ9AL z%W6mP-D$_HU~OZ4bNUT1?|R3(t!=GZ+xmHSOl*`#yRk2oCRQ+Z#eC6@4Aj}L^RQFp zvlwY{iL=ii{3r99buGVdS#2NE&mv!QC-qp^UBLQo^}b<8+B%}sq`!v~0oJ$pK4rE0 zkgoFL5B6_YoeZtStCy=7NiOs+jiw1RwF~P}hzYgT>-!zc7% z9sDRh+5HUVlY5*U>tHYPPgX}>15To`&o_N-A7Yko1{BfV#0uTz@y%=0n{#(K(SS}A z3zWG__`U+VXx_DUgIUrIW@$H=b@M%#k5jL0KJpHJNbf3j=kwjki^P!>u&XnX0qzT{ zJe^kj7`OYE^0gUVYpADdWokUy4SB3fK5NW<+MO+)r0gT;D$+OAmgr#k>#4BOpOQOD z-RYzo`eKK--WPVIKN)&KpBw!;$Dp4*L7g(@(6&fe!x_5jF?K#Y~ z-;pMt*kHy&I2>c?iVfNMwnXs1rEY+;p}GH*y8Dx_JKjYle?dFpd0`QrCN2^DwlF`GH=!tRP?Oh( zFHQe?WqDMBi+cKDcvrpw>VE|e1=3~n9gNMF>`%;1$pFsod+|QO+OECFR_2et zUsSDog53e`yn9Ps?T@IBvNuw8tRI!&CX_*gftxT~sJdH1$G8{=3w@TV>(Nf6#__Uwm4a9N-SqK;!9>Z;YGL z7Tr^t@YBcG^fY{1#Tkl#{0;Pf-y*uG&K!6-1U~w$`H-mc4)6_GO^=28=Xf!DR0VeO5Jso>rR(iXd<2K z4(^-L7}cRmsI6}rlREkmXY54VmA881QoOeI2cBpx9Af)9%}v0nwrfb%(mlzW*&XcL zrGzW}ek(A*eU7=HHSeeJifGE%w5Sc~{_}1wb;rOfYDaQqDDZ={b1wA**Oa=I@PYPp zPP6bePo46K=Bz|;b$DtWXL8f8m%0a&ul5e5Zrq-s7JTVSQ*Q9+Q1u&M$8NIp1=`6Ktu57zLnnRGyW{k<#eGD#K8~I3@rvKaM<^$H zR2Z5IAE)_1{bp_13@%2;Lr?Pk8SUe|IL-EPkDI*|#Q^wcz!e*yH~{tMLgv=h{Ot^t zWG_M&?HHpug1?Zy=lQMq)G^B0zMb>e9j9^jkUH=Djo;|UnwS2Wz~%3R-G;-EPcN6c zE#&``KjkAwI?oL*e}(ghlu5r->i(Jh!r-9MXXYS}(2tf@Lo=;uzD$WRR^`qem2b1= zJZ<6Sr5~MU^rMy_ZB^G`!@N-H-b239e+Qk?%(p@?j;wGtHE>^t;#AnLTeS?Hl8zz$ z+SB2CXJ4~v{&&R6-eiP#WH~F+dUdH=3V+}yZPs`7)uo9Nz8%FG)80;Gs$@2CiQBjF zn+tw!5zX!~eu6&PcG9#yIZn@87NTd&ACz9O6j`S7Q^hAcJ02IDpYl72-j@5YzdP^e zr3uad4@s8{P>h_)>s`tCu8zku8{kj)ZtTw}$2%IubK3Z|s3$t!j0}@5aoqa;CT6ph zvN?EHclhi8XZ>!qYy5c97|o2H$4hG)I7^m6=L-W{I(Y_~$H-g$IDD&fW{;M-yZ+j7_j=`tH>Pk8Ds84Y zC+G89fcQuCeLMJPBFJ=p*NrQ6KTtV*XMOfT*C7U?jeS$e&>qr9_zqsgn#A|Mtl#Z? zOV1xk9r)0T6=Q8ewi(#SC9_uLZ>7FpR=y3j zrP#AJ%E*T(*uqKQd1!Z&()b;qecgFojcvT`bLIi%{Qj(=oWAG$(8K8++rQ&AXP|us zJwxzDGbb(tUh0fe_fFd8+)T^yvW<&it+22L{lJ5@5?DUIUqGi~+BDFYeSxPrb2;Nv z+)tlQZ5McO9_vP@wcTL-FFL(x%ldQ@eT4IU!cBBy++OVlF9UAk7oYA;>^b;lbKT0O zkXI_Je){EGiJ_^cZ=##u-nG!ihw;~LFvKUt?WzC4bI}2Tsrs@@44+th7j~$Q?GH%{pI({>@h*fvx7(R}Ut=%Jud6wBG;<}X zw=yYvglr^!tN)A16Ft|Vf5_J%oo*eviYKc>*%xUG+O~whU78pJe6@#Dv7)dJ9gO#F zz9jy~fu|k=P62p=RRGpx3#$MurL_nSc9Pl@K0i<&XC-GymoV~aOle{;@QdY>Oq(>sB&D^{d-u?>Nsk-XVdfFhC3;7hNSwMZYR}zOWNnb~7R~xZsgB@o+ z>r_qdT`wj#8Jf65V;~soIG?!u(+D<6pvJsiNxdX;cYpLM$z#P{?!#~5Zn9^vPAkuU*6)99=4q`2uDFf`dObI;Ms&Pyy3}o z>0Mfr;>0Eg;Lr5K{oQrw^{wWP2ksc5&eg1s@@c%My*|n#r=A=|eEvt!Zqb}lx9)<} zj7hw)TK8b}EitERjT3S>=bo;AgF5;x9ByGuh=Fa99xr|CI_|GF`g^uN`*sz?l=jXp zh8MIhpG3VciU0I$0_@rqyiIeWvt4V;vfBo1)4Fp6>zA<~(EH3fM43ZK)4A4Mh10C@ zu0~%tkbWwy)4rgt;;#g=(!yvvR`QFrjkKPm6)3MbUXABq+Ek3-_3X2Wck;mfn{cO$ z#{UN7uW%EO7&%T~ZlX=o-ad7Y`u#l>TO^GxmR{7=-?_HG;y-^5?+2Xy;e}4ACr^5sY4jW-BZVy*VY{iFCgcg`ej0m|)}a`hDYfjLrtk@s9Ra;a82P z(L3j&D^ix2##Opsyy`bq+q&*j>62}kRpv^kNu#Gr$IDPoF-MAnZb07ZoNgsFPz=ne z?Egsz(VEpdLwi@1o%Pr}Zf;^uYTihHT%1y#HXY1+>B{?w@0lmXcFvr^VK*=UALP_h_mhW#OZidQ9tfN@tvxl8ziUF@Kt`zTKhNN8LdxnzWDe&ob){Qr<3SOk{(I z_UAzp$=n^lkkao`NwBL{RiMeC`8h*$z2F`6B?M<9SFXVkU`b!>PB0C&- zU%-Fz1^)%wiuR6t2f$=Km0z`G&}F4l3ui$8i%Q*JQRaSIE>={|;q0HvE~l(HCp@Xt zovm`$3J>}RylUcI1(WC{_9DGId>Sn*jd$AKsS+F!b?Z25oJ*FvKOh#CCWxnIW0+bcI`0H5!SYgKHf zZ&&J!x?_3s9G|9kkL`B<8yah0{4V_j(T638rh3Nb{8D!i-}}7l z@%srr3=8v@{Ct*#uxp<}eCN~pC47HccaDH&Z$iKQEk2rGPNg$!P8mM$@z}qKQuot8 zbFZIhd?@noKP9gJ{*ZXpvGq(pqU`H%o;QDXsk@ds&L#bMyVCQ;IdSoycm9vE!v!lv zEY}ZM8+vJe@f|?coX>);{N@X z{$bbRf?^&s&YH(@Y{J+yuinb-)U)=aPZQlWi$QGqsrkPi9&AIdrT9G_f3on9{BzL1 z@;~d}bx$(5zDrrzh|CjwEbR4di6+Ka_>wR3<>*fS>A)|sayC!w((13Vsgc*Ym8s zeqK5H(mma1@W5w#(x3(!m>4GTi{Y1OwfvKV7Q#dOR5}-VhkPf{J_{a)XiO-t{5-M2 z&9;uyiCfRC&Q8yu{r90q0s8rUm)yR^?>q4B0-kiUB=@`pun9BC{zlg+mz<=Z7kBGJ z)cNnKDco&8nep@W3CXN&@?+6vQfmxw)4)~zlc+z`(oS+U0}mv*LryWn{<_mX&Wk74 z8!Mgq$Yky`>KRVx%@xJ+?1zsdhJT>_tp0ACG0Jl%llCZ+*bTvJ!Sw*o&!=z2<+S|( zpYKn+^d$2PKCDMKdR+U#nm5(V8&kG7_0wJT1xNHKaPH5ngZ6z5rJc%Is@%TVf4sYB zVw`QPs<}Ie^Ua=4?djJk=GNB_c|5~fFf0#Vd1%vC9!<0o1CTkXH1Qt!TEo#*W*&bU zbYC23BrenVyM90)9eBv}4LvL_S;2SPHR!3!xKDa+pm8VrdEyV#Ps*sDn%8RUOYE=$ zx=0f`QDGT2|6$IwIOEGZv70Vo?u^{WY5Wwvdeh>lu}RuBZ_)=PZXNfjrAL$|9w9$Z zeP};(6nQe6nrDqaWj|>GTl{^Um5SeVt904XeBMHRrY736ARLLS1p`<}8Of1MT}$ zpIrhU=q`x*&8(@+pH;deTQpn9*#zwk+(3*$6Y0JmlW`oced1a25m3${?=kku1jFnl zfRk|G{(du$gyThz5^o3pr0C<_)KeXAZ`O--P7;6WpSymK{!FG!5`9JG4x%rbucxB( zO=4eTIdq#i!`s`K%-zGY`F)Xl>Z}IF5L+bh2Z_cqM4S$M1!7D7p4*R<|esRXGb)XlM@*%XB zjUl||_nN=pNX9`je+6gx^`G+<_0{`3)h6E5 zw$<^Pw`RrnW$%~#9C0<({k*-jmuXXTC&rpWY$d$I`2?GWe867u{EAQE=TuwcXiH}@ zu8BI0vqOD19o(<(Db6~N*E?v#!D|`skzI7`#2p!YPf7SCCs{*(8v2yFe*v!WWUe&_ z^wt@3TxWW9M~rwxZT%nX!}0V>aH_c@skN6!n}yWPP_GKU3Xu<=J;EF|ZB(VXvqE>= z+~mdJDz8p<8ttBLX_Lc>(m2UxTmH7^^EiufQkhk>`2y{$&4z8frS?^a*@L#l zrHOel@B7`Eudu z-D4#aByla{^9TsoVGpedwmQwnAs!|DkgNv4gFR@NjgGc(Z<@C*`h#o<}oADT|BI3%Dn@ z?Xi+X0pEALtTZu-yzf)yP}Y8(1K5g9uv$9BVEo0bty&XbhX2eQByFD3_H{nz%>Q^N z*5BQ*Bs7$pB{>I;ch_@PTHDJzZ#x{99n_TFO9Ca&e5OKiyg>l_8 zHeBmYQzq&<@j&C#@N^sBqxn4%--hO5)50je#9+3WyaIXEj~oRM-kYnco<$K?<3`0xh&D`OWhKfCQ+&0s7a zXKZxmL6SS%dPB?G`A&1+@AJq6>CQ>^4~|DiP48!I6<|%~zD((nzRmGt;Iy$;z$dKd z>H3fP)>vnkcrfzf*%6+7KdC%iTc>-`w{TM{`AVP8-Qn2yPc~8RF?7vLxzoIqJt2Ij z70vvYKjf{Q{aoo!+Znfv^heIE3ePzD6SfxToY3RZo!V(X!#gZ0b0qbZwv#%)XD$gR z?L{h0cKH&U=6|oVb1});f+W87)a_As1A2Pe?nSmXa`&zDcD`dF^ovDK<0SfAz@HUL zLUU-71fOINXL}4?4j!&ga;I%Nf?h{VzIgAq&=uXK=F6SPL*dJL(->=x;02CH-=vQ* zU|a~E!l7_&)IA(t$*?b$2L98uFWpCNJ;Cp#?0?D!IGi>06lnF8^4K4nL;hRr|H*%O z7HfLbES*j5pX~)K?9rLVugUi$%6%98PVl}*{cHDkwkN@*xL>O0_e=LTOyDk#o->?- z{we;X4;kiYcl^_$-%U~XPH<#in0o+Qd5=W?ni${5%V)f!pV?QPN859|@zfjG&9P7W zxsG&)E4{H6T^9E8_R)WVoXv0Z>Kh+%xB9KrmyILYDB0SF_L5t@@}X|?V5xken)mn; zeEX*BOtH7#G?dXt{6=y9>z*0CS09)fbtMO6|JCp(dCVNBU&5ZGbhuL1qiVkKZxhe0 zcl5j%8Tp1fI)Y1PqrZv|uan%tuOq!{^lW&HG?ke_y2erIdHi)IeX-Mch00@JJpYFSGedZ+nP4I|YyQi)?xUJ5DsIgNBk%LH?&LtwY42YpgZ*WnZ+j7cKu; zk}-Y*{h|XrCF6iuqqNsZ({KC!Lg(9?qJ#8+Tu6HCGv4_Q`Y;|HQS)%|gS)TMANt>R zjsC=b!&~0@z=XF(-%I+Sb4wD{2NTQqX4Ji!@6I(Eni>0YRn&d(rEl;p(HC>RW25E0 zXcb()4bP4>R#C@B! zO!RZ;%cZuS`VqXUB++mP=Nfr~?mMKbJp8fh8u%oM?U`(|{QMJd-Ik0k#%W)0I@7kJ zdc*kpiPd?A!k2C9c*B@9$(eUwq5t?ca%(-9MsL3?+Ife(-%s5mzlHVk7{SFKDOvYx zE4O2uRV$9UJ=eCiLGvEm8(N|Xy+?%YV`SU+SWD3X%$;lExpRSI)_maV`xXl~$2!?> znMb1}za{4a7f0P+A%|$w#C@cG98KK7H*&9e3Nmyh_pB%1_4=~H&h^dU?)O8wg76nl z%C~zK@Xec!;Hi1o%l1#>*Vp3p9{mvi3pdr(-J=?}*!GU$&Kj?+Da^lhw!Px9SVDX2 zMTgEisC*wSvEIh#j(p(0++FxQcq@3x6ZA#;(K6z5wqR#6x6GNlwcP0hZ;Wp`OY*sA z_Aj=acrQSjd}u0b=*V33%U7T2m0v`@@)Y-@wfB1b0mhDn_pn)JN>`c9f6?UE#4ia} z9dBqgkd{)qy(?)~Ict%97h3lNY(_`X9S7=*`XD<~Z+>nGg|jK-MHTJF;Mv@39-S6< zlc_1_Bfo${jM4O2d&C#jE{j5qp8l8F$`32~% zdmfL5_L}4I6<&WQck63U@h^RwLEl!uSK5bAyES%v^_y`tXII6mw+UzV%&X{265CgG zFQsk_nrIF4#?#kbpThTL-CL=@fA0XV{&sveF!Ja8$Qr9W!0}A0?XJpwDo;{ z&o_D(ajC5PdHSib7rbu)Pko+AJ;h(~HleXIKBfIH!CkPbgjZ3V5%b8i(HTqdH}SB+ zQCiPAPYR7tf-3yFZnwJCMRgUk;FpWoa^h)o764eH9kxcr^M5SjZPLKKc}^xewVFNB z%6nT|UO1 zNj}ui_>VRW!>4ZjLI;D7^xB){)8<|~d{R3C@RZUV`k;Aylclkdft$IDgS_q1)yb27 zB%Trv+(Db|^hf!h+kE9MqCMp|LQAtZ2R)7TQ_*(0HMn!XOEUBSuV`&^DaHQm?~ z#K}SDyZDyf@e}Ihig?)p_Y6KQ$tC#8+&Q%9Fi$r<2KuL|=go=o>`{D+&on=Mob#+X z(i!z%GE6jXALrjU@r=1=LU)o@S43TJot2H>+uT{RR%6cE;co|!FD75f(4ZT^l1ifb{csFqedXSi# zKG^Z{>z=DNZ2y5X{z_=JDCW&&`651H&Y1f|H6QtwTu}d&mZGfE3Y5|Rp5UhSn)Q5v z;xk0&K*n3+(A~#3fq%7K^Xi~=RmPdQNOqTn^A@lL=V;)_A0htL+d~=b=6gBs=#71^ z?ECavOAGc2OS;ZB~Rl^QOryV8&voeIwDJU!6%yQ(g$Vx=DCYT z_-<3WSx=Bt_Dsp`hIX9)wRuWkRH6CbGusF~6sxASr*5s+|Csjw$Xftxb&b-} zw9`HinaI9dfpO72xy+Lm;V{#~q5cc_q4%7ACWe?joqG6b`*(=zRlJRU%PvqH@fgxD z4zm+Qd(D5^OQZJ*b`qIB1$eq=c9wKvd=x3Z-^DkOCsyr8{MOx^;*SZ)dtZ+0Tk>CH znnq?F!+7X-PJPGLcltQZ=LjzQSkHpzF-5dV!+RO}viyQ*ZR%9U|FY=R{mDP9xD2vc zWfol!bsH!XyEHmAOny~y8T(em=p$K+DC1lbo%+@N$PVDQhNEtpv5n&+(sy+@nz)wl z+(Gma{NnWWQ1BBCgkw84uiBeKS?Lto=X{LuXq!8BNdxU@e$B(a811ANtUnQXjqgmp z5v?JoeC_o;2_42E2YyL^*He!*@gTippt_1Jyq>zUb?4AlfqbRMNNax)oJ+h|q8vE1 zF?Q<~2O1Samj>P+SzqM;LT@#3bEWLf&6!B-%6C%7Pg306O5UI#x{oRRC)RG)Cblp z`c;wrF7%RItODK^>TSVB%OT@3++nIUU=#DIcnv6^kE)#V*4sSkA-X57K)T=y?yVMX zob$Y*>3Zm+_=64Yk;GhdDDk=IdNy=DPUi zv^=she?Z-%@(s!ckzCf=D*uqat3U4;FZu}w#e0taLl}7xsM%lRY31~N@aG847x0I! z&C&~>N6gH9z`q*!BYYWWV`j{n$GCr+ zIZ|%cFW#_bO^`nQ{$h_-%)`z#bJDPAZQw%2cT{xh6Uqly>13Y)qf5`J$i6{4(s|lG z&>mhzb~W-m5B_HFdvKs}ALgA|kI4Ig_Rayf3gT$AH>q(v?(BZ<0nz_7^a>cY6^46ZT(Ot7WY5%{L9~^v6TZtz! z^N#km0=FC+;!)Ek`T+P#hkFm%tUhSoKGZFbcqG%`Jbvc)EL`LQ=Pd(`FVY{$HpR|} z?}e|%T=+^SD#mvsGGg98BYVWn)PS@0V;`4106)nC!TuYt1@9-okqxBu>!GjiMVn~p zsPQzi*?*JK#P@l2ddHX`Z!${Hir_;Eq3f2QV}*&;EL{@eysh-136?K>`EZZ_ZRNx7 z?RTeq_@gHuzDxR~KZO$2oW)NbA9WAoyHh?8yDYsZhTZ)A6^wT``Oqr)Fvi>4jGyey zqp>Tys8fwiRbG-_HQUw`EtMYlFp~H(bjO03-O>w3MBR4Mrx&F+ z@!pE+40rEb(C|jY{Yg6HQDh%4-VF?y7fq)csLWUdraFUMsfF`9*n6 zyyN1xSKStJ6GeF`@>C}iEYGI*rsy?sj8 zya;_u`;cwyk4V-Acw282^De;qgyHhLxNA(mue<$_&fl|dKaJlGZxWikGU7PgyNsVS zPMhebPda?-y+(9=W*;q<7*@ona4Gx9zU9bTfGV%zi3z&Uhx z8Z59hnD-Zt1|jOG9bX5LpZrML(%s(o0CQQe{F4U8L;KGfvjNa6d2l~>-k&3h#gx^Y z7);uwc8qe+rfV#EXFq=)oWuC%2MLc}ontY>;xRVcH5T3R=m8#Uz{BH{UfIj3BN?0_ zCSz^H`MhC2^rBclcgTa@`Y2qAVeDWX9uLmwm}ZQ*f4{k{FMQLNwWT+94LIwrFwwHF z+s~a9jNiU9G&Cz2Vr0FcaqsNicFxAMHb}pIFyh`T+kyQqeb>?coqVUU*J2@XAbvZK z?Wuh{*^%!l&W-=#6KC7(+a39F$^QboMq`xkyE|=;v9vMc51$TciX;ZxwOqWQ{eTtH zF%A_E^vR;v{)%&;Ss(5P7H+Kf?r{5cgFEHEJ>fnKT-io0wuZ-Jy|aBSJ)SY^K(Mja z@>i_AV=1@!?KZAK+s3@#b@A7)sOQi3wbW&;X8&w7vVRP+|5RlESk{7Xb7m*lD4&S8 zK6JfR;J;s>_X=bio`@`H$EQ1oy`ZKWLayQr7Kr}nb?E~zV<=Gqg&an^O^nmmV?o&}d-_-*=f9q`J!-I7_Jb&9Y z%ICXK=6(M{`P@<5I#;-rXQwM)-}5~9KUe+^;)-tY;9stMzUvP4>R+tw~*e=>==taCD>D;6#g zzlM^MF_qrlx8660@1bQ&EbP;=GW)=9A_>XMVp`+9|nKxG#&UmZ>2x3!#7jFUsmmeUQL6Wa9YP2l7TMCuPTl05WW#TkM%+{InK&L z&Cd^5`^s&b!cMc#5uCBXvFw z9e9=6XyU&gQ(9-oV*~yr>0zoX+NfSN`^~DWI^rAio-@1>Q3i5JQ12R*QpYsTSY%@iu#Z~r&qPNDB(?4Bd*;dTd}k&Fy*e|r4$N^|dL@*Cbj z&aaQS5#FtJpwq?pHKZ$PuC*DzSTE#D9r9%~@?{M2rRZG+D`T`*ulQQUCusll63#5D zzmMB~_OhUVBSNy;JN6C+ONP)y^8NnU3M|H?p&ua4ITcJL*Ln(F3X;;;`H(#dVDf( z+Mc@XF`^sg=0mqBjL|PFZnBSZ`)U6lUAl_)*F_Q&$h%bIh`&1UgOK|+vR?X#Lq9IH z_0)&pRiQ*6#vI3P{SN6We~AQBW3%ArnHjj;lc_z5 z(loA`D}{CF9xI&2*TF&GgY?FwO?#Cz^{eSh)_&-qJNNZn_g=)^Osv!EqzS(XjJeVq z-i^4oSbAlkSNy$7cjG$|_m5XZ5-TraTr9qt&!UIq$SdGI4*KkC>5+On;?A-#(%6ct zb+!dNO!#6))*QRbv{|FHIPp~R%3vNsl$J(zp2h3};H4!5p?vd4wo^KIGFC?~p!UWUHhdu{0Z1vm^s5)TWx zXHqr@4}FPmQS!g|Zq4}fm2BIZ{pjXhto^Sue#qoiyP|d5H2(Un|Lx>Q zN&K``#D16bIek_NdqsOxJJCC&QE@(()He|^6mggg1`7V%{sOYKegV& zN@IVfp^JmRO0jh+(?)!t>`C1@pQLQYFN2Jw+#BNCcWfGRsaZ1gAnFp6CqFXvbvH*> zeTTRAz63|TD>Dn5?s4`?!<5%sU%F=?rgzUt8wwoRKu4g*X`X2;plj#8tRKUtxIX`F z5b4nVTVLkf1iJGE=(mA4>GcknuTzVrbHN!NT(tq4QLtq@3ipeMInf!6h6?FqC7i_w zaTX&;JOy{uCy|ZXW8;2U**4Pa^nIpX2hcMw*ZnTWcfo)5iZ07bw?Oao&K5Y^H$u-3 zd54BKKx&LVPQTmmON+;@?C@g23o0YKu< z{Wo!5XjTe+PHlX|9>U(*@$l%G{Rlp~pr}2+U+U9G(7iK0d8p{Sr(WUPEjlB19%nSg zlMmeIt&K6e=6~dW+cp1F`wb6y{%zM=^M6PBqyt%Vxx>(TIFgvbcj^@n=5Ku%7UpXI z+roU?e)}-1_xE7lK>G6iL*`z@B=+`XzB~1Zx#$s-(Ic>F?|kkXeCEh_`ONe8+jX`w z${(n;&Ra_>F0%M&jMBXSHF_9&f$qrsVd< zH+_)xTe^$SQ;JE~8G+ny{&(HF47Pu_x{_7u_f6;Ew=ZP;m%AM{14sVcK`ej9e2O?vIn!whhcf+O#j=$ zOmu@;_q7MJ0~l>z2MxdFvDrW1J9FdiG!UJTXT$UJy)l@wAmWapzZ(DP{P)M;KIlIK z8g}v)d{r33JKaC6ba$cG?R7r}dYL%Y+dbGD0(<_qaoF&K=l5_=01Nk;Dy@g|AmF z;ynZLb$+hXc!Kx@zVLB)3>^H}X}^r#xDd~%obGK(8R%*}(%I>&m2Opim8XeqipeSF~-bQr4-s;|=uVR zXfA@Lo0+rnL&(09Jca)CiRUbDbg-w**!t;b*z_cO-KrzoQnB<;Dc&C+_N}blep=q9 zVLw%raDH%pnDer>ytx|#f3N7;Q~MdTZRp?ZOlz|AA3$5s^VJabE4|YLyw9iQ7UqhA%_db@?u9mmbj zcHyY^h&29t!|@aHd>l9Odv=6#hxF6n`lp4JZvx-^K6GK_8~paiMS5W|?t&v6iQC)_ z_w_bi<03uOr}KEl3KApee_vzAq^E`3y+1kNz<-A3dJoi-DSOgfF@Ju49^?0H(HwqU z^gnQansR%?y~UORN)eYx(ubS^N}*Y164rB9mUKW*z6@Aqq? zP3!#)eLB+XhvBEgz2AEslR@P9eX8O&@t|Gv+##a^KfLn9+sOD zsa@0-Occ1=bE(piDZ9Td(b8#Crs-FnwcV z7JeR@Hr?X2d7w?p(WdVBsH^wU$L3v4;=be5kY$6cg@&Wt3gk58|X zOq^F2aS!KzYn{hqSJ<|5=nV$Hx{^fJ$M0$nze~H}=V0%5$8UheFJ|$J8vHh|YCEzd z5pwV$SsZJ@vDM<3*Bd_Im|?Frcp7|nLV6X(RmFyr!0o6?SF{(+i}ikugXsTb=zlI{ z11bxh*%LJMi3uk337lAxm|^>on(Fmqge@akqccm4$#|9Z>HO)_9*mq~6G>mgcc^6a zqstHJqOk-1jXwU;m4!dLdk}i2PQn&EDN_40@}*zP#?bzIo;a65*qic^3GOrZ(GI?> z0>5ME#^M$2l zV@Ko%dwVvI0I!X9gp1Mn!KH)yD};;Y!jFKZGsEKJreh-sABIx`49mkGe`R@!Gs>;U zc=RT2tA3qLkFyt_s`cjX1k(Ry)A2J5Pen@1_*_N$+crJNz01|dcw=%W>2LV(NpC&E zgWp2>t3G_*I%_z}OBei=K78UE0!Ml6zD4>nA3kqTH5}=se@Qy;-FkC}^ngw83B4Zk z;S;CTaD-Q0XPO`O;Uh0IeXT7F4HuIKujqVar!1I2n)q=!w&6Z@+_e6z!RIMCi>@}l ztu`{Xbxe9y=7>n`#(SYXw5}WC$%;OVmxDd$)A}~scGAj=)`LqDFTgK~g{}U+N3(gh zjQIF@_&A5WDCXl6EFU{|E*>mCMpn#myZHF*`5kw!1sBN_;#-Dk-#3G-Xge~JXeIvn z0{C%AEaGavHWl+|f3a;hV`W95swA<{;#N1o!|g}5%v#+EZe>|9ZsiuYn8oeur-a+) zRg3o7T}~VVevkY3X-*423fdXhoidnp}U-D181`?TRHKX`hc966Yiq#mOD7Z>*FsuA^edOZPmz$)A76Y zi_~63{%&$26m0CHxygR8X!htIXs4T;kgYPM!jls}-y8ga(1&{n<9#BvXOh3$+y}ni zoiOl`TgG35{aXOHWi`$;o#$yoM_&%U>mREd$+?1>b&Kmpj)5NLO;GA2>BCR(E1P?0 zsi*Ht^bO9<+{1G%b>(l?+CDq#OiLo4o>tlc+|9)Ap&@6abmUkl&j0cnmDPDr*@8+F zPhW(;SZU}SBTGpiZu<%ShRwMR|JXV7kGESZNSD37_cQdb+B-CSzX-l^yU(Gshe_mu z&h%Wx+TH8ZzV7kc`nqw)d9szc8AJBX#?}gQwy7GKI;j_PHH2^KlB)?T1SQj+wK_k2!hj;K>aAz2FbMVEnj{EdY(s#wXR?^>P#Fr)E9cNQtx9!59 zDd$-FicZocv5OaQas8|NQ(o{!{{UO12wsesBEMffp}{b4egXc;v8N-N4)5q_RzLh0 z+Q-lx)HlD*)07o$bhi*ZSL2_sc}`l+p7lY$ z9!A-{?8`l6&O7;hsg-X7@eNz!>NE+? zx@maVVV+0_`3_@~%zJeoXb&5IZE;<_pKvqv{tPYTFV&l(;uHL!yk8orF?tg3cm~c6 zy0IhM-C^51`#L=HufE1#Dm?ChUy|^u_@>iW`dQeW@>zJdvm0w^FAwb3Y4a_70&44E zpI(-J7yI9qewW+tPWr_?`c;xXx-OWg`w8^>Pq=pL-NY%b>FYMof1Sl>`y`wwf2FUR z;ajr8%z5Y{zRVMElp=lk$Kk|o`RHdRU%p53C2w?x(oN_JL!o(ZaF^XCcx@YPUG`)B zxsivL@qe!xK{??O+!!|P_hMY0SlQRaWfbF)_T)(8@syWOD!}}hv?1)~igC6$H3ay0wY<^>hEps>*mg`dg5EOm8K2S4%*NL zPg(s*b2oCytZlh}^fhrs@^N3mn8m3(nL2gk&q6MXW~0}J-D=AEeRtTCGW*4o6_a0{ z-Fbfe$s2ch{E|mc&>5o*p+4+k_O4mSex_tV{+vMLJ3E12Mm!zm*`pp_IHzu8f&ZNM zn5H{0^EWQ66zu1YQy=uW2t16=rZKJJ?Y}S&_$OcsV^J(UoUVDp0U;5!NJgn zG2LU|;Kysi?n>SWoNMVUy7s5O{5tAq6L+Yo->Ge!dFTHc(XGAXaR;2V{;IrWVIAMg zkaL|fuJbHW*LmXv^T5bC=2QO__~DRAx7##mf_&rtU;CXyCY4i0`zeJX-n=@MywUH4 zr>3sOc3l;&t>!!TS1Xr9TkfyD6xwE<^=P}{^{~4Ryo%+@25c(v%-P_a{L9{DTIOl5 z{*-_0DbwDfev&?(VnE>vx(yN`Cp}ba$=F z&N(!gXm~a3rc2x1pe>t3wk99{W;u4l%VBrkOJTPcct9VGap!)L54Vl{c&Od|&sJ|O z(U=9WTQbex4EK=N!-;t-d0!AdE9Qy2Ws6eZKhLc@CO^2VYdjxZ?v3X_JAVFn4zk}G z&xMrHc&2)LYK6eRL^2ueS}K z4JW>(a<}h&?Ba~6Xc*oEG zte6~hZL}ACgLUm7eB909L>oRO*)cBjOYu7z4}D+Ax9Vi@ zb8M!Je&?Zok{DaYp=C~hw=m0zO?fn&c!T^+#bwabRc26>yTvJ!|64fm68TAc7WYhe z4Y|}JSlfQD_C5KfwUseiRkd$m+g04DV(yiLu4Wwtr|tAb=UW`kL@lG9aE)2Lb~S7B zD;9?gbQR5YHeK+N#89OKZ-4GCvt^Q$QJzDJop5A!s+C%p5bkH6$_X%91J#r`e2g>a+K3|u( zg+7eWpTdb*1qebEf$S^8G&jl|G5* z#B1-+j?%ve4{7Yqw>&t3|LU90So(dJY%)C8tiigyQE{C&BX^1rRzn_|D2OUAA$tPRvkx2Yg~ zPCk&RWQ%``_vNN?O z@g8l8kG1Bc@hvt{K6nT7tp@piTR8DJ`HJg{4MYEQ(VK@lEm~J4Yh}wRc2M&IodoKR7F1`0>@+ScE1^SRd7jOTO`pbKd z^drNXS~cI9RxSOoG(MAgGCWffpXtn~Jjf{toa>wf{uepZ6yKh?ysx_$IO?a`)w&@) z_dMXoN&gG*&%30rJBapE(EbI^keV{YG(b7nIQ9e3mk65Ec zzY5p3vVR$$7fxKRF{J($?3rrbX>h>9x#a3?=Q0f{{DJ5S+HEsL(k;heU+fwO- zNy-%74;f~WeUe~G@l!f9M@;Vx&c z`*}+Lw@vrcmR}Q2DE%FqF1R|Q_(NcuyZ@lkRh<7n%+f>n^#Z?~{7kyjSw3*ePr+W# z`Fpjb*TDk@pL6hmfScM_X4_D@);p~&`n~8EUG!Mmt&CsyZ$;^Yt`2v?)SY>v-&Slx z;$?d)?mx}?%UR8O?I{#!<5F;w%t?R8&S~)id^MT$BzC8hcN(>Sr!w2_=$eN~I}aB{ zv6F@&zpn@<-Xebsay0qMP4%%$|8hm{kkAubX;bIa&jFsXwTvIHSN3$uYFtG#wI?5t zd|ATrRDSCmWE1(i4=88OS>el|+=)!s@xK~eG{-dW8ZKw;!(Wm)z?*9U+MXQ@Y#NRK zb*ZI8Omj{BgQhkEe;&?09CtRe2hJ!PA@&4;^ju-(;){z-axix#Qi?_y44~F_you zV>!?EK{C}J%hB6QYMVx)UtAPUOd`MgSgKvM*ArSOPVYTndSj}0FMDO*yq$PF+P(U^ z;1bHttjajkGRSJtd;{ep(6t(xx7LU7xAx2qhX!W8Rw1{EyUVi%=6EL{6N9dU4PBd& zuO>FHL2HC9!zF#ae@ol3flkW~;F-2;{9X%o%$>x|3;v3)Jbq1b&yc|Z+=N4Bl($aJ zg%65#_AT6TdKUZVnN#|@5$L;t@{-Z28)vLkSMu7gCz&l?n!w*i>dJrqE$DW%rEMPm z(^x`-<~C$s!&%7R?}ZclkgxN5_%l9zvXXqRp4)7kf<9&%1NvEl5l^;q=& z61cZQ>*VtINXgT1q0{#vUW$LVex=;(09ICVxiF$aE(Q}6!~_a^XBR#*S{ zlVn(285ATgEfW+-fIwJ91k7ZEK$bBJ;!1{OvPd>335!w*xS&!M#jVzAa0j(@LF?Xt z_O)7D6?bbj;Qne`TeU^2@c(}Axp$sto|y?j-p~IxkeTOh=bn4+x#ygF@45Hk-od}g zyTI)e*oaQKzXNrev>u&CpBTP>f%IR4{vrK0X!^g2JdlI0vTi^6F$i3<>#LSiw-Em{ zj0eUM=MkU*>6eiH*Mt7of&Lx;@~(E$e{?VO&jtN+V(C9l)4vnEO4&=C`@xTaHuPoS zFAs3(KtFL#p!5vJ0LJ5(q(Shp#vErgc@W`tjk9x1(NCajgl%&TMqTyD_kOaq0(bHc z>!MuIzM@?i>&K~j#cz>g-iI*xJvfAG5JNW~gMQ(BYG}_M+BND75NSs_!Sg@a@57%G z`5whuEP0^&y**RhbsXfXV*u+o5OrV-ah`Az?m0UfFrj0%v&|On?B|@)?-d;Wi+&^y z-(W5p4+kIj)q%tH8i%fTG!D08eH6CBQHDQZyK_8R*nb_q>->LJ!M;eI4Y^W)@jngY z|0=oH(Mg|o$xGU=lXbj>FmVfFErQ|KfSd14*k|ZN_NCb?uR`Ctb*GV6luOy~?19X( zzI}N&?mX5)T5lgOwi#j)Xn{(v=vEN zjDHX1wynS%1oQi<>HV^vK)5p{b`H`Fnb++-();_tvaU+mOR$8<((GW3Bx)R^OHfckL0%7>$yGv8XSXs@TuNH80e!{ zum}5j6?kL>`Y8$T;imnPR6lhW?~+#gsmRAX)p#cg_g0vf`qjdk*`v^n3`3rL%Xb|O zM>)RtgmB4w7V3+dYvT;bNjT3*I$xpNY3Tfl32QpPuEU1TJDP;f7b1R5b5bA(dSp-N z=M5q}Pxsvl14H-SlP0WTcI&W#>0cr+TM)l<3Fcj-@wk58B7`I7KQ4g3Q8mtg{593f z_khGb{{cU3b^aq+boNEb{k+v^JN0%se%Tk)3j@#xJ;=+w#X``sSmSdz@^lTv`H!oT z0)Ctu=uGeD9gDPV)J?-aN?ep53Y5i}rZbnm*wkp!1|5PX+Q+@%+aRsov0T zkM|i}H)WTZzkQ5-J>oRlQ4Y6OTo1iLeARiSqaFmFIIqnPspxRS;zhsZO~=E(s+_aPXh+q zjJMxXR!7chRE@+Q8rEKS)FicnueNgy_SJtAzw8rMC0pN~G|)QdvxBhy`(dg&k2_-f z5H;`h-Ph0iDb6Jj?^@*J-Ew#0{h4*R^MLxlCfg%@g|oOD-?6;ic=zsB@KY`9$T>Ps z-bs>YC(qyxPV)Brq+j4sooB7ibKGpnvkhl&H)bYzeaQ10o#!r`|7BgCS(4}0ZvkgC zRsoLb7r0aBc~0l~@I=Y82Iq2j^tZg7NB0Z-O6U0mdAPUo>62XBk#jKe-`>#K8zjQ)68*GtMe{L zKKc!Cf3N2~!S$j8WA}6ZhB+3;_(GP0jtWC=4L?T8`5?#GMxH^uV<6V$UG3!h!ap&F zS*{9eFw`^kko{G#ORneHBIw2*zB>!))H|mGwgq|5{TJ9k6=?_b^G>O+n$GkMe@OL~ zBfSS_3xXI=BiN>cv#(CGa8F2T_SL-eCU*$z6SVPbwEqB2C+dVDSi>nYVcq`$9hUyb zy|A;S|My&p{+|Widno$9UqA1=2m{}5oirqU|A}~~ZlB_UKRpWm;hX(41pX(4KLdSC z_>k?-B21ahzJ3?_3~g2K)UfY9eqz&>XB3^cM|@J?H?-%Zq!T)US2FwnI3}{uZuCVN zY(czp#M(Ro^nO&?VW1CWBWco!J+bRvO7#xIm|cjwx=7cN$R~4J?9pT0a5(VUTIhkT zG-UIoNF%IljK5W*tmR#(Z^ubVSFui}vrbGBR5_kuB0Z3I3UTW>$$tWQ<5`sX1ZS9O zgQ)jXtINr9w8ps%4vst_)GLSQa8FtiQugb8by zztdp@Gi|KEY)1UHv9K!u)53cHe1zRHr2A`+_h-LJU;{ul&<5~rlkpY8dcTn&9E-*V z=+E^Js~UtFsRXUyg9{K`_mdt#FJQs`&$js?0Nt=mAF=FEqD8;pEkc)Z`C9P`fuo|Ge;)0_aGF8Z1= zen-F)Sf=5?Zkb|jR=T@v1ZV+XQfsLmu9agB&tQk$?m_(G!!f>~)2eoQyq6$+9B|nQJNSbX&lsME_VswYkN-Ns zSb+V;vCzFq#=;%1#~%y1Y#Z~UJ=9f~YJ5~59fchO-hxP8bHC4TzhdhyuIbAjGAYuO*zBw3e^Jy3ymt0qE z1Pmp&VUMJ6EZv56Yr+K{%u|EsZuBwJ)@*QCTJ|JAuax%+1Y-zO ziZms+!0SQWb2CHpTQ+F%qO%J*k8LO7!B^WE$M@^u zJ+i+gPj!K(AX^_}+vqdBQDoS5j-!VFr{qcDy=>%r2=rjR*8$fUp2PY2lQhp=q1$bE z?iCZ({PDUDqi)$h{+sZ}g@|ACcT3IHySI5-g9y9(H@hm;yWzgQ^zVg2!;2n>-@nJ` z{#}Lk(IzY6)CZ8c-*E!4?1U}v9h!`(W$ zSjWBq{4Vd=6Ca*`L#EKSH~#XtPhm6HI$(P!{q-vB%N0vgy={o&-J)FxQ?4YXSnC#m z-rQrOTw*-WWpyQ6-)@j~$!~jLzhJ)qc{23AFNNjsULTa@o>&#yuJ!?xU32*6Blq}U zoq#&PV_R+oEat1~f8@G_R_Y&jCLjLCWPwIbd)J&FV0?E9?~8g0zHCAhWw+s(eogdo`T%`T8?Bso zD+1=xS{`;|zd_xnjkqy7&WE@)Scl_Y0&SsNVMCcbg!6ac$2w!*!SY+>yTSgbI;Nl3 zynmGa!gIvm0hiOkrxPCqjd14SRrn(jC*nE`eb0BN%segCo7#}-J>kq$jz_Oa83Pq(2Q%QkEn4nWOFO*=sh?CQk8tmjojab&l_yoFaH(c8Ttpe<)JTlC)4wK zp7e<7o5;KoXBl`7d=JhP@^0~eU_FI2nhm}s9l_g5XRkJ4Ek7^P;fVZvM&#!d#IJeQ z3M8dN&fn$<3`Y37-wMnO14F}XG+_<1Rfi2s|5kxH9PvB1T7e*7c6WIK->-AXbl^p$7ap&F9Bc;QcMsADI}Nbk18njt?LxrY&b#N%fQ`>`*&eJJA>YPlE$?v- z{FyiTJowS+`~jW68+Xho`*NU%>p%)tA<{NG@d3Z1kGHJ3*3-H*6MOAfdje~b&T@+{ z*Dx{ur=Tq}P?k2zjq%EF@U;5j&*NKIou2YBS+!}Ej>KTtLjX_Pdk26={||Elmy-IxR&S@J6xH-N3)!@hGl z_p6e|d=C9jncj-MqMLy0R~IBhFXNmCaN&5`y`9@XAb!*ncz>(~S+=tp_s{*!Jr`-2Xrx zeW~OT?zICxUqRM!Uw_4nRPXhG{~cuQ4KtyO>2q_aHI=q3+PI>Nceu<4JmjaJiw}Fd zl*v1>7B~!djQI7Fnvq854|~tv^e2D=orkqRo|iv`$NfM@-WI& zQFiP26VXPKwsL@^lU}T+C*|nPow!qwby#>e2jMyE$wixaF9B`TkC30b!vlD(dc5`R)qvmW<$99X2t8OIA@OwRd1oNA5TrvU$~|95=A{pifx;0-T>^ z{oM!d`fYdeurXhu3}`oXHTX9>1wJ{JwWJd^1Z^4itLk6a;IQdlxe0$8k`G_^7p$q? zl5+Uxn6p(}FrfQ{>X}ygswvhvHL3H?4Z@CGm5%uiemhgTPr#XgbF%SFzFE`Ed(o4| zdXyN{dXW)C}#*cV*qs_z*?HBwSr0zeUZmxB#T4|kA-6?o2zDd%y zYP@*np8npH3qJ1GaBO|eHU1%+PeQ+|aZ)E`wxA4cP~vI)*W=qW&uKn;T%DOU_ROAD z{Wd*~GorL%4l#V9?Tvs5Yrd(_Vc{FRKj~+}Hz|l;d_MRF??C9P#@Tc5#q$pf%w2dU z{^UijWt`}Od6Ele+Ia%=?f;z&0 z{}t}m=$Qb$1Dvw^+vP6G!rU48DBlfUqfv(ILEV}MsJ~eDdQYl%72=2&!<<|FQRl&Y zbL#1kGo(A_uTvN5XCIzBF(-rGePm>&;CM0oQ$Bwo?V|i4o&O1YXNKm7Zt%lH zl(R)ROE41SW1h#GN}kZ|Iz_khf2bo6*8|-;UrC4?mKls zZ&sQ2F5!H>oEO*UC^4^o=+j~9ouZsebAB5HZPW115+7^{_M>&2vW<`TeKgE_?M_+O zvYL6dz*{@Zv<_7&{r_Th9u*?uiQ)Myw$oY2W_fC zo#d6|GpL(o4yxv_h~r)(?Fj0e9_%$xMsj}c+#@t=18f87y<@ob?Naa=ecGXO9yazc z-v?d=`tZKVF5D@;`n;6Dm6-QuqwlbOw1R%UxQj%sBfwTsd|ZXLb^lG;^)YbHPxZvy zm0pdu9Yy?r=cPFJ_CDsSY>#E$PkDefrQ@%|yp(k!0iMAZ4>K;iKkmH;-07%`Hr&^SkMMryA$#`xwhH4T*q-A32J^^l z*ntdhZA%IK6X9;|ZK2-9s3!=zr&M9A!@rDnCi}1JV`*b8;zkaRZR6LVeFoaev%HHj zCXYq`?f|_A;}%V;ZoubzAgYi~{^9$6i8pawr`z))_>_1gO-K7d59VW=sxbcjz>Vu` zrjIc$H{1K3vHEYfo;MVOhn%`#j%p2bYrc%HT*NOffXp9;@ioEY^&xz~ z7NPre14HY-^GsO7T&2SXW?HVm9FO>IxmF+zXSXcKvx5+h(SKt--dT6=MgP4c{qcK` zJ%^`^GBWsopo6IYGB7@Vfj&7{<3s(|br|$t1J?ebgL~3F-v3>@=lb>JPxQscV$0j8 z=N%T>vKwin9ounhofTLOotZt_~a_VHznZKQ$ItQc_?#)9w$am{Rg}}?WJMf*FZC;uJW1jgtKS&-z;>&xDow?IisTA zd6xGE@cb{p<41vx+#7|i(f8S=ZhlwIo8Ys3|0&;PYa5a}=UMQ4=-(+3*+HGdc2%$+ zwNBZl@p)J4lx&RIPjtWb;A{(Z%4@)jIIq|J<^zAy$KzEK*8KUVqhD$3r;Qi>ycqG@ z#-pD{fIm}Vb0AEe!n;mntPb6L4eUzRagEj~9SApSdhAW7>`6(&`~2kmDc_|sRFBab zgP$HxcbTxp_Z}TK<7s2M;CmY4b26XPI zftio^TSr;SN3d(CColrx$QXr=;Cn->279~}cO@93kbAUIt*365o8bcFghV`laO{c#}53bS7%w?3!tZrjXG49V>{N& z!?@x%&&`8n1edUTj~6#5A~$GPQUHQ=}W4=^V5I5jp7-=SHe>q$E~#k=K> zVcvROm;dfz-fqy&2mSs5coXw0wMIi&{j&X!rTH)~&+|WK0cINPf;7CF=XSv3IwH&D zjIdf+<{6Y_nH=~Osxl}$0Ohi;80KZUes3+_MSGIv32OuCgm(C`mX@z^0q?7KZ~9wO z0@*sQOU~=6wte&y%X=(r8^U4R)&NE)>P*pbNxtmI;9vgO4!lE;^cVoYojYe*<;3fb zmELle>CpA=fQ)6IjMDXVgU&3If_MKd_V7-wq%m`K-Ul%bptr|}4dUMfe!r?aWziei zM_Dj!vLEB~BIt9hKz`TRAA3abi>4m8&&DQi-iUr%AWEHRkWW6i@5r_jhm}%J+1by(zAevWbw(U?qp8IV|!Jg@W&>zuW7 z&>@?4rg*N}onqmgk13mW9F4f#l&f|Q$1l!{d~hs&`{5nWqwzc6dhDaI_#FhF!3p>+ zwI16!C>J;;;V%z=$(ufzjQCufSsZrgrjLgY+H@!Es@*9#_lY`4_oM^;<>mQh6^rr< z3K!*1b%InNVII zYHXZPmS2?bFV9~zCpUM>2^0MOvfR1Trbt>~N!Ti#J-h)pPp7X6dYrf^P3h|F0#yLKnNw~1Hb2efy zqSBH)NuO9RSoc}$tu||cbpi%O$ZED~tXiwZ!ps$+Mx=z)6XP3@Vp(-aZO5NwWg@lR z3LZGtycBHH7aDlp+k4h)!!joJrwxJMxF|k9F8(nozS{=TeoY z4LGtEmaaieBl4_Jp+yKSN2-*!th20;#i+GT!C|We z524OV`C#dh~>ic;0JxzU2Ro_$8_hj|WejI5{RNqz}Gsc@Ta344vSYDGTwO}rd#dKnn*co&Z=hU|rd!Lwt^ z+rtgbb!oGF>FG;b8ftuFGJIJXR!*p{p*au=SBIM0eeT5k=9)xFQRQa(?3`9!XlWqW zULOOjprJ7oHz8eNU)WsRQo8u;P<8uw9d2kZ54E=g=eF@ITiVKTiIE@O0^g`nzVe21 zLyXVL@U2`45y7$EXLznggCrfbwV`lPLtA@(b9;D2OhZaqYC@T_C09&hX}AFd4L0Vs zG&KdAYl<40Los>AYHToh_f*WrxJi5X|Ic}1gVj8@HU4 z;Tw_Rri*22iK#w4J*Tu3a(;u!|dU{byOY4GQSW!MIv##xw zhW2{J&n||v-0ALi6Pvlq_O+{y5PU>Hqn z4~5$T;g