Booting Arch and Arch Based Distributions with another Distribution's GRUB

May 1, 2015, 6 p.m.

by ORDINATECHNIC

Arch implements the loading of Intel processor microcode updates at boot differently from other distributions. While other distributions include the microcode into the initramfs (the replacement of the initrd) image, Arch leaves this as a separate image, which is loaded by Arch's GRUB at the same time as the initramfs. Because the implementation of GRUB through the scripts in /etc/grub.d/ by other distrubutions doesn't account for this difference, other distributions' GRUB try to load the microcode image as if it was the actual initramfs, resulting in an immediate kernel panic.

This issue is described further in this article, along with my preferred workaround which is part of another workaround for maintaining the visual polish available when using a distribution's native GRUB with another distribution's GRUB.

Arch implements the loading of Intel processor microcode updates at boot differently from other distributions. While other distributions include the microcode into the initramfs (the replacement of the initrd) image, Arch leaves this as a separate image, which is loaded by Arch's GRUB at the same time as the initramfs. Because the implementation of GRUB through the scripts in /etc/grub.d/ by other distrubutions doesn't account for this difference, other distributions' GRUB try to load the microcode image as if it was the actual initramfs, resulting in an immediate kernel panic.

This issue is described further in this article, along with my preferred workaround which is part of another workaround for maintaining the visual polish available when using a distribution's native GRUB with another distribution's GRUB.

Introduction

Before describing the issue, it is important to be aware of certain aspects of how GRUB works. Most Linux users are aware of the grub configuration file /etc/default/grub, where the user can control certain parts of the GRUB configuration, most importantly the kernel command default options -- shown below from my openSUSE Tumbleweed installation's /etc/default/grub --

GRUB_CMDLINE_LINUX_DEFAULT="resume=/dev/disk/by-uuid/69bb9b40-aedd-4278-ac57-0113a7dc816f splash=silent quiet showopts video.use_native_backlight=1"
which is used by the GRUB scripts to load kernel options. Parameters can be specified on this line, such as the resume device. Some other, less important parameters can be specified here as well, such as those involving backlight control methods, and whether to show messages during boot. This file can also be used to specify some GRUB appearance options such as the theme to use.

But this is not the only file that determines the operation of GRUB. Another important file is the grub.cfg file. This file is generated by the grub setup command, grub-mkconfig -- or its distribution dependent variants and aliases -- which in turn runs the scripts in /etc/grub.d in order to generate the GRUB menu entries.

DistributionCommand to Setup/Update GRUB Configuration
Arch and Derivtives (e.g. Manjaro)
grub-mkconfig -o /boot/grub/grub.cfg
Tanglu and other Debian based distros including Ubuntu
sudo update-grub

update-grub is an alias for grub-mkconfig
Sabayon
grub2-mkconfig -o /boot/grub/grub.cfg
openSUSE
grub2-mkconfig -o /boot/grub2/grub.cfg
Fedora
grub-mkconfig -o /boot/efi/EFI/fedora/grub.cfg

The following screenshot shows the contents of /etc/grub.d on my Debian based Voyager X8 installation.

list of scripts in /etc/grub.d
Output of ls -l in /etc/grub.d in the Debian Based Voyager X8
These scripts are run by grub-mkconfig to generate the /boot/grub/grub.cfg. Note the actual command and location of this file varies by distribution.
Each script adds a section in the grub.fcg named after the script.
### BEGIN /etc/grub.d/10_linux ###
function gfxmode {
	set gfxpayload="${1}"
}
set linux_gfx_mode=
export linux_gfx_mode
menuentry 'Debian GNU/Linux' --class debian --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-simple-d9f64562-53cf-4efa-ba54-83703eed0ead' {

...
		
For example, the above section of the /grub.cfg file is generated by /etc/grub.d/10_linux. The 10_linux section contains the menu entry for the native distribution. The /etc/grub.d/30_os-prober uses the os-prober utility to detect other distributions and OSes installed on the computer, and generates their GRUB menu entries. In most implementations, the sections 10_linux and 30_os-prober each contain a main menuentry and ususally another sub entry that is expanded to show a sub menu entries that may include options for booting with non-default kernels also installed on the system and fallback kernels.

