官术网_书友最值得收藏!

U-Boot

U-Boot, or to give its full name, Das U-Boot, began life as an open source bootloader for embedded PowerPC boards. Then, it was ported to ARM-based boards and later to other architectures, including MIPS, SH, and x86. It is hosted and maintained by Denx Software Engineering. There is plenty of information available, and a good place to start is www.denx.de/wiki/U-Boot. There is also a mailing list at .

Building U-Boot

Begin by getting the source code. As with most projects, the recommended way is to clone the git archive and check out the tag you intend to use which, in this case, is the version that was current at the time of writing:

$ git clone git://git.denx.de/u-boot.git
$ cd u-boot
$ git checkout v2015.07

Alternatively, you can get a tarball from ftp://ftp.denx.de/pub/u-boot/.

There are more than 1,000 configuration files for common development boards and devices in the configs/ directory. In most cases, you can make a good guess of which to use, based on the filename, but you can get more detailed information by looking through the per-board README files in the board/ directory, or you can find information in an appropriate web tutorial or forum. Beware, though, the way U-Boot is configured has undergone a lot of changes since the 2014.10 release. Double-check that the instructions you are following are appropriate.

Taking the BeagleBone Black as an example, we find that there is a likely configuration file named am335x_boneblack_defconfig in configs/ and we find the text The binary produced by this board supports … Beaglebone Black in the board README files for the am335x chip, board/ti/am335x/README. With this knowledge, building U-Boot for a BeagleBone Black is simple. You need to inform U-Boot of the prefix for your cross compiler by setting the make variable CROSS_COMPILE and then select the configuration file using a command of the type make [board]_defconfig, as follows:

$ make CROSS_COMPILE=arm-cortex_a8-linux-gnueabihf- am335x_boneblack_defconfig
$ make CROSS_COMPILE=arm-cortex_a8-linux-gnueabihf-

The results of the compilation are:

  • u-boot: This is U-Boot in ELF object format, suitable for use with a debugger
  • u-boot.map: This is the symbol table
  • u-boot.bin: This is U-Boot in raw binary format, suitable for running on your device
  • u-boot.img: This is u-boot.bin with a U-Boot header added, suitable for uploading to a running copy of U-Boot
  • u-boot.srec: This is U-Boot in Motorola srec format, suitable for transferring over a serial connection

The BeagleBone Black also requires a Secondary Program Loader (SPL), as described earlier. This is built at the same time and is named MLO:

$ ls -l MLO u-boot*
-rw-rw-r-- 1 chris chris 76100 Dec 20 11:22 MLO
-rwxrwxr-x 1 chris chris 2548778 Dec 20 11:22 u-boot
-rw-rw-r-- 1 chris chris 449104 Dec 20 11:22 u-boot.bin
-rw-rw-r-- 1 chris chris 449168 Dec 20 11:22 u-boot.img
-rw-rw-r-- 1 chris chris 434276 Dec 20 11:22 u-boot.map
-rw-rw-r-- 1 chris chris 1347442 Dec 20 11:22 u-boot.srec

The procedure is similar for other targets.

Installing U-Boot

Installing a bootloader on a board for the first time requires some outside assistance. If the board has a hardware debug interface, such as JTAG, it is usually possible to load a copy of U-Boot directly into RAM and set it running. From that point, you can use U-Boot commands to copy it into flash memory. The details of this are very board-specific and outside the scope of this book.

Some SoC designs have a boot ROM built in which can be used to read boot code from various external sources such as SD cards, serial interfaces, or USBs, and this is the case with the AM335x chip in the BeagleBone Black. Here is how to load U-Boot via the micro-SD card.

Firstly, format a micro-SD card so that the first partition is in FAT32 format, and mark it as bootable. If you have a direct SD slot available, the card appears as /dev/mmcblk0, otherwise, if you are using a memory card reader, it will be seen as /dev/sdb, or /dev/sdc, and so on. Now, type the following command to partition the micro-SD card, assuming that the card is seen as /dev/mmcblk0:

$ sudo sfdisk -D -H 255 -S 63 /dev/mmcblk0 << EOF 
,9,0x0C,*
,,,-
EOF

