[PATCH v3 0/7] Allow showing the memory map

This little series adds a new 'memmap' command, intended to show the layout of memory within U-Boot and how much memory is available for loading images.
Changes in v3: - Add a new Kconfig for the extra functionality
Changes in v2: - Split into its own patch - Modify the existing 'meminfo' command instead
Simon Glass (7): common: Fix up malloc() comment in reserve_noncached() common: Tidy up how malloc() is inited am65x: Use map_to_sysmem() to convert from pointer global_data: Add some more accessors bootstage: Allow counting memory without strings cmd: Move meminfo command into its own file cmd: Update the meminfo command to show the memory map
arch/arm/mach-k3/am65x/am654_init.c | 11 +-- cmd/Kconfig | 12 +++ cmd/Makefile | 1 + cmd/mem.c | 19 ----- cmd/meminfo.c | 75 ++++++++++++++++ common/board_f.c | 8 +- common/board_r.c | 3 +- common/bootstage.c | 16 ++-- common/dlmalloc.c | 8 +- common/spl/spl.c | 4 +- doc/usage/cmd/meminfo.rst | 128 ++++++++++++++++++++++++++++ doc/usage/index.rst | 1 + include/asm-generic/global_data.h | 30 +++++++ include/bootstage.h | 5 +- include/malloc.h | 8 ++ test/cmd/Makefile | 3 +- test/cmd/meminfo.c | 38 +++++++++ 17 files changed, 324 insertions(+), 46 deletions(-) create mode 100644 cmd/meminfo.c create mode 100644 doc/usage/cmd/meminfo.rst create mode 100644 test/cmd/meminfo.c

