grub2 build instructions


Quick instructions for build of bootx64.efi


1. Install Ubuntu 64-bit in VBox as UEFI VM (not MBR boot or complied bootx6.efi will give grub-efi-scure-boot not founderror when running ISOs, etc.!)

Note: seems to stick on remove CD - so reset

If doesn't boot to UEFI then boot from UEFI shell
fs0:
cd EFI
cd ubuntu
cp grubx64.efi bootx64.efi
bootx64
Once in terminal type
sudo su
grub-install

2. terminal sudo su - for elevated rights

3. git clone git://git.savannah.gnu.org/grub
4. cd grub
apt get install bison flex autoconf libdevmapper-dev
sudo apt install grub-efi-ia32-bin grub-efi-amd64-bin grub-pc-bin grub2-common grub-efi-amd64-signed

sudo apt-get install bison libopts25 libselinux1-dev autogen m4 autoconf help2man libopts25-dev flex libfont-freetype-perl automake autotools-dev libfreetype6-dev texinfo

make distclean
./autogen.sh
./configure --target=x86_64 --with-platform=efi
make

make check (takes ages for some reason!)


./grub-mkimage -O x86_64-efi -d . -o grub.efi -p "" boot normal part_gpt fat ext2 lvm configfile lspci ls reboot datetime loadenv search help video efi_gop

./grub-mkimage -d ./grub-core -o bootx64.efi -O x86_64-efi -c ./grub-buildin.cfg -p /foobar biosdisk part_msdos fat ntfs exfat configfile ls echo cpuid loopback regexp read bsd probe ext2

