[MINI-OS PATCH 06/19] mm: don't add module pages to free memory

Juergen Gross posted 19 patches 4 months ago
There is a newer version of this series
[MINI-OS PATCH 06/19] mm: don't add module pages to free memory
Posted by Juergen Gross 4 months ago
When initializing the memory allocator, don't add memory pages of
modules and the initial boot info structure to the free memory.

This is relevant only when running in PVH mode, as in PV mode only
memory above the initial page tables is added to free memory, and the
module and start_info pages are below the page tables.

Signed-off-by: Juergen Gross <jgross@suse.com>
---
 arch/x86/mm.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++
 include/mm.h  |  1 +
 mm.c          | 21 +++++++++++++-
 3 files changed, 101 insertions(+), 1 deletion(-)

diff --git a/arch/x86/mm.c b/arch/x86/mm.c
index 26ede6f4..7c3c83be 100644
--- a/arch/x86/mm.c
+++ b/arch/x86/mm.c
@@ -78,6 +78,10 @@ void arch_mm_preinit(void *p)
     last_free_pfn = si->nr_pages;
     balloon_set_nr_pages(last_free_pfn, last_free_pfn);
 }
+
+void check_memory_range(unsigned long *from, unsigned long *to)
+{
+}
 #else
 #include <mini-os/desc.h>
 user_desc gdt[NR_GDT_ENTRIES] =
@@ -125,6 +129,78 @@ void arch_mm_preinit(void *p)
     last_free_pfn = e820_get_maxpfn(pages);
     balloon_set_nr_pages(pages, last_free_pfn);
 }
+
+static void check_memory_range_conflict(unsigned long *from, unsigned long *to,
+                                        unsigned long chk, unsigned long sz)
+{
+    unsigned long chk_end = chk + sz;
+
+    if ( *to <= chk || *from >= chk_end )
+        return;
+
+    if ( chk <= *from )
+        *from = (chk_end >= *to) ? *to : chk_end;
+    else
+        *to = chk;
+}
+
+/* Reserved memory ranges not added to free memory. */
+#define MAX_RSV_RANGES  1
+static struct {
+    unsigned long start;
+    unsigned long size;
+} reserved_range[MAX_RSV_RANGES];
+
+void check_memory_range(unsigned long *from, unsigned long *to)
+{
+    unsigned int m;
+    struct hvm_modlist_entry *mod;
+
+    for ( m = 0; m < MAX_RSV_RANGES && reserved_range[m].size; m++ )
+        check_memory_range_conflict(from, to, reserved_range[m].start,
+                                    reserved_range[m].size);
+
+    mod = (struct hvm_modlist_entry *)(unsigned long)
+          hvm_start_info_ptr->modlist_paddr;
+    for ( m = 0; m < hvm_start_info_ptr->nr_modules; m++ )
+        check_memory_range_conflict(from, to, mod[m].paddr, mod[m].size);
+}
+
+#define max(a, b) ((a) < (b) ? (b) : (a))
+
+static void pvh_reserve_start_info(unsigned long *start_pfn)
+{
+    unsigned long end = 0;
+    unsigned long start = (unsigned long)hvm_start_info_ptr;
+    unsigned long end_pfn;
+    unsigned int m;
+    struct hvm_modlist_entry *mod;
+    char *cmdline;
+
+    mod = (void *)(unsigned long)hvm_start_info_ptr->modlist_paddr;
+
+    end = max(end, start + sizeof(struct hvm_start_info));
+    end = max(end, hvm_start_info_ptr->modlist_paddr +
+              hvm_start_info_ptr->nr_modules *
+              sizeof(struct hvm_modlist_entry));
+    for ( m = 0; m < hvm_start_info_ptr->nr_modules; m++ )
+    {
+        cmdline = (char *)(unsigned long)mod[m].cmdline_paddr;
+        if ( cmdline )
+            end = max(end, (unsigned long)cmdline + strlen(cmdline) + 1);
+    }
+    cmdline = (char *)(unsigned long)hvm_start_info_ptr->cmdline_paddr;
+    if ( cmdline )
+        end = max(end, (unsigned long)cmdline + strlen(cmdline) + 1);
+    if ( hvm_start_info_ptr->version >= 1 )
+        end = max(end, hvm_start_info_ptr->memmap_paddr +
+                  hvm_start_info_ptr->memmap_entries *
+                  sizeof(struct hvm_memmap_table_entry));
+
+    end_pfn = PFN_UP(end);
+    if ( end_pfn > *start_pfn )
+        *start_pfn = end_pfn;
+}
 #endif
 
 static const struct {
@@ -888,6 +964,10 @@ void arch_init_mm(unsigned long* start_pfn_p, unsigned long* max_pfn_p)
     if ( max_pfn >= MAX_MEM_SIZE / PAGE_SIZE )
         max_pfn = MAX_MEM_SIZE / PAGE_SIZE - 1;
 
+#ifndef CONFIG_PARAVIRT
+    pvh_reserve_start_info(&start_pfn);
+#endif
+
     printk("  start_pfn: %lx\n", start_pfn);
     printk("    max_pfn: %lx\n", max_pfn);
 
diff --git a/include/mm.h b/include/mm.h
index 1dc89ddb..995e9862 100644
--- a/include/mm.h
+++ b/include/mm.h
@@ -74,6 +74,7 @@ static __inline__ int get_order(unsigned long size)
 
 void arch_init_demand_mapping_area(void);
 void arch_init_mm(unsigned long* start_pfn_p, unsigned long* max_pfn_p);
+void check_memory_range(unsigned long *from, unsigned long *to);
 
 unsigned long allocate_ondemand(unsigned long n, unsigned long alignment);
 /* map f[i*stride]+i*increment for i in 0..n-1, aligned on alignment pages */
diff --git a/mm.c b/mm.c
index 858dc108..8c41d2f2 100644
--- a/mm.c
+++ b/mm.c
@@ -185,6 +185,25 @@ static void add_memory_range(unsigned long r_min, unsigned long r_max)
     }
 }
 
