Skip to content

Commit 4bdcd33

Browse files
Sainath Grandhiwenlingz
authored andcommitted
hv: Reserve space for VMs' EPT 4k pages after boot
As ACRN prepares to support servers with large amounts of memory current logic to allocate space for 4K pages of EPT at compile time will increase the size of .bss section of ACRN binary. Bootloaders could run into a situation where they cannot find enough contiguous space to load ACRN binary under 4GB, which is typically heavily fragmented with E820 types Reserved, ACPI data, 32-bit PCI hole etc. This patch does the following 1) Works only for "direct" mode of vboot 2) reserves space for 4K pages of EPT, after boot by parsing platform E820 table, for all types of VMs. Size comparison: w/o patch Size of DRAM Size of .bss 48 GB 0xe1bbc98 (~226 MB) 128 GB 0x222abc98 (~548 MB) w/ patch Size of DRAM Size of .bss 48 GB 0x1991c98 (~26 MB) 128 GB 0x1a81c98 (~28 MB) Tracked-On: #4563 Signed-off-by: Sainath Grandhi <sainath.grandhi@intel.com> Acked-by: Eddie Dong <eddie.dong@intel.com>
1 parent 963b8cb commit 4bdcd33

File tree

9 files changed

+119
-54
lines changed

9 files changed

+119
-54
lines changed

hypervisor/Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,9 @@ SYS_INIT_C_OBJS := $(patsubst %.c,$(HV_OBJDIR)/%.o,$(SYS_INIT_C_SRCS))
354354
ifneq ($(CONFIG_RELEASE),y)
355355
CFLAGS += -DHV_DEBUG -DPROFILING_ON -fno-omit-frame-pointer
356356
endif
357+
ifneq ($(FIRMWARE),uefi)
358+
CFLAGS += -DCONFIG_LAST_LEVEL_EPT_AT_BOOT
359+
endif
357360
PRE_BUILD_SRCS += pre_build/static_checks.c
358361
PRE_BUILD_OBJS := $(patsubst %.c,$(HV_OBJDIR)/%.o,$(PRE_BUILD_SRCS))
359362

hypervisor/arch/x86/cpu.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,12 @@ void init_pcpu_post(uint16_t pcpu_id)
243243
panic("failed to initialize sgx!");
244244
}
245245