Note the two additional modules
video and efi_gop which were not required in previous releases of GRUB2. The efi_gop module is for use with UEFI firmware that implements the Graphic Output Protocol which pretty much all UEFI implementations do. If your system firmware implements the older UGA ((Universal Graphics Adapter) Protocol which was part of the EFI 1.1 specification (older Apple Macs for example), then use the efi_uga module instead. If you use the wrong module, typically you will get an Error: no suitable mode found message but your system will continue to boot and you may or may nor be able to see anything on your screen.


foobar does not need to exist (get error if not specified). grub-buildin.cfg example - see below.


for pc build, best to keep core.img below 32k so fits between MBR and 2st partition (63 sectors).

Quicker method??
mount
apt install grub-efi-ia32-bin grub-efi-amd64-bin grub-pc-bin grub2-common grub-efi-amd64-signed
grub-install --removable --no-nvram --no-uefi-secure-boot --efi-directory=/mnt --boot-directory=/mnt --target=i386-efi
grub-install --removable --no-nvram --no-uefi-secure-boot --efi-directory=/mnt --boot-directory=/mnt --target=x86_64-efi
grub-install --removable --boot-directory=/mnt --target=i386-pc /dev/sdX
This did not seem to work (unbootable grubx64.efi) - grub-install --removable --no-nvram ---uefi-secure-boot --efi-directory=/mnt --boot-directory=/mnt --target=x86_64-efi


Signing??

In order to boot on the widest range of systems, Ubuntu uses the following chain of trust:
Microsoft signs Canonical's 'shim' 1st stage bootloader with their 'Microsoft Corporation UEFI CA'. When the system boots and Secure Boot is enabled, firmware verifies that this 1st stage bootloader (from the 'shim-signed' package) is signed with a key in DB (in this case 'Microsoft Corporation UEFI CA')
The second stage bootloader (grub-efi-amd64-signed) is signed with Canonical's 'Canonical Ltd. Secure Boot Signing' key. The shim 1st stage bootloader verifies that the 2nd stage grub2 bootloader is properly signed.
The 2nd stage grub2 bootloader boots an Ubuntu kernel (as of 2012/11, if the kernel (linux-signed) is signed with the 'Canonical Ltd. Secure Boot Signing' key, then grub2 will boot the kernel which will in turn apply quirks and call ExitBootServices. If the kernel is unsigned, grub2 will call ExitBootServices before booting the unsigned kernel)

Actually, the way Ubuntu does it is twofold: The grub bootloader is signed by a Canonical signing key (specifically, the common name is "Canonical Ltd. Secure Boot Signing"), and they have a signed 'shim' which is signed by Microsoft's UEFI key (bootx64.efi) which loads grub.
The way it's set up tells the secure boot system to allow the Canonical signing key, letting there be a full chain all the way.

This essentially means that Canonical (and thus the grub2-signed project) has access to a key which can be used to sign EFI binaries for secure boot, and thus it stands to reason that all grub modules can and should be signed with it at the same time as the main grub binary. I'd also like to note that the fwupdate-signed package's 'fwupx64.efi' binary is signed by the same key as the grub project, so there shouldn't be any 'we can only sign this one specific binary with this key' rules.
The mechanism used for module signing in GRUB postdates us setting up image signing for UEFI Secure Boot, and we've never got round to working out how the two might interact. (For instance, they use entirely different key formats.) This also means that we can confine the set of GRUB modules that could cause a Secure Boot compromise to a smaller set. You can certainly raise bugs asking for additional modules to be added.



sbsign signs EFI files
openssl genrsa -out test-key.rsa 2048
openssl req -new -x509 -sha256 -subj '/CN=test-key' -key test-key.rsa -out test-cert.pem
openssl x509 -in test-cert.pem -inform PEM -out test-cert.der -outform DER
For now, we'll just sign the regular GRUB2 image:
sbsign --key test-key.rsa --cert test-cert.pem --output grubx64.efi 



MISC NOTES/Links



Collection of useful info about grub2

build uefi grub2http://blog.fpmurphy.com/2011/06/boot-fedora-15-using-uefi-and-grub2.html


















sudo su - for elevated rights

for ubuntu: apt get install bison flex autoconf libdevmapper-dev
git clone git://git.savannah.gnu.org/grub
cd grub


old:
sudo apt-get install bison libopts25 libselinux1-dev autogen m4 autoconf help2man libopts25-dev flex libfont-freetype-perl automake autotools-dev freetype2-demos texinfo efibootmgr

sudo apt-get install build-essential autoconf automake
sudo apt-get build-dep grub-efi-amd64

sudo apt-get install gcc flex bison flex binutils gettext make python autoconf automake autogen grub-common libdevmapper-dev lsb-base libfuse2 zfs-fuse fuse-zip libfuse2 grub-common grub-efi-amd64
sudo apt install grub-efi-ia32-bin grub-efi-amd64-bin grub-pc-bin grub2-common grub-efi-amd64-signed


read text file install for instructions on how to build grub2

linux commands

I use grub 2.02 Beta 3 on Mint
make distclean
./autogen.sh
./configure --target=x86_64 --with-platform=efi
make

if no .mod files creeated in grub-core folder, use apt get install for missing package.
e.g. moddep.lst missing error.


(apt-get 
  cat << 'EOF'
  search --set=root --fs-uuid 1234-ABCD
  set prefix=($root)/EFI/BOOT
  EOF
) > grub-buildin.cfg


./grub-mkimage -d ./grub-core -o bootx64.efi -O x86_64-efi -c ./grub-buildin.cfg -p /foobar $(find . -name '*.mod' | tr '\n' ' ' | sed -e 's/\.mod//g')
./grub-mkimage -d ./grub-core -o bootx64.efi -O x86_64-efi -c ./grub-buildin.cfg -p /foobar biosdisk part_msdos fat ntfs exfat configfile ls echo cpuid loopback regexp read bsd probe ext2

grub-mkimage --prefix /AIO/grub2 --output core.img --format i386-pc --compression auto --config load.cfg biosdisk part_msdos ext2 fat ntfs search_fs_file
grub-mkimage --prefix /AIO/grub2 --output bootx64.efi --format x86_64-efi --compression auto --config load.cfg part_gpt part_msdos ext2 fat ntfs hfsplus search_fs_file
grub-mkimage --prefix /AIO/grub2 --output bootia32.efi --format i386-efi --compression auto --config load.cfg part_gpt part_msdos ext2 fat ntfs hfsplus search_fs_file


other useful modules to add: loopback regexp read echo bsd probe configfile echo search_fs_uuid 
./configure --with-platform=efi
./configure --target=i386 --with-platform=efi
./configure --with-platform=pc

modules
'acpi' 'adler32' 'affs' 'afs' 'ahci' 'all_video' 'aout' 'appleldr' 'archelp' 'ata' 'at_keyboard' 'backtrace' 'bfs' 'bitmap' 'bitmap_scale' 'blocklist' 'boot' 'bsd' 'bswap_test' 'btrfs' 'bufio' 'cat' 'cbfs' 'cbls' 'cbmemc' 'cbtable' 'cbtime' 'chain' 'cmdline_cat_test' 'cmp' 'cmp_test' 'configfile' 'cpio_be' 'cpio' 'cpuid' 'crc64' 'cryptodisk' 'crypto' 'cs5536' 'ctz_test' 'datehook' 'date' 'datetime' 'diskfilter' 'disk' 'div' 'div_test' 'dm_nv' 'echo' 'efifwsetup' 'efi_gop' 'efinet' 'efi_uga' 'ehci' 'elf' 'eval' 'exfat' 'exfctest' 'ext2' 'extcmd' 'fat' 'file' 'fixvideo' 'font' 'fshelp' 'functional_test' 'gcry_arcfour' 'gcry_blowfish' 'gcry_camellia' 'gcry_cast5' 'gcry_crc' 'gcry_des' 'gcry_dsa' 'gcry_idea' 'gcry_md4' 'gcry_md5' 'gcry_rfc2268' 'gcry_rijndael' 'gcry_rmd160' 'gcry_rsa' 'gcry_seed' 'gcry_serpent' 'gcry_sha1' 'gcry_sha256' 'gcry_sha512' 'gcry_tiger' 'gcry_twofish' 'gcry_whirlpool' 'geli' 'gettext' 'gfxmenu' 'gfxterm_background' 'gfxterm_menu' 'gfxterm' 'gptsync' 'gzio' 'halt' 'hashsum' 'hdparm' 'hello' 'help' 'hexdump' 'hfs' 'hfspluscomp' 'hfsplus' 'http' 'iorw' 'iso9660' 'jfs' 'jpeg' 'keylayouts' 'keystatus' 'ldm' 'legacycfg' 'legacy_password_test' 'linux16' 'linux' 'loadbios' 'loadenv' 'loopback' 'lsacpi' 'lsefimmap' 'lsefi' 'lsefisystab' 'lsmmap' 'ls' 'lspci' 'lssal' 'luks' 'lvm' 'lzopio' 'macbless' 'macho' 'mdraid09_be' 'mdraid09' 'mdraid1x' 'memdisk' 'memrw' 'minicmd' 'minix2_be' 'minix2' 'minix3_be' 'minix3' 'minix_be' 'minix' 'mmap' 'morse' 'mpi' 'msdospart' 'mul_test' 'multiboot2' 'multiboot' 'nativedisk' 'net' 'newc' 'nilfs2' 'normal' 'ntfscomp' 'ntfs' 'odc' 'offsetio' 'ohci' 'part_acorn' 'part_amiga' 'part_apple' 'part_bsd' 'part_dfly' 'part_dvh' 'part_gpt' 'part_msdos' 'part_plan' 'part_sun' 'part_sunpc' 'parttool' 'password' 'password_pbkdf2' 'pata' 'pbkdf2' 'pbkdf2_test' 'pcidump' 'play' 'png' 'priority_queue' 'probe' 'procfs' 'progress' 'raid5rec' 'raid6rec' 'random' 'read' 'reboot' 'regexp' 'reiserfs' 'relocator' 'romfs' 'scsi' 'search_fs_file' 'search_fs_uuid' 'search_label' 'search' 'serial' 'setjmp' 'setjmp_test' 'setpci' 'sfs' 'shift_test' 'signature_test' 'sleep' 'sleep_test' 'spkmodem' 'squash4' 'syslinuxcfg' 'tar' 'terminal' 'terminfo' 'test_blockarg' 'testload' 'test' 'testspeed' 'tftp' 'tga' 'time' 'trig' 'tr' 'true' 'udf' 'ufs1_be' 'ufs1' 'ufs2' 'uhci' 'usb_keyboard' 'usb' 'usbms' 'usbserial_common' 'usbserial_ftdi' 'usbserial_pl2303' 'usbserial_usbdebug' 'usbtest' 'verify' 'video_bochs' 'video_cirrus' 'video_colors' 'video_fb' 'videoinfo' 'video' 'videotest_checksum' 'videotest' 'xfs' 'xnu' 'xnu_uuid' 'xnu_uuid_test' 'xzio' 'zfscrypt' 'zfsinfo' 'zfs'
grub-mkstandalone -O x86_64-efi -o mygrub.efi

tips

linux find a file - find . -name '*.xml'
list files ls -l -R /filepath

misc

UEFI shim loader git https://github.com/mjg59/shim
grub2 HowTo UEFI&GPT http://lukeluo.blogspot.co.uk/2013/06/grub-how-to-3-uefi-and-gpt.html


core.img - first sectors

Sometimes I need a minimal boot-able Linux USB stick for rescue purpose, especially when I screw up my grub configuration on my desktop. This USB stick could also be used as a disk when you are using QEMU or other virtual machines. So let us just do it.

1. Make a GPT partition table and an ext4 file system in USB


GPT is the current and future. MBR is fading out. My T400 desktop does not have EFI, but Grub support BIOS+GPT configuration, on the condition that you provide a "GRUB boot partition" in GPT disk. GRUB will copy its "boot.img" to MBR, and "core.img" to this partition, because in a GPT disk, there is no so called "boot gap" between MBR and the first partion. In GPT disk, MBR is followed by GTP headers and first disk partition, no gap allowed. The core.img could not be fill in a gap as in MBR disk, so we must provide a separate partition for core.img to reside. You can refer to Wikipedia for more detail info on MBR/GPT. (
MBR/GPT)

Since Grub core.img will be much less than 1M, so give the "BIOS boot partition" 16M space, which is far more than enough. The left space will be occupied by a "Linux Filesystem" partition.



$ gdisk /dev/sdc
GPT fdisk (gdisk) version 0.8.5

Partition table scan:

MBR: not present
BSD: not present
APM: not present
GPT: not present

Creating new GPT entries.


Command (? for help): ?

...
n add a new partition
o create a new empty GUID partition table (GPT)
p print the partition table
...
Command (? for help): o
This option deletes all partitions and creates a new protective MBR.
Proceed? (Y/N): y

Command (? for help): p

Disk /dev/sdc: 30233588 sectors, 14.4 GiB
Logical sector size: 512 bytes
Disk identifier (GUID): 4052316D-A30D-4521-AC0A-9A248C2A37DF
Partition table holds up to 128 entries
First usable sector is 34, last usable sector is 30233554
Partitions will be aligned on 2048-sector boundaries
Total free space is 30233521 sectors (14.4 GiB)

Number Start (sector) End (sector) Size Code Name


Command (? for help): n

Partition number (1-128, default 1):
First sector (34-30233554, default = 2048) or {+-}size{KMGTP}:
Last sector (2048-30233554, default = 30233554) or {+-}size{KMGTP}: +16M
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300): L
.....
bf0b Solaris Reserved 5 c001 HP-UX data c002 HP-UX service
ef00 EFI System ef01 MBR partition scheme ef02 BIOS boot partition
fd00 Linux RAID
Hex code or GUID (L to show codes, Enter = 8300): ef02
Changed type of partition to 'BIOS boot partition'