The function name has changed, so update it.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
common/board_f.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/common/board_f.c b/common/board_f.c index f1bd70fdd6c..a87411ee350 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -501,9 +501,9 @@ static unsigned long reserve_stack_aligned(size_t size) static int reserve_noncached(void) { /* - * The value of gd->start_addr_sp must match the value of malloc_start - * calculated in board_r.c:initr_malloc(), which is passed to - * dlmalloc.c:mem_malloc_init() and then used by + * The value of gd->start_addr_sp must match the value of + * mem_malloc_start calculated in board_r.c:initr_malloc(), which is + * passed to dlmalloc.c:mem_malloc_init() and then used by * cache.c:noncached_init() * * These calculations must match the code in cache.c:noncached_init()

The call to malloc() is a bit strange. The naming of the arguments suggests that an address is passed, but in fact it is a pointer, at least in the board_init_r() function and SPL equivalent.
Update it to work as described. Add a function comment as well.
Note that this does adjustment does not extend into the malloc() implementation itself, apart from changing mem_malloc_init(), since there are lots of casts and pointers and integers are used interchangeably.
Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Tom Rini trini@konsulko.com ---
(no changes since v1)
common/board_r.c | 3 +-- common/dlmalloc.c | 8 +++++--- common/spl/spl.c | 4 +--- include/malloc.h | 8 ++++++++ 4 files changed, 15 insertions(+), 8 deletions(-)
diff --git a/common/board_r.c b/common/board_r.c index 1acad069d92..60eba0942d8 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -204,8 +204,7 @@ static int initr_malloc(void) */ start = gd->relocaddr - TOTAL_MALLOC_LEN; gd_set_malloc_start(start); - mem_malloc_init((ulong)map_sysmem(start, TOTAL_MALLOC_LEN), - TOTAL_MALLOC_LEN); + mem_malloc_init(start, TOTAL_MALLOC_LEN); return 0; }
diff --git a/common/dlmalloc.c b/common/dlmalloc.c index 1ac7ce3f43c..cc4d3a0a028 100644 --- a/common/dlmalloc.c +++ b/common/dlmalloc.c @@ -16,6 +16,8 @@ #include <asm/global_data.h>
#include <malloc.h> +#include <mapmem.h> +#include <string.h> #include <asm/io.h> #include <valgrind/memcheck.h>
@@ -598,9 +600,9 @@ void *sbrk(ptrdiff_t increment)
void mem_malloc_init(ulong start, ulong size) { - mem_malloc_start = start; - mem_malloc_end = start + size; - mem_malloc_brk = start; + mem_malloc_start = (ulong)map_sysmem(start, size); + mem_malloc_end = mem_malloc_start + size; + mem_malloc_brk = mem_malloc_start;
#ifdef CONFIG_SYS_MALLOC_DEFAULT_TO_INIT malloc_init(); diff --git a/common/spl/spl.c b/common/spl/spl.c index 94657d00591..1ceb63daf31 100644 --- a/common/spl/spl.c +++ b/common/spl/spl.c @@ -678,9 +678,7 @@ void board_init_r(gd_t *dummy1, ulong dummy2) spl_set_bd();
if (IS_ENABLED(CONFIG_SPL_SYS_MALLOC)) { - mem_malloc_init((ulong)map_sysmem(SPL_SYS_MALLOC_START, - SPL_SYS_MALLOC_SIZE), - SPL_SYS_MALLOC_SIZE); + mem_malloc_init(SPL_SYS_MALLOC_START, SPL_SYS_MALLOC_SIZE); gd->flags |= GD_FLG_FULL_MALLOC_INIT; } if (!(gd->flags & GD_FLG_SPL_INIT)) { diff --git a/include/malloc.h b/include/malloc.h index 07d3e90a855..9e0be482416 100644 --- a/include/malloc.h +++ b/include/malloc.h @@ -981,6 +981,14 @@ extern ulong mem_malloc_start; extern ulong mem_malloc_end; extern ulong mem_malloc_brk;
+/** + * mem_malloc_init() - Set up the malloc() pool + * + * Sets the region of memory to be used for all future calls to malloc(), etc. + * + * @start: Start address + * @size: Size in bytes + */ void mem_malloc_init(ulong start, ulong size);
#ifdef __cplusplus

Hi Simon,
I did review enough of this series in v1 [0]. Please resend it with the proper tags added. Did anything change and you dropped by r-b? Because the changelog says no changes
On Tue, 15 Oct 2024 at 16:33, Simon Glass sjg@chromium.org wrote:
The call to malloc() is a bit strange. The naming of the arguments suggests that an address is passed, but in fact it is a pointer, at least in the board_init_r() function and SPL equivalent.
Update it to work as described. Add a function comment as well.
Note that this does adjustment does not extend into the malloc() implementation itself, apart from changing mem_malloc_init(), since there are lots of casts and pointers and integers are used interchangeably.
Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Tom Rini trini@konsulko.com
(no changes since v1)
common/board_r.c | 3 +-- common/dlmalloc.c | 8 +++++--- common/spl/spl.c | 4 +--- include/malloc.h | 8 ++++++++ 4 files changed, 15 insertions(+), 8 deletions(-)
diff --git a/common/board_r.c b/common/board_r.c index 1acad069d92..60eba0942d8 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -204,8 +204,7 @@ static int initr_malloc(void) */ start = gd->relocaddr - TOTAL_MALLOC_LEN; gd_set_malloc_start(start);
mem_malloc_init((ulong)map_sysmem(start, TOTAL_MALLOC_LEN),
TOTAL_MALLOC_LEN);
mem_malloc_init(start, TOTAL_MALLOC_LEN); return 0;
}
diff --git a/common/dlmalloc.c b/common/dlmalloc.c index 1ac7ce3f43c..cc4d3a0a028 100644 --- a/common/dlmalloc.c +++ b/common/dlmalloc.c @@ -16,6 +16,8 @@ #include <asm/global_data.h>
#include <malloc.h> +#include <mapmem.h> +#include <string.h> #include <asm/io.h> #include <valgrind/memcheck.h>
@@ -598,9 +600,9 @@ void *sbrk(ptrdiff_t increment)
void mem_malloc_init(ulong start, ulong size) {
mem_malloc_start = start;
mem_malloc_end = start + size;
mem_malloc_brk = start;
mem_malloc_start = (ulong)map_sysmem(start, size);
mem_malloc_end = mem_malloc_start + size;
mem_malloc_brk = mem_malloc_start;
#ifdef CONFIG_SYS_MALLOC_DEFAULT_TO_INIT malloc_init(); diff --git a/common/spl/spl.c b/common/spl/spl.c index 94657d00591..1ceb63daf31 100644 --- a/common/spl/spl.c +++ b/common/spl/spl.c @@ -678,9 +678,7 @@ void board_init_r(gd_t *dummy1, ulong dummy2) spl_set_bd();
if (IS_ENABLED(CONFIG_SPL_SYS_MALLOC)) {
mem_malloc_init((ulong)map_sysmem(SPL_SYS_MALLOC_START,
SPL_SYS_MALLOC_SIZE),
SPL_SYS_MALLOC_SIZE);
mem_malloc_init(SPL_SYS_MALLOC_START, SPL_SYS_MALLOC_SIZE); gd->flags |= GD_FLG_FULL_MALLOC_INIT; } if (!(gd->flags & GD_FLG_SPL_INIT)) {
diff --git a/include/malloc.h b/include/malloc.h index 07d3e90a855..9e0be482416 100644 --- a/include/malloc.h +++ b/include/malloc.h @@ -981,6 +981,14 @@ extern ulong mem_malloc_start; extern ulong mem_malloc_end; extern ulong mem_malloc_brk;
+/**
- mem_malloc_init() - Set up the malloc() pool
- Sets the region of memory to be used for all future calls to malloc(), etc.
- @start: Start address
- @size: Size in bytes
- */
void mem_malloc_init(ulong start, ulong size);
#ifdef __cplusplus
2.34.1
[0] https://lore.kernel.org/u-boot/CAFLszThRCmPDfPxWZf9ZhbwcHLNhdUrzNCLwJKkz=17x...

Hi Ilias,
On Tue, 15 Oct 2024 at 07:38, Ilias Apalodimas ilias.apalodimas@linaro.org wrote:
Hi Simon,
I did review enough of this series in v1 [0]. Please resend it with the proper tags added. Did anything change and you dropped by r-b? Because the changelog says no changes
I collect tags with patman...it still doesn't see anything. Which patch are you referring to?
On Tue, 15 Oct 2024 at 16:33, Simon Glass sjg@chromium.org wrote:
The call to malloc() is a bit strange. The naming of the arguments suggests that an address is passed, but in fact it is a pointer, at least in the board_init_r() function and SPL equivalent.
Update it to work as described. Add a function comment as well.
Note that this does adjustment does not extend into the malloc() implementation itself, apart from changing mem_malloc_init(), since there are lots of casts and pointers and integers are used interchangeably.
Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Tom Rini trini@konsulko.com
(no changes since v1)
common/board_r.c | 3 +-- common/dlmalloc.c | 8 +++++--- common/spl/spl.c | 4 +--- include/malloc.h | 8 ++++++++ 4 files changed, 15 insertions(+), 8 deletions(-)
Regards, Simon

Simon,
On Tue, 15 Oct 2024 at 18:28, Simon Glass sjg@chromium.org wrote:
Hi Ilias,
On Tue, 15 Oct 2024 at 07:38, Ilias Apalodimas ilias.apalodimas@linaro.org wrote:
Hi Simon,
I did review enough of this series in v1 [0]. Please resend it with the proper tags added. Did anything change and you dropped by r-b? Because the changelog says no changes
I collect tags with patman...it still doesn't see anything. Which patch are you referring to?
It's in my response
Thanks /Ilias
On Tue, 15 Oct 2024 at 16:33, Simon Glass sjg@chromium.org wrote:
The call to malloc() is a bit strange. The naming of the arguments suggests that an address is passed, but in fact it is a pointer, at least in the board_init_r() function and SPL equivalent.
Update it to work as described. Add a function comment as well.
Note that this does adjustment does not extend into the malloc() implementation itself, apart from changing mem_malloc_init(), since there are lots of casts and pointers and integers are used interchangeably.
Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Tom Rini trini@konsulko.com
(no changes since v1)
common/board_r.c | 3 +-- common/dlmalloc.c | 8 +++++--- common/spl/spl.c | 4 +--- include/malloc.h | 8 ++++++++ 4 files changed, 15 insertions(+), 8 deletions(-)
Regards, Simon

Hi Ilias,
On Tue, 15 Oct 2024 at 13:24, Ilias Apalodimas ilias.apalodimas@linaro.org wrote:
Simon,
On Tue, 15 Oct 2024 at 18:28, Simon Glass sjg@chromium.org wrote:
Hi Ilias,
On Tue, 15 Oct 2024 at 07:38, Ilias Apalodimas ilias.apalodimas@linaro.org wrote:
Hi Simon,
I did review enough of this series in v1 [0]. Please resend it with the proper tags added. Did anything change and you dropped by r-b? Because the changelog says no changes
I collect tags with patman...it still doesn't see anything. Which patch are you referring to?
It's in my response
Oh I see, I missed it from the v1 series. Well, this is on hold for now as Tom has asked for lmb in the memory-map listing. But I've collected your tags.
Regards, Simon

The board_init_f() function for am65x is a bit confusing, since it uses the variable name 'pool_addr' to hold a pointer. It then casts it to an address to pass to mem_alloc_init()
Rename the variable and use mapmem to convert to an address.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
arch/arm/mach-k3/am65x/am654_init.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/arch/arm/mach-k3/am65x/am654_init.c b/arch/arm/mach-k3/am65x/am654_init.c index a4f038029d7..ddcc1355210 100644 --- a/arch/arm/mach-k3/am65x/am654_init.c +++ b/arch/arm/mach-k3/am65x/am654_init.c @@ -8,6 +8,7 @@
#include <fdt_support.h> #include <init.h> +#include <mapmem.h> #include <asm/global_data.h> #include <asm/io.h> #include <spl.h> @@ -165,7 +166,7 @@ void board_init_f(ulong dummy) #if defined(CONFIG_K3_LOAD_SYSFW) || defined(CONFIG_K3_AM654_DDRSS) struct udevice *dev; size_t pool_size; - void *pool_addr; + void *pool; int ret; #endif /* @@ -204,14 +205,14 @@ void board_init_f(ulong dummy) * malloc pool of which we use all that's left. */ pool_size = CONFIG_VAL(SYS_MALLOC_F_LEN) - gd->malloc_ptr; - pool_addr = malloc(pool_size); - if (!pool_addr) + pool = malloc(pool_size); + if (!pool) panic("ERROR: Can't allocate full malloc pool!\n");
- mem_malloc_init((ulong)pool_addr, (ulong)pool_size); + mem_malloc_init(map_to_sysmem(pool), (ulong)pool_size); gd->flags |= GD_FLG_FULL_MALLOC_INIT; debug("%s: initialized an early full malloc pool at 0x%08lx of 0x%lx bytes\n", - __func__, (unsigned long)pool_addr, (unsigned long)pool_size); + __func__, (unsigned long)pool, (unsigned long)pool_size); /* * Process pinctrl for the serial0 a.k.a. WKUP_UART0 module and continue * regardless of the result of pinctrl. Do this without probing the

On Tue, Oct 15, 2024 at 07:33:00AM -0600, Simon Glass wrote:
The board_init_f() function for am65x is a bit confusing, since it uses the variable name 'pool_addr' to hold a pointer. It then casts it to an address to pass to mem_alloc_init()
Rename the variable and use mapmem to convert to an address.
Signed-off-by: Simon Glass sjg@chromium.org
(no changes since v1)
arch/arm/mach-k3/am65x/am654_init.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/arch/arm/mach-k3/am65x/am654_init.c b/arch/arm/mach-k3/am65x/am654_init.c index a4f038029d7..ddcc1355210 100644 --- a/arch/arm/mach-k3/am65x/am654_init.c +++ b/arch/arm/mach-k3/am65x/am654_init.c @@ -8,6 +8,7 @@
#include <fdt_support.h> #include <init.h> +#include <mapmem.h> #include <asm/global_data.h> #include <asm/io.h> #include <spl.h> @@ -165,7 +166,7 @@ void board_init_f(ulong dummy) #if defined(CONFIG_K3_LOAD_SYSFW) || defined(CONFIG_K3_AM654_DDRSS) struct udevice *dev; size_t pool_size;
- void *pool_addr;
- void *pool; int ret;
#endif /* @@ -204,14 +205,14 @@ void board_init_f(ulong dummy) * malloc pool of which we use all that's left. */ pool_size = CONFIG_VAL(SYS_MALLOC_F_LEN) - gd->malloc_ptr;
- pool_addr = malloc(pool_size);
- if (!pool_addr)
- pool = malloc(pool_size);
- if (!pool) panic("ERROR: Can't allocate full malloc pool!\n");
- mem_malloc_init((ulong)pool_addr, (ulong)pool_size);
- mem_malloc_init(map_to_sysmem(pool), (ulong)pool_size); gd->flags |= GD_FLG_FULL_MALLOC_INIT; debug("%s: initialized an early full malloc pool at 0x%08lx of 0x%lx bytes\n",
__func__, (unsigned long)pool_addr, (unsigned long)pool_size);
/*__func__, (unsigned long)pool, (unsigned long)pool_size);
- Process pinctrl for the serial0 a.k.a. WKUP_UART0 module and continue
- regardless of the result of pinctrl. Do this without probing the
This covers half of what we talked about in v2. But map_to_sysmem() is a sandbox thing that should not be called outside of (a) arch/sandbox or (b) common code that runs on sandbox. And honestly, we should work to hide that abstraction as much as we can, not start introducing it more.

Hi Tom,
On Tue, 15 Oct 2024 at 08:37, Tom Rini trini@konsulko.com wrote:
On Tue, Oct 15, 2024 at 07:33:00AM -0600, Simon Glass wrote:
The board_init_f() function for am65x is a bit confusing, since it uses the variable name 'pool_addr' to hold a pointer. It then casts it to an address to pass to mem_alloc_init()
Rename the variable and use mapmem to convert to an address.
Signed-off-by: Simon Glass sjg@chromium.org
(no changes since v1)
arch/arm/mach-k3/am65x/am654_init.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/arch/arm/mach-k3/am65x/am654_init.c b/arch/arm/mach-k3/am65x/am654_init.c index a4f038029d7..ddcc1355210 100644 --- a/arch/arm/mach-k3/am65x/am654_init.c +++ b/arch/arm/mach-k3/am65x/am654_init.c @@ -8,6 +8,7 @@
#include <fdt_support.h> #include <init.h> +#include <mapmem.h> #include <asm/global_data.h> #include <asm/io.h> #include <spl.h> @@ -165,7 +166,7 @@ void board_init_f(ulong dummy) #if defined(CONFIG_K3_LOAD_SYSFW) || defined(CONFIG_K3_AM654_DDRSS) struct udevice *dev; size_t pool_size;
void *pool_addr;
void *pool; int ret;
#endif /* @@ -204,14 +205,14 @@ void board_init_f(ulong dummy) * malloc pool of which we use all that's left. */ pool_size = CONFIG_VAL(SYS_MALLOC_F_LEN) - gd->malloc_ptr;
pool_addr = malloc(pool_size);
if (!pool_addr)
pool = malloc(pool_size);
if (!pool) panic("ERROR: Can't allocate full malloc pool!\n");
mem_malloc_init((ulong)pool_addr, (ulong)pool_size);
mem_malloc_init(map_to_sysmem(pool), (ulong)pool_size); gd->flags |= GD_FLG_FULL_MALLOC_INIT; debug("%s: initialized an early full malloc pool at 0x%08lx of 0x%lx bytes\n",
__func__, (unsigned long)pool_addr, (unsigned long)pool_size);
__func__, (unsigned long)pool, (unsigned long)pool_size); /* * Process pinctrl for the serial0 a.k.a. WKUP_UART0 module and continue * regardless of the result of pinctrl. Do this without probing the
This covers half of what we talked about in v2. But map_to_sysmem() is a sandbox thing that should not be called outside of (a) arch/sandbox or (b) common code that runs on sandbox. And honestly, we should work to hide that abstraction as much as we can, not start introducing it more.
Yes that's right. Perhaps we should document that.
We can drop this patch.
Regards, Simon

Add accessors for bloblist, bootstage, trace and video to avoid needing more #ifdefs in the C code.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
include/asm-generic/global_data.h | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+)
diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h index 644a0d77873..9dc0f4308cc 100644 --- a/include/asm-generic/global_data.h +++ b/include/asm-generic/global_data.h @@ -544,6 +544,36 @@ static_assert(sizeof(struct global_data) == GD_SIZE); #define gd_set_upl(val) #endif
+#if CONFIG_IS_ENABLED(BLOBLIST) +#define gd_bloblist() gd->bloblist +#else +#define gd_bloblist() NULL +#endif + +#if CONFIG_IS_ENABLED(BOOTSTAGE) +#define gd_bootstage() gd->bootstage +#else +#define gd_bootstage() NULL +#endif + +#if CONFIG_IS_ENABLED(TRACE) +#define gd_trace_buff() gd->trace_buff +#define gd_trace_size() CONFIG_TRACE_BUFFER_SIZE +#else +#define gd_trace_buff() NULL +#define gd_trace_size() 0 +#endif + +#if CONFIG_IS_ENABLED(VIDEO) +#define gd_video_top() gd->video_top +#define gd_video_bottom() gd->video_bottom +#define gd_video_size() (gd->video_top - gd->video_bottom) +#else +#define gd_video_top() 0 +#define gd_video_bottom() 0 +#define gd_video_size() 0 +#endif + /** * enum gd_flags - global data flags *

The bootstage array includes pointers to strings but not the strings themselves. The strings are added when stashing, but including them in the size calculation gives an inflated view of the amount of space used by the array.
Update this function so it can return the amount of memory used by the bootstage structures themselves, without the strings which they point to.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
common/board_f.c | 2 +- common/bootstage.c | 16 +++++++++------- include/bootstage.h | 5 +++-- 3 files changed, 13 insertions(+), 10 deletions(-)
diff --git a/common/board_f.c b/common/board_f.c index a87411ee350..98dc2591e1d 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -582,7 +582,7 @@ static int reserve_fdt(void) static int reserve_bootstage(void) { #ifdef CONFIG_BOOTSTAGE - int size = bootstage_get_size(); + int size = bootstage_get_size(true);
gd->start_addr_sp = reserve_stack_aligned(size); gd->boardf->new_bootstage = map_sysmem(gd->start_addr_sp, size); diff --git a/common/bootstage.c b/common/bootstage.c index dd6aed7c2fd..c7bb204501a 100644 --- a/common/bootstage.c +++ b/common/bootstage.c @@ -520,17 +520,19 @@ int _bootstage_unstash_default(void) } #endif
-int bootstage_get_size(void) +int bootstage_get_size(bool add_strings) { - struct bootstage_data *data = gd->bootstage; - struct bootstage_record *rec; int size; - int i;
size = sizeof(struct bootstage_data); - for (rec = data->record, i = 0; i < data->rec_count; - i++, rec++) - size += strlen(rec->name) + 1; + if (add_strings) { + struct bootstage_data *data = gd->bootstage; + struct bootstage_record *rec; + int i; + + for (rec = data->record, i = 0; i < data->rec_count; i++, rec++) + size += strlen(rec->name) + 1; + }
return size; } diff --git a/include/bootstage.h b/include/bootstage.h index 57792648c49..3300ca0248a 100644 --- a/include/bootstage.h +++ b/include/bootstage.h @@ -371,9 +371,10 @@ int bootstage_unstash(const void *base, int size); /** * bootstage_get_size() - Get the size of the bootstage data * + * @add_strings: true to add the size of attached strings (for stashing) * Return: size of boostage data in bytes */ -int bootstage_get_size(void); +int bootstage_get_size(bool add_strings);
/** * bootstage_init() - Prepare bootstage for use @@ -444,7 +445,7 @@ static inline int bootstage_unstash(const void *base, int size) return 0; /* Pretend to succeed */ }
-static inline int bootstage_get_size(void) +static inline int bootstage_get_size(bool add_strings) { return 0; }

