It’s been a hot second since I’ve dived into the lands of initramfs and since then it seems like things have gotten more complicated. This is the way of things in tech and usually has a good reason. The simple way that used to work wonders (and is still required) to start with, was to identify if the file is compressed:
$ file /boot/initramfs-current.img /boot/initramfs-current.img: ASCII cpio archive (SVR4 with no CRC)
In this case the file appears to be entirely uncompressed which is convenient and likely exactly what you’ll experience for reasons I’m about to get to. This could indicate that there is a type of compression in place (such as gzip or the like) in which case your initramfs has likely not been generated by a modern version of Dracut and this post isn’t right for you.
Next let’s extract the contents into a new temporary directory:
$ mkdir init_tmp $ cd init_tmp $ cpio -mvid < /boot/initramfs-current.img . early_cpio kernel kernel/x86 kernel/x86/microcode kernel/x86/microcode/AuthenticAMD.bin 62 blocks
This is where things got weird and I got caught up. No
/init? No tools for
dealing with LVM, filesystems, device scanning? No core system directories like
/proc? What is going on here. We can also quickly see the
size doesn’t match what we extracted:
$ du --max-depth=1 -h 32K ./kernel 36K . $ ls -lh /boot/initramfs-current.img -rwxr-xr-x 1 root root 13M Feb 18 15:13 /boot/initramfs-current.img
Turns out this is an early optimization by dracut to get updated microcode to the
processor before we pass control over to any userspace programs. It’s actually
pretty slick and I’ll have to figure out how this works in some future post. To
get to the real initramfs we simply need to skip the first one using
Previosly when we extracted the CPIO archive it told us how large it was (The
62 blocks at the end). We simply need to skip those then we should be able to
decode the inner archive.
Side note for clarity with the following commands, I switched back to my home
directory and emptied out the extracted contents of the
init_tmp directory we
created earlier as that’s where we want to put the extracted inner initramfs
$ dd if=/boot/initramfs-current.img bs=512 skip=62 of=inner-initramfs-current.img 25995+1 records in 25995+1 records out 13309841 bytes (13 MB, 13 MiB) copied, 0.0848529 s, 157 MB/s
Once again we need to identify if compression is present:
$ file inner-initramfs-current.img inner-initramfs-current.img: LZ4 compressed data (v0.1-v0.9)
From here we can decompress it and extract the inner archive much like before using the appropriate utility (lz4cat does the trick here, your compression may vary).
$ cd init_tmp $ lz4cat ../inner-initramfs-current.img | cpio -mvid . bin bin/bash bin/cat bin/chown bin/chroot ...<contents remove for brevity> var var/lock var/run var/tmp 54581 blocks
Bam! That is a lot more like it. I’m really curious how the kernel boot process works with that early microcode but this got me where I needed to be and I hope this helps someone else out.
Additional note: I missed this but apparently dracut ships with a utility
skipcpio which you can pipe one of these initramfs files through to
skip the extra
dd step. Had a friend point that out after I wrote this up…