Installing Grub2
logo
Installing Grub2
Apr 4, 2022

By default Slackware uses eLILO as its bootloader ( on UEFI systems, LILO on legacy systems ). eLILO works, it's relatively easy to configure, and if you just want to boot your machine and get to work it is all you need to boot your Slackware box. If you're like me, always tinkering and experimenting with your machine ( if I don't break my machine at least twice a month I probably haven't had time to get on it), then you may be thinking about installing the GRUB. Slackware includes GRUB in the official installation, it's just not installed as the default bootloader. Installing GRUB as the bootloader is pretty easy if you follow the right steps, but there are times when that isn't the case. In this post I will take you through the process of installing GRUB on your machine, and these instructions should work on any Linux distribution, not just Slackware.

I strongly encourage to create a USB recovery bootdisk now if you haven't already. It will make your life easier, especially if you are like me and can't leave well enough alone. I break my machine regularly, but the recovery USB allows me to go in and fix things so I can break it again. In the end it's your choice, but you've been warned.

First, and this is very important, remove any USB drives from your machine, and if you have external storage media connected you should disconnect those as well. Before we get started, make sure your EFI partiion is mounted on /boot/efi that these three kernel modules are loaded:


# make sure you use the device name for your machine
jkenobi@slackerhacks:~$ sudo mount /dev/nvme0n1p1 /boot/efi

# These modules are needed to add a boot entry in the firmware
jkenobi@slackerhacks:~$ for mod in efivarfs efivars dm-mod; do sudo modprobe $mod; done

Most of the time you can just run 'grub-install' from the command line and grub will install just fine. This method however has been known to install the i386 version of GRUB on 64-bit machines, leaving users with an unbootable system. That's why it is important to have a USB bootdisk on hand in case you have to recover from an unbootable state. To make sure GRUB installs correctly, we'll use options to give GRUB the information it needs to install correctly.


kenobi@slackerhacks:~$ sudo grub-install --target=x86_64-efi --boot-directory=/boot --efi-directory=/boot/efi \
>/dev/nvme0n1 --recheck --debug | tee grub.log

# ...

# generate GRUB configuration file
jkenobi@slackerhacks:~$ sudo grub-mkconfig -o /boot/grub/grub.cfg

The --target option let's grub know that we are running a 64-bit machine with EFI firmware and to create the appropriate image. The next two are self-explanatory, explicitly specifying the location of the boot and efi directories. Next we tell grub what device the it is to be installed on. The --recheck option tells grub to delete the device map if one exists and create a new one, and the --debug option generates a ton of output, but we're mainly concerned with the last couple of lines that tell us if grub was able to install a boot entry in the firmware. You have to have efibootmgr installed in order for this to take place. Piping the output to the 'tee' command prints the output to the console and also to a text file which I named grub.log in the current directory. It could be useful if for some reason GRUB doesn't boot. Without the --debug option grub will only print  the line 'no errors occurred' or something like that, though doesn't necessarily mean your machine will boot successfully. Finally we let GRUB generate its own configuration file with the 'grub-mkconfig' command.

Before rebooting, let's take a look at the grub.cfg file. Depending on how many different kernels you have in your boot directory, if you open grub.cfg in a text editor you will see something like this:



#
# DO NOT EDIT THIS FILE
#
# It is automatically generated by grub-mkconfig using templates
# from /etc/grub.d and settings from /etc/default/grub
#

### BEGIN /etc/grub.d/00_header ###
if [ -s $prefix/grubenv ]; then
  load_env
fi
if [ "${next_entry}" ] ; then
   set default="${next_entry}"
   set next_entry=
   save_env next_entry
   set boot_once=true
else
   set default="0"
fi

if [ x"${feature_menuentry_id}" = xy ]; then
  menuentry_id_option="--id"
else
  menuentry_id_option=""
fi

export menuentry_id_option

if [ "${prev_saved_entry}" ]; then
  set saved_entry="${prev_saved_entry}"
  save_env saved_entry
  set prev_saved_entry=
  save_env prev_saved_entry
  set boot_once=true
fi

