Tuesday, September 24, 2019

12 - Final Config, XFS quotas, Firmware





Toucan Linux Project - 12


A Roll Your Own Distribution


Goal 1 – Base System


Stage 2 – Building the Base System


In this chapter we'll do a few more steps to finish the system. There is a big difference now because now you have booted into your new system and you no longer need the host (though you may still wish to use it the mount.sh and chroot_to_lfs scripts since you can still work in the graphical environment.) We did install a text based web browser that you can use to still read this while you work.

You can use two virtual terminals for this. When you first login you are in the first terminal. Then press CTRL-ALT-F2 to switch to another terminal, and login again. From it, use

links
https://toucanlinuxproject.blogspot.com

I have done my best to make it readable with a text browser (but you will miss console mouse support for now so this chapter can be done using the host if you want to avoid a lot of typing.)

Now you can switch back and forth from your work window to the browser by using CTRL-ALT-F1 and CTRL-ALT-F2.
You can, of course, still boot into the host, mount the partitions, and chroot to the target and continue working if you choose.

Step 1 - Disable Intermediate Tools

Just to make sure there is nothing using the tools directory from a PATH

mv /tools /tools-old
chmod 000 /tools-old

A note on these tools, now that you have built them there you can use them for another system. All you need to do to setup a new system is create partitions, create the file systems, mount them on a host OS, and put them in the root partition of the new system just like we did here. Then you can proceed building the new host.

If you choose, you can tar up the whole system onto a mountable media with something like this:

mkdir -v /mnt/backup
mount /dev/REMOVEABLE /mnt/backup
cd /mnt/backup
tar -czf /mnt/backup/mysys.tar.gz / --exclude /mnt/backup

You can put this on any filesystem, build and install the kernel and the bootloader, and you will have a working system without going through all the steps again we have so far.

Step 2 Distro Release File

To comply with the Linux Standards Base

cat > /etc/ttlp-release << "EOF"
DISTRIB_ID="The Toucan Linux Project"
DISTRIB_RELEASE="1r"
DISTRIB_CODENAME="KilledBill"
DISTRIB_DESCRIPTION="The Toucan Linux Project"
EOF

Since this is your distro do what you want here. The above is only if you want to stick solely with TTLP.

Step 3 - Fixing /dev/root Debacle

Depending on the boot options, how the system was booted, and several other things you might find yourself trapped into the /dev/root debacle. When Linux boots without an initramfs (initial ram filesystem) it uses a small, in-memory file system called rootfs that contains just the /dev directory and the console node (you can see this code in the kernel source tree in the file init/noinitramfs.c) for kernel startup and this uses a device called /dev/root. Later it mounts the real root device, probably a drive partition, as the root device. But /proc/mounts will still say that the root device is /dev/root and now there is no device /dev/root. This isn't problem for most things but it is a problem for utilities that use /proc/mounts to get the name of the root device.

There's several solutions to this problem. The first is simply making a symbolic link from the real root device to /dev/root. This solves the problem but requires a script to parse the kernel command line to find the real root. Another solution is to patch the kernel to only add /dev/root to /proc/mounts if the root has not been specified on the kernel command line. This is the solution I like because it preserves the real root device in listings and fixes a problem with the kernel (it shouldn't use a device that is later not available). In this method the kernel and user utilities will agree on the truth. It's not that the kernel isn't telling the truth, it's just telling it as it knows it not as everyone else does.

You can find the original patch from William Hubbs on LKML at https://lkml.org/lkml/2013/1/31/574 but I have modified it for newer kernels.

Choice 1) Create the link using s script
This might be more to what the kernel developers intended and it means you don't have to patch the kernel. For this to work we need to parse the kernel command line at /proc/cmdline for the root entry, get the real device, and make the link. Since /dev is actually a virtual filesystem (devfs) we have to make this link after we mount the virtual filesystems. Recall this is handled by a bootscript called mountvirtfs. Here's a script that will use commands available at system initialization to create the link by using the kernel command line to determine to root device. If you change the root device, this will still work.

#!/bin/bash
# Script to create sym link for /dev/root
# real root dev as specified on kernel cmd line
# Micheal R Stute for The Toucan Linux Project
#
for i in `cat /proc/cmdline`; do
   var=`echo $i|cut -c 1-5`
   if [ $var == "root=" ]; then
      dev=`echo $i|cut -f 2 -d '='`
      ln -s $dev /dev/root
   fi ;
done

This can be added to a bootscript like mountvirtfs itself at the bottom of the script. This is a pretty good choice, except it means you can't update the bootscripts without making this change.

To use this option do

cat > /bin/make_root_link.sh << "EOF"
#!/bin/sh
# Script to create sym link for /dev/root for
# root dev as specified on kernel cmd line
# Micheal R Stute for The Toucan Linux Project
#
for i in `cat /proc/cmdline`; do
   var=`echo $i|cut -c 1-5`
   if [ $var == "root=" ]; then
      dev=`echo $i|cut -f 2 -d '='`
      ln -s $dev /dev/root
   fi ;
done
EOF

sed -i "s#ln -sfn /run/shm /dev/shm#ln -sfn /run/shm /dev/shm\\n      /bin/make_root_link.sh\\n#" mountvirtfs

Choice 2) Create a startup script
This is probably a better choice, because it makes the script entirely independent. In this case we'll just put the code in the script.

cat > /etc/rc.d/init.d/makerootlink << "EOF"
#!/bin/sh
########################################################################
# Begin makerootlink
#
# Description : Create the /dev/root link in /dev
#
# Authors     : Michael R Stute - michaelrstute@gmail.com

# Version     : TTLP 1.0
#
########################################################################

### BEGIN INIT INFO
# Provides:            makerootlink
# Required-Start:
# Should-Start: 
# Required-Stop:
# Should-Stop:
# Default-Start:       S
# Default-Stop:
# Short-Description:   Creates the /dev/root link to proper device
# Description:         Use /proc/cmdline to create link to /dev/root
#                      from real root device
### END INIT INFO

. /lib/lsb/init-functions

case "${1}" in
   start)
      log_info_msg "Creating /dev/root link"

      for i in `cat /proc/cmdline`; do
         var=`echo $i|cut -c 1-5`
         if [ $var == "root=" ]; then
            dev=`echo $i|cut -f 2 -d '='`
            ln -s $dev /dev/root || $failed=1
         fi ;
      done
      
      (exit ${failed})
      evaluate_retval
      exit $failed
      ;;

   *)
      echo "Usage: ${0} {start}"
      exit 1
      ;;
esac

# End makerootlink
EOF

chmod 754 /etc/rc.d/init.d/makerootlink
pushd /etc/rc.d/rcS.d
ln -s ../init.d/makerootlink S02makerootlink
popd

Choice 3) Let udev make it
Create a rule to force udev to make the link when creating the real root device. This is very straight forward and is exactly what udev is intended to do. But it if you change your root device, you'll have to change the rule. Very straight forward. If your root partition never changes, then this makes the most sense. Setting it up is very simple

echo 'KERNEL=="sda3", SYMLINK+="root"' > /etc/udev/rules.d/90-make-root-link.rules

Choice 4) Patch the kernel
Patch the kernel to ensure it doesn't add /dev/root to the mounts in the first place. Whether this is intended by the kernel developers or not, adding /dev/root to /proc/mounts does create trouble for many programs that need to know the root device. As you create your own distro you'll find you have a growing list of patches you'll want to add to the kernel anyway, especially in an experimental distro like TTLP. What's one more? This is the official TTLP method of handling this situation. HIGHLY RECOMMEND method especially for BOFHs, purists, and minimalists.

First make the patch

pushd /sources
cat > kernel-fix-root-device.patch << "EOF"
diff -u a/init/do_mounts.c b/init/do_mounts.c
--- a/init/do_mounts.c 2019-09-13 09:52:03.732857317 -0500
+++ b/init/do_mounts.c 2019-09-13 09:51:38.881704523 -0500
@@ -511,7 +511,11 @@
  va_start(args, fmt);
  vsprintf(buf, fmt, args);
  va_end(args);
