diff --git a/arch/src/lib.rs b/arch/src/lib.rs
index 3e570efc5..33430cfa6 100644
--- a/arch/src/lib.rs
+++ b/arch/src/lib.rs
@@ -91,8 +91,9 @@ pub mod x86_64;
 #[cfg(target_arch = "x86_64")]
 pub use x86_64::{
     arch_memory_regions, configure_system, configure_vcpu, generate_common_cpuid,
-    get_host_cpu_phys_bits, initramfs_load_addr, layout, layout::CMDLINE_MAX_SIZE,
-    layout::CMDLINE_START, regs, CpuidConfig, CpuidFeatureEntry, EntryPoint, _NSIG,
+    generate_ram_ranges, get_host_cpu_phys_bits, initramfs_load_addr, layout,
+    layout::CMDLINE_MAX_SIZE, layout::CMDLINE_START, regs, CpuidConfig, CpuidFeatureEntry,
+    EntryPoint, _NSIG,
 };
 
 /// Safe wrapper for `sysconf(_SC_PAGESIZE)`.
diff --git a/arch/src/x86_64/mod.rs b/arch/src/x86_64/mod.rs
index 6827ec34d..0a0d533ea 100644
--- a/arch/src/x86_64/mod.rs
+++ b/arch/src/x86_64/mod.rs
@@ -926,6 +926,112 @@ pub fn configure_system(
     )
 }
 
