Re: RFC: Fast Migration for SEV and SEV-ES - blueprint and proof of concept
Ashish Kalra <ashish.kalra@...>
Hello Tobin,
On Wed, Oct 28, 2020 at 03:31:44PM -0400, Tobin Feldman-Fitzthum wrote: Hello,I have a question here, is there any kind of integrity protection on the CPU state when the target VM is resumed after nigration, for example, if there is a malicious hypervisor which maps a page with subverted CPU state on the nested page tables, what prevents the target VM to resume execution on a subverted or compromised CPU state ? Thanks, Ashish This means that when the
|
|||
|
|||
[PATCH v3 1/1] Silicon/Qemu/Sbsa: Add SBSA-wdt entry to GTDT
Shashi Mallela
SBSA generic watchdog timer structure entry has been added
to GTDT table as per SBSAv6.0. This enables acpi detection of wdt in qemu sbsa platform Cc: Leif Lindholm <leif@...> Cc: Ard Biesheuvel <ard.biesheuvel@...> Cc: Graeme Gregory <graeme@...> Signed-off-by: Shashi Mallela <shashi.mallela@...> --- Silicon/Qemu/SbsaQemu/AcpiTables/Gtdt.aslc | 87 ++++++++++++++------ 1 file changed, 62 insertions(+), 25 deletions(-) diff --git a/Silicon/Qemu/SbsaQemu/AcpiTables/Gtdt.aslc b/Silicon/Qemu/SbsaQemu/AcpiTables/Gtdt.aslc index d16778e01a5c..1713c203766e 100644 --- a/Silicon/Qemu/SbsaQemu/AcpiTables/Gtdt.aslc +++ b/Silicon/Qemu/SbsaQemu/AcpiTables/Gtdt.aslc @@ -24,42 +24,79 @@ #define SYSTEM_TIMER_BASE_ADDRESS 0xFFFFFFFFFFFFFFFF #endif -#define GTDT_TIMER_EDGE_TRIGGERED EFI_ACPI_5_0_GTDT_TIMER_FLAG_TIMER_INTERRUPT_MODE +#define GTDT_TIMER_EDGE_TRIGGERED EFI_ACPI_6_3_GTDT_TIMER_FLAG_TIMER_INTERRUPT_MODE #define GTDT_TIMER_LEVEL_TRIGGERED 0 -#define GTDT_TIMER_ACTIVE_LOW EFI_ACPI_5_0_GTDT_TIMER_FLAG_TIMER_INTERRUPT_POLARITY +#define GTDT_TIMER_ACTIVE_LOW EFI_ACPI_6_3_GTDT_TIMER_FLAG_TIMER_INTERRUPT_POLARITY #define GTDT_TIMER_ACTIVE_HIGH 0 #define GTDT_GTIMER_FLAGS (GTDT_TIMER_ACTIVE_LOW | GTDT_TIMER_LEVEL_TRIGGERED) +#define SBSA_PLATFORM_WATCHDOG_COUNT 1 +#define SBSA_PLATFORM_TIMER_COUNT (SBSA_PLATFORM_WATCHDOG_COUNT) + +#define SBSAQEMU_WDT_REFRESH_FRAME_BASE 0x50010000 +#define SBSAQEMU_WDT_CONTROL_FRAME_BASE 0x50011000 +#define SBSAQEMU_WDT_IRQ 44 + +#define GTDT_WDTIMER_EDGE_TRIGGERED EFI_ACPI_6_3_GTDT_SBSA_GENERIC_WATCHDOG_FLAG_TIMER_INTERRUPT_MODE +#define GTDT_WDTIMER_LEVEL_TRIGGERED 0 +#define GTDT_WDTIMER_ACTIVE_LOW EFI_ACPI_6_3_GTDT_SBSA_GENERIC_WATCHDOG_FLAG_TIMER_INTERRUPT_POLARITY +#define GTDT_WDTIMER_ACTIVE_HIGH 0 + +#define GTDT_WDTIMER_FLAGS (GTDT_WDTIMER_ACTIVE_HIGH | GTDT_WDTIMER_LEVEL_TRIGGERED) + +#define EFI_ACPI_6_3_SBSA_GENERIC_WATCHDOG_STRUCTURE_INIT( \ + RefreshFramePhysicalAddress, ControlFramePhysicalAddress, \ + WatchdogTimerGSIV, WatchdogTimerFlags) \ + { \ + EFI_ACPI_6_3_GTDT_SBSA_GENERIC_WATCHDOG, \ + sizeof(EFI_ACPI_6_3_GTDT_SBSA_GENERIC_WATCHDOG_STRUCTURE), \ + EFI_ACPI_RESERVED_WORD, \ + RefreshFramePhysicalAddress, \ + ControlFramePhysicalAddress, \ + WatchdogTimerGSIV, \ + WatchdogTimerFlags \ + } + #pragma pack (1) typedef struct { - EFI_ACPI_5_1_GENERIC_TIMER_DESCRIPTION_TABLE Gtdt; - } GENERIC_TIMER_DESCRIPTION_TABLE; + EFI_ACPI_6_3_GENERIC_TIMER_DESCRIPTION_TABLE Gtdt; + EFI_ACPI_6_3_GTDT_SBSA_GENERIC_WATCHDOG_STRUCTURE Gwdt; + } GENERIC_TIMER_DESCRIPTION_TABLES; #pragma pack () - GENERIC_TIMER_DESCRIPTION_TABLE Gtdt = { - { - SBSAQEMU_ACPI_HEADER( - EFI_ACPI_5_1_GENERIC_TIMER_DESCRIPTION_TABLE_SIGNATURE, - GENERIC_TIMER_DESCRIPTION_TABLE, - EFI_ACPI_5_1_GENERIC_TIMER_DESCRIPTION_TABLE_REVISION - ), - SYSTEM_TIMER_BASE_ADDRESS, // UINT64 PhysicalAddress - 0, // UINT32 Reserved - FixedPcdGet32 (PcdArmArchTimerSecIntrNum), // UINT32 SecurePL1TimerGSIV - GTDT_GTIMER_FLAGS, // UINT32 SecurePL1TimerFlags - FixedPcdGet32 (PcdArmArchTimerIntrNum), // UINT32 NonSecurePL1TimerGSIV - GTDT_GTIMER_FLAGS, // UINT32 NonSecurePL1TimerFlags - FixedPcdGet32 (PcdArmArchTimerVirtIntrNum), // UINT32 VirtualTimerGSIV - GTDT_GTIMER_FLAGS, // UINT32 VirtualTimerFlags - FixedPcdGet32 (PcdArmArchTimerHypIntrNum), // UINT32 NonSecurePL2TimerGSIV - GTDT_GTIMER_FLAGS, // UINT32 NonSecurePL2TimerFlags - 0xFFFFFFFFFFFFFFFF, // UINT64 CntReadBasePhysicalAddress - 0, // UINT32 PlatformTimerCount - 0 - }, + GENERIC_TIMER_DESCRIPTION_TABLES Gtdt = { + { + SBSAQEMU_ACPI_HEADER( + EFI_ACPI_6_3_GENERIC_TIMER_DESCRIPTION_TABLE_SIGNATURE, + GENERIC_TIMER_DESCRIPTION_TABLES, + EFI_ACPI_6_3_GENERIC_TIMER_DESCRIPTION_TABLE_REVISION + ), + SYSTEM_TIMER_BASE_ADDRESS, // UINT64 PhysicalAddress + 0, // UINT32 Reserved + FixedPcdGet32 (PcdArmArchTimerSecIntrNum), // UINT32 SecurePL1TimerGSIV + GTDT_GTIMER_FLAGS, // UINT32 SecurePL1TimerFlags + FixedPcdGet32 (PcdArmArchTimerIntrNum), // UINT32 NonSecurePL1TimerGSIV + GTDT_GTIMER_FLAGS, // UINT32 NonSecurePL1TimerFlags + FixedPcdGet32 (PcdArmArchTimerVirtIntrNum), // UINT32 VirtualTimerGSIV + GTDT_GTIMER_FLAGS, // UINT32 VirtualTimerFlags + FixedPcdGet32 (PcdArmArchTimerHypIntrNum), // UINT32 NonSecurePL2TimerGSIV + GTDT_GTIMER_FLAGS, // UINT32 NonSecurePL2TimerFlags + 0xFFFFFFFFFFFFFFFF, // UINT64 CntReadBasePhysicalAddress + SBSA_PLATFORM_TIMER_COUNT, // UINT32 PlatformTimerCount + sizeof(EFI_ACPI_6_3_GENERIC_TIMER_DESCRIPTION_TABLE), + // UINT32 PlatformTimerOffset + 0, // UINT32 VirtualPL2TimerGSIV + 0 // UINT32 VirtualPL2TimerFlags + }, + EFI_ACPI_6_3_SBSA_GENERIC_WATCHDOG_STRUCTURE_INIT( + SBSAQEMU_WDT_REFRESH_FRAME_BASE, + SBSAQEMU_WDT_CONTROL_FRAME_BASE, + SBSAQEMU_WDT_IRQ, + GTDT_WDTIMER_FLAGS + ) }; // Reference the table being generated to prevent the optimizer from removing the -- 2.18.4
|
|||
|
|||
[PATCH v3 0/1] Add SBSA-wdt entry to GTDT
Shashi Mallela
To enable detection of qemu SBSA generic watchdog timer device,this
patch has been added to create sbsa-wdt entry into the GTDT table which helps firmware report the presence of SBSA-wdt to the OS. Changes in v3: - fixed typo from earlier patch which was resulting in build failure - confirmed the overall functionality using latest build and testing with related qemu code for sbsa wdt Shashi Mallela (1): Silicon/Qemu/Sbsa: Add SBSA-wdt entry to GTDT Silicon/Qemu/SbsaQemu/AcpiTables/Gtdt.aslc | 87 ++++++++++++++------ 1 file changed, 62 insertions(+), 25 deletions(-) -- 2.18.4
|
|||
|
|||
[PATCH 1/1] uefi-sct/SctPkg: NULL deref in DevicePathToText test
Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=3D3029
Function DevicePathToTextConvertDeviceNodeToTextCoverageTest() tests if DeviceNodeToText() correctly converts a Relative Offset Range node. After calling SctConvertTextToDeviceNode() it tries to set the field Reserved of the returned device node to 0. If the tested firmware does not return the expected text SctConvertTextToDeviceNode() may return NULL or a device node that is shorter than expected. In both cases it is not possible to access the field Reserved. So we must check both that the returned node is not NULL and that it has the exepected size. Due to the missing check a NULL dereference was observed when running the SCT on U-Boot. Signed-off-by: Heinrich Schuchardt <xypron.glpk@...> --- .../BlackBoxTest/DevicePathToTextBBTestCoverage.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/uefi-sct/SctPkg/TestCase/UEFI/EFI/Protocol/DevicePathToText/Bl= ackBoxTest/DevicePathToTextBBTestCoverage.c b/uefi-sct/SctPkg/TestCase/UEFI= /EFI/Protocol/DevicePathToText/BlackBoxTest/DevicePathToTextBBTestCoverage.c index ee91bdfb..784d4748 100644 --- a/uefi-sct/SctPkg/TestCase/UEFI/EFI/Protocol/DevicePathToText/BlackBoxT= est/DevicePathToTextBBTestCoverage.c +++ b/uefi-sct/SctPkg/TestCase/UEFI/EFI/Protocol/DevicePathToText/BlackBoxT= est/DevicePathToTextBBTestCoverage.c @@ -1198,8 +1198,12 @@ DevicePathToTextConvertDeviceNodeToTextCoverageTest ( ((MEDIA_OFFSET_DEVICE_PATH *)pDeviceNode1)->EndingOffset =3D 0x1234;=0D Text =3D DevicePathToText->ConvertDeviceNodeToText (pDeviceNode1, FALSE,= FALSE);=0D pDeviceNode2 =3D SctConvertTextToDeviceNode(Text);=0D - ((MEDIA_OFFSET_DEVICE_PATH *)pDeviceNode2)->Reserved =3D 0;=0D -=0D + SctPrint(L"pDeviceNode2 =3D %p\n", pDeviceNode2);=0D + if (pDeviceNode2 &&=0D + ((MEDIA_OFFSET_DEVICE_PATH *)pDeviceNode2)->Length =3D=3D=0D + sizeof(MEDIA_OFFSET_DEVICE_PATH)) {=0D + ((MEDIA_OFFSET_DEVICE_PATH *)pDeviceNode2)->Reserved =3D 0;=0D + }=0D if ((pDeviceNode2 !=3D NULL) && (SctCompareMem (pDeviceNode2, pDeviceNod= e1, SctDevicePathNodeLength(pDeviceNode1)) =3D=3D 0)) {=0D AssertionType =3D EFI_TEST_ASSERTION_PASSED;=0D } else {=0D --=20 2.28.0
|
|||
|
|||
Why is MAX_LONG_FILE_PATH 500 vs. PATH_MAX?
Does anyone know why MAX_LONG_FILE_PATH [1] is hard coded to 500 vs. using the systems PATH_MAX? On Linux I think PATH_MAX is 4KiB and on macOS it is 1KiB. Thanks, Andrew Fish
|
|||
|
|||
[edk2-test]
Arpan Mukherjee <arpanbzs@...>
Not able to build SctPkg using UDK2017 for X64 architecture in Linux(ubuntu). In SctPkg/build.sh. Showing COMPONENT_TYPE not given. Here is the log. . SctPkg/build.sh X64 GCC Target: X64 Build: other Unsupported target architecture 'X64'! TOOLCHAIN is GCC49 Toolchain prefix: GCC49_X64_PREFIX= Building from: /home/xilinx/arpanm/edk2-vUDK2017 using prebuilt tools Building GenBin make: Entering directory '/home/xilinx/arpanm/edk2-vUDK2017/SctPkg/Tools/Source/GenBin' Attempting to detect ARCH from 'uname -m': x86_64 Detected ARCH of X64 using uname. make: Warning: File '/home/xilinx/arpanm/edk2-vUDK2017/BaseTools/Source/C/Makefiles/footer.makefile' has modification time 40845275 s in the future gcc -c -MD -fshort-wchar -fno-strict-aliasing -Wall -Werror -Wno-deprecated-declarations -Wno-unused-result -nostdlib -c -g -I /home/xilinx/arpanm/edk2-vUDK2017/BaseTools/Source/C -I /home/xilinx/arpanm/edk2-vUDK2017/BaseTools/Source/C/Include/Common -I /home/xilinx/arpanm/edk2-vUDK2017/BaseTools/Source/C/Include/ -I /home/xilinx/arpanm/edk2-vUDK2017/BaseTools/Source/C/Include/IndustryStandard -I /home/xilinx/arpanm/edk2-vUDK2017/BaseTools/Source/C/Common/ -I .. -I . -I /home/xilinx/arpanm/edk2-vUDK2017/BaseTools/Source/C/Include/X64/ -O2 GenBin.c -o GenBin.o gcc -o /home/xilinx/arpanm/edk2-vUDK2017/BaseTools/Source/C/bin/GenBin GenBin.o -L/home/xilinx/arpanm/edk2-vUDK2017/BaseTools/Source/C/libs make: warning: Clock skew detected. Your build may be incomplete. make: Leaving directory '/home/xilinx/arpanm/edk2-vUDK2017/SctPkg/Tools/Source/GenBin' Build environment: Linux-4.15.0-99-generic-x86_64-with-Ubuntu-16.04-xenial Build start time: 20:01:29, Feb.26 2016 WORKSPACE = /home/xilinx/arpanm/edk2-vUDK2017 ECP_SOURCE = /home/xilinx/arpanm/edk2-vUDK2017/EdkCompatibilityPkg EDK_SOURCE = /home/xilinx/arpanm/edk2-vUDK2017/EdkCompatibilityPkg EFI_SOURCE = /home/xilinx/arpanm/edk2-vUDK2017 EDK_TOOLS_PATH = /home/xilinx/arpanm/edk2-vUDK2017/BaseTools CONF_PATH = /home/xilinx/arpanm/edk2-vUDK2017/Conf Architecture(s) = X64 Build target = DEBUG Toolchain = GCC49 Active Platform = /home/xilinx/arpanm/edk2-vUDK2017/SctPkg/UEFI/UEFI_SCT.dsc Processing meta-data .. build.py... /home/xilinx/arpanm/edk2-vUDK2017/SctPkg/TestCase/UEFI/EFI/BootServices/ImageServices/BlackBoxTest/Dependency/InvalidImage1/InvalidImage1.inf(...): error 5000: COMPONENT_TYPE is not given - Failed - Build end time: 20:01:32, Feb.26 2016 Build total time: 00:00:03 Could not build the UEFI SCT package Please help in resolving the issue. Thanks and regards Arpan Mukherjee 5th-year Dual Degree student Instrumentation and Signal Processing Dept. of Electrical Engineering IIT Kharagpur
![]()
|
|||
|
|||
Re: [PATCH 0/5] Make the MD5 disable as default setting
Feng, Roger <roger.feng@...>
+Qi for review
toggle quoted messageShow quoted text
-----Original Message-----
From: Gao, Zhichao <zhichao.gao@...> Sent: Tuesday, October 27, 2020 8:55 AM To: Yao, Jiewen <jiewen.yao@...>; devel@edk2.groups.io Cc: Justen, Jordan L <jordan.l.justen@...>; Laszlo Ersek <lersek@...>; Ard Biesheuvel <ard.biesheuvel@...>; Sami Mujawar <sami.mujawar@...>; Leif Lindholm <leif@...>; Wang, Jian J <jian.j.wang@...>; Lu, XiaoyuX <xiaoyux.lu@...>; Jiang, Guomin <guomin.jiang@...>; Kinney, Michael D <michael.d.kinney@...>; Steele, Kelly <kelly.steele@...>; Sun, Zailiang <zailiang.sun@...>; Qian, Yi <yi.qian@...>; Liming Gao <gaoliming@...>; Maciej Rabeda <maciej.rabeda@...>; Wu, Jiaxin <jiaxin.wu@...>; Fu, Siyuan <siyuan.fu@...>; Feng, Roger <roger.feng@...> Subject: RE: [PATCH 0/5] Make the MD5 disable as default setting Let me prepare the V2 to remove them(MD5 and SHA1)。 Thanks, Zhichao -----Original Message-----
|
|||
|
|||
Cancelled Event: TianoCore Design Meeting - APAC/NAMO - Friday, 30 October 2020
#cal-cancelled
devel@edk2.groups.io Calendar <noreply@...>
Cancelled: TianoCore Design Meeting - APAC/NAMO This event has been cancelled. When: Where: Organizer: Ray Ni ray.ni@... Description: TOPIC
For more info, see here: https://www.tianocore.org/design-meeting/ Join Webex MeetingMeeting number: 130 073 1007 Password: MguMnPN@422 https://intel.webex.com/intel/j.php?MTID=m6bf2875d89c1ee88ca37eda8fd41a47b Join by video system Dial 1300731007@... You can also dial 173.243.2.68 and enter your meeting number. Join by phone +1-210-795-1110 US Toll +1-866-662-9987 US Toll Free Access code: 130 073 1007 (Webex can be downloaded from https://www.webex.com/downloads.html/.)
|
|||
|
|||
Re: [EFI Redfish Host Interface PATCH 5/5] RedfishPkg: Add RedfishHostInterfaceDxe to RedfishPkg
toggle quoted messageShow quoted text
-----Original Message-----Yes, we have to list the library provided by this package in [Components] section, CI also checks this.
|
|||
|
|||
Re: [DxeHttpIoLib PATCH V3 1/3] NetworkPkg/Library: Implementation of Http IO Helper Library
toggle quoted messageShow quoted text
-----Original Message-----That's no problem Maciej. V4 is sent and some feedbacks to your comments in line. Done. Done+ MessageBody = AllocatePool (AsciiStrLen (ChunkLengthStr) +MessageBodyLength + 2);+ if (MessageBody == NULL) {transfer\n")); Fixed.+ CopyMem (MessageBody + AsciiStrLen (ChunkLengthStr),RequestMessage->Body, MessageBodyLength);+ *(MessageBody + AsciiStrLen (ChunkLengthStr) + MessageBodyLength)= CHUNKED_TRANSFER_CODING_CR;+ *(MessageBody + AsciiStrLen (ChunkLengthStr) + MessageBodyLength+ 1) = CHUNKED_TRANSFER_CODING_LF;+ //transfer\n")); Sure. additional checking is added. Thanks for this feedback.+ //sizeof(HTTP_IO_RESPONSE_DATA)); ResponseData.BodyLength is given by *ContentLength and HttpIoRecvResponse only copies data read from TCP in ResponseData.BodyLength to ResponseData.Body.+ ThisChunk->Data = (CHAR8 *)AllocatePool (ThisChunk->Length);+ 1, ThisChunk->Length); Furthermore, If *ContentLength is huge but the response payload is returned in the same length, then we can just trust it with the checking the end "\r\n" of chunk payload. If *ContentLength is larger than the response payload can be returned by HTTP service then HttpIoRecvResponse suppose returns timeout or some other EFI errors. Then we exit chunk function with error code. If *ContentLength is smaller than the response payload returned by HTTP service, the checking of end "\r\n" of chunk payload will be failed. But this case shouldn't happen in HttpIoRecvResponse function. Currently we read the end "\r\n" of chunk payload however we don’t verify it. To add additional check on end "\r\n" of chunk at least can make sure the chunk is correct. Make sense? You can check v4 patch set for the corresponding changes. Done+ //(HTTP_IO_CHUNKS)); Done+TotalLength)); + FreePool (HttpChunks);DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION
|
|||
|
|||
[DxeHttpIoLib PATCH V4 3/3] NetworkPkg/HttpBootDxe: Utilize HttpIoLib
Remove HTTP IO realted funcitons from HttpBootDxe
and use HttpIoLib instead. Signed-off-by: Abner Chang <abner.chang@...> Cc: Maciej Rabeda <maciej.rabeda@...> Cc: Jiaxin Wu <jiaxin.wu@...> Cc: Siyuan Fu <siyuan.fu@...> Cc: Nickle Wang <nickle.wang@...> --- NetworkPkg/HttpBootDxe/HttpBootDxe.h | 3 +- NetworkPkg/HttpBootDxe/HttpBootDxe.inf | 2 + NetworkPkg/HttpBootDxe/HttpBootSupport.c | 431 +---------------------- NetworkPkg/HttpBootDxe/HttpBootSupport.h | 189 +--------- 4 files changed, 6 insertions(+), 619 deletions(-) diff --git a/NetworkPkg/HttpBootDxe/HttpBootDxe.h b/NetworkPkg/HttpBootDxe/HttpBootDxe.h index 0b45f9de0b..d692c3ad3c 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootDxe.h +++ b/NetworkPkg/HttpBootDxe/HttpBootDxe.h @@ -2,7 +2,7 @@ UEFI HTTP boot driver's private data structure and interfaces declaration. Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR> -(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR> +(C) Copyright 2016 - 2020 Hewlett Packard Enterprise Development LP<BR> SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -28,6 +28,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include <Library/DebugLib.h> #include <Library/NetLib.h> #include <Library/HttpLib.h> +#include <Library/HttpIoLib.h> #include <Library/HiiLib.h> #include <Library/PrintLib.h> #include <Library/DpcLib.h> diff --git a/NetworkPkg/HttpBootDxe/HttpBootDxe.inf b/NetworkPkg/HttpBootDxe/HttpBootDxe.inf index 5beab728dd..a27a561722 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootDxe.inf +++ b/NetworkPkg/HttpBootDxe/HttpBootDxe.inf @@ -2,6 +2,7 @@ # This modules produce the Load File Protocol for UEFI HTTP boot. # # Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR> +# (C) Copyright 2020 Hewlett-Packard Development Company, L.P.<BR> # SPDX-License-Identifier: BSD-2-Clause-Patent # ## @@ -52,6 +53,7 @@ DebugLib NetLib HttpLib + HttpIoLib HiiLib PrintLib DpcLib diff --git a/NetworkPkg/HttpBootDxe/HttpBootSupport.c b/NetworkPkg/HttpBootDxe/HttpBootSupport.c index 5b0e054a05..93d9dfc464 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootSupport.c +++ b/NetworkPkg/HttpBootDxe/HttpBootSupport.c @@ -2,7 +2,7 @@ Support functions implementation for UEFI HTTP boot driver. Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR> -(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR> +(C) Copyright 2016 - 2020 Hewlett Packard Enterprise Development LP<BR> SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -622,435 +622,6 @@ HttpBootSetHeader ( return EFI_SUCCESS; } -/** - Notify the callback function when an event is triggered. - - @param[in] Context The opaque parameter to the function. - -**/ -VOID -EFIAPI -HttpIoNotifyDpc ( - IN VOID *Context - ) -{ - *((BOOLEAN *) Context) = TRUE; -} - -/** - Request HttpIoNotifyDpc as a DPC at TPL_CALLBACK. - - @param[in] Event The event signaled. - @param[in] Context The opaque parameter to the function. - -**/ -VOID -EFIAPI -HttpIoNotify ( - IN EFI_EVENT Event, - IN VOID *Context - ) -{ - // - // Request HttpIoNotifyDpc as a DPC at TPL_CALLBACK - // - QueueDpc (TPL_CALLBACK, HttpIoNotifyDpc, Context); -} - -/** - Create a HTTP_IO to access the HTTP service. It will create and configure - a HTTP child handle. - - @param[in] Image The handle of the driver image. - @param[in] Controller The handle of the controller. - @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6. - @param[in] ConfigData The HTTP_IO configuration data. - @param[in] Callback Callback function which will be invoked when specified - HTTP_IO_CALLBACK_EVENT happened. - @param[in] Context The Context data which will be passed to the Callback function. - @param[out] HttpIo The HTTP_IO. - - @retval EFI_SUCCESS The HTTP_IO is created and configured. - @retval EFI_INVALID_PARAMETER One or more parameters are invalid. - @retval EFI_UNSUPPORTED One or more of the control options are not - supported in the implementation. - @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. - @retval Others Failed to create the HTTP_IO or configure it. - -**/ -EFI_STATUS -HttpIoCreateIo ( - IN EFI_HANDLE Image, - IN EFI_HANDLE Controller, - IN UINT8 IpVersion, - IN HTTP_IO_CONFIG_DATA *ConfigData, - IN HTTP_IO_CALLBACK Callback, - IN VOID *Context, - OUT HTTP_IO *HttpIo - ) -{ - 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; - - if ((Image == NULL) || (Controller == NULL) || (ConfigData == NULL) || (HttpIo == NULL)) { - return EFI_INVALID_PARAMETER; - } - - if (IpVersion != IP_VERSION_4 && IpVersion != IP_VERSION_6) { - return EFI_UNSUPPORTED; - } - - ZeroMem (HttpIo, sizeof (HTTP_IO)); - - // - // Create the HTTP child instance and get the HTTP protocol. - // - Status = NetLibCreateServiceChild ( - Controller, - Image, - &gEfiHttpServiceBindingProtocolGuid, - &HttpIo->Handle - ); - if (EFI_ERROR (Status)) { - return Status; - } - - Status = gBS->OpenProtocol ( - HttpIo->Handle, - &gEfiHttpProtocolGuid, - (VOID **) &Http, - Image, - Controller, - EFI_OPEN_PROTOCOL_BY_DRIVER - ); - if (EFI_ERROR (Status) || (Http == NULL)) { - goto ON_ERROR; - } - - // - // Init the configuration data and configure the HTTP child. - // - HttpIo->Image = Image; - HttpIo->Controller = Controller; - HttpIo->IpVersion = IpVersion; - HttpIo->Http = Http; - HttpIo->Callback = Callback; - HttpIo->Context = Context; - - ZeroMem (&HttpConfigData, sizeof (EFI_HTTP_CONFIG_DATA)); - HttpConfigData.HttpVersion = HttpVersion11; - HttpConfigData.TimeOutMillisec = ConfigData->Config4.RequestTimeOut; - if (HttpIo->IpVersion == IP_VERSION_4) { - HttpConfigData.LocalAddressIsIPv6 = FALSE; - - Http4AccessPoint.UseDefaultAddress = ConfigData->Config4.UseDefaultAddress; - Http4AccessPoint.LocalPort = ConfigData->Config4.LocalPort; - IP4_COPY_ADDRESS (&Http4AccessPoint.LocalAddress, &ConfigData->Config4.LocalIp); - IP4_COPY_ADDRESS (&Http4AccessPoint.LocalSubnet, &ConfigData->Config4.SubnetMask); - HttpConfigData.AccessPoint.IPv4Node = &Http4AccessPoint; - } else { - 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); - if (EFI_ERROR (Status)) { - goto ON_ERROR; - } - - // - // Create events for various asynchronous operations. - // - Status = gBS->CreateEvent ( - EVT_NOTIFY_SIGNAL, - TPL_NOTIFY, - HttpIoNotify, - &HttpIo->IsTxDone, - &Event - ); - if (EFI_ERROR (Status)) { - goto ON_ERROR; - } - HttpIo->ReqToken.Event = Event; - HttpIo->ReqToken.Message = &HttpIo->ReqMessage; - - Status = gBS->CreateEvent ( - EVT_NOTIFY_SIGNAL, - TPL_NOTIFY, - HttpIoNotify, - &HttpIo->IsRxDone, - &Event - ); - if (EFI_ERROR (Status)) { - goto ON_ERROR; - } - HttpIo->RspToken.Event = Event; - HttpIo->RspToken.Message = &HttpIo->RspMessage; - - // - // Create TimeoutEvent for response - // - Status = gBS->CreateEvent ( - EVT_TIMER, - TPL_CALLBACK, - NULL, - NULL, - &Event - ); - if (EFI_ERROR (Status)) { - goto ON_ERROR; - } - HttpIo->TimeoutEvent = Event; - - return EFI_SUCCESS; - -ON_ERROR: - HttpIoDestroyIo (HttpIo); - - return Status; -} - -/** - Destroy the HTTP_IO and release the resources. - - @param[in] HttpIo The HTTP_IO which wraps the HTTP service to be destroyed. - -**/ -VOID -HttpIoDestroyIo ( - IN HTTP_IO *HttpIo - ) -{ - EFI_HTTP_PROTOCOL *Http; - EFI_EVENT Event; - - if (HttpIo == NULL) { - return; - } - - Event = HttpIo->ReqToken.Event; - if (Event != NULL) { - gBS->CloseEvent (Event); - } - - Event = HttpIo->RspToken.Event; - if (Event != NULL) { - gBS->CloseEvent (Event); - } - - Event = HttpIo->TimeoutEvent; - if (Event != NULL) { - gBS->CloseEvent (Event); - } - - Http = HttpIo->Http; - if (Http != NULL) { - Http->Configure (Http, NULL); - gBS->CloseProtocol ( - HttpIo->Handle, - &gEfiHttpProtocolGuid, - HttpIo->Image, - HttpIo->Controller - ); - } - - NetLibDestroyServiceChild ( - HttpIo->Controller, - HttpIo->Image, - &gEfiHttpServiceBindingProtocolGuid, - HttpIo->Handle - ); -} - -/** - Synchronously send a HTTP REQUEST message to the server. - - @param[in] HttpIo The HttpIo wrapping the HTTP service. - @param[in] Request A pointer to storage such data as URL and HTTP method. - @param[in] HeaderCount Number of HTTP header structures in Headers list. - @param[in] Headers Array containing list of HTTP headers. - @param[in] BodyLength Length in bytes of the HTTP body. - @param[in] Body Body associated with the HTTP request. - - @retval EFI_SUCCESS The HTTP request is transmitted. - @retval EFI_INVALID_PARAMETER One or more parameters are invalid. - @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. - @retval EFI_DEVICE_ERROR An unexpected network or system error occurred. - @retval Others Other errors as indicated. - -**/ -EFI_STATUS -HttpIoSendRequest ( - IN HTTP_IO *HttpIo, - IN EFI_HTTP_REQUEST_DATA *Request, - IN UINTN HeaderCount, - IN EFI_HTTP_HEADER *Headers, - IN UINTN BodyLength, - IN VOID *Body - ) -{ - EFI_STATUS Status; - EFI_HTTP_PROTOCOL *Http; - - if (HttpIo == NULL || HttpIo->Http == NULL) { - return EFI_INVALID_PARAMETER; - } - - HttpIo->ReqToken.Status = EFI_NOT_READY; - HttpIo->ReqToken.Message->Data.Request = Request; - HttpIo->ReqToken.Message->HeaderCount = HeaderCount; - HttpIo->ReqToken.Message->Headers = Headers; - HttpIo->ReqToken.Message->BodyLength = BodyLength; - HttpIo->ReqToken.Message->Body = Body; - - if (HttpIo->Callback != NULL) { - Status = HttpIo->Callback ( - HttpIoRequest, - HttpIo->ReqToken.Message, - HttpIo->Context - ); - if (EFI_ERROR (Status)) { - return Status; - } - } - - // - // Queue the request token to HTTP instances. - // - Http = HttpIo->Http; - HttpIo->IsTxDone = FALSE; - Status = Http->Request ( - Http, - &HttpIo->ReqToken - ); - if (EFI_ERROR (Status)) { - return Status; - } - - // - // Poll the network until transmit finish. - // - while (!HttpIo->IsTxDone) { - Http->Poll (Http); - } - - return HttpIo->ReqToken.Status; -} - -/** - Synchronously receive a HTTP RESPONSE message from the server. - - @param[in] HttpIo The HttpIo wrapping the HTTP service. - @param[in] RecvMsgHeader TRUE to receive a new HTTP response (from message header). - FALSE to continue receive the previous response message. - @param[out] ResponseData Point to a wrapper of the received response data. - - @retval EFI_SUCCESS The HTTP response is received. - @retval EFI_INVALID_PARAMETER One or more parameters are invalid. - @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. - @retval EFI_DEVICE_ERROR An unexpected network or system error occurred. - @retval Others Other errors as indicated. - -**/ -EFI_STATUS -HttpIoRecvResponse ( - IN HTTP_IO *HttpIo, - IN BOOLEAN RecvMsgHeader, - OUT HTTP_IO_RESPONSE_DATA *ResponseData - ) -{ - EFI_STATUS Status; - EFI_HTTP_PROTOCOL *Http; - - if (HttpIo == NULL || HttpIo->Http == NULL || ResponseData == NULL) { - return EFI_INVALID_PARAMETER; - } - - // - // Start the timer, and wait Timeout seconds to receive the header packet. - // - Status = gBS->SetTimer (HttpIo->TimeoutEvent, TimerRelative, HTTP_BOOT_RESPONSE_TIMEOUT * TICKS_PER_MS); - if (EFI_ERROR (Status)) { - return Status; - } - - // - // Queue the response token to HTTP instances. - // - HttpIo->RspToken.Status = EFI_NOT_READY; - if (RecvMsgHeader) { - HttpIo->RspToken.Message->Data.Response = &ResponseData->Response; - } else { - HttpIo->RspToken.Message->Data.Response = NULL; - } - HttpIo->RspToken.Message->HeaderCount = 0; - HttpIo->RspToken.Message->Headers = NULL; - HttpIo->RspToken.Message->BodyLength = ResponseData->BodyLength; - HttpIo->RspToken.Message->Body = ResponseData->Body; - - Http = HttpIo->Http; - HttpIo->IsRxDone = FALSE; - Status = Http->Response ( - Http, - &HttpIo->RspToken - ); - - if (EFI_ERROR (Status)) { - gBS->SetTimer (HttpIo->TimeoutEvent, TimerCancel, 0); - return Status; - } - - // - // Poll the network until receive finish. - // - while (!HttpIo->IsRxDone && ((HttpIo->TimeoutEvent == NULL) || EFI_ERROR (gBS->CheckEvent (HttpIo->TimeoutEvent)))) { - Http->Poll (Http); - } - - gBS->SetTimer (HttpIo->TimeoutEvent, TimerCancel, 0); - - if (!HttpIo->IsRxDone) { - // - // Timeout occurs, cancel the response token. - // - Http->Cancel (Http, &HttpIo->RspToken); - - Status = EFI_TIMEOUT; - - return Status; - } else { - HttpIo->IsRxDone = FALSE; - } - - if ((HttpIo->Callback != NULL) && - (HttpIo->RspToken.Status == EFI_SUCCESS || HttpIo->RspToken.Status == EFI_HTTP_ERROR)) { - Status = HttpIo->Callback ( - HttpIoResponse, - HttpIo->RspToken.Message, - HttpIo->Context - ); - if (EFI_ERROR (Status)) { - return Status; - } - } - - // - // Store the received data into the wrapper. - // - ResponseData->Status = HttpIo->RspToken.Status; - ResponseData->HeaderCount = HttpIo->RspToken.Message->HeaderCount; - ResponseData->Headers = HttpIo->RspToken.Message->Headers; - ResponseData->BodyLength = HttpIo->RspToken.Message->BodyLength; - - return Status; -} - /** This function checks the HTTP(S) URI scheme. diff --git a/NetworkPkg/HttpBootDxe/HttpBootSupport.h b/NetworkPkg/HttpBootDxe/HttpBootSupport.h index 81d072ae37..1a2d32dd5a 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootSupport.h +++ b/NetworkPkg/HttpBootDxe/HttpBootSupport.h @@ -2,6 +2,7 @@ Support functions declaration for UEFI HTTP boot driver. Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR> +(C) Copyright 2020 Hewlett-Packard Development Company, L.P.<BR> SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -139,102 +140,6 @@ HttpBootSetHeader ( IN CHAR8 *FieldValue ); -/// -/// HTTP_IO_CALLBACK_EVENT -/// -typedef enum { - HttpIoRequest, - HttpIoResponse -} HTTP_IO_CALLBACK_EVENT; - -/** - HttpIo Callback function which will be invoked when specified HTTP_IO_CALLBACK_EVENT happened. - - @param[in] EventType Indicate the Event type that occurs in the current callback. - @param[in] Message HTTP message which will be send to, or just received from HTTP server. - @param[in] Context The Callback Context pointer. - - @retval EFI_SUCCESS Tells the HttpIo to continue the HTTP process. - @retval Others Tells the HttpIo to abort the current HTTP process. -**/ -typedef -EFI_STATUS -(EFIAPI * HTTP_IO_CALLBACK) ( - IN HTTP_IO_CALLBACK_EVENT EventType, - IN EFI_HTTP_MESSAGE *Message, - IN VOID *Context - ); - -// -// HTTP_IO configuration data for IPv4 -// -typedef struct { - EFI_HTTP_VERSION HttpVersion; - UINT32 RequestTimeOut; // In milliseconds. - UINT32 ResponseTimeOut; // In milliseconds. - BOOLEAN UseDefaultAddress; - EFI_IPv4_ADDRESS LocalIp; - EFI_IPv4_ADDRESS SubnetMask; - 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; - -// -// HTTP_IO wrapper of the EFI HTTP service. -// -typedef struct { - UINT8 IpVersion; - EFI_HANDLE Image; - EFI_HANDLE Controller; - EFI_HANDLE Handle; - - EFI_HTTP_PROTOCOL *Http; - - HTTP_IO_CALLBACK Callback; - VOID *Context; - - EFI_HTTP_TOKEN ReqToken; - EFI_HTTP_MESSAGE ReqMessage; - EFI_HTTP_TOKEN RspToken; - EFI_HTTP_MESSAGE RspMessage; - - BOOLEAN IsTxDone; - BOOLEAN IsRxDone; - - EFI_EVENT TimeoutEvent; -} HTTP_IO; - -// -// A wrapper structure to hold the received HTTP response data. -// -typedef struct { - EFI_HTTP_RESPONSE_DATA Response; - UINTN HeaderCount; - EFI_HTTP_HEADER *Headers; - UINTN BodyLength; - CHAR8 *Body; - EFI_STATUS Status; -} HTTP_IO_RESPONSE_DATA; - /** Retrieve the host address using the EFI_DNS6_PROTOCOL. @@ -267,98 +172,6 @@ HttpBootCommonNotify ( IN VOID *Context ); -/** - Create a HTTP_IO to access the HTTP service. It will create and configure - a HTTP child handle. - - @param[in] Image The handle of the driver image. - @param[in] Controller The handle of the controller. - @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6. - @param[in] ConfigData The HTTP_IO configuration data. - @param[in] Callback Callback function which will be invoked when specified - HTTP_IO_CALLBACK_EVENT happened. - @param[in] Context The Context data which will be passed to the Callback function. - @param[out] HttpIo The HTTP_IO. - - @retval EFI_SUCCESS The HTTP_IO is created and configured. - @retval EFI_INVALID_PARAMETER One or more parameters are invalid. - @retval EFI_UNSUPPORTED One or more of the control options are not - supported in the implementation. - @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. - @retval Others Failed to create the HTTP_IO or configure it. - -**/ -EFI_STATUS -HttpIoCreateIo ( - IN EFI_HANDLE Image, - IN EFI_HANDLE Controller, - IN UINT8 IpVersion, - IN HTTP_IO_CONFIG_DATA *ConfigData, - IN HTTP_IO_CALLBACK Callback, - IN VOID *Context, - OUT HTTP_IO *HttpIo - ); - -/** - Destroy the HTTP_IO and release the resources. - - @param[in] HttpIo The HTTP_IO which wraps the HTTP service to be destroyed. - -**/ -VOID -HttpIoDestroyIo ( - IN HTTP_IO *HttpIo - ); - -/** - Synchronously send a HTTP REQUEST message to the server. - - @param[in] HttpIo The HttpIo wrapping the HTTP service. - @param[in] Request A pointer to storage such data as URL and HTTP method. - @param[in] HeaderCount Number of HTTP header structures in Headers list. - @param[in] Headers Array containing list of HTTP headers. - @param[in] BodyLength Length in bytes of the HTTP body. - @param[in] Body Body associated with the HTTP request. - - @retval EFI_SUCCESS The HTTP request is transmitted. - @retval EFI_INVALID_PARAMETER One or more parameters are invalid. - @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. - @retval EFI_DEVICE_ERROR An unexpected network or system error occurred. - @retval Others Other errors as indicated. - -**/ -EFI_STATUS -HttpIoSendRequest ( - IN HTTP_IO *HttpIo, - IN EFI_HTTP_REQUEST_DATA *Request, OPTIONAL - IN UINTN HeaderCount, - IN EFI_HTTP_HEADER *Headers, OPTIONAL - IN UINTN BodyLength, - IN VOID *Body OPTIONAL - ); - -/** - Synchronously receive a HTTP RESPONSE message from the server. - - @param[in] HttpIo The HttpIo wrapping the HTTP service. - @param[in] RecvMsgHeader TRUE to receive a new HTTP response (from message header). - FALSE to continue receive the previous response message. - @param[out] ResponseData Point to a wrapper of the received response data. - - @retval EFI_SUCCESS The HTTP response is received. - @retval EFI_INVALID_PARAMETER One or more parameters are invalid. - @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. - @retval EFI_DEVICE_ERROR An unexpected network or system error occurred. - @retval Others Other errors as indicated. - -**/ -EFI_STATUS -HttpIoRecvResponse ( - IN HTTP_IO *HttpIo, - IN BOOLEAN RecvMsgHeader, - OUT HTTP_IO_RESPONSE_DATA *ResponseData - ); - /** This function checks the HTTP(S) URI scheme. -- 2.17.1
|
|||
|
|||
[DxeHttpIoLib PATCH V4 1/3] NetworkPkg/Library: Implementation of Http IO Helper Library
Add HTTP IO helper library which could be used by HTTP applications
such as HTTP Boot, Redfish HTTP REST EX driver instance and etc. Signed-off-by: Abner Chang <abner.chang@...> Cc: Maciej Rabeda <maciej.rabeda@...> Cc: Jiaxin Wu <jiaxin.wu@...> Cc: Siyuan Fu <siyuan.fu@...> Cc: Nickle Wang <nickle.wang@...> --- NetworkPkg/Include/Library/HttpIoLib.h | 328 +++++++ .../Library/DxeHttpIoLib/DxeHttpIoLib.c | 847 ++++++++++++++++++ .../Library/DxeHttpIoLib/DxeHttpIoLib.inf | 43 + .../Library/DxeHttpIoLib/DxeHttpIoLib.uni | 13 + 4 files changed, 1231 insertions(+) create mode 100644 NetworkPkg/Include/Library/HttpIoLib.h create mode 100644 NetworkPkg/Library/DxeHttpIoLib/DxeHttpIoLib.c create mode 100644 NetworkPkg/Library/DxeHttpIoLib/DxeHttpIoLib.inf create mode 100644 NetworkPkg/Library/DxeHttpIoLib/DxeHttpIoLib.uni diff --git a/NetworkPkg/Include/Library/HttpIoLib.h b/NetworkPkg/Include/Library/HttpIoLib.h new file mode 100644 index 0000000000..8f3804ca42 --- /dev/null +++ b/NetworkPkg/Include/Library/HttpIoLib.h @@ -0,0 +1,328 @@ +/** @file + HttpIoLib.h. + +(C) Copyright 2020 Hewlett-Packard Development Company, L.P.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef HTTP_IO_LIB_H_ +#define HTTP_IO_LIB_H_ + +#include <IndustryStandard/Http11.h> + +#include <Library/DpcLib.h> +#include <Library/HttpLib.h> +#include <Library/NetLib.h> + +#define HTTP_IO_MAX_SEND_PAYLOAD 1024 +#define HTTP_IO_CHUNK_SIZE_STRING_LEN 50 +#define HTTP_IO_CHUNKED_TRANSFER_CODING_DATA_LENGTH 256 + +/// +/// HTTP_IO_CALLBACK_EVENT +/// +typedef enum { + HttpIoRequest, + HttpIoResponse +} HTTP_IO_CALLBACK_EVENT; + +/** + HttpIo Callback function which will be invoked when specified HTTP_IO_CALLBACK_EVENT happened. + + @param[in] EventType Indicate the Event type that occurs in the current callback. + @param[in] Message HTTP message which will be send to, or just received from HTTP server. + @param[in] Context The Callback Context pointer. + + @retval EFI_SUCCESS Tells the HttpIo to continue the HTTP process. + @retval Others Tells the HttpIo to abort the current HTTP process. +**/ +typedef +EFI_STATUS +(EFIAPI * HTTP_IO_CALLBACK) ( + IN HTTP_IO_CALLBACK_EVENT EventType, + IN EFI_HTTP_MESSAGE *Message, + IN VOID *Context + ); + +/// +/// A wrapper structure to hold the received HTTP response data. +/// +typedef struct { + EFI_HTTP_RESPONSE_DATA Response; + UINTN HeaderCount; + EFI_HTTP_HEADER *Headers; + UINTN BodyLength; + CHAR8 *Body; + EFI_STATUS Status; +} HTTP_IO_RESPONSE_DATA; + +/// +/// HTTP_IO configuration data for IPv4 +/// +typedef struct { + EFI_HTTP_VERSION HttpVersion; + UINT32 RequestTimeOut; ///< In milliseconds. + UINT32 ResponseTimeOut; ///< In milliseconds. + BOOLEAN UseDefaultAddress; + EFI_IPv4_ADDRESS LocalIp; + EFI_IPv4_ADDRESS SubnetMask; + 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; + +/// +/// HTTP_IO wrapper of the EFI HTTP service. +/// +typedef struct { + UINT8 IpVersion; + EFI_HANDLE Image; + EFI_HANDLE Controller; + EFI_HANDLE Handle; + + EFI_HTTP_PROTOCOL *Http; + + HTTP_IO_CALLBACK Callback; + VOID *Context; + + EFI_HTTP_TOKEN ReqToken; + EFI_HTTP_MESSAGE ReqMessage; + EFI_HTTP_TOKEN RspToken; + EFI_HTTP_MESSAGE RspMessage; + + BOOLEAN IsTxDone; + BOOLEAN IsRxDone; + + EFI_EVENT TimeoutEvent; + UINT32 Timeout; +} HTTP_IO; + +/// +/// Process code of HTTP chunk transfer. +/// +typedef enum { + HttpIoSendChunkNone = 0, + HttpIoSendChunkHeaderZeroContent, + HttpIoSendChunkContent, + HttpIoSendChunkEndChunk, + HttpIoSendChunkFinish +} HTTP_IO_SEND_CHUNK_PROCESS; + +/// +/// Process code of HTTP non chunk transfer. +/// +typedef enum { + HttpIoSendNonChunkNone = 0, + HttpIoSendNonChunkHeaderZeroContent, + HttpIoSendNonChunkContent, + HttpIoSendNonChunkFinish +} HTTP_IO_SEND_NON_CHUNK_PROCESS; + +/// +/// Chunk links for HTTP chunked transfer coding. +/// +typedef struct { + LIST_ENTRY NextChunk; + UINTN Length; + CHAR8 *Data; +} HTTP_IO_CHUNKS; + +/** + Notify the callback function when an event is triggered. + + @param[in] Context The opaque parameter to the function. + +**/ +VOID +EFIAPI +HttpIoNotifyDpc ( + IN VOID *Context + ); + +/** + Request HttpIoNotifyDpc as a DPC at TPL_CALLBACK. + + @param[in] Event The event signaled. + @param[in] Context The opaque parameter to the function. + +**/ +VOID +EFIAPI +HttpIoNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +/** + Destroy the HTTP_IO and release the resources. + + @param[in] HttpIo The HTTP_IO which wraps the HTTP service to be destroyed. + +**/ +VOID +HttpIoDestroyIo ( + IN HTTP_IO *HttpIo + ); + +/** + Create a HTTP_IO to access the HTTP service. It will create and configure + a HTTP child handle. + + @param[in] Image The handle of the driver image. + @param[in] Controller The handle of the controller. + @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6. + @param[in] ConfigData The HTTP_IO configuration data. + @param[in] Callback Callback function which will be invoked when specified + HTTP_IO_CALLBACK_EVENT happened. + @param[in] Context The Context data which will be passed to the Callback function. + @param[out] HttpIo The HTTP_IO. + + @retval EFI_SUCCESS The HTTP_IO is created and configured. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_UNSUPPORTED One or more of the control options are not + supported in the implementation. + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. + @retval Others Failed to create the HTTP_IO or configure it. + +**/ +EFI_STATUS +HttpIoCreateIo ( + IN EFI_HANDLE Image, + IN EFI_HANDLE Controller, + IN UINT8 IpVersion, + IN HTTP_IO_CONFIG_DATA *ConfigData, + IN HTTP_IO_CALLBACK Callback, + IN VOID *Context, + OUT HTTP_IO *HttpIo + ); + +/** + Synchronously send a HTTP REQUEST message to the server. + + @param[in] HttpIo The HttpIo wrapping the HTTP service. + @param[in] Request A pointer to storage such data as URL and HTTP method. + @param[in] HeaderCount Number of HTTP header structures in Headers list. + @param[in] Headers Array containing list of HTTP headers. + @param[in] BodyLength Length in bytes of the HTTP body. + @param[in] Body Body associated with the HTTP request. + + @retval EFI_SUCCESS The HTTP request is transmitted. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. + @retval EFI_DEVICE_ERROR An unexpected network or system error occurred. + @retval Others Other errors as indicated. + +**/ +EFI_STATUS +HttpIoSendRequest ( + IN HTTP_IO *HttpIo, + IN EFI_HTTP_REQUEST_DATA *Request, OPTIONAL + IN UINTN HeaderCount, + IN EFI_HTTP_HEADER *Headers, OPTIONAL + IN UINTN BodyLength, + IN VOID *Body OPTIONAL + ); + +/** + Synchronously receive a HTTP RESPONSE message from the server. + + @param[in] HttpIo The HttpIo wrapping the HTTP service. + @param[in] RecvMsgHeader TRUE to receive a new HTTP response (from message header). + FALSE to continue receive the previous response message. + @param[out] ResponseData Point to a wrapper of the received response data. + + @retval EFI_SUCCESS The HTTP response is received. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. + @retval EFI_DEVICE_ERROR An unexpected network or system error occurred. + @retval Others Other errors as indicated. + +**/ +EFI_STATUS +HttpIoRecvResponse ( + IN HTTP_IO *HttpIo, + IN BOOLEAN RecvMsgHeader, + OUT HTTP_IO_RESPONSE_DATA *ResponseData + ); + +/** + Get the value of the content length if there is a "Content-Length" header. + + @param[in] HeaderCount Number of HTTP header structures in Headers. + @param[in] Headers Array containing list of HTTP headers. + @param[out] ContentLength Pointer to save the value of the content length. + + @retval EFI_SUCCESS Successfully get the content length. + @retval EFI_NOT_FOUND No "Content-Length" header in the Headers. + +**/ +EFI_STATUS +HttpIoGetContentLength ( + IN UINTN HeaderCount, + IN EFI_HTTP_HEADER *Headers, + OUT UINTN *ContentLength + ); + +/** + Synchronously receive a HTTP RESPONSE message from the server. + + @param[in] HttpIo The HttpIo wrapping the HTTP service. + @param[in] HeaderCount Number of headers in Headers. + @param[in] Headers Array containing list of HTTP headers. + @param[out] ChunkListHead A pointer to receivce list head of chunked data. + Caller has to release memory of ChunkListHead + and all list entries. + @param[out] ContentLength Total content length + + @retval EFI_SUCCESS The HTTP chunked transfer is received. + @retval EFI_NOT_FOUND No chunked transfer coding header found. + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. + @retval EFI_INVALID_PARAMETER Improper parameters. + @retval Others Other errors as indicated. + +**/ +EFI_STATUS +HttpIoGetChunkedTransferContent ( + IN HTTP_IO *HttpIo, + IN UINTN HeaderCount, + IN EFI_HTTP_HEADER *Headers, + OUT LIST_ENTRY **ChunkListHead, + OUT UINTN *ContentLength + ); + +/** + Send HTTP request in chunks. + + @param[in] HttpIo The HttpIo wrapping the HTTP service. + @param[in] SendChunkProcess Pointer to current chunk process status. + @param[out] RequestMessage Request to send. + + @retval EFI_SUCCESS Successfully to send chunk data according to SendChunkProcess. + @retval Other Other errors. + +**/ +EFI_STATUS +HttpIoSendChunkedTransfer ( + IN HTTP_IO *HttpIo, + IN HTTP_IO_SEND_CHUNK_PROCESS *SendChunkProcess, + IN EFI_HTTP_MESSAGE *RequestMessage +); +#endif diff --git a/NetworkPkg/Library/DxeHttpIoLib/DxeHttpIoLib.c b/NetworkPkg/Library/DxeHttpIoLib/DxeHttpIoLib.c new file mode 100644 index 0000000000..250477965c --- /dev/null +++ b/NetworkPkg/Library/DxeHttpIoLib/DxeHttpIoLib.c @@ -0,0 +1,847 @@ +/** @file + Http IO Helper Library. + + (C) Copyright 2020 Hewlett-Packard Development Company, L.P.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include <Uefi.h> + +#include <Protocol/Http.h> + +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> +#include <Library/HttpIoLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/PrintLib.h> +#include <Library/UefiBootServicesTableLib.h> + +/** + Notify the callback function when an event is triggered. + + @param[in] Context The opaque parameter to the function. + +**/ +VOID +EFIAPI +HttpIoNotifyDpc ( + IN VOID *Context + ) +{ + *((BOOLEAN *) Context) = TRUE; +} + +/** + Request HttpIoNotifyDpc as a DPC at TPL_CALLBACK. + + @param[in] Event The event signaled. + @param[in] Context The opaque parameter to the function. + +**/ +VOID +EFIAPI +HttpIoNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + // + // Request HttpIoNotifyDpc as a DPC at TPL_CALLBACK + // + QueueDpc (TPL_CALLBACK, HttpIoNotifyDpc, Context); +} + +/** + Destroy the HTTP_IO and release the resources. + + @param[in] HttpIo The HTTP_IO which wraps the HTTP service to be destroyed. + +**/ +VOID +HttpIoDestroyIo ( + IN HTTP_IO *HttpIo + ) +{ + EFI_HTTP_PROTOCOL *Http; + EFI_EVENT Event; + + if (HttpIo == NULL) { + return; + } + + Event = HttpIo->ReqToken.Event; + if (Event != NULL) { + gBS->CloseEvent (Event); + } + + Event = HttpIo->RspToken.Event; + if (Event != NULL) { + gBS->CloseEvent (Event); + } + + Event = HttpIo->TimeoutEvent; + if (Event != NULL) { + gBS->CloseEvent (Event); + } + + Http = HttpIo->Http; + if (Http != NULL) { + Http->Configure (Http, NULL); + gBS->CloseProtocol ( + HttpIo->Handle, + &gEfiHttpProtocolGuid, + HttpIo->Image, + HttpIo->Controller + ); + } + + NetLibDestroyServiceChild ( + HttpIo->Controller, + HttpIo->Image, + &gEfiHttpServiceBindingProtocolGuid, + HttpIo->Handle + ); +} + +/** + Create a HTTP_IO to access the HTTP service. It will create and configure + a HTTP child handle. + + @param[in] Image The handle of the driver image. + @param[in] Controller The handle of the controller. + @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6. + @param[in] ConfigData The HTTP_IO configuration data , + NULL means not to configure the HTTP child. + @param[in] Callback Callback function which will be invoked when specified + HTTP_IO_CALLBACK_EVENT happened. + @param[in] Context The Context data which will be passed to the Callback function. + @param[out] HttpIo The HTTP_IO. + + @retval EFI_SUCCESS The HTTP_IO is created and configured. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_UNSUPPORTED One or more of the control options are not + supported in the implementation. + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. + @retval Others Failed to create the HTTP_IO or configure it. + +**/ +EFI_STATUS +HttpIoCreateIo ( + IN EFI_HANDLE Image, + IN EFI_HANDLE Controller, + IN UINT8 IpVersion, + IN HTTP_IO_CONFIG_DATA *ConfigData, OPTIONAL + IN HTTP_IO_CALLBACK Callback, + IN VOID *Context, + OUT HTTP_IO *HttpIo + ) +{ + 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; + + if ((Image == NULL) || (Controller == NULL) || (HttpIo == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (IpVersion != IP_VERSION_4 && IpVersion != IP_VERSION_6) { + return EFI_UNSUPPORTED; + } + + ZeroMem (HttpIo, sizeof (HTTP_IO)); + ZeroMem (&HttpConfigData, sizeof (EFI_HTTP_CONFIG_DATA)); + + // + // Create the HTTP child instance and get the HTTP protocol. + // + Status = NetLibCreateServiceChild ( + Controller, + Image, + &gEfiHttpServiceBindingProtocolGuid, + &HttpIo->Handle + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->OpenProtocol ( + HttpIo->Handle, + &gEfiHttpProtocolGuid, + (VOID **) &Http, + Image, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status) || (Http == NULL)) { + goto ON_ERROR; + } + + // + // Init the configuration data and configure the HTTP child. + // + HttpIo->Image = Image; + HttpIo->Controller = Controller; + HttpIo->IpVersion = IpVersion; + HttpIo->Http = Http; + HttpIo->Callback = Callback; + HttpIo->Context = Context; + + if (ConfigData != NULL) { + if (HttpIo->IpVersion == IP_VERSION_4) { + HttpConfigData.LocalAddressIsIPv6 = FALSE; + HttpConfigData.HttpVersion = ConfigData->Config4.HttpVersion; + HttpConfigData.TimeOutMillisec = ConfigData->Config4.RequestTimeOut; + + Http4AccessPoint.UseDefaultAddress = ConfigData->Config4.UseDefaultAddress; + Http4AccessPoint.LocalPort = ConfigData->Config4.LocalPort; + IP4_COPY_ADDRESS (&Http4AccessPoint.LocalAddress, &ConfigData->Config4.LocalIp); + IP4_COPY_ADDRESS (&Http4AccessPoint.LocalSubnet, &ConfigData->Config4.SubnetMask); + HttpConfigData.AccessPoint.IPv4Node = &Http4AccessPoint; + } else { + HttpConfigData.LocalAddressIsIPv6 = TRUE; + HttpConfigData.HttpVersion = ConfigData->Config6.HttpVersion; + HttpConfigData.TimeOutMillisec = ConfigData->Config6.RequestTimeOut; + + Http6AccessPoint.LocalPort = ConfigData->Config6.LocalPort; + IP6_COPY_ADDRESS (&Http6AccessPoint.LocalAddress, &ConfigData->Config6.LocalIp); + HttpConfigData.AccessPoint.IPv6Node = &Http6AccessPoint; + } + + Status = Http->Configure (Http, &HttpConfigData); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + } + + // + // Create events for variuos asynchronous operations. + // + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + HttpIoNotify, + &HttpIo->IsTxDone, + &Event + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + HttpIo->ReqToken.Event = Event; + HttpIo->ReqToken.Message = &HttpIo->ReqMessage; + + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + HttpIoNotify, + &HttpIo->IsRxDone, + &Event + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + HttpIo->RspToken.Event = Event; + HttpIo->RspToken.Message = &HttpIo->RspMessage; + + // + // Create TimeoutEvent for response + // + Status = gBS->CreateEvent ( + EVT_TIMER, + TPL_CALLBACK, + NULL, + NULL, + &Event + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + HttpIo->TimeoutEvent = Event; + return EFI_SUCCESS; + +ON_ERROR: + HttpIoDestroyIo (HttpIo); + + return Status; +} + +/** + Synchronously send a HTTP REQUEST message to the server. + + @param[in] HttpIo The HttpIo wrapping the HTTP service. + @param[in] Request A pointer to storage such data as URL and HTTP method. + @param[in] HeaderCount Number of HTTP header structures in Headers list. + @param[in] Headers Array containing list of HTTP headers. + @param[in] BodyLength Length in bytes of the HTTP body. + @param[in] Body Body associated with the HTTP request. + + @retval EFI_SUCCESS The HTTP request is trasmitted. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. + @retval EFI_DEVICE_ERROR An unexpected network or system error occurred. + @retval Others Other errors as indicated. + +**/ +EFI_STATUS +HttpIoSendRequest ( + IN HTTP_IO *HttpIo, + IN EFI_HTTP_REQUEST_DATA *Request, + IN UINTN HeaderCount, + IN EFI_HTTP_HEADER *Headers, + IN UINTN BodyLength, + IN VOID *Body + ) +{ + EFI_STATUS Status; + EFI_HTTP_PROTOCOL *Http; + + if (HttpIo == NULL || HttpIo->Http == NULL) { + return EFI_INVALID_PARAMETER; + } + + HttpIo->ReqToken.Status = EFI_NOT_READY; + HttpIo->ReqToken.Message->Data.Request = Request; + HttpIo->ReqToken.Message->HeaderCount = HeaderCount; + HttpIo->ReqToken.Message->Headers = Headers; + HttpIo->ReqToken.Message->BodyLength = BodyLength; + HttpIo->ReqToken.Message->Body = Body; + + if (HttpIo->Callback != NULL) { + Status = HttpIo->Callback ( + HttpIoRequest, + HttpIo->ReqToken.Message, + HttpIo->Context + ); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // Queue the request token to HTTP instances. + // + Http = HttpIo->Http; + HttpIo->IsTxDone = FALSE; + Status = Http->Request ( + Http, + &HttpIo->ReqToken + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Poll the network until transmit finish. + // + while (!HttpIo->IsTxDone) { + Http->Poll (Http); + } + + return HttpIo->ReqToken.Status; +} + +/** + Synchronously receive a HTTP RESPONSE message from the server. + + @param[in] HttpIo The HttpIo wrapping the HTTP service. + @param[in] RecvMsgHeader TRUE to receive a new HTTP response (from message header). + FALSE to continue receive the previous response message. + @param[out] ResponseData Point to a wrapper of the received response data. + + @retval EFI_SUCCESS The HTTP response is received. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. + @retval EFI_DEVICE_ERROR An unexpected network or system error occurred. + @retval Others Other errors as indicated. + +**/ +EFI_STATUS +HttpIoRecvResponse ( + IN HTTP_IO *HttpIo, + IN BOOLEAN RecvMsgHeader, + OUT HTTP_IO_RESPONSE_DATA *ResponseData + ) +{ + EFI_STATUS Status; + EFI_HTTP_PROTOCOL *Http; + + if (HttpIo == NULL || HttpIo->Http == NULL || ResponseData == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Queue the response token to HTTP instances. + // + HttpIo->RspToken.Status = EFI_NOT_READY; + if (RecvMsgHeader) { + HttpIo->RspToken.Message->Data.Response = &ResponseData->Response; + } else { + HttpIo->RspToken.Message->Data.Response = NULL; + } + HttpIo->RspToken.Message->HeaderCount = 0; + HttpIo->RspToken.Message->Headers = NULL; + HttpIo->RspToken.Message->BodyLength = ResponseData->BodyLength; + HttpIo->RspToken.Message->Body = ResponseData->Body; + + Http = HttpIo->Http; + HttpIo->IsRxDone = FALSE; + + // + // Start the timer, and wait Timeout seconds to receive the header packet. + // + Status = gBS->SetTimer (HttpIo->TimeoutEvent, TimerRelative, HttpIo->Timeout * TICKS_PER_MS); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = Http->Response ( + Http, + &HttpIo->RspToken + ); + + if (EFI_ERROR (Status)) { + // + // Remove timeout timer from the event list. + // + gBS->SetTimer (HttpIo->TimeoutEvent, TimerCancel, 0); + return Status; + } + + // + // Poll the network until receive finish. + // + while (!HttpIo->IsRxDone && EFI_ERROR (gBS->CheckEvent (HttpIo->TimeoutEvent))) { + Http->Poll (Http); + } + + // + // Remove timeout timer from the event list. + // + gBS->SetTimer (HttpIo->TimeoutEvent, TimerCancel, 0); + + if (!HttpIo->IsRxDone) { + // + // Timeout occurs, cancel the response token. + // + Http->Cancel (Http, &HttpIo->RspToken); + + Status = EFI_TIMEOUT; + + return Status; + } else { + HttpIo->IsRxDone = FALSE; + } + + if ((HttpIo->Callback != NULL) && + (HttpIo->RspToken.Status == EFI_SUCCESS || HttpIo->RspToken.Status == EFI_HTTP_ERROR)) { + Status = HttpIo->Callback ( + HttpIoResponse, + HttpIo->RspToken.Message, + HttpIo->Context + ); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // Store the received data into the wrapper. + // + ResponseData->Status = HttpIo->RspToken.Status; + ResponseData->HeaderCount = HttpIo->RspToken.Message->HeaderCount; + ResponseData->Headers = HttpIo->RspToken.Message->Headers; + ResponseData->BodyLength = HttpIo->RspToken.Message->BodyLength; + + return Status; +} + +/** + Get the value of the content length if there is a "Content-Length" header. + + @param[in] HeaderCount Number of HTTP header structures in Headers. + @param[in] Headers Array containing list of HTTP headers. + @param[out] ContentLength Pointer to save the value of the content length. + + @retval EFI_SUCCESS Successfully get the content length. + @retval EFI_NOT_FOUND No "Content-Length" header in the Headers. + +**/ +EFI_STATUS +HttpIoGetContentLength ( + IN UINTN HeaderCount, + IN EFI_HTTP_HEADER *Headers, + OUT UINTN *ContentLength + ) +{ + EFI_HTTP_HEADER *Header; + + Header = HttpFindHeader (HeaderCount, Headers, HTTP_HEADER_CONTENT_LENGTH); + if (Header == NULL) { + return EFI_NOT_FOUND; + } + + return AsciiStrDecimalToUintnS (Header->FieldValue, (CHAR8 **) NULL, ContentLength); +} +/** + Send HTTP request in chunks. + + @param[in] HttpIo The HttpIo wrapping the HTTP service. + @param[in] SendChunkProcess Pointer to current chunk process status. + @param[in] RequestMessage Request to send. + + @retval EFI_SUCCESS Successfully to send chunk data according to SendChunkProcess. + @retval Other Other errors. + +**/ +EFI_STATUS +HttpIoSendChunkedTransfer ( + IN HTTP_IO *HttpIo, + IN HTTP_IO_SEND_CHUNK_PROCESS *SendChunkProcess, + IN EFI_HTTP_MESSAGE *RequestMessage +) +{ + EFI_STATUS Status; + EFI_HTTP_HEADER *NewHeaders; + EFI_HTTP_HEADER *ContentLengthHeader; + UINTN AddNewHeader; + UINTN HeaderCount; + CHAR8 *MessageBody; + UINTN MessageBodyLength; + UINTN ChunkLength; + CHAR8 ChunkLengthStr [HTTP_IO_CHUNK_SIZE_STRING_LEN]; + EFI_HTTP_REQUEST_DATA *SentRequestData; + + AddNewHeader = 0; + NewHeaders = NULL; + MessageBody = NULL; + ContentLengthHeader = NULL; + MessageBodyLength = 0; + + switch (*SendChunkProcess) { + case HttpIoSendChunkHeaderZeroContent: + ContentLengthHeader = HttpFindHeader (RequestMessage->HeaderCount, RequestMessage->Headers, HTTP_HEADER_CONTENT_LENGTH); + if (ContentLengthHeader == NULL) { + AddNewHeader = 1; + } + + NewHeaders = AllocateZeroPool ((RequestMessage->HeaderCount + AddNewHeader) * sizeof(EFI_HTTP_HEADER)); + CopyMem ((VOID*)NewHeaders, (VOID *)RequestMessage->Headers, RequestMessage->HeaderCount * sizeof (EFI_HTTP_HEADER)); + if (AddNewHeader == 0) { + // + // Override content-length to Transfer-Encoding. + // + ContentLengthHeader = HttpFindHeader (RequestMessage->HeaderCount, NewHeaders, HTTP_HEADER_CONTENT_LENGTH); + ContentLengthHeader->FieldName = NULL; + ContentLengthHeader->FieldValue = NULL; + } else { + ContentLengthHeader = NewHeaders + RequestMessage->HeaderCount; + } + HttpSetFieldNameAndValue (ContentLengthHeader, HTTP_HEADER_TRANSFER_ENCODING, HTTP_HEADER_TRANSFER_ENCODING_CHUNKED); + HeaderCount = RequestMessage->HeaderCount + AddNewHeader; + MessageBodyLength = 0; + MessageBody = NULL; + SentRequestData = RequestMessage->Data.Request; + break; + + case HttpIoSendChunkContent: + HeaderCount = 0; + NewHeaders = NULL; + SentRequestData = NULL; + if (RequestMessage->BodyLength > HTTP_IO_MAX_SEND_PAYLOAD) { + MessageBodyLength = HTTP_IO_MAX_SEND_PAYLOAD; + } else { + MessageBodyLength = RequestMessage->BodyLength; + } + AsciiSPrint ( + ChunkLengthStr, + HTTP_IO_CHUNK_SIZE_STRING_LEN, + "%x%c%c", + MessageBodyLength, + CHUNKED_TRANSFER_CODING_CR, + CHUNKED_TRANSFER_CODING_LF + ); + ChunkLength = AsciiStrLen (ChunkLengthStr); + MessageBody = AllocatePool (ChunkLength + MessageBodyLength + 2); + if (MessageBody == NULL) { + DEBUG((DEBUG_ERROR, "Not enough memory for chunk transfer\n")); + return EFI_OUT_OF_RESOURCES; + } + // + // Build up the chunk transfer paylaod. + // + CopyMem (MessageBody, ChunkLengthStr, ChunkLength); + CopyMem (MessageBody + ChunkLength, RequestMessage->Body, MessageBodyLength); + *(MessageBody + ChunkLength + MessageBodyLength) = CHUNKED_TRANSFER_CODING_CR; + *(MessageBody + ChunkLength + MessageBodyLength + 1) = CHUNKED_TRANSFER_CODING_LF; + // + // Change variables for the next chunk trasnfer. + // + RequestMessage->BodyLength -= MessageBodyLength; + RequestMessage->Body = (VOID *)((CHAR8 *)RequestMessage->Body + MessageBodyLength); + MessageBodyLength += (ChunkLength + 2); + if (RequestMessage->BodyLength == 0) { + *SendChunkProcess = HttpIoSendChunkEndChunk; + } + break; + + case HttpIoSendChunkEndChunk: + HeaderCount = 0; + NewHeaders = NULL; + SentRequestData = NULL; + AsciiSPrint ( + ChunkLengthStr, + HTTP_IO_CHUNK_SIZE_STRING_LEN, + "0%c%c%c%c", + CHUNKED_TRANSFER_CODING_CR, + CHUNKED_TRANSFER_CODING_LF, + CHUNKED_TRANSFER_CODING_CR, + CHUNKED_TRANSFER_CODING_LF + ); + MessageBody = AllocatePool (AsciiStrLen(ChunkLengthStr)); + if (MessageBody == NULL) { + DEBUG((DEBUG_ERROR, "Not enough memory for the end chunk transfer\n")); + return EFI_OUT_OF_RESOURCES; + } + CopyMem (MessageBody, ChunkLengthStr, AsciiStrLen (ChunkLengthStr)); + MessageBodyLength = AsciiStrLen (ChunkLengthStr); + *SendChunkProcess = HttpIoSendChunkFinish; + break; + + default: + return EFI_INVALID_PARAMETER; + } + + Status = HttpIoSendRequest ( + HttpIo, + SentRequestData, + HeaderCount, + NewHeaders, + MessageBodyLength, + MessageBody + ); + if (ContentLengthHeader != NULL) { + if (ContentLengthHeader->FieldName != NULL) { + FreePool (ContentLengthHeader->FieldName); + } + if (ContentLengthHeader->FieldValue != NULL) { + FreePool (ContentLengthHeader->FieldValue); + } + } + if (NewHeaders != NULL) { + FreePool (NewHeaders); + } + if (MessageBody != NULL) { + FreePool (MessageBody); + } + return Status; +} + +/** + Synchronously receive a HTTP RESPONSE message from the server. + + @param[in] HttpIo The HttpIo wrapping the HTTP service. + @param[in] HeaderCount Number of headers in Headers. + @param[in] Headers Array containing list of HTTP headers. + @param[out] ChunkListHead A pointer to receive list head + of chunked data. Caller has to + release memory of ChunkListHead + and all list entries. + @param[out] ContentLength Total content length + + @retval EFI_SUCCESS The HTTP chunked transfer is received. + @retval EFI_NOT_FOUND No chunked transfer coding header found. + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. + @retval EFI_INVALID_PARAMETER Improper parameters. + @retval Others Other errors as indicated. + +**/ +EFI_STATUS +HttpIoGetChunkedTransferContent ( + IN HTTP_IO *HttpIo, + IN UINTN HeaderCount, + IN EFI_HTTP_HEADER *Headers, + OUT LIST_ENTRY **ChunkListHead, + OUT UINTN *ContentLength + ) +{ + EFI_HTTP_HEADER *Header; + CHAR8 ChunkSizeAscii [256]; + EFI_STATUS Status; + UINTN Index; + HTTP_IO_RESPONSE_DATA ResponseData; + UINTN TotalLength; + LIST_ENTRY *HttpChunks; + HTTP_IO_CHUNKS *ThisChunk; + LIST_ENTRY *ThisListEntry; + + if (ChunkListHead == NULL || ContentLength == NULL) { + return EFI_INVALID_PARAMETER; + } + + *ContentLength = 0; + Header = HttpFindHeader (HeaderCount, Headers, HTTP_HEADER_TRANSFER_ENCODING); + if (Header == NULL) { + return EFI_NOT_FOUND; + } + + if (AsciiStrCmp (Header->FieldValue, HTTP_HEADER_TRANSFER_ENCODING_CHUNKED) != 0) { + return EFI_NOT_FOUND; + } + // + // Loop to get all chunks. + // + TotalLength = 0; + HttpChunks = (LIST_ENTRY *)AllocateZeroPool (sizeof (LIST_ENTRY)); + if (HttpChunks == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ExitDeleteChunks; + } + InitializeListHead (HttpChunks); + DEBUG ((DEBUG_INFO, " Chunked transfer\n")); + while (TRUE) { + ZeroMem((VOID *)&ResponseData, sizeof(HTTP_IO_RESPONSE_DATA)); + ResponseData.BodyLength = HTTP_IO_CHUNKED_TRANSFER_CODING_DATA_LENGTH; + ResponseData.Body = ChunkSizeAscii; + Status = HttpIoRecvResponse ( + HttpIo, + FALSE, + &ResponseData + ); + if (EFI_ERROR (Status)) { + goto ExitDeleteChunks; + } + // + // Decoding Chunked Transfer Coding. + // Only decode chunk-size and last chunk. + // + DEBUG ((DEBUG_INFO, " Chunk HTTP Response StatusCode - %d\n", ResponseData.Response.StatusCode)); + // + // Break if this is last chunk. + // + if (ChunkSizeAscii [0] == CHUNKED_TRANSFER_CODING_LAST_CHUNK) { + // + // Check if this is a valid Last-Chunk. + // + if ((ChunkSizeAscii [1] != CHUNKED_TRANSFER_CODING_CR) || + (ChunkSizeAscii [2] != CHUNKED_TRANSFER_CODING_LF) + ) { + DEBUG ((DEBUG_ERROR, " This is an invalid Last-chunk\n")); + Status = EFI_INVALID_PARAMETER; + goto ExitDeleteChunks; + } + + Status = EFI_SUCCESS; + DEBUG ((DEBUG_INFO, " Last-chunk\n")); + ThisChunk = (HTTP_IO_CHUNKS *)AllocateZeroPool (sizeof (HTTP_IO_CHUNKS)); + if (ThisChunk == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ExitDeleteChunks; + } + + InitializeListHead (&ThisChunk->NextChunk); + ThisChunk->Length = ResponseData.BodyLength - 1 - 2; // Minus sizeof '0' and CRLF. + ThisChunk->Data = (CHAR8 *)AllocatePool (ThisChunk->Length); + if (ThisChunk->Data == NULL) { + FreePool ((UINT8 *)ThisChunk); + Status = EFI_OUT_OF_RESOURCES; + goto ExitDeleteChunks; + } + CopyMem ((UINT8 *)ThisChunk->Data, (UINT8 *)ResponseData.Body + 1, ThisChunk->Length); + TotalLength += ThisChunk->Length; + InsertTailList (HttpChunks, &ThisChunk->NextChunk); + break; + } + + // + // Get the chunk length + // + Index = 0; + while ((ChunkSizeAscii [Index] != CHUNKED_TRANSFER_CODING_EXTENSION_SEPARATOR) && + (ChunkSizeAscii [Index] != (CHAR8)CHUNKED_TRANSFER_CODING_CR) && + (Index != HTTP_IO_CHUNKED_TRANSFER_CODING_DATA_LENGTH)) { + Index ++; + } + + if (Index == HTTP_IO_CHUNKED_TRANSFER_CODING_DATA_LENGTH) { + Status = EFI_NOT_FOUND; + goto ExitDeleteChunks; + } + ChunkSizeAscii[Index] = 0; + AsciiStrHexToUintnS (ChunkSizeAscii, NULL, ContentLength); + DEBUG ((DEBUG_INFO, " Length of this chunk %d\n", *ContentLength)); + // + // Receive the data; + // + ThisChunk = (HTTP_IO_CHUNKS *)AllocateZeroPool (sizeof (HTTP_IO_CHUNKS)); + if (ThisChunk == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ExitDeleteChunks; + } + ResponseData.BodyLength = *ContentLength; + ResponseData.Body = (CHAR8 *)AllocatePool (*ContentLength); + if (ResponseData.Body == NULL) { + FreePool (ThisChunk); + Status = EFI_OUT_OF_RESOURCES; + goto ExitDeleteChunks; + } + InitializeListHead (&ThisChunk->NextChunk); + ThisChunk->Length = *ContentLength; + ThisChunk->Data = ResponseData.Body; + InsertTailList (HttpChunks, &ThisChunk->NextChunk); + Status = HttpIoRecvResponse ( + HttpIo, + FALSE, + &ResponseData + ); + if (EFI_ERROR (Status)) { + goto ExitDeleteChunks; + } + // + // Read CRLF + // + ZeroMem((VOID *)&ResponseData, sizeof(HTTP_IO_RESPONSE_DATA)); + ResponseData.BodyLength = 2; + ResponseData.Body = ChunkSizeAscii; + Status = HttpIoRecvResponse ( + HttpIo, + FALSE, + &ResponseData + ); + if (EFI_ERROR (Status)) { + goto ExitDeleteChunks; + } + // + // Verify the end of chunk payload. + // + if ((ChunkSizeAscii [0] != CHUNKED_TRANSFER_CODING_CR) || + (ChunkSizeAscii [1] != CHUNKED_TRANSFER_CODING_LF) + ) { + DEBUG ((DEBUG_ERROR, " This is an invalid End-of-chunk notation.\n")); + goto ExitDeleteChunks; + } + TotalLength += *ContentLength; + } + + *ContentLength = TotalLength; + *ChunkListHead = HttpChunks; + DEBUG ((DEBUG_INFO, " Total of lengh of chunks :%d\n", TotalLength)); + return EFI_SUCCESS; + +ExitDeleteChunks: + if (HttpChunks != NULL) { + while (!IsListEmpty(HttpChunks)) { + ThisListEntry = GetFirstNode (HttpChunks); + RemoveEntryList (ThisListEntry); + ThisChunk = (HTTP_IO_CHUNKS *)ThisListEntry; + if (ThisChunk->Data != NULL) { + FreePool (ThisChunk->Data); + } + FreePool(ThisListEntry); + } + FreePool (HttpChunks); + } + return Status; +} diff --git a/NetworkPkg/Library/DxeHttpIoLib/DxeHttpIoLib.inf b/NetworkPkg/Library/DxeHttpIoLib/DxeHttpIoLib.inf new file mode 100644 index 0000000000..a02b409547 --- /dev/null +++ b/NetworkPkg/Library/DxeHttpIoLib/DxeHttpIoLib.inf @@ -0,0 +1,43 @@ +## @file +# This library instance provides HTTP IO helper functions. +# +# (C) Copyright 2020 Hewlett Packard Enterprise Development LP<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x0001001b + BASE_NAME = DxeHttpIoLib + MODULE_UNI_FILE = DxeHttpIoLib.uni + FILE_GUID = 50B198F8-7986-4F51-A857-CFE4643D59F3 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = HttpIoLib| DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC ARM AARM64 RISCV64 +# + +[Sources] + DxeHttpIoLib.c + +[Packages] + MdePkg/MdePkg.dec + NetworkPkg/NetworkPkg.dec + + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + DpcLib + MemoryAllocationLib + PrintLib + UefiBootServicesTableLib + +[Protocols] + gEfiHttpProtocolGuid ## SOMETIMES_CONSUMES + diff --git a/NetworkPkg/Library/DxeHttpIoLib/DxeHttpIoLib.uni b/NetworkPkg/Library/DxeHttpIoLib/DxeHttpIoLib.uni new file mode 100644 index 0000000000..d419b1a49d --- /dev/null +++ b/NetworkPkg/Library/DxeHttpIoLib/DxeHttpIoLib.uni @@ -0,0 +1,13 @@ +// /** @file +// The library instance provides HTTP IO helper functions. +// +// (C) Copyright 2020 Hewlett Packard Enterprise Development LP<BR> +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "HTTP IO Helper Library" + +#string STR_MODULE_DESCRIPTION #language en-US "The library instance provides HTTP IO helper functions." + -- 2.17.1
|
|||
|
|||
[DxeHttpIoLib PATCH V4 2/3] NetworkPkg: Add Http IO Helper Library to NetworkPkg
This library provides HTTP IO helper functions.
Signed-off-by: Abner Chang <abner.chang@...> Cc: Maciej Rabeda <maciej.rabeda@...> Cc: Jiaxin Wu <jiaxin.wu@...> Cc: Siyuan Fu <siyuan.fu@...> Cc: Nickle Wang <nickle.wang@...> --- NetworkPkg/NetworkLibs.dsc.inc | 5 ++++- NetworkPkg/NetworkPkg.dec | 6 +++++- NetworkPkg/NetworkPkg.dsc | 1 + 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/NetworkPkg/NetworkLibs.dsc.inc b/NetworkPkg/NetworkLibs.dsc.inc index 4b99f48085..7cfc1a151a 100644 --- a/NetworkPkg/NetworkLibs.dsc.inc +++ b/NetworkPkg/NetworkLibs.dsc.inc @@ -6,6 +6,7 @@ # of EDKII network library classes. # # Copyright (c) 2019, Intel Corporation. All rights reserved.<BR> +# (C) Copyright 2020 Hewlett Packard Enterprise Development LP<BR> # # SPDX-License-Identifier: BSD-2-Clause-Patent # @@ -16,5 +17,7 @@ IpIoLib|NetworkPkg/Library/DxeIpIoLib/DxeIpIoLib.inf UdpIoLib|NetworkPkg/Library/DxeUdpIoLib/DxeUdpIoLib.inf TcpIoLib|NetworkPkg/Library/DxeTcpIoLib/DxeTcpIoLib.inf - # HttpLib is used for Http Boot + # HttpLib and HttpIoLib are used for Http Boot and other + # HTTP applications. HttpLib|NetworkPkg/Library/DxeHttpLib/DxeHttpLib.inf + HttpIoLib|NetworkPkg/Library/DxeHttpIoLib/DxeHttpIoLib.inf diff --git a/NetworkPkg/NetworkPkg.dec b/NetworkPkg/NetworkPkg.dec index 66e500cbea..0449e1004a 100644 --- a/NetworkPkg/NetworkPkg.dec +++ b/NetworkPkg/NetworkPkg.dec @@ -4,7 +4,7 @@ # This package provides network modules that conform to UEFI 2.4 specification. # # Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR> -# (C) Copyright 2015-2017 Hewlett Packard Enterprise Development LP<BR> +# (C) Copyright 2015-2020 Hewlett Packard Enterprise Development LP<BR> # # SPDX-License-Identifier: BSD-2-Clause-Patent # @@ -41,6 +41,10 @@ # This library is only intended to be used by UEFI network stack modules. HttpLib|Include/Library/HttpLib.h + ## @libraryclass Http IO helper routines for HTTP transfer. + # This library is only intended to be used by UEFI network stack modules. + HttpIoLib|Include/Library/HttpIoLib.h + ## @libraryclass Library for Deferred Procedure Calls. DpcLib|Include/Library/DpcLib.h diff --git a/NetworkPkg/NetworkPkg.dsc b/NetworkPkg/NetworkPkg.dsc index 716d04fdad..216479a2f6 100644 --- a/NetworkPkg/NetworkPkg.dsc +++ b/NetworkPkg/NetworkPkg.dsc @@ -107,6 +107,7 @@ NetworkPkg/Application/VConfig/VConfig.inf NetworkPkg/Library/DxeDpcLib/DxeDpcLib.inf NetworkPkg/Library/DxeHttpLib/DxeHttpLib.inf + NetworkPkg/Library/DxeHttpIoLib/DxeHttpIoLib.inf NetworkPkg/Library/DxeIpIoLib/DxeIpIoLib.inf NetworkPkg/Library/DxeNetLib/DxeNetLib.inf NetworkPkg/Library/DxeTcpIoLib/DxeTcpIoLib.inf -- 2.17.1
|
|||
|
|||
[DxeHttpIoLib PATCH V4 0/3] Add Http IO Helper Library
In v4: - Address the comments given by Maciej.
- Add checking of "\r\n" notation on the Last-chunk and End-of-chunk. In v3: Address the comments given by Maciej. In v2: Revise HTTP Boot DXE to utilize HttpIoLib. In order to leverage HTTP IO related functions implemented in HttpBootDxe for edk2 Redfish REST EX HTTP driver instance, we would like to pull out HTTP IO related functions from HttpBootDxe to a helper library under network package. This set of patches is for the new library HttpIoLib. HttpBootDxe is also revised to utilize HttpIoLib. However we will need the owner of HttpBootDxe to verify the functionality of HTTP boot becuase I don't have the environment for that. Signed-off-by: Abner Chang <abner.chang@...> Cc: Maciej Rabeda <maciej.rabeda@...> Cc: Jiaxin Wu <jiaxin.wu@...> Cc: Siyuan Fu <siyuan.fu@...> Cc: Nickle Wang <nickle.wang@...> Abner Chang (3): NetworkPkg/Library: Implementation of Http IO Helper Library NetworkPkg: Add Http IO Helper Library to NetworkPkg NetworkPkg/HttpBootDxe: Utilize HttpIoLib NetworkPkg/HttpBootDxe/HttpBootDxe.h | 3 +- NetworkPkg/HttpBootDxe/HttpBootDxe.inf | 2 + NetworkPkg/HttpBootDxe/HttpBootSupport.c | 431 +-------- NetworkPkg/HttpBootDxe/HttpBootSupport.h | 189 +--- NetworkPkg/Include/Library/HttpIoLib.h | 328 +++++++ .../Library/DxeHttpIoLib/DxeHttpIoLib.c | 847 ++++++++++++++++++ .../Library/DxeHttpIoLib/DxeHttpIoLib.inf | 43 + .../Library/DxeHttpIoLib/DxeHttpIoLib.uni | 13 + NetworkPkg/NetworkLibs.dsc.inc | 5 +- NetworkPkg/NetworkPkg.dec | 6 +- NetworkPkg/NetworkPkg.dsc | 1 + 11 files changed, 1247 insertions(+), 621 deletions(-) create mode 100644 NetworkPkg/Include/Library/HttpIoLib.h create mode 100644 NetworkPkg/Library/DxeHttpIoLib/DxeHttpIoLib.c create mode 100644 NetworkPkg/Library/DxeHttpIoLib/DxeHttpIoLib.inf create mode 100644 NetworkPkg/Library/DxeHttpIoLib/DxeHttpIoLib.uni -- 2.17.1
|
|||
|
|||
[PATCH v3 11/11] UefiCpuPkg/MpInitLib: For SEV-ES guest, set stack based on processor number
Lendacky, Thomas
From: Tom Lendacky <thomas.lendacky@...>
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3008 Set the SEV-ES reset stack address for an AP based on the processor number instead of the APIC ID in case the APIC IDs are not zero-based and densely packed/enumerated. This will ensure an AP reset stack address does not get set outside of the AP reset stack memory allocation. Cc: Eric Dong <eric.dong@...> Cc: Ray Ni <ray.ni@...> Cc: Laszlo Ersek <lersek@...> Cc: Rahul Kumar <rahul1.kumar@...> Acked-by: Ray Ni <ray.ni@...> Signed-off-by: Tom Lendacky <thomas.lendacky@...> --- UefiCpuPkg/Library/MpInitLib/MpLib.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c index 1f47ff3f73b5..681fa79b4cff 100644 --- a/UefiCpuPkg/Library/MpInitLib/MpLib.c +++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c @@ -680,11 +680,16 @@ MpInitLibSevEsAPReset ( IN CPU_MP_DATA *CpuMpData ) { + EFI_STATUS Status; + UINTN ProcessorNumber; UINT16 Code16, Code32; AP_RESET *APResetFn; UINTN BufferStart; UINTN StackStart; + Status = GetProcessorNumber (CpuMpData, &ProcessorNumber); + ASSERT_EFI_ERROR (Status); + Code16 = GetProtectedMode16CS (); Code32 = GetProtectedMode32CS (); @@ -696,7 +701,7 @@ MpInitLibSevEsAPReset ( BufferStart = CpuMpData->MpCpuExchangeInfo->BufferStart; StackStart = CpuMpData->SevEsAPResetStackStart - - (AP_RESET_STACK_SIZE * GetApicId ()); + (AP_RESET_STACK_SIZE * ProcessorNumber); // // This call never returns. -- 2.28.0
|
|||
|
|||
[PATCH v3 10/11] UefiCpuPkg, OvmfPkg: Disable interrupts when using the GHCB
Lendacky, Thomas
From: Tom Lendacky <thomas.lendacky@...>
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3008 The QemuFlashPtrWrite() flash services runtime uses the GHCB and VmgExit() directly to perform the flash write when running as an SEV-ES guest. If an interrupt arrives between VmgInit() and VmgExit(), the Dr7 read in the interrupt handler will generate a #VC, which can overwrite information in the GHCB that QemuFlashPtrWrite() has set. This has been seen with the timer interrupt firing and the CpuExceptionHandlerLib library code, UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ Xcode5ExceptionHandlerAsm.nasm and ExceptionHandlerAsm.nasm reading the Dr7 register while QemuFlashPtrWrite() is using the GHCB. In general, it is necessary to protect the GHCB whenever it is used, not just in QemuFlashPtrWrite(). Disable interrupts around the usage of the GHCB by modifying the VmgInit() and VmgDone() interfaces: - VmgInit() will take an extra parameter that is a pointer to a BOOLEAN that will hold the interrupt state at the time of invocation. VmgInit() will get and save this interrupt state before updating the GHCB. - VmgDone() will take an extra parameter that is used to indicate whether interrupts are to be (re)enabled. Before exiting, VmgDone() will enable interrupts if that is requested. Fixes: 437eb3f7a8db7681afe0e6064d3a8edb12abb766 Cc: Eric Dong <eric.dong@...> Cc: Ray Ni <ray.ni@...> Cc: Laszlo Ersek <lersek@...> Cc: Rahul Kumar <rahul1.kumar@...> Cc: Jordan Justen <jordan.l.justen@...> Cc: Ard Biesheuvel <ard.biesheuvel@...> Cc: Tom Lendacky <thomas.lendacky@...> Cc: Brijesh Singh <brijesh.singh@...> Reviewed-by: Laszlo Ersek <lersek@...> Signed-off-by: Tom Lendacky <thomas.lendacky@...> --- UefiCpuPkg/Include/Library/VmgExitLib.h | 14 ++++++++--- OvmfPkg/Library/VmgExitLib/VmgExitLib.c | 26 +++++++++++++++++--- OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c | 5 ++-- OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlashDxe.c | 5 ++-- UefiCpuPkg/Library/MpInitLib/DxeMpLib.c | 5 ++-- UefiCpuPkg/Library/MpInitLib/MpLib.c | 7 +++--- UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.c | 18 ++++++++------ 7 files changed, 55 insertions(+), 25 deletions(-) diff --git a/UefiCpuPkg/Include/Library/VmgExitLib.h b/UefiCpuPkg/Include/Library/VmgExitLib.h index 07e8af6450b9..061948cf840d 100644 --- a/UefiCpuPkg/Include/Library/VmgExitLib.h +++ b/UefiCpuPkg/Include/Library/VmgExitLib.h @@ -50,13 +50,16 @@ VmgExit ( Performs the necessary steps in preparation for invoking VMGEXIT. Must be called before setting any fields within the GHCB. - @param[in, out] Ghcb A pointer to the GHCB + @param[in, out] Ghcb A pointer to the GHCB + @param[in, out] InterruptState A pointer to hold the current interrupt + state, used for restoring in VmgDone () **/ VOID EFIAPI VmgInit ( - IN OUT GHCB *Ghcb + IN OUT GHCB *Ghcb, + IN OUT BOOLEAN *InterruptState ); /** @@ -65,13 +68,16 @@ VmgInit ( Performs the necessary steps to cleanup after invoking VMGEXIT. Must be called after obtaining needed fields within the GHCB. - @param[in, out] Ghcb A pointer to the GHCB + @param[in, out] Ghcb A pointer to the GHCB + @param[in] InterruptState An indicator to conditionally (re)enable + interrupts **/ VOID EFIAPI VmgDone ( - IN OUT GHCB *Ghcb + IN OUT GHCB *Ghcb, + IN BOOLEAN InterruptState ); /** diff --git a/OvmfPkg/Library/VmgExitLib/VmgExitLib.c b/OvmfPkg/Library/VmgExitLib/VmgExitLib.c index 0540df8a04d4..bc5cd61d751f 100644 --- a/OvmfPkg/Library/VmgExitLib/VmgExitLib.c +++ b/OvmfPkg/Library/VmgExitLib/VmgExitLib.c @@ -132,15 +132,27 @@ VmgExit ( Performs the necessary steps in preparation for invoking VMGEXIT. Must be called before setting any fields within the GHCB. - @param[in, out] Ghcb A pointer to the GHCB + @param[in, out] Ghcb A pointer to the GHCB + @param[in, out] InterruptState A pointer to hold the current interrupt + state, used for restoring in VmgDone () **/ VOID EFIAPI VmgInit ( - IN OUT GHCB *Ghcb + IN OUT GHCB *Ghcb, + IN OUT BOOLEAN *InterruptState ) { + // + // Be sure that an interrupt can't cause a #VC while the GHCB is + // being used. + // + *InterruptState = GetInterruptState (); + if (*InterruptState) { + DisableInterrupts (); + } + SetMem (&Ghcb->SaveArea, sizeof (Ghcb->SaveArea), 0); } @@ -150,15 +162,21 @@ VmgInit ( Performs the necessary steps to cleanup after invoking VMGEXIT. Must be called after obtaining needed fields within the GHCB. - @param[in, out] Ghcb A pointer to the GHCB + @param[in, out] Ghcb A pointer to the GHCB + @param[in] InterruptState An indicator to conditionally (re)enable + interrupts **/ VOID EFIAPI VmgDone ( - IN OUT GHCB *Ghcb + IN OUT GHCB *Ghcb, + IN BOOLEAN InterruptState ) { + if (InterruptState) { + EnableInterrupts (); + } } /** diff --git a/OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c b/OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c index 9bf9d160179c..1671db3a01b1 100644 --- a/OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c +++ b/OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c @@ -1568,6 +1568,7 @@ VmgExitHandleVc ( SEV_ES_INSTRUCTION_DATA InstructionData; UINT64 ExitCode, Status; EFI_STATUS VcRet; + BOOLEAN InterruptState; VcRet = EFI_SUCCESS; @@ -1578,7 +1579,7 @@ VmgExitHandleVc ( Regs = SystemContext.SystemContextX64; Ghcb = Msr.Ghcb; - VmgInit (Ghcb); + VmgInit (Ghcb, &InterruptState); ExitCode = Regs->ExceptionData; switch (ExitCode) { @@ -1662,7 +1663,7 @@ VmgExitHandleVc ( VcRet = EFI_PROTOCOL_ERROR; } - VmgDone (Ghcb); + VmgDone (Ghcb, InterruptState); return VcRet; } diff --git a/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlashDxe.c b/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlashDxe.c index f9b21b54137d..1b0742967f71 100644 --- a/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlashDxe.c +++ b/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlashDxe.c @@ -52,6 +52,7 @@ QemuFlashPtrWrite ( if (MemEncryptSevEsIsEnabled ()) { MSR_SEV_ES_GHCB_REGISTER Msr; GHCB *Ghcb; + BOOLEAN InterruptState; Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB); Ghcb = Msr.Ghcb; @@ -63,12 +64,12 @@ QemuFlashPtrWrite ( // #VC exception. Instead, use the the VMGEXIT MMIO write support directly // to perform the update. // - VmgInit (Ghcb); + VmgInit (Ghcb, &InterruptState); Ghcb->SharedBuffer[0] = Value; Ghcb->SaveArea.SwScratch = (UINT64) (UINTN) Ghcb->SharedBuffer; VmgSetOffsetValid (Ghcb, GhcbSwScratch); VmgExit (Ghcb, SVM_EXIT_MMIO_WRITE, (UINT64) (UINTN) Ptr, 1); - VmgDone (Ghcb); + VmgDone (Ghcb, InterruptState); } else { *Ptr = Value; } diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c index 2c00d72ddefe..7839c249760e 100644 --- a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c +++ b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c @@ -171,6 +171,7 @@ GetSevEsAPMemory ( EFI_PHYSICAL_ADDRESS StartAddress; MSR_SEV_ES_GHCB_REGISTER Msr; GHCB *Ghcb; + BOOLEAN InterruptState; // // Allocate 1 page for AP jump table page @@ -192,9 +193,9 @@ GetSevEsAPMemory ( Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB); Ghcb = Msr.Ghcb; - VmgInit (Ghcb); + VmgInit (Ghcb, &InterruptState); VmgExit (Ghcb, SVM_EXIT_AP_JUMP_TABLE, 0, (UINT64) (UINTN) StartAddress); - VmgDone (Ghcb); + VmgDone (Ghcb, InterruptState); return (UINTN) StartAddress; } diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c index 6d977d45bcdd..1f47ff3f73b5 100644 --- a/UefiCpuPkg/Library/MpInitLib/MpLib.c +++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c @@ -884,6 +884,7 @@ ApWakeupFunction ( GHCB *Ghcb; UINT64 Status; BOOLEAN DoDecrement; + BOOLEAN InterruptState; DoDecrement = (BOOLEAN) (CpuMpData->InitFlag == ApInitConfig); @@ -891,7 +892,7 @@ ApWakeupFunction ( Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB); Ghcb = Msr.Ghcb; - VmgInit (Ghcb); + VmgInit (Ghcb, &InterruptState); if (DoDecrement) { DoDecrement = FALSE; @@ -905,11 +906,11 @@ ApWakeupFunction ( Status = VmgExit (Ghcb, SVM_EXIT_AP_RESET_HOLD, 0, 0); if ((Status == 0) && (Ghcb->SaveArea.SwExitInfo2 != 0)) { - VmgDone (Ghcb); + VmgDone (Ghcb, InterruptState); break; } - VmgDone (Ghcb); + VmgDone (Ghcb, InterruptState); } // diff --git a/UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.c b/UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.c index b47e282aff82..89b065cb3ff3 100644 --- a/UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.c +++ b/UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.c @@ -57,15 +57,16 @@ VmgExit ( Performs the necessary steps in preparation for invoking VMGEXIT. Must be called before setting any fields within the GHCB. - The base library function does nothing. - - @param[in, out] Ghcb A pointer to the GHCB + @param[in, out] Ghcb A pointer to the GHCB + @param[in, out] InterruptState A pointer to hold the current interrupt + state, used for restoring in VmgDone () **/ VOID EFIAPI VmgInit ( - IN OUT GHCB *Ghcb + IN OUT GHCB *Ghcb, + IN OUT BOOLEAN *InterruptState ) { } @@ -76,15 +77,16 @@ VmgInit ( Performs the necessary steps to cleanup after invoking VMGEXIT. Must be called after obtaining needed fields within the GHCB. - The base library function does nothing. - - @param[in, out] Ghcb A pointer to the GHCB + @param[in, out] Ghcb A pointer to the GHCB + @param[in] InterruptState An indicator to conditionally (re)enable + interrupts **/ VOID EFIAPI VmgDone ( - IN OUT GHCB *Ghcb + IN OUT GHCB *Ghcb, + IN BOOLEAN InterruptState ) { } -- 2.28.0
|
|||
|
|||
[PATCH v3 09/11] OvmfPkg/QemuFlashFvbServicesRuntimeDxe: Fix erase blocks for SEV-ES
Lendacky, Thomas
From: Tom Lendacky <thomas.lendacky@...>
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3008 The original SEV-ES support missed updating the QemuFlashEraseBlock() function to successfully erase blocks. Update QemuFlashEraseBlock() to call the QemuFlashPtrWrite() to be able to successfully perform the commands under SEV-ES. Fixes: 437eb3f7a8db7681afe0e6064d3a8edb12abb766 Cc: Jordan Justen <jordan.l.justen@...> Cc: Laszlo Ersek <lersek@...> Cc: Ard Biesheuvel <ard.biesheuvel@...> Reviewed-by: Laszlo Ersek <lersek@...> Signed-off-by: Tom Lendacky <thomas.lendacky@...> --- OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlash.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlash.c b/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlash.c index 0d29bf701aca..d19997032ec9 100644 --- a/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlash.c +++ b/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlash.c @@ -232,8 +232,8 @@ QemuFlashEraseBlock ( } Ptr = QemuFlashPtr (Lba, 0); - *Ptr = BLOCK_ERASE_CMD; - *Ptr = BLOCK_ERASE_CONFIRM_CMD; + QemuFlashPtrWrite (Ptr, BLOCK_ERASE_CMD); + QemuFlashPtrWrite (Ptr, BLOCK_ERASE_CONFIRM_CMD); return EFI_SUCCESS; } -- 2.28.0
|
|||
|
|||
[PATCH v3 08/11] OvmfPkg/QemuFlashFvbServicesRuntimeDxe: Set the SwScratch valid bit
Lendacky, Thomas
From: Tom Lendacky <thomas.lendacky@...>
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3008 All fields that are set in the GHCB should have their associated bit in the GHCB ValidBitmap field set. Add support to set the bit for the scratch area field (SwScratch). Fixes: 437eb3f7a8db7681afe0e6064d3a8edb12abb766 Cc: Jordan Justen <jordan.l.justen@...> Cc: Laszlo Ersek <lersek@...> Cc: Ard Biesheuvel <ard.biesheuvel@...> Reviewed-by: Laszlo Ersek <lersek@...> Signed-off-by: Tom Lendacky <thomas.lendacky@...> --- OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlashDxe.c | 1 + 1 file changed, 1 insertion(+) diff --git a/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlashDxe.c b/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlashDxe.c index 565383ee26d2..f9b21b54137d 100644 --- a/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlashDxe.c +++ b/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlashDxe.c @@ -66,6 +66,7 @@ QemuFlashPtrWrite ( VmgInit (Ghcb); Ghcb->SharedBuffer[0] = Value; Ghcb->SaveArea.SwScratch = (UINT64) (UINTN) Ghcb->SharedBuffer; + VmgSetOffsetValid (Ghcb, GhcbSwScratch); VmgExit (Ghcb, SVM_EXIT_MMIO_WRITE, (UINT64) (UINTN) Ptr, 1); VmgDone (Ghcb); } else { -- 2.28.0
|
|||
|
|||
[PATCH v3 07/11] UefiCpuPkg/MpInitLib: Set the SW exit fields when performing VMGEXIT
Lendacky, Thomas
From: Tom Lendacky <thomas.lendacky@...>
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3008 All fields that are set in the GHCB should have their associated bit in the GHCB ValidBitmap field set. Add support to set the bits for the software exit information fields when performing a VMGEXIT (SwExitCode, SwExitInfo1, SwExitInfo2). Fixes: 20da7ca42a33d3ef767ce4129f11496af7f67c9f Cc: Eric Dong <eric.dong@...> Cc: Ray Ni <ray.ni@...> Cc: Laszlo Ersek <lersek@...> Cc: Rahul Kumar <rahul1.kumar@...> Acked-by: Ray Ni <ray.ni@...> Signed-off-by: Tom Lendacky <thomas.lendacky@...> --- UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm b/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm index 5d30f35b201c..5532a1d391bc 100644 --- a/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm +++ b/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm @@ -533,6 +533,12 @@ BITS 64 mov rax, 0x80000004 ; VMGEXIT AP_RESET_HOLD mov [rdx + 0x390], rax + mov rax, 114 ; Set SwExitCode valid bit + bts [rdx + 0x3f0], rax + inc rax ; Set SwExitInfo1 valid bit + bts [rdx + 0x3f0], rax + inc rax ; Set SwExitInfo2 valid bit + bts [rdx + 0x3f0], rax pop rdx pop rcx -- 2.28.0
|
|||
|
|||
[PATCH v3 06/11] OvmfPkg/VmgExitLib: Set the SwScratch valid bit for MMIO events
Lendacky, Thomas
From: Tom Lendacky <thomas.lendacky@...>
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3008 All fields that are set in the GHCB should have their associated bit in the GHCB ValidBitmap field set. Add support to set the bit for the scratch area field (SwScratch). Fixes: c45f678a1ea2080344e125dc55b14e4b9f98483d Cc: Jordan Justen <jordan.l.justen@...> Cc: Laszlo Ersek <lersek@...> Cc: Ard Biesheuvel <ard.biesheuvel@...> Cc: Tom Lendacky <thomas.lendacky@...> Cc: Brijesh Singh <brijesh.singh@...> Reviewed-by: Laszlo Ersek <lersek@...> Signed-off-by: Tom Lendacky <thomas.lendacky@...> --- OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c b/OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c index e5f14035b06f..9bf9d160179c 100644 --- a/OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c +++ b/OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c @@ -664,6 +664,7 @@ MmioExit ( CopyMem (Ghcb->SharedBuffer, &InstructionData->Ext.RegData, Bytes); Ghcb->SaveArea.SwScratch = (UINT64) Ghcb->SharedBuffer; + VmgSetOffsetValid (Ghcb, GhcbSwScratch); Status = VmgExit (Ghcb, SVM_EXIT_MMIO_WRITE, ExitInfo1, ExitInfo2); if (Status != 0) { return Status; @@ -693,6 +694,7 @@ MmioExit ( CopyMem (Ghcb->SharedBuffer, InstructionData->Immediate, Bytes); Ghcb->SaveArea.SwScratch = (UINT64) Ghcb->SharedBuffer; + VmgSetOffsetValid (Ghcb, GhcbSwScratch); Status = VmgExit (Ghcb, SVM_EXIT_MMIO_WRITE, ExitInfo1, ExitInfo2); if (Status != 0) { return Status; @@ -725,6 +727,7 @@ MmioExit ( ExitInfo2 = Bytes; Ghcb->SaveArea.SwScratch = (UINT64) Ghcb->SharedBuffer; + VmgSetOffsetValid (Ghcb, GhcbSwScratch); Status = VmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2); if (Status != 0) { return Status; @@ -755,6 +758,7 @@ MmioExit ( ExitInfo2 = Bytes; Ghcb->SaveArea.SwScratch = (UINT64) Ghcb->SharedBuffer; + VmgSetOffsetValid (Ghcb, GhcbSwScratch); Status = VmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2); if (Status != 0) { return Status; @@ -780,6 +784,7 @@ MmioExit ( ExitInfo2 = Bytes; Ghcb->SaveArea.SwScratch = (UINT64) Ghcb->SharedBuffer; + VmgSetOffsetValid (Ghcb, GhcbSwScratch); Status = VmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2); if (Status != 0) { return Status; -- 2.28.0
|
|||
|