function savedefault {
  if [ -z "${boot_once}" ]; then
    saved_entry="${chosen}"
    save_env saved_entry
  fi
}

function load_video {
  if [ x$feature_all_video_module = xy ]; then
    insmod all_video
  else
    insmod efi_gop
    insmod efi_uga
    insmod ieee1275_fb
    insmod vbe
    insmod vga
    insmod video_bochs
    insmod video_cirrus
  fi
}

if [ x$feature_default_font_path = xy ] ; then
   font=dejavusansmono
else
insmod part_gpt
insmod xfs
search --no-floppy --fs-uuid --set=root 9ce75585-8ad8-4067-927f-9e6af096983b
    font="/usr/share/grub/dejavusansmono.pf2"
fi

if loadfont $font ; then
  set gfxmode=auto
  load_video
  insmod gfxterm
  set locale_dir=$prefix/locale
  set lang=en_US
  insmod gettext
fi
terminal_output gfxterm
if [ x$feature_timeout_style = xy ] ; then
  set timeout_style=menu
  set timeout=10
# Fallback normal timeout code in case the timeout_style feature is
# unavailable.
else
  set timeout=10
fi
### END /etc/grub.d/00_header ###

### BEGIN /etc/grub.d/10_linux ###
menuentry 'Slackware-15.0 GNU/Linux' --class slackware_15_0 --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-simple-9ce75585-8ad8-4067-927f-9e6af096983b' {
	load_video
	insmod gzio
	insmod part_gpt
	insmod xfs
	insmod ext2
	search --no-floppy --fs-uuid --set=root 56ad471c-6ef7-42a9-bd30-d982ec539a06
	echo	'Loading Linux 5.15.19 ...'
	linux	/vmlinuz-huge-5.15.19 root=UUID=9ce75585-8ad8-4067-927f-9e6af096983b ro  
	echo	'Loading initial ramdisk ...'
	initrd	/initrd-5.15.19.gz
}
submenu 'Advanced options for Slackware-15.0 GNU/Linux' $menuentry_id_option 'gnulinux-advanced-9ce75585-8ad8-4067-927f-9e6af096983b' {
	menuentry 'Slackware-15.0 GNU/Linux, with Linux 5.15.19' --class slackware_15_0 --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-5.15.19-advanced-9ce75585-8ad8-4067-927f-9e6af096983b' {
		load_video
		insmod gzio
		insmod xfs
		insmod part_gpt
		insmod ext2
		search --no-floppy --fs-uuid --set=root 56ad471c-6ef7-42a9-bd30-d982ec539a06
		echo	'Loading Linux 5.15.19 ...'
		linux	/vmlinuz-huge-5.15.19 root=UUID=9ce75585-8ad8-4067-927f-9e6af096983b ro  
		echo	'Loading initial ramdisk ...'
		initrd	/initrd-5.15.19.gz
	}
	menuentry 'Slackware-15.0 GNU/Linux, with Linux 5.15.19 (recovery mode)' --class slackware_15_0 --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-5.15.19-recovery-9ce75585-8ad8-4067-927f-9e6af096983b' {
		load_video
		insmod gzio
		insmod part_gpt
		insmod xfs
		insmod ext2
		search --no-floppy --fs-uuid --set=root 56ad471c-6ef7-42a9-bd30-d982ec539a06
		echo	'Loading Linux 5.15.19 ...'
		linux	/vmlinuz-huge-5.15.19 root=UUID=9ce75585-8ad8-4067-927f-9e6af096983b ro single 
		echo	'Loading initial ramdisk ...'
		initrd	/initrd-5.15.19.gz
	}
	menuentry 'Slackware-15.0 GNU/Linux, with Linux huge' --class slackware_15_0 --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-huge-advanced-9ce75585-8ad8-4067-927f-9e6af096983b' {
		load_video
		insmod gzio
		insmod part_gpt
		insmod xfs
		insmod ext2
		search --no-floppy --fs-uuid --set=root 56ad471c-6ef7-42a9-bd30-d982ec539a06
		echo	'Loading Linux huge ...'
		linux	/vmlinuz-huge root=UUID=9ce75585-8ad8-4067-927f-9e6af096983b ro  
		echo	'Loading initial ramdisk ...'
		initrd	/initrd.gz
	}
	menuentry 'Slackware-15.0 GNU/Linux, with Linux huge (recovery mode)' --class slackware_15_0 --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-huge-recovery-9ce75585-8ad8-4067-927f-9e6af096983b' {
		load_video
		insmod gzio
		insmod part_gpt
		insmod xfs
		insmod ext2
		search --no-floppy --fs-uuid --set=root 56ad471c-6ef7-42a9-bd30-d982ec539a06
		echo	'Loading Linux huge ...'
		linux	/vmlinuz-huge root=UUID=9ce75585-8ad8-4067-927f-9e6af096983b ro single 
		echo	'Loading initial ramdisk ...'
		initrd	/initrd.gz
	}
	menuentry 'Slackware-15.0 GNU/Linux, with Linux 5.15.19' --class slackware_15_0 --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-5.15.19-advanced-9ce75585-8ad8-4067-927f-9e6af096983b' {
		load_video
		insmod gzio
		insmod part_gpt
		insmod ext2
		insmod xfs
		search --no-floppy --fs-uuid --set=root 56ad471c-6ef7-42a9-bd30-d982ec539a06
		echo	'Loading Linux 5.15.19 ...'
		linux	/vmlinuz-generic-5.15.19 root=UUID=9ce75585-8ad8-4067-927f-9e6af096983b ro  
		echo	'Loading initial ramdisk ...'
		initrd	/initrd-5.15.19.gz
	}
	menuentry 'Slackware-15.0 GNU/Linux, with Linux 5.15.19 (recovery mode)' --class slackware_15_0 --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-5.15.19-recovery-9ce75585-8ad8-4067-927f-9e6af096983b' {
		load_video
		insmod gzio
		insmod part_gpt
		insmod ext2
		insmod xfs
		search --no-floppy --fs-uuid --set=root 56ad471c-6ef7-42a9-bd30-d982ec539a06
		echo	'Loading Linux 5.15.19 ...'
		linux	/vmlinuz-generic-5.15.19 root=UUID=9ce75585-8ad8-4067-927f-9e6af096983b ro single 
		echo	'Loading initial ramdisk ...'
		initrd	/initrd-5.15.19.gz
	}
	menuentry 'Slackware-15.0 GNU/Linux, with Linux generic' --class slackware_15_0 --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-generic-advanced-9ce75585-8ad8-4067-927f-9e6af096983b' {
		load_video
		insmod gzio
		insmod part_gpt
		insmod xfs
		insmod ext2
		search --no-floppy --fs-uuid --set=root 56ad471c-6ef7-42a9-bd30-d982ec539a06
		echo	'Loading Linux generic ...'
		linux	/vmlinuz-generic root=UUID=9ce75585-8ad8-4067-927f-9e6af096983b ro  
		echo	'Loading initial ramdisk ...'
		initrd	/initrd.gz
	}
	menuentry 'Slackware-15.0 GNU/Linux, with Linux generic (recovery mode)' --class slackware_15_0 --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-generic-recovery-9ce75585-8ad8-4067-927f-9e6af096983b' {
		load_video
		insmod gzio
		insmod part_gpt
		insmod xfs
		insmod ext2
		search --no-floppy --fs-uuid --set=root 56ad471c-6ef7-42a9-bd30-d982ec539a06
		echo	'Loading Linux generic ...'
		linux	/vmlinuz-generic root=UUID=9ce75585-8ad8-4067-927f-9e6af096983b ro single 
		echo	'Loading initial ramdisk ...'
		initrd	/initrd.gz
	}
}

