diff --git a/misc/efi-stub/Makefile b/misc/efi-stub/Makefile
new file mode 100644
index 000000000..48adf2902
--- /dev/null
+++ b/misc/efi-stub/Makefile
@@ -0,0 +1,96 @@
+#
+# Copyright (c) 2011 - 2021, Intel Corporation
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+HV_OBJDIR:=build
+HV_SRC:=../../hypervisor
+C_SRCS = boot.c pe.c malloc.c container.c
+ACRN_OBJS := $(patsubst %.c,$(EFI_OBJDIR)/%.o,$(C_SRCS))
+INCLUDE_PATH += $(INCDIR)/efi
+INCLUDE_PATH += $(HV_OBJDIR)/include
+INCLUDE_PATH += $(HV_SRC)/include/public
+INCLUDE_PATH += $(HV_SRC)/include/lib
+
+BOARD ?= tgl-rvp
+SCENARIO ?= hybrid_rt
+
+OBJCOPY=objcopy
+
+ARCH := x86_64
+FORMAT := efi-app-x86-64
+
+# Different Linux distributions have the 'gnu-efi' package install
+# its tools and libraries in different folders. The next couple of
+# variables will determine and set the right path for both the
+# tools $(GNUEFI_DIR) and libraries $(LIBDIR)
+GNUEFI_DIR := $(shell find $(SYSROOT)/usr/lib* -name elf_$(ARCH)_efi.lds -type f | xargs dirname)
+LIBDIR := $(subst gnuefi,,$(GNUEFI_DIR))
+CRT0 := $(GNUEFI_DIR)/crt0-efi-$(ARCH).o
+LDSCRIPT := $(GNUEFI_DIR)/elf_$(ARCH)_efi.lds
+
+INCDIR := $(SYSROOT)/usr/include
+
+CFLAGS=-I. -I.. -I$(INCDIR)/efi -I$(INCDIR)/efi/$(ARCH) \
+ -DEFI_FUNCTION_WRAPPER -fPIC -fshort-wchar -ffreestanding \
+ -Wall -I../fs/ -D$(ARCH) -O2 \
+ -include config.h
+
+CFLAGS += -mno-mmx -mno-sse -mno-sse2 -mno-80387 -mno-fp-ret-in-387
+
+CFLAGS += -fno-delete-null-pointer-checks -fwrapv -mno-red-zone
+
+LDFLAGS=-T $(LDSCRIPT) -Bsymbolic -shared -nostdlib -znocombreloc \
+ -L$(LIBDIR) $(CRT0)
+BOOT=$(EFI_OBJDIR)/boot.efi
+
+all: $(BOOT)
+
+$(BOOT): $(EFI_OBJDIR)/boot.so
+
+$(EFI_OBJDIR)/boot.so: $(ACRN_OBJS)
+ $(LD) $(LDFLAGS) -o $@ $^ -lgnuefi -lefi $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
+
+clean:
+ rm -f $(BOOT) $(EFI_OBJDIR)/boot.so $(ACRN_OBJS)
+
+-include $(ACRN_OBJS:.o=.d)
+
+$(EFI_OBJDIR)/%.o:%.S
+ [ ! -e $@ ] && mkdir -p $(dir $@); \
+ $(CC) $(CFLAGS) -c -o $@ $< -MMD -MT $@
+
+$(EFI_OBJDIR)/%.o: %.c
+ [ ! -e $@ ] && mkdir -p $(dir $@); \
+ $(CC) $(patsubst %, -I%, $(INCLUDE_PATH)) -I. -c $(CFLAGS) $(ARCH_CFLAGS) $< -o $@ -MMD -MT $@
+
+%.efi: %.so
+ $(OBJCOPY) -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel \
+ -j .rela -j .reloc --target=$(FORMAT) $*.so $@
diff --git a/misc/efi-stub/MpService.h b/misc/efi-stub/MpService.h
new file mode 100644
index 000000000..c31805328
--- /dev/null
+++ b/misc/efi-stub/MpService.h
@@ -0,0 +1,633 @@
+/** @file
+ When installed, the MP Services Protocol produces a collection of services
+ that are needed for MP management.
+
+ The MP Services Protocol provides a generalized way of performing following tasks:
+ - Retrieving information of multi-processor environment and MP-related status of
+ specific processors.
+ - Dispatching user-provided function to APs.
+ - Maintain MP-related processor status.
+
+ The MP Services Protocol must be produced on any system with more than one logical
+ processor.
+
+ The Protocol is available only during boot time.
+
+ MP Services Protocol is hardware-independent. Most of the logic of this protocol
+ is architecturally neutral. It abstracts the multi-processor environment and
+ status of processors, and provides interfaces to retrieve information, maintain,
+ and dispatch.
+
+ MP Services Protocol may be consumed by ACPI module. The ACPI module may use this
+ protocol to retrieve data that are needed for an MP platform and report them to OS.
+ MP Services Protocol may also be used to program and configure processors, such
+ as MTRR synchronization for memory space attributes setting in DXE Services.
+ MP Services Protocol may be used by non-CPU DXE drivers to speed up platform boot
+ by taking advantage of the processing capabilities of the APs, for example, using
+ APs to help test system memory in parallel with other device initialization.
+ Diagnostics applications may also use this protocol for multi-processor.
+
+Copyright (c) 2006 - 2021, 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.
+
+ @par Revision Reference:
+ This Protocol is defined in the UEFI Platform Initialization Specification 1.2,
+ Volume 2:Driver Execution Environment Core Interface.
+
+**/
+
+#ifndef _MP_SERVICE_PROTOCOL_H_
+#define _MP_SERVICE_PROTOCOL_H_
+
+typedef VOID(EFIAPI * EFI_AP_PROCEDURE )(IN OUT VOID *Buffer);
+///
+/// Global ID for the EFI_MP_SERVICES_PROTOCOL.
+///
+#define EFI_MP_SERVICES_PROTOCOL_GUID \
+ { \
+ 0x3fdda605, 0xa76e, 0x4f46, {0xad, 0x29, 0x12, 0xf4, 0x53, 0x1b, 0x3d, 0x08} \
+ }
+
+///
+/// Forward declaration for the EFI_MP_SERVICES_PROTOCOL.
+///
+typedef struct _EFI_MP_SERVICES_PROTOCOL EFI_MP_SERVICES_PROTOCOL;
+
+///
+/// Terminator for a list of failed CPUs returned by StartAllAPs().
+///
+#define END_OF_CPU_LIST 0xffffffff
+
+///
+/// This bit is used in the StatusFlag field of EFI_PROCESSOR_INFORMATION and
+/// indicates whether the processor is playing the role of BSP. If the bit is 1,
+/// then the processor is BSP. Otherwise, it is AP.
+///
+#define PROCESSOR_AS_BSP_BIT 0x00000001
+
+///
+/// This bit is used in the StatusFlag field of EFI_PROCESSOR_INFORMATION and
+/// indicates whether the processor is enabled. If the bit is 1, then the
+/// processor is enabled. Otherwise, it is disabled.
+///
+#define PROCESSOR_ENABLED_BIT 0x00000002
+
+///
+/// This bit is used in the StatusFlag field of EFI_PROCESSOR_INFORMATION and
+/// indicates whether the processor is healthy. If the bit is 1, then the
+/// processor is healthy. Otherwise, some fault has been detected for the processor.
+///
+#define PROCESSOR_HEALTH_STATUS_BIT 0x00000004
+
+///
+/// Structure that describes the pyhiscal location of a logical CPU.
+///
+typedef struct {
+ ///
+ /// Zero-based physical package number that identifies the cartridge of the processor.
+ ///
+ UINT32 Package;
+ ///
+ /// Zero-based physical core number within package of the processor.
+ ///
+ UINT32 Core;
+ ///
+ /// Zero-based logical thread number within core of the processor.
+ ///
+ UINT32 Thread;
+} EFI_CPU_PHYSICAL_LOCATION;
+
+///
+/// Structure that describes information about a logical CPU.
+///
+typedef struct {
+ ///
+ /// The unique processor ID determined by system hardware. For IA32 and X64,
+ /// the processor ID is the same as the Local APIC ID. Only the lower 8 bits
+ /// are used, and higher bits are reserved. For IPF, the lower 16 bits contains
+ /// id/eid, and higher bits are reserved.
+ ///
+ UINT64 ProcessorId;
+ ///
+ /// Flags indicating if the processor is BSP or AP, if the processor is enabled
+ /// or disabled, and if the processor is healthy. Bits 3..31 are reserved and
+ /// must be 0.
+ ///
+ ///
+ /// BSP ENABLED HEALTH Description
+ /// === ======= ====== ===================================================
+ /// 0 0 0 Unhealthy Disabled AP.
+ /// 0 0 1 Healthy Disabled AP.
+ /// 0 1 0 Unhealthy Enabled AP.
+ /// 0 1 1 Healthy Enabled AP.
+ /// 1 0 0 Invalid. The BSP can never be in the disabled state.
+ /// 1 0 1 Invalid. The BSP can never be in the disabled state.
+ /// 1 1 0 Unhealthy Enabled BSP.
+ /// 1 1 1 Healthy Enabled BSP.
+ ///
+ ///
+ UINT32 StatusFlag;
+ ///
+ /// The physical location of the processor, including the physical package number
+ /// that identifies the cartridge, the physical core number within package, and
+ /// logical thread number within core.
+ ///
+ EFI_CPU_PHYSICAL_LOCATION Location;
+} EFI_PROCESSOR_INFORMATION;
+
+/**
+ This service retrieves the number of logical processor in the platform
+ and the number of those logical processors that are enabled on this boot.
+ This service may only be called from the BSP.
+
+ This function is used to retrieve the following information:
+ - The number of logical processors that are present in the system.
+ - The number of enabled logical processors in the system at the instant
+ this call is made.
+
+ Because MP Service Protocol provides services to enable and disable processors
+ dynamically, the number of enabled logical processors may vary during the
+ course of a boot session.
+
+ If this service is called from an AP, then EFI_DEVICE_ERROR is returned.
+ If NumberOfProcessors or NumberOfEnabledProcessors is NULL, then
+ EFI_INVALID_PARAMETER is returned. Otherwise, the total number of processors
+ is returned in NumberOfProcessors, the number of currently enabled processor
+ is returned in NumberOfEnabledProcessors, and EFI_SUCCESS is returned.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
+ instance.
+ @param[out] NumberOfProcessors Pointer to the total number of logical
+ processors in the system, including the BSP
+ and disabled APs.
+ @param[out] NumberOfEnabledProcessors Pointer to the number of enabled logical
+ processors that exist in system, including
+ the BSP.
+
+ @retval EFI_SUCCESS The number of logical processors and enabled
+ logical processors was retrieved.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL.
+ @retval EFI_INVALID_PARAMETER NumberOfEnabledProcessors is NULL.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_MP_SERVICES_GET_NUMBER_OF_PROCESSORS)(
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ OUT UINTN *NumberOfProcessors,
+ OUT UINTN *NumberOfEnabledProcessors
+ );
+
+/**
+ Gets detailed MP-related information on the requested processor at the
+ instant this call is made. This service may only be called from the BSP.
+
+ This service retrieves detailed MP-related information about any processor
+ on the platform. Note the following:
+ - The processor information may change during the course of a boot session.
+ - The information presented here is entirely MP related.
+
+ Information regarding the number of caches and their sizes, frequency of operation,
+ slot numbers is all considered platform-related information and is not provided
+ by this service.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_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_MP_SERVICES_GET_PROCESSOR_INFO)(
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN UINTN ProcessorNumber,
+ OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer
+ );
+
+/**
+ This service executes a caller provided function on all enabled APs. APs can
+ run either simultaneously or one at a time in sequence. This service supports
+ both blocking and non-blocking requests. The non-blocking requests use EFI
+ events so the BSP can detect when the APs have finished. This service may only
+ be called from the BSP.
+
+ This function is used to dispatch all the enabled APs to the function specified
+ by Procedure. If any enabled AP is busy, then EFI_NOT_READY is returned
+ immediately and Procedure is not started on any AP.
+
+ If SingleThread is TRUE, all the enabled APs execute the function specified by
+ Procedure one by one, in ascending order of processor handle number. Otherwise,
+ all the enabled APs execute the function specified by Procedure simultaneously.
+
+ If WaitEvent is NULL, execution is in blocking mode. The BSP waits until all
+ APs finish or TimeoutInMicroSecs expires. Otherwise, execution is in non-blocking
+ mode, and the BSP returns from this service without waiting for APs. If a
+ non-blocking mode is requested after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT
+ is signaled, then EFI_UNSUPPORTED must be returned.
+
+ If the timeout specified by TimeoutInMicroseconds expires before all APs return
+ from Procedure, then Procedure on the failed APs is terminated. All enabled APs
+ are always available for further calls to EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
+ and EFI_MP_SERVICES_PROTOCOL.StartupThisAP(). If FailedCpuList is not NULL, its
+ content points to the list of processor handle numbers in which Procedure was
+ terminated.
+
+ Note: It is the responsibility of the consumer of the EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
+ to make sure that the nature of the code that is executed on the BSP and the
+ dispatched APs is well controlled. The MP Services Protocol does not guarantee
+ that the Procedure function is MP-safe. Hence, the tasks that can be run in
+ parallel are limited to certain independent tasks and well-controlled exclusive
+ code. EFI services and protocols may not be called by APs unless otherwise
+ specified.
+
+ In blocking execution mode, BSP waits until all APs finish or
+ TimeoutInMicroSeconds expires.
+
+ In non-blocking execution mode, BSP is freed to return to the caller and then
+ proceed to the next task without having to wait for APs. The following
+ sequence needs to occur in a non-blocking execution mode:
+
+ -# The caller that intends to use this MP Services Protocol in non-blocking
+ mode creates WaitEvent by calling the EFI CreateEvent() service. The caller
+ invokes EFI_MP_SERVICES_PROTOCOL.StartupAllAPs(). If the parameter WaitEvent
+ is not NULL, then StartupAllAPs() executes in non-blocking mode. It requests
+ the function specified by Procedure to be started on all the enabled APs,
+ and releases the BSP to continue with other tasks.
+ -# The caller can use the CheckEvent() and WaitForEvent() services to check
+ the state of the WaitEvent created in step 1.
+ -# When the APs complete their task or TimeoutInMicroSecondss expires, the MP
+ Service signals WaitEvent by calling the EFI SignalEvent() function. If
+ FailedCpuList is not NULL, its content is available when WaitEvent is
+ signaled. If all APs returned from Procedure prior to the timeout, then
+ FailedCpuList is set to NULL. If not all APs return from Procedure before
+ the timeout, then FailedCpuList is filled in with the list of the failed
+ APs. The buffer is allocated by MP Service Protocol using AllocatePool().
+ It is the caller's responsibility to free the buffer with FreePool() service.
+ -# This invocation of SignalEvent() function informs the caller that invoked
+ EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() that either all the APs completed
+ the specified task or a timeout occurred. The contents of FailedCpuList
+ can be examined to determine which APs did not complete the specified task
+ prior to the timeout.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
+ instance.
+ @param[in] Procedure A pointer to the function to be run on
+ enabled APs of the system. See type
+ EFI_AP_PROCEDURE.
+ @param[in] SingleThread If TRUE, then all the enabled APs execute
+ the function specified by Procedure one by
+ one, in ascending order of processor handle
+ number. If FALSE, then all the enabled APs
+ execute the function specified by Procedure
+ simultaneously.
+ @param[in] WaitEvent The event created by the caller with CreateEvent()
+ service. If it is NULL, then execute in
+ blocking mode. BSP waits until all APs finish
+ or TimeoutInMicroSeconds expires. If it's
+ not NULL, then execute in non-blocking mode.
+ BSP requests the function specified by
+ Procedure to be started on all the enabled
+ APs, and go on executing immediately. If
+ all return from Procedure, or TimeoutInMicroSeconds
+ expires, this event is signaled. The BSP
+ can use the CheckEvent() or WaitForEvent()
+ services to check the state of event. Type
+ EFI_EVENT is defined in CreateEvent() in
+ the Unified Extensible Firmware Interface
+ Specification.
+ @param[in] TimeoutInMicrosecsond Indicates the time limit in microseconds for
+ APs to return from Procedure, either for
+ blocking or non-blocking mode. Zero means
+ infinity. If the timeout expires before
+ all APs return from Procedure, then Procedure
+ on the failed APs is terminated. All enabled
+ APs are available for next function assigned
+ by EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
+ or EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
+ If the timeout expires in blocking mode,
+ BSP returns EFI_TIMEOUT. If the timeout
+ expires in non-blocking mode, WaitEvent
+ is signaled with SignalEvent().
+ @param[in] ProcedureArgument The parameter passed into Procedure for
+ all APs.
+ @param[out] FailedCpuList If NULL, this parameter is ignored. Otherwise,
+ if all APs finish successfully, then its
+ content is set to NULL. If not all APs
+ finish before timeout expires, then its
+ content is set to address of the buffer
+ holding handle numbers of the failed APs.
+ The buffer is allocated by MP Service Protocol,
+ and it's the caller's responsibility to
+ free the buffer with FreePool() service.
+ In blocking mode, it is ready for consumption
+ when the call returns. In non-blocking mode,
+ it is ready when WaitEvent is signaled. The
+ list of failed CPU is terminated by
+ END_OF_CPU_LIST.
+
+ @retval EFI_SUCCESS In blocking mode, all APs have finished before
+ the timeout expired.
+ @retval EFI_SUCCESS In non-blocking mode, function has been dispatched
+ to all enabled APs.
+ @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
+ UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
+ signaled.
+ @retval EFI_DEVICE_ERROR Caller processor is AP.
+ @retval EFI_NOT_STARTED No enabled APs exist in the system.
+ @retval EFI_NOT_READY Any enabled APs are busy.
+ @retval EFI_TIMEOUT In blocking mode, the timeout expired before
+ all enabled APs have finished.
+ @retval EFI_INVALID_PARAMETER Procedure is NULL.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_MP_SERVICES_STARTUP_ALL_APS)(
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN EFI_AP_PROCEDURE Procedure,
+ IN BOOLEAN SingleThread,
+ IN EFI_EVENT WaitEvent OPTIONAL,
+ IN UINTN TimeoutInMicroSeconds,
+ IN VOID *ProcedureArgument OPTIONAL,
+ OUT UINTN **FailedCpuList OPTIONAL
+ );
+
+/**
+ This service lets the caller get one enabled AP to execute a caller-provided
+ function. The caller can request the BSP to either wait for the completion
+ of the AP or just proceed with the next task by using the EFI event mechanism.
+ See EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() for more details on non-blocking
+ execution support. This service may only be called from the BSP.
+
+ This function is used to dispatch one enabled AP to the function specified by
+ Procedure passing in the argument specified by ProcedureArgument. If WaitEvent
+ is NULL, execution is in blocking mode. The BSP waits until the AP finishes or
+ TimeoutInMicroSecondss expires. Otherwise, execution is in non-blocking mode.
+ BSP proceeds to the next task without waiting for the AP. If a non-blocking mode
+ is requested after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT is signaled,
+ then EFI_UNSUPPORTED must be returned.
+
+ If the timeout specified by TimeoutInMicroseconds expires before the AP returns
+ from Procedure, then execution of Procedure by the AP is terminated. The AP is
+ available for subsequent calls to EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() and
+ EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
+ instance.
+ @param[in] Procedure A pointer to the function to be run on the
+ designated AP of the system. See type
+ EFI_AP_PROCEDURE.
+ @param[in] ProcessorNumber The handle number of the AP. The range is
+ from 0 to the total number of logical
+ processors minus 1. The total number of
+ logical processors can be retrieved by
+ EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
+ @param[in] WaitEvent The event created by the caller with CreateEvent()
+ service. If it is NULL, then execute in
+ blocking mode. BSP waits until this AP finish
+ or TimeoutInMicroSeconds expires. If it's
+ not NULL, then execute in non-blocking mode.
+ BSP requests the function specified by
+ Procedure to be started on this AP,
+ and go on executing immediately. If this AP
+ return from Procedure or TimeoutInMicroSeconds
+ expires, this event is signaled. The BSP
+ can use the CheckEvent() or WaitForEvent()
+ services to check the state of event. Type
+ EFI_EVENT is defined in CreateEvent() in
+ the Unified Extensible Firmware Interface
+ Specification.
+ @param[in] TimeoutInMicrosecsond Indicates the time limit in microseconds for
+ this AP to finish this Procedure, either for
+ blocking or non-blocking mode. Zero means
+ infinity. If the timeout expires before
+ this AP returns from Procedure, then Procedure
+ on the AP is terminated. The
+ AP is available for next function assigned
+ by EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
+ or EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
+ If the timeout expires in blocking mode,
+ BSP returns EFI_TIMEOUT. If the timeout
+ expires in non-blocking mode, WaitEvent
+ is signaled with SignalEvent().
+ @param[in] ProcedureArgument The parameter passed into Procedure on the
+ specified AP.
+ @param[out] Finished If NULL, this parameter is ignored. In
+ blocking mode, this parameter is ignored.
+ In non-blocking mode, if AP returns from
+ Procedure before the timeout expires, its
+ content is set to TRUE. Otherwise, the
+ value is set to FALSE. The caller can
+ determine if the AP returned from Procedure
+ by evaluating this value.
+
+ @retval EFI_SUCCESS In blocking mode, specified AP finished before
+ the timeout expires.
+ @retval EFI_SUCCESS In non-blocking mode, the function has been
+ dispatched to specified AP.
+ @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
+ UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
+ signaled.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_TIMEOUT In blocking mode, the timeout expired before
+ the specified AP has finished.
+ @retval EFI_NOT_READY The specified AP is busy.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.
+ @retval EFI_INVALID_PARAMETER Procedure is NULL.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_MP_SERVICES_STARTUP_THIS_AP)(
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN EFI_AP_PROCEDURE Procedure,
+ IN UINTN ProcessorNumber,
+ IN EFI_EVENT WaitEvent OPTIONAL,
+ IN UINTN TimeoutInMicroseconds,
+ IN VOID *ProcedureArgument OPTIONAL,
+ OUT BOOLEAN *Finished OPTIONAL
+ );
+
+/**
+ 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. This service may not be supported after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT
+ is signaled.
+
+ 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_MP_SERVICES_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. The total number of
+ logical processors can be retrieved by
+ EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
+ @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an
+ enabled AP. Otherwise, it will be disabled.
+
+ @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_DEVICE_ERROR 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_MP_SERVICES_SWITCH_BSP)(
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN UINTN ProcessorNumber,
+ IN BOOLEAN EnableOldBSP
+ );
+
+/**
+ This service lets the caller enable or disable an AP from this point onward.
+ This service may only be called from the BSP.
+
+ This service allows the caller enable or disable an AP from this point onward.
+ The caller can optionally specify the health status of the AP by Health. If
+ an AP is being disabled, then the state of the disabled AP is implementation
+ dependent. If an AP is enabled, then the implementation must guarantee that a
+ complete initialization sequence is performed on the AP, so the AP is in a state
+ that is compatible with an MP operating system. This service may not be supported
+ after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT is signaled.
+
+ If the enable or disable AP operation cannot be completed prior to the return
+ from this service, then EFI_UNSUPPORTED must be returned.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
+ @param[in] ProcessorNumber The handle number of AP.
+ The range is from 0 to the total number of
+ logical processors minus 1. The total number of
+ logical processors can be retrieved by
+ EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
+ @param[in] EnableAP Specifies the new state for the processor for
+ enabled, FALSE for disabled.
+ @param[in] HealthFlag If not NULL, a pointer to a value that specifies
+ the new health status of the AP. This flag
+ corresponds to StatusFlag defined in
+ EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only
+ the PROCESSOR_HEALTH_STATUS_BIT is used. All other
+ bits are ignored. If it is NULL, this parameter
+ is ignored.
+
+ @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
+ @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed
+ prior to this service returning.
+ @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber
+ does not exist.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_MP_SERVICES_ENABLEDISABLEAP)(
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN UINTN ProcessorNumber,
+ IN BOOLEAN EnableAP,
+ IN UINT32 *HealthFlag OPTIONAL
+ );
+
+/**
+ 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. The total number of logical processors can be retrieved
+ with EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors(). 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_MP_SERVICES_PROTOCOL instance.
+ @param[in] ProcessorNumber Pointer to the handle number of AP.
+ The range is from 0 to the total number of
+ logical processors minus 1. The total number of
+ logical processors can be retrieved by
+ EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
+
+ @retval EFI_SUCCESS The current processor handle number was returned
+ in ProcessorNumber.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_MP_SERVICES_WHOAMI)(
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ OUT UINTN *ProcessorNumber
+ );
+
+///
+/// When installed, the MP Services Protocol produces a collection of services
+/// that are needed for MP management.
+///
+/// Before the UEFI event EFI_EVENT_GROUP_READY_TO_BOOT is signaled, the module
+/// that produces this protocol is required to place all APs into an idle state
+/// whenever the APs are disabled or the APs are not executing code as requested
+/// through the StartupAllAPs() or StartupThisAP() services. The idle state of
+/// an AP before the UEFI event EFI_EVENT_GROUP_READY_TO_BOOT is signaled is
+/// implementation dependent.
+///
+/// After the UEFI event EFI_EVENT_GROUP_READY_TO_BOOT is signaled, all the APs
+/// must be placed in the OS compatible CPU state as defined by the UEFI
+/// Specification. Implementations of this protocol may use the UEFI event
+/// EFI_EVENT_GROUP_READY_TO_BOOT to force APs into the OS compatible state as
+/// defined by the UEFI Specification. Modules that use this protocol must
+/// guarantee that all non-blocking mode requests on all APs have been completed
+/// before the UEFI event EFI_EVENT_GROUP_READY_TO_BOOT is signaled. Since the
+/// order that event notification functions in the same event group are executed
+/// is not deterministic, an event of type EFI_EVENT_GROUP_READY_TO_BOOT cannot
+/// be used to guarantee that APs have completed their non-blocking mode requests.
+///
+/// When the UEFI event EFI_EVENT_GROUP_READY_TO_BOOT is signaled, the StartAllAPs()
+/// and StartupThisAp() services must no longer support non-blocking mode requests.
+/// The support for SwitchBSP() and EnableDisableAP() may no longer be supported
+/// after this event is signaled. Since UEFI Applications and UEFI OS Loaders
+/// execute after the UEFI event EFI_EVENT_GROUP_READY_TO_BOOT is signaled, these
+/// UEFI images must be aware that the functionality of this protocol may be reduced.
+///
+struct _EFI_MP_SERVICES_PROTOCOL {
+ EFI_MP_SERVICES_GET_NUMBER_OF_PROCESSORS GetNumberOfProcessors;
+ EFI_MP_SERVICES_GET_PROCESSOR_INFO GetProcessorInfo;
+ EFI_MP_SERVICES_STARTUP_ALL_APS StartupAllAPs;
+ EFI_MP_SERVICES_STARTUP_THIS_AP StartupThisAP;
+ EFI_MP_SERVICES_SWITCH_BSP SwitchBSP;
+ EFI_MP_SERVICES_ENABLEDISABLEAP EnableDisableAP;
+ EFI_MP_SERVICES_WHOAMI WhoAmI;
+};
+
+extern EFI_GUID gEfiMpServiceProtocolGuid;
+
+#endif
diff --git a/misc/efi-stub/boot.c b/misc/efi-stub/boot.c
new file mode 100644
index 000000000..b587e168c
--- /dev/null
+++ b/misc/efi-stub/boot.c
@@ -0,0 +1,623 @@
+/*
+ * Copyright (c) 2011 - 2021, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include
+#include
+#include "efilinux.h"
+#include "stdlib.h"
+#include "boot.h"
+#include "acrn_common.h"
+#include "MpService.h"
+#include "container.h"
+
+EFI_SYSTEM_TABLE *sys_table;
+EFI_BOOT_SERVICES *boot;
+HV_LOADER hvld;
+
+static EFI_STATUS
+get_efi_memmap(struct efi_memmap_info *mi, int size_only)
+{
+ UINTN map_size, map_key;
+ UINT32 desc_version;
+ UINTN desc_size;
+ EFI_MEMORY_DESCRIPTOR *map_buf;
+ EFI_STATUS err = EFI_SUCCESS;
+
+ /* We're just interested in the map's size for now */
+ map_size = 0;
+ err = get_memory_map(&map_size, NULL, NULL, &desc_size, NULL);
+ if (err != EFI_SUCCESS && err != EFI_BUFFER_TOO_SMALL)
+ goto out;
+
+ if (size_only) {
+ mi->map_size = map_size;
+ mi->desc_size = desc_size;
+ return err;
+ }
+
+again:
+ err = allocate_pool(EfiLoaderData, map_size, (void **) &map_buf);
+ if (err != EFI_SUCCESS)
+ goto out;
+
+ /*
+ * Remember! We've already allocated map_buf with emalloc (and
+ * 'map_size' contains its size) which means that it should be
+ * positioned below our allocation for the kernel. Use that
+ * space for the memory map.
+ */
+ err = get_memory_map(&map_size, map_buf, &map_key,
+ &desc_size, &desc_version);
+ if (err != EFI_SUCCESS) {
+ if (err == EFI_BUFFER_TOO_SMALL) {
+ /*
+ * Argh! The buffer that we allocated further
+ * up wasn't large enough which means we need
+ * to allocate them again, but this time
+ * larger. 'map_size' has been updated by the
+ * call to memory_map().
+ */
+ free_pool(map_buf);
+ goto again;
+ }
+ goto out;
+ }
+
+ mi->map_size = map_size;
+ mi->map_key = map_key;
+ mi->desc_version = desc_version;
+ mi->desc_size = desc_size;
+ mi->mmap = map_buf;
+
+out:
+ return err;
+}
+
+static EFI_STATUS
+terminate_boot_services(EFI_HANDLE image, struct efi_memmap_info *mmap_info)
+{
+ EFI_STATUS err = EFI_SUCCESS;
+
+ err = exit_boot_services(image, mmap_info->map_key);
+ if (err != EFI_SUCCESS) {
+ if (err == EFI_INVALID_PARAMETER) {
+ /*
+ * Incorrect map key: memory map changed during the call of get_memory_map
+ * and exit_boot_services.
+ * We must call get_memory_map and exit_boot_services one more time.
+ * We can't allocate nor free pool since exit_boot_services has already been called.
+ * Original memory pool should be sufficient and this call is expected to succeed.
+ */
+ err = get_memory_map(&mmap_info->map_size, mmap_info->mmap,
+ &mmap_info->map_key, &mmap_info->desc_size, &mmap_info->desc_version);
+ if (err != EFI_SUCCESS)
+ goto out;
+
+ err = exit_boot_services(image, mmap_info->map_key);
+ if (err != EFI_SUCCESS)
+ goto out;
+ }
+ }
+
+out:
+ return err;
+}
+
+static inline void hv_jump(EFI_PHYSICAL_ADDRESS hv_start,
+ struct multiboot_info *mbi)
+{
+ hv_func hf;
+
+ /* The 64-bit entry of acrn hypervisor is 0x1200 from the start
+ * address of hv image.
+ */
+ hf = (hv_func)(hv_start + 0x1200);
+
+ asm volatile ("cli");
+
+ /* jump to acrn hypervisor */
+ hf(MB_INFO_MAGIC, mbi);
+}
+
+static EFI_STATUS
+fill_e820(HV_LOADER hvld, struct efi_memmap_info *mmap_info,
+ struct multiboot_mmap *mmap, int32_t *e820_count)
+{
+ EFI_STATUS err = EFI_SUCCESS;
+ uint32_t mmap_entry_count = mmap_info->map_size / mmap_info->desc_size;
+ int32_t i, j;
+
+ /*
+ * Convert the EFI memory map to E820.
+ */
+ for (i = 0, j = 0; i < mmap_entry_count && j < MBOOT_MMAP_NUMS - 1; i++) {
+ EFI_MEMORY_DESCRIPTOR *d;
+ uint32_t e820_type = 0;
+
+ d = (EFI_MEMORY_DESCRIPTOR *)((uint64_t)mmap_info->mmap + \
+ (i * mmap_info->desc_size));
+ switch(d->Type) {
+ case EfiReservedMemoryType:
+ case EfiRuntimeServicesCode:
+ case EfiRuntimeServicesData:
+ case EfiMemoryMappedIO:
+ case EfiMemoryMappedIOPortSpace:
+ case EfiPalCode:
+ e820_type = E820_RESERVED;
+ break;
+
+ case EfiUnusableMemory:
+ e820_type = E820_UNUSABLE;
+ break;
+
+ case EfiACPIReclaimMemory:
+ e820_type = E820_ACPI;
+ break;
+
+ case EfiLoaderCode:
+ case EfiLoaderData:
+ case EfiBootServicesCode:
+ case EfiBootServicesData:
+ case EfiConventionalMemory:
+ e820_type = E820_RAM;
+ break;
+
+ case EfiACPIMemoryNVS:
+ e820_type = E820_NVS;
+ break;
+
+ default:
+ continue;
+ }
+
+ if ((j != 0) && mmap[j-1].mm_type == e820_type &&
+ (mmap[j-1].mm_base_addr + mmap[j-1].mm_length)
+ == d->PhysicalStart) {
+ mmap[j-1].mm_length += d->NumberOfPages << EFI_PAGE_SHIFT;
+ } else {
+ mmap[j].mm_base_addr = d->PhysicalStart;
+ mmap[j].mm_length = d->NumberOfPages << EFI_PAGE_SHIFT;
+ mmap[j].mm_type = e820_type;
+ j++;
+ }
+ }
+
+ /*
+ * if we haven't gone through all the mmap table entries,
+ * there must be a memory overwrite if we continue,
+ * so just abort anyway.
+ */
+ if (i < mmap_entry_count) {
+ Print(L": bios provides %d mmap entries which is beyond limitation[%d]\n",
+ mmap_entry_count, MBOOT_MMAP_NUMS-1);
+ err = EFI_INVALID_PARAMETER;
+ goto out;
+ }
+
+ /* switch hv memory region(0x20000000 ~ 0x22000000) to
+ * available RAM in e820 table
+ */
+ mmap[j].mm_base_addr = hvld->get_hv_hpa(hvld);
+ mmap[j].mm_length = CONFIG_HV_RAM_SIZE;
+ mmap[j].mm_type = E820_RAM;
+ j++;
+
+ mmap[j].mm_base_addr = hvld->get_mod_hpa(hvld);
+ mmap[j].mm_length = hvld->get_total_modsize(hvld);
+ mmap[j].mm_type = E820_RAM;
+ j++;
+
+ *e820_count = j;
+out:
+ return err;
+}
+
+
+EFI_STATUS construct_mbi(HV_LOADER hvld, struct multiboot_info **mbinfo, struct efi_memmap_info *mmap_info)
+{
+ EFI_STATUS err = EFI_SUCCESS;
+ int32_t e820_count = 0;
+ EFI_PHYSICAL_ADDRESS addr;
+ struct multiboot_mmap *mmap;
+ struct multiboot_info *mbi;
+ char *uefi_boot_loader_name;
+ static const char loader_name[BOOT_LOADER_NAME_SIZE] = UEFI_BOOT_LOADER_NAME;
+
+ err = allocate_pool(EfiLoaderData, EFI_BOOT_MEM_SIZE, (VOID *)&addr);
+ if (err != EFI_SUCCESS) {
+ Print(L"Failed to allocate memory for EFI boot\n");
+ goto out;
+ }
+ (void)memset((void *)addr, 0x0, EFI_BOOT_MEM_SIZE);
+
+ mmap = MBOOT_MMAP_PTR(addr);
+ mbi = MBOOT_INFO_PTR(addr);
+
+ uefi_boot_loader_name = BOOT_LOADER_NAME_PTR(addr);
+ memcpy(uefi_boot_loader_name, loader_name, BOOT_LOADER_NAME_SIZE);
+
+ err = get_efi_memmap(mmap_info, 0);
+ if (err != EFI_SUCCESS)
+ goto out;
+
+ err = fill_e820(hvld, mmap_info, mmap, &e820_count);
+ if (err != EFI_SUCCESS)
+ goto out;
+
+ /* TODO: Current container library does not handle mbi1 case */
+ /* mbi->mi_cmdline = (UINTN)hv_info->cmdline; */
+ mbi->mi_mmap_addr = (UINTN)mmap;
+ mbi->mi_mmap_length = e820_count*sizeof(struct multiboot_mmap);
+ mbi->mi_flags |= MULTIBOOT_INFO_HAS_MMAP | MULTIBOOT_INFO_HAS_CMDLINE;
+
+ /* Set boot loader name in the multiboot header of UEFI, this name is used by hypervisor;
+ * The host physical start address of boot loader name is stored in multiboot header.
+ */
+ mbi->mi_flags |= MULTIBOOT_INFO_HAS_LOADER_NAME;
+ mbi->mi_loader_name = (UINT32)(uint64_t)uefi_boot_loader_name;
+
+ mbi->mi_mods_addr = hvld->get_mod_hpa(hvld);
+ mbi->mi_mods_count = hvld->get_mod_count(hvld);
+ mbi->mi_flags |= MULTIBOOT_INFO_HAS_MODS;
+
+ *mbinfo = mbi;
+out:
+ return err;
+}
+
+#ifdef CONFIG_MULTIBOOT2
+static struct acpi_table_rsdp *
+search_rsdp()
+{
+ unsigned i;
+ struct acpi_table_rsdp *rsdp = NULL;
+ EFI_CONFIGURATION_TABLE *config_table = sys_table->ConfigurationTable;
+
+ for (i = 0; i < sys_table->NumberOfTableEntries; i++) {
+ EFI_GUID acpi_20_table_guid = ACPI_20_TABLE_GUID;
+ EFI_GUID acpi_table_guid = ACPI_TABLE_GUID;
+
+ if (CompareGuid(&acpi_20_table_guid,
+ &config_table->VendorGuid) == 0) {
+ rsdp = config_table->VendorTable;
+ break;
+ }
+
+ if (CompareGuid(&acpi_table_guid,
+ &config_table->VendorGuid) == 0)
+ rsdp = config_table->VendorTable;
+
+ config_table++;
+ }
+
+ return rsdp;
+}
+
+static uint32_t
+get_mbi2_size(HV_LOADER hvld, struct efi_memmap_info *mmap_info, uint32_t rsdp_length)
+{
+ uint32_t mmap_entry_count = mmap_info->map_size / mmap_info->desc_size;
+
+ return 2 * sizeof(uint32_t) \
+ /* Boot command line */
+ + (sizeof(struct multiboot2_tag_string) + \
+ ALIGN_UP(hvld->get_boot_cmdsize(hvld), MULTIBOOT2_TAG_ALIGN)) \
+
+ /* Boot loader name */
+ + (sizeof(struct multiboot2_tag_string) + \
+ ALIGN_UP(BOOT_LOADER_NAME_SIZE, MULTIBOOT2_TAG_ALIGN)) \
+
+ /* Modules */
+ + (hvld->get_mod_count(hvld) * sizeof(struct multiboot2_tag_module) + \
+ hvld->get_total_modcmdsize(hvld)) \
+
+ /* Memory Map */
+ + ALIGN_UP((sizeof(struct multiboot2_tag_mmap) + \
+ mmap_entry_count * sizeof(struct multiboot2_mmap_entry)), MULTIBOOT2_TAG_ALIGN) \
+
+ /* ACPI new */
+ + ALIGN_UP(sizeof(struct multiboot2_tag_new_acpi) + \
+ rsdp_length, MULTIBOOT2_TAG_ALIGN) \
+
+ /* EFI64 system table */
+ + ALIGN_UP(sizeof(struct multiboot2_tag_efi64), MULTIBOOT2_TAG_ALIGN) \
+
+ /* EFI memmap: Add an extra page since UEFI can alter the memory map */
+ + ALIGN_UP(sizeof(struct multiboot2_tag_efi_mmap) + \
+ ALIGN_UP(mmap_info->map_size + 0x1000, 0x1000), MULTIBOOT2_TAG_ALIGN) \
+
+ /* END */
+ + sizeof(struct multiboot2_tag);
+}
+
+EFI_STATUS
+construct_mbi2(struct hv_loader *hvld, void **mbi_addr, struct efi_memmap_info *mmap_info)
+{
+ uint64_t *mbistart;
+ uint64_t *p;
+ uint32_t mbi2_size;
+ struct multiboot_mmap *mmap;
+ struct acpi_table_rsdp *rsdp;
+ EFI_STATUS err;
+
+ rsdp = search_rsdp();
+ if (!rsdp)
+ return EFI_NOT_FOUND;
+
+ /* Get size only for mbi size calculation */
+ err = get_efi_memmap(mmap_info, 1);
+ if (err != EFI_SUCCESS && err != EFI_BUFFER_TOO_SMALL)
+ return err;
+
+ mbi2_size = get_mbi2_size(hvld, mmap_info, rsdp->length);
+
+ /* per UEFI spec v2.9: This allocation is guaranteed to be 8-bytes aligned */
+ err = allocate_pool(EfiLoaderData, mbi2_size, (void **)&mbistart);
+ if (err != EFI_SUCCESS)
+ goto out;
+
+ memset(mbistart, 0x0, mbi2_size);
+
+ /* Allocate temp buffer to hold memory map */
+ err = allocate_pool(EfiLoaderData,
+ (mmap_info->map_size / mmap_info->desc_size) * sizeof(struct multiboot_mmap),
+ (void **)&mmap);
+ if (err != EFI_SUCCESS)
+ goto out;
+
+ /*
+ * Get full memory map again.
+ * We have just allocated memory and the mmap_info will be different.
+ */
+ err = get_efi_memmap(mmap_info, 0);
+ if (err != EFI_SUCCESS)
+ goto out;
+
+ /* total_size and reserved */
+ p = mbistart;
+ p += (2 * sizeof(uint32_t)) / sizeof(uint64_t);
+
+ /* Boot command line */
+ {
+ struct multiboot2_tag_string *tag = (struct multiboot2_tag_string *)p;
+ (void)hvld->fill_bootcmd_tag(hvld, tag);
+ p += ALIGN_UP(tag->size, MULTIBOOT2_TAG_ALIGN) / sizeof(uint64_t);
+ }
+
+ /* Boot loader name */
+ {
+ struct multiboot2_tag_string *tag = (struct multiboot2_tag_string *)p;
+ tag->type = MULTIBOOT2_TAG_TYPE_BOOT_LOADER_NAME;
+ tag->size = sizeof(struct multiboot2_tag_string) + BOOT_LOADER_NAME_SIZE;
+ memcpy(tag->string, UEFI_BOOT_LOADER_NAME, BOOT_LOADER_NAME_SIZE);
+ p += ALIGN_UP(tag->size, MULTIBOOT2_TAG_ALIGN) / sizeof(uint64_t);
+ }
+
+ /* Modules */
+ {
+ unsigned i;
+ uint32_t mod_count = hvld->get_mod_count(hvld);
+ for (i = 0; i < mod_count; i++) {
+ struct multiboot2_tag_module *tag = (struct multiboot2_tag_module *)p;
+ (void)hvld->fill_module_tag(hvld, tag, i);
+ p += ALIGN_UP(tag->size, MULTIBOOT2_TAG_ALIGN) / sizeof(uint64_t);
+ }
+ }
+
+ /* Memory map */
+ {
+ unsigned i;
+ struct multiboot2_tag_mmap *tag = (struct multiboot2_tag_mmap *)p;
+ struct multiboot2_mmap_entry *e;
+ int32_t e820_count = 0;
+
+ err = fill_e820(hvld, mmap_info, mmap, &e820_count);
+ if (err != EFI_SUCCESS)
+ goto out;
+
+ tag->type = MULTIBOOT2_TAG_TYPE_MMAP;
+ tag->size = sizeof(struct multiboot2_tag_mmap) + sizeof(struct multiboot2_mmap_entry) * e820_count;
+ tag->entry_size = sizeof(struct multiboot2_mmap_entry);
+ tag->entry_version = 0;
+
+ for (i = 0, e = (struct multiboot2_mmap_entry *)tag->entries; i < e820_count; i++) {
+ e->addr = mmap[i].mm_base_addr;
+ e->len = mmap[i].mm_length;
+ e->type = mmap[i].mm_type;
+ e->zero = 0;
+ e = (struct multiboot2_mmap_entry *)((char *)e + sizeof(struct multiboot2_mmap_entry));
+ }
+
+ p += ALIGN_UP(tag->size, MULTIBOOT2_TAG_ALIGN) / sizeof(uint64_t);
+ }
+
+ /* ACPI new */
+ {
+ struct multiboot2_tag_new_acpi *tag = (struct multiboot2_tag_new_acpi *)p;
+ tag->type = MULTIBOOT2_TAG_TYPE_ACPI_NEW;
+ tag->size = sizeof(struct multiboot2_tag_new_acpi) + rsdp->length;
+ memcpy((char *)tag->rsdp, (char *)rsdp, rsdp->length);
+ p += ALIGN_UP(tag->size, MULTIBOOT2_TAG_ALIGN) / sizeof(uint64_t);
+ }
+
+ /* EFI64 system table */
+ {
+ struct multiboot2_tag_efi64 *tag = (struct multiboot2_tag_efi64 *)p;
+ tag->type = MULTIBOOT2_TAG_TYPE_EFI64;
+ tag->size = sizeof(struct multiboot2_tag_efi64);
+ tag->pointer = (uint64_t)sys_table;
+ p += ALIGN_UP(tag->size, MULTIBOOT2_TAG_ALIGN) / sizeof(uint64_t);
+ }
+
+ /* EFI memory map */
+ {
+ struct multiboot2_tag_efi_mmap *tag = (struct multiboot2_tag_efi_mmap *)p;
+ tag->type = MULTIBOOT2_TAG_TYPE_EFI_MMAP;
+ tag->size = sizeof(struct multiboot2_tag_efi_mmap) + mmap_info->map_size;
+ tag->descr_size = mmap_info->desc_size;
+ tag->descr_vers = mmap_info->desc_version;
+ memcpy((char *)tag->efi_mmap, (char *)mmap_info->mmap, mmap_info->map_size);
+ p += ALIGN_UP(tag->size, MULTIBOOT2_TAG_ALIGN) / sizeof(uint64_t);
+ }
+
+ /* END */
+ {
+ struct multiboot2_tag *tag = (struct multiboot2_tag *)p;
+ tag->type = MULTIBOOT2_TAG_TYPE_END;
+ tag->size = sizeof(struct multiboot2_tag);
+ p += ALIGN_UP(tag->size, MULTIBOOT2_TAG_ALIGN) / sizeof(uint64_t);
+ }
+
+ ((uint32_t *)mbistart)[0] = (uint64_t)((char *)p - (char *)mbistart);
+ ((uint32_t *)mbistart)[1] = 0;
+
+ *mbi_addr = (void *)mbistart;
+
+ return EFI_SUCCESS;
+
+out:
+ free_pool(mbistart);
+ return err;
+}
+#endif
+
+static EFI_STATUS
+run_acrn(EFI_HANDLE image, HV_LOADER hvld)
+{
+ EFI_STATUS err;
+ struct efi_memmap_info memmapinfo;
+ struct multiboot_info *mbi;
+
+#ifdef CONFIG_MULTIBOOT2
+ /* MB2 has no fixed mbinfo layout. The mbi as output will
+ * NOT conform to the layout of struct multiboot_info.
+ */
+ err = construct_mbi2(hvld, (void **)&mbi, &memmapinfo);
+#else
+ err = construct_mbi(hvld, &mbi, &memmapinfo);
+#endif
+ if (err != EFI_SUCCESS)
+ goto out;
+
+ err = terminate_boot_services(image, &memmapinfo);
+ if (err != EFI_SUCCESS)
+ goto out;
+
+ hv_jump(hvld->get_hv_hpa(hvld), mbi);
+
+ /* Not reached on success */
+out:
+ return err;
+}
+
+/**
+ * efi_main - The entry point for the OS loader image.
+ * @image: firmware-allocated handle that identifies the image
+ * @sys_table: EFI system table
+ */
+EFI_STATUS
+efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *_table)
+{
+ WCHAR *error_buf;
+ EFI_STATUS err;
+ EFI_LOADED_IMAGE *info;
+
+ INTN index;
+
+ InitializeLib(image, _table);
+ sys_table = _table;
+ boot = sys_table->BootServices;
+
+ if (CheckCrc(sys_table->Hdr.HeaderSize, &sys_table->Hdr) != TRUE)
+ return EFI_LOAD_ERROR;
+
+ err = handle_protocol(image, &LoadedImageProtocol, (void **)&info);
+ if (err != EFI_SUCCESS)
+ goto failed;
+
+ /*
+ * Load hypervisor boot image handler. Currently Slim Bootloader
+ * compatible embedded container format is supported. File system
+ * mode to come future.
+ */
+ err = container_init(info, &hvld);
+ if (err != EFI_SUCCESS) {
+ Print(L"Unable to init container library %r ", err);
+ goto failed;
+ }
+
+ err = hvld->load_boot_image(hvld);
+ if (err != EFI_SUCCESS) {
+ Print(L"Unable to load ACRNHV Image %r ", err);
+ goto failed;
+ }
+
+ err = hvld->load_modules(hvld);
+ if (err != EFI_SUCCESS) {
+ Print(L"Unable to load VM modules %r ", err);
+ goto failed;
+ }
+
+ err = run_acrn(image, hvld);
+ if (err != EFI_SUCCESS)
+ goto failed;
+
+ return EFI_SUCCESS;
+
+failed:
+ if (hvld) {
+ hvld->deinit(hvld);
+ }
+
+ /*
+ * We need to be careful not to trash 'err' here. If we fail
+ * to allocate enough memory to hold the error string fallback
+ * to returning 'err'.
+ */
+ if (allocate_pool(EfiLoaderData, ERROR_STRING_LENGTH,
+ (void **)&error_buf) != EFI_SUCCESS) {
+ Print(L"Couldn't allocate pages for error string\n");
+ return err;
+ }
+
+ StatusToString(error_buf, err);
+ Print(L": %s\n", error_buf);
+
+ /* If we don't wait for user input, (s)he will not see the error message */
+ uefi_call_wrapper(sys_table->ConOut->OutputString, 2, sys_table->ConOut, \
+ L"\r\n\r\n\r\nHit any key to exit\r\n");
+ uefi_call_wrapper(sys_table->BootServices->WaitForEvent, 3, 1, \
+ &sys_table->ConIn->WaitForKey, &index);
+
+ return exit(image, err, ERROR_STRING_LENGTH, error_buf);
+}
diff --git a/misc/efi-stub/boot.h b/misc/efi-stub/boot.h
new file mode 100644
index 000000000..43b8fc2a3
--- /dev/null
+++ b/misc/efi-stub/boot.h
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2011 - 2021, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ACRNBOOT_H__
+#define __ACRNBOOT_H__
+
+#include "multiboot.h"
+
+#define E820_RAM 1
+#define E820_RESERVED 2
+#define E820_ACPI 3
+#define E820_NVS 4
+#define E820_UNUSABLE 5
+
+#define ERROR_STRING_LENGTH 32
+#define EFI_LOADER_SIGNATURE "EL64"
+
+#define ACPI_XSDT_ENTRY_SIZE (sizeof(UINT64))
+#define ACPI_NAME_SIZE 4
+#define ACPI_OEM_ID_SIZE 6
+#define ACPI_OEM_TABLE_ID_SIZE 8
+
+#define MSR_IA32_PAT 0x00000277 /* PAT */
+#define MSR_IA32_EFER 0xC0000080
+#define MSR_IA32_FS_BASE 0xC0000100U
+#define MSR_IA32_GS_BASE 0xC0000101
+#define MSR_IA32_SYSENTER_ESP 0x00000175 /* ESP for sysenter */
+#define MSR_IA32_SYSENTER_EIP 0x00000176 /* EIP for sysenter */
+
+#define UEFI_BOOT_LOADER_NAME "ACRN UEFI loader"
+
+#define ALIGN_UP(addr, align) \
+ (((addr) + (typeof (addr)) (align) - 1) & ~((typeof (addr)) (align) - 1))
+
+/* Read MSR */
+#define CPU_MSR_READ(reg, msr_val_ptr) \
+{ \
+ uint32_t msrl, msrh; \
+ asm volatile ("rdmsr" : "=a"(msrl), \
+ "=d"(msrh) : "c" (reg)); \
+ *msr_val_ptr = ((uint64_t)msrh << 32U) | msrl; \
+}
+
+EFI_STATUS get_pe_section(CHAR8 *base, char *section_name, UINTN section_name_len, UINTN *vaddr, UINTN *size);
+typedef void(*hv_func)(int32_t, struct multiboot_info*);
+
+/*
+ * We allocate memory for the following struct together with hyperivosr itself
+ * memory allocation during boot.
+ */
+#define MBOOT_MMAP_NUMS 256
+#define MBOOT_MMAP_SIZE (sizeof(struct multiboot_mmap) * MBOOT_MMAP_NUMS)
+#define MBOOT_INFO_SIZE (sizeof(struct multiboot_info))
+#define MBOOT_MODS_NUMS 4
+#define MBOOT_MODS_SIZE (sizeof(struct multiboot_module) * MBOOT_MODS_NUMS)
+#define BOOT_LOADER_NAME_SIZE 17U
+#define EFI_BOOT_MEM_SIZE \
+ (MBOOT_MMAP_SIZE + MBOOT_INFO_SIZE + MBOOT_MODS_SIZE + BOOT_LOADER_NAME_SIZE)
+#define MBOOT_MMAP_PTR(addr) \
+ ((struct multiboot_mmap *)((VOID *)(addr)))
+#define MBOOT_INFO_PTR(addr) \
+ ((struct multiboot_info *)((VOID *)(addr) + MBOOT_MMAP_SIZE))
+#define MBOOT_MODS_PTR(addr) \
+ ((struct multiboot_module *)((VOID *)(addr) + MBOOT_MMAP_SIZE + MBOOT_INFO_SIZE))
+#define BOOT_LOADER_NAME_PTR(addr) \
+ ((char *)((VOID *)(addr) + MBOOT_MMAP_SIZE + MBOOT_INFO_SIZE + MBOOT_MODS_SIZE))
+
+struct efi_memmap_info {
+ UINTN map_size;
+ UINTN map_key;
+ UINT32 desc_version;
+ UINTN desc_size;
+ EFI_MEMORY_DESCRIPTOR *mmap;
+};
+
+struct efi_info {
+ UINT32 efi_loader_signature;
+ UINT32 efi_systab;
+ UINT32 efi_memdesc_size;
+ UINT32 efi_memdesc_version;
+ UINT32 efi_memmap;
+ UINT32 efi_memmap_size;
+ UINT32 efi_systab_hi;
+ UINT32 efi_memmap_hi;
+};
+
+struct e820_entry {
+ UINT64 addr; /* start of memory segment */
+ UINT64 size; /* size of memory segment */
+ UINT32 type; /* type of memory segment */
+} __attribute__((packed));
+
+struct acpi_table_rsdp {
+ /* ACPI signature, contains "RSD PTR " */
+ char signature[8];
+ /* ACPI 1.0 checksum */
+ UINT8 checksum;
+ /* OEM identification */
+ char oem_id[ACPI_OEM_ID_SIZE];
+ /* Must be (0) for ACPI 1.0 or (2) for ACPI 2.0+ */
+ UINT8 revision;
+ /* 32-bit physical address of the RSDT */
+ UINT32 rsdt_physical_address;
+ /* Table length in bytes, including header (ACPI 2.0+) */
+ UINT32 length;
+ /* 64-bit physical address of the XSDT (ACPI 2.0+) */
+ UINT64 xsdt_physical_address;
+ /* Checksum of entire table (ACPI 2.0+) */
+ UINT8 extended_checksum;
+ /* Reserved, must be zero */
+ UINT8 reserved[3];
+};
+
+struct acpi_table_header {
+ /* ASCII table signature */
+ char signature[ACPI_NAME_SIZE];
+ /* Length of table in bytes, including this header */
+ UINT32 length;
+ /* ACPI Specification minor version number */
+ UINT8 revision;
+ /* To make sum of entire table == 0 */
+ UINT8 checksum;
+ /* ASCII OEM identification */
+ char oem_id[ACPI_OEM_ID_SIZE];
+ /* ASCII OEM table identification */
+ char oem_table_id[ACPI_OEM_TABLE_ID_SIZE];
+ /* OEM revision number */
+ UINT32 oem_revision;
+ /* ASCII ASL compiler vendor ID */
+ char asl_compiler_id[ACPI_NAME_SIZE];
+ /* ASL compiler version */
+ UINT32 asl_compiler_revision;
+};
+
+/* hypervisor loader operation table */
+typedef struct hv_loader *HV_LOADER;
+struct hv_loader {
+ /* Load ACRN hypervisor image into memory */
+ EFI_STATUS (*load_boot_image)(IN HV_LOADER hvld);
+ /* Load VM Kernels and ACPI Tables into memory */
+ EFI_STATUS (*load_modules)(IN HV_LOADER hvld);
+
+ /* Get hypervisor boot command length */
+ UINTN (*get_boot_cmdsize)(IN HV_LOADER hvld);
+ /* Get the number of multiboot2 modules */
+ UINTN (*get_mod_count)(IN HV_LOADER hvld);
+ /* Get the total memory size allocated to load module files */
+ UINTN (*get_total_modsize)(IN HV_LOADER hvld);
+ /* Get the total lengths of the module commands */
+ UINTN (*get_total_modcmdsize)(IN HV_LOADER hvld);
+
+ /* Get the start address of the memory region stored ACRN hypervisor image */
+ EFI_PHYSICAL_ADDRESS (*get_hv_hpa)(IN HV_LOADER hvld);
+ /* Get the start address of the memory region stored module files */
+ EFI_PHYSICAL_ADDRESS (*get_mod_hpa)(IN HV_LOADER hvld);
+
+ /* Set hypervisor boot command line to multiboot2 tag */
+ void (*fill_bootcmd_tag)(IN HV_LOADER hvld, OUT struct multiboot2_tag_string *tag);
+ /* Set n-th module info to multiboot2 tag */
+ void (*fill_module_tag)(IN HV_LOADER hvld, OUT struct multiboot2_tag_module *tag, IN UINTN index);
+
+ /* free up memory allocated by hypervisor loader */
+ void (*deinit)(IN HV_LOADER hvld);
+};
+
+static inline uint64_t
+msr_read(uint32_t reg_num)
+{
+ uint64_t msr_val;
+
+ CPU_MSR_READ(reg_num, &msr_val);
+ return msr_val;
+}
+
+#endif
diff --git a/misc/efi-stub/container.c b/misc/efi-stub/container.c
new file mode 100644
index 000000000..212c3cb28
--- /dev/null
+++ b/misc/efi-stub/container.c
@@ -0,0 +1,487 @@
+/*
+ * Copyright (c) 2021, Intel Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Library to support ACRN HV booting with Slim Bootloader container
+ *
+*/
+
+#include
+#include
+#include
+#include "boot.h"
+#include "stdlib.h"
+#include "efilinux.h"
+#include "multiboot.h"
+#include "container.h"
+
+#define LZH_BOOT_CMD 0u
+#define LZH_BOOT_IMG 1u
+#define LZH_MOD0_CMD 2u
+
+typedef struct {
+ UINT32 Signature;
+ UINT8 Version;
+ UINT8 Svn;
+ UINT16 DataOffset;
+ UINT32 DataSize;
+ UINT8 AuthType;
+ UINT8 ImageType;
+ UINT8 Flags;
+ UINT8 Count;
+} CONTAINER_HDR;
+
+typedef struct {
+ UINT32 Name;
+ UINT32 Offset;
+ UINT32 Size;
+ UINT8 Attribute;
+ UINT8 Alignment;
+ UINT8 AuthType;
+ UINT8 HashSize;
+ UINT8 HashData[0];
+} COMPONENT_ENTRY;
+
+typedef struct {
+ UINT32 Signature;
+ UINT32 CompressedSize;
+ UINT32 Size;
+ UINT16 Version;
+ UINT8 Svn;
+ UINT8 Attribute;
+ UINT8 Data[];
+} LOADER_COMPRESSED_HEADER;
+
+struct container {
+ struct hv_loader ops; /* loader operation table */
+
+ CHAR16 *options; /* uefi boot option passed by efibootmgr -u */
+ UINT32 options_size; /* length of UEFI boot option */
+ UINTN boot_cmdsize; /* length of boot command to pass hypervisor */
+
+ EFI_PHYSICAL_ADDRESS hv_hpa; /* start of memory stored hv image */
+ EFI_PHYSICAL_ADDRESS mod_hpa; /* start of memory stored module files */
+
+ UINTN mod_count; /* num of modules */
+ UINTN total_modsize; /* memory size allocated to load modules */
+ UINTN total_modcmdsize; /* memory size to store module commands */
+
+ UINTN lzh_count; /* num of files in container */
+ LOADER_COMPRESSED_HEADER *lzh_ptr[]; /* cache of each file header in container */
+};
+
+/**
+ * @brief Load acrn.32.out ELF file
+ *
+ * @param[in] elf_image ELF image
+ * @param[out] hv_hpa The physical memory address the relocated hypervisor is stored
+ *
+ * @return EFI_SUCCESS(0) on success, non-zero on error
+ */
+static EFI_STATUS load_acrn_elf(const UINT8 *elf_image, EFI_PHYSICAL_ADDRESS *hv_hpa)
+{
+ EFI_STATUS err = EFI_SUCCESS;
+ int i;
+
+ EFI_PHYSICAL_ADDRESS addr = 0u;
+
+ Elf32_Ehdr *ehdr = (Elf32_Ehdr *)(elf_image);
+ Elf32_Phdr *pbase = (Elf32_Phdr *)(elf_image + ehdr->e_phoff);
+ Elf32_Phdr *phdr = (Elf32_Phdr *)(elf_image + ehdr->e_phoff);
+
+ /* without relocation enabled, hypervisor binary need to reside in
+ * fixed memory address starting from CONFIG_HV_RAM_START, make a call
+ * to emalloc_fixed_addr for that case. With CONFIG_RELOC enabled,
+ * hypervisor is able to do relocation, the only requirement is that
+ * it need to reside in memory below 4GB, call emalloc_reserved_mem()
+ * instead.
+ *
+ * Don't relocate hypervisor binary under 256MB, which could be where
+ * guest Linux kernel boots from, and other usage, e.g. hvlog buffer
+ */
+#ifdef CONFIG_RELOC
+ err = emalloc_reserved_aligned(hv_hpa, CONFIG_HV_RAM_SIZE, 2U * MEM_ADDR_1MB,
+ 256U * MEM_ADDR_1MB, MEM_ADDR_4GB);
+#else
+ err = emalloc_fixed_addr(hv_hpa, CONFIG_HV_RAM_SIZE, CONFIG_HV_RAM_START);
+#endif
+
+ if (err != EFI_SUCCESS) {
+ Print(L"Failed to allocate memory for ACRN HV %r\n", err);
+ goto out;
+ }
+
+ for (i = 0; i < ehdr->e_phnum; i++) {
+ phdr = (Elf32_Phdr *)((UINT8 *)pbase + i * ehdr->e_phentsize);
+ if ((phdr->p_type != PT_LOAD) || (phdr->p_memsz == 0) || (phdr->p_offset == 0)) {
+ continue;
+ }
+
+ if (phdr->p_filesz > phdr->p_memsz) {
+ err = EFI_LOAD_ERROR;
+ goto out;
+ }
+
+ addr = (EFI_PHYSICAL_ADDRESS)(*hv_hpa + (phdr->p_paddr - CONFIG_HV_RAM_START));
+ memcpy((char *)addr, (const char *)(elf_image + phdr->p_offset), phdr->p_filesz);
+
+ if (phdr->p_memsz > phdr->p_filesz) {
+ addr = (EFI_PHYSICAL_ADDRESS)(*hv_hpa + (phdr->p_paddr - CONFIG_HV_RAM_START + phdr->p_filesz));
+ (void)memset((void *)addr, 0x0, (phdr->p_memsz - phdr->p_filesz));
+ }
+ }
+
+out:
+ return err;
+}
+
+/**
+ * @brief Load hypervisor into memory from a container blob
+ *
+ * @param[in] hvld Loader handle
+ *
+ * @return EFI_SUCCESS(0) on success, non-zero on error
+ */
+static EFI_STATUS container_load_boot_image(HV_LOADER hvld)
+{
+ EFI_STATUS err = EFI_SUCCESS;
+ struct container *ctr = (struct container *)hvld;
+
+ LOADER_COMPRESSED_HEADER *lzh = NULL;
+
+ /* hv_cmdline.txt: to be copied into memory by the fill_bootcmd_tag operation later */
+ lzh = ctr->lzh_ptr[LZH_BOOT_CMD];
+ ctr->boot_cmdsize = lzh->Size + StrnLen(ctr->options, ctr->options_size);
+
+ /* acrn.32.out */
+ lzh = ctr->lzh_ptr[LZH_BOOT_IMG];
+ err = load_acrn_elf((const UINT8 *)lzh->Data, &ctr->hv_hpa);
+ if (err != EFI_SUCCESS) {
+ Print(L"Failed to load ACRN HV ELF Image%r\n", err);
+ goto out;
+ }
+out:
+ return err;
+}
+
+/**
+ * @brief Load kernel modules and acpi tables into memory from a container blob
+ *
+ * @param[in] hvld Loader handle
+ *
+ * @return EFI_SUCCESS(0) on success, non-zero on error
+ */
+ static EFI_STATUS container_load_modules(HV_LOADER hvld)
+{
+ EFI_STATUS err = EFI_SUCCESS;
+ struct container *ctr = (struct container *)hvld;
+
+ UINTN i;
+
+ UINT8 * p = NULL;
+ LOADER_COMPRESSED_HEADER *lzh = NULL;
+
+ /* scan module headers to calculate required memory size to store files */
+ for (i = LZH_MOD0_CMD; i < ctr->lzh_count - 1; i++) {
+ if ((i % 2) == 0) { /* vm0_tag.txt, vm1_tag.txt, acpi_vm0.txt ... */
+ ctr->total_modcmdsize += ctr->lzh_ptr[i]->Size;
+ } else { /* vm0_kernel, vm1_kernel, vm0_acpi.bin ... */
+ ctr->total_modsize += ALIGN_UP(ctr->lzh_ptr[i]->Size, EFI_PAGE_SIZE);
+ }
+ }
+ /* exclude hypervisor and SBL signature files. e.g.)
+ * lzh_count = 9 (hv_cmdline, acrn.32.out, vm0_tag, vm0_kernel, vm1_tag, vm1_kernel, vm0_acpi_tag, vm0_acpi, sig)
+ * mod_count = 3 (vm0_tag + vm0_kernel, vm1_tag + vm1_kernel, vm0_acpi_tag + vm0_acpi)
+ */
+ ctr->mod_count = (ctr->lzh_count - 3) / 2;
+
+ /* allocate single memory region to store all binary files to avoid mmap fragmentation */
+ err = emalloc_reserved_aligned(&(ctr->mod_hpa), ctr->total_modsize,
+ EFI_PAGE_SIZE, 256U * MEM_ADDR_1MB, MEM_ADDR_4GB);
+ if (err != EFI_SUCCESS) {
+ Print(L"Failed to allocate memory for modules %r\n", err);
+ goto out;
+ }
+
+ p = (UINT8 *)ctr->mod_hpa;
+ for (i = LZH_BOOT_IMG + 2; i < ctr->lzh_count - 1; i = i + 2) {
+ lzh = ctr->lzh_ptr[i];
+ memcpy((char *)p, (const char *)lzh->Data, lzh->Size);
+ p += ALIGN_UP(lzh->Size, EFI_PAGE_SIZE);
+ }
+out:
+ return err;
+}
+
+/**
+ * @brief Get hypervisor boot command length
+ *
+ * @param[in] hvld Loader handle
+ *
+ * @return the length of hypervisor boot command
+ */
+static UINTN container_get_boot_cmdsize(HV_LOADER hvld)
+{
+ /* boot_cmd = hv_cmdline.txt in container + extra arg given by the 'efibootmgr -u' option */
+ return ((struct container *)hvld)->boot_cmdsize;
+}
+
+/**
+ * @brief Get the number of multiboot2 modules
+ *
+ * @param[in] hvld Loader handle
+ *
+ * @return the number of multiboot2 modules
+ */
+static UINTN container_get_mod_count(HV_LOADER hvld)
+{
+ return ((struct container *)hvld)->mod_count;
+}
+
+/**
+ * @brief Get the total memory size allocated to load module files
+ *
+ * @param[in] hvld Loader handle
+ *
+ * @return the total size of memory allocated to store the module files
+ */
+static UINTN container_get_total_modsize(HV_LOADER hvld)
+{
+ return ((struct container *)hvld)->total_modsize;
+}
+
+/**
+ * @brief Get the total lengths of the module commands
+ *
+ * @param[in] hvld Loader handle
+ *
+ * @return the total lengths of module command files
+ */
+static UINTN container_get_total_modcmdsize(HV_LOADER hvld)
+{
+ return ((struct container *)hvld)->total_modcmdsize;
+}
+
+/**
+ * @brief Get the start address of the memory region stored ACRN hypervisor image
+ *
+ * @param[in] hvld Loader handle
+ *
+ * @return the address of hv image
+ */
+static EFI_PHYSICAL_ADDRESS container_get_hv_hpa(HV_LOADER hvld)
+{
+ return ((struct container *)hvld)->hv_hpa;
+}
+
+/**
+ * @brief Get the start address of the memory region stored module files
+ *
+ * @param[in] hvld Loader handle
+ *
+ * @return the address of modules
+ */
+static EFI_PHYSICAL_ADDRESS container_get_mod_hpa(HV_LOADER hvld)
+{
+ return ((struct container *)hvld)->mod_hpa;
+}
+
+/**
+ * @brief Set hypervisor boot command line to multiboot2 tag
+ *
+ * @param[in] hvld Loader handle
+ * @param[out] tag The buffer to be filled in. It's the caller's responsibility to allocate memory for the buffer
+ *
+ * @return None
+ */
+static void container_fill_bootcmd_tag(HV_LOADER hvld, struct multiboot2_tag_string *tag)
+{
+ struct container *ctr = (struct container *)hvld;
+ LOADER_COMPRESSED_HEADER *lzh = ctr->lzh_ptr[LZH_BOOT_CMD];
+ UINTN cmdline_size = container_get_boot_cmdsize(hvld);
+
+ UINTN i;
+
+ tag->type = MULTIBOOT2_TAG_TYPE_CMDLINE;
+ tag->size = sizeof(struct multiboot2_tag_string) + cmdline_size;
+
+ (void)memset((void *)tag->string, 0x0, cmdline_size);
+ memcpy(tag->string, (const char *)lzh->Data, lzh->Size - 1);
+ if (ctr->options) {
+ tag->string[lzh->Size - 1] = ' ';
+ for (i = lzh->Size; i < cmdline_size; i++) {
+ /* append the options to the boot command line */
+ tag->string[i] = ctr->options[i - lzh->Size];
+ }
+ }
+}
+
+/**
+ * @brief Set n-th module info to multiboot2 tag
+ *
+ * @param[in] hvld Loader handle
+ * @param[out] tag The buffer to be filled in. It's the caller's responsibility to allocate memory for the buffer
+ *
+ * @return None
+ */
+static void container_fill_module_tag(HV_LOADER hvld, struct multiboot2_tag_module *tag, UINTN index)
+{
+ struct container *ctr = (struct container *)hvld;
+
+ LOADER_COMPRESSED_HEADER *cmd_lzh = NULL;
+ LOADER_COMPRESSED_HEADER *mod_lzh = NULL;
+ UINT8 * p = (UINT8 *)ctr->mod_hpa;
+
+ UINTN i;
+
+ for (i = LZH_MOD0_CMD; i < ctr->lzh_count - 1; i = i + 2) {
+ mod_lzh = ctr->lzh_ptr[i + 1];
+ if (i == (index * 2 + LZH_MOD0_CMD)) {
+ cmd_lzh = ctr->lzh_ptr[i];
+ tag->type = MULTIBOOT2_TAG_TYPE_MODULE;
+ tag->size = sizeof(struct multiboot2_tag_module) + cmd_lzh->Size;
+ tag->mod_start = (EFI_PHYSICAL_ADDRESS)p;
+ tag->mod_end = tag->mod_start + mod_lzh->Size;
+ memcpy(tag->cmdline, (char *)(uint64_t)cmd_lzh->Data, cmd_lzh->Size);
+ break;
+ }
+ p += ALIGN_UP(mod_lzh->Size, EFI_PAGE_SIZE);
+ }
+}
+
+/**
+ * @brief Free up memory allocated by the container loader
+ *
+ * @param[in] hvld Loader handle
+ *
+ * @return None
+ */
+static void container_deinit(HV_LOADER hvld)
+{
+ struct container *ctr = (struct container *)hvld;
+
+ if (ctr->lzh_ptr) {
+ free_pool(ctr->lzh_ptr);
+ free_pool(ctr);
+ }
+
+ if (ctr->mod_hpa) {
+ free_pages(ctr->mod_hpa, EFI_SIZE_TO_PAGES(ctr->total_modsize));
+ }
+}
+
+/* hypervisor loader operation table */
+static struct hv_loader container_ops = {
+ .load_boot_image = container_load_boot_image,
+ .load_modules = container_load_modules,
+ .get_boot_cmdsize = container_get_boot_cmdsize,
+ .get_total_modsize = container_get_total_modsize,
+ .get_total_modcmdsize = container_get_total_modcmdsize,
+ .get_mod_count = container_get_mod_count,
+ .get_hv_hpa = container_get_hv_hpa,
+ .get_mod_hpa = container_get_mod_hpa,
+ .fill_bootcmd_tag = container_fill_bootcmd_tag,
+ .fill_module_tag = container_fill_module_tag,
+ .deinit = container_deinit,
+};
+
+/**
+ * @brief Initialize Container Library and returned the loader operation table
+ *
+ * @param[in] info Firmware-allocated handle that identifies the EFI application image (i.e. acrn.efi)
+ * @param[out] info Allocated loader operation table
+ *
+ * @return EFI_SUCCESS(0) on success, non-zero on error
+ */
+EFI_STATUS container_init(EFI_LOADED_IMAGE *info, HV_LOADER *hvld)
+{
+ EFI_STATUS err = EFI_SUCCESS;
+
+ struct container *ctr = NULL;
+
+ UINTN sec_addr = 0u;
+ UINTN sec_size = 0u;
+ char *section = ".hv";
+
+ UINTN i;
+ CONTAINER_HDR *hdr = NULL;
+ COMPONENT_ENTRY *comp = NULL;
+
+ UINTN offset = 0u;
+
+ err = allocate_pool(EfiLoaderData, sizeof(struct container), (void **)&ctr);
+ if (EFI_ERROR(err)) {
+ Print(L"Failed to allocate memory for Container Library %r\n", err);
+ goto out;
+ }
+
+ (void)memset((void *)ctr, 0x0, sizeof(struct container));
+ memcpy((char *)&ctr->ops, (const char *)&container_ops, sizeof(struct hv_loader));
+
+ /* store the options */
+ ctr->options = info->LoadOptions;
+ ctr->options_size = info->LoadOptionsSize;
+
+ /* read a container stitched at the .hv section */
+ err = get_pe_section(info->ImageBase, section, strlen(section), &sec_addr, &sec_size);
+ if (EFI_ERROR(err)) {
+ Print(L"Unable to locate section of ACRNHV Container %r ", err);
+ goto out;
+ }
+
+ hdr = (CONTAINER_HDR*)(info->ImageBase + sec_addr);
+ ctr->lzh_count = hdr->Count;
+
+ err = allocate_pool(EfiLoaderData, sizeof(LOADER_COMPRESSED_HEADER *) * hdr->Count, (void **)&ctr->lzh_ptr);
+ if (EFI_ERROR(err)) {
+ Print(L"Failed to allocate memory for Container Library %r\n", err);
+ goto out;
+ }
+
+ /* cache each file's header point for later use */
+ comp = (COMPONENT_ENTRY *)(hdr + 1);
+ for (i = 0; i < hdr->Count; i++) {
+ offset = hdr->DataOffset + comp->Offset;
+ ctr->lzh_ptr[i] = (LOADER_COMPRESSED_HEADER *)((UINT8 *)(hdr) + offset);
+
+ comp = (COMPONENT_ENTRY *)((UINT8 *)(comp + 1) + comp->HashSize);
+ }
+
+ *hvld = (struct hv_loader *)ctr;
+out:
+ if (EFI_ERROR(err)) {
+ if (ctr) {
+ container_deinit((HV_LOADER)ctr);
+ }
+ }
+ return err;
+}
diff --git a/misc/efi-stub/container.h b/misc/efi-stub/container.h
new file mode 100644
index 000000000..26edc9580
--- /dev/null
+++ b/misc/efi-stub/container.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2021, Intel Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#ifndef __ACRNCONTAINER_H__
+#define __ACRNCONTAINER_H__
+
+/**
+ * container_init - Initialize Container Library and returned the loader operation table.
+ * @info: Firmware-allocated handle that identifies the EFI application image (i.e. acrn.efi)
+ * @hvld: Loader operation table
+ */
+EFI_STATUS container_init(EFI_LOADED_IMAGE *info, HV_LOADER *hvld);
+
+#endif /* __ACRNCONTAINER_H__ */
diff --git a/misc/efi-stub/efilinux.h b/misc/efi-stub/efilinux.h
new file mode 100644
index 000000000..7f0d5f211
--- /dev/null
+++ b/misc/efi-stub/efilinux.h
@@ -0,0 +1,276 @@
+/*
+ * Copyright (c) 2011 - 2021, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file contains some wrappers around the gnu-efi functions. As
+ * we're not going through uefi_call_wrapper() directly, this allows
+ * us to get some type-safety for function call arguments and for the
+ * compiler to check that the number of function call arguments is
+ * correct.
+ *
+ * It's also a good place to document the EFI interface.
+ */
+
+#ifndef __EFILINUX_H__
+#define __EFILINUX_H__
+
+#define EFILINUX_VERSION_MAJOR 1
+#define EFILINUX_VERSION_MINOR 0
+
+#define MEM_ADDR_1MB (1U << 20U)
+#define MEM_ADDR_4GB (0xFFFFFFFFU)
+
+
+extern EFI_SYSTEM_TABLE *sys_table;
+extern EFI_BOOT_SERVICES *boot;
+
+extern EFI_STATUS
+emalloc_reserved_aligned(EFI_PHYSICAL_ADDRESS *addr, UINTN size, UINTN align,
+ EFI_PHYSICAL_ADDRESS minaddr, EFI_PHYSICAL_ADDRESS maxaddr);
+
+/**
+ * allocate_pages - Allocate memory pages from the system
+ * @atype: type of allocation to perform
+ * @mtype: type of memory to allocate
+ * @num_pages: number of contiguous 4KB pages to allocate
+ * @memory: used to return the address of allocated pages
+ *
+ * Allocate @num_pages physically contiguous pages from the system
+ * memory and return a pointer to the base of the allocation in
+ * @memory if the allocation succeeds. On success, the firmware memory
+ * map is updated accordingly.
+ *
+ * If @atype is AllocateAddress then, on input, @memory specifies the
+ * address at which to attempt to allocate the memory pages.
+ */
+static inline EFI_STATUS
+allocate_pages(EFI_ALLOCATE_TYPE atype, EFI_MEMORY_TYPE mtype,
+ UINTN num_pages, EFI_PHYSICAL_ADDRESS *memory)
+{
+ return uefi_call_wrapper(boot->AllocatePages, 4, atype,
+ mtype, num_pages, memory);
+}
+
+/**
+ * free_pages - Return memory allocated by allocate_pages() to the firmware
+ * @memory: physical base address of the page range to be freed
+ * @num_pages: number of contiguous 4KB pages to free
+ *
+ * On success, the firmware memory map is updated accordingly.
+ */
+static inline EFI_STATUS
+free_pages(EFI_PHYSICAL_ADDRESS memory, UINTN num_pages)
+{
+ return uefi_call_wrapper(boot->FreePages, 2, memory, num_pages);
+}
+
+/**
+ * allocate_pool - Allocate pool memory
+ * @type: the type of pool to allocate
+ * @size: number of bytes to allocate from pool of @type
+ * @buffer: used to return the address of allocated memory
+ *
+ * Allocate memory from pool of @type. If the pool needs more memory
+ * pages are allocated from EfiConventionalMemory in order to grow the
+ * pool.
+ *
+ * All allocations are eight-byte aligned.
+ */
+static inline EFI_STATUS
+allocate_pool(EFI_MEMORY_TYPE type, UINTN size, void **buffer)
+{
+ return uefi_call_wrapper(boot->AllocatePool, 3, type, size, buffer);
+}
+
+/**
+ * free_pool - Return pool memory to the system
+ * @buffer: the buffer to free
+ *
+ * Return @buffer to the system. The returned memory is marked as
+ * EfiConventionalMemory.
+ */
+static inline EFI_STATUS free_pool(void *buffer)
+{
+ return uefi_call_wrapper(boot->FreePool, 1, buffer);
+}
+
+/**
+ * get_memory_map - Return the current memory map
+ * @size: the size in bytes of @map
+ * @map: buffer to hold the current memory map
+ * @key: used to return the key for the current memory map
+ * @descr_size: used to return the size in bytes of EFI_MEMORY_DESCRIPTOR
+ * @descr_version: used to return the version of EFI_MEMORY_DESCRIPTOR
+ *
+ * Get a copy of the current memory map. The memory map is an array of
+ * EFI_MEMORY_DESCRIPTORs. An EFI_MEMORY_DESCRIPTOR describes a
+ * contiguous block of memory.
+ *
+ * On success, @key is updated to contain an identifer for the current
+ * memory map. The firmware's key is changed every time something in
+ * the memory map changes. @size is updated to indicate the size of
+ * the memory map pointed to by @map.
+ *
+ * @descr_size and @descr_version are used to ensure backwards
+ * compatibility with future changes made to the EFI_MEMORY_DESCRIPTOR
+ * structure. @descr_size MUST be used when the size of an
+ * EFI_MEMORY_DESCRIPTOR is used in a calculation, e.g when iterating
+ * over an array of EFI_MEMORY_DESCRIPTORs.
+ *
+ * On failure, and if the buffer pointed to by @map is too small to
+ * hold the memory map, EFI_BUFFER_TOO_SMALL is returned and @size is
+ * updated to reflect the size of a buffer required to hold the memory
+ * map.
+ */
+static inline EFI_STATUS
+get_memory_map(UINTN *size, EFI_MEMORY_DESCRIPTOR *map, UINTN *key,
+ UINTN *descr_size, UINT32 *descr_version)
+{
+ return uefi_call_wrapper(boot->GetMemoryMap, 5, size, map,
+ key, descr_size, descr_version);
+}
+
+/**
+ * exit_boot_serivces - Terminate all boot services
+ * @image: firmware-allocated handle that identifies the image
+ * @key: key to the latest memory map
+ *
+ * This function is called when efilinux wants to take complete
+ * control of the system. efilinux should not make calls to boot time
+ * services after this function is called.
+ */
+static inline EFI_STATUS
+exit_boot_services(EFI_HANDLE image, UINTN key)
+{
+ return uefi_call_wrapper(boot->ExitBootServices, 2, image, key);
+}
+
+
+/**
+ * handle_protocol - Query @handle to see if it supports @protocol
+ * @handle: the handle being queried
+ * @protocol: the GUID of the protocol
+ * @interface: used to return the protocol interface
+ *
+ * Query @handle to see if @protocol is supported. If it is supported,
+ * @interface contains the protocol interface.
+ */
+static inline EFI_STATUS
+handle_protocol(EFI_HANDLE handle, EFI_GUID *protocol, void **interface)
+{
+ return uefi_call_wrapper(boot->HandleProtocol, 3,
+ handle, protocol, interface);
+}
+
+
+/*
+ * emalloc_reserved_mem - it is called to allocate memory hypervisor itself
+ * and trampoline code, and mark the allocate memory as EfiReserved memory
+ * type so that SOS won't touch it during boot.
+ * @addr: a pointer to the allocated address on success
+ * @size: size in bytes of the requested allocation
+ * @max_addr: the allocated memory must be no more than this threshold
+ */
+static inline EFI_STATUS emalloc_reserved_mem(EFI_PHYSICAL_ADDRESS *addr,
+ UINTN size, EFI_PHYSICAL_ADDRESS max_addr)
+{
+ *addr = max_addr;
+ return allocate_pages(AllocateMaxAddress, EfiReservedMemoryType,
+ EFI_SIZE_TO_PAGES(size), addr);
+}
+
+
+/*
+ * emalloc_fixed_addr - it is called to allocate memory hypervisor itself
+ * when CONFIG_RELOC config is NOT enable.And mark the allocated memory as
+ * EfiReserved memory type so that SOS won't touch it during boot.
+ * @addr: a pointer to the allocated address on success
+ * @size: size in bytes of the requested allocation
+ */
+static inline EFI_STATUS emalloc_fixed_addr(EFI_PHYSICAL_ADDRESS *addr,
+ UINTN size, EFI_PHYSICAL_ADDRESS fixed_addr)
+{
+ *addr = fixed_addr;
+ return allocate_pages(AllocateAddress, EfiReservedMemoryType,
+ EFI_SIZE_TO_PAGES(size), addr);
+}
+
+/**
+ * exit - Terminate a loaded EFI image
+ * @image: firmware-allocated handle that identifies the image
+ * @status: the image's exit code
+ * @size: size in bytes of @reason. Ignored if @status is EFI_SUCCESS
+ * @reason: a NUL-terminated status string, optionally followed by binary data
+ *
+ * This function terminates @image and returns control to the boot
+ * services. This function MUST NOT be called until all loaded child
+ * images have exited. All memory allocated by the image must be freed
+ * before calling this function, apart from the buffer @reason, which
+ * will be freed by the firmware.
+ */
+static inline EFI_STATUS
+exit(EFI_HANDLE image, EFI_STATUS status, UINTN size, CHAR16 *reason)
+{
+ return uefi_call_wrapper(boot->Exit, 4, image, status, size, reason);
+}
+
+#define PAGE_SIZE 4096
+
+static const CHAR16 *memory_types[] = {
+ L"EfiReservedMemoryType",
+ L"EfiLoaderCode",
+ L"EfiLoaderData",
+ L"EfiBootServicesCode",
+ L"EfiBootServicesData",
+ L"EfiRuntimeServicesCode",
+ L"EfiRuntimeServicesData",
+ L"EfiConventionalMemory",
+ L"EfiUnusableMemory",
+ L"EfiACPIReclaimMemory",
+ L"EfiACPIMemoryNVS",
+ L"EfiMemoryMappedIO",
+ L"EfiMemoryMappedIOPortSpace",
+ L"EfiPalCode",
+};
+
+static inline const CHAR16 *memory_type_to_str(UINT32 type)
+{
+ if (type > sizeof(memory_types)/sizeof(CHAR16 *))
+ return L"Unknown";
+
+ return memory_types[type];
+}
+
+extern EFI_STATUS memory_map(EFI_MEMORY_DESCRIPTOR **map_buf,
+ UINTN *map_size, UINTN *map_key,
+ UINTN *desc_size, UINT32 *desc_version);
+
+#endif /* __EFILINUX_H__ */
diff --git a/misc/efi-stub/malloc.c b/misc/efi-stub/malloc.c
new file mode 100644
index 000000000..1fc83bded
--- /dev/null
+++ b/misc/efi-stub/malloc.c
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2011 - 2021, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include
+#include
+#include "efilinux.h"
+#include "stdlib.h"
+
+/**
+ * memory_map - Allocate and fill out an array of memory descriptors
+ * @map_buf: buffer containing the memory map
+ * @map_size: size of the buffer containing the memory map
+ * @map_key: key for the current memory map
+ * @desc_size: size of the desc
+ * @desc_version: memory descriptor version
+ *
+ * On success, @map_size contains the size of the memory map pointed
+ * to by @map_buf and @map_key, @desc_size and @desc_version are
+ * updated.
+ */
+EFI_STATUS
+memory_map(EFI_MEMORY_DESCRIPTOR **map_buf, UINTN *map_size,
+ UINTN *map_key, UINTN *desc_size, UINT32 *desc_version)
+{
+ EFI_STATUS err;
+
+ *map_size = sizeof(**map_buf) * 31;
+get_map:
+
+ /*
+ * Because we're about to allocate memory, we may
+ * potentially create a new memory descriptor, thereby
+ * increasing the size of the memory map. So increase
+ * the buffer size by the size of one memory
+ * descriptor, just in case.
+ */
+ *map_size += sizeof(**map_buf);
+
+ err = allocate_pool(EfiLoaderData, *map_size,
+ (void **)map_buf);
+ if (err != EFI_SUCCESS) {
+ Print(L"Failed to allocate pool for memory map");
+ goto failed;
+ }
+
+ err = get_memory_map(map_size, *map_buf, map_key,
+ desc_size, desc_version);
+ if (err != EFI_SUCCESS) {
+ if (err == EFI_BUFFER_TOO_SMALL) {
+ /*
+ * 'map_size' has been updated to reflect the
+ * required size of a map buffer.
+ */
+ free_pool((void *)*map_buf);
+ goto get_map;
+ }
+
+ Print(L"Failed to get memory map");
+ goto failed;
+ }
+
+failed:
+ return err;
+}
+
+
+EFI_STATUS
+emalloc_reserved_aligned(EFI_PHYSICAL_ADDRESS *addr, UINTN size, UINTN align,
+ EFI_PHYSICAL_ADDRESS minaddr, EFI_PHYSICAL_ADDRESS maxaddr)
+{
+ UINTN msize, mkey, desc_sz, desc_addr, pages;
+ UINT32 desc_version;
+ EFI_MEMORY_DESCRIPTOR *mbuf;
+ EFI_STATUS err;
+
+ pages = EFI_SIZE_TO_PAGES(size);
+
+ err = memory_map(&mbuf, &msize, &mkey, &desc_sz, &desc_version);
+ if (err != EFI_SUCCESS) {
+ goto fail;
+ }
+
+ /* In most time, Memory map reported by BIOS is an ordering list from low to hight.
+ * Scan it from high to low, so that allocate memory as high as possible
+ */
+ for (desc_addr = (UINTN)mbuf + msize - desc_sz; desc_addr >= (UINTN)mbuf; desc_addr -= desc_sz) {
+ EFI_MEMORY_DESCRIPTOR *desc;
+ EFI_PHYSICAL_ADDRESS start, end;
+
+ desc = (EFI_MEMORY_DESCRIPTOR*)desc_addr;
+ if (desc->Type != EfiConventionalMemory)
+ continue;
+
+ start = desc->PhysicalStart;
+ end = start + (desc->NumberOfPages << EFI_PAGE_SHIFT);
+
+ /* 1MB low memory is allocated only if required/requested */
+ if ((end <= MEM_ADDR_1MB) && (maxaddr > MEM_ADDR_1MB))
+ continue;
+
+ /* starting allocation from 1M above unless requested */
+ if ((start < MEM_ADDR_1MB) && (maxaddr > MEM_ADDR_1MB)) {
+ start = MEM_ADDR_1MB;
+ }
+
+ /* zero page won't be allocated */
+ if (start < 4096) {
+ start = 4096;
+ }
+
+ if (start < minaddr) {
+ start = minaddr;
+ }
+ start = (start + align - 1) & ~(align - 1);
+
+ /* Since this routine is called during booting, memory block is large
+ * enought, the reduction of memory size for memory alignment won't
+ * impact allocation. It is true in most cases. if it is not true, loop
+ * again
+ */
+ if ((start + size <= end) && (start + size <= maxaddr)) {
+ err = allocate_pages(AllocateAddress, EfiReservedMemoryType, pages, &start);
+ if (err == EFI_SUCCESS) {
+ *addr = start;
+ break;
+ }
+ }
+ }
+ if (desc_addr < (UINTN)mbuf) {
+ err = EFI_OUT_OF_RESOURCES;
+ }
+
+ free_pool(mbuf);
+
+fail:
+ return err;
+}
+
+EFI_STATUS dump_e820(void)
+{
+ UINTN map_size, map_key, desc_size;
+ EFI_MEMORY_DESCRIPTOR *map_buf;
+ UINTN d, map_end;
+ UINTN i;
+ UINT32 desc_version;
+ EFI_STATUS err;
+
+ err = memory_map(&map_buf, &map_size, &map_key,
+ &desc_size, &desc_version);
+ if (err != EFI_SUCCESS)
+ goto fail;
+
+ d = (UINTN)map_buf;
+ map_end = (UINTN)map_buf + map_size;
+
+ for (i = 0; d < map_end; d += desc_size, i++) {
+ EFI_MEMORY_DESCRIPTOR *desc;
+ EFI_PHYSICAL_ADDRESS start, end;
+
+ desc = (EFI_MEMORY_DESCRIPTOR *)d;
+ if (desc->Type != EfiConventionalMemory)
+ continue;
+
+ start = desc->PhysicalStart;
+ end = start + (desc->NumberOfPages << EFI_PAGE_SHIFT);
+
+ Print(L"[%d]start:%lx, end:%lx, type:%d\n", i, start, end, desc->Type);
+ }
+
+ free_pool(map_buf);
+fail:
+ return err;
+}
+
diff --git a/misc/efi-stub/multiboot.h b/misc/efi-stub/multiboot.h
new file mode 100644
index 000000000..1af7a3ad8
--- /dev/null
+++ b/misc/efi-stub/multiboot.h
@@ -0,0 +1,386 @@
+/* [ORIGIN: src/sys/arch/i386/include/... */
+/* $NetBSD: multiboot.h,v 1.8 2009/02/22 18:05:42 ahoka Exp $ */
+
+/*-
+ * Copyright (c) 2005, 2006 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Julio M. Merino Vidal.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * multiboot.h
+ */
+
+#ifndef _MULTIBOOT_H
+#define _MULTIBOOT_H
+
+#include
+#include
+
+struct multiboot_info;
+extern struct multiboot_info mbi;
+
+/*
+ * Multiboot header structure.
+ */
+#define MULTIBOOT_HEADER_MAGIC 0x1BADB002
+#define MULTIBOOT_HEADER_MODS_ALIGNED 0x00000001
+#define MULTIBOOT_HEADER_WANT_MEMORY 0x00000002
+#define MULTIBOOT_HEADER_HAS_VBE 0x00000004
+#define MULTIBOOT_HEADER_HAS_ADDR 0x00010000
+
+#if !defined(_LOCORE)
+struct multiboot_header {
+ uint32_t mh_magic;
+ uint32_t mh_flags;
+ uint32_t mh_checksum;
+
+ /* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_ADDR. */
+ uint32_t mh_header_addr;
+ uint32_t mh_load_addr;
+ uint32_t mh_load_end_addr;
+ uint32_t mh_bss_end_addr;
+ uint32_t mh_entry_addr;
+
+ /* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_VBE. */
+ uint32_t mh_mode_type;
+ uint32_t mh_width;
+ uint32_t mh_height;
+ uint32_t mh_depth;
+};
+#endif /* !defined(_LOCORE) */
+
+/*
+ * Symbols defined in locore.S.
+ */
+extern struct multiboot_header *Multiboot_Header;
+
+/*
+ * Multiboot information structure.
+ */
+#define MULTIBOOT_INFO_MAGIC 0x2BADB002U
+#define MULTIBOOT_INFO_HAS_MEMORY 0x00000001U
+#define MULTIBOOT_INFO_HAS_BOOT_DEVICE 0x00000002U
+#define MULTIBOOT_INFO_HAS_CMDLINE 0x00000004U
+#define MULTIBOOT_INFO_HAS_MODS 0x00000008U
+#define MULTIBOOT_INFO_HAS_AOUT_SYMS 0x00000010U
+#define MULTIBOOT_INFO_HAS_ELF_SYMS 0x00000020U
+#define MULTIBOOT_INFO_HAS_MMAP 0x00000040U
+#define MULTIBOOT_INFO_HAS_DRIVES 0x00000080U
+#define MULTIBOOT_INFO_HAS_CONFIG_TABLE 0x00000100U
+#define MULTIBOOT_INFO_HAS_LOADER_NAME 0x00000200U
+#define MULTIBOOT_INFO_HAS_APM_TABLE 0x00000400U
+#define MULTIBOOT_INFO_HAS_VBE 0x00000800U
+
+#if !defined(_LOCORE)
+struct multiboot_info {
+ uint32_t mi_flags;
+
+ /* Valid if mi_flags sets MULTIBOOT_INFO_HAS_MEMORY. */
+ uint32_t mi_mem_lower;
+ uint32_t mi_mem_upper;
+
+ /* Valid if mi_flags sets MULTIBOOT_INFO_HAS_BOOT_DEVICE. */
+ uint8_t mi_boot_device_part3;
+ uint8_t mi_boot_device_part2;
+ uint8_t mi_boot_device_part1;
+ uint8_t mi_boot_device_drive;
+
+ /* Valid if mi_flags sets MULTIBOOT_INFO_HAS_CMDLINE. */
+ uint32_t mi_cmdline;
+
+ /* Valid if mi_flags sets MULTIBOOT_INFO_HAS_MODS. */
+ uint32_t mi_mods_count;
+ uint32_t mi_mods_addr;
+
+ /* Valid if mi_flags sets MULTIBOOT_INFO_HAS_{AOUT,ELF}_SYMS. */
+ uint32_t mi_elfshdr_num;
+ uint32_t mi_elfshdr_size;
+ uint32_t mi_elfshdr_addr;
+ uint32_t mi_elfshdr_shndx;
+
+ /* Valid if mi_flags sets MULTIBOOT_INFO_HAS_MMAP. */
+ uint32_t mi_mmap_length;
+ uint32_t mi_mmap_addr;
+
+ /* Valid if mi_flags sets MULTIBOOT_INFO_HAS_DRIVES. */
+ uint32_t mi_drives_length;
+ uint32_t mi_drives_addr;
+
+ /* Valid if mi_flags sets MULTIBOOT_INFO_HAS_CONFIG_TABLE. */
+ uint32_t unused_mi_config_table;
+
+ /* Valid if mi_flags sets MULTIBOOT_INFO_HAS_LOADER_NAME. */
+ uint32_t mi_loader_name;
+
+ /* Valid if mi_flags sets MULTIBOOT_INFO_HAS_APM. */
+ uint32_t unused_mi_apm_table;
+
+ /* Valid if mi_flags sets MULTIBOOT_INFO_HAS_VBE. */
+ uint32_t unused_mi_vbe_control_info;
+ uint32_t unused_mi_vbe_mode_info;
+ uint32_t unused_mi_vbe_interface_seg;
+ uint32_t unused_mi_vbe_interface_off;
+ uint32_t unused_mi_vbe_interface_len;
+}__aligned(8);
+
+
+/*
+ * Memory mapping. This describes an entry in the memory mappings table
+ * as pointed to by mi_mmap_addr.
+ *
+ * Be aware that mm_size specifies the size of all other fields *except*
+ * for mm_size. In order to jump between two different entries, you
+ * have to count mm_size + 4 bytes.
+ */
+struct __attribute__((packed)) multiboot_mmap {
+ uint32_t mm_size;
+ uint64_t mm_base_addr;
+ uint64_t mm_length;
+ uint32_t mm_type;
+};
+
+/*
+ * Modules. This describes an entry in the modules table as pointed
+ * to by mi_mods_addr.
+ */
+
+struct multiboot_module {
+ uint32_t mmo_start;
+ uint32_t mmo_end;
+ uint32_t mmo_string;
+ uint32_t mmo_reserved;
+} __packed;
+
+#endif /* !defined(_LOCORE) */
+
+#ifdef CONFIG_MULTIBOOT2
+#define MB_INFO_MAGIC MULTIBOOT2_INFO_MAGIC
+#else
+#define MB_INFO_MAGIC MULTIBOOT_INFO_MAGIC
+#endif
+
+#ifdef CONFIG_MULTIBOOT2
+
+struct multiboot2_header
+{
+ uint32_t magic;
+ uint32_t architecture;
+ uint32_t header_length;
+ uint32_t checksum;
+};
+
+#define MULTIBOOT2_SEARCH 32768
+
+#define MULTIBOOT2_HEADER_ALIGN 8
+
+#define MULTIBOOT2_HEADER_MAGIC 0xe85250d6U
+
+/* This should be in %eax. */
+#define MULTIBOOT2_INFO_MAGIC 0x36d76289U
+
+/* Alignment of the multiboot info structure. */
+#define MULTIBOOT2_INFO_ALIGN 0x00000008U
+
+/* Flags set in the 'flags' member of the multiboot header. */
+
+#define MULTIBOOT2_TAG_ALIGN 8U
+#define MULTIBOOT2_TAG_TYPE_END 0U
+#define MULTIBOOT2_TAG_TYPE_CMDLINE 1U
+#define MULTIBOOT2_TAG_TYPE_BOOT_LOADER_NAME 2U
+#define MULTIBOOT2_TAG_TYPE_MODULE 3U
+#define MULTIBOOT2_TAG_TYPE_BASIC_MEMINFO 4U
+#define MULTIBOOT2_TAG_TYPE_BOOTDEV 5U
+#define MULTIBOOT2_TAG_TYPE_MMAP 6U
+#define MULTIBOOT2_TAG_TYPE_VBE 7U
+#define MULTIBOOT2_TAG_TYPE_FRAMEBUFFER 8U
+#define MULTIBOOT2_TAG_TYPE_ELF_SECTIONS 9U
+#define MULTIBOOT2_TAG_TYPE_APM 10U
+#define MULTIBOOT2_TAG_TYPE_EFI32 11U
+#define MULTIBOOT2_TAG_TYPE_EFI64 12U
+#define MULTIBOOT2_TAG_TYPE_SMBIOS 13U
+#define MULTIBOOT2_TAG_TYPE_ACPI_OLD 14U
+#define MULTIBOOT2_TAG_TYPE_ACPI_NEW 15U
+#define MULTIBOOT2_TAG_TYPE_NETWORK 16U
+#define MULTIBOOT2_TAG_TYPE_EFI_MMAP 17U
+#define MULTIBOOT2_TAG_TYPE_EFI_BS 18U
+#define MULTIBOOT2_TAG_TYPE_EFI32_IH 19U
+#define MULTIBOOT2_TAG_TYPE_EFI64_IH 20U
+#define MULTIBOOT2_TAG_TYPE_LOAD_BASE_ADDR 21U
+
+#define MULTIBOOT2_HEADER_TAG_END 0
+#define MULTIBOOT2_HEADER_TAG_INFORMATION_REQUEST 1
+#define MULTIBOOT2_HEADER_TAG_ADDRESS 2
+#define MULTIBOOT2_HEADER_TAG_ENTRY_ADDRESS 3
+#define MULTIBOOT2_HEADER_TAG_CONSOLE_FLAGS 4
+#define MULTIBOOT2_HEADER_TAG_FRAMEBUFFER 5
+#define MULTIBOOT2_HEADER_TAG_MODULE_ALIGN 6
+#define MULTIBOOT2_HEADER_TAG_EFI_BS 7
+#define MULTIBOOT2_HEADER_TAG_ENTRY_ADDRESS_EFI32 8
+#define MULTIBOOT2_HEADER_TAG_ENTRY_ADDRESS_EFI64 9
+#define MULTIBOOT2_HEADER_TAG_RELOCATABLE 10
+#define MULTIBOOT2_HEADER_TAG_OPTIONAL 1
+
+#define MULTIBOOT2_ARCHITECTURE_I386 0
+#define MULTIBOOT2_ARCHITECTURE_MIPS32 4
+
+#ifndef ASSEMBLER
+
+struct multiboot2_header_tag
+{
+ uint16_t type;
+ uint16_t flags;
+ uint32_t size;
+};
+
+struct multiboot2_header_tag_information_request
+{
+ uint16_t type;
+ uint16_t flags;
+ uint32_t size;
+ uint32_t requests[0];
+};
+
+struct multiboot2_header_tag_address
+{
+ uint16_t type;
+ uint16_t flags;
+ uint32_t size;
+ uint32_t header_addr;
+ uint32_t load_addr;
+ uint32_t load_end_addr;
+ uint32_t bss_end_addr;
+};
+
+struct multiboot2_header_tag_entry_address
+{
+ uint16_t type;
+ uint16_t flags;
+ uint32_t size;
+ uint32_t entry_addr;
+};
+
+struct multiboot2_header_tag_console_flags
+{
+ uint16_t type;
+ uint16_t flags;
+ uint32_t size;
+ uint32_t console_flags;
+};
+
+struct multiboot2_header_tag_framebuffer
+{
+ uint16_t type;
+ uint16_t flags;
+ uint32_t size;
+ uint32_t width;
+ uint32_t height;
+ uint32_t depth;
+};
+
+struct multiboot2_header_tag_module_align
+{
+ uint16_t type;
+ uint16_t flags;
+ uint32_t size;
+};
+
+struct multiboot2_header_tag_relocatable
+{
+ uint16_t type;
+ uint16_t flags;
+ uint32_t size;
+ uint32_t min_addr;
+ uint32_t max_addr;
+ uint32_t align;
+ uint32_t preference;
+};
+
+struct multiboot2_mmap_entry
+{
+ uint64_t addr;
+ uint64_t len;
+ uint32_t type;
+ uint32_t zero;
+};
+
+struct multiboot2_tag
+{
+ uint32_t type;
+ uint32_t size;
+};
+
+struct multiboot2_tag_string
+{
+ uint32_t type;
+ uint32_t size;
+ char string[0];
+};
+
+struct multiboot2_tag_module
+{
+ uint32_t type;
+ uint32_t size;
+ uint32_t mod_start;
+ uint32_t mod_end;
+ char cmdline[0];
+};
+
+struct multiboot2_tag_mmap
+{
+ uint32_t type;
+ uint32_t size;
+ uint32_t entry_size;
+ uint32_t entry_version;
+ struct multiboot2_mmap_entry entries[0];
+};
+
+struct multiboot2_tag_new_acpi
+{
+ uint32_t type;
+ uint32_t size;
+ uint8_t rsdp[0];
+};
+
+struct multiboot2_tag_efi64
+{
+ uint32_t type;
+ uint32_t size;
+ uint64_t pointer;
+};
+
+struct multiboot2_tag_efi_mmap {
+ uint32_t type;
+ uint32_t size;
+ uint32_t descr_size;
+ uint32_t descr_vers;
+ uint8_t efi_mmap[0];
+};
+#endif
+
+#endif /* CONFIG_MULTIBOOT2 */
+
+#endif /* _MULTIBOOT_H */
diff --git a/misc/efi-stub/pe.c b/misc/efi-stub/pe.c
new file mode 100644
index 000000000..0c734aa4d
--- /dev/null
+++ b/misc/efi-stub/pe.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2011 - 2021, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file contains some wrappers around the gnu-efi functions. As
+ * we're not going through uefi_call_wrapper() directly, this allows
+ * us to get some type-safety for function call arguments and for the
+ * compiler to check that the number of function call arguments is
+ * correct.
+ *
+ * It's also a good place to document the EFI interface.
+ */
+
+#include
+#include
+#include "stdlib.h"
+
+#define DOS_FILE_MAGIC_NUMBER 0x5A4D /* "MZ" */
+struct DosFileHeader {
+ uint16_t mMagic;
+ uint16_t LastSize;
+ uint16_t nBlocks;
+ uint16_t nReloc;
+ uint16_t HdrSize;
+ uint16_t MinAlloc;
+ uint16_t MaxAlloc;
+ uint16_t ss;
+ uint16_t sp;
+ uint16_t Checksum;
+ uint16_t ip;
+ uint16_t cs;
+ uint16_t RelocPos;
+ uint16_t nOverlay;
+ uint16_t reserved[4];
+ uint16_t OEMId;
+ uint16_t OEMInfo;
+ uint16_t reserved2[10];
+ uint32_t ExeHeader;
+} __attribute__((packed));
+
+#define IMAGE_FILE_MACHINE_I386 0x14c
+#define IMAGE_FILE_MACHINE_AMD64 0x8664
+#define PE_FILE_MAGIC_NUMBER 0x00004550 /* "PE\0\0" */
+struct PeHeader {
+ uint32_t mMagic;
+ uint16_t mMachine;
+ uint16_t mNumberOfSections;
+ uint32_t mTimeDateStamp;
+ uint32_t mPointerToSymbolTable;
+ uint32_t mNumberOfSymbols;
+ uint16_t mSizeOfOptionalHeader;
+ uint16_t mCharacteristics;
+} __attribute__((packed));
+
+struct OptionHeader {
+ uint16_t Format;
+ uint8_t MajorLinkVer;
+ uint8_t MinorLinkVer;
+ uint32_t CodeSize;
+ uint32_t InitializedDataSize;
+ uint32_t UninitializedDataSize;
+ uint32_t EntryPoint;
+ uint32_t BaseOfCode;
+ uint32_t BaseOfDate;
+} __attribute__((packed));
+
+
+struct PeSectionHeader {
+ char mName[8];
+ uint32_t mVirtualSize;
+ uint32_t mVirtualAddress;
+ uint32_t mSizeOfRawData;
+ uint32_t mPointerToRawData;
+ uint32_t mPointerToRealocations;
+ uint32_t mPointerToLinenumbers;
+ uint16_t mNumberOfRealocations;
+ uint16_t mNumberOfLinenumbers;
+ uint32_t mCharacteristics;
+} __attribute__((packed));
+
+
+EFI_STATUS get_pe_section(CHAR8 *base, char *section_name,
+ UINTN section_name_len, UINTN *vaddr, UINTN *size)
+{
+ struct PeSectionHeader *ph;
+ struct DosFileHeader *dh;
+ struct PeHeader *pe;
+ UINTN i;
+ UINTN offset;
+
+ dh = (struct DosFileHeader *)base;
+
+ if (dh->mMagic != DOS_FILE_MAGIC_NUMBER)
+ return EFI_LOAD_ERROR;
+
+ pe = (struct PeHeader *)&base[dh->ExeHeader];
+ if (pe->mMagic != PE_FILE_MAGIC_NUMBER)
+ return EFI_LOAD_ERROR;
+
+ if ((pe->mMachine != IMAGE_FILE_MACHINE_AMD64)
+ && (pe->mMachine != IMAGE_FILE_MACHINE_I386))
+ return EFI_LOAD_ERROR;
+
+ offset = dh->ExeHeader + sizeof(*pe) + pe->mSizeOfOptionalHeader;
+
+ for (i = 0; i < pe->mNumberOfSections; i++) {
+ ph = (struct PeSectionHeader *)&base[offset];
+ if (CompareMem(ph->mName, section_name, section_name_len) == 0) {
+ *vaddr = (UINTN)ph->mVirtualAddress;
+ *size = (UINTN)ph->mVirtualSize;
+ break;
+ }
+
+ offset += sizeof(*ph);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+EFI_IMAGE_ENTRY_POINT get_pe_entry(CHAR8 *base)
+{
+ struct DosFileHeader* dh;
+ struct PeHeader* pe;
+ struct OptionHeader* oh;
+ UINTN offset;
+
+ dh = (struct DosFileHeader *)base;
+
+ if (dh->mMagic != DOS_FILE_MAGIC_NUMBER)
+ return NULL;
+
+ pe = (struct PeHeader *)&base[dh->ExeHeader];
+ if (pe->mMagic != PE_FILE_MAGIC_NUMBER)
+ return NULL;
+
+ if ((pe->mMachine != IMAGE_FILE_MACHINE_AMD64)
+ && (pe->mMachine != IMAGE_FILE_MACHINE_I386))
+ return NULL;
+
+ offset = dh->ExeHeader + sizeof(*pe);
+ oh = (struct OptionHeader*)&base[offset];
+
+ return (EFI_IMAGE_ENTRY_POINT)((UINT64)base + oh->EntryPoint);
+}
diff --git a/misc/efi-stub/stdlib.h b/misc/efi-stub/stdlib.h
new file mode 100644
index 000000000..a8d8e2007
--- /dev/null
+++ b/misc/efi-stub/stdlib.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2011 - 2021, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file contains some wrappers around the gnu-efi functions. As
+ * we're not going through uefi_call_wrapper() directly, this allows
+ * us to get some type-safety for function call arguments and for the
+ * compiler to check that the number of function call arguments is
+ * correct.
+ *
+ * It's also a good place to document the EFI interface.
+ */
+
+
+
+#ifndef __STDLIB_H__
+#define __STDLIB_H__
+
+
+static inline void memset(void *dstv, char ch, UINTN size)
+{
+ char *dst = dstv;
+ int32_t i;
+
+ for (i = 0; i < size; i++)
+ dst[i] = ch;
+}
+
+static inline void memcpy(char *dst, const char *src, UINTN size)
+{
+ int32_t i;
+
+ for (i = 0; i < size; i++)
+ *dst++ = *src++;
+}
+
+static inline int32_t strlen(const char *str)
+{
+ int32_t len;
+
+ len = 0;
+ while (*str++)
+ len++;
+
+ return len;
+}
+
+static inline CHAR16 *strstr_16(CHAR16 *haystack, CHAR16 *needle, UINTN len)
+{
+ CHAR16 *p;
+ CHAR16 *word = NULL;
+
+ if (!len)
+ return NULL;
+
+ p = haystack;
+ while (*p) {
+ if (!StrnCmp(p, needle, len)) {
+ word = p;
+ break;
+ }
+ p++;
+ }
+
+ return (CHAR16*)word;
+}
+
+static inline char *ch16_2_ch8(CHAR16 *str16, UINTN len)
+{
+ UINTN i;
+ char *str8;
+
+ str8 = AllocatePool((len + 1) * sizeof(char));
+
+ for (i = 0; i < len; i++)
+ str8[i] = str16[i];
+
+ str8[len] = 0;
+
+ return str8;
+}
+
+static inline CHAR16 *ch8_2_ch16(char *str8, UINTN len)
+{
+ UINTN i;
+ CHAR16 *str16;
+
+ str16 = AllocatePool((len + 1) * sizeof(CHAR16));
+
+ for (i = 0; i < len; i++)
+ str16[i] = str8[i];
+
+ str16[len] = 0;
+
+ return str16;
+}
+
+#endif /* __STDLIB_H__ */