Command (? for help): p

Disk /dev/sdc: 30233588 sectors, 14.4 GiB
Logical sector size: 512 bytes
Disk identifier (GUID): 4052316D-A30D-4521-AC0A-9A248C2A37DF
Partition table holds up to 128 entries
First usable sector is 34, last usable sector is 30233554
Partitions will be aligned on 2048-sector boundaries
Total free space is 30200753 sectors (14.4 GiB)

Number Start (sector) End (sector) Size Code Name

1 2048 34815 16.0 MiB EF02 BIOS boot partition

Command (? for help): n

Partition number (2-128, default 2):
First sector (34-30233554, default = 34816) or {+-}size{KMGTP}:
Last sector (34816-30233554, default = 30233554) or {+-}size{KMGTP}:
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300):
Changed type of partition to 'Linux filesystem'

Command (? for help): p

..........

Number Start (sector) End (sector) Size Code Name
1 2048 34815 16.0 MiB EF02 BIOS boot partition
2 34816 30233554 14.4 GiB 8300 Linux filesystem

Command (? for help): w


Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING

PARTITIONS!!

Do you want to proceed? (Y/N): y

OK; writing new GUID partition table (GPT) to /dev/sdc.
.....

$ sudo partprobe /dev/sdc


$ sudo mkfs.ext4 /dev/sdc1

