What process is used under the covers to load the Ubuntu Linux kernel?

Solution 1:

Booting the Ubuntu Linux kernel From Disk For Traditional i386 and amd64 Architecture Computers Without EFI

Modern desktop and laptop computers with the EFI feature. As opposed to the traditional BIOS systems used for more than 20 years these systems virtually have an operating systems in their firmware--capable of loading substantial software items in one go. Furthermore these can be started on the computer with more security in the face of attacks by software that has somehow acquired the ability to store startup software.

More traditional hardware has less firmware and starts little-by-little. Those systems, described here, run self-tests in their firmware and then start off the boot process.

Here's the firmware code that booted the first PC's from floppy diskette (after the diskette sub-system was reset):

   MOV AX,201H  
   SUB DX,DX  
   MOV ES,DX  
   MOV BS,OFFSET BOOT_LOCN  
   MOV CX,1  
   INT 13H  
   JNC H4  

What followed was error handling (4 retries) starting with resets.

H4 was located a little bit earlier and was:

   JMP BOOT_LOCN  

The BOOT_LOCN was defined as location 7C00H

[1] IBM PC Technical Reference Manual (1984)

There's not much there to get your system started. The first sector of the storage media, the Master Boot Record, is read into the computer's memory at location 0:7c00 and then execution jumps to its start.

It's said that boot refers to picking oneself up by your bootstraps. There's a thin string of events that must take place correctly to get your system started. Once enough code has been loaded from disk and started the system can provide things like error messages, prompts, and error handling. A single sector doesn't have enough room for any of that complexity.

By the way, eventually the code changed a bit. The high order byte of DX was set to 80H to refer to the first disk rather than the first diskette. Of course still later additions to a PC's BIOS incorporated bent geometry and packet-based I/O for larger sector addresses and the ability to allow it to boot from CD's, over USB, etc. The idea on traditional PC hardware is still the same, read the first sector and transfer control.

Other than that not much happened until EFI.

It's up to that first sector to find what should happen next and load at least its first sector, then up to that sector to load several sectors--and your system should then be off and running. That's how modern Ubuntu systems boot on almost-modern hardware.

MBR


Sources:
http://bazaar.launchpad.net/~ubuntu-branches/ubuntu/utopic/grub2/utopic/view/head:/grub-core/boot/i386/pc/boot.S


The first sector is the MBR and the next sector is the first part of Grub2. I should add that the four primary partitions are also defined in the MBR, and one of those can describe a region of the disk containing a chain of extended partitions. The first sector's address is sector 0.

What can go wrong:
If Windows is installed or reinstalled after Grub, it can replace The Grub MBR code with its own. With that the pointer to the Grub code is gone and the new Windows code will search for a partition with the Boot flag, loading a sector from its beginning and transferring control to it.

In a usual installation the remainder of the core of the grub code follows directly and the Grub MBR points to the next sector, sector 1. If you install Grub to a partition the pointer may get changed. That grub pointer is in 0x5c-0x60 of the MBR and must be changed correspondingly.

00000050  f7 c1 01 00 74 03 fe 46  10 66 00 80 01 00 00 00  |....t..F.f......|
                                               ^

The largest sector number that 4 byte pointer will hold is 2^32, 2,294,967,296 sectors, or less than 2.2 x 1012 bytes. The following grub code must be within that part of the disk.

Grub2 core.img Start


Sources:
http://bazaar.launchpad.net/~ubuntu-branches/ubuntu/utopic/grub2/utopic/view/head:/grub-core/boot/i386/pc/diskboot.S


Usually starting at sector 1 (if you installed Grub2 to /dev/sda, for example) are the parts of the core.img. The whole image must be loaded for grub to give you a prompt. At the very end of its first sector is a blocklist, a list of sectors and counts from which the rest of the image must be loaded. Unlike the MBR there is enough room in the sector to load multiple sets of multiple sectors. Now we are getting somewhere. Sectors are positioned every 0x200 bytes. Each extent is described in 16 bytes.

         |
00000360  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000370  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000380  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000390  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000003a0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000003b0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000003c0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000003d0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000003e0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000003f0  00 00 00 00 02 00 00 00  00 00 00 00 63 00 20 08  |............c. .|

What can go wrong:
GPT formatted drives have the partition descriptors located starting on the second sector. In that case the grub image must be located somewhere else in a partition. It would probably be best to format a small partition just for grub to hold its core image. Place it somewhere close to the beginning of the disk where you won't be tempted to move or disturb it. It mustn't be moved without re-installing grub to it.

If something, like a whole disk encryption system was installed in this location it is wiped out. It probably has to be there to boot your system or to access your data. Ouch.