Format the first partition as FAT16:

$ sudo mkfs.vfat -F 16 -n boot /dev/mmcblk0p1

Now, mount the partition you have just formatted: on some systems it is enough to simply remove the micro-SD card and then plug it back in again, on others you may have to click on an icon. On current versions of Ubuntu, it should be mounted as /media/[user]/boot so I would copy U-Boot and the SPL to it like this:

cp MLO u-boot.img /media/chris/boot

Finally, unmount it.

With no power on the BeagleBone board, insert the micro-SD card.

Plug in the serial cable. A serial port should appear on your PC as /dev/ttyUSB0 or similar.

Start a suitable terminal program such as gtkterm, minicom, or picocom and attach to the port at 115,200 bps with no flow control:

$ gtkterm -p /dev/ttyUSB0 -s 115200

Press and hold the Boot Switch button on the Beaglebone, power up the board using the external 5V power connector, and release the button after about 5 seconds. You should see a U-Boot prompt on the serial console:

U-Boot#

Using U-Boot

In this section, I will describe some of the common tasks that you can use U-Boot to perform.

Usually, U-Boot offers a command-line interface over a serial port. It gives a command prompt which is customized for each board. In the examples, I will use U-Boot#. Typing help prints out all the commands configured in this version of U-Boot; typing help <command> prints out more information about a particular command.

The default command interpreter is quite simple. There is no command-line editing by pressing cursor left or right keys; there is no command completion by pressing the Tab key; there is no command history by pressing the cursor up key. Pressing any of these keys will disrupt the command you are currently trying to type and you will have to type Ctrl+C and start over again. The only line editing key you can safely use is the back space. As an option, you can configure a different command shell called Hush, which has more sophisticated interactive support.

The default number format is hexadecimal. For example, as shown in this command:

nand read 82000000 400000 200000

This command will read 0x200000 bytes from offset 0x400000 from the start of the NAND flash memory into RAM address 0x82000000.

Environment variables

U-Boot uses environment variables extensively to store and pass information between functions and even to create scripts. Environment variables are simple name=value pairs that are stored in an area of memory. The initial population of variables may be coded in the board configuration header file, like this:

#define CONFIG_EXTRA_ENV_SETTINGS \
"myvar1=value1\0" \
"myvar2=value2\0"

You can create and modify variables from the U-Boot command line using setenv. For example setenv foo bar creates the variable foo with the value bar. Note that there is no = sign between the variable name and the value. You can delete a variable by setting it to a null string, setenv foo. You can print all the variables to the console using printenv, or a single variable using printenv foo.

Usually, it is possible to use the saveenv command to save the entire environment to permanent storage of some kind. If there is raw NAND or NOR flash, then an erase block is reserved for this purpose, often with another used for a redundant copy to guard against corruption. If there is eMMC or SD card storage it can be stored in a file in a partition of the disk. Other options include storing in a serial EEPROM connected via an I2C or SPI interface or non-volatile RAM.

Boot image format

U-Boot doesn't have a filesystem. Instead, it tags blocks of information with a 64-byte header so that it can track the contents. You prepare files for U-Boot using the mkimage command. Here is a brief summary of its usage:

$ mkimage
Usage: mkimage -l image
-l ==> list image header information
mkimage [-x] -A arch -O os -T type -C comp -a addr -e ep -n name -d data_file[:data_file...] image
-A ==> set architecture to 'arch'
-O ==> set operating system to 'os'
-T ==> set image type to 'type'
-C ==> set compression type 'comp'
-a ==> set load address to 'addr' (hex)
-e ==> set entry point to 'ep' (hex)
-n ==> set image name to 'name'
-d ==> use image data from 'datafile'
-x ==> set XIP (execute in place)
mkimage [-D dtc_options] -f fit-image.its fit-image
mkimage -V ==> print version information and exit

For example, to prepare a kernel image for an ARM processor, the command is:

$ mkimage -A arm -O linux -T kernel -C gzip -a 0x80008000 \
-e 0x80008000 -n 'Linux' -d zImage uImage

Loading images

