Analysis of initRD startup process

Posted by ashleek007 on Fri, 14 Jan 2022 14:24:41 +0100

1. The root file system is stored in flash, and it will take a long time to start the device. This is because reading rootfs data from flash is time-consuming, and reading *. Stored in rootfs at the same time so,*. ko and other documents are also time-consuming. This is determined by the read and write properties of flash itself. For some devices that need to start quickly, the read-write rate of flash cannot be met, so you can consider mounting rootfs in memory, that is, ramdisk.

2. Using ramdisk requires kernel support, and config needs to be opened_ BLK_ DEV_ Initrd macro

3. The initramfs initialization flow chart is shown in the following figure, which is mainly divided into two parts.
3.1. Mount rootfs ("/"), vfs_caches_init branch
3.2. Making rootfs and rest_init branch

4. Establish rootfs

struct vfsmount *
vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data)
{
	......
	root = mount_fs(type, flags, name, data);
	......
}
EXPORT_SYMBOL_GPL(vfs_kern_mount);

According to VFS_ kern_ The name="rootfs" passed in by the mount function will eventually execute rootfs_mount completes the establishment of the root file system.

static struct file_system_type rootfs_fs_type = {
	.name		= "rootfs",
	.mount		= rootfs_mount,
	.kill_sb	= kill_litter_super,
};

5. Make root file system
5.1. How to start from__ initcall6_start to populate_rootfs
device_initcall(populate_rootfs);
populate_rootfs function through device_initcall macro, loaded into a specific section (. initcall6.init)

#define device_initcall(fn)		__define_initcall(fn, 6)
#define __define_initcall(fn, id) ___define_initcall(fn, id, .initcall##id)
#define ___define_initcall(fn, id, __sec) \
	static initcall_t __initcall_##fn##id __used \
		__attribute__((__section__(#__sec ".init"))) = fn;

device_initcall function__ initcall_populate_rootfs6 is stored in initcall6. In the section of init
Via / / include / ASM generic / vmlinux lds. H link script file, found

When executed__ initcall6_ When the start function is executed, it is stored in the initcall6.init is the data of this section, i.e__ initcall_populate_rootfs6 function

5.2. Making rootfs

static int __init populate_rootfs(void)
{
	char *err = unpack_to_rootfs(__initramfs_start, __initramfs_size);
	......
	if (initrd_start) {
		......
		printk(KERN_INFO "Unpacking initramfs...\n");
		err = unpack_to_rootfs((char *)initrd_start,
			initrd_end - initrd_start);
		if (err)
			printk(KERN_EMERG "Initramfs unpacking failed: %s\n", err);
		free_initrd();

		/*
		 * Try loading default modules from initramfs.  This gives
		 * us a chance to load before device_initcalls.
		 */
		load_default_modules();
	}

	return 0;
}

5.2.1 first unpcak_ to_ [_initramfs_start, _initramfs_start + _initramfs_size] data of rootfs
Via / / include / ASM generic / vmlinux lds. H link script file, found

It defines init.ramfs and init.ramfs.info two section s
Via / / usr/initramfs_data.S file discovery__ initramfs_size is determined by initramfs_data.o confirm

Including INITRAMFS_IMAGE is defined in / / usr/Makefile file

initramfs is generally not used after loading

5.2.2 post unpack_ to_ [initrd_start, initrd_end] data of rootfs
Where initrd_end and initrd_start is passed in through cmdline, and the data has been decompressed from the rootfs partition of flash and moved to initrd in the uboot phase_ Start address.

5.2.2.1 production of rootfs in flash image
rootfs generates *. Through cpio command cpio files are compressed according to the compression method (in the build\images.mk script)

#lzo compression mode, rootfs Bin is rootfs_initramfs.cpio lzo compressed file
lzop -x rootfs.bin
#Convert the cpio file into directory format, and ls view the specific directory content
cpio -idmv < rootfs_initramfs.cpio 

5.2.2.2 production of rootfs in memory

static char * __init unpack_to_rootfs(char *buf, unsigned len)
{
	......
	while (!message && len) {
		loff_t saved_offset = this_header;
		if (*buf == '0' && !(this_header & 3)) {
			state = Start;
			written = write_buffer(buf, len);
			......
		}
		......
		this_header = 0;
		decompress = decompress_method(buf, len, &compress_name);
		if (decompress) {
			res = decompress(buf, len, NULL, flush_buffer, NULL,
				   &my_inptr, error);
			if (res)
				error("decompressor failed");
		} 
		......
	}
}

The data in the current buf has been decompress ed and written directly_ Buffer function production; No specific compression method is used to de compress the post flush_buffer implementation
write_buffer parses the buf fer data through the following functions to complete the creation of the root file system

static __initdata int (*actions[])(void) = {
	[Start]		    = do_start,
	[Collect]	    = do_collect,
	[GotHeader]	    = do_header,
	[SkipIt]	    = do_skip,
	[GotName]	    = do_name,
	[CopyFile]	    = do_copy,
	[GotSymlink]	= do_symlink,
	[Reset]		    = do_reset,
};

 

6. Run the application in the file system

//kernel_ In the init function, execute ramdisk_execute_command application, where ramdisk_execute_command passed in from cmdline
if (ramdisk_execute_command) {
	if (!run_init_process(ramdisk_execute_command))
		return 0;
	pr_err("Failed to execute %s\n", ramdisk_execute_command);
}

Topics: Linux