mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-05-16 12:19:42 +00:00
With this patch, we relocate hypervisor image to HPA 256MB and above, thus the hardcoded hvlog and ramoops buffer for SOS can safely reside at addresses under HPA 256MB, given that 1:1 mapping between SOS GPA and HPA. Tracked-On: #4760 Signed-off-by: Zide Chen <zide.chen@intel.com> Reviewed-by: Jason Chen CJ <jason.cj.chen@intel.com>
559 lines
16 KiB
C
559 lines
16 KiB
C
/*
|
|
* Copyright (c) 2011, 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 "deprivilege_boot.h"
|
|
#include "MpService.h"
|
|
|
|
EFI_SYSTEM_TABLE *sys_table;
|
|
EFI_BOOT_SERVICES *boot;
|
|
char *cmdline = NULL;
|
|
extern const uint64_t guest_entry;
|
|
static UINT64 hv_hpa;
|
|
|
|
static void
|
|
enable_disable_all_ap(BOOLEAN enable)
|
|
{
|
|
EFI_MP_SERVICES_PROTOCOL *mp = NULL;
|
|
EFI_STATUS err;
|
|
EFI_GUID mp_guid = EFI_MP_SERVICES_PROTOCOL_GUID;
|
|
UINTN n_proc, n_enabled_proc, bsp, i;
|
|
|
|
err = uefi_call_wrapper(boot->LocateProtocol, 3, &mp_guid, NULL, (void **)&mp);
|
|
if (err != EFI_SUCCESS) {
|
|
Print(L"Unable to locate MP service protocol: %r, skip %s all AP\n",
|
|
err, enable ? "enable" : "disable");
|
|
return;
|
|
}
|
|
|
|
err = uefi_call_wrapper(mp->GetNumberOfProcessors, 3, mp, &n_proc, &n_enabled_proc);
|
|
if (err != EFI_SUCCESS) {
|
|
Print(L"failed to GetNumberOfProcessors: %r\n", err);
|
|
return;
|
|
}
|
|
Print(L"detected %d processes, %d enabled\n", n_proc, n_enabled_proc);
|
|
|
|
err = uefi_call_wrapper(mp->WhoAmI, 2, mp, &bsp);
|
|
if (err != EFI_SUCCESS) {
|
|
Print(L"failed to WhoAmI: %r\n", err);
|
|
return;
|
|
}
|
|
Print(L"current on process %d\n", bsp);
|
|
|
|
for (i = 0; i < n_proc; i++) {
|
|
if (i == bsp) {
|
|
continue;
|
|
}
|
|
|
|
err = uefi_call_wrapper(mp->EnableDisableAP, 4, mp, i, enable, NULL);
|
|
if (err != EFI_SUCCESS) {
|
|
Print(L"failed to %s AP%d: %r\n", enable ? "enable" : "disable", i, err);
|
|
}
|
|
}
|
|
}
|
|
|
|
static inline void hv_jump(EFI_PHYSICAL_ADDRESS hv_start,
|
|
struct multiboot_info *mbi, struct depri_boot_context *efi_ctx)
|
|
{
|
|
hv_func hf;
|
|
|
|
efi_ctx->vcpu_regs.rip = (uint64_t)&guest_entry;
|
|
|
|
/* 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(MULTIBOOT_INFO_MAGIC, mbi);
|
|
}
|
|
|
|
EFI_STATUS construct_mbi(EFI_PHYSICAL_ADDRESS hv_hpa, struct multiboot_info *mbi,
|
|
struct multiboot_mmap *mmap)
|
|
{
|
|
UINTN map_size, map_key;
|
|
UINT32 desc_version;
|
|
UINTN desc_size;
|
|
EFI_MEMORY_DESCRIPTOR *map_buf;
|
|
EFI_STATUS err = EFI_SUCCESS;
|
|
int32_t i, j, mmap_entry_count;
|
|
|
|
/* We're just interested in the map's size for now */
|
|
map_size = 0;
|
|
err = get_memory_map(&map_size, NULL, NULL, NULL, NULL);
|
|
if (err != EFI_SUCCESS && err != EFI_BUFFER_TOO_SMALL)
|
|
goto out;
|
|
|
|
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;
|
|
}
|
|
|
|
mmap_entry_count = map_size / desc_size;
|
|
/*
|
|
* 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)map_buf + (i * 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 = hv_hpa;
|
|
mmap[j].mm_length = CONFIG_HV_RAM_SIZE;
|
|
mmap[j].mm_type = E820_RAM;
|
|
j++;
|
|
|
|
mbi->mi_cmdline = (UINTN)cmdline;
|
|
mbi->mi_mmap_addr = (UINTN)mmap;
|
|
mbi->mi_mmap_length = j*sizeof(struct multiboot_mmap);
|
|
mbi->mi_flags |= MULTIBOOT_INFO_HAS_MMAP | MULTIBOOT_INFO_HAS_CMDLINE;
|
|
out:
|
|
return err;
|
|
}
|
|
|
|
static EFI_STATUS
|
|
switch_to_guest_mode(EFI_HANDLE image, EFI_PHYSICAL_ADDRESS hv_hpa)
|
|
{
|
|
EFI_PHYSICAL_ADDRESS addr;
|
|
EFI_STATUS err;
|
|
struct multiboot_mmap *mmap;
|
|
struct multiboot_info *mbi;
|
|
struct depri_boot_context *efi_ctx;
|
|
struct acpi_table_rsdp *rsdp = NULL;
|
|
int32_t i;
|
|
EFI_CONFIGURATION_TABLE *config_table;
|
|
char *uefi_boot_loader_name;
|
|
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);
|
|
efi_ctx = BOOT_CTX_PTR(addr);
|
|
|
|
uefi_boot_loader_name = BOOT_LOADER_NAME_PTR(addr);
|
|
memcpy(uefi_boot_loader_name, loader_name, BOOT_LOADER_NAME_SIZE);
|
|
|
|
/* reserve secondary memory region for CPU trampoline code */
|
|
err = emalloc_reserved_mem(&addr, CONFIG_LOW_RAM_SIZE, MEM_ADDR_1MB);
|
|
if (err != EFI_SUCCESS)
|
|
goto out;
|
|
if (addr < 4096)
|
|
Print(L"Warning: CPU trampoline code buf occupied zero-page\n");
|
|
|
|
efi_ctx->ap_trampoline_buf = addr;
|
|
|
|
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++;
|
|
}
|
|
|
|
if (rsdp == NULL) {
|
|
Print(L"unable to find RSDP\n");
|
|
goto out;
|
|
}
|
|
|
|
efi_ctx->rsdp = rsdp;
|
|
|
|
/* construct multiboot info and deliver it to hypervisor */
|
|
err = construct_mbi(hv_hpa, mbi, mmap);
|
|
if (err != EFI_SUCCESS)
|
|
goto out;
|
|
|
|
mbi->mi_flags |= MULTIBOOT_INFO_HAS_DRIVES;
|
|
mbi->mi_drives_addr = (UINT32)(UINTN)efi_ctx;
|
|
|
|
/* 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)uefi_boot_loader_name;
|
|
|
|
asm volatile ("pushf\n\t"
|
|
"pop %0\n\t"
|
|
: "=r"(efi_ctx->vcpu_regs.rflags)
|
|
: );
|
|
asm volatile ("movq %%rax, %0" : "=r"(efi_ctx->vcpu_regs.gprs.rax));
|
|
asm volatile ("movq %%rbx, %0" : "=r"(efi_ctx->vcpu_regs.gprs.rbx));
|
|
asm volatile ("movq %%rcx, %0" : "=r"(efi_ctx->vcpu_regs.gprs.rcx));
|
|
asm volatile ("movq %%rdx, %0" : "=r"(efi_ctx->vcpu_regs.gprs.rdx));
|
|
asm volatile ("movq %%rdi, %0" : "=r"(efi_ctx->vcpu_regs.gprs.rdi));
|
|
asm volatile ("movq %%rsi, %0" : "=r"(efi_ctx->vcpu_regs.gprs.rsi));
|
|
asm volatile ("movq %%rsp, %0" : "=r"(efi_ctx->vcpu_regs.gprs.rsp));
|
|
asm volatile ("movq %%rbp, %0" : "=r"(efi_ctx->vcpu_regs.gprs.rbp));
|
|
asm volatile ("movq %%r8, %0" : "=r"(efi_ctx->vcpu_regs.gprs.r8));
|
|
asm volatile ("movq %%r9, %0" : "=r"(efi_ctx->vcpu_regs.gprs.r9));
|
|
asm volatile ("movq %%r10, %0" : "=r"(efi_ctx->vcpu_regs.gprs.r10));
|
|
asm volatile ("movq %%r11, %0" : "=r"(efi_ctx->vcpu_regs.gprs.r11));
|
|
asm volatile ("movq %%r12, %0" : "=r"(efi_ctx->vcpu_regs.gprs.r12));
|
|
asm volatile ("movq %%r13, %0" : "=r"(efi_ctx->vcpu_regs.gprs.r13));
|
|
asm volatile ("movq %%r14, %0" : "=r"(efi_ctx->vcpu_regs.gprs.r14));
|
|
asm volatile ("movq %%r15, %0" : "=r"(efi_ctx->vcpu_regs.gprs.r15));
|
|
|
|
hv_jump(hv_hpa, mbi, efi_ctx);
|
|
asm volatile (".global guest_entry\n\t"
|
|
"guest_entry:\n\t");
|
|
|
|
out:
|
|
return err;
|
|
}
|
|
|
|
static inline EFI_STATUS isspace(CHAR8 ch)
|
|
{
|
|
return ((uint8_t)ch <= ' ');
|
|
}
|
|
|
|
EFI_STATUS reserve_unconfigure_high_memory(void)
|
|
{
|
|
#define PLATFORM_LO_MMIO_SIZE 0x80000000UL
|
|
UINTN map_size, map_key, desc_size;
|
|
EFI_MEMORY_DESCRIPTOR *map_buf;
|
|
UINTN d, map_end;
|
|
UINTN i;
|
|
UINT32 desc_version;
|
|
EFI_STATUS err;
|
|
UINT64 reserved_hpa;
|
|
EFI_PHYSICAL_ADDRESS top_addr_space = CONFIG_PLATFORM_RAM_SIZE + PLATFORM_LO_MMIO_SIZE;
|
|
|
|
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);
|
|
|
|
if (end > top_addr_space) {
|
|
if (start < top_addr_space)
|
|
start = top_addr_space;
|
|
err = emalloc_fixed_addr(&reserved_hpa, end - start, start);
|
|
Print(L"memory region (%lx, %lx) is truncated from region (%lx, %lx).",
|
|
start, end, desc->PhysicalStart, end);
|
|
if (err != EFI_SUCCESS)
|
|
break;
|
|
}
|
|
}
|
|
|
|
free_pool(map_buf);
|
|
fail:
|
|
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;
|
|
UINTN sec_addr;
|
|
UINTN sec_size;
|
|
char *section;
|
|
EFI_DEVICE_PATH *path;
|
|
|
|
INTN index;
|
|
CHAR16 *bootloader_name = NULL;
|
|
CHAR16 bootloader_param[] = L"bootloader=";
|
|
EFI_HANDLE bootloader_image;
|
|
CHAR16 *options = NULL;
|
|
UINT32 options_size = 0, bootloader_name_off = 0;
|
|
CHAR16 *cmdline16, *n;
|
|
|
|
InitializeLib(image, _table);
|
|
sys_table = _table;
|
|
boot = sys_table->BootServices;
|
|
|
|
if (CheckCrc(sys_table->Hdr.HeaderSize, &sys_table->Hdr) != TRUE)
|
|
return EFI_LOAD_ERROR;
|
|
|
|
/* make sure only bsp is enable before entering hv */
|
|
enable_disable_all_ap(FALSE);
|
|
|
|
err = handle_protocol(image, &LoadedImageProtocol, (void **)&info);
|
|
if (err != EFI_SUCCESS)
|
|
goto failed;
|
|
|
|
/* get the options */
|
|
options = info->LoadOptions;
|
|
options_size = info->LoadOptionsSize;
|
|
|
|
/* convert the options to cmdline */
|
|
if (options_size > 0)
|
|
cmdline = ch16_2_ch8(options, StrnLen(options, options_size));
|
|
|
|
/* First check if we were given a bootloader name
|
|
* E.g.: "bootloader=\EFI\org.clearlinux\bootloaderx64.efi"
|
|
*/
|
|
cmdline16 = StrDuplicate(options);
|
|
bootloader_name = strstr_16(cmdline16, bootloader_param, StrLen(bootloader_param));
|
|
|
|
if (bootloader_name) {
|
|
bootloader_name = bootloader_name + StrLen(bootloader_param);
|
|
bootloader_name_off = bootloader_name - cmdline16;
|
|
|
|
bootloader_name_off *= sizeof(CHAR16);
|
|
|
|
n = bootloader_name;
|
|
while (*n && !isspace((CHAR8)*n) && (*n < 0xff) && (bootloader_name_off < options_size)) {
|
|
n++; bootloader_name_off += sizeof(CHAR16);
|
|
}
|
|
*n++ = '\0';
|
|
} else {
|
|
/*
|
|
* If we reach this point, it means we did not receive a specific
|
|
* bootloader name to be used. Fall back to the default bootloader
|
|
* as specified in config.h
|
|
*/
|
|
bootloader_name = ch8_2_ch16(CONFIG_UEFI_OS_LOADER_NAME, strlen(CONFIG_UEFI_OS_LOADER_NAME));
|
|
}
|
|
|
|
section = ".hv";
|
|
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 %r ", err);
|
|
goto free_args;
|
|
}
|
|
|
|
err = reserve_unconfigure_high_memory();
|
|
if (err != EFI_SUCCESS) {
|
|
Print(L"Unable to reserve un-configure high memory %r ", err);
|
|
goto free_args;
|
|
}
|
|
|
|
/* without relocateion 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)
|
|
goto free_args;
|
|
|
|
memcpy((char *)hv_hpa, info->ImageBase + sec_addr, sec_size);
|
|
|
|
/* load hypervisor and begin to run on it */
|
|
err = switch_to_guest_mode(image, hv_hpa);
|
|
if (err != EFI_SUCCESS)
|
|
goto free_args;
|
|
|
|
/*
|
|
* enable all AP here will reset all APs,
|
|
* so acrn can handle their ctx from now on.
|
|
*/
|
|
enable_disable_all_ap(TRUE);
|
|
|
|
/* load and start the default bootloader */
|
|
path = FileDevicePath(info->DeviceHandle, bootloader_name);
|
|
if (!path)
|
|
goto free_args;
|
|
|
|
FreePool(cmdline16);
|
|
|
|
err = uefi_call_wrapper(boot->LoadImage, 6, FALSE, image,
|
|
path, NULL, 0, &bootloader_image);
|
|
if (EFI_ERROR(err)) {
|
|
uefi_call_wrapper(boot->Stall, 1, 3 * 1000 * 1000);
|
|
goto failed;
|
|
}
|
|
|
|
err = uefi_call_wrapper(boot->StartImage, 3, bootloader_image,
|
|
NULL, NULL);
|
|
if (EFI_ERROR(err)) {
|
|
uefi_call_wrapper(boot->Stall, 1, 3 * 1000 * 1000);
|
|
goto failed;
|
|
}
|
|
uefi_call_wrapper(boot->UnloadImage, 1, bootloader_image);
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
free_args:
|
|
FreePool(cmdline16);
|
|
failed:
|
|
/*
|
|
* 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);
|
|
}
|