- fd = ksys_open("/dev/root", O_RDWR | O_NDELAY, 0);
+
+ if (saved_root_name[0])
+ fd = sys_open(saved_root_name, O_RDWR | O_NDELAY, 0);
+ else
+ fd = sys_open("/dev/root", O_RDWR | O_NDELAY, 0);   
  if (fd >= 0) {
  ksys_ioctl(fd, FDEJECT, 0);
  ksys_close(fd);
@@ -555,11 +559,16 @@
 #endif
 #ifdef CONFIG_BLOCK
  {
- int err = create_dev("/dev/root", ROOT_DEV);
-
- if (err < 0)
- pr_emerg("Failed to create /dev/root: %d\n", err);
- mount_block_root("/dev/root", root_mountflags);
+ if (saved_root_name[0]) {
+ int err = create_dev(saved_root_name, ROOT_DEV);
+ if(err < 0)
+ pr_emerg("Failed to create root device: %d\n", err);
+ mount_block_root(saved_root_name, root_mountflags);
+ } else {
+ int err = create_dev("/dev/root", ROOT_DEV);
+ if(err < 0)
+ pr_emerg("Failed to create /dev/root: %d\n", err);
+ mount_block_root("/dev/root", root_mountflags);
  }
 #endif
 }
EOF
popd

Now you need to unpack the kernel source (unless you left the source tree intact as recommended), copy in your config file, and apply the patch. You should be in the kernel source tree underneath /sources such as /sources/linux-5.2.9.

Apply the patch with

patch -Np1 -i ../kernel-fix-root-device.patch

and recompile the kernel, modules, and reinstall using the directions from last chapter.

Step 4 - Limit the Size of the Logs (Optional)

One problem that might occur with our system is that /var is part of the root partition and a user might generate enough messages to fill it up, creating an issue for maintenance. We can use the XFS project quota system to limit the directory to a smaller size to ensure it can't fill the root. If you are the only one using your computer and you aren't concerned about some malicious code using the age old denial of service of filling the root device by causing the system to log a lot of lines, then you can skip this step entirely. Quotas of any kind do slow down the filesystem and if you are looking for extreme performance then you want to avoid quotas anyway. TTLP will not use the standard log daemons by default (syslogd/klogd) but we will replace it later with one that will make sure the logs don't grow too large anyway, rendering this step entirely optional. However, it is still a good tutorial for XFS quotas.

XFS has it's own quota system that can be used to limit the amount of space that users, groups, and projects are allowed. This is beyond what the standard kernel quota support allows. One of the nicest features of XFS is that it allows a directory and all its sub-directories to be considered part of a project and that project can be limited in the amount of disk space it is allowed. This is for any directory (including sub-directories) on the partition, not just mount points.

XFS does this by using extended attributes to mark every file in a directory with a project number and then marking all newly created files with the project number as well using inheritance from the parent directory. Their can be many projects and a hard and soft limit for inodes, blocks, and realtime blocks (realtime is a special sub-partition that XFS supports for fast disk space allocation intended to write streaming data we will cover much later in TTLP). Before we can this we need to add a mount option to the root drive.

If you created your own /var as a separate partition then you might opt out of this step since the logs can't fill the root drive but if you intended to limit the space of /tmp using this method (see the next step) you'll need to do this anyway. If /var is a separate partition then you only need to add the mount option "prjquota" to the options in /etc/fstab. But if /var is part of the root partition the we need to add the mount option in the bootloader. The file we need to modify is /boot/grub/grub.cfg.
Currently there should be a menu entry created at the bottom of the file that looks like this (from last chapter)

menuentry "LFS kernel 5.2-pf Toucan Linux" {
  insmod part_gpt
  insmod fat
  insmod xfs
  set root=(hd0,gpt1)
  linux /vmlinuz-5.2-pf5.ttlp rootfstype=xfs root=/dev/sda3 ro rootfstype=xfs 
}

On the line to load the linux kernel starting with "linux" we need to add a boot parameter called rootflags that is the mount options for the root partition. That line should be modified as follows

linux /vmlinuz-5.2-9.ttlp rootfstype=xfs root=/dev/sda3 ro rootfstype=xfs rootflags=prjquota

where /dev/sda3 is your root device. This will enable project quotas for the root partition.

You now need to reboot before resuming.

You must use one of the methods from step 3 to resolve the /dev/root problem or XFS commands won't work.

Setting Up the Limits

XFS defines a project using two files. The first assigns a project number (called project ID) to a directory tree. This is called /etc/projects. The second assigns a name to a project to make it easier to use. This is recorded in /etc/projid. The project numbers can be any 32-bit number (0 - 4,294,967,295). For the log space allowed we will use a project name "logfiles" and an ID of 11.

Add the project ID  to the system log area (/var/log)

echo "11:/var/log" > /etc/projects

Give project 11 the name "logfiles"

echo "logfiles:11" > /etc/projid

The command to control XFS quotas sis xfs_quota. Within xfs_quota are two modes, one for users to check their own usage and quota, and another for the administrator to make changes to the quotas which is only allowed as the superuser (root). The -x option allows the use of the superuser commands. In this case we have defined a project called logfiles with a project number of 11 and applied it to the /var/log directory tree in the root device. So far we haven't applied this to the filesystem. To do so we first must apply the project to the filesystem which will go through the process of creating the project extended attributes and applying them to all the current files and directories of the project. To do this use

xfs_quota -x -c 'project -s logfiles' /

Now that the current files are marked and the inheritance flags are set on the sub-directories we can now create the limits. As of this moment, no limits have been set.

There are three kinds of limits. The first is the number of inodes the user is allowed to use. The second is the number of blocks of data space the user is allowed to use. The third is the number of blocks in the realtime space that the user is allowed to use. In addition there are two types of limits. The first is the hard limit which determines how much of the given resource is allowed. Once the user has hit this amount, all further allocations of the resources are denied. There is also a soft limit which is the amount of the resource the user is expected to stay under. When the soft limit is exceeded a timer starts and when the timer reaches zero the soft limits are enforced as though they are hard limits. This gives the user a grace period to use more resources than the soft limit, but if the situation is the same when the timer runs out they aren't allowed any more usage until they first delete enough data or inodes to go below the soft limit then the timer is reset. For the logfiles project we want hard limits.

The xfs_quota command is used to administrate XFS quotas. To set the hard limit to 4GB of log file space use

xfs_quota -x -c 'limit -p bhard=4g logfiles' /

The -x option turns on "expert" mode which is superuser mode. The -c specifies the command to run which is limit to adjust the limits. The -p options specifies you are modifying a project quota. The bhard option selects the data block hard limit and sets it to the number of blocks required to allow 4GB space for the project named "logfile". The last required parameter is the filesystem (XFS partition) on which to enforce the quota.

Now we can check it a couple of ways. We can show the filesystem paths with the path command.

# xfs_quota -x -c path
      Filesystem          Pathname
[000] /                   /dev/sda3 (pquota)
 001  /home               /dev/sda4
 002  /usr/local          /dev/sda5
 003  /var/log            /dev/sda3 (project 11, logfiles)

Here we see all the XFS filesystems on the computer (I have my work laptop partitioned as a root, boot, home, /usr/local primary and secondary, the boot is not XFS and the secondary /usr/local is not mounted). Here you can see that only root has been mounted with the pquota (same a prjquota) support. It also shows the project 11, "logfiles", applied to /var/log. We can see how much the of limit is used with the report command.

# xfs_quota -x -c report
Project quota on / (/dev/sda3)
                               Blocks
Project ID       Used       Soft       Hard    Warn/Grace
---------- --------------------------------------------------
#0           17514628          0          0     00 [--------]
logfiles         7088          0    4194304     00 [--------]

You can find more information about XFS quotas in the man page for xfs_quota. Quota for realtime sub-partitions is not supported nor is the soft limit warning system built into XFS. You'll need to use the warnquota command instead.

Step 5 - Handling /tmp

The /tmp directory is an area used for short term transitory space. This might be for creating an intermediate file in a print process or some temporary data used during processing. All users can write to the directory but the sticky bit is set only the file owner, directory owner, or root can delete or rename files in the directory. But files are readable by anyone by default for any distros so this is not a place to store data that should be private. TTLP modifies the umask so that files are not publicly readable, however using /tmp is still not a good idea for private data. Since a user can read the data (unless the default umask is changed per TTLP) they can make a copy of it. However, many programs will still use it and adjust permissions on file creation to limit access. This is often a place for named pipes (a device which one process writes to and another reads from with a name and location on a drive -- also called a FIFO), Unix domain sockets (another inter-process communication device), or temporary directories applications might use. A programmer might choose /tmp over something in the user's directory because the system will clean the /tmp periodically which ensures these temporary devices get deleted.

The speed of the temporary directory can help with the speed of overall processes that use it for temporary storage, making if beneficial to put on a fast device. Exactly how big it should be is another question entirely. Users (and applications) should not be encouraged to write large amounts of data to the /tmp directory so keeping it small will certainly discourage misuse. If it is part of the root partition, it can be used to fill up the partition and cause problems. Generally the most it should have is 500MB but even 200MB is sufficient (it seems strange to think of a 200MB temporary area when my first hard drive was 10MB maximum) There are three good ways to handle the /tmp directory.

1) Keep it in the root partition.
This is a good choice especially if the root drive is on an NVMe or SSD drive. But you should put a project quota on it like we did the /var/log directory. To set up the quota