Usually, you will load images from removable storage such as an SD card or a network. SD cards are handled in U-Boot by the mmc driver. A typical sequence to load an image into memory would be:

U-Boot# mmc rescan
U-Boot# fatload mmc 0:1 82000000 uimage
reading uimage
4605000 bytes read in 254 ms (17.3 MiB/s)
U-Boot# iminfo 82000000

## Checking Image at 82000000 ...
Legacy image found
Image Name: Linux-3.18.0
Created: 2014-12-23 21:08:07 UTC
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 4604936 Bytes = 4.4 MiB
Load Address: 80008000
Entry Point: 80008000
Verifying Checksum ... OK

The command mmc rescan re-initializes the mmc driver, perhaps to detect that an SD card has recently been inserted. Next, fatload is used to read a file from a FAT-formatted partition on the SD card. The format is:

fatload <interface> [<dev[:part]> [<addr> [<filename> [bytes [pos]]]]]

If <interface> is mmc, as in our case, <dev:part> is the device number of the mmc interface counting from zero, and the partition number counting from one. Hence <0:1> is the first partition on the first device. The memory location, 0x82000000, is chosen to be in an area of RAM that is not being used at this moment. If we intend to boot this kernel, we have to make sure that this area of RAM will not be overwritten when the kernel image is decompressed and located at the runtime location, 0x80008000.

To load image files over a network you use the Trivial File Transfer Protocol (TFTP). This requires you to install a TFTP daemon, tftpd, on your development system and start it running. You also have to configure any firewalls between your PC and the target board to allow the TFTP protocol on UDP port 69 to pass through. The default configuration of tftpd allows access only to the directory /var/lib/tftpboot. The next step is to copy the files you want to transfer to the target into that directory. Then, assuming that you are using a pair of static IP addresses, which removes the need for further network administration, the sequence of commands to load a set of kernel image files should look like this:

U-Boot# setenv ipaddr 192.168.159.42
U-Boot# setenv serverip 192.168.159.99
U-Boot# tftp 82000000 uImage
link up on port 0, speed 100, full duplex
Using cpsw device
TFTP from server 192.168.159.99; our IP address is 192.168.159.42
Filename 'uImage'.
Load address: 0x82000000
Loading:
#################################################################
#################################################################
#################################################################
######################################################
3 MiB/s
done
Bytes transferred = 4605000 (464448 hex)

Finally, let's look at how to program images into NAND flash memory and read them back, which is is handled by the nand command. This example loads a kernel image via TFTP and programs it into flash:

U-Boot# fatload mmc 0:1 82000000 uimage
reading uimage
4605000 bytes read in 254 ms (17.3 MiB/s)

U-Boot# nandecc hw
U-Boot# nand erase 280000 400000

NAND erase: device 0 offset 0x280000, size 0x400000
Erasing at 0x660000 -- 100% complete.
OK
U-Boot# nand write 82000000 280000 400000

NAND write: device 0 offset 0x280000, size 0x400000
4194304 bytes written: OK

Now you can load the kernel from flash memory using nand read:

U-Boot# nand read 82000000 280000 400000

Booting Linux

The bootm command starts a kernel image running. The syntax is:

bootm [address of kernel] [address of ramdisk] [address of dtb].

The address of the kernel image is necessary, but the address of ramdisk and dtb can be omitted if the kernel configuration does not need them. If there is a dtb but no ramdisk, the second address can be replaced with a dash (-). That would look like this:

U-Boot# bootm 82000000 - 83000000

Automating the boot with U-Boot scripts

Plainly, typing a long series of commands to boot your board each time it is turned on is not acceptable. To automate the process, U-Boot stores a sequence of commands in environment variables. If the special variable named bootcmd contains a script, it is run at power-up after a delay of bootdelay seconds. If you are watching this on the serial console, you will see the delay counting down to zero. You can press any key during this period to terminate the countdown and enter into an interactive session with U-Boot.

The way that you create scripts is simple, though not easy to read. You simply append commands separated by semicolons, which must be preceded by a backslash escape character. So, for example, to load a kernel image from an offset in flash memory and boot it, you might use the following command:

setenv bootcmd nand read 82000000 400000 200000\;bootm 82000000

