Add a kernel parameter pmemmem=<size>:<phys_addr> to reserve a region of physical memory as persistent memory (pmem) used by rmfork's ubmem allocator for storing process memory pages during checkpoint. Changes: - lib/Kconfig: add CONFIG_KUP_PMEM_MEMORY option - arch/arm64/mm/init.c: parse_pmem() early_param handler, reserve_pmem() called from arm64_memblock_init(), pmem_res struct definition - arch/arm64/kernel/setup.c: insert pmem_res into iomem_resource tree - include/linux/ioport.h: add IORES_DESC_KPMEM_DEV resource descriptor - include/linux/mm.h: expose pmem_res extern under CONFIG_KUP_PMEM_MEMORY Example: pmemmem=8G:0x40000000 reserves 8GB at physical 0x40000000. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --- arch/arm64/kernel/setup.c | 5 +++ arch/arm64/mm/init.c | 75 +++++++++++++++++++++++++++++++++++++++ include/linux/ioport.h | 1 + include/linux/mm.h | 4 +++ lib/Kconfig | 6 ++++ 5 files changed, 91 insertions(+) diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index 09a15a9a8b2b..6e85500b098f 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -281,6 +281,11 @@ static void __init request_standard_resources(void) insert_resource(&iomem_resource, &kernel_code); insert_resource(&iomem_resource, &kernel_data); +#ifdef CONFIG_KUP_PMEM_MEMORY + if (pmem_res.end) + insert_resource(&iomem_resource, &pmem_res); +#endif + num_standard_resources = memblock.memory.cnt; res_size = num_standard_resources * sizeof(*standard_resources); standard_resources = memblock_alloc(res_size, SMP_CACHE_BYTES); diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c index da75dd9d964b..c60a7fbc3ea5 100644 --- a/arch/arm64/mm/init.c +++ b/arch/arm64/mm/init.c @@ -72,6 +72,18 @@ EXPORT_SYMBOL(memstart_addr); */ phys_addr_t __ro_after_init arm64_dma_phys_limit; +#ifdef CONFIG_KUP_PMEM_MEMORY +static unsigned long long pmem_size, pmem_phystart; + +struct resource pmem_res = { + .name = "Kpmem Dev", + .start = 0, + .end = 0, + .flags = IORESOURCE_MEM, + .desc = IORES_DESC_KPMEM_DEV +}; +#endif + /* Current arm64 boot protocol requires 2MB alignment */ #define CRASH_ALIGN SZ_2M @@ -128,6 +140,65 @@ static int __init reserve_crashkernel_low(unsigned long long low_size) return 0; } +#ifdef CONFIG_KUP_PMEM_MEMORY +static int __init parse_pmem(char *par) +{ + char *cur = par; + + if (!par) + return 0; + + pmem_size = 0; + pmem_phystart = 0; + + pmem_size = memparse(par, &cur); + if (par == cur) { + pr_warn("pmem: memory value expected\n"); + return -EINVAL; + } + + if (*cur == ':') + pmem_phystart = memparse(cur + 1, &cur); + else if (*cur != ' ' && *cur != '\0') { + pr_warn("pmem: unrecognized char %c\n", *cur); + return -EINVAL; + } + + return 0; +} +early_param("pmemmem", parse_pmem); + +static void __init reserve_pmem(void) +{ + if (!pmem_size || !pmem_phystart) + return; + + pmem_size = PAGE_ALIGN(pmem_size); + + if (!memblock_is_region_memory(pmem_phystart, pmem_size)) { + pr_warn("cannot reserve pmem: region is not memory!\n"); + return; + } + + if (memblock_is_region_reserved(pmem_phystart, pmem_size)) { + pr_warn("cannot reserve pmem: region overlaps reserved memory!\n"); + return; + } + + if (!IS_ALIGNED(pmem_phystart, SZ_2M)) { + pr_warn("cannot reserve pmem: base address is not 2MB aligned\n"); + return; + } + memblock_reserve(pmem_phystart, pmem_size); + memblock_remove(pmem_phystart, pmem_size); + pr_info("pmem reserved: 0x%016llx - 0x%016llx (%lld MB)\n", + pmem_phystart, pmem_phystart + pmem_size, pmem_size >> 20); + + pmem_res.start = pmem_phystart; + pmem_res.end = pmem_phystart + pmem_size - 1; +} +#endif /* CONFIG_KUP_PMEM_MEMORY */ + /* * reserve_crashkernel() - reserves memory for crash kernel * @@ -551,6 +622,10 @@ void __init arm64_memblock_init(void) early_init_fdt_scan_reserved_mem(); +#ifdef CONFIG_KUP_PMEM_MEMORY + reserve_pmem(); +#endif + high_memory = __va(memblock_end_of_DRAM() - 1) + 1; } diff --git a/include/linux/ioport.h b/include/linux/ioport.h index 25d768d48970..69139a9000e6 100644 --- a/include/linux/ioport.h +++ b/include/linux/ioport.h @@ -143,6 +143,7 @@ enum { IORES_DESC_RESERVED = 7, IORES_DESC_SOFT_RESERVED = 8, IORES_DESC_CXL = 9, + IORES_DESC_KPMEM_DEV = 10, }; /* diff --git a/include/linux/mm.h b/include/linux/mm.h index 75d32b512cb4..f269dca11bef 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -44,6 +44,10 @@ extern int sysctl_page_lock_unfairness; void mm_core_init(void); void init_mm_internals(void); +#ifdef CONFIG_KUP_PMEM_MEMORY +extern struct resource pmem_res; +#endif + #ifndef CONFIG_NUMA /* Don't use mapnrs, do it properly */ extern unsigned long max_mapnr; diff --git a/lib/Kconfig b/lib/Kconfig index 43d69669465a..d574c240b977 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -754,6 +754,12 @@ config PLDMFW select CRC32 default n +config KUP_PMEM_MEMORY + bool "reserve memory for kup pmem to store image" + default y + help + Say y here to enable this feature + config ASN1_ENCODER tristate -- 2.53.0