mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-06-25 06:51:49 +00:00
efi-stub: add acrn efi application as an alternative bootloader for secure boot
ACRN EFI application based on the legacy efi-stub code provides booting method of HV on UEFI-BIOS without using the GRUB Bootloader. It is supposed to be used for secure booting on certain platform. By means of that users can boot HV, Service VM kernel, pre-launched VM kernel and its ACPI table binary packed in the Slim Bootloader container boot image file format. ACRN EFI application has additional dependencies to compile which are not listed in the existing ACRN GSG doc. Since this is an optional feature but not all users need, it does not get compiled by default to avoid causing any confusion for existing users. README for how to use the feature will come later in a separated commit. Tracked-On: #6078 Signed-off-by: Toshiki Nishioka <toshiki.nishioka@intel.com> Signed-off-by: Yifan Liu <yifan1.liu@intel.com> Co-developed-by: Yifan Liu <yifan1.liu@intel.com>
This commit is contained in:
parent
8f640c61ae
commit
a9cc4b7629
96
misc/efi-stub/Makefile
Normal file
96
misc/efi-stub/Makefile
Normal file
@ -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 $@
|
633
misc/efi-stub/MpService.h
Normal file
633
misc/efi-stub/MpService.h
Normal file
@ -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.<BR>
|
||||
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.
|
||||
///
|
||||
/// <pre>
|
||||
/// 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.
|
||||
/// </pre>
|
||||
///
|
||||
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
|
623
misc/efi-stub/boot.c
Normal file
623
misc/efi-stub/boot.c
Normal file
@ -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 <efi.h>
|
||||
#include <efilib.h>
|
||||
#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);
|
||||
}
|
205
misc/efi-stub/boot.h
Normal file
205
misc/efi-stub/boot.h
Normal file
@ -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
|
487
misc/efi-stub/container.c
Normal file
487
misc/efi-stub/container.c
Normal file
@ -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 <elf.h>
|
||||
#include <efi.h>
|
||||
#include <efilib.h>
|
||||
#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;
|
||||
}
|
44
misc/efi-stub/container.h
Normal file
44
misc/efi-stub/container.h
Normal file
@ -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__ */
|
276
misc/efi-stub/efilinux.h
Normal file
276
misc/efi-stub/efilinux.h
Normal file
@ -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__ */
|
204
misc/efi-stub/malloc.c
Normal file
204
misc/efi-stub/malloc.c
Normal file
@ -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 <efi.h>
|
||||
#include <efilib.h>
|
||||
#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;
|
||||
}
|
||||
|
386
misc/efi-stub/multiboot.h
Normal file
386
misc/efi-stub/multiboot.h
Normal file
@ -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 <stdint.h>
|
||||
#include <types.h>
|
||||
|
||||
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 */
|
173
misc/efi-stub/pe.c
Normal file
173
misc/efi-stub/pe.c
Normal file
@ -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 <efi.h>
|
||||
#include <efilib.h>
|
||||
#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);
|
||||
}
|
126
misc/efi-stub/stdlib.h
Normal file
126
misc/efi-stub/stdlib.h
Normal file
@ -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__ */
|
Loading…
Reference in New Issue
Block a user