### END /etc/grub.d/10_linux ###

### BEGIN /etc/grub.d/20_linux_xen ###
### END /etc/grub.d/20_linux_xen ###

### BEGIN /etc/grub.d/30_os-prober ###
### END /etc/grub.d/30_os-prober ###

### BEGIN /etc/grub.d/30_uefi-firmware ###
### END /etc/grub.d/30_uefi-firmware ###

### BEGIN /etc/grub.d/40_custom ###
# This file provides an easy way to add custom menu entries.  Simply type the
# menu entries you want to add after this comment.  Be careful not to change
# the 'exec tail' line above.
### END /etc/grub.d/40_custom ###

### BEGIN /etc/grub.d/41_custom ###
if [ -f  ${config_directory}/custom.cfg ]; then
  source ${config_directory}/custom.cfg
elif [ -z "${config_directory}" -a -f  $prefix/custom.cfg ]; then
  source $prefix/custom.cfg
fi
### END /etc/grub.d/41_custom ###

GRUB will make an entry for not only each kernel version, but any symbolic links to a kernel  as well. I don't generally run grub-mkconfig myself, but for the sake of this tutorial I included it here. Being the Slacker that I am, I prefer a simpler, less cluttered config file, so I write my own. I usually have three entries for Slackware and one for Windows. The default entry is usually the most recent kernel that I've compiled for my machine, then I have an entry for the generic kernel that ships with Slackware, and an entry to boot into single user mode using the generic kernel. Let's go through the steps real quick.