Porting U-Boot to a new board

Let's assume that your hardware department has created a new board called "Nova" that is based on the BeagleBone Black and that you need to port U-Boot to it. You will need to understand the layout of the U-Boot code and how the board configuration mechanism works. In the 2014.10 release, U-Boot adopted the same configuration mechanism as the Linux kernel, Kconfig. Over the next few releases, the existing configuration settings will be moved from the current location in the header files in include/configs into Kconfig files. As of the 2014.10 release, each board had a Kconfig file which contains minimal information derived from the old boards.cfg file.

The main directories you will be dealing with are:

  • arch: Contains code specific to each supported architecture in directories arm, mips, powerpc, and so on. Within each architecture, there is a subdirectory for each member of the family, for example, in arch/arm/cpu, there are directories for the architecture variants, including amt926ejs, armv7, and armv8.
  • board: Contains code specific to a board. Where there are several boards from the same vendor, they can be collected together into a subdirectory, hence the support for the am335x evm board, on which the BeagelBone is based, is in board/ti/am335x.
  • common: Contains core functions including the command shells and the commands that can be called from them, each in a file named cmd_[command name].c.
  • doc: Contains several README files describing various aspects of U-Boot. If you are wondering how to proceed with your U-Boot port, this is a good place to start.
  • include: In addition to many shared header files, this contains the very important subdirectory include/configs where you will find the majority of the board configuration settings. As the move to Kconfig progresses, the information will be moved out into Kconfig files but, at the time of writing, that process has only just begun.

Kconfig and U-Boot

The way that Kconfig extracts configuration information from Kconfig files and stores the total system configuration in a file named .config is described in some detail in up to three binaries: a normal u-boot.bin, a Secondary Program Loader (SPL), and a Tertiary Program Loader (TPL), each with possibly different configuration options. Consequently, lines in .config and default configuration files can be prefixed with the codes shown in the following table to indicate which target they apply to:

Each board has a default configuration stored in configs/[board name}_defconfig. For your Nova board, you will have to create a file named nova_defonfig. for example, and add these lines to it:

CONFIG_SPL=y
CONFIG_SYS_EXTRA_OPTIONS="SERIAL1,CONS_INDEX=1,EMMC_BOOT"
+S:CONFIG_ARM=y
+S:CONFIG_TARGET_NOVA=y

On the first line, CONFIG_SPL=y causes the SPL binary, MLO, to be generated, CONFIG_ARM=y causes the contents of arch/arm/Kconfig to be included on line three. On line four, CONFIG_TARGET_NOVA=y selects your board. Note that lines three and four are prefixed by +S: so that they apply to both the SPL and normal binaries.

You should also add a menu option to the ARM architecture Kconfig that allows people to select Nova as a target:

CONFIG_SPL=y
config TARGET_NOVA
bool "Support Nova!"

Board-specific files

Each board has a subdirectory named board/[board name] or board/[vendor]/[board name] which should contain:

  • Kconfig: Contains configuration options for the board
  • MAINTAINERS: Contains a record of whether the board is currently maintained and, if so, by whom
  • Makefile: Used to build the board-specific code
  • README: Contains any useful information about this port of U-Boot, for example, which hardware variants are covered

In addition, there may be source files for board specific functions.

Your Nova board is based on a BeagleBone which, in turn, is based on a TI AM335x EVM, so, you can start by taking a copy of the am335x board files:

$ mkdir board/nova
$ cp -a board/ti/am335x board/nova

Next, change the Kconfig file to reflect the Nova board:

if TARGET_NOVA

config SYS_CPU
default "armv7"

config SYS_BOARD
default "nova"

config SYS_SOC
default "am33xx"

config SYS_CONFIG_NAME
default "nova"
endif

Setting SYS_CPU to armv7 causes the code in arch/arm/cpu/armv7 to be compiled and linked. Setting SYS_SOC to am33xx causes the code in arch/arm/cpu/armv7/am33xx to be included, setting SYS_BOARD to nova brings in board/nova and setting SYS_CONFIG_NAME to nova means that the header file include/configs/nova.h is used for further configuration options.