$ sudo mount /dev/sdc2 /mnt/usb
$ sudo tune2fs -L minimal-Ubuntu /dev/sdc2
$ blkid /dev/sdc2
/dev/sdc2: LABEL="minimal-Ubuntu" UUID="f81e7302-2c5c-4a8d-9c7a-3e4aff68241b" TYPE="ext4"




After gdisk, we need to use "partprobe" to inform kernel that disk partition has changed. Do you notice that gdisk generate a "GUID" for this disk? ( Disk identifier (GUID): 4052316D-A30D-4521-AC0A-9A248C2A37DF). That is what GPT means to do. It will generate a GUID for disk and every partition it create. You can check the GUID of partition with gdisk command "i", as below:



$ gdisk /dev/sdc
GPT fdisk (gdisk) version 0.8.5
.....
Command (? for help): i
Partition number (1-2): 1
Partition GUID code: 21686148-6449-6E6F-744E-656564454649 (BIOS boot partition)
Partition unique GUID: 04F2CC95-E0D6-419C-A14E-F1082E4A3AC7
.......

Command (? for help): i
Partition number (1-2): 2
Partition GUID code: 0FC63DAF-8483-4772-8E79-3D69D8477DE4 (Linux filesystem)
Partition unique GUID: 6BB6D2A3-8D75-4277-B9EC-12772BC8D10F
.......


