When working on low level kernel code, the indication that something
went wrong is often noticed as a kernel oops, or even a totally silent
system. This usually implies a modify-recompile-reboot cycle which can
become very very annoying if the reboot step implies popping out an SD
card from the board, inserting it into the work PC, mounting it, copying
the newly compiled kernel over, unmounting, moving the SD card back to
the board, to finally hit the reset button.
If you are an old fashioned kernel developer like me and live by the
simplest development environment (bash, vi, gcc) and your most trusted
debugging tool is printk(), then having the ability to quickly boot a
new kernel after moving printk traces around in order to pinpoint a
crash location is vital. But even for validation purposes on a remote
board, not needing physical intervention is really nice.
So, by popular demand, here's how I accomplished this on VirtualExpress
with a TC2 tile. This probably applies to other VirtualExpress
configurations too, but TC2 is the only one I tested.
Obtaining U-Boot
----------------
I don't have a particular affection for any bootloaders. They tend to
ask for more and more attention and visibility while their raison d'ĂȘtre
is actually to get out of the way and disappear as fast as possible.
While U-Boot has many things that certainly gets on my nerves, it has a
good point for itself which is its networking support. And here is the
key: let's fetch everything we need to boot the board over the network,
script it, so not to have to deal with the bootloader (or bootloaders in
this case) anymore.
First, let's get a copy of the U-Boot source tree. I used the Linaro
version as it includes Versatile Express support.
$ git clone git://git.linaro.org/boot/u-boot-linaro-stable.git
$ cd u-boot-linaro-stable/
Now... to get rid of U-Boot's most obnoxious feature (my opinion),
the following patch should be applied:
diff --git a/include/configs/vexpress_common.h
b/include/configs/vexpress_common.h
index 88a2c95..3328443 100644
--- a/include/configs/vexpress_common.h
+++ b/include/configs/vexpress_common.h
@@ -177,6 +177,8 @@
#define CONFIG_CMD_SAVEENV
#define CONFIG_CMD_RUN
#define CONFIG_CMD_BOOTD
+#define CONFIG_CMD_BOOTZ
+#define CONFIG_SUPPORT_RAW_INITRD
#define CONFIG_CMD_ECHO
#define CONFIG_CMD_FAT
That basically enables U-Boot to boot a plain ARM Linux zImage file
without going through the mkimage step (the bootz command), and load a
plain ramdisk image without having to run mkimage on it. This mkimage
step is just extra fuss I can dispense with when working on and booting
kernels frequently.
Now let's build it. There is no TC2 (ca15 or ca7) config, however the
ca5 one appears to be close enough for our needs:
$ make vexpress_ca5x2
You should end up with a u-boot.bin to be used later.
ARM Versatile Express Boot Monitor
----------------------------------
This is the native boot loader on the Virtual Express. In fact there
are many instances of different loaders even on different processors
making the whole system rather weird but flexible. It lacks the ability
to load files from the network though. But that's what a second stage
bootloader such as U-Boot is for.
Good information on setting up a Virtual Express already exists. While
the instructions listed therein may or may not all apply to our case, I
still recommend to read the following pages to get familiar with this
beast:
https://wiki.linaro.org/PawelMoll/BootingVEMadeEasy
The script to generate a boot script to generate an ATAGS block is a
rather nice hack. But I want runtime DTB support and I prefer booting
over the network, especially when playing with ramdisk images which is
otherwise long to get reflashed. Still this page provides a nice
introduction to Virtual Express setup and gives good insights on the
micro switch usage and the VE boot monitor structure.
https://wiki.linaro.org/ARM/VersatileExpressSetup
This page shows how to install U-Boot on a Virtual Express and that's
what we want here. you should follow the instructions listed for the
CA15x2 CoreTile, except that the U-Boot binary to use is the one we just
compiled above. Also, for TC2 the images.txt file is located in
SITE1/HBI0249A/.
In short, once the internal MicroSD card is mounted over USb, the
u-boot.bin file we compiled should be copied to SOFTWARE/u-boot.bin.
Then the file SITE1/HBI0249A/images.txt should be updated to contain
something similar to this:
NOR4UPDATE: AUTO
NOR4ADDRESS: 0f800000
NOR4FILE: \SOFTWARE\u-boot.bin
NOR4LOAD: 0x80800000
NOR4ENTRY: 0x80800000
We also need a boot script to start U-Boot automatically:
NOR5UPDATE: AUTO
NOR5NAME: BOOTSCRIPT
NOR5ADDRESS: 00000000
NOR5FILE: \SOFTWARE\boot.txt
Here the "BOOTSCRIPT" name is important otherwise the script won't be
found and executed.
The number after "NOR" may differ, depending on the other images your
images.txt may already contain. Don't forget to update the TOTALIMAGES
value at the top to reflect the number of image definitions you have,
especially if you added new ones.
Finally, the content of SOFTWARE/boot.txt only needs to contain one
line:
flash run u-boot
That's it! unmounting the USB disk, setting SW[0] down and booting the
main board (entering the "reboot" command on the serial console) should
bring you to an U-Boot prompt.
The U-Boot configuration
------------------------
Once at the U-Boot prompt, it is necessary to set a couple environment
variables:
VExpress# setenv bootcmd run loadbootscript\; source \$fileaddr
VExpress# setenv loadbootscript dhcp 0x84000000 192.168.2.2:tc2_boot.scr
VExpress# saveenv
In the loadbootscript definition, I used an explicit IP address to
prefix the file name. This is because my DHCP server is not the same
machine as my TFTP server used to provide the location for the loaded
files. If your DHCP configuration already provides that information
then it is not necessary to provide such prefix. If you prefer using a
fixed IP address for the board, you may simply set the ipaddr, netmask
and gatewayip environment variables accordingly, and replace dhcp with
tftp in the definition of loadbootscript. And don't forget to saveenv
again.
That's it! Once the script is loaded over the network, we don't need to
deal with U-Boot's configuration anymore.
The U-Boot boot script
----------------------
Now you need a TFTP server (normally tftpd) on your PC or laptop. In
its content directory, there should be a file called tc2_boot.scr.
Unfortunately, the U-Boot obnoxiousness is striking back at us since
this must be mkimage wrapped. Let's start with the source, say
tc2_boot.txt which should contain the following U-Boot commands:
# set the TFTP server address (the dhcp command clobbers it)
setenv serverip 192.168.2.2
# load a DTB
tftp 0x82000000 vexpress-v2p-iks-tc2.dtb
# tell U-Boot about it
fdt addr $fileaddr
# load a ramdisk image
tftp 0x88000000 initrd.gz
# remember its location and size for later
setenv rd_addr $fileaddr
setenv rd_size $filesize
# load the kernel
tftp 0x81000000 zImage
# set our kernel parameters
setenv bootargs console=ttyAMA0,38400 earlyprintk debug root=/dev/sda1 rootwait
# boot the kernel
bootz $fileaddr $rd_addr:$rd_size $fdtaddr
The above is what I use and can be adapted to your needs. Again, maybe
you don't need to override serverip. Maybe you wish to use a NFS root.
Etc. That's the beauty of it: it is just a .txt file on your PC that you
can modify at will without having to flash it anywhere. Temporary
changes to the DTB with the fdt commands are also possible without
having to modify and recompile the corresponding .dts, etc.
However we need to ubootize it into tc2_boot.scr before it is usable:
$ mkimage -A ARM -T script -C none -d tc2_boot.txt tc2_boot.scr
(The one who tells me how to avoid this step gets a cookie.)
Suffice to copy the desired kernel zImage and initrd files there too for
the boot to proceed. It might even be possible to use a symbolic link
towards the zImage produced by the compilation of the kernel directly so
to avoid that copy, but I didn't push my own laziness that far.
Let's boot!
-----------
Now you may use the "reboot" command at the "Cmd>" prompt provided by
the microcontroller to power up the board. When the board is booted,
this prompt is moved from UART 0 to UART 1 while the kernel console
output is going to UART 0, so it is possible to shutdown or reboot the
board over UART 1 entirely unattended and remotely when both serial
ports are connected to a computer.
Enjoy !
Nicolas
_______________________________________________
linaro-dev mailing list
linaro-dev@lists.linaro.org
http://lists.linaro.org/mailman/listinfo/linaro-dev