Skip to content

Commit f8f9ee1

Browse files
committed
feat: support memory over 4GiB
This commits adds support for allocating memory over 4GiB to the VM. It creates a new memory region after the APIC and MSI interrupt region. Signed-off-by: Nils Ponsard <nilsponsard@gmail.com>
1 parent 9e708c5 commit f8f9ee1

File tree

2 files changed

+61
-12
lines changed

2 files changed

+61
-12
lines changed

src/vmm/src/kernel.rs

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ fn add_e820_entry(
7575
pub fn build_bootparams(
7676
guest_memory: &GuestMemoryMmap,
7777
himem_start: GuestAddress,
78+
reserved_memory_start: GuestAddress,
79+
reserved_memory_end: GuestAddress,
7880
) -> std::result::Result<boot_params, Error> {
7981
let mut params = boot_params::default();
8082

@@ -88,14 +90,35 @@ pub fn build_bootparams(
8890

8991
// Add entries for the usable RAM regions.
9092
let last_addr = guest_memory.last_addr();
91-
add_e820_entry(
92-
&mut params,
93-
himem_start.raw_value() as u64,
94-
last_addr
95-
.checked_offset_from(himem_start)
96-
.ok_or(Error::HimemStartPastMemEnd)?,
97-
E820_RAM,
98-
)?;
93+
94+
if reserved_memory_start > last_addr {
95+
add_e820_entry(
96+
&mut params,
97+
himem_start.raw_value() as u64,
98+
last_addr
99+
.checked_offset_from(himem_start)
100+
.ok_or(Error::HimemStartPastMemEnd)?,
101+
E820_RAM,
102+
)?;
103+
} else {
104+
add_e820_entry(
105+
&mut params,
106+
himem_start.raw_value() as u64,
107+
reserved_memory_start
108+
.checked_offset_from(himem_start)
109+
.ok_or(Error::HimemStartPastMemEnd)?,
110+
E820_RAM,
111+
)?;
112+
113+
add_e820_entry(
114+
&mut params,
115+
reserved_memory_end.raw_value() as u64,
116+
last_addr
117+
.checked_offset_from(reserved_memory_end)
118+
.ok_or(Error::HimemStartPastMemEnd)?,
119+
E820_RAM,
120+
)?;
121+
}
99122

100123
Ok(params)
101124
}
@@ -109,6 +132,8 @@ pub fn build_bootparams(
109132
pub fn kernel_setup(
110133
guest_memory: &GuestMemoryMmap,
111134
kernel_path: PathBuf,
135+
reserved_memory_start: GuestAddress,
136+
reserved_memory_end: GuestAddress,
112137
) -> Result<KernelLoaderResult> {
113138
let mut kernel_image = File::open(kernel_path).map_err(Error::IO)?;
114139
let zero_page_addr = GuestAddress(ZEROPG_START);
@@ -123,7 +148,12 @@ pub fn kernel_setup(
123148
.map_err(Error::KernelLoad)?;
124149

125150
// Generate boot parameters.
126-
let mut bootparams = build_bootparams(guest_memory, GuestAddress(HIMEM_START))?;
151+
let mut bootparams = build_bootparams(
152+
guest_memory,
153+
GuestAddress(HIMEM_START),
154+
reserved_memory_start,
155+
reserved_memory_end,
156+
)?;
127157

128158
// Add the kernel command line to the boot parameters.
129159
bootparams.hdr.cmd_line_ptr = CMDLINE_START as u32;

src/vmm/src/lib.rs

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ mod epoll_context;
3030
use epoll_context::{EpollContext, EPOLL_EVENTS_LEN};
3131
mod kernel;
3232

33+
/// avoid the memory space where the APIC and MSI interrupts are located
34+
const HIGH_RESERVED_MEMORY_END: usize = 1 << 32;
35+
const HIGH_RESERVED_MEMORY_SIZE: usize = 0x1400000;
36+
const HIGH_RESERVED_MEMORY_START: usize = HIGH_RESERVED_MEMORY_END - HIGH_RESERVED_MEMORY_SIZE;
37+
3338
#[derive(Debug)]
3439

3540
/// VMM errors.
@@ -112,8 +117,17 @@ impl VMM {
112117
// Convert memory size from MBytes to bytes.
113118
let mem_size = ((mem_size_mb as u64) << 20) as usize;
114119

115-
// Create one single memory region, from zero to mem_size.
116-
let mem_regions = vec![(GuestAddress(0), mem_size)];
120+
// Check if the memory is overlapping with the APIC memory region.
121+
// If it is, split the memory into two regions.
122+
123+
let mem_regions = if mem_size < HIGH_RESERVED_MEMORY_START {
124+
vec![(GuestAddress(0), mem_size)]
125+
} else {
126+
vec![
127+
(GuestAddress(0), HIGH_RESERVED_MEMORY_START),
128+
(GuestAddress(HIGH_RESERVED_MEMORY_END as u64), mem_size - HIGH_RESERVED_MEMORY_END),
129+
]
130+
};
117131

118132
// Allocate the guest memory from the memory region.
119133
let guest_memory = GuestMemoryMmap::from_ranges(&mem_regions).map_err(Error::Memory)?;
@@ -269,7 +283,12 @@ impl VMM {
269283
pub fn configure(&mut self, num_vcpus: u8, mem_size_mb: u32, kernel_path: &str, console: Option<String>) -> Result<()> {
270284
self.configure_console(console)?;
271285
self.configure_memory(mem_size_mb)?;
272-
let kernel_load = kernel::kernel_setup(&self.guest_memory, PathBuf::from(kernel_path))?;
286+
let kernel_load = kernel::kernel_setup(
287+
&self.guest_memory,
288+
PathBuf::from(kernel_path),
289+
GuestAddress(HIGH_RESERVED_MEMORY_START as u64),
290+
GuestAddress(HIGH_RESERVED_MEMORY_END as u64),
291+
)?;
273292
self.configure_io()?;
274293
self.configure_vcpus(num_vcpus, kernel_load)?;
275294

0 commit comments

Comments
 (0)