+type RamRange = (u64, u64);
+
+/// Returns usable physical memory ranges for the guest
+/// These should be used to create e820_RAM memory maps
+///
+/// There are up to two usable physical memory ranges,
+/// divided by the gap at the end of 32bit address space.
+pub fn generate_ram_ranges(
+    guest_mem: &GuestMemoryMmap,
+) -> super::Result<(RamRange, Option<RamRange>)> {
+    // Merge continuous memory regions into one region.
+    // Note: memory regions from "GuestMemory" are sorted and non-zero sized.
+    let ram_regions = {
+        let mut ram_regions = Vec::new();
+        let mut current_start = guest_mem
+            .iter()
+            .next()
+            .map(GuestMemoryRegion::start_addr)
+            .expect("GuestMemory must have one memory region at least")
+            .raw_value();
+        let mut current_end = current_start;
+
+        for (start, size) in guest_mem
+            .iter()
+            .map(|m| (m.start_addr().raw_value(), m.len()))
+        {
+            if current_end == start {
+                // This zone is continuous with the previous one.
+                current_end += size;
+            } else {
+                ram_regions.push((current_start, current_end));
+
+                current_start = start;
+                current_end = start + size;
+            }
+        }
+
+        ram_regions.push((current_start, current_end));
+
+        ram_regions
+    };
+
+    if ram_regions.len() > 2 {
+        error!(
+            "There should be up to two usable physical memory ranges, devidided by the
+            gap at the end of 32bit address space (e.g. between 3G and 4G)."
+        );
+        return Err(super::Error::MemmapTableSetup);
+    }
+
+    // Generate the first usable physical memory range before the gap
+    let first_ram_range = {
+        let (first_region_start, first_region_end) =
+            ram_regions.first().ok_or(super::Error::MemmapTableSetup)?;
+        let high_ram_start = layout::HIGH_RAM_START.raw_value();
+        let mem_32bit_reserved_start = layout::MEM_32BIT_RESERVED_START.raw_value();
+
+        if !((first_region_start <= &high_ram_start)
+            && (first_region_end > &high_ram_start)
+            && (first_region_end <= &mem_32bit_reserved_start))
+        {
+            error!(
+                "Unexpected first memory region layout: (start: 0x{:08x}, end: 0x{:08x}).
+                high_ram_start: 0x{:08x}, mem_32bit_reserved_start: 0x{:08x}",
+                first_region_start, first_region_end, high_ram_start, mem_32bit_reserved_start
+            );
+
+            return Err(super::Error::MemmapTableSetup);
+        }
+
+        info!(
+            "first usable physical memory range, start: 0x{:08x}, end: 0x{:08x}",
+            high_ram_start, first_region_end
+        );
+
+        (high_ram_start, *first_region_end)
+    };
+
+    // Generate the second usable physical memory range after the gap if any
+    let second_ram_range = if let Some((second_region_start, second_region_end)) =
+        ram_regions.get(1)
+    {
+        let ram_64bit_start = layout::RAM_64BIT_START.raw_value();
+
+        if second_region_start != &ram_64bit_start {
+            error!(
+                "Unexpected second memory region layout: start: 0x{:08x}, ram_64bit_start: 0x{:08x}",
+                second_region_start, ram_64bit_start
+            );
+
+            return Err(super::Error::MemmapTableSetup);
+        }
+
+        info!(
+            "Second usable physical memory range, start: 0x{:08x}, end: 0x{:08x}",
+            ram_64bit_start, second_region_end
+        );
+
+        Some((ram_64bit_start, *second_region_end))
+    } else {
+        None
+    };
+
+    Ok((first_ram_range, second_ram_range))
+}
+
 fn configure_pvh(
     guest_mem: &GuestMemoryMmap,
     cmdline_addr: GuestAddress,
@@ -972,100 +1078,31 @@ fn configure_pvh(
     // Create the memory map entries.
     add_memmap_entry(&mut memmap, 0, layout::EBDA_START.raw_value(), E820_RAM);
 
-    // Merge continuous memory regions into one region.
-    // Note: memory regions from "GuestMemory" are sorted and non-zero sized.
-    let ram_regions = {
-        let mut ram_regions = Vec::new();
-        let mut current_start = guest_mem
-            .iter()
-            .next()
-            .map(GuestMemoryRegion::start_addr)
-            .expect("GuestMemory must have one memory region at least")
-            .raw_value();
-        let mut current_end = current_start;
+    // Get usable physical memory ranges
+    let (first_ram_range, second_ram_range) = generate_ram_ranges(guest_mem)?;
 
-        for (start, size) in guest_mem
-            .iter()
-            .map(|m| (m.start_addr().raw_value(), m.len()))
-        {
-            if current_end == start {
-                // This zone is continuous with the previous one.
-                current_end += size;
-            } else {
-                ram_regions.push((current_start, current_end));
-
-                current_start = start;
-                current_end = start + size;
-            }
-        }
-
-        ram_regions.push((current_start, current_end));
-
-        ram_regions
-    };
-
-    if ram_regions.len() > 2 {
-        error!(
-            "There should be up to two non-continuous regions, devidided by the
-            gap at the end of 32bit address space (e.g. between 3G and 4G)."
-        );
-        return Err(super::Error::MemmapTableSetup);
-    }
-
-    // Create the memory map entry for memory region before the gap
-    {
-        let (first_region_start, first_region_end) =
-            ram_regions.first().ok_or(super::Error::MemmapTableSetup)?;
-        let high_ram_start = layout::HIGH_RAM_START.raw_value();
-        let mem_32bit_reserved_start = layout::MEM_32BIT_RESERVED_START.raw_value();
-
-        if !((first_region_start <= &high_ram_start)
-            && (first_region_end > &high_ram_start)
-            && (first_region_end <= &mem_32bit_reserved_start))
-        {
-            error!(
-                "Unexpected first memory region layout: (start: 0x{:08x}, end: 0x{:08x}).
-                high_ram_start: 0x{:08x}, mem_32bit_reserved_start: 0x{:08x}",
-                first_region_start, first_region_end, high_ram_start, mem_32bit_reserved_start
-            );
-
-            return Err(super::Error::MemmapTableSetup);
-        }
+    // Create e820 memory map entry before the gap
+    info!(
+        "create_memmap_entry, start: 0x{:08x}, end: 0x{:08x}",
+        first_ram_range.0, first_ram_range.1
+    );
+    add_memmap_entry(
+        &mut memmap,
+        first_ram_range.0,
+        first_ram_range.1 - first_ram_range.0,
+        E820_RAM,
+    );
 
+    // Create e820 memory map after the gap if any
+    if let Some(second_ram_range) = second_ram_range {
         info!(
             "create_memmap_entry, start: 0x{:08x}, end: 0x{:08x}",
-            high_ram_start, first_region_end
-        );
-
-        add_memmap_entry(
-            &mut memmap,
-            high_ram_start,
-            first_region_end - high_ram_start,
-            E820_RAM,
-        );
-    }
-
-    // Create the memory map entry for memory region after the gap if any
-    if let Some((second_region_start, second_region_end)) = ram_regions.get(1) {
-        let ram_64bit_start = layout::RAM_64BIT_START.raw_value();
-
-        if second_region_start != &ram_64bit_start {
-            error!(
-                "Unexpected second memory region layout: start: 0x{:08x}, ram_64bit_start: 0x{:08x}",
-                second_region_start, ram_64bit_start
-            );
-
-            return Err(super::Error::MemmapTableSetup);
-        }
-
-        info!(
-            "create_memmap_entry, start: 0x{:08x}, end: 0x{:08x}",
-            ram_64bit_start, second_region_end
+            second_ram_range.0, second_ram_range.1
         );
         add_memmap_entry(
             &mut memmap,
-            ram_64bit_start,
-            second_region_end - ram_64bit_start,
+            second_ram_range.0,
+            second_ram_range.1 - second_ram_range.0,
             E820_RAM,
         );
     }