如何获取initrd起始地址

我们知道用户在制作rootfs的时候,最终rootfs会三种方式挂接到系统:

  1. 用户制作的根文件系统通过initramfs的方式与内核镜像打包在一起,这种情况下的rootfs内核会进行cpio压缩;
    此时主要会通过rest_init->kernel_init->populate_rootfs将用户根文件系统释放到内核的rootfs中。

  2. 用户制作的根文件系统通过cpio的方式单独处理,不与内核镜像打包在一起;
    仍然会通过rest_init->kernel_init->populate_rootfs路径,只不过这里会判断一下initrd_start是否被初始化过,它主要来源于dts的chosen节点解析的linux,initrd-start,如果initrd_start变量不为空,那么代表用户将根文件系统存放到内存的某个区域,

  3. 用户制作的根文件系统以某种文件系统格式化,形成文件系统镜像,内核在启动时,进行挂载
    prepare_namespace,主要针对格式化rootfs为某种文件系统的情况,主要通过挂载用户制作的rootfs根文件系统镜像
    注:这里主要通过init_eaccess检查是否能访问到某个文件(如linuxrc),如果能访问到则表示已经通过populate_rootfs 释放到内核根目录/,则不会执行prepare_namespace,否则将执行prepare_namespace挂载用户根文件系统

注:参考 kernel启动流程-start_kernel的执行_8.cpio initrd解包

此处我们主要描述第2种情况下内核如何获取用户根文件系统的地址,下面主要描述这个过程:

我们知道在内核启动start_kenrel -> setup_arch时会调用setup_machine_fdt这个函数,就是在这个函数中提取了rootfs在内存的地址:

start_kernel
    |--setup_arch
           |--setup_machine_fdt->early_init_dt_scan
				|--early_init_dt_scan_nodes
                 	|--of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line)
                         |--early_init_dt_check_for_initrd(node)
                                |--prop = of_get_flat_dt_prop(node, "linux,initrd-start", &len);
                                |--start = of_read_number(prop, len/4);
                                |--prop = of_get_flat_dt_prop(node, "linux,initrd-end", &len);
                                
                                |--end = of_read_number(prop, len/4)
                                |--phys_initrd_start = start;
                                |--phys_initrd_size = end - start; 

我们看phys_initrd_start 这个地址是怎么被使用的?

setup_arch
    |--arm64_memblock_init
           |...
           |--if (IS_ENABLED(CONFIG_BLK_DEV_INITRD) && phys_initrd_size)
           |       u64 base = phys_initrd_start & PAGE_MASK;
           |       u64 size = PAGE_ALIGN(phys_initrd_start + phys_initrd_size) - base;
           |       ....
           |--if (IS_ENABLED(CONFIG_BLK_DEV_INITRD) && phys_initrd_size)
                  initrd_start = __phys_to_virt(phys_initrd_start)
                  initrd_end = initrd_start + phys_initrd_size;

phys_initrd_start 最终被赋值给全局initrd_start,通过拿到这个变量,在populate_rootfs时就可以将内存中的根文件系统释放到内核rootfs的根目录

Guess you like

Origin blog.csdn.net/jasonactions/article/details/121415119