How Linux Parses Memory Tags from U‑Boot and Adjusts Boot Parameters
This article explains the two-stage process by which the Linux kernel parses memory information passed from U‑Boot—first via ATAG tags and then through the boot command line—detailing the relevant code, data structures, and practical methods for modifying memory size on embedded platforms.
During system startup, different product models often require adjustments to the amount of memory managed by Linux. The kernel parses memory information twice: first from tags created by U‑Boot and second from the boot_command_line arguments.
Parsing U‑Boot Tags (parse_tags)
U‑Boot's do_bootm_linux() builds a linked list of tags in physical memory. The start tag is created by setup_start_tag(), using the address stored in bd->bi_boot_params:
static void setup_start_tag(bd_t *bd) {
params = (struct tag *)bd->bi_boot_params;
params->hdr.tag = ATAG_CORE;
params->hdr.size = tag_size(tag_core);
params->u.core.flags = 0;
params->u.core.pagesize = 0;
params->u.core.rootdev = 0;
params = tag_next(params);
}The board_init() function sets bd->bi_boot_params = CFG_BOOT_PARAMS, establishing the physical base for tags.
Memory tags are created in setup_memory_tags() with ATAG_MEM. The parsing function parse_tag_mem32() registers via the __tagtable macro:
static int __init parse_tag_mem32(const struct tag *tag) {
if (meminfo.nr_banks >= NR_BANKS) {
printk(KERN_WARNING "Ignoring memory bank 0x%08x size %dKB
",
tag->u.mem.start, tag->u.mem.size / 1024);
return -EINVAL;
}
arm_add_memory(tag->u.mem.start, tag->u.mem.size);
return 0;
}
__tagtable(ATAG_MEM, parse_tag_mem32);The macro places the tagtable entry into the .taglist.init section, linking tag types to their parsers.
During start_kernel() → setup_arch() → parse_tags(), the kernel reads each tag from the physical address defined by MACHINE_START(...).boot_params. When a tag's hdr.tag matches an entry in the tagtable, the associated parse() function is invoked, populating the global struct meminfo meminfo with struct membank entries that describe each memory bank.
Parsing the Boot Command Line (early_mem)
The boot command line is assembled in U‑Boot's fix_bootargs(), where a mem= parameter may be added:
static void fix_bootargs(char *cmdline) {
// ...
p = strstr(cmdline, "mem=");
if (!p) {
sprintf(args, " mem=%dM", gd->bd->bi_dram[0].size / 0x200000);
strcat(cmdline, args);
}
// ...
}Linux processes this line early via early_mem(), registered with __early_param("mem=", early_mem):
static void __init early_mem(char **p) {
static int usermem __initdata = 0;
unsigned long size, start;
if (usermem == 0) {
usermem = 1;
meminfo.nr_banks = 0;
}
start = PHYS_OFFSET;
size = memparse(*p, p);
if (**p == '@')
start = memparse(*p + 1, p);
arm_add_memory(start, size);
}
__early_param("mem=", early_mem);If a mem= argument is present, it overwrites any memory banks previously set by tag parsing, effectively giving the command‑line precedence.
Practical Ways to Adjust Memory Size
Modify U‑Boot tags or bootargs directly. This works but requires changing the bootloader, which can complicate production and risk bricking devices.
Alter the mem= portion of the boot command line before the kernel parses it. This method is more flexible across product variants and easier to maintain.
On HiSilicon platforms, a custom function hikio_fix_meminfo() demonstrates the second approach by injecting a new mem= value and updating meminfo before parse_cmdline() runs.
void __init hikio_fix_meminfo(char *cmdline, struct meminfo *mi) {
// ...
strcpy(p, p+8);
strcat(cmdline, " mem=72M");
mi->bank[0].size = 72 * 0x100000;
}
hikio_fix_meminfo(from, &meminfo);
memcpy(boot_command_line, from, COMMAND_LINE_SIZE);
boot_command_line[COMMAND_LINE_SIZE-1] = '\0';
parse_cmdline(cmdline_p, from);This technique allows memory size changes without touching U‑Boot, making it the preferred solution for many embedded projects.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
ITPUB
Official ITPUB account sharing technical insights, community news, and exciting events.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
