"Das U-Boot" Source Tree

Merge patch series "Allow showing the memory map"

Simon Glass <sjg@chromium.org> says:

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.

Link: https://lore.kernel.org/r/20241021081934.289473-1-sjg@chromium.org

+347 -42
+12
cmd/Kconfig
··· 885 885 886 886 config CMD_MEMINFO 887 887 bool "meminfo" 888 + default y if SANDBOX 888 889 help 889 890 Display memory information. 891 + 892 + config CMD_MEMINFO_MAP 893 + bool "- with memory map" 894 + depends on CMD_MEMINFO 895 + default y if SANDBOX 896 + help 897 + Shows a memory map, in addition to just the DRAM size. This allows 898 + seeing where U-Boot's memory area is, at the top of DRAM, as well as 899 + detail about each piece of it. 900 + 901 + See doc/usage/cmd/meminfo.rst for more information. 890 902 891 903 config CMD_MEMORY 892 904 bool "md, mm, nm, mw, cp, cmp, base, loop"
+1
cmd/Makefile
··· 109 109 obj-$(CONFIG_CMD_LSBLK) += lsblk.o 110 110 obj-$(CONFIG_CMD_MD5SUM) += md5sum.o 111 111 obj-$(CONFIG_CMD_MEMORY) += mem.o 112 + obj-$(CONFIG_CMD_MEMINFO) += meminfo.o 112 113 obj-$(CONFIG_CMD_IO) += io.o 113 114 obj-$(CONFIG_CMD_MII) += mii.o 114 115 obj-$(CONFIG_CMD_MISC) += misc.o
-19
cmd/mem.c
··· 1379 1379 1380 1380 #endif 1381 1381 1382 - #ifdef CONFIG_CMD_MEMINFO 1383 - static int do_mem_info(struct cmd_tbl *cmdtp, int flag, int argc, 1384 - char *const argv[]) 1385 - { 1386 - puts("DRAM: "); 1387 - print_size(gd->ram_size, "\n"); 1388 - 1389 - return 0; 1390 - } 1391 - #endif 1392 - 1393 1382 U_BOOT_CMD( 1394 1383 base, 2, 1, do_mem_base, 1395 1384 "print or set address offset", ··· 1432 1421 "[.b, .w, .l" HELP_Q "] address value delay(ms)" 1433 1422 ); 1434 1423 #endif /* CONFIG_CMD_MX_CYCLIC */ 1435 - 1436 - #ifdef CONFIG_CMD_MEMINFO 1437 - U_BOOT_CMD( 1438 - meminfo, 3, 1, do_mem_info, 1439 - "display memory information", 1440 - "" 1441 - ); 1442 - #endif 1443 1424 1444 1425 #ifdef CONFIG_CMD_RANDOM 1445 1426 U_BOOT_CMD(
+99
cmd/meminfo.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + /* 3 + * Copyright 2024 Google LLC 4 + * Written by Simon Glass <sjg@chromium.org> 5 + */ 6 + 7 + #include <bloblist.h> 8 + #include <bootstage.h> 9 + #include <command.h> 10 + #include <display_options.h> 11 + #include <lmb.h> 12 + #include <malloc.h> 13 + #include <mapmem.h> 14 + #include <asm/global_data.h> 15 + 16 + DECLARE_GLOBAL_DATA_PTR; 17 + 18 + static void print_region(const char *name, ulong base, ulong size, ulong *uptop) 19 + { 20 + ulong end = base + size; 21 + 22 + printf("%-12s %8lx %8lx %8lx", name, base, size, end); 23 + if (*uptop) 24 + printf(" %8lx", *uptop - end); 25 + putc('\n'); 26 + *uptop = base; 27 + } 28 + 29 + static void show_lmb(const struct lmb *lmb, ulong *uptop) 30 + { 31 + int i; 32 + 33 + for (i = lmb->used_mem.count - 1; i >= 0; i--) { 34 + const struct lmb_region *rgn = alist_get(&lmb->used_mem, i, 35 + struct lmb_region); 36 + 37 + /* 38 + * Assume that the top lmb region is the U-Boot region, so just 39 + * take account of the memory not already reported 40 + */ 41 + if (lmb->used_mem.count - 1) 42 + print_region("lmb", rgn->base, *uptop - rgn->base, 43 + uptop); 44 + else 45 + print_region("lmb", rgn->base, rgn->size, uptop); 46 + *uptop = rgn->base; 47 + } 48 + } 49 + 50 + static int do_meminfo(struct cmd_tbl *cmdtp, int flag, int argc, 51 + char *const argv[]) 52 + { 53 + ulong upto, stk_bot; 54 + 55 + puts("DRAM: "); 56 + print_size(gd->ram_size, "\n"); 57 + 58 + if (!IS_ENABLED(CONFIG_CMD_MEMINFO_MAP)) 59 + return 0; 60 + 61 + printf("\n%-12s %8s %8s %8s %8s\n", "Region", "Base", "Size", "End", 62 + "Gap"); 63 + printf("------------------------------------------------\n"); 64 + upto = 0; 65 + if (IS_ENABLED(CONFIG_VIDEO)) 66 + print_region("video", gd_video_bottom(), 67 + gd_video_size(), &upto); 68 + if (IS_ENABLED(CONFIG_TRACE)) 69 + print_region("trace", map_to_sysmem(gd_trace_buff()), 70 + gd_trace_size(), &upto); 71 + print_region("code", gd->relocaddr, gd->mon_len, &upto); 72 + print_region("malloc", map_to_sysmem((void *)mem_malloc_start), 73 + mem_malloc_end - mem_malloc_start, &upto); 74 + print_region("board_info", map_to_sysmem(gd->bd), 75 + sizeof(struct bd_info), &upto); 76 + print_region("global_data", map_to_sysmem((void *)gd), 77 + sizeof(struct global_data), &upto); 78 + print_region("devicetree", map_to_sysmem(gd->fdt_blob), 79 + fdt_totalsize(gd->fdt_blob), &upto); 80 + if (IS_ENABLED(CONFIG_BOOTSTAGE)) 81 + print_region("bootstage", map_to_sysmem(gd_bootstage()), 82 + bootstage_get_size(false), &upto); 83 + if (IS_ENABLED(CONFIG_BLOBLIST)) 84 + print_region("bloblist", map_to_sysmem(gd_bloblist()), 85 + bloblist_get_total_size(), &upto); 86 + stk_bot = gd->start_addr_sp - CONFIG_STACK_SIZE; 87 + print_region("stack", stk_bot, CONFIG_STACK_SIZE, &upto); 88 + if (IS_ENABLED(CONFIG_LMB)) 89 + show_lmb(lmb_get(), &upto); 90 + print_region("free", gd->ram_base, upto, &upto); 91 + 92 + return 0; 93 + } 94 + 95 + U_BOOT_CMD( 96 + meminfo, 1, 1, do_meminfo, 97 + "display memory information", 98 + "" 99 + );
+4 -4
common/board_f.c
··· 501 501 static int reserve_noncached(void) 502 502 { 503 503 /* 504 - * The value of gd->start_addr_sp must match the value of malloc_start 505 - * calculated in board_r.c:initr_malloc(), which is passed to 506 - * dlmalloc.c:mem_malloc_init() and then used by 504 + * The value of gd->start_addr_sp must match the value of 505 + * mem_malloc_start calculated in board_r.c:initr_malloc(), which is 506 + * passed to dlmalloc.c:mem_malloc_init() and then used by 507 507 * cache.c:noncached_init() 508 508 * 509 509 * These calculations must match the code in cache.c:noncached_init() ··· 582 582 static int reserve_bootstage(void) 583 583 { 584 584 #ifdef CONFIG_BOOTSTAGE 585 - int size = bootstage_get_size(); 585 + int size = bootstage_get_size(true); 586 586 587 587 gd->start_addr_sp = reserve_stack_aligned(size); 588 588 gd->boardf->new_bootstage = map_sysmem(gd->start_addr_sp, size);
+1 -2
common/board_r.c
··· 204 204 */ 205 205 start = gd->relocaddr - TOTAL_MALLOC_LEN; 206 206 gd_set_malloc_start(start); 207 - mem_malloc_init((ulong)map_sysmem(start, TOTAL_MALLOC_LEN), 208 - TOTAL_MALLOC_LEN); 207 + mem_malloc_init(start, TOTAL_MALLOC_LEN); 209 208 return 0; 210 209 } 211 210
+9 -7
common/bootstage.c
··· 520 520 } 521 521 #endif 522 522 523 - int bootstage_get_size(void) 523 + int bootstage_get_size(bool add_strings) 524 524 { 525 - struct bootstage_data *data = gd->bootstage; 526 - struct bootstage_record *rec; 527 525 int size; 528 - int i; 529 526 530 527 size = sizeof(struct bootstage_data); 531 - for (rec = data->record, i = 0; i < data->rec_count; 532 - i++, rec++) 533 - size += strlen(rec->name) + 1; 528 + if (add_strings) { 529 + struct bootstage_data *data = gd->bootstage; 530 + struct bootstage_record *rec; 531 + int i; 532 + 533 + for (rec = data->record, i = 0; i < data->rec_count; i++, rec++) 534 + size += strlen(rec->name) + 1; 535 + } 534 536 535 537 return size; 536 538 }
+5 -3
common/dlmalloc.c
··· 16 16 #include <asm/global_data.h> 17 17 18 18 #include <malloc.h> 19 + #include <mapmem.h> 20 + #include <string.h> 19 21 #include <asm/io.h> 20 22 #include <valgrind/memcheck.h> 21 23 ··· 598 600 599 601 void mem_malloc_init(ulong start, ulong size) 600 602 { 601 - mem_malloc_start = start; 602 - mem_malloc_end = start + size; 603 - mem_malloc_brk = start; 603 + mem_malloc_start = (ulong)map_sysmem(start, size); 604 + mem_malloc_end = mem_malloc_start + size; 605 + mem_malloc_brk = mem_malloc_start; 604 606 605 607 #ifdef CONFIG_SYS_MALLOC_DEFAULT_TO_INIT 606 608 malloc_init();
+1 -3
common/spl/spl.c
··· 678 678 spl_set_bd(); 679 679 680 680 if (IS_ENABLED(CONFIG_SPL_SYS_MALLOC)) { 681 - mem_malloc_init((ulong)map_sysmem(SPL_SYS_MALLOC_START, 682 - SPL_SYS_MALLOC_SIZE), 683 - SPL_SYS_MALLOC_SIZE); 681 + mem_malloc_init(SPL_SYS_MALLOC_START, SPL_SYS_MALLOC_SIZE); 684 682 gd->flags |= GD_FLG_FULL_MALLOC_INIT; 685 683 } 686 684 if (!(gd->flags & GD_FLG_SPL_INIT)) {
+128
doc/usage/cmd/meminfo.rst
··· 1 + .. SPDX-License-Identifier: GPL-2.0+: 2 + 3 + .. index:: 4 + single: meminfo (command) 5 + 6 + meminfo command 7 + =============== 8 + 9 + Synopsis 10 + -------- 11 + 12 + :: 13 + 14 + meminfo 15 + 16 + Description 17 + ----------- 18 + 19 + The meminfo command shows the amount of memory. If ``CONFIG_CMD_MEMINFO_MAP`` is 20 + enabled, then it also shows the layout of memory used by U-Boot and the region 21 + which is free for use by images. 22 + 23 + The layout of memory is set up before relocation, within the init sequence in 24 + ``board_init_f()``, specifically the various ``reserve_...()`` functions. This 25 + 'reservation' of memory starts from the top of RAM and proceeds downwards, 26 + ending with the stack. This results in the maximum possible amount of memory 27 + being left free for image-loading. 28 + 29 + The meminfo command writes the DRAM size, then the rest of its outputs in 5 30 + columns: 31 + 32 + Region 33 + Name of the region 34 + 35 + Base 36 + Base address of the region, i.e. where it starts in memory 37 + 38 + Size 39 + Size of the region, which may be a little smaller than the actual size 40 + reserved, e.g. due to alignment 41 + 42 + End 43 + End of the region. The last byte of the region is one lower than the address 44 + shown here 45 + 46 + Gap 47 + Gap between the end of this region and the base of the one above 48 + 49 + Regions shown are: 50 + 51 + video 52 + Memory reserved for video framebuffers. This reservation happens in the 53 + bind() methods of all video drivers which are present before relocation, 54 + so the size depends on that maximum amount of memory which all such drivers 55 + want to reserve. This may be significantly greater than the amount actually 56 + needed, if the display is ultimately set to a smaller resolution or colour 57 + depth than the maximum supported. 58 + 59 + code 60 + U-Boot's code and Block-Starting Symbol (BSS) region. Before relocation, 61 + U-Boot copies its code to a high region and sets up a BSS immediately after 62 + that. The size of this region is generally therefore ``__bss_end`` - 63 + ``__image_copy_start`` 64 + 65 + malloc 66 + Contains the malloc() heap. The size of this is set by 67 + ``CONFIG_SYS_MALLOC_LEN``. 68 + 69 + board_info 70 + Contains the ``bd_info`` structure, with some information about the current 71 + board. 72 + 73 + global_data 74 + Contains the global-data structure, pointed to by ``gd``. This includes 75 + various pointers, values and flags which control U-Boot. 76 + 77 + devicetree 78 + Contains the flatted devicetree blob (FDT) being used by U-Boot to configure 79 + itself and its devices. 80 + 81 + bootstage 82 + Contains the bootstage records, which keep track of boot time as U-Boot 83 + executes. The size of this is determined by 84 + ``CONFIG_BOOTSTAGE_RECORD_COUNT``, with each record taking approximately 85 + 32 bytes. 86 + 87 + bloblist 88 + Contains the bloblist, which is a list of tables and other data created by 89 + U-Boot while executed. The size of this is determined by 90 + ``CONFIG_BLOBLIST_SIZE``. 91 + 92 + stack 93 + Contains U-Boot's stack, growing downwards from the top. The nominal size of 94 + this region is set by ``CONFIG_STACK_SIZE`` but there is no actual limit 95 + enforced, so the stack can grow behind that. Images should be loaded lower 96 + in memory to avoid any conflict. 97 + 98 + free 99 + Free memory, which is available for loading images. The base address of 100 + this is ``gd->ram_base`` which is generally set by ``CFG_SYS_SDRAM_BASE``. 101 + 102 + Example 103 + ------- 104 + 105 + This example shows output with both ``CONFIG_CMD_MEMINFO`` and 106 + ``CONFIG_CMD_MEMINFO_MAP`` enabled:: 107 + 108 + => meminfo 109 + DRAM: 256 MiB 110 + 111 + Region Base Size End Gap 112 + ------------------------------------------------ 113 + video f000000 1000000 10000000 114 + code ec3a000 3c5d28 efffd28 2d8 115 + malloc 8c38000 6002000 ec3a000 0 116 + board_info 8c37f90 68 8c37ff8 8 117 + global_data 8c37d80 208 8c37f88 8 118 + devicetree 8c33000 4d7d 8c37d7d 3 119 + bootstage 8c32c20 3c8 8c32fe8 18 120 + bloblist 8c32000 400 8c32400 820 121 + stack 7c31ff0 1000000 8c31ff0 10 122 + free 0 7c31ff0 7c31ff0 0 123 + 124 + 125 + Return value 126 + ------------ 127 + 128 + The return value $? is always 0 (true).
+1
doc/usage/index.rst
··· 84 84 cmd/loads 85 85 cmd/loadx 86 86 cmd/loady 87 + cmd/meminfo 87 88 cmd/mbr 88 89 cmd/md 89 90 cmd/mmc
+30
include/asm-generic/global_data.h
··· 543 543 #define gd_set_upl(val) 544 544 #endif 545 545 546 + #if CONFIG_IS_ENABLED(BLOBLIST) 547 + #define gd_bloblist() gd->bloblist 548 + #else 549 + #define gd_bloblist() NULL 550 + #endif 551 + 552 + #if CONFIG_IS_ENABLED(BOOTSTAGE) 553 + #define gd_bootstage() gd->bootstage 554 + #else 555 + #define gd_bootstage() NULL 556 + #endif 557 + 558 + #if CONFIG_IS_ENABLED(TRACE) 559 + #define gd_trace_buff() gd->trace_buff 560 + #define gd_trace_size() CONFIG_TRACE_BUFFER_SIZE 561 + #else 562 + #define gd_trace_buff() NULL 563 + #define gd_trace_size() 0 564 + #endif 565 + 566 + #if CONFIG_IS_ENABLED(VIDEO) 567 + #define gd_video_top() gd->video_top 568 + #define gd_video_bottom() gd->video_bottom 569 + #define gd_video_size() (gd->video_top - gd->video_bottom) 570 + #else 571 + #define gd_video_top() 0 572 + #define gd_video_bottom() 0 573 + #define gd_video_size() 0 574 + #endif 575 + 546 576 /** 547 577 * enum gd_flags - global data flags 548 578 *
+3 -2
include/bootstage.h
··· 371 371 /** 372 372 * bootstage_get_size() - Get the size of the bootstage data 373 373 * 374 + * @add_strings: true to add the size of attached strings (for stashing) 374 375 * Return: size of boostage data in bytes 375 376 */ 376 - int bootstage_get_size(void); 377 + int bootstage_get_size(bool add_strings); 377 378 378 379 /** 379 380 * bootstage_init() - Prepare bootstage for use ··· 444 445 return 0; /* Pretend to succeed */ 445 446 } 446 447 447 - static inline int bootstage_get_size(void) 448 + static inline int bootstage_get_size(bool add_strings) 448 449 { 449 450 return 0; 450 451 }
+8
include/malloc.h
··· 981 981 extern ulong mem_malloc_end; 982 982 extern ulong mem_malloc_brk; 983 983 984 + /** 985 + * mem_malloc_init() - Set up the malloc() pool 986 + * 987 + * Sets the region of memory to be used for all future calls to malloc(), etc. 988 + * 989 + * @start: Start address 990 + * @size: Size in bytes 991 + */ 984 992 void mem_malloc_init(ulong start, ulong size); 985 993 986 994 #ifdef __cplusplus
+1 -1
lib/lmb.c
··· 887 887 return 0; 888 888 } 889 889 890 - #if CONFIG_IS_ENABLED(UNIT_TEST) 891 890 struct lmb *lmb_get(void) 892 891 { 893 892 return &lmb; 894 893 } 895 894 895 + #if CONFIG_IS_ENABLED(UNIT_TEST) 896 896 int lmb_push(struct lmb *store) 897 897 { 898 898 int ret;
+2 -1
test/cmd/Makefile
··· 19 19 obj-$(CONFIG_CONSOLE_TRUETYPE) += font.o 20 20 obj-$(CONFIG_CMD_HISTORY) += history.o 21 21 obj-$(CONFIG_CMD_LOADM) += loadm.o 22 + obj-$(CONFIG_CMD_MEMINFO) += meminfo.o 23 + obj-$(CONFIG_CMD_MEMORY) += mem_copy.o 22 24 obj-$(CONFIG_CMD_MEM_SEARCH) += mem_search.o 23 - obj-$(CONFIG_CMD_MEMORY) += mem_copy.o 24 25 ifdef CONFIG_CMD_PCI 25 26 obj-$(CONFIG_CMD_PCI_MPS) += pci_mps.o 26 27 endif
+42
test/cmd/meminfo.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + /* 3 + * Test for 'meminfo' command 4 + * 5 + * Copyright 2024 Google LLC 6 + * Written by Simon Glass <sjg@chromium.org> 7 + */ 8 + 9 + #include <dm/test.h> 10 + #include <test/cmd.h> 11 + #include <test/ut.h> 12 + 13 + /* Test 'meminfo' command */ 14 + static int cmd_test_meminfo(struct unit_test_state *uts) 15 + { 16 + ut_assertok(run_command("meminfo", 0)); 17 + ut_assert_nextline("DRAM: 256 MiB"); 18 + ut_assert_nextline_empty(); 19 + 20 + ut_assert_nextline("Region Base Size End Gap"); 21 + ut_assert_nextlinen("-"); 22 + 23 + /* For now we don't worry about checking the values */ 24 + ut_assert_nextlinen("video"); 25 + ut_assert_nextlinen("code"); 26 + ut_assert_nextlinen("malloc"); 27 + ut_assert_nextlinen("board_info"); 28 + ut_assert_nextlinen("global_data"); 29 + ut_assert_nextlinen("devicetree"); 30 + ut_assert_nextlinen("bootstage"); 31 + ut_assert_nextlinen("bloblist"); 32 + ut_assert_nextlinen("stack"); 33 + 34 + /* we expect at least one lmb line, but don't know how many */ 35 + ut_assert_nextlinen("lmb"); 36 + ut_assert_skip_to_linen("free"); 37 + 38 + ut_assert_console_end(); 39 + 40 + return 0; 41 + } 42 + CMD_TEST(cmd_test_meminfo, UTF_CONSOLE);