In linux, many linux native file systems will be generated with an UUID , as you can see from the output of "blkid". This UUID is different from the UUID of disk partition, and is generated by "mkfs.ext4" but not "gdisk". Linux use this UUID to identify partitions and corresponding file system on it. If you are curious about what "GUID/UUID" means, use "uuid" to make a check and refer to
Wikipedia for more information. GUID is just one version of UUID.



$ ls -l /dev/disk/by-uuid/
total 0
lrwxrwxrwx 1 root root 10 Jun 13 16:02 f81e7302-2c5c-4a8d-9c7a-3e4aff68241b -> ../../sdc2



$ uuid -d f81e7302-2c5c-4a8d-9c7a-3e4aff68241b
encode: STR: f81e7302-2c5c-4a8d-9c7a-3e4aff68241b
SIV: 329806644509704839954557263724052751387
decode: variant: DCE 1.1, ISO/IEC 11578:1996
version: 4 (random data based)
content: F8:1E:73:02:2C:5C:0A:8D:1C:7A:3E:4A:FF:68:24:1B
(no semantics: random data only)


2. Install a minimal Ubuntu into USB

we use "debootstrap" to populate a Linux root file system into our USB Linux partition. Debootstrap accomplish goal by installing a series of basic Ubuntu packages into this partition using "apt-get". It is a normal "apt-get" process. We are in Ubuntu 13.04 (raring), and I choose a installation mirror close to me.


sudo debootstrap raring /mnt/usb/ http://mirror.sohu.com/ubuntu

......


I: Configuring ubuntu-minimal...
I: Configuring libc-bin...
I: Configuring initramfs-tools...
I: Base system installed successfully.



It will take a while to download and install all the basic packages. After done, take a look /mnt/usb. You now can get a basic feeling of a "minimal" Linux system by scanning throw all those basic packages.


$ sudo chroot /mnt/usb

# dpkg -l
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name Version Architecture Description
+++-=================================-=====================-=====================-========================================================================
ii adduser 3.113+nmu3ubuntu1 all add and remove users and groups
ii apt 0.9.7.7ubuntu4 amd64 commandline package manager
ii apt-utils 0.9.7.7ubuntu4 amd64 package managment related utility programs

.....





You can find all the packages which have been installed into root file system. But no linux kernel and grub are installed, since the minimal system is regarded to work in a "chroot" environment, and it is not considered to be booted by itself and it will use the current kernel in your current Linux environment. To make it a bootable and standalone system, let us go to step 3.