+static void consider_memory_range(unsigned long r_min, unsigned long r_max,
+                                  void (*func)(unsigned long, unsigned long))
+{
+    unsigned long from = r_min;
+    unsigned long to = r_max;
+
+    while ( true )
+    {
+        check_memory_range(&from, &to);
+        if ( from == to )
+            return;
+
+        func(from, to);
+
+        from = to;
+        to = r_max;
+    }
+}
+
 void iterate_memory_range(unsigned long min, unsigned long max,
                           void (*func)(unsigned long, unsigned long))
 {
@@ -207,7 +226,7 @@ void iterate_memory_range(unsigned long min, unsigned long max,
         if ( r_max > max )
             r_max = max;
 
-        func(r_min, r_max);
+        consider_memory_range(r_min, r_max, func);
     }
 }
 
-- 
2.43.0
Re: [MINI-OS PATCH 06/19] mm: don't add module pages to free memory
Posted by Jason Andryuk 3 months, 3 weeks ago
On 2025-07-02 04:12, Juergen Gross wrote:
> When initializing the memory allocator, don't add memory pages of
> modules and the initial boot info structure to the free memory.
> 
> This is relevant only when running in PVH mode, as in PV mode only
> memory above the initial page tables is added to free memory, and the
> module and start_info pages are below the page tables.
> 
> Signed-off-by: Juergen Gross <jgross@suse.com>
>
> +/* Reserved memory ranges not added to free memory. */
> +#define MAX_RSV_RANGES  1
> +static struct {
> +    unsigned long start;
> +    unsigned long size;
> +} reserved_range[MAX_RSV_RANGES];
> +
> +void check_memory_range(unsigned long *from, unsigned long *to)
> +{
> +    unsigned int m;
> +    struct hvm_modlist_entry *mod;
> +
> +    for ( m = 0; m < MAX_RSV_RANGES && reserved_range[m].size; m++ )
> +        check_memory_range_conflict(from, to, reserved_range[m].start,
> +                                    reserved_range[m].size);

reserved_range[] isn't updated, so this is dead code.  I guess that is 
fine for now.
> +
> +    mod = (struct hvm_modlist_entry *)(unsigned long)
> +          hvm_start_info_ptr->modlist_paddr;
> +    for ( m = 0; m < hvm_start_info_ptr->nr_modules; m++ )
> +        check_memory_range_conflict(from, to, mod[m].paddr, mod[m].size);
> +}
> +