## /boot/grub/grub.cfg
#
# GRUB configuration file
#
##

# first we let grub know which is our root partition
set root=(hd0,gpt6)

# next we tell grub where to find its modules, configfile, etc.
set prefix=(hd0,gpt6)/boot/grub

# now we load modules for video, filesystem, etc.
insmod efi_gop
insmod efi_uga
insmod vbe
insmod vga
insmod video_bochs
insmod video_cirrus
insmod part_gpt
insmod ext2

# set terminal to text console
terminal_output console

# set timeout
set timeout_style=menu
set timeout=30

This first part of the config file lets grub know where to find its modules so it can boot the kernel. The 'prefix' environment varialble tells grub w86here to find the directory x86_64-efi, where its modules are stored. We then load the modules we need , set the terminal to text mode, and set the timeout to 30 sec before grub boots the default kernel. Now we can set up our entries that will appear in the GRUBs boot menu.


# ....

menuentry 'Slackware Linux 15.0 w/ 5.16.10 kernel' --id default {

         insmod part_gpt
         insmod ext2
         insmod gzio
         set root='hd0,gpt6'
         echo 'Loading vmlinuz-5.16.10...'
         linux /boot/vmlinuz-5.16.10 root=UUID=9ce75585-8ad8-4067-927f-9e6af096983b ro eDP:1920x1080 quiet
         echo 'Loading initrd-5.16.10.gz'
         initrd /boot/initrd-5.16.10

}

Let's take a look at this entry. The first line specifies a menuentry with the label being the text in quotes. That's what will show in GRUBs menu. The --id tag isn't necessary, but there are situations where it is used to identify an entry. The three modules are loaded so GRUB know we have a GPT disk, extX filesystem, and the gzio module is so that it can unzip the initrd. The set root='hd0,gpt' specifes the root partition so that grub can find the kernel and initrd that we specify. The path to the kernel and initrd is relative to this 'set root= ' entry. I could have put 'set root=(hd0,gpt6)/boot', and then the entry for the kernel would be 'linux /vimlinuz-5.16.10 ...'

On my machines this first menu entry changes periodically. I usually keep a recent stable kernel version here. For the next two entries I use the default kernel for the latest Slackware release, which at this time is Slackware 15.0, with kernel version 5.15.19. I use the generic kernel and an initrd so that I'll always have a bootable system. The entry is the same as above, the only difference being the label and the kernel version number. I then make an exact copy of that entry, adding 'single' to the end of the kernel command line, which causes the system to boot into single user mode for system maintenance/repair.

The final version of my grub.cfg file is at the end of this tutorial. For those of you who are like me and run a dual boot configuration with Windows, I'm going to go over the correct way to boot Windows from grub. It's not that different from booting Linux, except that we use GRUBs chainloader. The key is to understand the Windows boot process. The Windows boot configuration is located in a file called BCD. This file is located on the EFI partition in the /EFI/Microsoft/Boot directory. It contains the same sort of information as grub.cfg - root partition, Windows root directory, the path to the file that starts to boot process - using a different format and syntax, of course. Here's my Windows entry in grub.cfg:


## /boot/grub/grub.cfg
#
# GRUB configuration file
#
##

