HV: use tag to specify multiboot module

Previously multiboot mods[0] is designed for kernel module for all
pre-launched VMs including SOS VM, and mods[0].mm_string is used
to store kernel cmdline. This design could not satisfy the requirement
of hybrid mode scenarios that each VM might use their own kernel image
also ramdisk image. To resolve this problem, we will use a tag in
mods mm_string field to specify the module type. If the tag could
be matched with os_config of VM configurations, the corresponding
module would be loaded;

Tracked-On: #3214

Signed-off-by: Victor Sun <victor.sun@intel.com>
Reviewed-by: Jason Chen CJ <jason.cj.chen@intel.com>
This commit is contained in:
Victor Sun 2019-06-03 00:05:09 +08:00 committed by wenlingz
parent d0fa83b2cb
commit ea7ca8595c
7 changed files with 143 additions and 124 deletions

View File

@ -453,7 +453,7 @@ int32_t create_vm(uint16_t vm_id, struct acrn_vm_config *vm_config, struct acrn_
if (vm_config->load_order == PRE_LAUNCHED_VM) { if (vm_config->load_order == PRE_LAUNCHED_VM) {
create_prelaunched_vm_e820(vm); create_prelaunched_vm_e820(vm);
prepare_prelaunched_vm_memmap(vm, vm_config); prepare_prelaunched_vm_memmap(vm, vm_config);
(void)init_vm_boot_info(vm); status = init_vm_boot_info(vm);
} }
} }

View File