There is one other file in board/nova that you need to change, the linker script placed at board/nova/u-boot.lds, which has a hard-coded reference to board/ti/am335x/built-in.o. Change this to use the copy local to nova:

diff --git a/board/nova/u-boot.lds b/board/nova/u-boot.lds
index 78f294a..6689b3d 100644
--- a/board/nova/u-boot.lds
+++ b/board/nova/u-boot.lds
@@ -36,7 +36,7 @@ SECTIONS
*(.__image_copy_start)
*(.vectors)
CPUDIR/start.o (.text*)
- board/ti/am335x/built-in.o (.text*)
+ board/nova/built-in.o (.text*)
*(.text*)
}

Configuration header files

Each board has a header file in include/configs which contains the majority of the configuration. The file is named by the SYS_CONFIG_NAME identifier in the board's Kconfig. The format of this file is described in detail in the README file at the top level of the U-Boot source tree.

For the purposes of your Nova board, simply copy am335x_evm.h to nova.h to nova.h and make a small number of changes:

diff --git a/include/configs/nova.h b/include/configs/nova.h
index a3d8a25..8ea1410 100644
--- a/include/configs/nova.h
+++ b/include/configs/nova.h
@@ -1,5 +1,5 @@
/*
- * am335x_evm.h
+ * nova.h, based on am335x_evm.h
*
* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
*
@@ -13,8 +13,8 @@
* GNU General Public License for more details.
*/
-#ifndef __CONFIG_AM335X_EVM_H
-#define __CONFIG_AM335X_EVM_H
+#ifndef __CONFIG_NOVA
+#define __CONFIG_NOVA
#include <configs/ti_am335x_common.h>
@@ -39,7 +39,7 @@
#define V_SCLK (V_OSCK)
/* Custom script for NOR */
-#define CONFIG_SYS_LDSCRIPT "board/ti/am335x/u-boot.lds"
+#define CONFIG_SYS_LDSCRIPT "board/nova/u-boot.lds"
/* Always 128 KiB env size */
#define CONFIG_ENV_SIZE (128 << 10)
@@ -50,6 +50,9 @@
#define CONFIG_PARTITION_UUIDS
#define CONFIG_CMD_PART
+#undef CONFIG_SYS_PROMPT
+#define CONFIG_SYS_PROMPT "nova!> "
+
#ifdef CONFIG_NAND
#define NANDARGS \
"mtdids=" MTDIDS_DEFAULT "\0" \

Building and testing

To build for the Nova board, select the configuration you have just created:

$ make CROSS_COMPILE=arm-cortex_a8-linux-gnueabi- nova_defconfig
$ make CROSS_COMPILE=arm-cortex_a8-linux-gnueabi-

Copy MLO and u-boot.img to the FAT partition of the micro-SD card you created earlier and boot the board.

Falcon mode

We are used to the idea that booting a modern embedded processor involves the CPU boot ROM loading an SPL which loads u-boot.bin which then loads a Linux kernel. You may be wondering if there is a way to reduce the number of steps, thereby simplifying and speeding up the boot process. The answer is U-Boot "Falcon mode", named after the Peregrine falcon which is claimed to be the fastest of all birds.

The idea is simple: have the SPL load a kernel image directly, missing out u-boot.bin. There is no user interaction and there are no scripts. It just loads a kernel from a known location in flash or eMMC into memory, passes it a pre-prepared parameter block and starts it running. The details of configuring Falcon mode are beyond this book. If you would like more information, take a look at doc/README.falcon.

主站蜘蛛池模板: 改则县| 济宁市| 墨玉县| 奉化市| 南丰县| 原平市| 无极县| 寿阳县| 湘西| 巩留县| 民县| 镇巴县| 肥乡县| 平湖市| 明溪县| 万源市| 根河市| 苍南县| 天柱县| 香河县| 天台县| 广德县| 涡阳县| 呼伦贝尔市| 咸丰县| 西乡县| 平远县| 鱼台县| 若尔盖县| 布拖县| 高淳县| 襄汾县| 纳雍县| 葫芦岛市| 呼图壁县| 蕉岭县| 绍兴县| 宣武区| 富宁县| 乌兰浩特市| 望谟县|