Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix e820_alloc_memory() may overlap hypervisor memory #8739

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion hypervisor/arch/x86/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,7 @@ void cpu_dead(void)
vmx_off();

stac();
flush_cache_range((void *)get_hv_image_base(), get_hv_ram_size());
flush_cache_range((void *)get_hv_image_base(), get_hv_image_size());
clac();

/* Set state to show CPU is dead */
Expand Down
70 changes: 46 additions & 24 deletions hypervisor/arch/x86/e820.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <asm/e820.h>
#include <asm/mmu.h>
#include <boot.h>
#include <reloc.h>
#include <efi_mmap.h>
#include <logmsg.h>
#include <asm/guest/ept.h>
Expand Down Expand Up @@ -232,6 +233,47 @@ static void calculate_e820_ram_size(void)
dev_dbg(DBG_LEVEL_E820, "ram size: 0x%016lx ",hv_e820_ram_size);
}

static void reserve_e820_region(uint64_t start_hpa, uint64_t end_hpa)
{
uint32_t e820_index;
uint64_t entry_start, entry_end;

for (e820_index = 0; e820_index < hv_e820_entries_nr; e820_index++) {
entry_start = hv_e820[e820_index].baseaddr;
entry_end = hv_e820[e820_index].baseaddr + hv_e820[e820_index].length;

/* No need handle in these cases*/
if ((hv_e820[e820_index].type != E820_TYPE_RAM) || (entry_end <= start_hpa) || (entry_start >= end_hpa)) {
continue;
}

if ((entry_start <= start_hpa) && (entry_end >= end_hpa)) {
hv_e820[e820_index].length = start_hpa - entry_start;

if (end_hpa < entry_end) {
/*
* .......|start_hpa......................end_hpa|.....
* |entry_start..............................entry_end|
*/
insert_e820_entry(e820_index + 1, end_hpa, entry_end - end_hpa, E820_TYPE_RAM);
}
} else {
panic("%s: region 0x%016x-0x%016x crosses multiple e820 entries, check your bootloader!",
__func__, entry_start, entry_end);
}
}
}

static void alloc_hv_memory(void)
{
uint64_t hv_start = hva2hpa((void *)(get_hv_image_base()));
uint64_t hv_end = hv_start + get_hv_image_size();

pr_err("%s: hv start: 0x%016x, end: 0x%016x", __func__, hv_start, hv_end);

reserve_e820_region(hv_start, hv_end);
}

static void alloc_mods_memory(void)
{
uint32_t mod_index, e820_index, target_index;
Expand All @@ -242,32 +284,11 @@ static void alloc_mods_memory(void)
/* 1st pass: remove the exact region */
for (mod_index = 0; mod_index < abi->mods_count; mod_index++) {
mod_start = hva2hpa(abi->mods[mod_index].start);
mod_end = hva2hpa(abi->mods[mod_index].start) + abi->mods[mod_index].size;

for (e820_index = 0; e820_index < hv_e820_entries_nr; e820_index++) {
entry_start = hv_e820[e820_index].baseaddr;
entry_end = hv_e820[e820_index].baseaddr + hv_e820[e820_index].length;
mod_end = mod_start + abi->mods[mod_index].size;

/* No need handle in these cases*/
if ((hv_e820[e820_index].type != E820_TYPE_RAM) || (entry_end <= mod_start) || (entry_start >= mod_end)) {
continue;
}

if ((entry_start <= mod_start) && (entry_end >= mod_end)) {
hv_e820[e820_index].length = mod_start - entry_start;
pr_err("%s: mod %d, start: 0x%016x, end: 0x%016x", __func__, mod_index, mod_start, mod_end);

if (mod_end < entry_end) {
/*
* .......|start_pa... ....................end_pa|.....
* |entry_start..............................entry_end|
*/
insert_e820_entry(e820_index + 1, mod_end, entry_end - mod_end, E820_TYPE_RAM);
}
} else {
panic("%s: region 0x%016x-0x%016x crosses multiple e820 entries, check your bootloader!",
__func__, entry_start, entry_end);
}
}
reserve_e820_region(mod_start, mod_end);
}

/* 2nd pass: shrink the entries to page boundary */
Expand Down Expand Up @@ -300,6 +321,7 @@ void init_e820(void)
}

calculate_e820_ram_size();
alloc_hv_memory();
/* reserve multiboot modules memory */
alloc_mods_memory();
}
Expand Down
2 changes: 1 addition & 1 deletion hypervisor/arch/x86/guest/optee.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ void prepare_tee_vm_memmap(struct acrn_vm *vm, const struct acrn_vm_config *vm_c
prepare_vm_identical_memmap(vm, E820_TYPE_RAM, EPT_WB | EPT_RWX);

hv_hpa = hva2hpa((void *)(get_hv_image_base()));
ept_del_mr(vm, (uint64_t *)vm->arch_vm.nworld_eptp, hv_hpa, get_hv_ram_size());
ept_del_mr(vm, (uint64_t *)vm->arch_vm.nworld_eptp, hv_hpa, get_hv_image_size());
}
}