In preparation for expanding this command, move it into a separate file. Rename the function to remove the extra underscore. Update the number of arguments to 1, since 3 is incorrect.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v2)
Changes in v2: - Split into its own patch
cmd/Kconfig | 1 + cmd/Makefile | 1 + cmd/mem.c | 19 ------------------- cmd/meminfo.c | 26 ++++++++++++++++++++++++++ 4 files changed, 28 insertions(+), 19 deletions(-) create mode 100644 cmd/meminfo.c
diff --git a/cmd/Kconfig b/cmd/Kconfig index 37894eb80d6..2fd29e9fa88 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -878,6 +878,7 @@ config MD5SUM_VERIFY
config CMD_MEMINFO bool "meminfo" + default y if SANDBOX help Display memory information.
diff --git a/cmd/Makefile b/cmd/Makefile index 21d376309b9..b630756a629 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -110,6 +110,7 @@ obj-$(CONFIG_CMD_LOG) += log.o obj-$(CONFIG_CMD_LSBLK) += lsblk.o obj-$(CONFIG_CMD_MD5SUM) += md5sum.o obj-$(CONFIG_CMD_MEMORY) += mem.o +obj-$(CONFIG_CMD_MEMINFO) += meminfo.o obj-$(CONFIG_CMD_IO) += io.o obj-$(CONFIG_CMD_MII) += mii.o obj-$(CONFIG_CMD_MISC) += misc.o diff --git a/cmd/mem.c b/cmd/mem.c index 4d6fde28531..9e716776393 100644 --- a/cmd/mem.c +++ b/cmd/mem.c @@ -1379,17 +1379,6 @@ U_BOOT_CMD(
#endif
-#ifdef CONFIG_CMD_MEMINFO -static int do_mem_info(struct cmd_tbl *cmdtp, int flag, int argc, - char *const argv[]) -{ - puts("DRAM: "); - print_size(gd->ram_size, "\n"); - - return 0; -} -#endif - U_BOOT_CMD( base, 2, 1, do_mem_base, "print or set address offset", @@ -1433,14 +1422,6 @@ U_BOOT_CMD( ); #endif /* CONFIG_CMD_MX_CYCLIC */
-#ifdef CONFIG_CMD_MEMINFO -U_BOOT_CMD( - meminfo, 3, 1, do_mem_info, - "display memory information", - "" -); -#endif - #ifdef CONFIG_CMD_RANDOM U_BOOT_CMD( random, 4, 0, do_random, diff --git a/cmd/meminfo.c b/cmd/meminfo.c new file mode 100644 index 00000000000..bb9bcec2e3f --- /dev/null +++ b/cmd/meminfo.c @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2024 Google LLC + * Written by Simon Glass sjg@chromium.org + */ + +#include <command.h> +#include <display_options.h> +#include <asm/global_data.h> + +DECLARE_GLOBAL_DATA_PTR; + +static int do_meminfo(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + puts("DRAM: "); + print_size(gd->ram_size, "\n"); + + return 0; +} + +U_BOOT_CMD( + meminfo, 1, 1, do_meminfo, + "display memory information", + "" +);

U-Boot has a fairly rigid memory map which is normally not visible unless debugging is enabled in board_f.c
Update the 'meminfo' command to show it. This command does not cover arch-specific pieces but gives a good overview of where things are.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: - Add a new Kconfig for the extra functionality
Changes in v2: - Modify the existing 'meminfo' command instead
cmd/Kconfig | 11 ++++ cmd/meminfo.c | 51 ++++++++++++++- doc/usage/cmd/meminfo.rst | 128 ++++++++++++++++++++++++++++++++++++++ doc/usage/index.rst | 1 + test/cmd/Makefile | 3 +- test/cmd/meminfo.c | 38 +++++++++++ 6 files changed, 230 insertions(+), 2 deletions(-) create mode 100644 doc/usage/cmd/meminfo.rst create mode 100644 test/cmd/meminfo.c
diff --git a/cmd/Kconfig b/cmd/Kconfig index 2fd29e9fa88..fd8060c2c34 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -882,6 +882,17 @@ config CMD_MEMINFO help Display memory information.
+config CMD_MEMINFO_MAP + bool "- with memory map" + depends on CMD_MEMINFO + default y if SANDBOX + help + Shows a memory map, in addition to just the DRAM size. This allows + seeing where U-Boot's memory area is, at the top of DRAM, as well as + detail about each piece of it. + + See doc/usage/cmd/meminfo.rst for more information. + config CMD_MEMORY bool "md, mm, nm, mw, cp, cmp, base, loop" default y diff --git a/cmd/meminfo.c b/cmd/meminfo.c index bb9bcec2e3f..0e6d2f9cc2c 100644 --- a/cmd/meminfo.c +++ b/cmd/meminfo.c @@ -4,18 +4,67 @@ * Written by Simon Glass sjg@chromium.org */
+#include <bloblist.h> +#include <bootstage.h> #include <command.h> #include <display_options.h> +#include <malloc.h> +#include <mapmem.h> #include <asm/global_data.h>
DECLARE_GLOBAL_DATA_PTR;
+static void print_region(const char *name, ulong base, ulong size, ulong *uptop) +{ + ulong end = base + size; + + printf("%-12s %8lx %8lx %8lx", name, base, size, end); + if (*uptop) + printf(" %8lx", *uptop - end); + putc('\n'); + *uptop = base; +} + static int do_meminfo(struct cmd_tbl *cmdtp, int flag, int argc, - char *const argv[]) + char *const argv[]) { + ulong upto, stk_bot; + puts("DRAM: "); print_size(gd->ram_size, "\n");
+ if (!IS_ENABLED(CONFIG_CMD_MEMINFO_MAP)) + return 0; + + printf("\n%-12s %8s %8s %8s %8s\n", "Region", "Base", "Size", "End", + "Gap"); + printf("------------------------------------------------\n"); + upto = 0; + if (IS_ENABLED(CONFIG_VIDEO)) + print_region("video", gd_video_bottom(), + gd_video_size(), &upto); + if (IS_ENABLED(CONFIG_TRACE)) + print_region("trace", map_to_sysmem(gd_trace_buff()), + gd_trace_size(), &upto); + print_region("code", gd->relocaddr, gd->mon_len, &upto); + print_region("malloc", map_to_sysmem((void *)mem_malloc_start), + mem_malloc_end - mem_malloc_start, &upto); + print_region("board_info", map_to_sysmem(gd->bd), + sizeof(struct bd_info), &upto); + print_region("global_data", map_to_sysmem((void *)gd), + sizeof(struct global_data), &upto); + print_region("devicetree", map_to_sysmem(gd->fdt_blob), + fdt_totalsize(gd->fdt_blob), &upto); + if (IS_ENABLED(CONFIG_BOOTSTAGE)) + print_region("bootstage", map_to_sysmem(gd_bootstage()), + bootstage_get_size(false), &upto); + if (IS_ENABLED(CONFIG_BLOBLIST)) + print_region("bloblist", map_to_sysmem(gd_bloblist()), + bloblist_get_total_size(), &upto); + stk_bot = gd->start_addr_sp - CONFIG_STACK_SIZE; + print_region("stack", stk_bot, CONFIG_STACK_SIZE, &upto); + print_region("free", gd->ram_base, stk_bot, &upto); + return 0; }
diff --git a/doc/usage/cmd/meminfo.rst b/doc/usage/cmd/meminfo.rst new file mode 100644 index 00000000000..6c94493cccc --- /dev/null +++ b/doc/usage/cmd/meminfo.rst @@ -0,0 +1,128 @@ +.. SPDX-License-Identifier: GPL-2.0+: + +.. index:: + single: meminfo (command) + +meminfo command +=============== + +Synopsis +-------- + +:: + + meminfo + +Description +----------- + +The meminfo command shows the amount of memory. If ``CONFIG_CMD_MEMINFO_MAP`` is +enabled, then it also shows the layout of memory used by U-Boot and the region +which is free for use by images. + +The layout of memory is set up before relocation, within the init sequence in +``board_init_f()``, specifically the various ``reserve_...()`` functions. This +'reservation' of memory starts from the top of RAM and proceeds downwards, +ending with the stack. This results in the maximum possible amount of memory +being left free for image-loading. + +The meminfo command writes the DRAM size, then the rest of its outputs in 5 +columns: + +Region + Name of the region + +Base + Base address of the region, i.e. where it starts in memory + +Size + Size of the region, which may be a little smaller than the actual size + reserved, e.g. due to alignment + +End + End of the region. The last byte of the region is one lower than the address + shown here + +Gap + Gap between the end of this region and the base of the one above + +Regions shown are: + +video + Memory reserved for video framebuffers. This reservation happens in the + bind() methods of all video drivers which are present before relocation, + so the size depends on that maximum amount of memory which all such drivers + want to reserve. This may be significantly greater than the amount actually + needed, if the display is ultimately set to a smaller resolution or colour + depth than the maximum supported. + +code + U-Boot's code and Block-Starting Symbol (BSS) region. Before relocation, + U-Boot copies its code to a high region and sets up a BSS immediately after + that. The size of this region is generally therefore ``__bss_end`` - + ``__image_copy_start`` + +malloc + Contains the malloc() heap. The size of this is set by + ``CONFIG_SYS_MALLOC_LEN``. + +board_info + Contains the ``bd_info`` structure, with some information about the current + board. + +global_data + Contains the global-data structure, pointed to by ``gd``. This includes + various pointers, values and flags which control U-Boot. + +devicetree + Contains the flatted devicetree blob (FDT) being used by U-Boot to configure + itself and its devices. + +bootstage + Contains the bootstage records, which keep track of boot time as U-Boot + executes. The size of this is determined by + ``CONFIG_BOOTSTAGE_RECORD_COUNT``, with each record taking approximately + 32 bytes. + +bloblist + Contains the bloblist, which is a list of tables and other data created by + U-Boot while executed. The size of this is determined by + ``CONFIG_BLOBLIST_SIZE``. + +stack + Contains U-Boot's stack, growing downwards from the top. The nominal size of + this region is set by ``CONFIG_STACK_SIZE`` but there is no actual limit + enforced, so the stack can grow behind that. Images should be loaded lower + in memory to avoid any conflict. + +free + Free memory, which is available for loading images. The base address of + this is ``gd->ram_base`` which is generally set by ``CFG_SYS_SDRAM_BASE``. + +Example +------- + +This example shows output with both ``CONFIG_CMD_MEMINFO`` and +``CONFIG_CMD_MEMINFO_MAP`` enabled:: + + => meminfo + DRAM: 256 MiB + + Region Base Size End Gap + ------------------------------------------------ + video f000000 1000000 10000000 + code ec3a000 3c5d28 efffd28 2d8 + malloc 8c38000 6002000 ec3a000 0 + board_info 8c37f90 68 8c37ff8 8 + global_data 8c37d80 208 8c37f88 8 + devicetree 8c33000 4d7d 8c37d7d 3 + bootstage 8c32c20 3c8 8c32fe8 18 + bloblist 8c32000 400 8c32400 820 + stack 7c31ff0 1000000 8c31ff0 10 + free 0 7c31ff0 7c31ff0 0 + + +Return value +------------ + +The return value $? is always 0 (true). diff --git a/doc/usage/index.rst b/doc/usage/index.rst index 70563374899..3939add8eaf 100644 --- a/doc/usage/index.rst +++ b/doc/usage/index.rst @@ -83,6 +83,7 @@ Shell commands cmd/loads cmd/loadx cmd/loady + cmd/meminfo cmd/mbr cmd/md cmd/mmc diff --git a/test/cmd/Makefile b/test/cmd/Makefile index 8f2134998ad..0f1c8d77dd9 100644 --- a/test/cmd/Makefile +++ b/test/cmd/Makefile @@ -18,8 +18,9 @@ obj-$(CONFIG_CMD_FDT) += fdt.o obj-$(CONFIG_CONSOLE_TRUETYPE) += font.o obj-$(CONFIG_CMD_HISTORY) += history.o obj-$(CONFIG_CMD_LOADM) += loadm.o -obj-$(CONFIG_CMD_MEM_SEARCH) += mem_search.o +obj-$(CONFIG_CMD_MEMINFO) += meminfo.o obj-$(CONFIG_CMD_MEMORY) += mem_copy.o +obj-$(CONFIG_CMD_MEM_SEARCH) += mem_search.o ifdef CONFIG_CMD_PCI obj-$(CONFIG_CMD_PCI_MPS) += pci_mps.o endif diff --git a/test/cmd/meminfo.c b/test/cmd/meminfo.c new file mode 100644 index 00000000000..84981305bf0 --- /dev/null +++ b/test/cmd/meminfo.c @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Test for 'meminfo' command + * + * Copyright 2024 Google LLC + * Written by Simon Glass sjg@chromium.org + */ + +#include <dm/test.h> +#include <test/cmd.h> +#include <test/ut.h> + +/* Test 'meminfo' command */ +static int cmd_test_meminfo(struct unit_test_state *uts) +{ + ut_assertok(run_command("meminfo", 0)); + ut_assert_nextline("DRAM: 256 MiB"); + ut_assert_nextline_empty(); + + ut_assert_nextline("Region Base Size End Gap"); + ut_assert_nextlinen("-"); + + /* For now we don't worry about checking the values */ + ut_assert_nextlinen("video"); + ut_assert_nextlinen("code"); + ut_assert_nextlinen("malloc"); + ut_assert_nextlinen("board_info"); + ut_assert_nextlinen("global_data"); + ut_assert_nextlinen("devicetree"); + ut_assert_nextlinen("bootstage"); + ut_assert_nextlinen("bloblist"); + ut_assert_nextlinen("stack"); + ut_assert_nextlinen("free"); + ut_assert_console_end(); + + return 0; +} +CMD_TEST(cmd_test_meminfo, UTF_CONSOLE);

On Tue, Oct 15, 2024 at 07:33:04AM -0600, Simon Glass wrote:
U-Boot has a fairly rigid memory map which is normally not visible unless debugging is enabled in board_f.c
Update the 'meminfo' command to show it. This command does not cover arch-specific pieces but gives a good overview of where things are.
Signed-off-by: Simon Glass sjg@chromium.org
Please add dumping the lmb to this command, thanks.
participants (3)
-
Ilias Apalodimas
-
Simon Glass
-
Tom Rini