Besides determining the menu structure, the grub.cfg file, for each OS, specifies the root filesystem, the resume device, the kernel to load, and the initramfs, some of these taken from the /etc/default/grub file. In the following excerpt,

menuentry 'Debian GNU/Linux' --class debian --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-simple-d9f64562-53cf-4efa-ba54-83703eed0ead' {
	load_video
	insmod gzio
	if [ x$grub_platform = xxen ]; then insmod xzio; insmod lzopio; fi
	insmod part_gpt
	insmod ext2
	set root='hd0,gpt23'
	if [ x$feature_platform_search_hint = xy ]; then
	  search --no-floppy --fs-uuid --set=root --hint-bios=hd0,gpt23 --hint-efi=hd0,gpt23 --hint-baremetal=ahci0,gpt23  d9f64562-53cf-4efa-ba54-83703eed0ead
	else
	  search --no-floppy --fs-uuid --set=root d9f64562-53cf-4efa-ba54-83703eed0ead
	fi
	echo	'Loading Linux 4.3.0-1-amd64 ...'
	linux	/boot/vmlinuz-4.3.0-1-amd64 root=UUID=d9f64562-53cf-4efa-ba54-83703eed0ead ro  quiet
	echo	'Loading initial ramdisk ...'
	initrd	/boot/initrd.img-4.3.0-1-amd64
	
linux	/boot/vmlinuz-4.3.0-1-amd64 root=UUID=d9f64562-53cf-4efa-ba54-83703eed0ead ro  quiet
specifies the kernel to load and
initrd	/boot/initrd.img-4.3.0-1-amd64
specifies the initrd or initramfs.

The Arch Way

Arch complicates this for booting it with another distribution's GRUB by splitting the microcode correction out of the initramfs or the initrd with the justification that because of upstream changes the split is the only way to load the microcode early in the boot process. In my opinion this doesn't seem to be a real justification since distributions that use dracut for initramfs generation can include the microcode early and include it in the initramfs. In this excerpt from Arch's native grub.cfg

menuentry 'Arch Linux' --class arch --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-simple-789e80e5-5f66-4eb8-a471-03fb728e8c95' {
	savedefault
	load_video
	set gfxpayload=keep
	insmod gzio
	insmod part_gpt 
	insmod ext2
	set root='hd0,gpt25'
	if [ x$feature_platform_search_hint = xy ]; then
	  search --no-floppy --fs-uuid --set=root --hint-bios=hd0,gpt25 --hint-efi=hd0,gpt25 --hint-baremetal=ahci0,gpt25  789e80e5-5f66-4eb8-a471-03fb728e8c95
	else
	  search --no-floppy --fs-uuid --set=root 789e80e5-5f66-4eb8-a471-03fb728e8c95
	fi
	echo	'Loading Linux linux ...'
	linux	/boot/vmlinuz-linux root=UUID=789e80e5-5f66-4eb8-a471-03fb728e8c95 rw  resume=/dev/disk/by-uuid/69bb9b40-aedd-4278-ac57-0113a7dc816f splash=silent quiet showopts video.use_native_backlight=1
	echo	'Loading initial ramdisk ...'
	initrd	/boot/intel-ucode.img /boot/initramfs-linux.img
		
