diff --git a/kernel/resource.c b/kernel/resource.c index e3f5680a564cf656ac0d5847f36b78291c31ade3..4126827db0bf8b8e843815bac4c6b1179a6a2963 100644 --- a/kernel/resource.c +++ b/kernel/resource.c @@ -2015,3 +2015,77 @@ static int __init iomem_init_inode(void) fs_initcall(iomem_init_inode); __setup("iomem=", strict_iomem); +#ifdef CONFIG_FREE_RESERVED_MM +int release_reserved_resource(resource_size_t start, resource_size_t end, + unsigned long flags, bool first_lvl) +{ + bool siblings_only = false; + struct resource *p; + struct resource *new_res = NULL; + + if (start >= end) + return -EINVAL; + + read_lock(&resource_lock); + + for (p = iomem_resource.child; p; p = next_resource(p)) { + if (p->start > end) { + p = NULL; + break; + } + + if (p->end < start) + continue; + + if (p->end > end && p->child) + continue; + + siblings_only = first_lvl; + + if ((p->flags & flags) != flags) + continue; + + break; + } + + read_unlock(&resource_lock); + + if (p) { + pr_info("p->start=%llx,p->end=%llx\n", p->start, p->end); + if (p->start == start && p->end == end) { + release_resource(p); + } else if (p->start == start && p->end != end) { + /* adjust the start */ + adjust_resource(p, end + 1, p->end - end); + } else if (p->start != start && p->end == end) { + /* adjust the end */ + adjust_resource(p, p->start, start - p->start); + } else { + /* split into entries - we need a new resource */ + read_lock(&resource_lock); + new_res = alloc_resource(GFP_KERNEL); + if (!new_res) + alloc_resource(GFP_ATOMIC); + if (!new_res) + alloc_resource(GFP_KERNEL | __GFP_NOFAIL); + new_res->name = p->name; + new_res->start = end + 1; + new_res->end = p->end; + new_res->flags = p->flags; + new_res->parent = p->parent; + new_res->sibling = p->sibling; + new_res->child = NULL; + read_unlock(&resource_lock); + + if (adjust_resource(p, p->start, start - p->start)) + goto out; + p->sibling = new_res; + new_res = NULL; + } + } + +out: + free_resource(new_res); + return p ? 0 : -ENODEV; +} +#endif diff --git a/nos/extend_features/free_reserved_mm/Kconfig b/nos/extend_features/free_reserved_mm/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..1dfa7f48c169ad3c7fca383a953b0c486901f189 --- /dev/null +++ b/nos/extend_features/free_reserved_mm/Kconfig @@ -0,0 +1,5 @@ +config FREE_RESERVED_MM + bool "Free reserved memory after system start" + default n + help + Free reserved memory, while reserved memory must be mapped. \ No newline at end of file diff --git a/nos/extend_features/free_reserved_mm/Makefile b/nos/extend_features/free_reserved_mm/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..73e4e6a466fff532fd5722a24a18adea410434b0 --- /dev/null +++ b/nos/extend_features/free_reserved_mm/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_FREE_RESERVED_MM) += free_reserved_mm.o \ No newline at end of file diff --git a/nos/extend_features/free_reserved_mm/free_reserved_mm.c b/nos/extend_features/free_reserved_mm/free_reserved_mm.c new file mode 100644 index 0000000000000000000000000000000000000000..982a3ecd224f07456dd005bda9292c68756906cf --- /dev/null +++ b/nos/extend_features/free_reserved_mm/free_reserved_mm.c @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#include +#include +#include +#include +#ifdef CONFIG_X86 +#include +#endif +#include + +extern int release_reserved_resource(resource_size_t start, resource_size_t end, + unsigned long flags, bool first_lvl); + +static unsigned long memblock_addrs_inlap(phys_addr_t base1, phys_addr_t size1, + phys_addr_t base2, phys_addr_t size2) +{ + return (base1 + size1) <= (base2 + size2) && base1 >= base2; +} + +static bool memblock_inlaps_region(struct memblock_type *type, + phys_addr_t base, phys_addr_t size) +{ + unsigned long i; + + for (i = 0; i < type->cnt; i++) + if (memblock_addrs_inlap(base, size, type->regions[i].base, + type->regions[i].size)) + break; + return i < type->cnt; +} + +static bool memblock_in_region_reserved(phys_addr_t base, phys_addr_t size) +{ + size = min(size, (phys_addr_t)ULLONG_MAX - base); + return memblock_inlaps_region(&memblock.reserved, base, size); +} + +int free_reserved_mm(unsigned long resv_start, unsigned long resv_size) +{ + unsigned long pfn_start_align, pfn_end_align; + void *start, *end; + + pfn_start_align = PFN_UP(resv_start); + pfn_end_align = PFN_DOWN(resv_start + resv_size); + +#ifdef CONFIG_X86 + if (!pfn_range_is_mapped(pfn_start_align, pfn_end_align)) { + pr_warn("[0x%lx, 0x%lx] is not mapped\n", + pfn_start_align << PAGE_SHIFT, + pfn_end_align << PAGE_SHIFT); + return -EINVAL; + } +#endif + + start = __va(pfn_start_align << PAGE_SHIFT); + end = __va(pfn_end_align << PAGE_SHIFT); + + if (!memblock_in_region_reserved(pfn_start_align << PAGE_SHIFT, + PAGE_ALIGN(resv_size))) { + pr_warn("[0x%lx, 0x%lx] is not all reserved\n", + pfn_start_align << PAGE_SHIFT, + pfn_end_align << PAGE_SHIFT); + return -EINVAL; + } + + free_reserved_area(start, end, 0, "reserve free"); + memblock_free(pfn_start_align << PAGE_SHIFT, + (pfn_end_align << PAGE_SHIFT) - (pfn_start_align << PAGE_SHIFT)); + + return release_reserved_resource(pfn_start_align << PAGE_SHIFT, + (pfn_end_align << PAGE_SHIFT) - 1, + IORESOURCE_MEM, false); +} +EXPORT_SYMBOL(free_reserved_mm); \ No newline at end of file