echo "10:/tmp" >> /etc/projects
echo "tmp:10" >> /etc/projid
xfs_quota -x -c 'project -s tmp' /
xfs_quota -x -c 'limit -p bhard=200m logfiles' /

This sets the maximum size of the temporary area to be 200m for all users except the superuser.

2) Put it on a different partition. You may opt for a faster drive such as an SSD or NVMe if your main drive is a hard drive. In this case you create the partition, create a file system on it (XFS is still a good choice), and mount it using /tmp as the mount point. For this example we'll assume that /dev/sdX2 is the partition you wish to use for /tmp but you'll need to replace it with the proper device.

mkfs.xfs /dev/sdX2
echo "/dev/sdX2        /tmp         xfs        defaults,noatime,nosuid   0   1" >> /etc/fstab
mount /tmp

In future system starts, /tmp will be automatically mounted. Be sure to use the real device in the command above.

Using a separate partition ensures it can't be used to fill up the root partition. If you do have applications that write large amounts of data to /tmp this is probably your best choice so you can use an SSD or NVMe drive for better performance.

3) Use a tmpfs. The Linux kernel has a type of filesystem called tmpfs which is designed to be exactly what we want. It is a RAM disk but it automatically shrinks and grows depending on the data it holds. It expands as data is written to it (up to an optional upper limit) and frees the memory when files are removed. This is ideal for /tmp and is the option we will use for TTLP. The only caveat here is if you have low RAM in your system this might not be a good choice, but with an upper limit of 200M it shouldn't be a problem for any system with at least 2GB of RAM. Remember it won't use all 200MB unless it is full.

Using it is very easy.

echo "tmpfs          /tmp         tmpfs    size=200,defaults,nosuid,noatime   0   0" >> /etc/fstab
mount /tmp

Now you have a super fast RAM disk for the temporary storage area and it will be mounted automatically whenever you boot. It will use, at most, 200M of RAM. If you want a bigger or smaller temporary area change the 200M above to the size you want.

It is possible to specify the size of the tmpfs as a percentage of memory using size=xx% such as size=20% and if you don't specify a size it defaults to 50% which could be a real problem on a 2GB system.

Step 6 - CPU microcode

CPU vendors often issue new microcode for their CPUs. This often is to handle security problems and sometimes as a way to increase performance. Unless you really need an older version of microcode you should always run the latest version from your vendor. But before you do that, first update the BIOS to latest version available from your system vendor since the BIOS will load the microcode and the latest from your CPU vendor (AMD or Intel) will be included in your BIOS.

Once your BIOS is up to date, check to see if you need to update the microcode.
There are two ways to load new microcode for your system. The easiest is called "late loading" and loads after the kernel has brought up user space. If the microcode contains essential security patches they are loaded in the system initialization phase which might be too late. It is still a good way to test a version of the microcode.

The procedure is different for AMD and Intel CPUs so we'll handle them separately.

Intel

First you'll need to determine the three byte code that identifies your processor.

head /proc/cpuinfo

Look for the following lines

cpu family      : 6
model           : 142
model name      : Intel(R) Core(TM) i7-8565U CPU @ 1.80GHz
stepping        : 11

Write down family, model, and stepping then convert them to hexadecimal. Run the following to do this

printf "%x\n" `grep 'cpu family' /proc/cpuinfo|uniq |cut -f 2 -d ':'`
printf "%x\n" `grep model /proc/cpuinfo|grep -v name|uniq |cut -f 2 -d ':'`
printf "%x\n" `grep stepping /proc/cpuinfo|uniq |cut -f 2 -d ':'`

For the above the numbers are 6 for the family, 8e for the model, and b for the stepping, giving 06-83-0b. With that three byte combination in hand go to

https://downloadcenter.intel.com/download/28087/Linux-Processor-Microcode-Data-File

and download the file that is named using those three numbers

06-83-b0

for the above CPU. If Intel has changed the download site, the page at the link above will have a link to the correct page.
Once the file is downloaded place it in the area where the kernel expects to find it

mkdir -pv /lib/firmware/intel-ucode
mv -v xx-yy-zz /lib/firmware/intel-ucode

Verify the kernel is setup to load Intel microcode

General Setup --->
  [*] Initial RAM filesystem and RAM disk (initramfs/initrd) support
      ()    Initramfs source file(s)
  [*]   Support initial ramdisk/ramfs compressed using gzip
  [*]   Support initial ramdisk/ramfs compressed using bzip2
  [*]   Support initial ramdisk/ramfs compressed using LZMA
  [*]   Support initial ramdisk/ramfs compressed using XZ
  [*]   Support initial ramdisk/ramfs compressed using LZO
  [*]   Support initial ramdisk/ramfs compressed using LZ4

Processor type and features  --->
  [*] CPU microcode loading support
  [*]   Intel microcode loading support

The make defconfig will add support for both Intel and AMD processors, making it unlikely these are not already specified. If you made changes to the kernel you need to recompile, reinstall, and then continue with the next step.

Test the loading of the microcode but first making sure you have nothing running you haven't saved. Then test using "load late" with

echo 1 > /sys/devices/system/cpu/microcode/reload

It all goes well, it will return and nothing will appear to have happened. If it fails, then the system might lock up and you'll need to power off to restart. If it looks like all went well then check it will

dmesg | grep 'microcode'

It will return something like the following

[    0.158208] MDS: Vulnerable: Clear CPU buffers attempted, no microcode
[    1.757722] microcode: sig=0x806eb, pf=0x80, revision=0x98
[    1.758267] microcode: Microcode Update Driver: v2.2.

In the above case it is showing that the CPU already has the proper version of microcode and it doesn't need to be updated. If that's the case, you're done but it might be updated in the future, so continue reading so you'll know what to do if that happens.

The sig= line shows the version (in little-endian) currently loaded. Since the versions are the same, nothing needs to be done (for my system updating the BIOS also updated it to the most current version of the microcode). Here is from a different system with a need to update the microcode

[    0.827634] microcode: sig=0x806e9, pf=0x80, revision=0xb4
[    0.827735] microcode: Microcode Update Driver: v2.2.
[  520.005457] microcode: sig=0806e9, pf=80, revision=0x38
[  520.057063] microcode: updated to revision 0xb4, date = 2019-04-01
[  520.057731] microcode: sig=0x806e9, pf=0x80 revision=0xb4

Here we can see on line 1 that the file is revision 0xb4. Line 3 shows the current version as revision 0x38 which is an older version requiring an update. The kernel updated the microcode as shown on line 4 and prints the loaded version on line 5. If you see "updated to revision" if means you need to load new microcode.

We need to switch the microcode load to "early load" where the kernel will load it as soon as possible. See the section "Early Loading" below.

AMD

Find the family of your CPU

cat /proc/cpuinfo | grep family

It will return something like

cpu family  : 15

This shows the family. Now download the proper microcode file from

https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git/tree/amd-ucode

Families 10h to 14h (16 to 20) are in microcode_amd.bin. Families 15h, 16h and 17h have their own files. Install the microcode with

mkdir p /lib/firmware/amd-ucode
mv microcode_amd_famxxh.bin /lib/firmware/amd-ucode

Verify the kernel can install the AMD microcode. As with Intel the default configuration for the architecture will enable, but if you enabled them, recompile the kernel, install it, and reboot before continuing.