If you later install encryption or other software that uses this area for some of its contents core grub will no longer start.

The blocklist reserves 2 long words for sector number, so every bit has to be stored within 2^21 terabytes of the beginning of the drive. That should be good enough for a while. Much of what it loads is compressed. Older systems had space between the MBR and the first partition of only 1 track - 1 MBR sector. This might be about 63 sectors and 63 sectors is what Ubuntu 14.04 loads at this writing. The compression is so that the whole grub kernel in the image can fit, along with a couple of handy grub modules. This will comprise the whole grub system when it first starts.

lzma_decompress.image


Sources:
http://bazaar.launchpad.net/~ubuntu-branches/ubuntu/utopic/grub2/utopic/view/head:/grub-core/boot/i386/pc/startup_raw.S
http://bazaar.launchpad.net/~ubuntu-branches/ubuntu/utopic/grub2/utopic/view/head:/grub-core/boot/i386/pc/lzma_decode.S


This is the beginning of what is loaded by the last step, and typically is in sector 2, the third sector.

The whole core image is now all loaded. This part takes the rest of the information following it and uncompresses it in memory.

Grub2 Start


Sources:
http://bazaar.launchpad.net/~ubuntu-branches/ubuntu/utopic/grub2/utopic/files/head:/grub-core/
http://www.gnu.org/software/grub/manual/html_node/index.html


At this point a substantial amount of Grub2 code is loaded and uncompressed. This code includes a couple of modules as long with the grub2 kernel. Sort of appearing like a module is a short segment containing the grub prefix. This is a string like:

(hd0,msdos5)

When grub starts, if you enter the c key you can enter a grub command, if you do that and enter the set command you can see what prefix was set when your Grub2 code was installed on your disk. (Press ESC to go back).

Grub can now access, and navigate through, many kinds of file systems and the prefix is key to where it will start to look.

From the directory described by the prefix grub loads the grub.cfg file. This file is (re-)created by the update-grub command which find all the places you may want to boot from, and specifies these in the menu structure defined by the file. The file also specifies if the grubenv file should be loaded. That file loads a grub2 environment, possibly including, for some grub configurations, the last successfully loaded boot menu. The grub.cfg file also directs the loading of more grub modules from the same directory.

grub can now display a menu if there are choices to be made.

When you select an item from the menu that item is used to run the grub commands in that menu entry. These may load further modules necessary to deal with the kernel and initrd image at the location referred to by that menu item.

The final commands of the menu item are of particular interest.

  1. The linux command specifies the linux kernel grub is to load, and the linux boot command that should be passed. Of special interest in the Linux kernel command is the root= parameter. It will tell the kernel, in the kernel's terms rather than in grub's, what partition should be mounted as root.

  2. The initrd command specifies the location of the matching compressed cpio initramfs file (called initrd.img-version) that contains an in-memory file tree containing extra information the linux kernel needs to start up, and kernel modules it may need.

  3. The boot command then transfers CPU control to the loaded kernel for it to start up.

What can go wrong:
If the prefix is wrong, grub will not start properly, and cannot load a menu or appropriate modules. This can be caused if partitions are reordered or previous partitions deleted, changing the partition numbering. It can also be caused if the information in the specified partition has been changed. It should always match what is stored by grub-install, which was given a particular directory to install from. If the actual grub code is changed on the partition from which grub is working grub should probably be reinstalled on the drive with grub-install. Even so, if you can find the correct partition you should be able to manually set the prefix and get grub to work.

Things to know when running Grub2:

  1. Enter the command pager=1 to avoid items rolling off the top of the screen.
  2. Enter the command debug=all to put out debugging messages to give you extra information about what is happening as you enter commands.

Kernel Boot

That kernel initialization up begins generically and is described in books, etc. After a bit it refers to Debian and Ubuntu specific information in the initrd file system image. In part: the partition designated for the root directory is found, checked if necessary, and mounted for writing, the in-memory log is copied to it, and upstart is run. Upstart takes over system initialization, including running the traditional scripts in the /etc/rc.#/ directories in its /etc/init/rc-sysinit.conf job.

What can go wrong:
Perhaps the most frequent grub-introduced problem is that the root= kernel command passed from grub to the kernel is wrong. This can cause an early halt in the initialization of the kernel with a busybox prompt as the root of the desired system can't be found.


[1] IBM Personal Computer Hardware Reference Library: Technical Reference; Part number 6361453 (1984), Page 5-50 (for the IBM 5150 Personal computer, the only "PC™" at the time)
http://www.minuszerodegrees.net/manuals/IBM_5150_Technical_Reference_6322507_APR84.pdf page 143