you can see the difference and the cause for the problem when booting with another distribution's GRUB in the line
initrd	/boot/intel-ucode.img /boot/initramfs-linux.img
which specifies two images to load, the microcode image (/boot/intel-ucode.img and the default initramfs or initrd (/boot/initramfs-linux.img). Other distributions' GRUB scripts are not implemented in a way that can deal with more than one image.

The Solution

The solution is to simply copy Arch's menu entries in its own native grub.cfg (/boot/grub/grub.cfg) and paste it over the Arch entries in the grub.cfg generated by the GRUB of the distribution you have chosen to manage booting your multi-boot system. I use the openSUSE installation's GRUB to boot all of the OSes on this laptop, so I replaced the Arch (and Antergos, Netrunner, and Manjaro) entries openSUSE's grub.cfg (/boot/grub2/grub.cfg and replaced it with those from each of these distributions' native grub.cfg. It is also sometimes necessary to further edit the new entries because there may be parameters defined in these distribution's native set of /etc/grub.d scripts. The following excerpt of the openSUSE grub.cfg shows Arch's main entry after replacement with Arch's native entries and further editing.

...
menuentry 'Arch Linux' --class arch --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-simple-789e80e5-5f66-4eb8-a471-03fb728e8c95' {
	savedefault
	load_video
	set gfxpayload=keep
	insmod gzio
	insmod part_gpt 
	insmod ext2
	set root='hd0,gpt25'
	if [ x$feature_platform_search_hint = xy ]; then
	  search --no-floppy --fs-uuid --set=root --hint-bios=hd0,gpt25 --hint-efi=hd0,gpt25 --hint-baremetal=ahci0,gpt25  789e80e5-5f66-4eb8-a471-03fb728e8c95
	else
	  search --no-floppy --fs-uuid --set=root 789e80e5-5f66-4eb8-a471-03fb728e8c95
	fi
	echo	'Loading Linux linux ...'
	linuxefi	/boot/vmlinuz-linux root=UUID=789e80e5-5f66-4eb8-a471-03fb728e8c95 rw  resume=/dev/disk/by-uuid/69bb9b40-aedd-4278-ac57-0113a7dc816f splash=silent quiet showopts video.use_native_backlight=1
	echo	'Loading initial ramdisk ...'
	initrdefi	/boot/intel-ucode.img /boot/initramfs-linux.img
}
...
		
Note that in openSUSE if the user chooses to use linuxefi when installing it, commands are linuxefi and initrdefi instead of linux and initrd in
inuxefi	/boot/vmlinuz-linux root=UUID=789e80e5-5f66-4eb8-a471-03fb728e8c95 rw  resume=/dev/disk/by-uuid/69bb9b40-aedd-4278-ac57-0113a7dc816f splash=silent quiet showopts video.use_native_backlight=1
and
initrdefi	/boot/intel-ucode.img /boot/initramfs-linux.img

As you can see, this has both images specified. Had I chosen to not use linuxefi (there may not be an option anymore in openSUSE) when installing openSUSE or if using another distribution that doesn't use linuxefi, the above lines would have linux and initrd instead of linuxefi and initrdefi.

Other Benefits

Copying entries from a distribution's own grub.cfg to the booting distribution's grub.cfg file has other benefits. It maintains the the booted distributions kernel command line options added to its own /etc/default/grub configuration, although these can be added manually in the booting distributions grub.cfg, and maintains the visual polish by preserving elements of the native grub.cfg, as if it was being booted with its own GRUB, allowing Plymouth, for example to display as intended.

Fedora happens to have the best transition from selection in GRUB through the display of the Plymouth to the to the appearance of the login greeter. This would not be possible if using another distribution's 30_os-prober generated entry. The grub.cfg I am currently using is here for reference.

There is one drawback when using this method with non-Arch distributions, which is that when the kernel is updated in these distributions, the booting distgrub.cfg must be edited to reflect the updated kernel version. This is not a problem for booting Arch, since it is not possible to install more than one version of the same kernel flavor. Also, the grub.cfg file of the booting distribution will be overwritten when its kernel is updated, so some manual system is needed to replace the overwritten entries.

Conclusion

I read a review of Manjaro that mentioned the issue discussed in this article as a major failure of Manjaro. But as it turns out this is actually a feature of The Arch Way which uses mkinitcpio, for simplicity, to generate the initramfs instead of dracut and requires some knowledge of how it works for proper maintenance.

But solving this issue illustrates one of the benefits of using GNU/Linux, with some knowledge a user can use his/her computing tools as he/she wishes --using multiple installations, mixing tools from different distributions, etc.

blog comments powered by Disqus