General Setup --->
  [*] Initial RAM filesystem and RAM disk (initramfs/initrd) support
      ()    Initramfs source file(s)
  [*]   Support initial ramdisk/ramfs compressed using gzip
  [*]   Support initial ramdisk/ramfs compressed using bzip2
  [*]   Support initial ramdisk/ramfs compressed using LZMA
  [*]   Support initial ramdisk/ramfs compressed using XZ
  [*]   Support initial ramdisk/ramfs compressed using LZO
  [*]   Support initial ramdisk/ramfs compressed using LZ4

Processor type and features  --->
  [*] CPU microcode loading support
  [*]   AMD microcode loading support


Now test the firmware in "load late" mode. Be sure any data you want is saved then.

echo 1 > /sys/devices/system/cpu/microcode/reload

Now check the kernel logs with

dmesg | grep -e 'microcode

If returns something along this lines

[    0.307619] microcode: CPU0: patch_level=0x010000b6
[    0.307671] microcode: CPU1: patch_level=0x010000b6
[    0.307743] microcode: Microcode Update Driver: v2.2.

the there is no need to update your microcode. It is the latest available for your chip as supplied (probably) by your BIOS. If instead it shows

[    0.307619] microcode: CPU0: patch_level=0x010000b6
[    0.307671] microcode: CPU1: patch_level=0x010000b6
[    0.307743] microcode: Microcode Update Driver: v2.2.
[  187.928891] microcode: CPU0: new patch_level=0x010000c8
[  187.928899] microcode: CPU1: new patch_level=0x010000c8

It shows the microcode was updated, requiring an "early load" initial disk.

Early Load

To early load the microcode we need to create an initial ramdisk (initrd) that contains a cpio archive of the file with a given name located in a given directory. While this can be done manually the kernel maintainers have provided a tool that can be used instead.

Here's a crude example how to prepare an initrd with microcode (this is normally done automatically by the distribution, when recreating the initrd, so you don't really have to do it yourself unless, of course, you are creating your own distribution.) The tool as provided loads all the microcode for all processors into the archive, instead we'll use only the microcode file we need.

Make the script

echo > /usr/bin/create_ucode_initd << "EOF"
#!/bin/bash

if [ -z "$1" ]; then
    echo "You need to supply an initrd file"
    exit 1
fi

if [ -z "$2" ]; then
    echo "You need to supply an microcode file"
    exit 1
fi

INITRD="$1"
MCFILE="$2"

DSTDIR=kernel/x86/microcode
TMPDIR=/tmp/initrd

rm -rf $TMPDIR

mkdir $TMPDIR
cd $TMPDIR
mkdir -p $DSTDIR

if [ -d /lib/firmware/amd-ucode ]; then
        cat /lib/firmware/amd-ucode/$MCFILE > $DSTDIR/AuthenticAMD.bin
fi

if [ -d /lib/firmware/intel-ucode ]; then
        cat /lib/firmware/intel-ucode/$MCFILE > $DSTDIR/GenuineIntel.bin
fi

find . | cpio -o -H newc >../ucode.cpio
cd ..
mv $INITRD $INITRD.orig
cat ucode.cpio $INITRD.orig > $INITRD

rm -rf $TMPDIR
EOF

Now use the script to create the initrd

mount /boot
create_ucode_initrd /boot/early_ucode.cpio <your ucode file>

replacing <your ucode file> with the AMD or Intel microcode file as determined above. Then enable the initrd in Grub's config file. You simply need to add the following to the menuentry section after the linux line in the grub.cfg. It should now look like this

menuentry "Toucan Linux, Linux 5.2.29" {
   set root=(hd0,1)
   insmod xfs
   linux /vmlinuz-5.2.9-ttlp root=/dev/sda2 ro rootfstype=xfs
   initrd /early_ucode.cpio
}

Now reboot. If all goes well then you can use the dmesg command to verify the microcode was loaded (as we did before).
If something goes wrong and the system fails to boot, you can go to the menu entry in Grub, press 'e' to edit with BACKSPACE or DEL, and remove the "initrd /early_ucode.cpio" line, and press CTRL-X to complete booting. You can then remove the line from the Grub config file or place a '#' in front of the line to ignore it. But if the "late load" test worked, there is little chance of trouble.

Step 7 - Firmware

Many hardware components including network interfaces (both wired and wireless), sound cards, video cards, and USB controllers might need firmware updates in order to work. This is certainly true with many wireless network adapters. If you have failed to get your wireless network working, this is probably the reason.

Fortunately it is easy to install the firmware. For now we'll do it manually, but later we'll have the package manager handle it for us.

First, retrieve the firmware using

pushd /sources
wget https://cdn.kernel.org/pub/linux/kernel/firmware/linux-firmware-20190815.tar.xz --no-check-certificate

Then exploded it and remove the unnecessary license files

tar -xf  linux-firmware-20190815.tar.xz
cd linux-firmware-20199815
rm LICEN[SC]E*

Rename it and move it where the kernel expects to find it.

cd ..
mv -v linux-firmware-20190815 /lib/firmware

If you created the firmware directory to install microcode above run this