# ...


# Windows boot entry

menuentry 'Windows 11' --id windows {

        insmod part_msdos
        insmod part_gpt
        insmod fat
        insmod chain
        set root='hd0,gpt1'
        chainloader /EFI/Microsoft/Boot/bootmgfw.efi
}

## end of /boot/grub/grub.cfg

And that's really all there is to it. The main thing is understanding the 'set root= ' command doesn't refer to the OS root partition. It serves as a reference point for GRUB to locate to files required to boot the OS. I'm not certain the part_msdos module is necessary, but it doesn't hurt anything. We also load the 'fat' module because the EFI partition has to formatted with either FAT16 or FAT32 filesystem. The chain module enables the chainloader we use to call the bootmgfw.efi file that initiates the rest of the Windows boot process.

Putting all the pieces together it's plain to see that this config file is much easier to read and understand that the one generated by grub-mkconfig. Simple is generally better, as simple systems are easier to debug. Here is my complete grub.cfg file:


## /boot/grub/grub.cfg
#
# GRUB configuration file
#
##

# first we let grub know which is our root partition
set root=(hd0,gpt6)

# next we tell grub where to find its modules, configfile, etc.
set prefix=(hd0,gpt6)/boot/grub

# now we load modules for video, filesystem, etc.
insmod efi_gop
insmod efi_uga
insmod vbe
insmod vga
insmod video_bochs
insmod video_cirrus
insmod part_gpt
insmod ext2

# set terminal to text console
terminal_output console

# set timeout
set timeout_style=menu
set timeout=30

## Linux boot entries

menuentry 'Slackware Linux 15.0 w/ 5.16.10 kernel' --id default {

         insmod part_gpt
         insmod ext2
         insmod gzio
         set root='hd0,gpt6'
         echo 'Loading vmlinuz-5.16.10...'
         linux /boot/vmlinuz-5.16.10 root=UUID=9ce75585-8ad8-4067-927f-9e6af096983b ro eDP:1920x1080 quiet
         echo 'Loading initrd-5.16.10.gz'
         initrd /boot/initrd-5.16.10.gz

}


menuentry 'Slackware Linux 15.0 w/ generic-5.15.19 kernel' --id stable {

         insmod part_gpt
         insmod ext2
         insmod gzio
         set root='hd0,gpt6'
         echo 'Loading vmlinuz-generic-5.15.19...'
         linux /boot/vmlinuz-generic-5.15.19 root=UUID=9ce75585-8ad8-4067-927f-9e6af096983b ro eDP:1920x1080 quiet
         echo 'Loading initrd-generic-5.15.19.gz'
         initrd /boot/initrd-generic-5.15.19.gz

}

menuentry 'Slackware Linux 15.0 w/ generic-5.15.19 kernel(recovery mode)' --id recovery {

         insmod part_gpt
         insmod ext2
         insmod gzio
         set root='hd0,gpt6'
         echo 'Loading vmlinuz-5.16.10...'
         linux /boot/vmlinuz-generic-5.15.19 root=UUID=9ce75585-8ad8-4067-927f-9e6af096983b ro eDP:1920x1080 quiet single
         echo 'Loading initrd-generic-5.15.19.gz'
         initrd /boot/initrd-generic-5.15.19.gz

}

# Windows boot entry

menuentry 'Windows 11' --id windows {

        insmod part_msdos
        insmod part_gpt
        insmod fat
        insmod chain
        set root='hd0,gpt1'
        chainloader /EFI/Microsoft/Boot/bootmgfw.efi
}

## end of /boot/grub/grub.cfg

Congratulations! You have successfully installed and configured GRUB on your machine, and hopefully the process doesn't seem so intimidating. One of the reasons I run Slackware is because it expects us to take control of our machines on a more granular level. It used be said that if you run Debian or RedHat ( Fedora these days ), you'll learn that distro, but if you run Slackware, you'll learn Linux. Hopefully you found this informative, and if you have any questions leave them in the comments below and I'll do my best to answer them.

 



October 2024
SunMonTueWedThuFriSat
  12345
6789101112
13141516171819
20212223242526
2728293031