On Thu, Nov 13, 2025 at 12:08:18PM +0100, Jan Beulich wrote: > ... to replace ebmalloc(), and then to find further use(s) to allow > recovering memory which is needed very early (and hence needs setting up > statically), but may not fully be used (or not used at all). > > Note that unlike free_ebmalloc_unused_mem(), brk_free_unused() (once > other code is converted) will be able to free part of the BRK space even > in the xen.efi case. That would happen if BRK space extends across a 2Mb > boundary, and actual use stops before that boundary. > > Signed-off-by: Jan Beulich > --- > Changing setup.c's reserve_e820_ram() uses would be cumbersome when done > right here. That'll be done when ebmalloc() is replaced, and hence > what's there can also simply be replaced. > > The xen.efi detection may want separating out into a helper. > > When linking xen.efi, ld produces a base relocation for the reference to > __subsystem__, which is wrong (that's an absolute symbol, after all). > While that will need fixing there, it does no harm for our purposes. > > --- a/xen/arch/x86/boot/Makefile > +++ b/xen/arch/x86/boot/Makefile > @@ -1,4 +1,5 @@ > obj-bin-y += head.o > +obj-bin-y += brk.init.o > obj-bin-y += built-in-32.o > obj-bin-y += $(obj64) > > --- /dev/null > +++ b/xen/arch/x86/boot/brk.c > @@ -0,0 +1,72 @@ > +/* SPDX-License-Identifier: GPL-2.0-or-later */ > + > +#include > +#include > +#include > +#include > + > +#include > + > +extern char __brk_start[]; > +extern const char __bss_end[]; > + > +static unsigned long __initdata allocated; > +static bool __initdata finished; > + > +void *__init brk_alloc(size_t size) > +{ > + void *ptr = __brk_start + allocated; > + > + if ( finished ) > + return NULL; > + > + /* Allocations PAGE_SIZE and up will be page-aligned. */ > + if ( size >= PAGE_SIZE ) > + allocated = ROUNDUP(allocated, PAGE_SIZE); > + > + allocated += ROUNDUP(size, sizeof(void *)); > + > + if ( allocated > __bss_end - __brk_start ) > + return NULL; > + > + return ptr; > +} > + > +unsigned long __init brk_get_unused_start(void) It's a bit unintuitive for brk_get_* to have this significant side effect. Maybe name it brk_finalize_get_unused_start() ? > +{ > + finished = true; > + > + allocated = ROUNDUP(allocated, PAGE_SIZE); > + > + return (unsigned long)__brk_start + allocated; > +} > + > +void __init brk_free_unused(void) > +{ > + unsigned long start = brk_get_unused_start(), > + end = (unsigned long)__bss_end; > + unsigned int subsys; > + > + /* > + * Only xen.efi will have the symbol __subsystem__ available, and it'll > + * be non-zero (10) there. In ELF the symbol will be undefined, and > + * hence zero will be loaded into the register. > + */ > + asm ( ".weak __subsystem__; mov $__subsystem__, %0" : "=r" (subsys) ); Is this really the best way to detect xen.efi? > + > + /* using_2M_mapping() isn't available here. */ > + if ( IS_ENABLED(CONFIG_XEN_ALIGN_2M) || subsys ) > + start = PAGE_ALIGN_2M(start); > + > + if ( start >= end ) > + return; > + > + destroy_xen_mappings(start, PAGE_ALIGN_2M(end)); > + > + /* > + * By reserving needed space early in the E820 map, excess space gets freed > + * way before we make it here. Don't free the range a 2nd time. > + */ > + > + printk(XENLOG_INFO "Freed %lukB unused BRK memory\n", (end - start) >> 10); > +} > --- /dev/null > +++ b/xen/arch/x86/include/asm/brk.h > @@ -0,0 +1,7 @@ > +/* SPDX-License-Identifier: GPL-2.0-or-later */ > + > +#include > + > +void *brk_alloc(size_t size); > +unsigned long brk_get_unused_start(void); > +void brk_free_unused(void); > --- a/xen/arch/x86/xen.lds.S > +++ b/xen/arch/x86/xen.lds.S > @@ -331,7 +331,11 @@ SECTIONS > __bss_start = .; > *(.bss.page_aligned*) > PERCPU_BSS > - *(.bss .bss.*) > + *(.bss .bss.[a-zA-Z0-9_]*) > + . = ALIGN(PAGE_SIZE); > + __brk_start = .; > + *(.bss..brk.page_aligned*) > + *(.bss..brk*) > . = ALIGN(POINTER_ALIGN); > __bss_end = .; > } PHDR(text) > --- a/xen/arch/x86/mm.c > +++ b/xen/arch/x86/mm.c > @@ -112,6 +112,7 @@ > #include > #include > > +#include > #include > #include > #include > @@ -337,6 +338,8 @@ void __init arch_init_memory(void) > > efi_init_memory(); > > + brk_free_unused(); > + > #ifndef NDEBUG > if ( highmem_start ) > { > > -- Best Regards, Marek Marczykowski-Górecki Invisible Things Lab