Expand Down
4 changes: 0 additions & 4 deletions hypervisor/arch/x86/guest/ve820.c
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,6 @@ void create_service_vm_e820(struct acrn_vm *vm)
{
uint16_t vm_id;
uint32_t i;
uint64_t hv_start_pa = hva2hpa((void *)(get_hv_image_base()));
uint64_t hv_end_pa = hv_start_pa + get_hv_ram_size();
uint32_t entries_count = get_e820_entries_count();
struct acrn_vm_config *service_vm_config = get_vm_config(vm->vm_id);

Expand All @@ -148,8 +146,6 @@ void create_service_vm_e820(struct acrn_vm *vm)

vm->e820_entry_num = entries_count;
vm->e820_entries = service_vm_e820;
/* filter out hv memory from e820 table */
filter_mem_from_service_vm_e820(vm, hv_start_pa, hv_end_pa);

/* filter out prelaunched vm memory from e820 table */
for (vm_id = 0U; vm_id < CONFIG_MAX_VM_NUM; vm_id++) {
Expand Down
2 changes: 1 addition & 1 deletion hypervisor/arch/x86/guest/vm.c
Original file line number Diff line number Diff line change
Expand Up @@ -528,7 +528,7 @@ static void prepare_service_vm_memmap(struct acrn_vm *vm)
* will cause EPT violation if Service VM accesses hv memory
*/
hv_hpa = hva2hpa((void *)(get_hv_image_base()));
ept_del_mr(vm, pml4_page, hv_hpa, get_hv_ram_size());
ept_del_mr(vm, pml4_page, hv_hpa, get_hv_image_size());
/* unmap prelaunch VM memory */
for (vm_id = 0U; vm_id < CONFIG_MAX_VM_NUM; vm_id++) {
vm_config = get_vm_config(vm_id);
Expand Down
9 changes: 1 addition & 8 deletions hypervisor/arch/x86/mmu.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@
#include <logmsg.h>
#include <misc_cfg.h>

static uint64_t hv_ram_size;
static void *ppt_mmu_pml4_addr;
/**
* @brief The sanitized page
Expand Down Expand Up @@ -147,11 +146,6 @@ void invept(const void *eptp)
}
}

uint64_t get_hv_ram_size(void)
{
return hv_ram_size;
}

void enable_paging(void)
{
uint64_t tmp64 = 0UL;
Expand Down Expand Up @@ -265,7 +259,6 @@ void init_paging(void)
const struct abi_mmap *p_mmap = abi->mmap_entry;

pr_dbg("HV MMU Initialization");
hv_ram_size = (uint64_t)(&ld_ram_end - &ld_ram_start);

init_sanitized_page((uint64_t *)sanitized_page, hva2hpa_early(sanitized_page));

Expand Down Expand Up @@ -314,7 +307,7 @@ void init_paging(void)
*/
hv_hva = get_hv_image_base();
pgtable_modify_or_del_map((uint64_t *)ppt_mmu_pml4_addr, hv_hva & PDE_MASK,
hv_ram_size + (((hv_hva & (PDE_SIZE - 1UL)) != 0UL) ? PDE_SIZE : 0UL),
get_hv_image_size() + (((hv_hva & (PDE_SIZE - 1UL)) != 0UL) ? PDE_SIZE : 0UL),
PAGE_CACHE_WB, PAGE_CACHE_MASK | PAGE_USER, &ppt_pgtable, MR_MODIFY);

/*
Expand Down
1 change: 1 addition & 0 deletions hypervisor/boot/include/reloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
extern void relocate(void);
extern uint64_t get_hv_image_delta(void);
extern uint64_t get_hv_image_base(void);
extern uint64_t get_hv_image_size(void);

/* external symbols that are helpful for relocation */
extern uint8_t _DYNAMIC[1];
Expand Down
5 changes: 5 additions & 0 deletions hypervisor/boot/reloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ uint64_t get_hv_image_base(void)
return (get_hv_image_delta() + CONFIG_HV_RAM_START);
}

inline uint64_t get_hv_image_size(void)
{
return (uint64_t)(&ld_ram_end - &ld_ram_start);
}

void relocate(void)
{
#ifdef CONFIG_RELOC
Expand Down
2 changes: 1 addition & 1 deletion hypervisor/common/hypercall.c
Original file line number Diff line number Diff line change
Expand Up @@ -764,7 +764,7 @@ static int32_t write_protect_page(struct acrn_vm *vm,const struct wp_data *wp)
base_paddr = hva2hpa((void *)(get_hv_image_base()));
if (((hpa <= base_paddr) && ((hpa + PAGE_SIZE) > base_paddr)) ||
((hpa >= base_paddr) &&
(hpa < (base_paddr + get_hv_ram_size())))) {
(hpa < (base_paddr + get_hv_image_size())))) {
pr_err("%s: overlap the HV memory region.", __func__);
} else {
prot_set = (wp->set != 0U) ? 0UL : EPT_WR;
Expand Down
2 changes: 0 additions & 2 deletions hypervisor/include/arch/x86/asm/mmu.h
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,6 @@ void flush_vpid_global(void);
*/
void invept(const void *eptp);

uint64_t get_hv_ram_size(void);

/* get PDPT address from CR3 vaule in PAE mode */
static inline uint64_t get_pae_pdpt_addr(uint64_t cr3)
{
Expand Down