@ -23,6 +23,21 @@
#define ACRN_DBG_BOOT 6U #define ACRN_DBG_BOOT 6U
#define MAX_BOOT_PARAMS_LEN 64U #define MAX_BOOT_PARAMS_LEN 64U
#define INVALID_MOD_IDX 0xFFFFU
/**
* @pre vm != NULL && mbi != NULL
*/
static void init_vm_ramdisk_info(struct acrn_vm *vm, struct multiboot_module *mod)
{
void *mod_addr = hpa2hva((uint64_t)mod->mm_mod_start);
uint32_t mod_size = mod->mm_mod_end - mod->mm_mod_start;
vm->sw.ramdisk_info.src_addr = mod_addr;
vm->sw.ramdisk_info.load_addr = vm->sw.kernel_info.kernel_load_addr + vm->sw.kernel_info.kernel_size;
vm->sw.ramdisk_info.load_addr = (void *)round_page_up((uint64_t)vm->sw.ramdisk_info.load_addr);
vm->sw.ramdisk_info.size = mod_size;
}
/* There are two sources for sos_vm kernel cmdline: /* There are two sources for sos_vm kernel cmdline:
* - cmdline from direct boot mbi->cmdline * - cmdline from direct boot mbi->cmdline
@ -31,68 +46,6 @@
*/ */
static char kernel_cmdline[MAX_BOOTARGS_SIZE + 1U]; static char kernel_cmdline[MAX_BOOTARGS_SIZE + 1U];
/* now modules support: FIRMWARE & RAMDISK & SeedList */
static void parse_other_modules(struct acrn_vm *vm, const struct multiboot_module *mods, uint32_t mods_count)
{
uint32_t i;
for (i = 0U; i < mods_count; i++) {
uint32_t type_len;
const char *start = (char *)hpa2hva((uint64_t)mods[i].mm_string);
const char *end;
void *mod_addr = hpa2hva((uint64_t)mods[i].mm_mod_start);
uint32_t mod_size = mods[i].mm_mod_end - mods[i].mm_mod_start;
dev_dbg(ACRN_DBG_BOOT, "other mod-%d start=0x%x, end=0x%x",
i, mods[i].mm_mod_start, mods[i].mm_mod_end);
dev_dbg(ACRN_DBG_BOOT, "cmd addr=0x%x, str=%s",
mods[i].mm_string, start);
while (*start == ' ') {
start++;
}
end = start;
while (((*end) != ' ') && ((*end) != '\0')) {
end++;
}
type_len = end - start;
if (strncmp("FIRMWARE", start, type_len) == 0) {
char dyn_bootargs[100] = {'\0'};
void *load_addr = gpa2hva(vm, (uint64_t)vm->sw.bootargs_info.load_addr);
uint32_t args_size = vm->sw.bootargs_info.size;
static int32_t copy_once = 1;
start = end + 1; /*it is fw name for boot args */
snprintf(dyn_bootargs, 100U, " %s=0x%x@0x%x ", start, mod_size, mod_addr);
dev_dbg(ACRN_DBG_BOOT, "fw-%d: %s", i, dyn_bootargs);
/*copy boot args to load addr, set src=load addr*/
if (copy_once != 0) {
copy_once = 0;
(void)strncpy_s(load_addr, MAX_BOOTARGS_SIZE + 1U,
(const char *)vm->sw.bootargs_info.src_addr,
vm->sw.bootargs_info.size);
vm->sw.bootargs_info.src_addr = load_addr;
}
(void)strncpy_s(load_addr + args_size, 100U, dyn_bootargs, 100U);
vm->sw.bootargs_info.size = strnlen_s(load_addr, MAX_BOOTARGS_SIZE);
} else if (strncmp("RAMDISK", start, type_len) == 0) {
vm->sw.ramdisk_info.src_addr = mod_addr;
vm->sw.ramdisk_info.load_addr = vm->sw.kernel_info.kernel_load_addr +
vm->sw.kernel_info.kernel_size;
vm->sw.ramdisk_info.load_addr =
(void *)round_page_up((uint64_t)vm->sw.ramdisk_info.load_addr);
vm->sw.ramdisk_info.size = mod_size;
} else {
pr_warn("not support mod, cmd: %s", start);
}
}
}
/** /**
* @pre vm != NULL && cmdline != NULL && cmdstr != NULL * @pre vm != NULL && cmdline != NULL && cmdstr != NULL
*/ */
@ -167,11 +120,117 @@ static void *get_kernel_load_addr(struct acrn_vm *vm)
return load_addr; return load_addr;
} }
/**
* @pre vm != NULL && mbi != NULL
*/
static int32_t init_vm_kernel_info(struct acrn_vm *vm, struct multiboot_module *mod)
{
struct acrn_vm_config *vm_config = get_vm_config(vm->vm_id);
dev_dbg(ACRN_DBG_BOOT, "kernel mod start=0x%x, end=0x%x",
mod->mm_mod_start, mod->mm_mod_end);
vm->sw.kernel_type = vm_config->os_config.kernel_type;
vm->sw.kernel_info.kernel_src_addr = hpa2hva((uint64_t)mod->mm_mod_start);
vm->sw.kernel_info.kernel_size = mod->mm_mod_end - mod->mm_mod_start;
vm->sw.kernel_info.kernel_load_addr = get_kernel_load_addr(vm);
return (vm->sw.kernel_info.kernel_load_addr == NULL) ? (-EINVAL) : 0;
}
/**
* @pre vm != NULL && mbi != NULL
*/
static void init_vm_bootargs_info(struct acrn_vm *vm, struct multiboot_info *mbi)
{
struct acrn_vm_config *vm_config = get_vm_config(vm->vm_id);
char *bootargs = vm_config->os_config.bootargs;
if (vm_config->load_order == PRE_LAUNCHED_VM) {
vm->sw.bootargs_info.src_addr = bootargs;
vm->sw.bootargs_info.size = strnlen_s(bootargs, MAX_BOOTARGS_SIZE);
} else {
/* vm_config->load_order == SOS_VM */
if ((mbi->mi_flags & MULTIBOOT_INFO_HAS_CMDLINE) != 0U) {
/*
* If there is cmdline from mbi->mi_cmdline, merge it with
* vm_config->os_config.bootargs
*/
merge_cmdline(vm, hpa2hva((uint64_t)mbi->mi_cmdline), bootargs);
vm->sw.bootargs_info.src_addr = kernel_cmdline;
vm->sw.bootargs_info.size = strnlen_s(kernel_cmdline, MAX_BOOTARGS_SIZE);
} else {
vm->sw.bootargs_info.src_addr = bootargs;
vm->sw.bootargs_info.size = strnlen_s(bootargs, MAX_BOOTARGS_SIZE);
}
}
/* Kernel bootarg and zero page are right before the kernel image */
if (vm->sw.bootargs_info.size > 0) {
vm->sw.bootargs_info.load_addr = vm->sw.kernel_info.kernel_load_addr - (MEM_1K * 8U);
} else {
vm->sw.bootargs_info.load_addr = NULL;
}
}
static uint32_t get_mod_idx_by_tag(struct multiboot_module *mods, uint32_t mods_count, const char *tag)
{
uint32_t i, ret = INVALID_MOD_IDX;
uint32_t tag_len = strnlen_s(tag, MAX_MOD_TAG_LEN);
for (i = 0; i < mods_count; i++) {
const char *mm_string = (char *)hpa2hva((uint64_t)mods[i].mm_string);
uint32_t mm_str_len = strnlen_s(mm_string, MAX_MOD_TAG_LEN);
/* when do file stitch by tool, the tag in mm_string might be followed with 0x0d or 0x0a */
if ((mm_str_len >= tag_len) && (strncmp(mm_string, tag, tag_len) == 0)
&& ((mm_string[tag_len] == 0x0d)
|| (mm_string[tag_len] == 0x0a)
|| (mm_string[tag_len] == 0))){
ret = i;
break;
}
}
return ret;
}
/* @pre vm != NULL && mbi != NULL
*/
static int32_t init_vm_sw_load(struct acrn_vm *vm, struct multiboot_info *mbi)
{
struct acrn_vm_config *vm_config = get_vm_config(vm->vm_id);
struct multiboot_module *mods = (struct multiboot_module *)hpa2hva((uint64_t)mbi->mi_mods_addr);
uint32_t mod_idx;
int32_t ret = -EINVAL;
dev_dbg(ACRN_DBG_BOOT, "mod counts=%d\n", mbi->mi_mods_count);
mod_idx = get_mod_idx_by_tag(mods, mbi->mi_mods_count, vm_config->os_config.kernel_mod_tag);
if (mod_idx != INVALID_MOD_IDX) {
ret = init_vm_kernel_info(vm, &mods[mod_idx]);
}
if (ret == 0) {
init_vm_bootargs_info(vm, mbi);
/* check whether there is a ramdisk module */
mod_idx = get_mod_idx_by_tag(mods, mbi->mi_mods_count, vm_config->os_config.ramdisk_mod_tag);
if (mod_idx != INVALID_MOD_IDX) {
init_vm_ramdisk_info(vm, &mods[mod_idx]);
/* TODO: prepare other modules like firmware, seedlist */
}
} else {
pr_err("failed to load VM %d kernel module", vm->vm_id);
}
return ret;
}
/**
* @pre vm != NULL
*/
static int32_t init_general_vm_boot_info(struct acrn_vm *vm) static int32_t init_general_vm_boot_info(struct acrn_vm *vm)
{ {
struct multiboot_module *mods = NULL;
struct multiboot_info *mbi = NULL; struct multiboot_info *mbi = NULL;
struct acrn_vm_config *vm_config = get_vm_config(vm->vm_id);
int32_t ret = -EINVAL; int32_t ret = -EINVAL;
if (boot_regs[0] != MULTIBOOT_INFO_MAGIC) { if (boot_regs[0] != MULTIBOOT_INFO_MAGIC) {
@ -183,59 +242,11 @@ static int32_t init_general_vm_boot_info(struct acrn_vm *vm)
stac(); stac();
dev_dbg(ACRN_DBG_BOOT, "Multiboot detected, flag=0x%x", mbi->mi_flags); dev_dbg(ACRN_DBG_BOOT, "Multiboot detected, flag=0x%x", mbi->mi_flags);
if ((mbi->mi_flags & MULTIBOOT_INFO_HAS_MODS) == 0U) { if ((mbi->mi_flags & MULTIBOOT_INFO_HAS_MODS) == 0U) {
panic("no sos kernel info found"); panic("no multiboot module info found");
clac();
} else { } else {
ret = init_vm_sw_load(vm, mbi);
dev_dbg(ACRN_DBG_BOOT, "mod counts=%d\n", mbi->mi_mods_count);
/* mod[0] is for kernel, other mod for ramdisk/firmware info*/
mods = (struct multiboot_module *)hpa2hva((uint64_t)mbi->mi_mods_addr);
dev_dbg(ACRN_DBG_BOOT, "mod0 start=0x%x, end=0x%x",
mods[0].mm_mod_start, mods[0].mm_mod_end);
vm->sw.kernel_type = vm_config->os_config.kernel_type;
vm->sw.kernel_info.kernel_src_addr = hpa2hva((uint64_t)mods[0].mm_mod_start);
vm->sw.kernel_info.kernel_size = mods[0].mm_mod_end - mods[0].mm_mod_start;
vm->sw.kernel_info.kernel_load_addr = get_kernel_load_addr(vm);
if (vm_config->load_order == PRE_LAUNCHED_VM) {
vm->sw.bootargs_info.src_addr = (void *)vm_config->os_config.bootargs;
vm->sw.bootargs_info.size =
strnlen_s(vm_config->os_config.bootargs, MAX_BOOTARGS_SIZE);
} else {
if ((mbi->mi_flags & MULTIBOOT_INFO_HAS_CMDLINE) != 0U) {
/*
* If there is cmdline from mbi->mi_cmdline, merge it with
* vm_config->os_config.bootargs
*/
merge_cmdline(vm, hpa2hva((uint64_t)mbi->mi_cmdline),
vm_config->os_config.bootargs);
vm->sw.bootargs_info.src_addr = kernel_cmdline;
vm->sw.bootargs_info.size =
strnlen_s(kernel_cmdline, MAX_BOOTARGS_SIZE);
} else {
vm->sw.bootargs_info.src_addr = vm_config->os_config.bootargs;
vm->sw.bootargs_info.size =
strnlen_s(vm_config->os_config.bootargs, MAX_BOOTARGS_SIZE);
}
}
/* Kernel bootarg and zero page are right before the kernel image */
vm->sw.bootargs_info.load_addr =
vm->sw.kernel_info.kernel_load_addr - (MEM_1K * 8U);
if (mbi->mi_mods_count > 1U) {
/*parse other modules, like firmware /ramdisk */
parse_other_modules(vm, mods + 1, mbi->mi_mods_count - 1);
} }
clac(); clac();
if (vm->sw.kernel_info.kernel_load_addr != NULL) {
ret = 0;
}
}
} }
} }
return ret; return ret;