3. Make USB boot-able as full functional minimal Ubuntu


We need to install add "kernel" and "grub" to USB. Let us get these packages first. Before we can install kernel and grub, we need to mount some "virtual file system" to this chroot env to make it look "real" to the post installation script of kernel and grub. These scripts will check system devices and other system related information for their own configuration.

$ sudo chroot /mnt/usb
# mount -t devtmpfs dev /dev
# mount -t devpts devpts /dev/pts
# mount -t proc proc /proc
# mount -t sysfs sysfs /sys
# cat /etc/mtab
/dev /dev devtmpfs rw 0 0
devpts /dev/pts devpts rw 0 0
proc /proc proc rw 0 0
sysfs /sys sysfs rw 0 0



with these virtual file systems ready, we can install kernel and grub now.



# apt-get install linux-image
Reading package lists... Done
Building dependency tree... Done
The following extra packages will be installed:
crda gettext-base grub-common grub-gfxpayload-lists grub-pc grub-pc-bin grub2-common iw libasprintf0c2 libfreetype6 libfuse2 libnl-3-200 libnl-genl-3-200
linux-firmware linux-image-3.8.0-19-generic linux-image-extra-3.8.0-19-generic linux-image-generic os-prober wireless-regdb
Suggested packages:
multiboot-doc grub-emu xorriso desktop-base fuse fdutils linux-doc-3.8.0 linux-source-3.8.0 linux-tools linux-headers-3.8.0-19-generic
The following NEW packages will be installed:
crda gettext-base grub-common grub-gfxpayload-lists grub-pc grub-pc-bin grub2-common iw libasprintf0c2 libfreetype6 libfuse2 libnl-3-200 libnl-genl-3-200
linux-firmware linux-image linux-image-3.8.0-19-generic linux-image-extra-3.8.0-19-generic linux-image-generic os-prober wireless-regdb
0 upgraded, 20 newly installed, 0 to remove and 0 not upgraded.
Need to get 68.7 MB of archives.
After this operation, 216 MB of additional disk space will be used.
Do you want to continue [Y/n]? y
Get:1 http://mirror.sohu.com/ubuntu/ raring/main libasprintf0c2 amd64 0.18.1.1-10ubuntu3 [6864 B]
Get:2 http://mirror.sohu.com/ubuntu/ raring/main libfuse2 amd64 2.9.0-1ubuntu3 [133 kB]
........


Processing triggers for libc-bin ...
ldconfig deferred processing now taking place





The kernel package "linux-image" depends on quite some other packages, including "grub". So we do not need to install grub separately. During the installation, the kernel and grub package will be configured. Let us take a look at what have been populated in root file systems.


# ls -l /boot
total 24808
-rw------- 1 root root 3059890 Apr 17 18:42 System.map-3.8.0-19-generic
-rw-r--r-- 1 root root 918868 Apr 17 18:42 abi-3.8.0-19-generic
-rw-r--r-- 1 root root 154942 Apr 17 18:42 config-3.8.0-19-generic
drwxr-xr-x 5 root root 4096 Jun 13 09:50 grub
-rw-r--r-- 1 root root 15898830 Jun 13 09:48 initrd.img-3.8.0-19-generic
-rw------- 1 root root 5355920 Apr 17 18:42 vmlinuz-3.8.0-19-generic


These are all the Linux kernel files, including initrd ram disks.


# ls -l /boot/grub
total 2220
drwxr-xr-x 2 root root 4096 Jun 13 09:50 fonts
-rw-r--r-- 1 root root 699 Jun 13 09:49 gfxblacklist.txt
-r--r--r-- 1 root root 14859 Jun 13 09:50 grub.cfg
-rw-r--r-- 1 root root 1024 Jun 13 09:48 grubenv
drwxr-xr-x 2 root root 12288 Jun 13 09:50 i386-pc
drwxr-xr-x 2 root root 4096 Jun 13 09:50 locale
-rw-r--r-- 1 root root 2226340 Jun 13 09:50 unicode.pf2


These are the grub files. Let us check the grub.cfg to see if out root files system is in the boot menu entry list.

# cat /boot/grub/grub.cfg

