Booting Ubuntu Manually
-----------------------
This shows a manual approach to booting Ubuntu without standard boot or the EFI
interface.
As an example of how to set up your boot flow with U-Boot, here are
instructions for starting Ubuntu from U-Boot. These instructions have been
tested on Minnowboard MAX with a SATA drive but are equally applicable on
other platforms and other media. There are really only four steps and it's a
very simple script, but a more detailed explanation is provided here for
completeness.
Note: It is possible to set up U-Boot to boot automatically using syslinux.
It could also use the grub.cfg file (/efi/ubuntu/grub.cfg) to obtain the
GUID. If you figure these out, please post patches to this README.
Firstly, you will need Ubuntu installed on an available disk. It should be
possible to make U-Boot start a USB start-up disk but for now let's assume
that you used another boot loader to install Ubuntu.
Use the U-Boot command line to find the UUID of the partition you want to
boot. For example our disk is SCSI device 0::
=> part list scsi 0
Partition Map for SCSI device 0 -- Partition Type: EFI
Part Start LBA End LBA Name
Attributes
Type GUID
Partition GUID
1 0x00000800 0x001007ff ""
attrs: 0x0000000000000000
type: c12a7328-f81f-11d2-ba4b-00a0c93ec93b
guid: 9d02e8e4-4d59-408f-a9b0-fd497bc9291c
2 0x00100800 0x037d8fff ""
attrs: 0x0000000000000000
type: 0fc63daf-8483-4772-8e79-3d69d8477de4
guid: 965c59ee-1822-4326-90d2-b02446050059
3 0x037d9000 0x03ba27ff ""
attrs: 0x0000000000000000
type: 0657fd6d-a4ab-43c4-84e5-0933c84b4f4f
guid: 2c4282bd-1e82-4bcf-a5ff-51dedbf39f17
=>
This shows that your SCSI disk has three partitions. The really long hex
strings are called Globally Unique Identifiers (GUIDs). You can look up the
'type' ones `here`_. On this disk the first partition is for EFI and is in
VFAT format (DOS/Windows)::
=> fatls scsi 0:1
efi/
0 file(s), 1 dir(s)
Partition 2 is 'Linux filesystem data' so that will be our root disk. It is
in ext2 format::
=> ext2ls scsi 0:2
4096 .
4096 ..
16384 lost+found
4096 boot
12288 etc
4096 media
4096 bin
4096 dev
4096 home
4096 lib
4096 lib64
4096 mnt
4096 opt
4096 proc
4096 root
4096 run
12288 sbin
4096 srv
4096 sys
4096 tmp
4096 usr
4096 var
33 initrd.img
30 vmlinuz
4096 cdrom
33 initrd.img.old
=>
and if you look in the /boot directory you will see the kernel::
=> ext2ls scsi 0:2 /boot
4096 .
4096 ..
4096 efi
4096 grub
3381262 System.map-3.13.0-32-generic
1162712 abi-3.13.0-32-generic
165611 config-3.13.0-32-generic
176500 memtest86+.bin
178176 memtest86+.elf
178680 memtest86+_multiboot.bin
5798112 vmlinuz-3.13.0-32-generic
165762 config-3.13.0-58-generic
1165129 abi-3.13.0-58-generic
5823136 vmlinuz-3.13.0-58-generic
19215259 initrd.img-3.13.0-58-generic
3391763 System.map-3.13.0-58-generic
5825048 vmlinuz-3.13.0-58-generic.efi.signed
28304443 initrd.img-3.13.0-32-generic
=>
The 'vmlinuz' files contain a packaged Linux kernel. The format is a kind of
self-extracting compressed file mixed with some 'setup' configuration data.
Despite its size (uncompressed it is >10MB) this only includes a basic set of
device drivers, enough to boot on most hardware types.
The 'initrd' files contain a RAM disk. This is something that can be loaded
into RAM and will appear to Linux like a disk. Ubuntu uses this to hold lots
of drivers for whatever hardware you might have. It is loaded before the
real root disk is accessed.
The numbers after the end of each file are the version. Here it is Linux
version 3.13. You can find the source code for this in the Linux tree with
the tag v3.13. The '.0' allows for additional Linux releases to fix problems,
but normally this is not needed. The '-58' is used by Ubuntu. Each time they
release a new kernel they increment this number. New Ubuntu versions might
include kernel patches to fix reported bugs. Stable kernels can exist for
some years so this number can get quite high.
The '.efi.signed' kernel is signed for EFI's secure boot. U-Boot has its own
secure boot mechanism - see `this`_ & `that`_. It cannot read .efi files
at present.
To boot Ubuntu from U-Boot the steps are as follows:
1. Set up the boot arguments. Use the GUID for the partition you want to boot::
=> setenv bootargs root=/dev/disk/by-partuuid/965c59ee-1822-4326-90d2-b02446050059 ro
Here root= tells Linux the location of its root disk. The disk is specified
by its GUID, using '/dev/disk/by-partuuid/', a Linux path to a 'directory'
containing all the GUIDs Linux has found. When it starts up, there will be a
file in that directory with this name in it. It is also possible to use a
device name here, see later.
2. Load the kernel. Since it is an ext2/4 filesystem we can do::
=> ext2load scsi 0:2 03000000 /boot/vmlinuz-3.13.0-58-generic
The address 30000000 is arbitrary, but there seem to be problems with using
small addresses (sometimes Linux cannot find the ramdisk). This is 48MB into
the start of RAM (which is at 0 on x86).
3. Load the ramdisk (to 64MB)::
=> ext2load scsi 0:2 04000000 /boot/initrd.img-3.13.0-58-generic
4. Start up the kernel. We need to know the size of the ramdisk, but can use
a variable for that. U-Boot sets 'filesize' to the size of the last file it
loaded::
=> zboot 03000000 0 04000000 ${filesize}
Type 'help zboot' if you want to see what the arguments are. U-Boot on x86 is
quite verbose when it boots a kernel. You should see these messages from
U-Boot::
Valid Boot Flag
Setup Size = 0x00004400
Magic signature found
Using boot protocol version 2.0c
Linux kernel version 3.13.0-58-generic (buildd@allspice) #97-Ubuntu SMP Wed Jul 8 02:56:15 UTC 2015
Building boot_params at 0x00090000
Loading bzImage at address 100000 (5805728 bytes)
Magic signature found
Initial RAM disk at linear address 0x04000000, size 19215259 bytes
Kernel command line: "root=/dev/disk/by-partuuid/965c59ee-1822-4326-90d2-b02446050059 ro"
Starting kernel ...
U-Boot prints out some bootstage timing. This is more useful if you put the
above commands into a script since then it will be faster::
Timer summary in microseconds:
Mark Elapsed Stage
0 0 reset
241,535 241,535 board_init_r
2,421,611 2,180,076 id=64
2,421,790 179 id=65
2,428,215 6,425 main_loop
48,860,584 46,432,369 start_kernel
Accumulated time:
240,329 ahci
1,422,704 vesa display
Now the kernel actually starts (if you want to examine kernel boot up message on
the serial console, append "console=ttyS0,115200" to the kernel command line)::
[ 0.000000] Initializing cgroup subsys cpuset
[ 0.000000] Initializing cgroup subsys cpu
[ 0.000000] Initializing cgroup subsys cpuacct
[ 0.000000] Linux version 3.13.0-58-generic (buildd@allspice) (gcc version 4.8.2 (Ubuntu 4.8.2-19ubuntu1) ) #97-Ubuntu SMP Wed Jul 8 02:56:15 UTC 2015 (Ubuntu 3.13.0-58.97-generic 3.13.11-ckt22)
[ 0.000000] Command line: root=/dev/disk/by-partuuid/965c59ee-1822-4326-90d2-b02446050059 ro console=ttyS0,115200
It continues for a long time. Along the way you will see it pick up your
ramdisk::
[ 0.000000] RAMDISK: [mem 0x04000000-0x05253fff]
...
[ 0.788540] Trying to unpack rootfs image as initramfs...
[ 1.540111] Freeing initrd memory: 18768K (ffff880004000000 - ffff880005254000)
...
Later it actually starts using it::
Begin: Running /scripts/local-premount ... done.
You should also see your boot disk turn up::
[ 4.357243] scsi 1:0:0:0: Direct-Access ATA ADATA SP310 5.2 PQ: 0 ANSI: 5
[ 4.366860] sd 1:0:0:0: [sda] 62533296 512-byte logical blocks: (32.0 GB/29.8 GiB)
[ 4.375677] sd 1:0:0:0: Attached scsi generic sg0 type 0
[ 4.381859] sd 1:0:0:0: [sda] Write Protect is off
[ 4.387452] sd 1:0:0:0: [sda] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[ 4.399535] sda: sda1 sda2 sda3
Linux has found the three partitions (sda1-3). Mercifully it doesn't print out
the GUIDs. In step 1 above we could have used::
setenv bootargs root=/dev/sda2 ro
instead of the GUID. However if you add another drive to your board the
numbering may change whereas the GUIDs will not. So if your boot partition
becomes sdb2, it will still boot. For embedded systems where you just want to
boot the first disk, you have that option.
The last thing you will see on the console is mention of plymouth (which
displays the Ubuntu start-up screen) and a lot of 'Starting' messages::
* Starting Mount filesystems on boot [ OK ]
After a pause you should see a login screen on your display and you are done.
If you want to put this in a script you can use something like this::
setenv bootargs root=UUID=b2aaf743-0418-4d90-94cc-3e6108d7d968 ro
setenv boot zboot 03000000 0 04000000 \${filesize}
setenv bootcmd "ext2load scsi 0:2 03000000 /boot/vmlinuz-3.13.0-58-generic; ext2load scsi 0:2 04000000 /boot/initrd.img-3.13.0-58-generic; run boot"
saveenv
The \ is to tell the shell not to evaluate ${filesize} as part of the setenv
command.
You can also bake this behaviour into your build by hard-coding the
environment variables if you add this to minnowmax.h:
.. code-block:: c
#undef CONFIG_BOOTCOMMAND
#define CONFIG_BOOTCOMMAND \
"ext2load scsi 0:2 03000000 /boot/vmlinuz-3.13.0-58-generic; " \
"ext2load scsi 0:2 04000000 /boot/initrd.img-3.13.0-58-generic; " \
"run boot"
#undef CFG_EXTRA_ENV_SETTINGS
#define CFG_EXTRA_ENV_SETTINGS "boot=zboot 03000000 0 04000000 ${filesize}"
and change CONFIG_BOOTARGS value in configs/minnowmax_defconfig to::
CONFIG_BOOTARGS="root=/dev/sda2 ro"
.. _here: https://en.wikipedia.org/wiki/GUID_Partition_Table
.. _this: http://events.linuxfoundation.org/sites/events/files/slides/chromeos_and_diy_vboot_0.pdf
.. _that: http://events.linuxfoundation.org/sites/events/files/slides/elce-2014.pdf