diff --git a/Android.mk b/Android.mk index f12e51d7..448e910a 100644 --- a/Android.mk +++ b/Android.mk @@ -30,6 +30,10 @@ ifeq ($(TARGET_USE_SBL),true) KERNELFLINGER_CFLAGS += -DUSE_SBL endif +ifeq ($(TARGET_USE_ACRN),true) + KERNELFLINGER_CFLAGS += -DUSE_ACRN -DMB2_PARTS=\"$(MB2_PARTS)\" +endif + ifeq ($(TARGET_USE_TRUSTY),true) KERNELFLINGER_CFLAGS += -DUSE_TRUSTY endif diff --git a/include/acpi.h b/include/acpi.h index 277e1018..78dbfd75 100644 --- a/include/acpi.h +++ b/include/acpi.h @@ -148,6 +148,8 @@ enum acpi_src_type { ACPI_SRC_TYPE_MAX }; +EFI_STATUS get_acpi_rsdp(VOID **prsdp); + /* Some ACPI table signatures, SSDT for instance, might appear several * times. An extra table number can be appended to the supplied * SIGNATURE to specify which one is required. For instance, with diff --git a/include/acrn.h b/include/acrn.h new file mode 100644 index 00000000..7cbddff3 --- /dev/null +++ b/include/acrn.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ACRN_H__ +#define __ACRN_H__ + +#include "multiboot.h" + +struct efi_memmap_info { + UINTN map_size; + UINTN map_key; + UINT32 desc_version; + UINTN desc_size; + EFI_MEMORY_DESCRIPTOR *mmap; +}; + +/* + * 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 "kernelflinger" +#define BOOT_LOADER_NAME_SIZE (strlen(BOOT_LOADER_NAME) + 1) +#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)) + + +EFI_STATUS acrn_mb2_add_kernel( + IN struct mb2_images *images, + IN EFI_PHYSICAL_ADDRESS kernel_start, + IN UINTN kernel_size, + IN EFI_PHYSICAL_ADDRESS cmdline_start, + IN UINTN cmdline_size, + IN EFI_PHYSICAL_ADDRESS ramdisk_start, + IN INTN ramdisk_size); + +/* Functions to load acrn multiboot2 image and modules. */ +EFI_STATUS acrn_image_start( + IN EFI_HANDLE parent_image, + IN struct mb2_images *images); + +#endif /* __ACRN_H__ */ diff --git a/include/android.h b/include/android.h index 0ddade1f..a5d203c6 100644 --- a/include/android.h +++ b/include/android.h @@ -25,6 +25,7 @@ #endif #include "targets.h" #include "android_vb2.h" +#include "multiboot.h" #define BOOT_MAGIC "ANDROID!" #define BOOT_MAGIC_SIZE 8 @@ -495,6 +496,21 @@ _Static_assert(sizeof(struct bootloader_control) == "struct bootloader_control has wrong size"); #endif +/* load kernel, cmdline and ramdisk */ +EFI_STATUS load_kernel( + IN __attribute__((unused)) EFI_HANDLE parent_image, + IN VOID *bootimage, + IN VOID *vendorbootimage, + IN enum boot_target boot_target, + IN UINT8 boot_state, + IN EFI_GUID *swap_guid, + IN VBDATA *vb_data, + IN const CHAR8 *abl_cmd_line, + IN EFI_PHYSICAL_ADDRESS *kernel_start, IN UINTN *kernel_size, + IN EFI_PHYSICAL_ADDRESS *ramdisk_start, IN UINTN *ramdisk_size, + IN EFI_PHYSICAL_ADDRESS *cmdline_start, IN UINTN *cmdline_size); + + /* Functions to load an Android boot image. * You can do this from a file, a partition GUID, or * from a RAM buffer */ diff --git a/include/multiboot.h b/include/multiboot.h new file mode 100644 index 00000000..7defcb2c --- /dev/null +++ b/include/multiboot.h @@ -0,0 +1,286 @@ +/* [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 + +struct multiboot2_header +{ + uint32_t magic; + uint32_t architecture; + uint32_t header_length; + uint32_t checksum; +} __attribute__((__packed__)); + +#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 + +struct multiboot2_header_tag +{ + uint16_t type; + uint16_t flags; + uint32_t size; +}__attribute__((__packed__)); + +struct multiboot2_header_tag_information_request +{ + uint16_t type; + uint16_t flags; + uint32_t size; + uint32_t requests[0]; +}__attribute__((__packed__)); + +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; +}__attribute__((__packed__)); + +struct multiboot2_header_tag_entry_address +{ + uint16_t type; + uint16_t flags; + uint32_t size; + uint32_t entry_addr; +}__attribute__((__packed__)); + +struct multiboot2_header_tag_console_flags +{ + uint16_t type; + uint16_t flags; + uint32_t size; + uint32_t console_flags; +}__attribute__((__packed__)); + +struct multiboot2_header_tag_framebuffer +{ + uint16_t type; + uint16_t flags; + uint32_t size; + uint32_t width; + uint32_t height; + uint32_t depth; +}__attribute__((__packed__)); + +struct multiboot2_header_tag_module_align +{ + uint16_t type; + uint16_t flags; + uint32_t size; +}__attribute__((__packed__)); + +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; +}__attribute__((__packed__)); + +struct multiboot2_mmap_entry +{ + uint64_t addr; + uint64_t len; + uint32_t type; + uint32_t zero; +}__attribute__((__packed__)); + +struct multiboot2_tag +{ + uint32_t type; + uint32_t size; +}__attribute__((__packed__)); + +struct multiboot2_tag_string +{ + uint32_t type; + uint32_t size; + char string[0]; +}__attribute__((__packed__)); + +struct multiboot2_tag_module +{ + uint32_t type; + uint32_t size; + uint32_t mod_start; + uint32_t mod_end; + char cmdline[0]; +}__attribute__((__packed__)); + +struct multiboot2_tag_mmap +{ + uint32_t type; + uint32_t size; + uint32_t entry_size; + uint32_t entry_version; + struct multiboot2_mmap_entry entries[0]; +}__attribute__((__packed__)); + +struct multiboot2_tag_new_acpi +{ + uint32_t type; + uint32_t size; + uint8_t rsdp[0]; +}__attribute__((__packed__)); + +struct multiboot2_tag_efi64 +{ + uint32_t type; + uint32_t size; + uint64_t pointer; +}__attribute__((__packed__)); + +struct multiboot2_tag_efi_mmap { + uint32_t type; + uint32_t size; + uint32_t descr_size; + uint32_t descr_vers; + uint8_t efi_mmap[0]; +}__attribute__((__packed__)); + +struct mb2header_tag_list { + struct multiboot2_header_tag_information_request *info_req; + struct multiboot2_header_tag_address *addr; + struct multiboot2_header_tag_entry_address *entry; + struct multiboot2_header_tag_console_flags *console_flags; + struct multiboot2_header_tag_framebuffer *frbuf; + struct multiboot2_header_tag_module_align *modalign; + struct multiboot2_header_tag_relocatable *reloc; +}; + +const struct multiboot2_header *find_mb2header(const uint8_t *buffer, uint64_t len); +int parse_mb2header(const struct multiboot2_header *header, struct mb2header_tag_list *tags); + +#define ALIGN_UP(x, align) (((x) + (align) - 1) & ~((align) - 1)) + + +/* in-partitioin MB2 image format, irralevant to multiboot protocol. We may + * change the image format in future. + */ +struct mb2_image_header { +#define MB2_MAGIC_SIZE 8 +#define MB2_MAGIC "ACRNMB2" + uint8_t magic[MB2_MAGIC_SIZE]; + uint32_t header_version; + uint32_t header_size; + uint32_t mod_offset; + uint32_t mod_size; + uint32_t mod_align; +#define MB2_CMDLINE_SIZE 4096 + uint8_t cmdline[MB2_CMDLINE_SIZE]; /* NULL terminated */ +}__attribute__((__packed__)); +void dump_mb2_partition(struct mb2_image_header *hdr); + +struct mb2_module { + void *start; + uint64_t size; + char *cmdline; + uint64_t cmdline_buf_size; +}; + +#define MAX_MB2_IMAGES 16 +struct mb2_images { + struct mb2_image_header *headers[MAX_MB2_IMAGES]; + const char *names[MAX_MB2_IMAGES]; + struct mb2_module mods[16]; + uint8_t cnt; +}; + +EFI_STATUS load_mb2_images(IN struct mb2_images *images); + + + +#endif /* _MULTIBOOT_H */ diff --git a/include/targets.h b/include/targets.h index b64786e6..0e92bf8d 100644 --- a/include/targets.h +++ b/include/targets.h @@ -50,7 +50,9 @@ enum boot_target { MEMORY, CHARGER, POWER_OFF, - EXIT_SHELL + EXIT_SHELL, + ASOS, + MAX_BOOT_TARGET, }; #define is_bootimg_target(target) \ diff --git a/kernelflinger.c b/kernelflinger.c index 2744162e..87994aa7 100644 --- a/kernelflinger.c +++ b/kernelflinger.c @@ -79,6 +79,7 @@ BOOLEAN andr_tpm = true; #else BOOLEAN andr_tpm = false; #endif +#include "acrn.h" /* Ensure this is embedded in the EFI binary somewhere */ static const CHAR16 __attribute__((used)) magic[] = L"### kernelflinger ###"; @@ -1057,6 +1058,7 @@ static EFI_STATUS avb_load_verify_boot_image( EFI_STATUS ret; switch (boot_target) { + case ASOS: case NORMAL_BOOT: case CHARGER: if (!slot_data) { @@ -1118,6 +1120,7 @@ static EFI_STATUS avb_load_verify_vendor_boot_image( AvbSlotVerifyData *slot_data; switch (boot_target) { + case ASOS: case NORMAL_BOOT: case CHARGER: case RECOVERY: @@ -1135,6 +1138,50 @@ static EFI_STATUS avb_load_verify_vendor_boot_image( } +/* Use AVB load and verify multiboot2 images into RAM. + * + * boot_target - Boot image to load. Values supported are ASOS so far. + * images - loaded multiboot2 images for acrn and Prelaunched VMs. + * + * Return values: + * EFI_INVALID_PARAMETER - Unsupported boot target type, key is not well-formed, + * or loaded acrn image was missing or corrupt + * EFI_ACCESS_DENIED - Validation failed against OEM or embedded certificate, + * acrn image still usable + */ +EFI_STATUS avb_load_verify_mb2_images( + IN enum boot_target boot_target, + IN struct mb2_images *images) +{ + UINT8 boot_state; + AvbSlotVerifyData *slot_data; // TODO take care for production + struct mb2_image_header *hdr; + EFI_STATUS ret; + CHAR8 *image_names = MB2_PARTS; + + images->cnt = 0; + CHAR16* str = stra_to_str(image_names); + info(L"Multiboot2 Images: %s", str); + FreePool(str); + + if (boot_target == ASOS) { + ret = android_image_load_partition_avb_ab("acrn", (void **)&hdr, &boot_state, &slot_data); + if (EFI_ERROR(ret)) { + error(L"fail to load acrn partition"); + return ret; + } + dump_mb2_partition(hdr); + images->headers[images->cnt] = hdr; + images->names[images->cnt] = "acrn"; + images->cnt++; + + /* TODO add pre launch vms components */ + return EFI_SUCCESS; + } else { + return EFI_INVALID_PARAMETER; + } +} + #define OEMVARS_MAGIC "#OEMVARS\n" #define OEMVARS_MAGIC_SZ 9 @@ -1183,7 +1230,8 @@ static EFI_STATUS set_image_oemvars(VOID *bootimage) return set_image_oemvars_nocheck(bootimage, NULL); } -static EFI_STATUS load_image(VOID *bootimage, VOID *vendorbootimage, UINT8 boot_state, +static EFI_STATUS load_image(struct mb2_images *images, VOID *bootimage, + VOID *vendorbootimage, UINT8 boot_state, enum boot_target boot_target, VBDATA *vb_data ) @@ -1273,6 +1321,35 @@ static EFI_STATUS load_image(VOID *bootimage, VOID *vendorbootimage, UINT8 boot_ else if (andr_tpm) tpm2_end(); +#ifdef USE_ACRN + if (boot_target == ASOS) { + ret = load_mb2_images(images); + if (EFI_ERROR(ret)) + goto failed; + + EFI_PHYSICAL_ADDRESS kernel_start, cmdline_start, ramdisk_start; + UINTN kernel_size, cmdline_size, ramdisk_size; + ret = load_kernel(g_parent_image, bootimage, + vendorbootimage, boot_target, boot_state, NULL, + vb_data, NULL, &kernel_start, &kernel_size, + &ramdisk_start, &ramdisk_size, &cmdline_start, + &cmdline_size); + if (EFI_ERROR(ret)) + goto failed; + + /* add kernel and ramdisk as multiboot2 modules */ + acrn_mb2_add_kernel(images, kernel_start, kernel_size, + cmdline_start, cmdline_size, + ramdisk_start, ramdisk_size); + + debug(L"chainloading acrn image, boot state is %s", boot_state_to_string(boot_state)); + ret = acrn_image_start(g_parent_image, images); + if (EFI_ERROR(ret)) + efi_perror(ret, L"Couldn't load acrn image"); + + } else +#endif + { debug(L"chainloading boot image, boot state is %s", boot_state_to_string(boot_state)); ret = android_image_start_buffer(g_parent_image, bootimage, vendorbootimage, @@ -1281,7 +1358,9 @@ static EFI_STATUS load_image(VOID *bootimage, VOID *vendorbootimage, UINT8 boot_ cmd_buf); if (EFI_ERROR(ret)) efi_perror(ret, L"Couldn't load Boot image"); + } +failed: ret = slot_boot_failed(boot_target); if (EFI_ERROR(ret)) efi_perror(ret, L"Failed to write slot failure"); @@ -1373,7 +1452,7 @@ static VOID enter_fastboot_mode(UINT8 boot_state) if (EFI_ERROR(ret)) efi_perror(ret, L"Fastboot mode fail to load slot data"); set_image_oemvars_nocheck(bootimage, NULL); - load_image(bootimage, NULL, BOOT_STATE_ORANGE, NORMAL_BOOT, slot_data); + load_image(NULL, bootimage, NULL, BOOT_STATE_ORANGE, NORMAL_BOOT, slot_data); } FreePool(bootimage); bootimage = NULL; @@ -1505,6 +1584,8 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) #ifdef __CRASH_DUMP EFI_GUID dump_partition = { 0xCAB9B00C, 0xCC1B, 0x4C0F, {0xB9, 0x32, 0x82, 0x92, 0x0D, 0xA5, 0x22, 0x51} }; #endif + struct mb2_images mb2_images; + memset(&mb2_images, 0, sizeof(struct mb2_images)); set_boottime_stamp(TM_EFI_MAIN); /* gnu-efi initialization */ @@ -1642,6 +1723,11 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) if (boot_target == DNX || boot_target == CRASHMODE) reboot_to_target(boot_target, EfiResetCold); +#ifdef USE_ACRN + if (boot_target == NORMAL_BOOT) + boot_target = ASOS; +#endif + #ifdef USERDEBUG debug(L"checking device state"); @@ -1713,6 +1799,10 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) disable_slot_if_efi_loaded_slot_failed(); ret = avb_load_verify_boot_image(boot_target, target_path, &bootimage, oneshot, &boot_state, &vb_data); avb_load_verify_vendor_boot_image(boot_target, &vendorbootimage); +#ifdef USE_ACRN + /* just verify images paritions, will load images later */ + avb_load_verify_mb2_images(boot_target, &mb2_images); +#endif set_boottime_stamp(TM_VERIFY_BOOT_DONE); @@ -1734,6 +1824,9 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) set_image_oemvars_nocheck(bootimage, NULL); set_oemvars_update(TRUE); break; +#ifdef USE_ACRN + case ASOS: +#endif case NORMAL_BOOT: case CHARGER: set_image_oemvars(bootimage); @@ -1742,13 +1835,16 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) break; } - ret = load_image(bootimage, vendorbootimage, boot_state, boot_target, + ret = load_image(&mb2_images, bootimage, vendorbootimage, boot_state, boot_target, vb_data ); if (EFI_ERROR(ret)) efi_perror(ret, L"Failed to start boot image"); switch (boot_target) { +#ifdef USE_ACRN + case ASOS: +#endif case NORMAL_BOOT: case CHARGER: if (slot_get_active()) diff --git a/libkernelflinger/Android.mk b/libkernelflinger/Android.mk index 584638e4..aa0ec6c3 100755 --- a/libkernelflinger/Android.mk +++ b/libkernelflinger/Android.mk @@ -97,6 +97,7 @@ ifeq ($(MULTI_USER_SUPPORT),true) endif LOCAL_SRC_FILES := \ + acrn.c \ android.c \ efilinux.c \ acpi.c \ @@ -111,6 +112,7 @@ LOCAL_SRC_FILES := \ storage.c \ pci.c \ mmc.c \ + multiboot.c \ ufs.c \ sdcard.c \ sdio.c \ diff --git a/libkernelflinger/acpi.c b/libkernelflinger/acpi.c index 21140c7a..668a287a 100644 --- a/libkernelflinger/acpi.c +++ b/libkernelflinger/acpi.c @@ -183,6 +183,12 @@ static EFI_STATUS get_xsdt_table(struct XSDT_TABLE **xsdt) return ret; } +EFI_STATUS get_acpi_rsdp(VOID **prsdp) +{ + EFI_GUID acpi2_guid = ACPI_20_TABLE_GUID; + return LibGetSystemConfigurationTable(&acpi2_guid, prsdp); +} + EFI_STATUS get_acpi_table(const CHAR8 *signature, VOID **table) { struct XSDT_TABLE *xsdt; diff --git a/libkernelflinger/acrn.c b/libkernelflinger/acrn.c new file mode 100644 index 00000000..f9fca625 --- /dev/null +++ b/libkernelflinger/acrn.c @@ -0,0 +1,512 @@ +#include +#include +#include + +#include "android.h" +#include "efilinux.h" +#include "lib.h" +#include "security.h" +#include "vars.h" +#include "power.h" +#include "targets.h" +#include "gpt.h" +#include "storage.h" +#include "text_parser.h" +#include "watchdog.h" +#ifdef HAL_AUTODETECT +#include "blobstore.h" +#endif +#include "slot.h" +#include "pae.h" +#include "timer.h" +#include "android_vb2.h" +#include "acpi.h" +#ifdef USE_FIRSTSTAGE_MOUNT +#include "firststage_mount.h" +#endif +#ifdef USE_TRUSTY +#include "trusty_common.h" +#endif + +#include "uefi_utils.h" +#include "libxbc.h" + +#include "acrn.h" + +#if 0 +static int mb2_images_add(struct mb2_images *images, + VOID *start, UINTN size, + CHAR8 *cmdline, UINTN cmdline_buf_size) +{ + if (images->cnt >= 15) { + error(L"too many multiboot images"); + return -1; + } + + images->mods[images->cnt].start = start; + images->mods[images->cnt].size = size; + images->mods[images->cnt].cmdline = cmdline; + images->mods[images->cnt].cmdline_buf_size = cmdline_buf_size; + images->cnt++; + return 0; +} +#endif + +static void mb2_images_dump(struct mb2_images *images) +{ + int i; + struct mb2_module *mod; + CHAR16* str; + + for(i = 0; i < images->cnt; i++) { + mod = &images->mods[i]; + str = stra_to_str(mod->cmdline); + debug(L"Image%d, start: 0x%lx, size: 0x%lx, cmdlen: %d, cmdline: %s", + i, mod->start, mod->size, strnlen(mod->cmdline, mod->cmdline_buf_size), str); + } +} + +EFI_STATUS acrn_mb2_add_kernel( + IN struct mb2_images *images, + IN EFI_PHYSICAL_ADDRESS kernel_start, + IN UINTN kernel_size, + IN EFI_PHYSICAL_ADDRESS cmdline_start, + IN UINTN cmdline_size, + IN EFI_PHYSICAL_ADDRESS ramdisk_start, + IN INTN ramdisk_size) +{ + EFI_STATUS ret; + EFI_PHYSICAL_ADDRESS tag_buf; + + if (images->cnt >= 14) + return EFI_OUT_OF_RESOURCES; + + /* append kernel cmdline to acrn cmdline line */ + struct mb2_module *acrn = &images->mods[0]; + UINTN cur_len = strnlen(acrn->cmdline, acrn->cmdline_buf_size); + UINTN kernel_cmdlen = strnlen((char*)cmdline_start, cmdline_size); + acrn->cmdline[cur_len] = ' '; + cur_len ++; + if (acrn->cmdline_buf_size < cur_len + kernel_cmdlen) { + error(L"acrn cmdline buffer is to small to hold kernel cmdline"); + } + memcpy_s(acrn->cmdline + cur_len, acrn->cmdline_buf_size - cur_len, + (VOID *)cmdline_start, kernel_cmdlen); + free_pages(cmdline_start, EFI_SIZE_TO_PAGES(cmdline_size)); + + ret = emalloc(4096, 4, &tag_buf, FALSE); + if (EFI_ERROR(ret)) + return ret; + + /* bzImage multiboot2 mod */ + CHAR8 *tag = "asos_bzimage"; + UINTN tag_size = strlen(tag); + images->mods[images->cnt].start = (VOID *)kernel_start; + images->mods[images->cnt].size = kernel_size; + images->mods[images->cnt].cmdline = (CHAR8 *)tag_buf; + images->mods[images->cnt].cmdline_buf_size = 2048; + memcpy_s((VOID *)tag_buf, 2048, tag, tag_size); + *((CHAR8*)tag_buf + tag_size) = '\0'; + images->cnt++; + + /* ramdisk mod */ + tag = "asos_ramdisk"; + tag_size = strlen(tag); + images->mods[images->cnt].start = (VOID *)ramdisk_start; + images->mods[images->cnt].size = ramdisk_size; + images->mods[images->cnt].cmdline = (CHAR8*)(tag_buf + 2048); + images->mods[images->cnt].cmdline_buf_size = 2048; + memcpy_s((VOID *)(tag_buf + 2048), 2048, tag, tag_size); + *((CHAR8*)tag_buf + 2048 + tag_size) = '\0'; + images->cnt++; + + return EFI_SUCCESS; +} + +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 UINT32 calc_mbi_size(struct mb2_images *images, + struct efi_memmap_info *emi, UINT32 sorted_mmap_cnt, UINT32 rsdp_len) +{ + uint32_t allmods_len = 0; + int i; + for(i = 1; i < images->cnt; i++) { + allmods_len += ALIGN_UP(sizeof(struct multiboot2_tag_module) + strnlen(images->mods[i].cmdline, images->mods[i].cmdline_buf_size) + 1, MULTIBOOT2_TAG_ALIGN); /* tailing '\0' */ + } + + return 2 * sizeof(uint32_t) \ + /* Boot command line */ + + ALIGN_UP(sizeof(struct multiboot2_tag_string) + strnlen(images->mods[0].cmdline, images->mods[0].cmdline_buf_size) + 1, MULTIBOOT2_TAG_ALIGN) \ + + /* Boot loader name */ + + ALIGN_UP(sizeof(struct multiboot2_tag_string) + BOOT_LOADER_NAME_SIZE, MULTIBOOT2_TAG_ALIGN) \ + + /* Modules */ + + allmods_len \ + + /* Memory Map */ + + ALIGN_UP((sizeof(struct multiboot2_tag_mmap) + sorted_mmap_cnt * sizeof(struct multiboot2_mmap_entry)), MULTIBOOT2_TAG_ALIGN) \ + + /* ACPI new */ + + ALIGN_UP(sizeof(struct multiboot2_tag_new_acpi) + rsdp_len, 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(emi->map_size + 0x1000, 0x1000), MULTIBOOT2_TAG_ALIGN) \ + + /* END */ + + ALIGN_UP(sizeof(struct multiboot2_tag), MULTIBOOT2_TAG_ALIGN); +} + +#define E820_UNDEFINED 0 +#define E820_RAM 1 +#define E820_RESERVED 2 +#define E820_ACPI 3 +#define E820_NVS 4 +#define E820_UNUSABLE 5 + +UINT32 efimmap_to_mb2( + struct efi_memmap_info *emi, + struct multiboot2_mmap_entry *sorted, + UINT32 len) +{ + UINT32 i, j, k, sorted_len = 0; + for (i = 0; i < emi->map_size/emi->desc_size; i++) { + uint32_t e820_type = 0; + EFI_MEMORY_DESCRIPTOR *d = (EFI_MEMORY_DESCRIPTOR *)((UINT64)emi->mmap + i * emi->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: + error(L"unknown efi mmap type"); + ;//possible ? + } + struct multiboot2_mmap_entry e; + e.addr = d->PhysicalStart; + e.len = d->NumberOfPages << EFI_PAGE_SHIFT; + e.type = e820_type; + e.zero = 0; + + for (j = 0; j < sorted_len; j++) { + if (e.addr < sorted[j].addr) { + for (k = sorted_len; k > j; k--) { + sorted[k] = sorted[k-1]; + } + sorted[j] = e; + sorted_len++; + break; + } + } + if (j == sorted_len) { + sorted[sorted_len++] = e; + } + if (sorted_len > len) { + error(L"should panic"); + break; + } + } + for (i = sorted_len - 1; i > 0; i--) { + if ((sorted[i].type == sorted[i-1].type) && (sorted[i-1].addr + sorted[i-1].len >= sorted[i].addr)) { + sorted[i-1].len += sorted[i].len; + for (j = i; j < sorted_len -1; j++) { + sorted[j] = sorted[j+1]; + } + sorted_len--; + } + } + for (i = 0; i < sorted_len; i++) { + debug(L"mmap entry: addr: 0x%lx, len: 0x%lx, type: %d", + sorted[i].addr, sorted[i].len, sorted[i].type); + } + return sorted_len; + +} +static EFI_STATUS construct_mbi2( + struct mb2_images *images, + EFI_PHYSICAL_ADDRESS *pmbi) +{ + EFI_STATUS ret; + struct RSDP_TABLE *rsdp; + VOID *mbi; + UINT32 mbi_size, mmap_cnt, sorted_mmap_cnt; + struct efi_memmap_info emi; + struct multiboot2_mmap_entry *sorted_mmap_entries; + + ret = get_acpi_rsdp((VOID **)&rsdp); + if (EFI_ERROR(ret)) { + error(L"fail to get rsdp"); + return ret; + } + + ret = get_efi_memmap(&emi, 0); + if (EFI_ERROR(ret)) { + error(L"fail to get efi memmap"); + return ret; + } + + mmap_cnt = emi.map_size / emi.desc_size; + ret = allocate_pool(EfiLoaderData, mmap_cnt * sizeof(struct multiboot2_mmap_entry), (void **)&sorted_mmap_entries); + if (EFI_ERROR(ret)) { + error(L"fail to alloc buffer for MB2 mmap"); + return ret; + } + sorted_mmap_cnt = efimmap_to_mb2(&emi, sorted_mmap_entries, mmap_cnt); + mbi_size = calc_mbi_size(images, &emi, sorted_mmap_cnt, rsdp->length); + /* This allocation is guaranteed to be 8-bytes aligned */ + ret = allocate_pool(EfiLoaderData, mbi_size, (void **) &mbi); + if (EFI_ERROR(ret)) { + error(L"fail to alloc buffer for MBI"); + return ret; + } + memset(mbi, 0, mbi_size); + + UINT64 *p = mbi; + p += (2 * sizeof(UINT32)) / sizeof(UINT64); + + /* TODO setup MBI per image's request */ + /* Boot command line */ + { + struct multiboot2_tag_string *tag = (struct multiboot2_tag_string *)p; + UINTN cmdline_size = strnlen(images->mods[0].cmdline, images->mods[0].cmdline_buf_size) + 1; + tag->type = MULTIBOOT2_TAG_TYPE_CMDLINE; + tag->size = sizeof(struct multiboot2_tag_string) + cmdline_size; + memcpy(tag->string, images->mods[0].cmdline, cmdline_size); + 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, 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 = images->cnt; + for (i = 1; i < mod_count; i++) { + struct mb2_module *mod = &images->mods[i]; + struct multiboot2_tag_module *tag = (struct multiboot2_tag_module *)p; + tag->type = MULTIBOOT2_TAG_TYPE_MODULE; + tag->size = sizeof(struct multiboot2_tag_module) + strnlen(mod->cmdline, mod->cmdline_buf_size) + 1; + tag->mod_start = (uint32_t)mod->start; + tag->mod_end = tag->mod_start + mod->size; + memcpy(tag->cmdline, mod->cmdline, strnlen(mod->cmdline, mod->cmdline_buf_size) + 1); + p += ALIGN_UP(tag->size, MULTIBOOT2_TAG_ALIGN) / sizeof(uint64_t); + } + } + + /* Memory map */ + { + struct multiboot2_tag_mmap *tag = (struct multiboot2_tag_mmap *)p; + tag->type = MULTIBOOT2_TAG_TYPE_MMAP; + tag->size = sizeof(struct multiboot2_tag_mmap) + sizeof(struct multiboot2_mmap_entry) * sorted_mmap_cnt; + tag->entry_size = sizeof(struct multiboot2_mmap_entry); + tag->entry_version = 0; + memcpy(tag->entries, sorted_mmap_entries, sorted_mmap_cnt * 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)ST; + 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) + emi.map_size; + tag->descr_size = emi.desc_size; + tag->descr_vers = emi.desc_version; + memcpy((char *)tag->efi_mmap, (char *)emi.mmap, emi.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 *)mbi)[0] = (uint64_t)((char *)p - (char *)mbi); + ((uint32_t *)mbi)[1] = 0; + + *pmbi = (EFI_PHYSICAL_ADDRESS)mbi; + + return EFI_SUCCESS; +} + +static EFI_STATUS get_mb2_entry(struct mb2_images *images, EFI_PHYSICAL_ADDRESS *entry) +{ + VOID *acrn = images->mods[0].start; + const struct multiboot2_header *mb2header = find_mb2header((uint8_t *)acrn, 4096); + struct mb2header_tag_list tags; + int ret = parse_mb2header(mb2header, &tags); + if (ret) { + error(L"fail to parse multiboot2 header of acrn image"); + return EFI_INVALID_PARAMETER; + } + struct multiboot2_header_tag_address *addr_tag = tags.addr; + struct multiboot2_header_tag_entry_address *entry_tag = tags.entry; + *entry = (EFI_PHYSICAL_ADDRESS)acrn + entry_tag->entry_addr - addr_tag->load_addr; + + return EFI_SUCCESS; +} + +static inline void hv_jump(EFI_PHYSICAL_ADDRESS hv_entry, uint32_t mbi, int32_t magic) +{ + asm volatile ( + "cli\n\t" + "jmp *%2\n\t" + : + : "a"(magic), "b"(mbi), "r"(hv_entry) + ); +} + +EFI_STATUS acrn_image_start( + IN EFI_HANDLE parent_image, + IN struct mb2_images *images) +{ + EFI_STATUS ret; + EFI_PHYSICAL_ADDRESS mbi, acrn_entry; + UINTN nr_entries, entry_sz, key; + UINT32 entry_ver; + EFI_MEMORY_DESCRIPTOR *mem_entries; + + mb2_images_dump(images); + + ret = construct_mbi2(images, &mbi); + if (EFI_ERROR(ret)) + return ret; + debug(L"constructed mbi at 0x%lx", mbi); + + debug(L"exit boot services"); + mem_entries = LibMemoryMap(&nr_entries, &key, &entry_sz, &entry_ver); + if (!mem_entries) { + error(L"fail to get memmap to exit bootservice"); + return EFI_OUT_OF_RESOURCES; + } + FreePool(mem_entries); + ret = uefi_call_wrapper(BS->ExitBootServices, 2, parent_image, key); + if (!EFI_ERROR(ret)) { + error(L"fail to exit bootservice"); + return ret; + } + + ret = get_mb2_entry(images, &acrn_entry); + if (EFI_ERROR(ret)) { + error(L"fail to get acrn entry point"); + return ret; + } + debug(L"jump to acrn entrypint at 0x%lx", acrn_entry); + hv_jump(acrn_entry, (uint32_t)mbi, MULTIBOOT2_INFO_MAGIC); + + return ret; +} + + diff --git a/libkernelflinger/android.c b/libkernelflinger/android.c index bfce0ffb..5109631c 100644 --- a/libkernelflinger/android.c +++ b/libkernelflinger/android.c @@ -560,16 +560,15 @@ static struct boot_params *get_boot_param_hdr (VOID *bootimage) return (struct boot_params *)(bootimage + hdr_size); } -static EFI_STATUS setup_ramdisk(UINT8 *bootimage, UINT8 *vendorbootimage, UINT8 *androidcmd) +static EFI_STATUS parse_ramdisk(UINT8 *bootimage, UINT8 *vendorbootimage, UINT8 *androidcmd, + EFI_PHYSICAL_ADDRESS *ramdisk_start, UINTN *ramdisk_size) { struct boot_img_hdr *aosp_header; - struct boot_params *bp; UINT32 roffset, rsize; EFI_PHYSICAL_ADDRESS ramdisk_addr; EFI_STATUS ret; aosp_header = (struct boot_img_hdr *)bootimage; - bp = get_boot_param_hdr(bootimage); if (aosp_header->header_version < BOOT_HEADER_V3) { roffset = aosp_header->page_size + pagealign(aosp_header, @@ -580,17 +579,11 @@ static EFI_STATUS setup_ramdisk(UINT8 *bootimage, UINT8 *vendorbootimage, UINT8 return EFI_SUCCESS; // no ramdisk, so nothing to do } - bp->hdr.ramdisk_len = rsize; debug(L"ramdisk size %d", rsize); ret = emalloc(rsize, 0x1000, &ramdisk_addr, FALSE); if (EFI_ERROR(ret)) return ret; - if ((UINTN)ramdisk_addr > bp->hdr.ramdisk_max) { - error(L"Ramdisk address is too high!"); - efree(ramdisk_addr, rsize); - return EFI_OUT_OF_RESOURCES; - } ret = memcpy_s((VOID *)(UINTN)ramdisk_addr, rsize, bootimage + roffset, rsize); } else if (aosp_header->header_version == BOOT_HEADER_V3) { // boot image v3 struct vendor_boot_img_hdr_v3 *vendor_hdr = (struct vendor_boot_img_hdr_v3 *)vendorbootimage; @@ -603,23 +596,16 @@ static EFI_STATUS setup_ramdisk(UINT8 *bootimage, UINT8 *vendorbootimage, UINT8 return EFI_SUCCESS; // no ramdisk, so nothing to do } - bp->hdr.ramdisk_len = rsize; ret = emalloc(rsize, 0x1000, &ramdisk_addr, FALSE); if (EFI_ERROR(ret)) return ret; - if ((UINTN)ramdisk_addr > bp->hdr.ramdisk_max) { - error(L"Ramdisk address is too high!"); - ret = EFI_OUT_OF_RESOURCES; - goto out; - } ret = memcpy_s((VOID *)(UINTN)ramdisk_addr, rsize, vendorbootimage + BOOT_IMG_HEADER_SIZE_V3, vendor_hdr->vendor_ramdisk_size); if (EFI_ERROR(ret)) goto out; - ret = memcpy_s((VOID *)(UINTN)ramdisk_addr + vendor_hdr->vendor_ramdisk_size, rsize, bootimage + roffset, boot_hdr->ramdisk_size); if (EFI_ERROR(ret)) @@ -652,17 +638,10 @@ static EFI_STATUS setup_ramdisk(UINT8 *bootimage, UINT8 *vendorbootimage, UINT8 return EFI_SUCCESS; // no ramdisk, so nothing to do } - bp->hdr.ramdisk_len = rsize; ret = emalloc(rsize, 0x1000, &ramdisk_addr, FALSE); if (EFI_ERROR(ret)) return ret; - if ((UINTN)ramdisk_addr > bp->hdr.ramdisk_max) { - error(L"Ramdisk address is too high!"); - ret = EFI_OUT_OF_RESOURCES; - goto out; - } - ret = memcpy_s((VOID *)(UINTN)ramdisk_addr, rsize, vendorbootimage + vendor_ramdisk_offset, vendor_hdr->vendor_ramdisk_size); @@ -700,7 +679,8 @@ static EFI_STATUS setup_ramdisk(UINT8 *bootimage, UINT8 *vendorbootimage, UINT8 } } - bp->hdr.ramdisk_start = (UINT32)(UINTN)ramdisk_addr; + *ramdisk_start = ramdisk_addr; + *ramdisk_size = rsize; return EFI_SUCCESS; out: @@ -708,6 +688,31 @@ static EFI_STATUS setup_ramdisk(UINT8 *bootimage, UINT8 *vendorbootimage, UINT8 return ret; } +static EFI_STATUS setup_ramdisk(UINT8 *bootimage, UINT8 *vendorbootimage, UINT8 *androidcmd) +{ + struct boot_params *bp; + EFI_STATUS ret; + EFI_PHYSICAL_ADDRESS ramdisk_start; + UINTN ramdisk_size; + + ret = parse_ramdisk(bootimage, vendorbootimage, androidcmd, + &ramdisk_start, &ramdisk_size); + if (EFI_ERROR(ret)) + return ret; + + bp = get_boot_param_hdr(bootimage); + + if (ramdisk_start > bp->hdr.ramdisk_max) { + error(L"Ramdisk address is too high!"); + efree(ramdisk_start, ramdisk_size); + return EFI_OUT_OF_RESOURCES; + } + + bp->hdr.ramdisk_len = ramdisk_size; + bp->hdr.ramdisk_start = (UINT32)ramdisk_start; + return EFI_SUCCESS; +} + EFI_STATUS setup_acpi_table(VOID *bootimage, __attribute__((__unused__)) enum boot_target target) @@ -936,7 +941,7 @@ static CHAR16 *get_command_line(IN struct boot_img_hdr *aosp_header, CHAR16 *cmdline_prepend = NULL; BOOLEAN needs_pause = FALSE; - if (boot_target == NORMAL_BOOT || boot_target == MEMORY) { + if (boot_target == NORMAL_BOOT || boot_target == ASOS || boot_target == MEMORY) { cmdline16 = get_efi_variable_str8(&loader_guid, CMDLINE_REPLACE_VAR); cmdline_append = get_efi_variable_str8(&loader_guid, CMDLINE_APPEND_VAR); cmdline_prepend = get_efi_variable_str8(&loader_guid, CMDLINE_PREPEND_VAR); @@ -1311,38 +1316,36 @@ static BOOLEAN is_same_console_type(CHAR8 *sos_console, CHAR8 *kernel_console) { return (sos_console == sos_prefix_end) && (kernel_console == kernel_prefix_end); } -/* when we call setup_command_line in EFI, parameter is EFI_GUID *swap_guid. - * when we call setup_command_line in NON EFI, parameter is const CHAR8 *abl_cmd_line. - * */ -static EFI_STATUS setup_command_line( +static EFI_STATUS parse_command_line( IN UINT8 *bootimage, IN UINT8 *vendorbootimage, IN enum boot_target boot_target, IN void *parameter, IN UINT8 boot_state, IN VBDATA *vb_data, - OUT UINT8 **androidcmd + OUT UINT8 **androidcmd, + OUT EFI_PHYSICAL_ADDRESS *cmdline_start, + OUT UINTN *cmdline_size ) { - CHAR16 *cmdline16 = NULL; - char *serialno = NULL; - CHAR16 *serialport = NULL; - CHAR16 *bootreason = NULL; - EFI_PHYSICAL_ADDRESS cmdline_addr = 0; - CHAR8 *cmdline; - CHAR8 *cmd_conf= NULL; - UINTN cmdlen; - UINTN cmdsize; - UINTN vb_cmdlen = 0; - EFI_STATUS ret; - struct boot_params *buf; - struct boot_img_hdr *aosp_header; - CHAR8 time_str8[128] = {0}; - CHAR16 *time_str16 = NULL; - EFI_GUID *swap_guid = NULL; - CHAR8 *abl_cmd_line = NULL; - BOOLEAN is_uefi = TRUE; - UINTN abl_cmd_len = 0; + CHAR16 *cmdline16 = NULL; + char *serialno = NULL; + CHAR16 *serialport = NULL; + CHAR16 *bootreason = NULL; + EFI_PHYSICAL_ADDRESS cmdline_addr = 0; + CHAR8 *cmdline; + CHAR8 *cmd_conf= NULL; + UINTN cmdlen; + UINTN cmdsize; + UINTN vb_cmdlen = 0; + EFI_STATUS ret; + struct boot_img_hdr *aosp_header; + CHAR8 time_str8[128] = {0}; + CHAR16 *time_str16 = NULL; + EFI_GUID *swap_guid = NULL; + CHAR8 *abl_cmd_line = NULL; + BOOLEAN is_uefi = TRUE; + UINTN abl_cmd_len = 0; #ifdef USE_SBL const char *cmd_for_kernel = NULL; char *tmp = NULL; @@ -1527,14 +1530,14 @@ static EFI_STATUS setup_command_line( if (EFI_ERROR(ret)) goto out; #if defined(DYNAMIC_PARTITIONS) && defined(USE_SLOT) - //BOARD_USES_RECOVERY_AS_BOOT is set to true, the recovery image is built as boot.img - //containing the recovery’s ramdisk. command line "androidboot.force_normal_boot=1" is - //mandatory for normal boot. - if(boot_target == NORMAL_BOOT) { - ret = prepend_command_line(&cmdline16, L"androidboot.force_normal_boot=1"); - if (EFI_ERROR(ret)) - goto out; - } + //BOARD_USES_RECOVERY_AS_BOOT is set to true, the recovery image is built as boot.img + //containing the recovery’s ramdisk. command line "androidboot.force_normal_boot=1" is + //mandatory for normal boot. + if(boot_target == NORMAL_BOOT || boot_target == ASOS) { + ret = prepend_command_line(&cmdline16, L"androidboot.force_normal_boot=1"); + if (EFI_ERROR(ret)) + goto out; + } #endif ret = prepend_command_line(&cmdline16, L"androidboot.acpi_idx=%a ", acpi_loaded_table_idx_to_string(BOOT_ACPI)); @@ -1710,18 +1713,18 @@ static EFI_STATUS setup_command_line( goto out; } - buf = get_boot_param_hdr(bootimage); - buf->hdr.cmd_line_ptr = (UINT32)(UINTN)cmdline; - ret = EFI_SUCCESS; + *cmdline_start = (EFI_PHYSICAL_ADDRESS)cmdline; + *cmdline_size = cmdsize; + ret = EFI_SUCCESS; out: - if (cmdline16) - FreePool(cmdline16); - if (cmd_conf) - FreePool(cmd_conf); - if (serialport) - FreePool(serialport); - if (time_str16) - FreePool(time_str16); + if (cmdline16) + FreePool(cmdline16); + if (cmd_conf) + FreePool(cmd_conf); + if (serialport) + FreePool(serialport); + if (time_str16) + FreePool(time_str16); if (EFI_ERROR(ret) && cmdline_addr) { if (is_uefi) { free_pages(cmdline_addr, EFI_SIZE_TO_PAGES(cmdsize)); @@ -1733,7 +1736,38 @@ static EFI_STATUS setup_command_line( if (f_bootreason) free_pool(f_bootreason); #endif - return ret; + + return ret; + +} + +/* when we call setup_command_line in EFI, parameter is EFI_GUID *swap_guid. + * when we call setup_command_line in NON EFI, parameter is const CHAR8 *abl_cmd_line. + * */ +static EFI_STATUS setup_command_line( + IN UINT8 *bootimage, + IN UINT8 *vendorbootimage, + IN enum boot_target boot_target, + IN void *parameter, + IN UINT8 boot_state, + IN VBDATA *vb_data, + OUT UINT8 **androidcmd) +{ + EFI_STATUS ret; + struct boot_params *buf; + EFI_PHYSICAL_ADDRESS cmdline_start; + UINTN cmdline_size; + + ret = parse_command_line(bootimage, vendorbootimage, boot_target, + parameter, boot_state, vb_data, androidcmd, + &cmdline_start, &cmdline_size); + if (EFI_ERROR(ret)) { + return ret; + } + + buf = get_boot_param_hdr(bootimage); + buf->hdr.cmd_line_ptr = (UINT32)cmdline_start; + return EFI_SUCCESS; } extern EFI_GUID GraphicsOutputProtocol; @@ -2083,23 +2117,11 @@ EFI_STATUS android_image_load_file( return ret; } - -EFI_STATUS android_image_start_buffer( - IN EFI_HANDLE parent_image, - IN VOID *bootimage, - IN VOID *vendorbootimage, - IN enum boot_target boot_target, - IN UINT8 boot_state, - IN __attribute__((unused)) EFI_GUID *swap_guid, - IN VBDATA *vb_data, - IN __attribute__((unused)) const CHAR8 *abl_cmd_line) +EFI_STATUS check_bootimage(IN VOID *bootimage, IN VOID *vendorbootimage) { struct boot_img_hdr *aosp_header; struct boot_params *buf; - void *parameter = NULL; - UINT8 *androidcmd= NULL; - EFI_STATUS ret; - BOOLEAN use_ramdisk = TRUE; + if (!bootimage) return EFI_INVALID_PARAMETER; @@ -2136,6 +2158,31 @@ EFI_STATUS android_image_start_buffer( return EFI_INVALID_PARAMETER; } + return EFI_SUCCESS; +} + +EFI_STATUS android_image_start_buffer( + IN EFI_HANDLE parent_image, + IN VOID *bootimage, + IN VOID *vendorbootimage, + IN enum boot_target boot_target, + IN UINT8 boot_state, + IN EFI_GUID *swap_guid, + IN VBDATA *vb_data, + IN const CHAR8 *abl_cmd_line) +{ + struct boot_params *buf; + void *parameter = NULL; + UINT8 *androidcmd= NULL; + EFI_STATUS ret; + BOOLEAN use_ramdisk = TRUE; + + ret = check_bootimage(bootimage, vendorbootimage); + if (EFI_ERROR(ret)) { + return ret; + } + buf = get_boot_param_hdr(bootimage); + debug(L"Creating command line"); if (is_UEFI()) parameter = (void *)swap_guid; @@ -2186,6 +2233,101 @@ EFI_STATUS android_image_start_buffer( return ret; } +EFI_STATUS load_kernel( + IN __attribute__((unused)) EFI_HANDLE parent_image, + IN VOID *bootimage, + IN VOID *vendorbootimage, + IN enum boot_target boot_target, + IN UINT8 boot_state, + IN EFI_GUID *swap_guid, + IN VBDATA *vb_data, + IN const CHAR8 *abl_cmd_line, + IN EFI_PHYSICAL_ADDRESS *kernel_start, IN UINTN *kernel_size, + IN EFI_PHYSICAL_ADDRESS *ramdisk_start, IN UINTN *ramdisk_size, + IN EFI_PHYSICAL_ADDRESS *cmdline_start, IN UINTN *cmdline_size) +{ + struct boot_img_hdr *aosp_header; + void *parameter = NULL; + UINT8 *androidcmd= NULL; + EFI_STATUS ret; + BOOLEAN use_ramdisk = TRUE; + + ret = check_bootimage(bootimage, vendorbootimage); + if (EFI_ERROR(ret)) { + return ret; + } + + debug(L"Creating command line"); + if (is_UEFI()) + parameter = (void *)swap_guid; + else + parameter = (void *)abl_cmd_line; + + ret = parse_command_line(bootimage, vendorbootimage, + boot_target, + parameter, + boot_state, + vb_data, + &androidcmd, + cmdline_start, + cmdline_size); + if (EFI_ERROR(ret)) { + efi_perror(ret, L"parse_command_line"); + if (androidcmd != NULL) + FreePool(androidcmd); + return ret; + } + debug(L"kernel cmdlen: %d", strnlen((CHAR8*)(*cmdline_start), *cmdline_size)); + + debug(L"Parsing ramdisk"); +#ifndef DYNAMIC_PARTITIONS + use_ramdisk = !recovery_in_boot_partition() || boot_target == RECOVERY || boot_target == MEMORY; +#endif + if (use_ramdisk) { + ret = parse_ramdisk(bootimage, vendorbootimage, androidcmd, ramdisk_start, ramdisk_size); + if (EFI_ERROR(ret)) { + efi_perror(ret, L"parse_ramdisk"); + if (androidcmd != NULL) + FreePool(androidcmd); + goto out_cmdline; + } + } + + if (androidcmd != NULL) + FreePool(androidcmd); + + /* acrn will not decompress it */ + debug(L"Loading kernel"); + EFI_PHYSICAL_ADDRESS buf; + VOID *kernel; + aosp_header = (struct boot_img_hdr *)bootimage; + /* need a copy? acrn will make a copy when loading */ + if (aosp_header->header_version < BOOT_HEADER_V3) + kernel = bootimage + aosp_header->page_size; + else + kernel = bootimage + BOOT_IMG_HEADER_SIZE_V3; + ret = emalloc(aosp_header->kernel_size, 2 *1024 *1024, &buf, FALSE); + if (EFI_ERROR(ret)) { + error(L"fail to allocate buffer to load bzImage"); + goto out_ramdisk; + } + memcpy((VOID *)buf, kernel, aosp_header->kernel_size); + *kernel_start = buf; + *kernel_size = aosp_header->kernel_size; + + return EFI_SUCCESS; +out_ramdisk: + efree(*ramdisk_start, *ramdisk_size); + *ramdisk_start = 0; + *ramdisk_size = 0; +out_cmdline: + free_pages(*cmdline_start, EFI_SIZE_TO_PAGES(*cmdline_size)); + *cmdline_start = 0; + *cmdline_size = 0; + return ret; + +} + #if DEBUG_MESSAGES VOID dump_bcb(IN struct bootloader_message *bcb) diff --git a/libkernelflinger/android_vb2.c b/libkernelflinger/android_vb2.c index c72c46d5..19f7e0db 100644 --- a/libkernelflinger/android_vb2.c +++ b/libkernelflinger/android_vb2.c @@ -416,6 +416,8 @@ EFI_STATUS android_image_load_partition_avb_ab( #endif #ifdef USE_ACPIO "acpio", +#endif +#ifdef USE_ACRN #endif NULL}; bool allow_verification_error = device_is_unlocked(); diff --git a/libkernelflinger/multiboot.c b/libkernelflinger/multiboot.c new file mode 100644 index 00000000..2db0c095 --- /dev/null +++ b/libkernelflinger/multiboot.c @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2021 - 2022, Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include + +#include "android.h" +#include "efilinux.h" +#include "lib.h" +#include "security.h" +#include "vars.h" +#include "power.h" +#include "targets.h" +#include "gpt.h" +#include "storage.h" +#include "text_parser.h" +#include "watchdog.h" +#ifdef HAL_AUTODETECT +#include "blobstore.h" +#endif +#include "slot.h" +#include "pae.h" +#include "timer.h" +#include "android_vb2.h" +#include "acpi.h" +#ifdef USE_FIRSTSTAGE_MOUNT +#include "firststage_mount.h" +#endif +#ifdef USE_TRUSTY +#include "trusty_common.h" +#endif + +#include "uefi_utils.h" +#include "libxbc.h" + +#include "multiboot.h" +#include "lib.h" + + +/** + * @brief Search the first len bytes in buffer for multiboot2 header. + * + * @param[in] buffer Buffer to be searched + * @param[in] len Search length + * + * @return A pointer to the multiboot2 header if found. NULL otherwise. + */ +const struct multiboot2_header *find_mb2header(const uint8_t *buffer, uint64_t len) +{ + const struct multiboot2_header *header; + + for (header = (const struct multiboot2_header *)buffer; + ((char *)header <= (char *)buffer + len - 12); + header = (struct multiboot2_header *)((uint64_t)header + MULTIBOOT2_HEADER_ALIGN / 4)) + { + if (header->magic == MULTIBOOT2_HEADER_MAGIC && + !(header->magic + header->architecture + header->header_length + header->checksum) && + header->architecture == MULTIBOOT2_ARCHITECTURE_I386) + return header; + } + + return NULL; +} + +/** + * @brief Parse the multiboot2 header and return a list of pointers to the header tags. + * + * @param[in] header Multiboot2 header to be parsed. + * @param[out] tags An mb2header_tag_list struct that contains pointers to all possible + * tags in a multiboot2 header. If a field in this struct is not NULL, it + * means the tag was found in the given header. NULL otherwise. + * + * @return 0 on success. -1 on error. + */ +int parse_mb2header(const struct multiboot2_header *header, struct mb2header_tag_list *tags) +{ + struct multiboot2_header_tag *tag; + + memset(tags, 0, sizeof(struct mb2header_tag_list)); + + for (tag = (struct multiboot2_header_tag *)(header + 1); + tag->type != MULTIBOOT2_TAG_TYPE_END; + tag = (struct multiboot2_header_tag *)((uint32_t *)tag + ALIGN_UP(tag->size, MULTIBOOT2_TAG_ALIGN) / 4)) + { + switch (tag->type) { + case MULTIBOOT2_HEADER_TAG_INFORMATION_REQUEST: + /* Ignored. Currently we didn't support all categories of requested information, + * only the part that ACRN requests. So we don't parse the requests here. */ + break; + + case MULTIBOOT2_HEADER_TAG_ADDRESS: + tags->addr = (struct multiboot2_header_tag_address *)tag; + break; + + case MULTIBOOT2_HEADER_TAG_ENTRY_ADDRESS: + tags->entry = (struct multiboot2_header_tag_entry_address *)tag; + break; + + case MULTIBOOT2_HEADER_TAG_RELOCATABLE: + tags->reloc = (struct multiboot2_header_tag_relocatable *)tag; + break; + + default: + Print(L"Unsupported multiboot2 tag type: %d\n", tag->type); + return -1; + } + } + + if (tags->addr && !tags->entry) + return -1; + + return 0; +} + +void dump_mb2_partition(struct mb2_image_header *hdr) +{ + CHAR16* cmdline16 = stra_to_str(hdr->cmdline); + debug(L"mb2 mod offset: 0x%lx", hdr->mod_offset); + debug(L"mb2 mod size: 0x%lx", hdr->mod_size); + debug(L"mb2 mod cmdline: %s", cmdline16); + FreePool(cmdline16); +} + +static bool check_mb2_image(struct mb2_image_header *hdr) +{ + return strncmp(hdr->magic, MB2_MAGIC, MB2_MAGIC_SIZE) == 0; +} + +EFI_STATUS load_mb2_images(IN struct mb2_images *images) +{ + EFI_STATUS ret; + uint8_t i; + + for (i = 0; i < images->cnt; i++) { + struct mb2_image_header *hdr = images->headers[i]; + struct mb2_module *mod = &images->mods[i]; + + CHAR16* str = stra_to_str(images->names[i]); + info(L"loading multiboot2 image/module: %s", str); + FreePool(str); + + if (!check_mb2_image(hdr)) { + return EFI_LOAD_ERROR; + } + + if (i == 0) { + EFI_PHYSICAL_ADDRESS acrn_addr; + uint8_t *buf = (uint8_t *)hdr + hdr->mod_offset; + const struct multiboot2_header *mb2_header = find_mb2header(buf, 4096); + struct mb2header_tag_list tags; + if(parse_mb2header(mb2_header, &tags)) { + error(L"fail to parse multiboot2 header"); + return EFI_LOAD_ERROR; + } + uint32_t acrn_size = tags.addr->load_end_addr - tags.addr->load_addr; + + /* copy acrn to a proper place to meet alignment requirements */ + ret = emalloc(acrn_size, 4*1024*1024, &acrn_addr, FALSE); + if (EFI_ERROR(ret)) { + error(L"fail to allocate memory for acrn image"); + return ret; + } + memset((VOID *)acrn_addr, 0, acrn_size); + memcpy((VOID *)acrn_addr, (void *)hdr + hdr->mod_offset, hdr->mod_size); + mod->start = (VOID *)acrn_addr; + mod->size = acrn_size; + mod->cmdline = hdr->cmdline; + mod->cmdline_buf_size = MB2_CMDLINE_SIZE; + } else { + /* TODO add pre launch vms */ + } + } + + return ret; +} + +