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??

https://debian-administration.org/users/dkg/weblog/112

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)

https://answers.launchpad.net/ubuntu/+source/grub2-signed/+question/295452

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.

Ubuntu .der files http://bazaar.launchpad.net/~ubuntu-bugcontrol/qa-regression-testing/master/files/head:/notes_testing/secure-boot/keys/

sbsign signs EFI files

https://wiki.ubuntu.com/UEFI/SecureBoot?highlight=%28secureboot%29%7C%28grubx64.efi%29

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 grub2 http://blog.fpmurphy.com/2011/06/boot-fedora-15-using-uefi-and-grub2.html

Slides on grub2 boot process,

https://www.suse.com/documentation/sles-12/book_sle_admin/data/sec_uefi_secboot.html

http://www.linux-magazine.com/index.php/layout/set/print/Issues/2014/164/The-State-of-Secure-Boot/(tagID)/154

https://www.wzdftpd.net/blog/uefi-secureboot-debian.html

https://technet.microsoft.com/en-us/library/dn747883.aspx?f=255&MSPPError=-2147217396

http://www.linuxquestions.org/questions/slackware-14/slackware64-14-1-uefi-booting-with-secure-boot-enabled-4175532990/

YouTube video on grub2 compilation under Windows using grub-mkimage

https://www.wzdftpd.net/blog/uefi-secureboot-debian.html

Ubuntu Secure boot information

Make grub2 USB drive + compiling boot files

User dialog on compiling grub2

grub2 download

grub2 man manual

rodsbooks efi signing

site of tui - grub2

building and booting grub2 for UEFI http://twobit.us/2015/09/building-and-booting-grub2-for-uefi-system/

boot linux with grub2 securely http://prosauce.org/blog/2015/10/31/booting-linux-securely

compile grub2 ask ubuntu Q

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 */

blocklist_default_start:

/* this is the sector start parameter, in logical sectors from

the start of the disk, sector 0 */

.long 2, 0

blocklist_default_len:

/* this is the number of sectors to read. grub-mkimage

will fill this up */

.word 0

blocklist_default_seg:

/* this is the segment of the starting address to load the data into */

.word (GRUB_BOOT_MACHINE_KERNEL_SEG + 0x20)

0x1F4~0x1FB: 8 bytes. The start sector on disk of kernel.img. bootdisk.img use this LBA to load kernel.img and other modules into memory.

0x1F4~0x1FB: 8 bytes. The start sector on disk of kernel.img. bootdisk.img use this LBA to load kernel.img and other modules into memory.

0x1FC~0x1FD: 2 bytes. How many sectors to load kernel/modules into memory

0x1FE~0x1FF: Memory segment address to load kernel into. Since diskboot.img has occupy 0x200 (512d) bytes, so this segment address need to add (0x200>>4)

In this case, kernel start LBA is 0x0801(2049d), the second sector of "Bios boot partition". The first partition is occupied by "diskboot.img", as we have seen in previous analysis. Number of sectors to be loaded is 0x67(103d) sector.

Starting from 0x200 is the start of kernel.img. The source code for this part is "grub-core/boot/i386/pc/startup_raw.S".

grub2, memdisk and loopback - http://lukeluo.blogspot.co.uk/2013/06/grub-how-to-4-memdisk-and-loopback.html

grub2 nad PXE booting - http://lukeluo.blogspot.co.uk/2013/06/grub-how-to6-pxe-boot.html