........
menuentry 'Ubuntu' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-simple-f81e7302-2c5c-4a8d-9c7a-3e4aff68241b' {
recordfail
load_video
gfxmode $linux_gfx_mode
insmod gzio
insmod part_gpt
insmod ext2
set root='hd2,gpt2'
if [ x$feature_platform_search_hint = xy ]; then
search --no-floppy --fs-uuid --set=root --hint-bios=hd2,gpt2 --hint-efi=hd2,gpt2 --hint-baremetal=ahci2,gpt2 f81e7302-2c5c-4a8d-9c7a-3e4aff68241b
else
search --no-floppy --fs-uuid --set=root f81e7302-2c5c-4a8d-9c7a-3e4aff68241b
fi
linux /boot/vmlinuz-3.8.0-19-generic root=UUID=f81e7302-2c5c-4a8d-9c7a-3e4aff68241b ro quiet splash $vt_handoff
initrd /boot/initrd.img-3.8.0-19-generic
}

........................



From the boot entry, we can see both grub and kernel use the disk partition uuid to search for the root file system partition. Let cross check to ensure this is exactly the root file system we created in USB:



# blkid /dev/sdc2
/dev/sdc2: LABEL="minimal-Ubuntu" UUID="f81e7302-2c5c-4a8d-9c7a-3e4aff68241b" TYPE="ext4"


Yes, it matches. We are good. Now we clean the fields by restarting system, since all those "virtual file system" will cause us headache if we don't restart system. Before we restart, let us change the root password first. So we can log in using root after we boot this USB.


$ sudo chroot /mnt/usb
# passwd
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully



If you are not that sure how a grub configuration works, you can do these youself.



# grub-install /dev/sdc
Installation finished. No error reported.
# update-grub
Generating grub.cfg ...
Found linux image: /boot/vmlinuz-3.8.0-19-generic
Found initrd image: /boot/initrd.img-3.8.0-19-generic
done



4. A grub interlude


I have mentioned something about how GRUB works under BIOS+GPT environment. I said "boot.img" will be "flashed" into "protective MBR" in GPT disk and "core.img" will be "flashed" into "BIOS boot partition". Let us verify this.


# ls -l /boot/grub/i386-pc/boot.img
-rw-r--r-- 1 root root 512 Jun 13 10:18 /boot/grub/i386-pc/boot.img
# file /boot/grub/i386-pc/boot.img
/boot/grub/i386-pc/boot.img: x86 boot sector; partition 4: ID=0xd3, starthead 205, startsector 4278184271, 0 sectors, code offset 0x63


So boot.img sure is a "boot sector" (MBR). Let us make sure it is "flashed" into MBR in /dev/sdc.



# dd if=/dev/sdc of=mbr bs=446 count=11+0 records in
# dd if=/boot/grub/i386-pc/boot.img of=boot.img.446 bs=446 count=1

# dhex mbr boot.img.446





dhex output


