summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/Kconfig12
-rw-r--r--cmd/Makefile1
-rw-r--r--cmd/mem.c19
-rw-r--r--cmd/meminfo.c99
-rw-r--r--common/board_f.c8
-rw-r--r--common/board_r.c3
-rw-r--r--common/bootstage.c16
-rw-r--r--common/dlmalloc.c8
-rw-r--r--common/spl/spl.c4
-rw-r--r--doc/usage/cmd/meminfo.rst128
-rw-r--r--doc/usage/index.rst1
-rw-r--r--include/asm-generic/global_data.h30
-rw-r--r--include/bootstage.h5
-rw-r--r--include/malloc.h8
-rw-r--r--lib/lmb.c2
-rw-r--r--test/cmd/Makefile3
-rw-r--r--test/cmd/meminfo.c42
17 files changed, 347 insertions, 42 deletions
diff --git a/cmd/Kconfig b/cmd/Kconfig
index 40485be192f..4fba9fe6703 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -885,9 +885,21 @@ config MD5SUM_VERIFY
config CMD_MEMINFO
bool "meminfo"
+ default y if SANDBOX
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/Makefile b/cmd/Makefile
index 7fe2044aab7..b4668eb73e5 100644
--- a/cmd/Makefile
+++ b/cmd/Makefile
@@ -109,6 +109,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..5e83d61c2dd
--- /dev/null
+++ b/cmd/meminfo.c
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2024 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <bloblist.h>
+#include <bootstage.h>
+#include <command.h>
+#include <display_options.h>
+#include <lmb.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 void show_lmb(const struct lmb *lmb, ulong *uptop)
+{
+ int i;
+
+ for (i = lmb->used_mem.count - 1; i >= 0; i--) {
+ const struct lmb_region *rgn = alist_get(&lmb->used_mem, i,
+ struct lmb_region);
+
+ /*
+ * Assume that the top lmb region is the U-Boot region, so just
+ * take account of the memory not already reported
+ */
+ if (lmb->used_mem.count - 1)
+ print_region("lmb", rgn->base, *uptop - rgn->base,
+ uptop);
+ else
+ print_region("lmb", rgn->base, rgn->size, uptop);
+ *uptop = rgn->base;
+ }
+}
+
+static int do_meminfo(struct cmd_tbl *cmdtp, int flag, int argc,
+ 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);
+ if (IS_ENABLED(CONFIG_LMB))
+ show_lmb(lmb_get(), &upto);
+ print_region("free", gd->ram_base, upto, &upto);
+
+ return 0;
+}
+
+U_BOOT_CMD(
+ meminfo, 1, 1, do_meminfo,
+ "display memory information",
+ ""
+);
diff --git a/common/board_f.c b/common/board_f.c
index f1bd70fdd6c..98dc2591e1d 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()
@@ -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/board_r.c b/common/board_r.c
index e5f33f40643..8a19817fa39 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/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/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/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 b84d8ee909f..db71711c393 100644
--- a/doc/usage/index.rst
+++ b/doc/usage/index.rst
@@ -84,6 +84,7 @@ Shell commands
cmd/loads
cmd/loadx
cmd/loady
+ cmd/meminfo
cmd/mbr
cmd/md
cmd/mmc
diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h
index b84cc5bbecd..bf593d96a84 100644
--- a/include/asm-generic/global_data.h
+++ b/include/asm-generic/global_data.h
@@ -543,6 +543,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
*
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;
}
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
diff --git a/lib/lmb.c b/lib/lmb.c
index 7e90f178763..eec99c185ee 100644
--- a/lib/lmb.c
+++ b/lib/lmb.c
@@ -887,12 +887,12 @@ int lmb_init(void)
return 0;
}
-#if CONFIG_IS_ENABLED(UNIT_TEST)
struct lmb *lmb_get(void)
{
return &lmb;
}
+#if CONFIG_IS_ENABLED(UNIT_TEST)
int lmb_push(struct lmb *store)
{
int ret;
diff --git a/test/cmd/Makefile b/test/cmd/Makefile
index 40808350962..4b487c1d2cb 100644
--- a/test/cmd/Makefile
+++ b/test/cmd/Makefile
@@ -19,8 +19,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..53b41e3b49e
--- /dev/null
+++ b/test/cmd/meminfo.c
@@ -0,0 +1,42 @@
+// 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");
+
+ /* we expect at least one lmb line, but don't know how many */
+ ut_assert_nextlinen("lmb");
+ ut_assert_skip_to_linen("free");
+
+ ut_assert_console_end();
+
+ return 0;
+}
+CMD_TEST(cmd_test_meminfo, UTF_CONSOLE);