Scenario
The raw format disk image used here already contained a
Buildroot compiled
filesystem1.
It was partitioned as follows:
$ sudo losetup /dev/loop0 brdisk-img.raw
$ sudo fdisk -l -u /dev/loop0
Disk /dev/loop0: 2684 MB, 2684354560 bytes
255 heads, 63 sectors/track, 326 cylinders, total 5242880 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x56a8c587
Device Boot Start End Blocks Id System
/dev/loop0p1 2048 1026047 512000 83 Linux
/dev/loop0p2 1026048 5242879 2108416 83 Linux
where:
-
The first partition will be used as the boot partition. Note that this partition will
be (re-)formatted here before having grub installed in it.
-
The second partition already contained the rest of the
Buildroot compiled root filesystem i.e. everything other than /boot .
In addition, the current working directory also
contained the bzImage used to QEMU boot against this disk image2
$ ls
bzImage brdisk-img.raw
$ WORKDIR=$PWD
$ mkdir boot
NOTE: GRUB, if used incorrectly, can overwrite the bootloader of your system. So, preferably, the instructions in Sections link and link should
be performed from within another QEMU VM environment
(running a full blown distro). In fact, the instructions
contained here were performed from within a QEMU VM instance running
Ubuntu 12.04.
Otherwise, if working from a physical machine environment,
proceed with extreme caution.
GRUB
The GRand Unified Bootloader (GRUB), or more precisely GRUB 2, is the successor of the older GRUB Legacy (also known as GRUB version 0.9x). For the differences between GRUB Legacy and GRUB,
follow this link.
Download, configure and build GRUB:
$ cd $WORKDIR
$ wget -c ftp://ftp./gnu/grub/grub-2.00.tar.xz
$ tar xJf grub-2.00.tar.xz
$ mkdir {gtemp,gbuild,gv2}
$ GRUB_INSTALL=${WORKDIR}/gv2
$ GRUB_TEMP=${WORKDIR}/gtemp
$ GRUB_SOURCE=${WORKDIR}/grub-2.00
$ cd $GRUB_TEMP
$ sudo apt-get install bison flex autoconf automake autotools-dev libtool gettext libdevmapper-dev
$ ${GRUB_SOURCE}/configure --prefix=${GRUB_INSTALL}/usr --enable-device-mapper
...
*******************************************************
GRUB2 will be compiled with following components:
Platform: i386-pc
With devmapper support: Yes
With memory debugging: No
With disk cache statistics: No
efiemu runtime: Yes
grub-mkfont: No (need freetype2 library)
grub-mount: No (need FUSE library)
starfield theme: No (No grub-mkfont)
With libzfs support: No (need zfs library)
*******************************************************
$ make [-jN]
$ make install
This should result in the following GRUB installation:
$ cd $WORKDIR
$ tree -L 3 gv2/
gv2/
└── usr
├── bin
│ ├── grub-editenv
│ ├── grub-fstest
│ ├── grub-kbdcomp
│ ├── grub-menulst2cfg
│ ├── grub-mkfont
│ ├── grub-mkimage
│ ├── grub-mklayout
│ ├── grub-mkpasswd-pbkdf2
│ ├── grub-mkrelpath
│ ├── grub-mkrescue
│ ├── grub-mkstandalone
│ └── grub-script-check
├── etc
│ ├── bash_completion.d
│ └── grub.d
├── lib
│ └── grub
├── sbin
│ ├── grub-bios-setup
│ ├── grub-install
│ ├── grub-mkconfig
│ ├── grub-mknetdir
│ ├── grub-ofpathname
│ ├── grub-probe
│ ├── grub-reboot
│ ├── grub-set-default
│ └── grub-sparc64-setup
└── share
├── grub
├── info
└── locale
Installing GRUB in the Disk Image
Apparently, GRUB only works on partitions attached to loopback devices
via /dev/mapper/loopN , as opposed to those attached via /dev/loopN .
So proceeding with kpartx(8) 3:
$ cd $WORKDIR
$ sudo apt-get install kpartx # if not yet installed
$ sudo kpartx -l brdisk-img.raw
loop0p1 : 0 1024000 /dev/loop0 2048
loop0p2 : 0 4216832 /dev/loop0 1026048
loop deleted : /dev/loop0
$ sudo kpartx -a brdisk-img.raw
$ sudo mkfs.ext3 /dev/mapper/loop0p1
$ sudo mount /dev/mapper/loop0p1 boot
Now, if performing these instructions in a physical machine
environment, be warned that the grub-install command below
could overwrite the bootloader of your system if used
incorrectly:
-
The value against --root-directory must be set to the boot partition mount of the QEMU disk image.
-
The specified device must be the loopback device attached to the entire disk image - in this case, /dev/loop0 rather than /dev/loop0p1 .
Install GRUB in the disk image:
$ cd $WORKDIR
$ sudo ${GRUB_INSTALL}/usr/sbin/grub-install --no-floppy --root-directory=./ /dev/loop0
Note: On my system, the grub-install command emitted a slew of warnings:
device-mapper: table ioctl failed: No such device or address
device-mapper: table ioctl failed: No such device or address
device-mapper: table ioctl failed: No such device or address
device-mapper: table ioctl failed: No such device or address
...
...but still completed successfully...
Installation finished. No error reported.
The grub-install command should result in the following installation
in ${WORKDIR}/boot :
$ cd $WORKDIR
$ tree -L 2 boot/
boot/
├── grub
│ ├── grubenv
│ ├── i386-pc
│ ├── locale
│ └── themes
└── lost+found
Now create grub.cfg such that:
$ cat boot/grub/grub.cfg
set default="0"
set timeout="3"
menuentry "Buildroot" {
insmod gzio
insmod part_msdos
insmod ext2
linux (hd0,msdos1)/bzImage root=/dev/sda2 rw console=tty0 console=ttyS0
}
The console=tty0 console=ttyS0 kernel commandline parameters
are not essential. They are included here for debugging purposes.
Finally, install bzImage and cleanup:
$ sudo cp -a bzImage boot
$ ls boot/
bzImage grub lost+found
$ sudo umount boot
$ sudo kpartx -d brdisk-img.raw
loop deleted : /dev/loop0
Testing
Your QEMU commandline may vary somewhat. The important thing to note is the fact that no -kernel option and kernel image are specified here:
$ cd $WORKDIR
$ qemu-system-i386 -machine accel=kvm:tcg brdisk-img.raw -serial stdio
Strike e on the keyboard to view (and, if desired, edit) the
GRUB boot entry:
Hit F10 to proceed with the boot:
The buildroot login: prompt on both the Linux FB VT
and the QEMU launch xterm was possible due to the combination of the
-serial stdio QEMU commandline option,
the kernel configuration CONFIG_SERIAL_8250_CONSOLE=y setting, the
console=tty0 console=ttyS0 Linux commandline settings, and the
Buildroot root filesystem /etc/inittab configuration4:
[root@buildroot ~]# cat /etc/inittab
...
1:1:respawn:/sbin 38400 tty1
2:1:respawn:/sbin 38400 tty2
S0::respawn:/sbin -L ttyS0 115200 vt100
...
UUID
Persistent device naming for block devices via the
Universally Unique IDentifier (UUID)
has been made possible courtersy of udev. It presents some
advantages over the use of traditional bus-based names such as
/dev/sda1 (or /dev/hda1 ).
Specifying a partition's by UUID guarantees that the partition will be found even if its disk assignment changes between
system boots.
The UUID of a partition can be retrieved by way of the
blkid command. For instance:
$ sudo blkid /dev/mapper/loop0p1
/dev/mapper/loop0p1: UUID="47c6fa91-6482-4956-912f-574ada8f5cd5" TYPE="ext3"
$ sudo blkid /dev/mapper/loop0p2
/dev/mapper/loop0p2: UUID="4a73b1bf-af94-436e-ba88-d6c9c3f71d99" TYPE="ext3"
With respect to GRUB, this translates to:
$ cat boot/grub/grub.cfg
set default="0"
set timeout="3"
menuentry "Buildroot" {
insmod gzio
insmod part_msdos
insmod ext2
set root='(hd0,msdos1)'
search --no-floppy --fs-uuid --set=root 47c6fa91-6482-4956-912f-574ada8f5cd5
linux /bzImage root=/dev/sda2 rw console=tty0 console=ttyS0
}
Note that in order to specify the UUID value against root= i.e:
...
set root='(hd0,msdos1)'
search --no-floppy --fs-uuid --set=root 47c6fa91-6482-4956-912f-574ada8f5cd5
linux /bzImage root=UUID=4a73b1bf-af94-436e-ba88-d6c9c3f71d99 rw
...
will require use of an initramfs (or initrd)5.
The kernel does not understand UUID and the boot process
will fail with a message similar to:
[ 0.373251] sr0: scsi3-mmc drive: 4x/4x cd/rw xa/form2 tray
[ 0.374700] cdrom: Uniform CD-ROM driver Revision: 3.20
[ 0.375843] sr 1:0:0:0: Attached scsi generic sg1 type 5
[ 0.377311] VFS: Cannot open root device "UUID=4a73b1bf-af94-436e-ba88-d6c9c3f71d99" or unknown-block(0,0): error -6
[ 0.379753] Please append a correct "root=" boot option; here are the available partitions:
[ 0.381611] 0800 2621440 sda driver: sd
[ 0.383407] 0801 512000 sda1 00000000-0000-0000-0000-000000000000
[ 0.385464] 0802 2108416 sda2 00000000-0000-0000-0000-000000000000
[ 0.387316] 0b00 1048575 sr0 driver: sr
[ 0.388405] Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)
[ 0.390412] Pid: 1, comm: swapper Not tainted 3.5.1 #4
[ 0.392356] Call Trace:
[ 0.393497] [<c1584314>] panic+0x78/0x166
[ 0.394777] [<c1817d4e>] mount_block_root+0x1b2/0x23a
Alternatively, PARTUUID could be specified
instead of using an initramfs. In otherwords, while
the kernel does not support root=UUID= , it understands root=PARTUUID= .
But this will not be discussed any further here. See Section "Resources" below for pointers on using PARTUUID.
Resources
- https://wiki./index.php/Creating_Arch_Linux_disk_image
- https://wiki./Part-UUID#Via_UUIDs
- http://www./lfs/view/development/chapter06/grub.html
- http://www./lfs/view/development/chapter08/grub.html
- See the
root= entry in Documentation/kernel-parameters.txt and comments
in init/do_mounts.c for more details on UUIDs, PARTUUIDs etc
Footnotes
1. See Transfering Buildroot compiled filesystem data into a QEMU disk image [go back]
2. The images used in this guide were x86 (32-bit) [go back]
3. To avoid complications, make sure no files are attached to the loop devices /dev/loopN before proceeding; run losetup -a to view any attached files and losetup -d /dev/loopN to dettach [go back]
4. See QEMU Serial port system console [go back]
5. See Initramfs Tutorial [go back]
|