From 9b529598b68a9e865183d57ef681cb451d0b0a42 Mon Sep 17 00:00:00 2001
From: Jonathan Klimt <jonathan.klimt@eonerc.rwth-aachen.de>
Date: Thu, 19 Sep 2024 10:42:42 +0200
Subject: [PATCH] Enhanced uhyve memory detection

---
 src/arch/x86_64/mm/paging.rs      |  9 ++++----
 src/arch/x86_64/mm/physicalmem.rs | 36 ++++++++++++++++++++-----------
 2 files changed, 27 insertions(+), 18 deletions(-)

diff --git a/src/arch/x86_64/mm/paging.rs b/src/arch/x86_64/mm/paging.rs
index d8947df827..2f83033e8e 100644
--- a/src/arch/x86_64/mm/paging.rs
+++ b/src/arch/x86_64/mm/paging.rs
@@ -15,6 +15,7 @@ use x86_64::structures::paging::{
 
 use crate::arch::x86_64::kernel::processor;
 use crate::arch::x86_64::mm::{physicalmem, PhysAddr, VirtAddr};
+use crate::kernel::get_limit;
 use crate::{env, mm, scheduler};
 
 pub trait PageTableEntryFlagsExt {
@@ -305,11 +306,9 @@ pub fn init_page_tables() {
 		// See https://github.com/hermit-os/uhyve/issues/426
 		let kernel_end_addr = x86_64::VirtAddr::new(mm::kernel_end_address().as_u64());
 		let start_page = Page::<Size2MiB>::from_start_address(kernel_end_addr).unwrap();
-		let end_page = Page::from_page_table_indices_2mib(
-			start_page.p4_index(),
-			start_page.p3_index(),
-			PageTableIndex::new(511),
-		);
+		let end_page =
+			Page::<Size2MiB>::from_start_address(x86_64::VirtAddr::new(get_limit() as u64))
+				.unwrap();
 		let page_range = Page::range_inclusive(start_page, end_page);
 
 		let mut page_table = unsafe { recursive_page_table() };
diff --git a/src/arch/x86_64/mm/physicalmem.rs b/src/arch/x86_64/mm/physicalmem.rs
index cb25c5c4c7..146ccee5d2 100644
--- a/src/arch/x86_64/mm/physicalmem.rs
+++ b/src/arch/x86_64/mm/physicalmem.rs
@@ -4,9 +4,10 @@ use free_list::{AllocError, FreeList, PageLayout, PageRange};
 use hermit_sync::InterruptTicketMutex;
 use multiboot::information::{MemoryType, Multiboot};
 
-use crate::arch::x86_64::kernel::{get_fdt, get_limit, get_mbinfo};
+use crate::arch::x86_64::kernel::{boot_info, get_fdt, get_limit, get_mbinfo};
 use crate::arch::x86_64::mm::paging::{BasePageSize, PageSize};
 use crate::arch::x86_64::mm::{MultibootMemory, PhysAddr, VirtAddr};
+use crate::mm::kernel_start_address;
 use crate::{env, mm};
 
 pub static PHYSICAL_FREE_LIST: InterruptTicketMutex<FreeList<16>> =
@@ -110,36 +111,45 @@ fn detect_from_uhyve() -> Result<(), ()> {
 		return Err(());
 	}
 
-	let limit = get_limit();
-	assert_ne!(limit, 0);
+	let physmem_end = get_limit();
+	assert_ne!(physmem_end, 0);
 	let mut free_list = PHYSICAL_FREE_LIST.lock();
 	let total_memory;
 
+	let kernel_end = mm::kernel_end_address().as_usize();
 	// add gap for the APIC
-	if limit > KVM_32BIT_GAP_START {
-		let range =
-			PageRange::new(mm::kernel_end_address().as_usize(), KVM_32BIT_GAP_START).unwrap();
+	assert!(
+		kernel_end < KVM_32BIT_GAP_START || kernel_end > KVM_32BIT_GAP_START + KVM_32BIT_GAP_SIZE,
+		"Kernel was loaded into the KVM 32BIT GAP"
+	);
+	if physmem_end > KVM_32BIT_GAP_START && kernel_end < KVM_32BIT_GAP_START {
+		let range = PageRange::new(kernel_end, KVM_32BIT_GAP_START).unwrap();
 		unsafe {
 			free_list.deallocate(range).unwrap();
 		}
-		if limit > KVM_32BIT_GAP_START + KVM_32BIT_GAP_SIZE {
-			let range = PageRange::new(KVM_32BIT_GAP_START + KVM_32BIT_GAP_SIZE, limit).unwrap();
+		if physmem_end > KVM_32BIT_GAP_START + KVM_32BIT_GAP_SIZE {
+			let range =
+				PageRange::new(KVM_32BIT_GAP_START + KVM_32BIT_GAP_SIZE, physmem_end).unwrap();
 			unsafe {
 				free_list.deallocate(range).unwrap();
 			}
-			total_memory = limit - KVM_32BIT_GAP_SIZE;
+			total_memory = boot_info().hardware_info.phys_addr_range.end
+				- boot_info().hardware_info.phys_addr_range.start
+				- KVM_32BIT_GAP_SIZE as u64;
 		} else {
-			total_memory = KVM_32BIT_GAP_START;
+			total_memory =
+				KVM_32BIT_GAP_START as u64 - boot_info().hardware_info.phys_addr_range.start;
 		}
 	} else {
-		let range = PageRange::new(mm::kernel_end_address().as_usize(), limit).unwrap();
+		let range = PageRange::new(kernel_end, physmem_end).unwrap();
 		unsafe {
 			free_list.deallocate(range).unwrap();
 		}
-		total_memory = limit;
+		total_memory = boot_info().hardware_info.phys_addr_range.end
+			- boot_info().hardware_info.phys_addr_range.start;
 	}
 
-	TOTAL_MEMORY.store(total_memory, Ordering::Relaxed);
+	TOTAL_MEMORY.store(total_memory as usize, Ordering::Relaxed);
 
 	Ok(())
 }