mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-07-01 09:42:10 +00:00
dm: add BIOS/ROM image loading support at High BIOS region
Generic infrastructure for loading BIOS/ROM and providing EPT pages at High BIOS region. The size of High BIOS is rounded up to a multiple of 2MB. v2 -> v3: - refine mmap_hugetlbfs* to reduce code replication v1 -> v2: - make this code generic instead of OVMF-specific Tracked-On: #1832 Signed-off-by: Peter Fang <peter.fang@intel.com> Acked-by: Anthony Xu <anthony.xu@intel.com>
This commit is contained in:
parent
653a57958b
commit
9e97fd0680
@ -36,6 +36,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "vmmapi.h"
|
||||
|
||||
@ -80,6 +81,7 @@ struct hugetlb_info {
|
||||
int fd;
|
||||
int pg_size;
|
||||
size_t lowmem;
|
||||
size_t biosmem;
|
||||
size_t highmem;
|
||||
|
||||
int pages_delta;
|
||||
@ -95,6 +97,7 @@ static struct hugetlb_info hugetlb_priv[HUGETLB_LV_MAX] = {
|
||||
.fd = -1,
|
||||
.pg_size = 0,
|
||||
.lowmem = 0,
|
||||
.biosmem = 0,
|
||||
.highmem = 0,
|
||||
|
||||
.pages_delta = 0,
|
||||
@ -108,6 +111,7 @@ static struct hugetlb_info hugetlb_priv[HUGETLB_LV_MAX] = {
|
||||
.fd = -1,
|
||||
.pg_size = 0,
|
||||
.lowmem = 0,
|
||||
.biosmem = 0,
|
||||
.highmem = 0,
|
||||
|
||||
.pages_delta = 0,
|
||||
@ -205,7 +209,8 @@ static bool should_enable_hugetlb_level(int level)
|
||||
}
|
||||
|
||||
return (hugetlb_priv[level].lowmem > 0 ||
|
||||
hugetlb_priv[level].highmem > 0);
|
||||
hugetlb_priv[level].biosmem > 0 ||
|
||||
hugetlb_priv[level].highmem > 0);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -214,7 +219,7 @@ static bool should_enable_hugetlb_level(int level)
|
||||
* offset : region start offset from ctx->baseaddr
|
||||
* skip : skip offset in different level hugetlbfs fd
|
||||
*/
|
||||
static int mmap_hugetlbfs(struct vmctx *ctx, int level, size_t len,
|
||||
static int mmap_hugetlbfs_from_level(struct vmctx *ctx, int level, size_t len,
|
||||
size_t offset, size_t skip)
|
||||
{
|
||||
char *addr;
|
||||
@ -247,59 +252,87 @@ static int mmap_hugetlbfs(struct vmctx *ctx, int level, size_t len,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mmap_hugetlbfs_lowmem(struct vmctx *ctx)
|
||||
static int mmap_hugetlbfs(struct vmctx *ctx, size_t offset,
|
||||
void (*get_param)(struct hugetlb_info *, size_t *, size_t *),
|
||||
size_t (*adj_param)(struct hugetlb_info *, struct hugetlb_info *, int))
|
||||
{
|
||||
size_t len, offset, skip;
|
||||
size_t len, skip;
|
||||
int level, ret = 0, pg_size;
|
||||
|
||||
offset = skip = 0;
|
||||
for (level = hugetlb_lv_max - 1; level >= HUGETLB_LV1; level--) {
|
||||
len = hugetlb_priv[level].lowmem;
|
||||
get_param(&hugetlb_priv[level], &len, &skip);
|
||||
pg_size = hugetlb_priv[level].pg_size;
|
||||
|
||||
while (len > 0) {
|
||||
ret = mmap_hugetlbfs(ctx, level, len, offset, skip);
|
||||
assert((offset & (pg_size - 1)) == 0);
|
||||
ret = mmap_hugetlbfs_from_level(ctx, level, len, offset, skip);
|
||||
|
||||
if (ret < 0 && level > HUGETLB_LV1) {
|
||||
len -= pg_size;
|
||||
hugetlb_priv[level].lowmem = len;
|
||||
hugetlb_priv[level-1].lowmem += pg_size;
|
||||
} else if (ret < 0 && level == HUGETLB_LV1)
|
||||
return ret;
|
||||
else {
|
||||
len = adj_param(
|
||||
&hugetlb_priv[level], &hugetlb_priv[level-1],
|
||||
pg_size);
|
||||
} else if (ret < 0 && level == HUGETLB_LV1) {
|
||||
goto done;
|
||||
} else {
|
||||
offset += len;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mmap_hugetlbfs_highmem(struct vmctx *ctx)
|
||||
static void get_lowmem_param(struct hugetlb_info *htlb,
|
||||
size_t *len, size_t *skip)
|
||||
{
|
||||
size_t len, offset, skip;
|
||||
int level, ret = 0, pg_size;
|
||||
*len = htlb->lowmem;
|
||||
*skip = 0; /* nothing to skip as lowmen is mmap'ed first */
|
||||
}
|
||||
|
||||
offset = 4 * GB;
|
||||
for (level = hugetlb_lv_max - 1; level >= HUGETLB_LV1; level--) {
|
||||
skip = hugetlb_priv[level].lowmem;
|
||||
len = hugetlb_priv[level].highmem;
|
||||
pg_size = hugetlb_priv[level].pg_size;
|
||||
while (len > 0) {
|
||||
ret = mmap_hugetlbfs(ctx, level, len, offset, skip);
|
||||
if (ret < 0 && level > HUGETLB_LV1) {
|
||||
len -= pg_size;
|
||||
hugetlb_priv[level].highmem = len;
|
||||
hugetlb_priv[level-1].highmem += pg_size;
|
||||
} else if (ret < 0 && level == HUGETLB_LV1)
|
||||
return ret;
|
||||
else {
|
||||
offset += len;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
static size_t adj_lowmem_param(struct hugetlb_info *htlb,
|
||||
struct hugetlb_info *htlb_prev, int adj_size)
|
||||
{
|
||||
assert(htlb->lowmem >= adj_size);
|
||||
htlb->lowmem -= adj_size;
|
||||
htlb_prev->lowmem += adj_size;
|
||||
|
||||
return 0;
|
||||
return htlb->lowmem;
|
||||
}
|
||||
|
||||
static void get_highmem_param(struct hugetlb_info *htlb,
|
||||
size_t *len, size_t *skip)
|
||||
{
|
||||
*len = htlb->highmem;
|
||||
*skip = htlb->lowmem;
|
||||
}
|
||||
|
||||
static size_t adj_highmem_param(struct hugetlb_info *htlb,
|
||||
struct hugetlb_info *htlb_prev, int adj_size)
|
||||
{
|
||||
assert(htlb->highmem >= adj_size);
|
||||
htlb->highmem -= adj_size;
|
||||
htlb_prev->highmem += adj_size;
|
||||
|
||||
return htlb->highmem;
|
||||
}
|
||||
|
||||
static void get_biosmem_param(struct hugetlb_info *htlb,
|
||||
size_t *len, size_t *skip)
|
||||
{
|
||||
*len = htlb->biosmem;
|
||||
*skip = htlb->lowmem + htlb->highmem;
|
||||
}
|
||||
|
||||
static size_t adj_biosmem_param(struct hugetlb_info *htlb,
|
||||
struct hugetlb_info *htlb_prev, int adj_size)
|
||||
{
|
||||
assert(htlb->biosmem >= adj_size);
|
||||
htlb->biosmem -= adj_size;
|
||||
htlb_prev->biosmem += adj_size;
|
||||
|
||||
return htlb->biosmem;
|
||||
}
|
||||
|
||||
static int create_hugetlb_dirs(int level)
|
||||
@ -410,7 +443,7 @@ static bool hugetlb_check_memgap(void)
|
||||
|
||||
for (lvl = HUGETLB_LV1; lvl < hugetlb_lv_max; lvl++) {
|
||||
free_pages = read_sys_info(hugetlb_priv[lvl].free_pages_path);
|
||||
need_pages = (hugetlb_priv[lvl].lowmem +
|
||||
need_pages = (hugetlb_priv[lvl].lowmem + hugetlb_priv[lvl].biosmem +
|
||||
hugetlb_priv[lvl].highmem) / hugetlb_priv[lvl].pg_size;
|
||||
|
||||
hugetlb_priv[lvl].pages_delta = need_pages - free_pages;
|
||||
@ -518,7 +551,7 @@ static bool hugetlb_reserve_pages(void)
|
||||
reserve_more_pages(level);
|
||||
|
||||
/* check if reserved enough pages */
|
||||
if (hugetlb_priv[level].pages_delta == 0)
|
||||
if (hugetlb_priv[level].pages_delta <= 0)
|
||||
continue;
|
||||
|
||||
/* probably system allocates fewer pages than needed
|
||||
@ -530,7 +563,7 @@ static bool hugetlb_reserve_pages(void)
|
||||
left_gap = hugetlb_priv[level].pages_delta;
|
||||
pg_size = hugetlb_priv[level].pg_size;
|
||||
hugetlb_priv[level - 1].pages_delta += (size_t)left_gap
|
||||
* pg_size / hugetlb_priv[level - 1].pg_size;
|
||||
* (pg_size / hugetlb_priv[level - 1].pg_size);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -584,9 +617,14 @@ bool check_hugetlb_support(void)
|
||||
int hugetlb_setup_memory(struct vmctx *ctx)
|
||||
{
|
||||
int level;
|
||||
size_t lowmem, highmem;
|
||||
size_t lowmem, biosmem, highmem;
|
||||
bool has_gap;
|
||||
|
||||
if (ctx->lowmem == 0) {
|
||||
perror("vm requests 0 memory");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* for first time DM start UOS, hugetlbfs is already mounted by
|
||||
* check_hugetlb_support; but for reboot, here need re-mount
|
||||
* it as it already be umount by hugetlb_unsetup_memory
|
||||
@ -604,34 +642,42 @@ int hugetlb_setup_memory(struct vmctx *ctx)
|
||||
}
|
||||
}
|
||||
|
||||
/* all memory should be at least align with
|
||||
/* all memory should be at least aligned with
|
||||
* hugetlb_priv[HUGETLB_LV1].pg_size */
|
||||
ctx->lowmem =
|
||||
ALIGN_DOWN(ctx->lowmem, hugetlb_priv[HUGETLB_LV1].pg_size);
|
||||
ctx->biosmem =
|
||||
ALIGN_DOWN(ctx->biosmem, hugetlb_priv[HUGETLB_LV1].pg_size);
|
||||
ctx->highmem =
|
||||
ALIGN_DOWN(ctx->highmem, hugetlb_priv[HUGETLB_LV1].pg_size);
|
||||
|
||||
if (ctx->highmem > 0)
|
||||
/*
|
||||
* High BIOS resides right below 4GB.
|
||||
* Therefore, at least 4GB of memory space is needed.
|
||||
*/
|
||||
if (ctx->biosmem > 0 || ctx->highmem > 0)
|
||||
total_size = 4 * GB + ctx->highmem;
|
||||
else
|
||||
total_size = ctx->lowmem;
|
||||
|
||||
if (total_size == 0) {
|
||||
perror("vm request 0 memory");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* check & set hugetlb level memory size for lowmem & highmem */
|
||||
highmem = ctx->highmem;
|
||||
/* check & set hugetlb level memory size for lowmem/biosmem/highmem */
|
||||
lowmem = ctx->lowmem;
|
||||
biosmem = ctx->biosmem;
|
||||
highmem = ctx->highmem;
|
||||
|
||||
for (level = hugetlb_lv_max - 1; level >= HUGETLB_LV1; level--) {
|
||||
hugetlb_priv[level].lowmem =
|
||||
ALIGN_DOWN(lowmem, hugetlb_priv[level].pg_size);
|
||||
hugetlb_priv[level].biosmem =
|
||||
ALIGN_DOWN(biosmem, hugetlb_priv[level].pg_size);
|
||||
hugetlb_priv[level].highmem =
|
||||
ALIGN_DOWN(highmem, hugetlb_priv[level].pg_size);
|
||||
|
||||
if (level > HUGETLB_LV1) {
|
||||
hugetlb_priv[level-1].lowmem = lowmem =
|
||||
lowmem - hugetlb_priv[level].lowmem;
|
||||
hugetlb_priv[level-1].biosmem = biosmem =
|
||||
biosmem - hugetlb_priv[level].biosmem;
|
||||
hugetlb_priv[level-1].highmem = highmem =
|
||||
highmem - hugetlb_priv[level].highmem;
|
||||
}
|
||||
@ -655,8 +701,10 @@ int hugetlb_setup_memory(struct vmctx *ctx)
|
||||
/* dump hugepage trying to setup */
|
||||
printf("\ntry to setup hugepage with:\n");
|
||||
for (level = HUGETLB_LV1; level < hugetlb_lv_max; level++) {
|
||||
printf("\tlevel %d - lowmem 0x%lx, highmem 0x%lx\n", level,
|
||||
printf("\tlevel %d - lowmem 0x%lx, biosmem 0x%lx, highmem 0x%lx\n",
|
||||
level,
|
||||
hugetlb_priv[level].lowmem,
|
||||
hugetlb_priv[level].biosmem,
|
||||
hugetlb_priv[level].highmem);
|
||||
}
|
||||
printf("total_size 0x%lx\n\n", total_size);
|
||||
@ -680,28 +728,48 @@ int hugetlb_setup_memory(struct vmctx *ctx)
|
||||
printf("mmap ptr 0x%p -> baseaddr 0x%p\n", ptr, ctx->baseaddr);
|
||||
|
||||
/* mmap lowmem */
|
||||
if (mmap_hugetlbfs_lowmem(ctx) < 0)
|
||||
if (mmap_hugetlbfs(ctx, 0, get_lowmem_param, adj_lowmem_param) < 0) {
|
||||
perror("lowmem mmap failed");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* mmap highmem */
|
||||
if (mmap_hugetlbfs_highmem(ctx) < 0)
|
||||
if (mmap_hugetlbfs(ctx, 4 * GB, get_highmem_param, adj_highmem_param) < 0) {
|
||||
perror("highmem mmap failed");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* mmap biosmem */
|
||||
if (mmap_hugetlbfs(ctx, 4 * GB - ctx->biosmem,
|
||||
get_biosmem_param, adj_biosmem_param) < 0) {
|
||||
perror("biosmem mmap failed");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* dump hugepage really setup */
|
||||
printf("\nreally setup hugepage with:\n");
|
||||
for (level = HUGETLB_LV1; level < hugetlb_lv_max; level++) {
|
||||
printf("\tlevel %d - lowmem 0x%lx, highmem 0x%lx\n", level,
|
||||
printf("\tlevel %d - lowmem 0x%lx, biosmem 0x%lx, highmem 0x%lx\n",
|
||||
level,
|
||||
hugetlb_priv[level].lowmem,
|
||||
hugetlb_priv[level].biosmem,
|
||||
hugetlb_priv[level].highmem);
|
||||
}
|
||||
printf("total_size 0x%lx\n\n", total_size);
|
||||
|
||||
/* map ept for lowmem*/
|
||||
/* map ept for lowmem */
|
||||
if (vm_map_memseg_vma(ctx, ctx->lowmem, 0,
|
||||
(uint64_t)ctx->baseaddr, PROT_ALL) < 0)
|
||||
goto err;
|
||||
|
||||
/* map ept for highmem*/
|
||||
/* map ept for biosmem */
|
||||
if (ctx->biosmem > 0) {
|
||||
if (vm_map_memseg_vma(ctx, ctx->biosmem, 4 * GB - ctx->biosmem,
|
||||
(uint64_t)(ctx->baseaddr + 4 * GB - ctx->biosmem),
|
||||
PROT_READ | PROT_EXEC) < 0)
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* map ept for highmem */
|
||||
if (ctx->highmem > 0) {
|
||||
if (vm_map_memseg_vma(ctx, ctx->highmem, 4 * GB,
|
||||
(uint64_t)(ctx->baseaddr + 4 * GB), PROT_ALL) < 0)
|
||||
|
@ -237,6 +237,14 @@ virtio_uses_msix(void)
|
||||
return virtio_msix;
|
||||
}
|
||||
|
||||
size_t
|
||||
high_bios_size(void)
|
||||
{
|
||||
size_t size = 0;
|
||||
|
||||
return roundup2(size, 2 * MB);
|
||||
}
|
||||
|
||||
static void *
|
||||
start_thread(void *param)
|
||||
{
|
||||
|
@ -292,6 +292,8 @@ vm_setup_memory(struct vmctx *ctx, size_t memsize)
|
||||
ctx->highmem = 0;
|
||||
}
|
||||
|
||||
ctx->biosmem = high_bios_size();
|
||||
|
||||
return hugetlb_setup_memory(ctx);
|
||||
}
|
||||
|
||||
|
@ -58,6 +58,7 @@ int vmexit_task_switch(struct vmctx *ctx, struct vhm_request *vhm_req,
|
||||
*/
|
||||
void *paddr_guest2host(struct vmctx *ctx, uintptr_t gaddr, size_t len);
|
||||
int virtio_uses_msix(void);
|
||||
size_t high_bios_size(void);
|
||||
void ptdev_no_reset(bool enable);
|
||||
void init_debugexit(void);
|
||||
void deinit_debugexit(void);
|
||||
|
@ -53,10 +53,11 @@ struct vmctx {
|
||||
int ioreq_client;
|
||||
uint32_t lowmem_limit;
|
||||
size_t lowmem;
|
||||
size_t biosmem;
|
||||
size_t highmem;
|
||||
char *baseaddr;
|
||||
char *name;
|
||||
uuid_t vm_uuid;
|
||||
uuid_t vm_uuid;
|
||||
|
||||
/* fields to track virtual devices */
|
||||
void *atkbdc_base;
|
||||
|
Loading…
Reference in New Issue
Block a user