246+
/*
247+
* Reserve memory from platform E820 for EPT 4K pages for all VMs
248+
*/
249+
#ifdef CONFIG_LAST_LEVEL_EPT_AT_BOOT
250+
reserve_buffer_for_ept_pages();
251+
#endif
246252
/* Start all secondary cores */
247253
startup_paddr = prepare_trampoline();
248254
if (!start_pcpus(AP_MASK)) {

hypervisor/arch/x86/e820.c

Lines changed: 55 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <mmu.h>
1212
#include <boot.h>
1313
#include <logmsg.h>
14+
#include <ept.h>
1415

1516
/*
1617
* e820.c contains the related e820 operations; like HV to get memory info for its MMU setup;
@@ -51,63 +52,75 @@ static void obtain_mem_range_info(void)
5152
}
5253
}
5354

54-
/* get some RAM below 1MB in e820 entries, hide it from sos_vm, return its start address */
55-
uint64_t e820_alloc_low_memory(uint32_t size_arg)
55+
/*
56+
* @brief reserve some RAM, hide it from sos_vm, return its start address
57+
* @param size_arg Amount of memory to be found and marked reserved
58+
* @param max_addr Maximum address below which memory is to be identified
59+
*
60+
* @pre hv_e820_entries_nr > 0U
61+
* @pre (size_arg & 0xFFFU) == 0U
62+
* @return base address of the memory region
63+
*/
64+
uint64_t e820_alloc_memory(uint32_t size_arg, uint64_t max_addr)
5665
{
57-
uint32_t i;
58-
uint32_t size = size_arg;
59-
uint64_t ret = ACRN_INVALID_HPA;
66+
int32_t i;
67+
uint64_t size = size_arg;
68+
uint64_t ret = INVALID_HPA;
6069
struct e820_entry *entry, *new_entry;
6170

62-
/* We want memory in page boundary and integral multiple of pages */
63-
size = (((size + PAGE_SIZE) - 1U) >> PAGE_SHIFT) << PAGE_SHIFT;
64-
65-
for (i = 0U; i < hv_e820_entries_nr; i++) {
71+
for (i = (int32_t)hv_e820_entries_nr - 1; i >= 0; i--) {
6672
entry = &hv_e820[i];
6773
uint64_t start, end, length;
6874

6975
start = round_page_up(entry->baseaddr);
7076
end = round_page_down(entry->baseaddr + entry->length);
71-
length = end - start;
72-
length = (end > start) ? (end - start) : 0;
73-
74-
/* Search for available low memory */
75-
if ((entry->type != E820_TYPE_RAM) || (length < size) || ((start + size) > MEM_1M)) {
76-
continue;
77-
}
77+
length = (end > start) ? (end - start) : 0UL;
78+
79+
if ((entry->type == E820_TYPE_RAM) && (length >= size) && ((start + size) <= max_addr)) {
80+
81+
82+
/* found exact size of e820 entry */
83+
if (length == size) {
84+
entry->type = E820_TYPE_RESERVED;
85+
hv_mem_range.total_mem_size -= size;
86+
ret = start;
87+
} else {
88+
89+
/*
90+
* found entry with available memory larger than requested (length > size)
91+
* Reserve memory if
92+
* 1) hv_e820_entries_nr < E820_MAX_ENTRIES
93+
* 2) if end of this "entry" is <= max_addr
94+
* use memory from end of this e820 "entry".
95+
*/
96+
97+
if ((hv_e820_entries_nr < E820_MAX_ENTRIES) && (end <= max_addr)) {
98+
99+
new_entry = &hv_e820[hv_e820_entries_nr];
100+
new_entry->type = E820_TYPE_RESERVED;
101+
new_entry->baseaddr = end - size;
102+
new_entry->length = (entry->baseaddr + entry->length) - new_entry->baseaddr;
103+
/* Shrink the existing entry and total available memory */
104+
entry->length -= new_entry->length;
105+
hv_mem_range.total_mem_size -= new_entry->length;
106+
hv_e820_entries_nr++;
107+
108+
ret = new_entry->baseaddr;
109+
}
110+
}
78111

79-
/* found exact size of e820 entry */
80-
if (length == size) {
81-
entry->type = E820_TYPE_RESERVED;
82-
hv_mem_range.total_mem_size -= size;
83-
ret = start;
84-
break;
112+
if (ret != INVALID_HPA) {
113+
break;
114+
}
85115
}
86-
87-
/*
88-
* found entry with available memory larger than requested
89-
* allocate memory from the end of this entry at page boundary
90-
*/
91-
new_entry = &hv_e820[hv_e820_entries_nr];
92-
new_entry->type = E820_TYPE_RESERVED;
93-
new_entry->baseaddr = end - size;
94-
new_entry->length = (entry->baseaddr + entry->length) - new_entry->baseaddr;
95-
96-
/* Shrink the existing entry and total available memory */
97-
entry->length -= new_entry->length;
98-
hv_mem_range.total_mem_size -= new_entry->length;
99-
hv_e820_entries_nr++;
100-
101-
ret = new_entry->baseaddr;
102-
break;
103116
}
104117

105-
if (ret == ACRN_INVALID_HPA) {
106-
pr_fatal("Can't allocate memory under 1M from E820\n");
118+
if (ret == INVALID_HPA) {
119+
panic("Requested memory from E820 cannot be reserved!!");
107120
}
121+
108122
return ret;
109123
}
110-
111124
/* HV read multiboot header to get e820 entries info and calc total RAM info */
112125
void init_e820(void)
113126
{

hypervisor/arch/x86/guest/vm.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ static void prepare_sos_vm_memmap(struct acrn_vm *vm)
322322

323323
/* unmap AP trampoline code for security
324324
* 'allocate_pages()' in depri boot mode or
325-
* 'e820_alloc_low_memory()' in direct boot
325+
* 'e820_alloc_memory()' in direct boot
326326
* mode will ensure the base address of tramploline
327327
* code be page-aligned.
328328
*/

hypervisor/arch/x86/page.c

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <vtd.h>
1313
#include <security.h>
1414
#include <vm.h>
15+
#include <vm_configurations.h>
1516

1617
static struct page ppt_pml4_pages[PML4_PAGE_NUM(CONFIG_PLATFORM_RAM_SIZE + PLATFORM_LO_MMIO_SIZE)];
1718
static struct page ppt_pdpt_pages[PDPT_PAGE_NUM(CONFIG_PLATFORM_RAM_SIZE + PLATFORM_LO_MMIO_SIZE)];
@@ -80,19 +81,15 @@ const struct memory_ops ppt_mem_ops = {
8081
static struct page sos_vm_pml4_pages[SOS_VM_NUM][PML4_PAGE_NUM(EPT_ADDRESS_SPACE(CONFIG_SOS_RAM_SIZE))];
8182
static struct page sos_vm_pdpt_pages[SOS_VM_NUM][PDPT_PAGE_NUM(EPT_ADDRESS_SPACE(CONFIG_SOS_RAM_SIZE))];
8283
static struct page sos_vm_pd_pages[SOS_VM_NUM][PD_PAGE_NUM(EPT_ADDRESS_SPACE(CONFIG_SOS_RAM_SIZE))];
83-
static struct page sos_vm_pt_pages[SOS_VM_NUM][PT_PAGE_NUM(EPT_ADDRESS_SPACE(CONFIG_SOS_RAM_SIZE))];
84-
8584
/* pre_uos_nworld_pml4_pages */
8685
static struct page pre_uos_nworld_pml4_pages[PRE_VM_NUM][PML4_PAGE_NUM(PRE_VM_EPT_ADDRESS_SPACE(CONFIG_UOS_RAM_SIZE))];
8786
static struct page pre_uos_nworld_pdpt_pages[PRE_VM_NUM][PDPT_PAGE_NUM(PRE_VM_EPT_ADDRESS_SPACE(CONFIG_UOS_RAM_SIZE))];
8887
static struct page pre_uos_nworld_pd_pages[PRE_VM_NUM][PD_PAGE_NUM(PRE_VM_EPT_ADDRESS_SPACE(CONFIG_UOS_RAM_SIZE))];
89-
static struct page pre_uos_nworld_pt_pages[PRE_VM_NUM][PT_PAGE_NUM(PRE_VM_EPT_ADDRESS_SPACE(CONFIG_UOS_RAM_SIZE))];
9088

9189
/* post_uos_nworld_pml4_pages */
9290
static struct page post_uos_nworld_pml4_pages[MAX_POST_VM_NUM][PML4_PAGE_NUM(EPT_ADDRESS_SPACE(CONFIG_UOS_RAM_SIZE))];
9391
static struct page post_uos_nworld_pdpt_pages[MAX_POST_VM_NUM][PDPT_PAGE_NUM(EPT_ADDRESS_SPACE(CONFIG_UOS_RAM_SIZE))];
9492
static struct page post_uos_nworld_pd_pages[MAX_POST_VM_NUM][PD_PAGE_NUM(EPT_ADDRESS_SPACE(CONFIG_UOS_RAM_SIZE))];
95-
static struct page post_uos_nworld_pt_pages[MAX_POST_VM_NUM][PT_PAGE_NUM(EPT_ADDRESS_SPACE(CONFIG_UOS_RAM_SIZE))];
9693

9794
static struct page post_uos_sworld_pgtable_pages[MAX_POST_VM_NUM][TRUSTY_PGTABLE_PAGE_NUM(TRUSTY_RAM_SIZE)];
9895
/* pre-assumption: TRUSTY_RAM_SIZE is 2M aligned */
@@ -101,6 +98,39 @@ static struct page post_uos_sworld_memory[MAX_POST_VM_NUM][TRUSTY_RAM_SIZE >> PA
10198
/* ept: extended page table*/
10299
static union pgtable_pages_info ept_pages_info[CONFIG_MAX_VM_NUM];
103100

101+
102+
#ifdef CONFIG_LAST_LEVEL_EPT_AT_BOOT
103+
/* Array with address space size for each type of load order of VM */
104+
static const uint64_t vm_address_space_size[MAX_LOAD_ORDER] = {
105+
PRE_VM_EPT_ADDRESS_SPACE(CONFIG_UOS_RAM_SIZE), /* for Pre-Launched VM */
106+
EPT_ADDRESS_SPACE(CONFIG_SOS_RAM_SIZE), /* for SOS VM */
107+
EPT_ADDRESS_SPACE(CONFIG_SOS_RAM_SIZE), /* for Post-Launched VM */
108+
};
109+
110+
/*
111+
* @brief Reserve space for EPT 4K pages from platform E820 table
112+
*/
113+
void reserve_buffer_for_ept_pages(void)
114+
{
115+
uint64_t pt_base;
116+
uint16_t vm_id;
117+
uint32_t offset = 0U;
118+
struct acrn_vm_config *vm_config;
119+
120+
pt_base = e820_alloc_memory(TOTAL_EPT_4K_PAGES_SIZE, ~0UL);
121+
hv_access_memory_region_update(pt_base, TOTAL_EPT_4K_PAGES_SIZE);
122+
for (vm_id = 0U; vm_id < CONFIG_MAX_VM_NUM; vm_id++) {
123+
vm_config = get_vm_config(vm_id);
124+
ept_pages_info[vm_id].ept.nworld_pt_base = (struct page *)(void *)(pt_base + offset);
125+
offset += PT_PAGE_NUM(vm_address_space_size[vm_config->load_order])*MEM_4K;
126+
}
127+
}
128+
#else
129+
static struct page sos_vm_pt_pages[SOS_VM_NUM][PT_PAGE_NUM(EPT_ADDRESS_SPACE(CONFIG_SOS_RAM_SIZE))];
130+
static struct page pre_uos_nworld_pt_pages[PRE_VM_NUM][PT_PAGE_NUM(PRE_VM_EPT_ADDRESS_SPACE(CONFIG_UOS_RAM_SIZE))];
131+
static struct page post_uos_nworld_pt_pages[MAX_POST_VM_NUM][PT_PAGE_NUM(EPT_ADDRESS_SPACE(CONFIG_UOS_RAM_SIZE))];
132+
#endif
133+
104134
void *get_reserve_sworld_memory_base(void)
105135
{
106136
return post_uos_sworld_memory;
@@ -190,13 +220,17 @@ void init_ept_mem_ops(struct memory_ops *mem_ops, uint16_t vm_id)
190220
ept_pages_info[vm_id].ept.nworld_pml4_base = sos_vm_pml4_pages[0U];
191221
ept_pages_info[vm_id].ept.nworld_pdpt_base = sos_vm_pdpt_pages[0U];
192222
ept_pages_info[vm_id].ept.nworld_pd_base = sos_vm_pd_pages[0U];
223+
#ifndef CONFIG_LAST_LEVEL_EPT_AT_BOOT
193224
ept_pages_info[vm_id].ept.nworld_pt_base = sos_vm_pt_pages[0U];
225+
#endif
194226
} else if (is_prelaunched_vm(vm)) {
195-
ept_pages_info[vm_id].ept.top_address_space = EPT_ADDRESS_SPACE(CONFIG_UOS_RAM_SIZE);
227+
ept_pages_info[vm_id].ept.top_address_space = PRE_VM_EPT_ADDRESS_SPACE(CONFIG_UOS_RAM_SIZE);
196228
ept_pages_info[vm_id].ept.nworld_pml4_base = pre_uos_nworld_pml4_pages[vm_id];
197229
ept_pages_info[vm_id].ept.nworld_pdpt_base = pre_uos_nworld_pdpt_pages[vm_id];
198230
ept_pages_info[vm_id].ept.nworld_pd_base = pre_uos_nworld_pd_pages[vm_id];
231+
#ifndef CONFIG_LAST_LEVEL_EPT_AT_BOOT
199232
ept_pages_info[vm_id].ept.nworld_pt_base = pre_uos_nworld_pt_pages[vm_id];
233+
#endif
200234
} else {
201235
uint16_t sos_vm_id = (get_sos_vm())->vm_id;
202236
uint16_t page_idx = vmid_2_rel_vmid(sos_vm_id, vm_id) - 1U;
@@ -205,7 +239,9 @@ void init_ept_mem_ops(struct memory_ops *mem_ops, uint16_t vm_id)
205239
ept_pages_info[vm_id].ept.nworld_pml4_base = post_uos_nworld_pml4_pages[page_idx];
206240
ept_pages_info[vm_id].ept.nworld_pdpt_base = post_uos_nworld_pdpt_pages[page_idx];
207241
ept_pages_info[vm_id].ept.nworld_pd_base = post_uos_nworld_pd_pages[page_idx];
242+
#ifndef CONFIG_LAST_LEVEL_EPT_AT_BOOT
208243
ept_pages_info[vm_id].ept.nworld_pt_base = post_uos_nworld_pt_pages[page_idx];
244+
#endif
209245
ept_pages_info[vm_id].ept.sworld_pgtable_base = post_uos_sworld_pgtable_pages[page_idx];
210246
ept_pages_info[vm_id].ept.sworld_memory_base = post_uos_sworld_memory[page_idx];
211247
mem_ops->get_sworld_memory_base = ept_get_sworld_memory_base;

hypervisor/boot/guest/direct_boot.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,14 @@
1111
#include <cpu.h>
1212
#include <boot.h>
1313
#include <direct_boot.h>
14+
#include <mmu.h>
1415

1516
/* AP trampoline code buffer base address. */
1617
static uint64_t ap_trampoline_buf;
1718

1819
static void init_direct_boot(void)
1920
{
20-
ap_trampoline_buf = e820_alloc_low_memory(CONFIG_LOW_RAM_SIZE);
21+
ap_trampoline_buf = e820_alloc_memory(CONFIG_LOW_RAM_SIZE, MEM_1M);
2122
}
2223

2324
/* @post: return != 0UL */

hypervisor/include/arch/x86/e820.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,7 @@ struct mem_range {
3737
/* HV read multiboot header to get e820 entries info and calc total RAM info */
3838
void init_e820(void);
3939

40-
/* get some RAM below 1MB in e820 entries, hide it from sos_vm, return its start address */
41-
uint64_t e820_alloc_low_memory(uint32_t size_arg);
42-
40+
uint64_t e820_alloc_memory(uint32_t size_arg, uint64_t max_addr);
4341
/* get total number of the e820 entries */
4442
uint32_t get_e820_entries_count(void);
4543

hypervisor/include/arch/x86/page.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@
4040

4141
#define PRE_VM_EPT_ADDRESS_SPACE(size) (PTDEV_HI_MMIO_START + PTDEV_HI_MMIO_SIZE)
4242

43+
#define TOTAL_EPT_4K_PAGES_SIZE (PRE_VM_NUM*(PT_PAGE_NUM(PRE_VM_EPT_ADDRESS_SPACE(CONFIG_UOS_RAM_SIZE))*MEM_4K)) + \
44+
(SOS_VM_NUM*(PT_PAGE_NUM(EPT_ADDRESS_SPACE(CONFIG_SOS_RAM_SIZE))*MEM_4K)) + \
45+
(MAX_POST_VM_NUM*(PT_PAGE_NUM(EPT_ADDRESS_SPACE(CONFIG_UOS_RAM_SIZE))*MEM_4K))
46+
4347
#define TRUSTY_PML4_PAGE_NUM(size) (1UL)
4448
#define TRUSTY_PDPT_PAGE_NUM(size) (1UL)
4549
#define TRUSTY_PD_PAGE_NUM(size) (PD_PAGE_NUM(size))
@@ -90,4 +94,7 @@ extern const struct memory_ops ppt_mem_ops;
9094
void init_ept_mem_ops(struct memory_ops *mem_ops, uint16_t vm_id);
9195
void *get_reserve_sworld_memory_base(void);
9296

97+
#ifdef CONFIG_LAST_LEVEL_EPT_AT_BOOT
98+
void reserve_buffer_for_ept_pages(void);
99+
#endif
93100
#endif /* PAGE_H */

hypervisor/include/arch/x86/vm_config.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,10 @@
3838
* POST_LAUNCHED_VM is launched by ACRN devicemodel, with/without LAPIC_PT depends on usecases.
3939
*/
4040
enum acrn_vm_load_order {
41-
PRE_LAUNCHED_VM = 1,
41+
PRE_LAUNCHED_VM = 0,
4242
SOS_VM,
43-
POST_LAUNCHED_VM /* Launched by Devicemodel in SOS_VM */
43+
POST_LAUNCHED_VM, /* Launched by Devicemodel in SOS_VM */
44+
MAX_LOAD_ORDER
4445
};
4546

4647
/* ACRN guest severity */

0 commit comments

Comments
 (0)