work with minimal adjustments on other x86 boards since coreboot deals with
most of the low-level details.
-U-Boot also supports booting directly from x86 reset vector without coreboot,
-aka raw support or bare support. Currently Link, QEMU x86 targets and all
-Intel boards support running U-Boot 'bare metal'.
+U-Boot also supports booting directly from x86 reset vector, without coreboot.
+In this case, known as bare mode, from the fact that it runs on the
+'bare metal', U-Boot acts like a BIOS replacement. Currently Link, QEMU x86
+targets and all Intel boards support running U-Boot 'bare metal'.
As for loading an OS, U-Boot supports directly booting a 32-bit or 64-bit
Linux kernel as part of a FIT image. It also supports a compressed zImage.
-Build Instructions
-------------------
+Build Instructions for U-Boot as coreboot payload
+-------------------------------------------------
Building U-Boot as a coreboot payload is just like building U-Boot for targets
on other architectures, like below:
to point to a new board. You can also change the Cache-As-RAM (CAR) related
settings here if the default values do not fit your new board.
+Build Instructions for U-Boot as BIOS replacement (bare mode)
+-------------------------------------------------------------
Building a ROM version of U-Boot (hereafter referred to as u-boot.rom) is a
little bit tricky, as generally it requires several binary blobs which are not
shipped in the U-Boot source tree. Due to this reason, the u-boot.rom build is
This tells the Makefile to build u-boot.rom as a target.
-Link-specific instructions:
+---
+
+Chromebook Link specific instructions for bare mode:
First, you need the following binary blobs:
$ make chromebook_link_defconfig
$ make all
-Intel Crown Bay specific instructions:
+---
+
+Intel Crown Bay specific instructions for bare mode:
U-Boot support of Intel Crown Bay board [4] relies on a binary blob called
Firmware Support Package [5] to perform all the necessary initialization steps
$ make crownbay_defconfig
$ make all
-Intel Minnowboard Max instructions:
+---
+
+Intel Minnowboard Max instructions for bare mode:
This uses as FSP as with Crown Bay, except it is for the Atom E3800 series.
Download this and get the .fd file (BAYTRAIL_FSP_GOLD_003_16-SEP-2014.fd at
Overall ROM image size is controlled by CONFIG_ROM_SIZE.
+---
-Intel Galileo instructions:
+Intel Galileo instructions for bare mode:
Only one binary blob is needed for Remote Management Unit (RMU) within Intel
Quark SoC. Not like FSP, U-Boot does not call into the binary. The binary is
# in the coreboot root directory
$ ./build/util/cbfstool/cbfstool build/coreboot.rom add-flat-binary \
- -f u-boot-dtb.bin -n fallback/payload -c lzma -l 0x1110000 -e 0x1110015
+ -f u-boot-dtb.bin -n fallback/payload -c lzma -l 0x1110000 -e 0x1110000
-Make sure 0x1110000 matches CONFIG_SYS_TEXT_BASE and 0x1110015 matches the
-symbol address of _start (in arch/x86/cpu/start.S).
+Make sure 0x1110000 matches CONFIG_SYS_TEXT_BASE, which is the symbol address
+of _x86boot_start (in arch/x86/cpu/start.S).
If you want to use ELF as the coreboot payload, change U-Boot configuration to
use CONFIG_OF_EMBED instead of CONFIG_OF_SEPARATE.
the video information correctly (it always says the resolution is 0x0). This
works correctly for link though.
-Test with QEMU
---------------
+Test with QEMU for bare mode
+----------------------------
QEMU is a fancy emulator that can enable us to test U-Boot without access to
a real x86 board. Please make sure your QEMU version is 2.3.0 or above test
U-Boot. To launch QEMU with u-boot.rom, call QEMU as follows:
show QEMU's VGA console window. Note this will disable QEMU's serial output.
If you want to check both consoles, use '-serial stdio'.
+Multicore is also supported by QEMU via '-smp n' where n is the number of cores
+to instantiate. Currently the default U-Boot built for QEMU supports 2 cores.
+In order to support more cores, you need add additional cpu nodes in the device
+tree and change CONFIG_MAX_CPUS accordingly.
+
CPU Microcode
-------------
Modern CPUs usually require a special bit stream called microcode [8] to be
mode to use. U-Boot sets up some reasonable values but you can
adjust then with this command.
+Booting Ubuntu
+--------------
+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 driver but are equally applicable on
+other platforms and other media. There are really only four steps and its 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 Ubunutu 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 [11]. 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
+ <DIR> 4096 .
+ <DIR> 4096 ..
+ <DIR> 16384 lost+found
+ <DIR> 4096 boot
+ <DIR> 12288 etc
+ <DIR> 4096 media
+ <DIR> 4096 bin
+ <DIR> 4096 dev
+ <DIR> 4096 home
+ <DIR> 4096 lib
+ <DIR> 4096 lib64
+ <DIR> 4096 mnt
+ <DIR> 4096 opt
+ <DIR> 4096 proc
+ <DIR> 4096 root
+ <DIR> 4096 run
+ <DIR> 12288 sbin
+ <DIR> 4096 srv
+ <DIR> 4096 sys
+ <DIR> 4096 tmp
+ <DIR> 4096 usr
+ <DIR> 4096 var
+ <SYM> 33 initrd.img
+ <SYM> 30 vmlinuz
+ <DIR> 4096 cdrom
+ <SYM> 33 initrd.img.old
+ =>
+
+and if you look in the /boot directory you will see the kernel:
+
+ => ext2ls scsi 0:2 /boot
+ <DIR> 4096 .
+ <DIR> 4096 ..
+ <DIR> 4096 efi
+ <DIR> 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 [12] [13] and 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: "console=ttyS0,115200 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:
+
+ [ 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: console=ttyS0,115200 root=/dev/disk/by-partuuid/965c59ee-1822-4326-90d2-b02446050059 ro
+
+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 will also need to add this to your board configuration file, e.g.
+include/configs/minnowmax.h:
+
+ #define CONFIG_BOOTDELAY 2
+
+Now when you reset your board it wait a few seconds (in case you want to
+interrupt) and then should boot straight into Ubuntu.
+
+You can also bake this behaviour into your build by hard-coding the
+environment variables if you add this to minnowmax.h:
+
+#undef CONFIG_BOOTARGS
+#undef CONFIG_BOOTCOMMAND
+
+#define CONFIG_BOOTARGS \
+ "root=/dev/sda2 ro"
+#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 CONFIG_EXTRA_ENV_SETTINGS
+#define CONFIG_EXTRA_ENV_SETTINGS "boot=zboot 03000000 0 04000000 ${filesize}"
+
+
Development Flow
----------------
These notes are for those who want to port U-Boot to a new x86 platform.
For the microcode you can create a suitable device tree file using the
microcode tool:
- ./tools/microcode-tool -d microcode.dat create <model>
+ ./tools/microcode-tool -d microcode.dat -m <model> create
or if you only have header files and not the full Intel microcode.dat database:
./tools/microcode-tool -H BAY_TRAIL_FSP_KIT/Microcode/M0130673322.h \
-H BAY_TRAIL_FSP_KIT/Microcode/M0130679901.h \
- create all
+ -m all create
These are written to arch/x86/dts/microcode/ by default.
If not, you can try to get serial working as early as possible. The early
debug serial port may be useful here. See setup_early_uart() for an example.
+During the U-Boot porting, one of the important steps is to write correct PIRQ
+routing information in the board device tree. Without it, device drivers in the
+Linux kernel won't function correctly due to interrupt is not working. Please
+refer to U-Boot doc [14] for the device tree bindings of Intel interrupt router.
+Here we have more details on the intel,pirq-routing property below.
+
+ intel,pirq-routing = <
+ PCI_BDF(0, 2, 0) INTA PIRQA
+ ...
+ >;
+
+As you see each entry has 3 cells. For the first one, we need describe all pci
+devices mounted on the board. For SoC devices, normally there is a chapter on
+the chipset datasheet which lists all the available PCI devices. For example on
+Bay Trail, this is chapter 4.3 (PCI configuration space). For the second one, we
+can get the interrupt pin either from datasheet or hardware via U-Boot shell.
+The reliable source is the hardware as sometimes chipset datasheet is not 100%
+up-to-date. Type 'pci header' plus the device's pci bus/device/function number
+from U-Boot shell below.
+
+ => pci header 0.1e.1
+ vendor ID = 0x8086
+ device ID = 0x0f08
+ ...
+ interrupt line = 0x09
+ interrupt pin = 0x04
+ ...
+
+It shows this PCI device is using INTD pin as it reports 4 in the interrupt pin
+register. Repeat this until you get interrupt pins for all the devices. The last
+cell is the PIRQ line which a particular interrupt pin is mapped to. On Intel
+chipset, the power-up default mapping is INTA/B/C/D maps to PIRQA/B/C/D. This
+can be changed by registers in LPC bridge. So far Intel FSP does not touch those
+registers so we can write down the PIRQ according to the default mapping rule.
+
+Once we get the PIRQ routing information in the device tree, the interrupt
+allocation and assignment will be done by U-Boot automatically. Now you can
+enable CONFIG_GENERATE_PIRQ_TABLE for testing Linux kernel using i8259 PIC and
+CONFIG_GENERATE_MP_TABLE for testing Linux kernel using local APIC and I/O APIC.
+
+This script might be useful. If you feed it the output of 'pci long' from
+U-Boot then it will generate a device tree fragment with the interrupt
+configuration for each device (note it needs gawk 4.0.0):
+
+ $ cat console_output |awk '/PCI/ {device=$4} /interrupt line/ {line=$4} \
+ /interrupt pin/ {pin = $4; if (pin != "0x00" && pin != "0xff") \
+ {patsplit(device, bdf, "[0-9a-f]+"); \
+ printf "PCI_BDF(%d, %d, %d) INT%c PIRQ%c\n", strtonum("0x" bdf[1]), \
+ strtonum("0x" bdf[2]), bdf[3], strtonum(pin) + 64, 64 + strtonum(pin)}}'
+
+Example output:
+ PCI_BDF(0, 2, 0) INTA PIRQA
+ PCI_BDF(0, 3, 0) INTA PIRQA
+...
+
TODO List
---------
- Audio
[8] http://en.wikipedia.org/wiki/Microcode
[9] http://simplefirmware.org
[10] http://www.intel.com/design/archives/processors/pro/docs/242016.htm
+[11] https://en.wikipedia.org/wiki/GUID_Partition_Table
+[12] http://events.linuxfoundation.org/sites/events/files/slides/chromeos_and_diy_vboot_0.pdf
+[13] http://events.linuxfoundation.org/sites/events/files/slides/elce-2014.pdf
+[14] doc/device-tree-bindings/misc/intel,irq-router.txt