For the whole 446 bytes, (after 446 bytes, it is partition table. We don't need to compare those) , only 4 bytes are different. Those are bytes at address 0x5c/0x5d/0x66/0x67. These are the data that are hard coded into boot.img by grub. So what are they? If you are curious enough, let us check grub source code.



  • get the source code : get it
  • look into the "grub-core/boot/i386/pc/boot.S"
Let us skip the code reading and jump to conclusion:

  • in address 0x5c-0x63, Grub allocate a 8 byte "kernel_header" with initial value 1. This value is changed to 0x0800 when boot.img is "flashed" into MBR.
. = _start + 0x5c
kernel_sector:
.long 1, 0

What is "0x0800"? It is 2048 in decimal. It is exactly the start sector of our "BIOS boot partition".

$ gdisk -l /dev/sdc

Number Start (sector) End (sector) Size Code Name
1 2048 34815 16.0 MiB EF02 BIOS boot partition
2 34816 30233554 14.4 GiB 8300 Linux filesystem


In GPT disk, LBA is using 8 byte. That is why 8 byte is allocated for "kernel_sector". By this value, boot.img could load "core.img" (aka "grub kernel") image from disk.


in address 0x66-0x67, it is a instruction "jmp xx"



. = _start + GRUB_BOOT_MACHINE_DRIVE_CHECK
boot_drive_check:
jmp 3f /* grub-setup may overwrite this jump */
testb $0x80, %dl
jz 2f
3:
/* Ignore %dl different from 0-0x0f and 0x80-0x8f. */
testb $0x70, %dl
jz 1f
2:
movb $0x80, %dl
1:
/*
* ljmp to the next instruction because some bogus BIOSes
* jump to 07C0:0000 instead of 0000:7C00.
*/
ljmp $0, $real_start

real_start:



BIOS set register %dl to the booted disk number to make boot loader know which disk it is booted from, so boot loader can know where to load more contents from booted disk. Generally, %dl=0x00 means booting from floppy disk "A", and %dl=0x80 from hard disk "C:". Since in BIOS setting, we generally boot USB stick using "USB-HDD", %dl should be 0x80. Here "Grub-install" replace "jmp 3f" with "0x90, 0x90", which is instruction "nop; nop". That means "grub-install" consider the BIOS in this machine is not "bogus", and let the logic runs. Refer to this link for more detail on this. Now we should know why there is 4 bytes difference between boot.img and MBR. It is the result of "grub-install" do low level manipulation.

How can we ensure the contents of "BIOS boot partition" is "Grub-kernel" (a.k.a core.img). To check this, we first generate a grub core image using "grub-mkimage", and diff it with the contents in "bios boot partition" (/dev/sdc1).

grub-install will call "grub-mkimage" and "grub-bios-setup" to do the real work. Let us trace grub-install to see how it call these two scripts.

# bash -x grub-install /dev/sdc


In the trace, we pick these two lines:



+ /usr/bin/grub-mkimage -d /usr/lib/grub/i386-pc -O i386-pc --output=/boot/grub/i386-pc/core.img '--prefix=(,gpt2)/boot/grub' biosdisk ext2 part_gpt


+ /usr/sbin/grub-bios-setup --directory=/boot/grub/i386-pc --device-map= /dev/sdc



We can see from above that the generated core.img is placed under "/boot/grub/i386-pc". Its size is 26322 bytes.



# ls -l core.img
-rw-r--r-- 1 root root 26322 Jun 13 13:30 core.img


To find out what is in the core.img and how core.img is written into /dev/sdc1 (GRUB Boot partition), let us strace these two calls:


strace -o grub-mkimage.trace /usr/bin/grub-mkimage -d /usr/lib/grub/i386-pc -O i386-pc --output=/boot/grub/i386-pc/core.img '--prefix=(,gpt2)/boot/grub' biosdisk ext2 part_gpt


strace -o grub-bios-setup.trace /usr/sbin/grub-bios-setup --directory=/boot/grub/i386-pc --device-map= /dev/sdc


After analyze these trace files and refer to grub docs (link), we can see:

grub-mkimage will collect "kernel.img/lzma_decompress.img/diskboot.img/biosdisk.mod/fshelp.mod/ext2.mod/part_gpt.mod"from "/boot/grub/i386-pc", after compress these image and merged into a "core.img" in /boot/grub/i386-pc directory.

grub-bios-setup will just "flashed" boot.img to MBR and core.img to /dev/sdc1 (BIOS Boot partition).

Let us verify our observation.


# ls -l /boot/grub/i386-pc/core.img
-rw-r--r-- 1 root root 26322 Jun 13 15:34 /boot/grub/i386-pc/core.img
# dd if=/dev/sdc1 of=sdc1.core bs=26332 count=1
# dhex /boot/grub/i386-pc/core.img sdc1.core

http://lukeluo.blogspot.co.uk/2013/06/how-to-make-bootstrap-ubuntu-usb-stick.html?view=timeslide

After a thorough check, these two files only differ in 5 bytes. What did "grub-bios-setup" do to our core.img?
The first sector of core.img is "diskboot.img" in this case. Its source code is "grub-core/boot/i386/pc/diskboot.S". diskboot.img is 512 bytes. At the end of source code, we have these lines:

. = _start + 0x200 - GRUB_BOOT_MACHINE_LIST_SIZE
LOCAL(firstlist): /* this label has to be before the first list entry!!! */
/* fill the first data listing with the default */