acrn-hypervisor/hypervisor/boot/guest/vboot_info.c
Geoffroy Van Cutsem 8b16be9185 Remove "All rights reserved" string headers
Many of the license and Intel copyright headers include the "All rights
reserved" string. It is not relevant in the context of the BSD-3-Clause
license that the code is released under. This patch removes those strings
throughout the code (hypervisor, devicemodel and misc).

Tracked-On: #7254
Signed-off-by: Geoffroy Van Cutsem <geoffroy.vancutsem@intel.com>
2022-04-06 13:21:02 +08:00

231 lines
6.9 KiB
C

/*
* Copyright (C) 2019 Intel Corporation.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <types.h>
#include <rtl.h>
#include <errno.h>
#include <asm/per_cpu.h>
#include <asm/irq.h>
#include <boot.h>
#include <asm/pgtable.h>
#include <asm/zeropage.h>
#include <asm/seed.h>
#include <asm/mmu.h>
#include <asm/guest/vm.h>
#include <asm/guest/ept.h>
#include <reloc.h>
#include <logmsg.h>
#include <vboot.h>
#include <vacpi.h>
#define DBG_LEVEL_BOOT 6U
/**
* @pre vm != NULL && mod != NULL
*/
static void init_vm_ramdisk_info(struct acrn_vm *vm, const struct abi_module *mod)
{
if (mod->start != NULL) {
vm->sw.ramdisk_info.src_addr = mod->start;
vm->sw.ramdisk_info.size = mod->size;
}
dev_dbg(DBG_LEVEL_BOOT, "ramdisk mod start=0x%x, size=0x%x", (uint64_t)mod->start, mod->size);
}
/**
* @pre vm != NULL && mod != NULL
*/
static void init_vm_acpi_info(struct acrn_vm *vm, const struct abi_module *mod)
{
vm->sw.acpi_info.src_addr = mod->start;
vm->sw.acpi_info.load_addr = (void *)VIRT_ACPI_DATA_ADDR;
vm->sw.acpi_info.size = ACPI_MODULE_SIZE;
}
/**
* @pre vm != NULL && mod != NULL
*/
static int32_t init_vm_kernel_info(struct acrn_vm *vm, const struct abi_module *mod)
{
int32_t ret = -EINVAL;
struct acrn_vm_config *vm_config = get_vm_config(vm->vm_id);
dev_dbg(DBG_LEVEL_BOOT, "kernel mod start=0x%x, size=0x%x",
(uint64_t)mod->start, mod->size);
vm->sw.kernel_type = vm_config->os_config.kernel_type;
if ((mod->start != NULL) && (mod->size != 0U)) {
vm->sw.kernel_info.kernel_src_addr = mod->start;
vm->sw.kernel_info.kernel_size = mod->size;
if ((vm->sw.kernel_type > 0) && (vm->sw.kernel_type < KERNEL_UNKNOWN)) {
ret = 0;
} else {
pr_err("Unsupported Kernel type.");
}
}
return ret;
}
/* cmdline parsed from abi module string, for pre-launched VMs and Service VM only. */
static char mod_cmdline[PRE_VM_NUM + SERVICE_VM_NUM][MAX_BOOTARGS_SIZE] = { 0 };
/**
* @pre vm != NULL && abi != NULL
*/
static void init_vm_bootargs_info(struct acrn_vm *vm, const struct acrn_boot_info *abi)
{
struct acrn_vm_config *vm_config = get_vm_config(vm->vm_id);
vm->sw.bootargs_info.src_addr = vm_config->os_config.bootargs;
/* If module string of the kernel module exists, it would OVERRIDE the pre-configured build-in VM bootargs,
* which means we give user a chance to re-configure VM bootargs at bootloader runtime. e.g. GRUB menu
*/
if (mod_cmdline[vm->vm_id][0] != '\0') {
vm->sw.bootargs_info.src_addr = &mod_cmdline[vm->vm_id][0];
}
if (vm_config->load_order == SERVICE_VM) {
if (strncat_s((char *)vm->sw.bootargs_info.src_addr, MAX_BOOTARGS_SIZE, " ", 1U) == 0) {
char seed_args[MAX_SEED_ARG_SIZE] = "";
fill_seed_arg(seed_args, MAX_SEED_ARG_SIZE);
/* Fill seed argument for Service VM
* seed_args string ends with a white space and '\0', so no additional delimiter is needed
*/
if (strncat_s((char *)vm->sw.bootargs_info.src_addr, MAX_BOOTARGS_SIZE,
seed_args, (MAX_BOOTARGS_SIZE - 1U)) != 0) {
pr_err("failed to fill seed arg to Service VM bootargs!");
}
/* If there is cmdline from abi->cmdline, merge it with configured Service VM bootargs.
* This is very helpful when one of configured bootargs need to be revised at GRUB runtime
* (e.g. "root="), since the later one would override the previous one if multiple bootargs exist.
*/
if (abi->cmdline[0] != '\0') {
if (strncat_s((char *)vm->sw.bootargs_info.src_addr, MAX_BOOTARGS_SIZE,
abi->cmdline, (MAX_BOOTARGS_SIZE - 1U)) != 0) {
pr_err("failed to merge mbi cmdline to Service VM bootargs!");
}
}
} else {
pr_err("no space to append Service VM bootargs!");
}
}
vm->sw.bootargs_info.size = strnlen_s((const char *)vm->sw.bootargs_info.src_addr, (MAX_BOOTARGS_SIZE - 1U)) + 1U;
}
/* @pre abi != NULL && tag != NULL
*/
struct abi_module *get_mod_by_tag(const struct acrn_boot_info *abi, const char *tag)
{
uint32_t i;
struct abi_module *mod = NULL;
struct abi_module *mods = (struct abi_module *)(&abi->mods[0]);
uint32_t tag_len = strnlen_s(tag, MAX_MOD_TAG_LEN);
for (i = 0U; i < abi->mods_count; i++) {
const char *string = (char *)hpa2hva((uint64_t)(mods + i)->string);
uint32_t str_len = strnlen_s(string, MAX_MOD_TAG_LEN);
const char *p_chr = string + tag_len; /* point to right after the end of tag */
/* The tag must be located at the first word in string and end with SPACE/TAB or EOL since
* when do file stitch by tool, the tag in string might be followed by EOL(0x0d/0x0a).
*/
if ((str_len >= tag_len) && (strncmp(string, tag, tag_len) == 0)
&& (is_space(*p_chr) || is_eol(*p_chr))) {
mod = mods + i;
break;
}
}
/* GRUB might put module at address 0 or under 1MB in the case that the module size is less then 1MB
* ACRN will not support these cases
*/
if ((mod != NULL) && (mod->start == NULL)) {
pr_err("Unsupported module: start at HPA 0, size 0x%x .", mod->size);
mod = NULL;
}
return mod;
}
/* @pre vm != NULL && abi != NULL
*/
static int32_t init_vm_sw_load(struct acrn_vm *vm, const struct acrn_boot_info *abi)
{
struct acrn_vm_config *vm_config = get_vm_config(vm->vm_id);
struct abi_module *mod;
int32_t ret = -EINVAL;
dev_dbg(DBG_LEVEL_BOOT, "mod counts=%d\n", abi->mods_count);
/* find kernel module first */
mod = get_mod_by_tag(abi, vm_config->os_config.kernel_mod_tag);
if (mod != NULL) {
const char *string = (char *)hpa2hva((uint64_t)mod->string);
uint32_t str_len = strnlen_s(string, MAX_BOOTARGS_SIZE);
uint32_t tag_len = strnlen_s(vm_config->os_config.kernel_mod_tag, MAX_MOD_TAG_LEN);
const char *p_chr = string + tag_len + 1; /* point to the possible start of cmdline */
/* check whether there is a cmdline configured in module string */
if (((str_len > (tag_len + 1U))) && (is_space(*(p_chr - 1))) && (!is_eol(*p_chr))) {
(void)strncpy_s(&mod_cmdline[vm->vm_id][0], MAX_BOOTARGS_SIZE,
p_chr, (MAX_BOOTARGS_SIZE - 1U));
}
ret = init_vm_kernel_info(vm, mod);
}
if (ret == 0) {
/* Currently VM bootargs only support Linux guest */
if (vm->sw.kernel_type == KERNEL_BZIMAGE) {
init_vm_bootargs_info(vm, abi);
}
/* check whether there is a ramdisk module */
mod = get_mod_by_tag(abi, vm_config->os_config.ramdisk_mod_tag);
if (mod != NULL) {
init_vm_ramdisk_info(vm, mod);
}
if (is_prelaunched_vm(vm)) {
mod = get_mod_by_tag(abi, vm_config->acpi_config.acpi_mod_tag);
if ((mod != NULL) && (mod->size == ACPI_MODULE_SIZE)) {
init_vm_acpi_info(vm, mod);
} else {
pr_err("failed to load VM %d acpi module", vm->vm_id);
}
}
} else {
pr_err("failed to load VM %d kernel module", vm->vm_id);
}
return ret;
}
/**
* @param[inout] vm pointer to a vm descriptor
*
* @retval 0 on success
* @retval -EINVAL on invalid parameters
*
* @pre vm != NULL
*/
int32_t init_vm_boot_info(struct acrn_vm *vm)
{
struct acrn_boot_info *abi = get_acrn_boot_info();
int32_t ret = -EINVAL;
stac();
ret = init_vm_sw_load(vm, abi);
clac();
return ret;
}