From c8a8f0196bdb068f07a5565bf4ce5f43f5003f6e Mon Sep 17 00:00:00 2001 From: Sughosh Ganu Date: Tue, 15 Oct 2024 21:07:03 +0530 Subject: lmb: add versions of the lmb API with flags The LMB module is to be used as a backend for allocating and freeing up memory requested from other modules like EFI. These memory requests are different from the typical LMB reservations in that memory required by the EFI module cannot be overwritten, or re-requested. Add versions of the LMB API functions with flags for allocating and freeing up memory. The caller can then use these API's for specifying the type of memory that is required. For now, these functions will be used by the EFI memory module. Signed-off-by: Sughosh Ganu Reviewed-by: Simon Glass --- lib/lmb.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 1 deletion(-) (limited to 'lib/lmb.c') diff --git a/lib/lmb.c b/lib/lmb.c index 380d92a6718..a38537af9c3 100644 --- a/lib/lmb.c +++ b/lib/lmb.c @@ -479,7 +479,7 @@ long lmb_add(phys_addr_t base, phys_size_t size) return lmb_add_region(lmb_rgn_lst, base, size); } -long lmb_free(phys_addr_t base, phys_size_t size) +static long __lmb_free(phys_addr_t base, phys_size_t size) { struct lmb_region *rgn; struct alist *lmb_rgn_lst = &lmb.used_mem; @@ -530,6 +530,27 @@ long lmb_free(phys_addr_t base, phys_size_t size) rgn[i].flags); } +long lmb_free(phys_addr_t base, phys_size_t size) +{ + return __lmb_free(base, size); +} + +/** + * lmb_free_flags() - Free up a region of memory + * @base: Base Address of region to be freed + * @size: Size of the region to be freed + * @flags: Memory region attributes + * + * Free up a region of memory. + * + * Return: 0 if successful, -1 on failure + */ +long lmb_free_flags(phys_addr_t base, phys_size_t size, + __always_unused uint flags) +{ + return __lmb_free(base, size); +} + long lmb_reserve_flags(phys_addr_t base, phys_size_t size, enum lmb_flags flags) { struct alist *lmb_rgn_lst = &lmb.used_mem; @@ -613,6 +634,23 @@ phys_addr_t lmb_alloc(phys_size_t size, ulong align) return lmb_alloc_base(size, align, LMB_ALLOC_ANYWHERE); } +/** + * lmb_alloc_flags() - Allocate memory region with specified attributes + * @size: Size of the region requested + * @align: Alignment of the memory region requested + * @flags: Memory region attributes to be set + * + * Allocate a region of memory with the attributes specified through the + * parameter. + * + * Return: base address on success, 0 on error + */ +phys_addr_t lmb_alloc_flags(phys_size_t size, ulong align, uint flags) +{ + return __lmb_alloc_base(size, align, LMB_ALLOC_ANYWHERE, + flags); +} + phys_addr_t lmb_alloc_base(phys_size_t size, ulong align, phys_addr_t max_addr) { phys_addr_t alloc; @@ -626,6 +664,33 @@ phys_addr_t lmb_alloc_base(phys_size_t size, ulong align, phys_addr_t max_addr) return alloc; } +/** + * lmb_alloc_base_flags() - Allocate specified memory region with specified attributes + * @size: Size of the region requested + * @align: Alignment of the memory region requested + * @max_addr: Maximum address of the requested region + * @flags: Memory region attributes to be set + * + * Allocate a region of memory with the attributes specified through the + * parameter. The max_addr parameter is used to specify the maximum address + * below which the requested region should be allocated. + * + * Return: base address on success, 0 on error + */ +phys_addr_t lmb_alloc_base_flags(phys_size_t size, ulong align, + phys_addr_t max_addr, uint flags) +{ + phys_addr_t alloc; + + alloc = __lmb_alloc_base(size, align, max_addr, flags); + + if (alloc == 0) + printf("ERROR: Failed to allocate 0x%lx bytes below 0x%lx.\n", + (ulong)size, (ulong)max_addr); + + return alloc; +} + static phys_addr_t __lmb_alloc_addr(phys_addr_t base, phys_size_t size, enum lmb_flags flags) { @@ -660,6 +725,24 @@ phys_addr_t lmb_alloc_addr(phys_addr_t base, phys_size_t size) return __lmb_alloc_addr(base, size, LMB_NONE); } +/** + * lmb_alloc_addr_flags() - Allocate specified memory address with specified attributes + * @base: Base Address requested + * @size: Size of the region requested + * @flags: Memory region attributes to be set + * + * Allocate a region of memory with the attributes specified through the + * parameter. The base parameter is used to specify the base address + * of the requested region. + * + * Return: base address on success, 0 on error + */ +phys_addr_t lmb_alloc_addr_flags(phys_addr_t base, phys_size_t size, + uint flags) +{ + return __lmb_alloc_addr(base, size, flags); +} + /* Return number of bytes from a given address that are free */ phys_size_t lmb_get_free_size(phys_addr_t addr) { -- cgit v1.2.3 From 3c6896ad2fb876b0a23202f62a83c0d44380c9ea Mon Sep 17 00:00:00 2001 From: Sughosh Ganu Date: Tue, 15 Oct 2024 21:07:04 +0530 Subject: lmb: add a flag to allow suppressing memory map change notification Add a flag LMB_NONOTIFY that can be passed to the LMB API's for reserving memory. This will then result in no notification being sent from the LMB module for the changes to the LMB's memory map. While here, also add a description of the memory attributes that the flags signify. Signed-off-by: Sughosh Ganu --- lib/lmb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/lmb.c') diff --git a/lib/lmb.c b/lib/lmb.c index a38537af9c3..e1e616679f0 100644 --- a/lib/lmb.c +++ b/lib/lmb.c @@ -30,7 +30,7 @@ static struct lmb lmb; static void lmb_print_region_flags(enum lmb_flags flags) { u64 bitpos; - const char *flag_str[] = { "none", "no-map", "no-overwrite" }; + const char *flag_str[] = { "none", "no-map", "no-overwrite", "no-notify" }; do { bitpos = flags ? fls(flags) - 1 : 0; -- cgit v1.2.3 From eb052cbb896fee6f947765b44b0d80a54b19ce1a Mon Sep 17 00:00:00 2001 From: Sughosh Ganu Date: Tue, 15 Oct 2024 21:07:05 +0530 Subject: lmb: add and reserve memory above ram_top U-Boot does not use memory above ram_top. However, this memory does need to get registered as part of the memory map, so that subsystems like EFI pass it on to the operating system as part of the EFI memory map. Add memory above ram_top and reserve it with the LMB_NOOVERWRITE flag so that it does not get allocated or re-used. Signed-off-by: Sughosh Ganu Suggested-by: Mark Kettenis --- lib/lmb.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'lib/lmb.c') diff --git a/lib/lmb.c b/lib/lmb.c index e1e616679f0..0504a7b3407 100644 --- a/lib/lmb.c +++ b/lib/lmb.c @@ -281,7 +281,6 @@ void lmb_add_memory(void) { int i; phys_size_t size; - phys_addr_t rgn_top; u64 ram_top = gd->ram_top; struct bd_info *bd = gd->bd; @@ -292,16 +291,16 @@ void lmb_add_memory(void) for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { size = bd->bi_dram[i].size; if (size) { - if (bd->bi_dram[i].start > ram_top) - continue; - - rgn_top = bd->bi_dram[i].start + - bd->bi_dram[i].size; - - if (rgn_top > ram_top) - size -= rgn_top - ram_top; - lmb_add(bd->bi_dram[i].start, size); + + /* + * Reserve memory above ram_top as + * no-overwrite so that it cannot be + * allocated + */ + if (bd->bi_dram[i].start >= ram_top) + lmb_reserve_flags(bd->bi_dram[i].start, size, + LMB_NOOVERWRITE); } } } -- cgit v1.2.3 From 2f6191526a1325b6ddb59795a093eca69dbf8976 Mon Sep 17 00:00:00 2001 From: Sughosh Ganu Date: Tue, 15 Oct 2024 21:07:07 +0530 Subject: lmb: notify of any changes to the LMB memory map In U-Boot, LMB and EFI are two primary modules who provide memory allocation and reservation API's. Both these modules operate with the same regions of memory for allocations. Use the LMB memory map update event to notify other interested listeners about a change in it's memory map. This can then be used by the other module to keep track of available and used memory. There is no need to send these notifications when the LMB module is being unit-tested. Add a flag to the lmb structure to indicate if the memory map is being used for tests, and suppress sending any notifications when running these unit tests. Signed-off-by: Sughosh Ganu --- lib/lmb.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 92 insertions(+), 12 deletions(-) (limited to 'lib/lmb.c') diff --git a/lib/lmb.c b/lib/lmb.c index 0504a7b3407..e7167f858f0 100644 --- a/lib/lmb.c +++ b/lib/lmb.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -22,11 +23,52 @@ DECLARE_GLOBAL_DATA_PTR; +#define MAP_OP_RESERVE (u8)0x1 +#define MAP_OP_FREE (u8)0x2 +#define MAP_OP_ADD (u8)0x3 + #define LMB_ALLOC_ANYWHERE 0 #define LMB_ALIST_INITIAL_SIZE 4 static struct lmb lmb; +static bool lmb_should_notify(enum lmb_flags flags) +{ + return !lmb.test && !(flags & LMB_NONOTIFY) && + CONFIG_IS_ENABLED(EFI_LOADER); +} + +static int __maybe_unused lmb_map_update_notify(phys_addr_t addr, + phys_size_t size, + u8 op) +{ + u64 efi_addr; + u64 pages; + efi_status_t status; + + if (op != MAP_OP_RESERVE && op != MAP_OP_FREE && op != MAP_OP_ADD) { + log_err("Invalid map update op received (%d)\n", op); + return -1; + } + + efi_addr = (uintptr_t)map_sysmem(addr, 0); + pages = efi_size_in_pages(size + (efi_addr & EFI_PAGE_MASK)); + efi_addr &= ~EFI_PAGE_MASK; + + status = efi_add_memory_map_pg(efi_addr, pages, + op == MAP_OP_RESERVE ? + EFI_BOOT_SERVICES_DATA : + EFI_CONVENTIONAL_MEMORY, + false); + if (status != EFI_SUCCESS) { + log_err("%s: LMB Map notify failure %lu\n", __func__, + status & ~EFI_ERROR_MASK); + return -1; + } else { + return 0; + } +} + static void lmb_print_region_flags(enum lmb_flags flags) { u64 bitpos; @@ -473,9 +515,17 @@ static long lmb_add_region(struct alist *lmb_rgn_lst, phys_addr_t base, /* This routine may be called with relocation disabled. */ long lmb_add(phys_addr_t base, phys_size_t size) { + long ret; struct alist *lmb_rgn_lst = &lmb.free_mem; - return lmb_add_region(lmb_rgn_lst, base, size); + ret = lmb_add_region(lmb_rgn_lst, base, size); + if (ret) + return ret; + + if (lmb_should_notify(LMB_NONE)) + return lmb_map_update_notify(base, size, MAP_OP_ADD); + + return 0; } static long __lmb_free(phys_addr_t base, phys_size_t size) @@ -529,11 +579,6 @@ static long __lmb_free(phys_addr_t base, phys_size_t size) rgn[i].flags); } -long lmb_free(phys_addr_t base, phys_size_t size) -{ - return __lmb_free(base, size); -} - /** * lmb_free_flags() - Free up a region of memory * @base: Base Address of region to be freed @@ -545,16 +590,38 @@ long lmb_free(phys_addr_t base, phys_size_t size) * Return: 0 if successful, -1 on failure */ long lmb_free_flags(phys_addr_t base, phys_size_t size, - __always_unused uint flags) + uint flags) { - return __lmb_free(base, size); + long ret; + + ret = __lmb_free(base, size); + if (ret < 0) + return ret; + + if (lmb_should_notify(flags)) + return lmb_map_update_notify(base, size, MAP_OP_FREE); + + return ret; +} + +long lmb_free(phys_addr_t base, phys_size_t size) +{ + return lmb_free_flags(base, size, LMB_NONE); } long lmb_reserve_flags(phys_addr_t base, phys_size_t size, enum lmb_flags flags) { + long ret = 0; struct alist *lmb_rgn_lst = &lmb.used_mem; - return lmb_add_region_flags(lmb_rgn_lst, base, size, flags); + ret = lmb_add_region_flags(lmb_rgn_lst, base, size, flags); + if (ret < 0) + return -1; + + if (lmb_should_notify(flags)) + return lmb_map_update_notify(base, size, MAP_OP_RESERVE); + + return ret; } long lmb_reserve(phys_addr_t base, phys_size_t size) @@ -586,6 +653,8 @@ static phys_addr_t lmb_align_down(phys_addr_t addr, phys_size_t size) static phys_addr_t __lmb_alloc_base(phys_size_t size, ulong align, phys_addr_t max_addr, enum lmb_flags flags) { + u8 op; + int ret; long i, rgn; phys_addr_t base = 0; phys_addr_t res_base; @@ -616,6 +685,15 @@ static phys_addr_t __lmb_alloc_base(phys_size_t size, ulong align, if (lmb_add_region_flags(&lmb.used_mem, base, size, flags) < 0) return 0; + + if (lmb_should_notify(flags)) { + op = MAP_OP_RESERVE; + ret = lmb_map_update_notify(base, size, + op); + if (ret) + return ret; + } + return base; } @@ -785,7 +863,7 @@ int lmb_is_reserved_flags(phys_addr_t addr, int flags) return 0; } -static int lmb_setup(void) +static int lmb_setup(bool test) { bool ret; @@ -803,6 +881,8 @@ static int lmb_setup(void) return -ENOMEM; } + lmb.test = test; + return 0; } @@ -822,7 +902,7 @@ int lmb_init(void) { int ret; - ret = lmb_setup(); + ret = lmb_setup(false); if (ret) { log_info("Unable to init LMB\n"); return ret; @@ -850,7 +930,7 @@ int lmb_push(struct lmb *store) int ret; *store = lmb; - ret = lmb_setup(); + ret = lmb_setup(true); if (ret) return ret; -- cgit v1.2.3 From 497da0c5ce9084fed8166b18b4f1f9dbe1532034 Mon Sep 17 00:00:00 2001 From: Sughosh Ganu Date: Tue, 15 Oct 2024 21:07:11 +0530 Subject: lmb: allow for boards to specify memory map Some architectures have special or unique aspects which need consideration when adding memory ranges to the list of available memory map. Enable this config in such scenarios which allow architectures and boards to define their own memory map. Signed-off-by: Sughosh Ganu --- lib/lmb.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'lib/lmb.c') diff --git a/lib/lmb.c b/lib/lmb.c index e7167f858f0..ae69201d5b7 100644 --- a/lib/lmb.c +++ b/lib/lmb.c @@ -326,6 +326,9 @@ void lmb_add_memory(void) u64 ram_top = gd->ram_top; struct bd_info *bd = gd->bd; + if (CONFIG_IS_ENABLED(LMB_ARCH_MEM_MAP)) + return lmb_arch_add_memory(); + /* Assume a 4GB ram_top if not defined */ if (!ram_top) ram_top = 0x100000000ULL; -- cgit v1.2.3 From 596516d3301ef7b6594dc5d24bc8fd4461279437 Mon Sep 17 00:00:00 2001 From: Sughosh Ganu Date: Tue, 15 Oct 2024 21:07:15 +0530 Subject: lmb: remove call to efi_lmb_reserve() The EFI memory allocations are now being done through the LMB module. With this change, there is no need to get the EFI memory map and set aside EFI allocated memory. Signed-off-by: Sughosh Ganu Reviewed-by: Ilias Apalodimas Reviewed-by: Simon Glass --- lib/lmb.c | 35 ----------------------------------- 1 file changed, 35 deletions(-) (limited to 'lib/lmb.c') diff --git a/lib/lmb.c b/lib/lmb.c index ae69201d5b7..f3a1d8ca256 100644 --- a/lib/lmb.c +++ b/lib/lmb.c @@ -204,38 +204,6 @@ static void lmb_fix_over_lap_regions(struct alist *lmb_rgn_lst, lmb_remove_region(lmb_rgn_lst, r2); } -/** - * efi_lmb_reserve() - add reservations for EFI memory - * - * Add reservations for all EFI memory areas that are not - * EFI_CONVENTIONAL_MEMORY. - * - * Return: 0 on success, 1 on failure - */ -static __maybe_unused int efi_lmb_reserve(void) -{ - struct efi_mem_desc *memmap = NULL, *map; - efi_uintn_t i, map_size = 0; - efi_status_t ret; - - ret = efi_get_memory_map_alloc(&map_size, &memmap); - if (ret != EFI_SUCCESS) - return 1; - - for (i = 0, map = memmap; i < map_size / sizeof(*map); ++map, ++i) { - if (map->type != EFI_CONVENTIONAL_MEMORY) { - lmb_reserve_flags(map_to_sysmem((void *)(uintptr_t) - map->physical_start), - map->num_pages * EFI_PAGE_SIZE, - map->type == EFI_RESERVED_MEMORY_TYPE - ? LMB_NOMAP : LMB_NONE); - } - } - efi_free_pool(memmap); - - return 0; -} - static void lmb_reserve_uboot_region(void) { int bank; @@ -282,9 +250,6 @@ static void lmb_reserve_common(void *fdt_blob) if (CONFIG_IS_ENABLED(OF_LIBFDT) && fdt_blob) boot_fdt_add_mem_rsv_regions(fdt_blob); - - if (CONFIG_IS_ENABLED(EFI_LOADER)) - efi_lmb_reserve(); } static __maybe_unused void lmb_reserve_common_spl(void) -- cgit v1.2.3 From 8d0df5fde3b8d4083936129e0c01884f9555f197 Mon Sep 17 00:00:00 2001 From: Sughosh Ganu Date: Tue, 15 Oct 2024 21:07:17 +0530 Subject: lmb: replace the double-underscore with single-underscore for all functions A bunch of static functions in the LMB module have used a double-undersore for the function names. It was suggested to use a single-underscore instead, as the double-underscore is usually used by library functions. Replace the double-underscore with single-underscore for all functions. Signed-off-by: Sughosh Ganu Suggested-by: Simon Glass --- lib/lmb.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'lib/lmb.c') diff --git a/lib/lmb.c b/lib/lmb.c index f3a1d8ca256..78fe2d4de7c 100644 --- a/lib/lmb.c +++ b/lib/lmb.c @@ -496,7 +496,7 @@ long lmb_add(phys_addr_t base, phys_size_t size) return 0; } -static long __lmb_free(phys_addr_t base, phys_size_t size) +static long _lmb_free(phys_addr_t base, phys_size_t size) { struct lmb_region *rgn; struct alist *lmb_rgn_lst = &lmb.used_mem; @@ -562,7 +562,7 @@ long lmb_free_flags(phys_addr_t base, phys_size_t size, { long ret; - ret = __lmb_free(base, size); + ret = _lmb_free(base, size); if (ret < 0) return ret; @@ -618,7 +618,7 @@ static phys_addr_t lmb_align_down(phys_addr_t addr, phys_size_t size) return addr & ~(size - 1); } -static phys_addr_t __lmb_alloc_base(phys_size_t size, ulong align, +static phys_addr_t _lmb_alloc_base(phys_size_t size, ulong align, phys_addr_t max_addr, enum lmb_flags flags) { u8 op; @@ -692,15 +692,15 @@ phys_addr_t lmb_alloc(phys_size_t size, ulong align) */ phys_addr_t lmb_alloc_flags(phys_size_t size, ulong align, uint flags) { - return __lmb_alloc_base(size, align, LMB_ALLOC_ANYWHERE, - flags); + return _lmb_alloc_base(size, align, LMB_ALLOC_ANYWHERE, + flags); } phys_addr_t lmb_alloc_base(phys_size_t size, ulong align, phys_addr_t max_addr) { phys_addr_t alloc; - alloc = __lmb_alloc_base(size, align, max_addr, LMB_NONE); + alloc = _lmb_alloc_base(size, align, max_addr, LMB_NONE); if (alloc == 0) printf("ERROR: Failed to allocate 0x%lx bytes below 0x%lx.\n", @@ -727,7 +727,7 @@ phys_addr_t lmb_alloc_base_flags(phys_size_t size, ulong align, { phys_addr_t alloc; - alloc = __lmb_alloc_base(size, align, max_addr, flags); + alloc = _lmb_alloc_base(size, align, max_addr, flags); if (alloc == 0) printf("ERROR: Failed to allocate 0x%lx bytes below 0x%lx.\n", @@ -736,7 +736,7 @@ phys_addr_t lmb_alloc_base_flags(phys_size_t size, ulong align, return alloc; } -static phys_addr_t __lmb_alloc_addr(phys_addr_t base, phys_size_t size, +static phys_addr_t _lmb_alloc_addr(phys_addr_t base, phys_size_t size, enum lmb_flags flags) { long rgn; @@ -767,7 +767,7 @@ static phys_addr_t __lmb_alloc_addr(phys_addr_t base, phys_size_t size, */ phys_addr_t lmb_alloc_addr(phys_addr_t base, phys_size_t size) { - return __lmb_alloc_addr(base, size, LMB_NONE); + return _lmb_alloc_addr(base, size, LMB_NONE); } /** @@ -785,7 +785,7 @@ phys_addr_t lmb_alloc_addr(phys_addr_t base, phys_size_t size) phys_addr_t lmb_alloc_addr_flags(phys_addr_t base, phys_size_t size, uint flags) { - return __lmb_alloc_addr(base, size, flags); + return _lmb_alloc_addr(base, size, flags); } /* Return number of bytes from a given address that are free */ -- cgit v1.2.3