View File

@ -127,16 +127,11 @@ static void prepare_loading_bzimage(struct acrn_vm *vm, struct acrn_vcpu *vcpu)
vcpu_set_gpreg(vcpu, i, 0UL); vcpu_set_gpreg(vcpu, i, 0UL);
} }
/* Copy Guest OS bootargs to its load location */
(void)copy_to_gpa(vm, bootargs_info->src_addr,
(uint64_t)bootargs_info->load_addr,
(strnlen_s((char *)bootargs_info->src_addr, MAX_BOOTARGS_SIZE) + 1U));
/* add "hugepagesz=1G hugepages=x" to cmdline for 1G hugepage /* add "hugepagesz=1G hugepages=x" to cmdline for 1G hugepage
* reserving. Current strategy is "total_mem_size in Giga - * reserving. Current strategy is "total_mem_size in Giga -
* remained 1G pages" for reserving. * remained 1G pages" for reserving.
*/ */
if (is_sos_vm(vm)) { if (is_sos_vm(vm) && (bootargs_info->load_addr != NULL)) {
int64_t reserving_1g_pages; int64_t reserving_1g_pages;
reserving_1g_pages = (vm_config->memory.size >> 30U) - NUM_REMAIN_1G_PAGES; reserving_1g_pages = (vm_config->memory.size >> 30U) - NUM_REMAIN_1G_PAGES;
@ -159,6 +154,7 @@ int32_t direct_boot_sw_loader(struct acrn_vm *vm)
{ {
int32_t ret = 0; int32_t ret = 0;
struct sw_kernel_info *sw_kernel = &(vm->sw.kernel_info); struct sw_kernel_info *sw_kernel = &(vm->sw.kernel_info);
struct sw_module_info *bootargs_info = &(vm->sw.bootargs_info);
struct sw_module_info *ramdisk_info = &(vm->sw.ramdisk_info); struct sw_module_info *ramdisk_info = &(vm->sw.ramdisk_info);
/* get primary vcpu */ /* get primary vcpu */
struct acrn_vcpu *vcpu = vcpu_from_vid(vm, BOOT_CPU_ID); struct acrn_vcpu *vcpu = vcpu_from_vid(vm, BOOT_CPU_ID);
@ -173,13 +169,18 @@ int32_t direct_boot_sw_loader(struct acrn_vm *vm)
(uint64_t)sw_kernel->kernel_load_addr, sw_kernel->kernel_size); (uint64_t)sw_kernel->kernel_load_addr, sw_kernel->kernel_size);
/* Check if a RAM disk is present */ /* Check if a RAM disk is present */
if (ramdisk_info->src_addr != NULL) { if (ramdisk_info->size != 0U) {
/* Copy RAM disk to its load location */ /* Copy RAM disk to its load location */
(void)copy_to_gpa(vm, ramdisk_info->src_addr, (void)copy_to_gpa(vm, ramdisk_info->src_addr,
(uint64_t)ramdisk_info->load_addr, (uint64_t)ramdisk_info->load_addr,
ramdisk_info->size); ramdisk_info->size);
} }
/* Copy Guest OS bootargs to its load location */
if (bootargs_info->size != 0U) {
(void)copy_to_gpa(vm, bootargs_info->src_addr,
(uint64_t)bootargs_info->load_addr,
(strnlen_s((char *)bootargs_info->src_addr, MAX_BOOTARGS_SIZE) + 1U));
}
switch (vm->sw.kernel_type) { switch (vm->sw.kernel_type) {
case KERNEL_BZIMAGE: case KERNEL_BZIMAGE:
prepare_loading_bzimage(vm, vcpu); prepare_loading_bzimage(vm, vcpu);

View File

@ -18,6 +18,7 @@
#define PLUG_CPU(n) (1U << (n)) #define PLUG_CPU(n) (1U << (n))
#define MAX_VUART_NUM_PER_VM 2U #define MAX_VUART_NUM_PER_VM 2U
#define MAX_VM_OS_NAME_LEN 32U #define MAX_VM_OS_NAME_LEN 32U
#define MAX_MOD_TAG_LEN 32U
/* /*
* PRE_LAUNCHED_VM is launched by ACRN hypervisor, with LAPIC_PT; * PRE_LAUNCHED_VM is launched by ACRN hypervisor, with LAPIC_PT;
@ -68,6 +69,8 @@ enum os_kernel_type {
struct acrn_vm_os_config { struct acrn_vm_os_config {
char name[MAX_VM_OS_NAME_LEN]; /* OS name, useful for debug */ char name[MAX_VM_OS_NAME_LEN]; /* OS name, useful for debug */
enum os_kernel_type kernel_type; /* used for kernel specifc loading method */ enum os_kernel_type kernel_type; /* used for kernel specifc loading method */
char kernel_mod_tag[MAX_MOD_TAG_LEN]; /* multiboot module tag for kernel */
char ramdisk_mod_tag[MAX_MOD_TAG_LEN]; /* multiboot module tag for ramdisk */
char bootargs[MAX_BOOTARGS_SIZE]; /* boot args/cmdline */ char bootargs[MAX_BOOTARGS_SIZE]; /* boot args/cmdline */
} __aligned(8); } __aligned(8);

View File

@ -23,6 +23,7 @@ struct acrn_vm_config vm_configs[CONFIG_MAX_VM_NUM] = {
.os_config = { .os_config = {
.name = "ACRN Service OS", .name = "ACRN Service OS",
.kernel_type = KERNEL_BZIMAGE, .kernel_type = KERNEL_BZIMAGE,
.kernel_mod_tag = "Linux_bzImage",
.bootargs = SOS_VM_BOOTARGS .bootargs = SOS_VM_BOOTARGS
}, },
.vuart[0] = { .vuart[0] = {

View File

@ -27,6 +27,7 @@ struct acrn_vm_config vm_configs[CONFIG_MAX_VM_NUM] = {
.os_config = { .os_config = {
.name = "ClearLinux", .name = "ClearLinux",
.kernel_type = KERNEL_BZIMAGE, .kernel_type = KERNEL_BZIMAGE,
.kernel_mod_tag = "Linux_bzImage",
.bootargs = VM0_CONFIG_OS_BOOTARG_CONSOLE \ .bootargs = VM0_CONFIG_OS_BOOTARG_CONSOLE \
VM0_CONFIG_OS_BOOTARG_MAXCPUS \ VM0_CONFIG_OS_BOOTARG_MAXCPUS \
VM0_CONFIG_OS_BOOTARG_ROOT \ VM0_CONFIG_OS_BOOTARG_ROOT \
@ -66,6 +67,7 @@ struct acrn_vm_config vm_configs[CONFIG_MAX_VM_NUM] = {
.os_config = { .os_config = {
.name = "ClearLinux", .name = "ClearLinux",
.kernel_type = KERNEL_BZIMAGE, .kernel_type = KERNEL_BZIMAGE,
.kernel_mod_tag = "Linux_bzImage",
.bootargs = VM1_CONFIG_OS_BOOTARG_CONSOLE \ .bootargs = VM1_CONFIG_OS_BOOTARG_CONSOLE \
VM1_CONFIG_OS_BOOTARG_MAXCPUS \ VM1_CONFIG_OS_BOOTARG_MAXCPUS \
VM1_CONFIG_OS_BOOTARG_ROOT \ VM1_CONFIG_OS_BOOTARG_ROOT \

View File

@ -25,6 +25,7 @@ struct acrn_vm_config vm_configs[CONFIG_MAX_VM_NUM] = {
.os_config = { .os_config = {
.name = "ACRN Service OS", .name = "ACRN Service OS",
.kernel_type = KERNEL_BZIMAGE, .kernel_type = KERNEL_BZIMAGE,
.kernel_mod_tag = "Linux_bzImage",
.bootargs = SOS_VM_BOOTARGS, .bootargs = SOS_VM_BOOTARGS,
}, },
.vuart[0] = { .vuart[0] = {