>   
>   static const struct {
> @@ -888,6 +964,10 @@ void arch_init_mm(unsigned long* start_pfn_p, unsigned long* max_pfn_p)
>       if ( max_pfn >= MAX_MEM_SIZE / PAGE_SIZE )
>           max_pfn = MAX_MEM_SIZE / PAGE_SIZE - 1;
>   
> +#ifndef CONFIG_PARAVIRT
> +    pvh_reserve_start_info(&start_pfn);
> +#endif

Maybe this ifdef can be removed and arch_mm_preinit() can call 
pvh_reserve_start_info() and update first_free_pfn (which is assigned to 
start_pfn)?

Regards,
Jason
Re: [MINI-OS PATCH 06/19] mm: don't add module pages to free memory
Posted by Jürgen Groß 3 months, 3 weeks ago
On 08.07.25 23:14, Jason Andryuk wrote:
> On 2025-07-02 04:12, Juergen Gross wrote:
>> When initializing the memory allocator, don't add memory pages of
>> modules and the initial boot info structure to the free memory.
>>
>> This is relevant only when running in PVH mode, as in PV mode only
>> memory above the initial page tables is added to free memory, and the
>> module and start_info pages are below the page tables.
>>
>> Signed-off-by: Juergen Gross <jgross@suse.com>
>>
>> +/* Reserved memory ranges not added to free memory. */
>> +#define MAX_RSV_RANGES  1
>> +static struct {
>> +    unsigned long start;
>> +    unsigned long size;
>> +} reserved_range[MAX_RSV_RANGES];
>> +
>> +void check_memory_range(unsigned long *from, unsigned long *to)
>> +{
>> +    unsigned int m;
>> +    struct hvm_modlist_entry *mod;
>> +
>> +    for ( m = 0; m < MAX_RSV_RANGES && reserved_range[m].size; m++ )
>> +        check_memory_range_conflict(from, to, reserved_range[m].start,
>> +                                    reserved_range[m].size);
> 
> reserved_range[] isn't updated, so this is dead code.  I guess that is fine for 
> now.

I thought so, yes. It felt more natural to add it in this patch.

>> +
>> +    mod = (struct hvm_modlist_entry *)(unsigned long)
>> +          hvm_start_info_ptr->modlist_paddr;
>> +    for ( m = 0; m < hvm_start_info_ptr->nr_modules; m++ )
>> +        check_memory_range_conflict(from, to, mod[m].paddr, mod[m].size);
>> +}
>> +
> 
>>   static const struct {
>> @@ -888,6 +964,10 @@ void arch_init_mm(unsigned long* start_pfn_p, unsigned 
>> long* max_pfn_p)
>>       if ( max_pfn >= MAX_MEM_SIZE / PAGE_SIZE )
>>           max_pfn = MAX_MEM_SIZE / PAGE_SIZE - 1;
>> +#ifndef CONFIG_PARAVIRT
>> +    pvh_reserve_start_info(&start_pfn);
>> +#endif
> 
> Maybe this ifdef can be removed and arch_mm_preinit() can call 
> pvh_reserve_start_info() and update first_free_pfn (which is assigned to 
> start_pfn)?

Yes, that should be possible.

Thanks for the idea, I'll modify the patch.


Juergen
Re: [MINI-OS PATCH 06/19] mm: don't add module pages to free memory
Posted by Jason Andryuk 3 months, 3 weeks ago
On 2025-07-02 04:12, Juergen Gross wrote:
> When initializing the memory allocator, don't add memory pages of
> modules and the initial boot info structure to the free memory.
> 
> This is relevant only when running in PVH mode, as in PV mode only
> memory above the initial page tables is added to free memory, and the
> module and start_info pages are below the page tables.
> 
> Signed-off-by: Juergen Gross <jgross@suse.com>
> ---
>   arch/x86/mm.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++
>   include/mm.h  |  1 +
>   mm.c          | 21 +++++++++++++-
>   3 files changed, 101 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/x86/mm.c b/arch/x86/mm.c
> index 26ede6f4..7c3c83be 100644
> --- a/arch/x86/mm.c
> +++ b/arch/x86/mm.c
> @@ -78,6 +78,10 @@ void arch_mm_preinit(void *p)
>       last_free_pfn = si->nr_pages;
>       balloon_set_nr_pages(last_free_pfn, last_free_pfn);
>   }
> +
> +void check_memory_range(unsigned long *from, unsigned long *to)
> +{
> +}
>   #else
>   #include <mini-os/desc.h>
>   user_desc gdt[NR_GDT_ENTRIES] =
> @@ -125,6 +129,78 @@ void arch_mm_preinit(void *p)
>       last_free_pfn = e820_get_maxpfn(pages);
>       balloon_set_nr_pages(pages, last_free_pfn);
>   }
> +
> +static void check_memory_range_conflict(unsigned long *from, unsigned long *to,
> +                                        unsigned long chk, unsigned long sz)
> +{
> +    unsigned long chk_end = chk + sz;
> +
> +    if ( *to <= chk || *from >= chk_end )
> +        return;
> +
> +    if ( chk <= *from )
> +        *from = (chk_end >= *to) ? *to : chk_end;
> +    else
> +        *to = chk;
> +}
> +
> +/* Reserved memory ranges not added to free memory. */
> +#define MAX_RSV_RANGES  1
> +static struct {
> +    unsigned long start;
> +    unsigned long size;
> +} reserved_range[MAX_RSV_RANGES];
> +
> +void check_memory_range(unsigned long *from, unsigned long *to)
> +{
> +    unsigned int m;
> +    struct hvm_modlist_entry *mod;
> +
> +    for ( m = 0; m < MAX_RSV_RANGES && reserved_range[m].size; m++ )
> +        check_memory_range_conflict(from, to, reserved_range[m].start,
> +                                    reserved_range[m].size);
> +
> +    mod = (struct hvm_modlist_entry *)(unsigned long)
> +          hvm_start_info_ptr->modlist_paddr;
> +    for ( m = 0; m < hvm_start_info_ptr->nr_modules; m++ )
> +        check_memory_range_conflict(from, to, mod[m].paddr, mod[m].size);
> +}
> +
> +#define max(a, b) ((a) < (b) ? (b) : (a))
> +
> +static void pvh_reserve_start_info(unsigned long *start_pfn)
> +{
> +    unsigned long end = 0;
> +    unsigned long start = (unsigned long)hvm_start_info_ptr;
> +    unsigned long end_pfn;
> +    unsigned int m;
> +    struct hvm_modlist_entry *mod;
> +    char *cmdline;
> +
> +    mod = (void *)(unsigned long)hvm_start_info_ptr->modlist_paddr;
> +
> +    end = max(end, start + sizeof(struct hvm_start_info));
> +    end = max(end, hvm_start_info_ptr->modlist_paddr +
> +              hvm_start_info_ptr->nr_modules *
> +              sizeof(struct hvm_modlist_entry));
> +    for ( m = 0; m < hvm_start_info_ptr->nr_modules; m++ )
> +    {
> +        cmdline = (char *)(unsigned long)mod[m].cmdline_paddr;
> +        if ( cmdline )
> +            end = max(end, (unsigned long)cmdline + strlen(cmdline) + 1);
> +    }
> +    cmdline = (char *)(unsigned long)hvm_start_info_ptr->cmdline_paddr;
> +    if ( cmdline )
> +        end = max(end, (unsigned long)cmdline + strlen(cmdline) + 1);
> +    if ( hvm_start_info_ptr->version >= 1 )
> +        end = max(end, hvm_start_info_ptr->memmap_paddr +
> +                  hvm_start_info_ptr->memmap_entries *
> +                  sizeof(struct hvm_memmap_table_entry));
> +
> +    end_pfn = PFN_UP(end);
> +    if ( end_pfn > *start_pfn )
> +        *start_pfn = end_pfn;
> +}
>   #endif
>   
>   static const struct {
> @@ -888,6 +964,10 @@ void arch_init_mm(unsigned long* start_pfn_p, unsigned long* max_pfn_p)
>       if ( max_pfn >= MAX_MEM_SIZE / PAGE_SIZE )
>           max_pfn = MAX_MEM_SIZE / PAGE_SIZE - 1;
>   
> +#ifndef CONFIG_PARAVIRT
> +    pvh_reserve_start_info(&start_pfn);
> +#endif
> +
>       printk("  start_pfn: %lx\n", start_pfn);
>       printk("    max_pfn: %lx\n", max_pfn);
>   
> diff --git a/include/mm.h b/include/mm.h
> index 1dc89ddb..995e9862 100644
> --- a/include/mm.h
> +++ b/include/mm.h
> @@ -74,6 +74,7 @@ static __inline__ int get_order(unsigned long size)
>   
>   void arch_init_demand_mapping_area(void);
>   void arch_init_mm(unsigned long* start_pfn_p, unsigned long* max_pfn_p);
> +void check_memory_range(unsigned long *from, unsigned long *to);
>   
>   unsigned long allocate_ondemand(unsigned long n, unsigned long alignment);
>   /* map f[i*stride]+i*increment for i in 0..n-1, aligned on alignment pages */
> diff --git a/mm.c b/mm.c
> index 858dc108..8c41d2f2 100644
> --- a/mm.c
> +++ b/mm.c
> @@ -185,6 +185,25 @@ static void add_memory_range(unsigned long r_min, unsigned long r_max)
>       }
>   }
>   
> +static void consider_memory_range(unsigned long r_min, unsigned long r_max,
> +                                  void (*func)(unsigned long, unsigned long))
> +{
> +    unsigned long from = r_min;
> +    unsigned long to = r_max;
> +
> +    while ( true )
> +    {
> +        check_memory_range(&from, &to);
> +        if ( from == to )
> +            return;
> +
> +        func(from, to);
> +
> +        from = to;
> +        to = r_max;
> +    }
> +}
> +
>   void iterate_memory_range(unsigned long min, unsigned long max,
>                             void (*func)(unsigned long, unsigned long))
>   {
> @@ -207,7 +226,7 @@ void iterate_memory_range(unsigned long min, unsigned long max,
>           if ( r_max > max )
>               r_max = max;
>   
> -        func(r_min, r_max);
> +        consider_memory_range(r_min, r_max, func);
>       }
>   }
>