[LINUX] Whereabouts of memory (what happens to kernel / initrd / fdt?)

It's a small story, but I will briefly summarize what happens to kernel / initrd / fdt that was placed in physical memory at startup.

First of all, here is the code to see

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/arch/arm/mm/init.c

When it starts up, it reserves more and more reserves.

--Kernel: Reserved --initrd: Discard after interpretation --fdt: (Maybe) remain reserve

You can see ...

init.c



void __init arm_memblock_init(const struct machine_desc *mdesc)
{
	/* Register the kernel text, kernel data and initrd with memblock. */
	memblock_reserve(__pa(KERNEL_START), KERNEL_END - KERNEL_START);★ Reserve Kernel

	arm_initrd_init();★ Reserve initrd

	arm_mm_memblock_reserve();★ Reserve page table

	/* reserve any platform specific memblock areas */
	if (mdesc->reserve)
		mdesc->reserve();

	early_init_fdt_reserve_self();★ Reserve fdt area
	early_init_fdt_scan_reserved_mem();★ Reserve reserved memory in fdt

	/* reserve memory for DMA contiguous allocations */
	dma_contiguous_reserve(arm_dma_limit); ★dma reserve

	arm_memblock_steal_permitted = false;
	memblock_dump_all();
}

init.c


/*
 * Reserve the special regions of memory
 */
void __init arm_mm_memblock_reserve(void)
{
    /*
     * Reserve the page tables.  These are already in use,
     * and can only be in node 0.
     */
    memblock_reserve(__pa(swapper_pg_dir), SWAPPER_PG_DIR_SIZE);

#ifdef CONFIG_SA1111
    /*
     * Because of the SA1111 DMA bug, we want to preserve our
     * precious DMA-able memory...
     */
    memblock_reserve(PHYS_OFFSET, __pa(swapper_pg_dir) - PHYS_OFFSET);
#endif
}



static void __init arm_initrd_init(void)
{
#ifdef CONFIG_BLK_DEV_INITRD
	phys_addr_t start;
	unsigned long size;

	initrd_start = initrd_end = 0;

	if (!phys_initrd_size)
		return;

	/*
	 * Round the memory region to page boundaries as per free_initrd_mem()
	 * This allows us to detect whether the pages overlapping the initrd
	 * are in use, but more importantly, reserves the entire set of pages
	 * as we don't want these pages allocated for other purposes.
	 */
	start = round_down(phys_initrd_start, PAGE_SIZE);
	size = phys_initrd_size + (phys_initrd_start - start);
	size = round_up(size, PAGE_SIZE);

	if (!memblock_is_region_memory(start, size)) {
		pr_err("INITRD: 0x%08llx+0x%08lx is not a memory region - disabling initrd\n",
		       (u64)start, size);
		return;
	}

	if (memblock_is_region_reserved(start, size)) {
		pr_err("INITRD: 0x%08llx+0x%08lx overlaps in-use memory region - disabling initrd\n",
		       (u64)start, size);
		return;
	}

	memblock_reserve(start, size);

	/* Now convert initrd to virtual addresses */
	initrd_start = __phys_to_virt(phys_initrd_start);
	initrd_end = initrd_start + phys_initrd_size;
#endif
}

Yeah, I feel like I've come to understand it.

The fdt relationship is implemented under driver / of. It seems that it is reserved.

drivers/of/fdt.c


/**
 * early_init_fdt_reserve_self() - reserve the memory used by the FDT blob
 */
void __init early_init_fdt_reserve_self(void)
{
    if (!initial_boot_params)
        return;

    /* Reserve the dtb region */
    early_init_dt_reserve_memory_arch(__pa(initial_boot_params),
                      fdt_totalsize(initial_boot_params),
                      false);
}

/**
 * early_init_fdt_scan_reserved_mem() - create reserved memory regions
 *
 * This function grabs memory from early allocator for device exclusive use
 * defined in device tree structures. It should be called by arch specific code
 * once the early allocator (i.e. memblock) has been fully activated.
 */
void __init early_init_fdt_scan_reserved_mem(void)
{
    int n;
    u64 base, size;

    if (!initial_boot_params)
        return;

    /* Process header /memreserve/ fields */
    for (n = 0; ; n++) {
        fdt_get_mem_rsv(initial_boot_params, n, &base, &size);
        if (!size)
            break;
        early_init_dt_reserve_memory_arch(base, size, false);
    }

    of_scan_flat_dt(__fdt_scan_reserved_mem, NULL);
    fdt_init_reserved_mem();
}

So, it is called from init / initramfs.c, but it seems that initrd will be thrown away once rootfs is expanded.

init/initramfs.c


static int __init populate_rootfs(void)
{
    /* Load the built in initramfs */
    char *err = unpack_to_rootfs(__initramfs_start, __initramfs_size);
    if (err)
        panic("%s", err); /* Failed to decompress INTERNAL initramfs */

    if (!initrd_start || IS_ENABLED(CONFIG_INITRAMFS_FORCE))
        goto done;

    if (IS_ENABLED(CONFIG_BLK_DEV_RAM))
        printk(KERN_INFO "Trying to unpack rootfs image as initramfs...\n");
    else
        printk(KERN_INFO "Unpacking initramfs...\n");

    err = unpack_to_rootfs((char *)initrd_start, initrd_end - initrd_start);
    if (err) {
        clean_rootfs();
        populate_initrd_image(err);
    }

done:
    /*
     * If the initrd region is overlapped with crashkernel reserved region,
     * free only memory that is not part of crashkernel region.
     */
    if (!do_retain_initrd && initrd_start && !kexec_free_initrd())
        free_initrd_mem(initrd_start, initrd_end);★ Here! !! !! !! !! !! !! !! !! !! !!
    initrd_start = 0;
    initrd_end = 0;

    flush_delayed_fput();
    return 0;
}
rootfs_initcall(populate_rootfs);

that's all.

Recommended Posts

Whereabouts of memory (what happens to kernel / initrd / fdt?)
What kind of Kernel is this Kernel?
What happens when I change the hyperparameters of SVM (RBF kernel)?
Try to make a kernel of Jupyter
What I did to save Python memory
What to do when PermissionError of tempfile.mkstemp occurs