mv -v firmware/* /lib/firmware

If you didn't create the firmware directory use this command

mv -v firmware /lib

Now reboot the system and boot into TLLP Linux. When it has finished, login as root and check which firmware is loaded with

dmesg|grep firmware

Return to your previous working directory with

popd

For me it returned

[    5.888806] iwlwifi 0000:00:14.3: Direct firmware load for iwlwifi-9000-pu-b0-jf-b0-46.ucode failed with error -2
[    6.021114] [drm] Finished loading DMC firmware i915/kbl_dmc_ver1_04.bin (v1.4)
[    6.175951] Bluetooth: hci0: Minimum firmware build 1 week 10 2014
[    6.178349] Bluetooth: hci0: Found device firmware: intel/ibt-17-16-1.sfi
[    7.512657] Bluetooth: hci0: Waiting for firmware download to complete
[   67.483737] iwlwifi 0000:00:14.3: Direct firmware load for iwlwifi-9000-pu-b0-jf-b0-45.ucode failed with error -2
[  128.923158] iwlwifi 0000:00:14.3: Direct firmware load for iwlwifi-9000-pu-b0-jf-b0-44.ucode failed with error -2
[  190.372566] iwlwifi 0000:00:14.3: loaded firmware version 43.95eb4e97.0 op_mode iwlmvm

Showing it loaded firmware for the Intel i915 video hardware, the Intel Bluetooth hardware, and the Intel IWL wireless hardware. Notice the driver tried loading version 46, then 45 and 44, before version 43 for the IWL. That is normal for some drivers though it can be undesirable because some drivers wait 30 seconds before trying another version making your boot time (or when the module is loaded on use) very long. Don't worry, we can fix this later.

Next time, we'll start by making the boot Grub screen a wee bit more fancy with our mascot Killbill, move on to our second goal, angband,  and start on the package manager.

But Wait My NIC Still Doesn't Work!

If you have newer hardware this can still be a problem, especially for wireless interfaces. If that's the case switch to a wired interface as they generally are much simpler. If you don't have a wired interface then you might get a USB Ethernet adapter to try a wire or even a different (and common) USB wireless adapter. Here's a site that has a list of USB wireless adapters that are known to work with Linux (https://www.wirelesshack.org/top-linux-compatible-usb-wireless-adapters.html). If the host could use your network but the target can not it is a matter of configuration or missing firmware. Some vendors don't license their firmware in a way that is Linux friendly and you'll need to go to their site to get it. If you buy a lot of newer gear you'll need on of these anyway. It is a way to get a network connection long enough to download what you need to get the built-in hardware working.

Copyright (C) 2019 Michael R Stute

Tuesday, September 10, 2019

11 - UEFI Boot Setup








Toucan Linux Project - 11


A Roll Your Own Distribution
Goal 1 – Base System
Stage 2 – Building the Base System

This installment will cover the changes required to boot the system using UEFI. Last time we did the much simpler legacy boot option using the Master Boot Record of the BIOS. Though UEFI makes booting from multiple media much easier, to do so it introduces complexity. First, we'll cover the UEFI boot process. Even if you are using MBR I suggest you read through this section for additional understanding of the Linux boot process. At the end is a tutorial to boot from the Grub command line in case of serious problems.

UEFI Booting


BIOS booting is very simple, at least in concept, but in practice it started getting more complicated. With BIOS style booting the first sector of the disk contained a table of the partitions on the system and a small space for the boot loader code--very small. When the system is turned on the start address for the CPU is hardwired and jumped into the BIOS firmware. The BIOS firmware did whatever it needed to configure the hardware to known state, and at some point loaded the loader code from the MBR into memory and jumped to it. This code then did whatever it needed to get the hardware ready for the operating system, and then loaded the operating system kernel image into memory and finally executed it. Since the MBR boot code was so small, it might just load a much larger boot loader into memory and jump into it. This is how most modern MBR boot loaders work like Grub, LILO, etc.

UEFI is much different. It is a specification for what firmware should do. Most importantly is defines a type of executable file that the firmware must be able to read, load, and execute. This means as an OS vendor all you need to do is write your boot loader program in the proper executable file format and the firmware can run it. This was very important because in the BIOS MBR world, the BIOS didn't understand executable file formats, partitions, disks, etc. it just loaded the boot code (or whatever was written there, expecting it to be code) and then executed it. UEFI also requires the firmware be able to read at least one partition table format known as GUID Partition Tables (GPT) in order to read and define disk partitions. It also requires the firmware to understand at least one filesystem which is the Microsoft File Allocation Table (FAT) in the FAT12, FAT16, and FAT32 variations. This meant the firmware could now read partitions, understand a file system to read files and directories, and execute code in a given format.

The last important part of the UEFI specification (though there is a lot more) is an area to store variables in NVRAM that will persist between power cycles and defines the format of some of those variables to be standard. Now all that is needed is a piece of code called the boot manager that will read those variables in order to create a set of choices in order to boot whatever operating systems are present and each operating system vendor then only needs to write his boot loader in the native processor binary code and store it in the standard executable file format. After that all that needs to be done is add in the proper variables for the firmware boot manager to add the new operating system to the menu (which might not be a menu at all).

The beauty of this is that the boot loader is now just a file on disk. It can be very complicated or very simple but it is a file not a "magic boot area" that only one operating system can own at a time. So UEFI booting at the bare bones level might go something like this:

1) Read the UEFI variables looking for the variables that define boot loaders
2) Read another variable to determine which one to boot or
3) Show all entries in a menu and let the user pick one

But it might also be something like

1) Start with the first disk on the bus the firmware understands
2) Read the partition table (GPT format)
3) Go through the partitions and look for ones of type "EFI System Partition"
4) This will be a FAT12, FAT16, ro FAT32 filesystem so
5) Go through the files looking for files that are in the proper executable formation and
6) Add them to a list or possible boot loaders
7) Go to the net disk and jump to set 1 or if the last disk then
8) Present a menu to allow the user to choose which boot loader to use

Most UEFI firmwares will do a combination of the two and automatically show a menu containing the boot loaders as defined in the UEFI variables. But they will generally also look at other disks, such as USB, SD, etc. to find other choices. If the "special key" isn't pressed on system startup, it just boots the operating systems in the order provided from the EUFI variables. But if the special key is pressed, it instead interrogates all disks and presents a menu with everything it finds.

EUFI Booting with Grub


To boot using UEFI requires some additional packages be added to the base system. Several have dependencies that must also be added, and because we are using a newer binutils, we are required to  make some changes to the GRUB source code and recompile. Fortunately, we can do this as a patch.

Grub needs a font for the graphics console or boot messages won't appear until the kernel takes over the video. In order to see all messages from the beginning of the boot process, we need to supply a font. Grub does have the ability to make the font using grub-mkfont, but this requires FreeType and its dependencies which, at this point, we want to avoid. Fortunately Grub has a default font we can use as an alternative, allowing us to avoid additional build requirements. At this point we won't support grub-mkfont.

Step 1 - Checking the Environment


First be sure your system booted using UEFI. This will be the method that booted the host operating system (MX Linux) but since we are using its kernel and mounting the sysfs we have everything we need. To verify it was booted using UEFI type

ls /sys/firmware/efi

If you see directories under this then the system booted using UEFI.

As before you should have mounted the target filesystem using mount.sh, the virtual filesystems (proc, sys, dev , dev/pts) , and change the root to the target using chroot_to_lfs. Make sure the boot partition is mounted under /boot on the target. Ensure the confs environment variable is set

Step 2 - Download the source


To fetch the source

cd /sources
cat > wget-efi.files << EOF
http://rpm5.org/files/popt/popt-1.16.tar.gz
https://github.com/dosfstools/dosfstools/releases/download/v4.1/dosfstools-4.1.tar.xz
https://github.com/rhinstaller/efibootmgr/releases/download/16/efibootmgr-16.tar.bz2 
EOF

wget --input-file=wget-efi.files --continue --no-check-certificate

Note we skip the certificate check when using wget since we have no set up the local CA. We'll address that later.

Now switch to the directory where the cci.pl program is located
cd ~/cci

Step 3 - popt-1.16


Create the config

echo "./configure --prefix=/usr --enable-static" > $confs/config.popt

Though we have opted to avoid static libraries this one is require because efivars requires it.

Now build with

./cci.pl -n popt -p popt-1.16.tar.gz -c config.popt 

Step 4 - dosfstool-4.1


This is required by efibootmgr at runtime.
Only a configuration is need for this one.

Create the config

cat > $confs/config.dosfstools << EOF
./configure --prefix=/usr \
     --sbindir=/usr/bin \
     --mandir=/usr/share/man \
     --docdir=/usr/share/doc
EOF

The build with

./cci.pl -n dosfstools -p dosfstools-4.1.tar.xz -c config.dosfstools

Step 5 - efivar-30


Running the test suite for this package has been known to corrupt the UEFI firmware. It isn't ran by default, but because this package has undergone changes in the past regarding how it builds and test, we disable the test suite to make sure it is never ran.

There is also changes required to compile with GCC 9 that are not yet part of a release. We can make a patch or use the GIT master. Using the master presents a problem as we have no official release tarball. We will make one from the master.

pushd /sources
wget https://github.com/rhboot/efivar/archive/master.zip --no-check-certificate
mkdir -v sandbox
cd sandbox
unzip ../master.zip
mv efivar-master/ efivar-37.1pre
tar -czf ../efivar-37.1pre.tar.gz efivar-37.1pre/
cd ..
rm -rf sandbox
popd

Create the config

cat > $confs/config.efivar << "EOF"
cp -p Make.defaults Make.defaults.dist
sed 's|-O2|-Os|g' -i Make.defaults
cp -p src/test/Makefile src/test/Makefile.dist
sed 's|-rpath=$(TOPDIR)/src/|-rpath=$(libdir)|g' -i src/test/Makefile
EOF

It doesn't support parallel builds so we must disable them. Create the compile

cat > $confs/compile.efivar << "EOF"
make libdir="/usr/lib/" bindir="/usr/bin/" \
         mandir="/usr/share/man/"     \
         includedir="/usr/include/" V=1 -j1
EOF

Lastly, create the install

cat > $confs/install.efivar << "EOF"
make -j1 V=1 DESTDIR="${pkgdir}/" libdir="/usr/lib/" \
         bindir="/usr/bin/" mandir="/usr/share/man"   \
         includedir="/usr/include/" install
EOF

The build with

./cci.pl -n efivar -p efivar-37.1pre.tar.gz -c config.efivar -m compile.efivar -t null -i install.efivar

This means we will need to revisit this package once they create a real release.

Step 6 - efibootmgr-16


There is no test. We need to make a config to patch the make files to turn of errors as warnings. These errors are not fatal.

echo "sed -i s/-Werror// Make.defaults" > $confs/config.efibootmgr

Create the install

cat > $confs/install.efibootmgr << EOF
install -v -D -m0755 src/efibootmgr /usr/sbin/efibootmgr
install -v -D -m0644 src/efibootmgr.8 /usr/share/man/man8/efibootmgr.8
install -v -D -m0644 src/efibootdump.8 /usr/share/man/man8/efibootdump.8
EOF

Create the compile

echo "EFIDIR=/boot/efi make" > compile.efibootmgr

Now build with

./cci.pl -n efibootmgr -p efibootmgr-14.tar.bz2 -c config.efibootmgr -m compile.egibootmgr -t null -i install.efibootmgr

Step 7 - Fixing Grub for newer binutils


We need to make a few changes to Grub. Under the newer binutils the x86_64 assembler creates a file that is a different format (R_X86_64_PLT32) which Grub doesn't know how to handle relocation. After a lot of research I found this can be handled the same as the R_X86_64_PC32 file. This change can be applied through a patch.

First make the patch file

cat > /sources/grub-x86_64_plt32_fix_relocation.patch < "EOF"
diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c
index a2bb054..39d7efb 100644
--- a/util/grub-mkimagexx.c
+++ b/util/grub-mkimagexx.c
@@ -841,6 +841,7 @@ SUFFIX (relocate_addresses) (Elf_Ehdr *e, Elf_Shdr
*sections,
           break;

         case R_X86_64_PC32:
+        case R_X86_64_PLT32:
           {
             grub_uint32_t *t32 = (grub_uint32_t *) target;
             *t32 = grub_host_to_target64 (grub_target_to_host32 (*t32)
diff --git a/util/grub-module-verifier.c b/util/grub-module-verifier.c
index 9179285..a79271f 100644
--- a/util/grub-module-verifier.c
+++ b/util/grub-module-verifier.c
@@ -19,6 +19,7 @@ struct grub_module_verifier_arch archs[] = {
       -1
     }, (int[]){
       R_X86_64_PC32,
+      R_X86_64_PLT32,
       -1
     }
   },
EOF

Again we will manually handle the patch path.

Create the config

cat > $confs/config.grub < EOF
patch -Np1 -i /sources/grub-x86_64_plt32_fix_relocation.patch
./configure --prefix=/usr  \
            --sbindir=/sbin        \
            --sysconfdir=/etc      \
            --disable-efiemu       \
            --disable-grub-mkfont  \
            --with-platform=efi    \
            --target=x86_64        \
            --program-prefix=""    \
            --with-bootdir="/boot" \
            --with-grubdir="grub" \
            --disable-werror
EOF

The install with

./cci.pl -n grub -p grub-2.02.tar.xz -c config.grub -t null

Step 8 - Installing the Default Font


Since we chose not to create the grub-mkfont program which will create the font from scratch we need to supply it with a default font. This can be downloaded, but you have a copy available on the host.

First create the directory

mkdir -vp /boot/grub/fonts

In a terminal on the host do
cp /boot/grub/unicode.pf2 $LFS/boot/grub/fonts

Or if you prefer download it

wget --no-certificate-check --directory-prefix=/boot/grub/fonts https://github.com/nlamirault/muk/raw/master/grub/fonts/unicode.pf2

Step 9 - Mount  efivarfs


For the efibootmgr to access the EFI variables on the system, they need to be exposed for access. There is a special virtual filesystem called efivarsfs. Add it the /etc/fstab

echo "efivarfs       /sys/firmware/efi/efivars  efivarfs  defaults  0      1" >> /etc/fstab

The mount with

mount /sys/firmware/efi/efivars

Check to be sure it worked

$ ls /sys/firmware/efi/efivars
AMITCGPPIVAR-a8a2093b-fefa-43c1-8e62-ce526847265e
AWVC-c07a1f7c-fa13-4fcb-92ca-3b32bc092e13
AsusCountryCodeIntel-607005d5-3f75-4b2e-98f0-85ba66797a3e
AsusEDID-607005d5-3f75-4b2e-98f0-85ba66797a3e
...

The contents depend entirely on your system but it should contain files with similar endings. If this doesn't work check all kernel parameters in the next step.

Step 10 - Checking the Kernel


If something didn't work with the previous step it probably means something is missing in the kernel. Check the following options to make sure. With the default configuration it will pick all the right options for UEFI but one and we have already selected it (EFI Stud support). But check the code of the kernel with

cd /sources/linux-5.2.9
make nconfig

Then check the following

       ## CONFIG_EFI_PARTITION=y
         -> Enable the block layer
           -> Partition Types
             [*] Advanced partition selection
             ...
             [*] EFI GUID Partition support

     ## CONFIG_EFI=y
     ## CONFIG_EFI_STUB=y
         -> Processor type and features
           [*] EFI runtime service support
           [*]   EFI stub support
           [*]      EFI mixed-mode support

     ## CONFIG_FB_EFI=y
         -> Device Drivers
           -> Graphics support
             -> Frame buffer Devices
               [*] Support for frame buffer devices
               [*]    EFI-based Framebuffer Support

     ## CONFIG_FRAMEBUFFER_CONSOLE=y
         -> Device Drivers
           -> Graphics support
             -> Console display driver support
             [*]   Framebuffer consoel support 
             [*]      Map the console to primary display device

     ## CONFIG_EFI_VARS is not set
     ## CONFIG_EFI_RUNTIME_MAP=y
         -> Firmware Drivers
           -> EFI (Extensible Firmware Interface) Support
             < > EFI Variable Support via sysfs
             [*] Export efi runtime maps to sysfs

     ## CONFIG_EFIVAR_FS=y
          -> File systems
            -> Pseudo filesystems
              [*] EFI Variable filesystem

If you made any changes rebuild and install the kernel using Steps 5 - 8 of chapter 10.

Step 11 - Installing the Bootloader


Now we use the Grub install to put the bootloader into the EFI partition which is our boot partition that also contains the kernel image itself.

grub-install --target=x86_64-efi --efi-directory=/boot/efi  \
       --bootloader-id=TTLP --recheck --debug

This will call efibootmgr to add a boot entry into the system's boot manager. When complete check the /boot partition for the grub code

ls /boot/efi/EFI/TTLP

also run efibootmgr as root and verify there is a TTLP entry.

Step 12 - Create the GRUB configuration


Now create the configuration for GRUB

cat > /boot/grub/grub.cfg << "EOF"
# Begin /boot/grub/grub.cfg for The Toucan Linux Project
set default=0
set timeout=3

if loadfont /grub/fonts/unicode.pf2; then
   set gfxmode=800x600
   insmod all_video
   terminal_output gfxterm
fi

set menu_color_normal=white/blue
set menu_color_highlight=blue/yellow

insmod part_gpt
insmod fat

menuentry "Toucan Linux, Linux 5.2.29" {
   set root=(hd0,1)
   insmod xfs
   linux /vmlinuz-5.2.9-ttlp  root=/dev/sda2 ro rootfstype=xfs
}
EOF

You will need to change the (hd0,1) in the set root entry to the proper disk and partition for your system. See the discussion under MBR last chapter.

Step 13 - Learn How to Boot From the Grub Command Line


In case you make an error in the grub.cfg or have a bad kernel or install the wrong firmware it is good to know how to use the GRUB command line to edit an entry or even how to boot manually to make sure you can boot the system to fix the problems. For that we will have a quick tutorial on the GRUB command line.

When Grub first boots into the menu there will be an option at the bottom to press 'E' to edit the entry and another to press 'C' for the command line. If you select a boot option using the arrow keys and press 'E' it will open up an editor that will let you change the stanza from the grub.cfg file for that boot option. Often this is all you need to make the changes to get the system booted so you can modify the configuration. But you might need to manually boot if the grub.cfg is missing.
Start by pressing 'c' to get into the command mode. Now type

ls

and Grub will show the drives and partitions it sees such as

(hd0) (hd1) (hd0,gpt1) (hd0,gpt2) (hd0,gpt3) (hd1,msdos1) (hd1,msdos2)

This show Grub has found two drives, The first is is called (hd0) which has three GPT partitions. The second drive it calls (hd1) and it has two MSDOS partitions. They might both have boot partitions, maybe one, maybe you know which is the boot, or maybe you don't. The devices that Grub can support include the following

(fd0)
(hd0)
(cd)
(ahci0)
(ata0)
(crypto0)
(usb0)
(cryptouuid/123456789abcdef0123456789abcdef0)
(mduuid/123456789abcdef0123456789abcdef0)
(lvm/system-root)
(lvmid/F1ikgD-2RES-306G-il9M-7iwa-4NKW-EbV1NV/eLGuCQ-L4Ka-XUgR-sjtJ-ffch-bajr-fCNfz5)
(md/myraid)
(md/0)
(ieee1275/disk2)
(ieee1275//pci@1f\,0/ide@d/disk@2)
(nand)
(memdisk)
(host)
(myloop)
(hostdisk//dev/sda)

The partition types are mostly for your information, they aren't need in Grub commands. If you needed to find the boot filesystem you could start by using the 'ls' command

ls (hd0,1)/
ls (hd0,2)/
ls (hd0,3)/

You could use (hd0,gpt1) if you wanted but it isn't necessary. If Grub responds with "Error: unknown filesystem." it means you need to load the module for that file system. It is generally the commonly used abbreviation of the filesystem. For XFS use

insmod xfs

For MSDOS type file systems (except exFAT) use

insmod fat

Then try again

ls (hd0,1)/

which will show the files and directories in that partition. You can use it just like ls such as

ls (hd0,1)/etc

To show the contents of a file use the 'cat' command

cat (hd0,1)/etc/fstab

If you are in rescue mode where the prompt says

grub rescue>:

Then grub wasn't able to find its own files. For this you will need to set the prefix but you can't use the modules so it might not be possible to list the contents of filesystem. You have to know where it is. For this example we'll assume (hd0,3) is the boot drive with the Linux kernel, the EFI partition (if using EFI). In that case it is

set prefix=(hd0,gpt1)/boot/grub
insmod normal

Now you are in normal mode and can proceed with using Grub modules and commands. Once you've found the boot filesystem set the Grub root with

set root=(hd3,0)

Use the ls command to find the kernel

grub>: ls (hd3,0)/ 
System.map-5.2.9 config-5.2.9 efi grub 
vmlinuz-5.2.9

Now load the linux kernel image

grub>: linux /vmlinuz-5.2.9 rootfstype=xfs root=/dev/sda2 ro 
grub>: boot

If you are using an initial ramdisk you need to specify it after the kernel

grub>: ls (hd3,0)/ 
System.map-5.2.9 config-5.2.9 efi grub initrd-5.2.9
vmlinuz-5.2.9

Now load the linux kernel image

grub>: linux /vmlinuz-5.2.9 rootfstype=xfs root=/dev/sda2 ro
grub>: initrd /initrd-5.2.9
grub>: boot

Now reboot and, for the first time, boot into the new system using your system's UEFI Boot Manger. If all went well, you'll be greeted with a login in screen which will allow you login, explore, and finally use shutdown -r now to reboot into the host if you need to do so.

Next time, we'll work on some configuration issues, and move to the second goal, angband.

GRUB Modules


Here's a list of the common Grub 2 modules for your reference

915resolution - This module is used to change the video resolution for Intel 915 video hardware.

acpi - Advanced Configuration and Power Interface (ACPI) is used to perform various power-related functions.

adler32 - This is a cryptography module that contains the tools needed to use the Adler-32 checksum.

affs - Support for the AFFS filesystem is provided by this module.

afs - Support for the AFS filesystem is provided by this module.

ahci - AHCI stands for "Advanced Host Controller Interface" and this is a special hard-drive format (like IDE or SATA). This module offers the needed code for GRUB to recognize such devices.

all_video - Additional video and graphics support can be gained when the "all_video" module is loaded.

ata - This module provides support for ATA computer buses.

at_keyboard - This module is used to support the 84-key keyboards.
backtrace - This module gets the list of functions that are running in an active thread.

bfs - This module provides support for the Be FileSystem which is used by BeOS.

biosdisk - This module provides GRUB with the ability to boot off of LiveDisks.

blocklist - This module displays the list of blocks used by the specified file.

bsd - This module provides support for loading BSD kernels.

btrfs - This module provides support for the B-tree Filesystem.

bufio - This module supports buffer reads and writes.

cat - The "cat" command is provided by this module.

cbfs - This module provides GRUB with support for the Callback Filesystem (CBFS).

cbls - This module lists the coreboot tables.

cbmemc - This module displays the contents of the CBMEM console.

cbtable - This module provides support for Coreboot tables.

chain - This module offers chainloading capabilities.

cmosdump - This command displays the raw CMOS data.

cmp - The "cmp" command is provided by this module.

configfile - This module provides the ability to read and manipulate configuration files.

cpio_be - This module provides support for big-endian CPIO.

cpio - This module provides support for CPIO.

cpuid - This modules tests for various CPU features.

crc64 - This module offers an error-detection tool known as Cyclic Redundancy Check (CRC).

cryptodisk - This module is needed to mount a crypto disk.

date - This module provides the "date" command.

datetime - This module provides the "datetime" command.

diskfilter - This module is needed to read RAID arrays.

disk - This module is needed to read hard-drives.

drivemap - This module contains functions related to BIOS drive mappings.

echo - This module provides the "echo" command.

efiemu - This module provides EFI emulation features.

ehci - This module provides support for the Enhanced Host Controller Interface (EHCI) which is used by USBv2.

elf - This module loads ELF files.

eval - This module provides the "eval" command which is used to evaluate expressions.

exfat - GRUB can gain support for FAT64 (also called exFAT) with this module.

ext2 - This module provides support for EXT2 filesystems.

fat - GRUB can gain support for the FAT filesystem with this module.

file - This module provides the basic file I/O functions.

font - This module provides many font-related functions.

freedos - This module contains the code needed to boot FreeDOS.

fshelp - This module contains functions related to filesystem-helpers.

gdb - This module contains features related to the GNU Debugger (GDB).

geli - This module provides a block device-layer disk encryption system for FreeBSD.

gettext - This module provides language translation abilities.

gfxmenu - This module provides the gfxmenu.

gptsync - A GPT partition table can be synced with an MBR partition table using this module.

gzio - This module offers Gzip I/O abilities.
halt - This module provides the "halt" command.

hashsum - This module provides the features needed to compute and check hash checksums.

hdparm - GRUB can use this module to set and get ATA parameters.

hello - This module is an "Hello World" example for making GRUB modules.

help - This module provides the help utility.

hexdump - This module offers hex dump capabilities.

hfs - GRUB uses this module to gain support for the HFS filesystem.

hfspluscomp - HFS+ compression is supported with this module.

hfsplus - GRUB uses this module to gain support for the HFS+ filesystem.

http - GRUB can boot systems that reside on a Network Filesystem (NFS). This means that GRUB may need some networking capabilities sometimes. The "http" module provides the Hyper Text Transfer Protocol.

hwmatch - Blacklists and whitelists for hardware are used with this module.
iorw - This module is used to read and write the input and output of devices.

iso9660 - This module offers iso9660 support which is needed to read optical discs that use this filesystem.

jfs - GRUB uses this module to gain support for the JFS filesystem.

jpeg - GRUB can have background images (like a wallpaper). The "jpeg" module provides support for JPEG images, which GRUB can use as a background image.
keylayouts - The keyboard layout can be changed using this module.

keystatus - By using the keystatus module, GRUB can detect whether or not key modifiers are active (such as caps-lock, shift, ctrl, etc.).

ldm - The LDM module offers support for the LDM partitioning layout (Microsoft's Logical Disk Manager).

legacycfg - Backwards compatibility for various GRUB Legacy features are provided with this module.

legacy_password_test - This module is used to test the legacy password system.
linux16 - The "linux16" command is in this module. The command is used to load a 16-bit Linux system.

linux - This module is just like the "linux16" module except that this is the standard "linux" command.

loadenv - This module provides the "loadenv" command which is used to load variables from the environment block file.

looback - The "loopback" command comes from the "loopback" module. "loopback" provides the tools needed to create loopback devices.

lsacpi - This module is used to list the detected ACPI devices.

lsapm - This module lists Advanced Power Management (APM) devices. APM is the predessor to ACPI.

lsmmap - This module displays the memory map (LiSt Memory Map).
ls - This module provides GRUB with the "ls" command which is used to list devices or files.

lspci - This module provides the "lspci" command which is used to list PCI devices.

luks - Linux Unified Key Setup (LUKS) is a special disk-encryption format used by Linux systems. With this driver, GRUB can access LUKS partitions with this module.
lvm - This module offers GRUB support for Linux's Logical Volume Manager (LVM).

lzopio - This module provides support for reading and writing (I/O) files that are compressed with lzop. "lzop" is similar to Gzip and uses the LZO compression library.

macbless - With this module, GRUB can "bless" a file or directory that resides on an HFS or HFS+ filesystem. To "bless" a file means to make it bootable and set various options related to startup.

macho - Mach-O files cannot be loaded without using this module. A Mach-O file is a Mach Object file format that has replaced the "a.out" file format.

mda_text - This driver provides text support for MDA (Monochrome Display Adapter) as opposed to VGA.

mdraid09_be - RAID support with big-endian is given to GRUB via this module.

mdraid09 - RAID support is given to GRUB via this module.

mdraid1x - RAID1 support is offered with this module.

memdisk - This module provides GRUB a way to boot old operating systems (like from floppy drives). http://www.syslinux.org/wiki/index.php/MEMDISK

memrw - GRUB uses this module to read and write to physical memory.

minicmd - The commands that are available in rescue mode come from this module.

minix2_be - Support for MinixFS v2 with big-endian is provided by this module.

minix2 - Support for MinixFS v2 without big-endian is provided by this module.

minix3_be - Support for MinixFS v3 with big-endian is provided by this module.

minix3 - Support for MinixFS v3 without big-endian is provided by this module.

minix_be - Support for MinixFS v1 with big-endian is provided by this module.

minix - General support for Minix filesystems is offered by this module.

mmap - This module provides the needed code for memory mapping.

morse - GRUB can provide information via Morse Code when this module is loaded.

mpi - GRUB can support the Message Passing Interface (MPI) which is commonly seen on clusters.

msdospart - Support for MS-DOS partitions (commonly called "MBR partitions") is provided by this module.

multiboot2 - This module provides various functions needed to support multi-booting systems (just like the "multiboot" system). However, this module provides additional and newer features.

multiboot - This module provides various functions needed to support multi-booting systems.

named-colors - This module is a library that contains various color names with the RGB values for that color.

nativedisk - This module makes GRUB use native disk drivers such as pata, ahci, usbms, ohci, uhci, and ehci.

net - Many network drivers and functions are contained in this module. GRUB is able to boot from remote hard-drives via the network.

newc - NewC is a special CPIO format. This module provides a way for GRUB to access such CPIO files.

nilfs2 - This module provides support for NILFS2 (New Implementation of Log filesystem v2).

normal - This module provides "Normal Mode" which is the opposite of "Rescue Mode".

ntfscomp - GRUB is able to support the compression commonly used in NTFS with this module.

ntfs - GRUB uses this module to gain support for the NTFS filesystem.

ntldr - This module is based on the "chainloader" module and is used to boot a Windows partition. This module does not read the Volume Boot Record. This is helpful in cases when the Volume Boot Record is corrupted.

odc - This module provides support for a special CPIO format known as "Octet-oriented cpio format".

ohci - Open Host Controller Interface (OHCI) is a hardware standard commonly used by FireWire devices.

part_acorn - This module provides support for Acorn partitions and partitioning tables.

part_amiga - This module provides support for Amiga partitions and partitioning tables.

part_apple - This module provides support for Apple partitions and partitioning tables.

part_bsd - This module provides support for BSD partitions and partitioning tables.

part_dfly - This module provides support for DFLY partitions and partitioning tables.

part_dvh - This module provides support for DVH partitions and partitioning tables.

part_gpt - This module provides support for GPT (GUID Partition Table) partitions and partitioning tables.

part_msdos - This module provides support for MS-DOS (MBR) partitions and partitioning tables.

part_plan - This module provides support for Plan9 partitions and partitioning tables.

part_sun - This module provides support for Sun partitions and partitioning tables.

part_sunpc - This module provides support for SunPC partitions and partitioning tables.

parttool - This module provides the "parttool" command.

password - This module provides the "password" command.

pata - Support for the Parallel ATA (PATA) disk interface is provided by this module.

pbkdf2 - This module provides the PBKDF2 (Password-Based Key Derivation Function 2) cryptography tool.

pcidump - This module provides information on the detected PCI devices.
pci - This module provides support for Peripheral Component Interconnect (PCI) computer buses.

plan9 - This module is needed by GRUB to load Plan9 kernels.

play - This module provides the "play" command which is used to play sound via the BIOS speaker.

png - PNG files can be used as the background image when this module is loaded.

probe - This module is used to probe for device information.

procfs - This module provides support for ProcFS.

progress - This module provides a progress bar.

pxechain - This module supports PXE chainloading.

pxe - GRUB uses this module to gain support for Preboot eXecution Environment (PXE). This is used to boot an operating system independently of local storage units using a network.

raid5rec - This module provides RAID5 support.

raid6rec - This module provides RAID6 support.

read - This module provides the "read" command.

reboot - This module provides the "reboot" command.

regexp - Regular Expressions (REGEX wildcards) are supported via this module.
reiserfs - This module provides support for the Reiser Filesystem.

romfs - This module provides RomFS support.

scsi - This module provides support for the SCSI (Small Computer System Interface) hardware protocols and standards.

sendkey - This module provides the "sendkey" command which is used to send emulated key-presses to GRUB.

serial - This module provides support for serial devices.

setjmp - This module is a library that provides support for non-local jumps. This is needed to manage errors and interrupts.

setpci - This module is used to configure PCI devices.

sfs - Support for the Smart Filesystem (SFS) is offered by this module. SFS is a journaling filesystem used by Amiga systems.

sleep - The "sleep" command is provided by this module. The "sleep" command is just like the one in BASH; execution will wait/pause for the specified time.
sleep_test - This module is used to test for proper "sleep" support.

squash4 - GRUB can access Squash Filesystem with this module. SquashFS is a read-only filesystem that is compressed.

syslinuxcfg - GRUB can support SysLinux configuration files with this module.

tar - Support for Tar files is offered with this module.

terminal - This module provides support for terminals.

terminfo - GRUB can read terminfo entries via this module.

testload - GRUB can load a file multiple ways to test for errors.

test - This module provides the "test" command which is used to evaluate an expression.

testspeed - GRUB's file reading speed can be measured with this module.

tftp - Trivial File Transfer Protocol (TFTP) provides GRUB a way to get files needed for booting from another system. This also provides a way to support diskless booting.

tga - This module offers support for the Tandy Graphics Adapter (TGA) which is a technology similar to VGA.

time - This module provides the "time" command which prints the current time.
trig - This module provides trigonometric functions to GRUB.

tr - The "tr" command is provided by this module. This is the same "tr" command as seen in BASH and other shells.

truecrypt - Truecrypted MBR partitions require that this module be loaded so that GRUB can boot such partitions. TrueCrypt is an on-the-fly-encryption (OTFE) utility for files or partitions.

true - This module provides the boolean commands "true" and "false".

udf - The "udf" module provides support for the Universal Disk Format (UDF).

ufs1_be - Support for the Unix Filesystem v1 with big-endian is provided with this module.

ufs1 - Support for the Unix Filesystem v1 is provided with this module.

ufs2 - Support for the Unix Filesystem v2 is provided with this module.

uhci - This module provides support for the Universal Host Controller Interface (UHCI).

usb_keyboard - USB keyboards are supported with this module.

usb - USB devices in general are supported with the "usb" module.

usbms - USB mice are supported by this module that offers features needed for USB data streams.

usbtest - USB support is tested with this module.

vbe - VESA BIOS Extensions (VBE) is a specific VESA standard that this module supports.

verify - File signatures can be verified using the "verify" module.

vga - This module provides VGA support.
vga_text - This module provides the text-only (VGA) mode.

video_bochs - This module provides the Bochs video driver.

video_cirrus - This module provides the Cirrus video driver.

video_colors - Many functions related to color come from this module.

video_fb - This module is for the video framebuffer.

videoinfo - Various information concerning the graphics can be displayed using the tools that are part of the "videoinfo" module.

video - This provides code needed for various video modes.

videotest - The video settings can be tested using this module.

xfs - GRUB uses this module to gain support for the XFS filesystem.

xnu - This module provides support for XNU kernels (like OS X).

xnu_uuid - This module converts the 64-bit UUIDs to the 128-bit UUIDs used by Xnu kernels.

xnu_uuid_test - This module is used to ensure that two 128-bit UUIDs match.

xzio - This module provides read and write support for xz-compressed files.

zfscrypt - Encryption tools for the ZFS filesystem are in this module.

zfsinfo - This module displays various information about a ZFS filesystem/partition.

zfs - GRUB uses this module to gain support for the ZFS filesystem.

Copyright (C) 2019 by Michael R Stute