- GNU-Linux Rapid Embedded Programming
- Rodolfo Giometti
- 5131字
- 2021-07-09 18:40:29
A quick tour into the bootloader
As stated at the beginning of this chapter, using the serial console, we can get access to the bootloader.
Actually, all the developer kits presented in this book have two bootloaders: a pre-bootloader or Secondary Program Loader (SPL), named MLO
for the BeagleBone Black, boot.bin
for SAMA5D3 Xplained, and SPL
for the Wandboard, which initializes the hardware components, such as the RAM and some mass storage devices, and bootloader named U-Boot for all boards, which is the real bootloader that initializes almost all the peripherals and has support for, among other things, booting over network and a scriptable shell through which basic commands can be given. Now the one million dollar question is: why should a developer be able to manage the bootloader too?
Well the answers are more than one; however, the most important ones are:
- By passing a well-formed command line to the kernel, we can change some functionalities in the running filesystem.
- From the bootloader, we can easily manage a factory restore method (it is usually made with a hidden button in a tiny hole on the system's box. By keeping that button pressed while powering up the system, the user can cause the whole system to reset to its factory defaults).
- Through the bootloader, we can decide which device to use to perform a boot. For instance, we can force a boot from a microSD or from a USB key.
So now let's see how we can get the U-Boot's prompt using one kit since they're running the same U-Boot version (the following messages are from SAMA5D3 Xplained).
Just after the power up, we will see some interesting messages on the serial console:
RomBOOT U-Boot SPL 2016.03-dirty (Apr 15 2016 - 19:51:18) Trying to boot from MMC reading u-boot.img U-Boot 2016.03-dirty (Apr 15 2016 - 19:51:18 +0200) CPU: SAMA5D36 Crystal frequency: 12 MHz CPU clock : 528 MHz Master clock : 132 MHz DRAM: 256 MiB NAND: 256 MiB MMC: mci: 0 reading uboot.env ** Unable to read "uboot.env" from mmc0:1 ** Using default environment In: serial Out: serial Err: serial Net: gmac0 Error: gmac0 address not set. , macb0 Error: macb0 address not set. Hit any key to stop autoboot: 1
At this time, we have less than 1 second to strike the Enter key to stop the countdown and get the U-Boot prompt shown as follows:
=>
Well, now we can get a list of the available commands using the help
command:
=> help ? - alias for 'help' base - print or set address offset bdinfo - print Board Info structure boot - boot default, i.e., run 'bootcmd' bootd - boot default, i.e., run 'bootcmd' ... usb - USB sub-system usbboot - boot from USB device version - print monitor, compiler and linker version
As you can see, the list is quite long; however, due to spacing reasons, we cannot report or explain all commands, so we'll take a look at the most important ones.
Tip
For further information regarding the U-Boot bootloader, you may take a look at the user manual at http://www.denx.de/wiki/DULG/Manual .
The help
command can also be used to get more information about a command:
=> help help help - print command description/usage Usage: help - print brief description of all commands help command ... - print detailed usage of 'command'
Tip
Note that most of the commands will display their helping message when executed without any arguments. Of course, this behavior is not respected by those commands that execute with no arguments.
The environment
Before starting to take a look at the commands, we should first see one of the most important features of U-Boot: the environment. We can store whatever we need to accomplish a safe system boot in the environment. We can store variables, commands, and even complete scripts in it!
To check the environment content, we can use the print
command:
=> print arch=arm baudrate=115200 board=sama5d3_xplained board_name=sama5d3_xplained bootargs=console=ttyS0,115200 root=/dev/mmcblk0p2 ro rootwait bootcmd=if test ! -n ${dtb_name}; then setenv dtb_name at91-${board_na me}.dtb; fi; fatload mmc 0:1 0x21000000 /dtbs/${dtb_name}; fatload mmc 0:1 0x22000000 zImage; bootz 0x22000000 - 0x21000000 bootdelay=1 cpu=armv7 ethact=gmac0 soc=at91 vendor=atmel Environment size: 412/16380 bytes
If we need to inspect a specific variable, we can use the print
command:
=> print baudrate baudrate=115200
We can also inspect a complete script using the print command again:
=> print bootcmd bootcmd=if test ! -n ${dtb_name}; then setenv dtb_name at91-${board_na me}.dtb; fi; fatload mmc 0:1 0x21000000 /dtbs/${dtb_name}; fatload mmc 0:1 0x22000000 zImage; bootz 0x22000000 - 0x21000000
Tip
The bootcmd
command is the default boot command that is executed each time the system starts.
The command output is quite cryptic due the fact that the newline (\n
) characters are missing (although U-Boot doesn't need them to correctly interpret a script); however, to make the output more readable, the preceding output has been rewritten here with the necessary newline characters:
if test ! -n ${dtb_name}; then setenv dtb_name at91-${board_name}.dtb; fi; fatload mmc 0:1 0x21000000 /dtbs/${dtb_name}; fatload mmc 0:1 0x22000000 zImage; bootz 0x22000000 - 0x21000000
In this case, we cannot properly talk about man pages, but if we use the help
command, we can take a kind of them.
Tip
Note that the print
command is just a short form of the real command printenv
.
To write/modify an environment variable, we can use the setenv
command:
=> setenv myvar 12345 => print myvar myvar=12345
We can read the variable content by prefixing its name with the $
character:
=> echo "myvar is set to: $myvar" myvar is set to: 12345
In a similar manner, to write a script, we can use this:
=> setenv myscript 'while sleep 1 ; do echo "1 second is passed away.. ." ; done'
Tip
Note that we used the two '
characters to delimitate the script commands! This is to prevent U-Boot from doing some variable replacement before storing the script (it's something similar to what we do when we use the Bash shell's variable substitution).
Again, over here, we did not add the newlines; however, this time, the script is quite simple and readable. In fact, with the newline characters, the output should appear as follows:
while sleep 1 ; do echo "1 second is passed away..." ; done
In the end, we can run a by using the run
command, as follows:
=> run myscript 1 second is passed away... 1 second is passed away... 1 second is passed away... ...
Note
We can stop the script by hitting Ctr l + C . The environment is reset each time the system starts, but it can be altered by modifying the environment file in the microSD (refer to the next section).
In case we made some errors, don't panic! We can edit the variable with this command:
=> env edit myscript edit: while sleep 1 ; do echo "1 second is passed away..." ; done
Now we can do all the required modifications to the script in an easy manner.
Managing the storage devices
The main goal of a bootloader is to load the kernel into the memory and then execute it; to do that, we must be able to get access to all the storage devices of the board where the kernel can be located. Our boards have several storage devices; however, in this book, we'll see only two of them: MMC (or eMMC) and NAND flash.
MMC
To show MMC (Multi Media Card) management in U-Boot, we are going to use the BeagleBone Black since it has both an eMMC and a microSD port on board. As already stated in the first chapter, we're able to choose our booting device simply using the user button, so it's very important to discover how we can manage these devices, so let's power on our BeagleBone Black and then stop the bootloader by pressing the spacebar within two seconds, as shown here:
U-Boot SPL 2016.03-dirty (Apr 15 2016 - 13:44:25) Trying to boot from MMC bad magic U-Boot 2016.03-dirty (Apr 15 2016 - 13:44:25 +0200) Watchdog enabled I2C: ready DRAM: 512 MiB Reset Source: Global warm SW reset has occurred. Reset Source: Power-on reset has occurred. MMC: OMAP SD/MMC: 0, OMAP SD/MMC: 1 Using default environment Net: <ethaddr> not set. Validating first E-fuse MAC cpsw, usb_ether Press SPACE to abort autoboot in 2 seconds =>
Now, as already done earlier with SAMA5D3 Xplained, we can use the help
command to see which are the MMC-related commands. We discover that the MMC support is implemented with the mmcinfo
and mmc
commands. The former can be used to get some useful information about the microSD/MMC present on the selected MMC slot, while the latter is used to effectively manage the microSD.
Let's look at some examples.
We know that our BeagleBone Black has an onboard eMMC on MMC slot 1
, so to get some information about that device, we should first select the MMC slot to be examined using the following command:
=> mmc dev 1 switch to partitions #0, OK mmc1(part 0) is current device
Then, we can ask for the MMC device information using the mmcinfo
command:
=> mmcinfo Device: OMAP SD/MMC Manufacturer ID: 70 OEM: 100 Name: MMC04 Tran Speed: 52000000 Rd Block Len: 512 MMC version 4.5 High Capacity: Yes Capacity: 3.6 GiB Bus Width: 4-bit Erase Group Size: 512 KiB HC WP Group Size: 4 MiB User Capacity: 3.6 GiB Boot Capacity: 2 MiB ENH RPMB Capacity: 128 KiB ENH
In the same manner, we can examine the alternate booting microSD we built in Chapter 1, Installing the Developing System, and that we used to boot the system. Here is the output that appears on my system:
=> mmc dev 0 switch to partitions #0, OK mmc0 is current device => mmcinfo Device: OMAP SD/MMC Manufacturer ID: 41 OEM: 3432 Name: SD4GB Tran Speed: 50000000 Rd Block Len: 512 SD version 3.0 High Capacity: Yes Capacity: 3.7 GiB Bus Width: 4-bit Erase Group Size: 512 Bytes
Now we can examine the microSD partition table by using the following command:
=> mmc part Partition Map for MMC device 0 -- Partition Type: DOS Part Start Sector Num Sectors UUID Type 1 2048 7772160 5697a348-01 83 Boot
We get only one partition where our Debian filesystem is located.
Let's examine the /
(root) directory using another command that's useful in listing the content of a EXT4 filesystem, which is the command etx4ls
, as shown here:
=> ext4ls mmc 0:1 <DIR> 4096 . <DIR> 4096 .. <DIR> 16384 lost+found <DIR> 4096 opt <DIR> 4096 boot <DIR> 4096 lib <DIR> 4096 sys <DIR> 4096 home <DIR> 4096 mnt <DIR> 4096 dev ... <DIR> 4096 sbin <DIR> 4096 proc <DIR> 4096 tmp
We found the root directory of a Debian OS, and we can use the following command to read the contents of the /boot
directory:
=> ext4ls mmc 0:1 /boot <DIR> 4096 . <DIR> 4096 .. 726 uEnv.txt 7408440 vmlinuz-4.4.7-bone9 <DIR> 4096 dtbs <DIR> 4096 uboot 9089599 initrd.img-4.4.7-bone9
Now, as an example, in order to import the uEnv.txt
file content, we can use the load
command:
=> load mmc 0:1 $loadaddr /boot/uEnv.txt 726 bytes read in 28 ms (24.4 KiB/s)
Tip
Note that the value for the loadaddr
variable is usually defined in the default environment (that is, the default built in the U-Boot image at the compilation stage) or using the uEnv.txt
configuration file.
The command loads a file from the microSD into the RAM, and then we can parse it and store the data into the environment using the env
command:
=> env import -t $loadaddr $filesize
Tip
In contrast with the earlier loadaddr
variable, the filesize
variable is dynamically set after each file manipulation command's execution, for instance, the just used load
command.
To save a variable/command in the environment (in a way that the new value is reloaded at the next boot), we can use U-Boot itself, but the procedure is quite complex and, in my humble opinion, the quickest and simplest way to do it is by just putting the microSD on a host PC and then changing the file on it!
In any case, we can take a look at the read data using the md command, as follows:
=> md $loadaddr 82000000: 64616f6c 72646461 3878303d 30303032 loadaddr=0x82000 82000010: 0a303030 61746466 3d726464 38387830 000.fdtaddr=0x88 82000020: 30303030 720a3030 64646164 78303d72 000000.rdaddr=0x 82000030: 38303838 30303030 6e690a0a 64727469 88080000..initrd 82000040: 6769685f 78303d68 66666666 66666666 _high=0xffffffff 82000050: 7464660a 6769685f 78303d68 66666666 .fdt_high=0xffff 82000060: 66666666 636d6d0a 746f6f72 65642f3d ffff.mmcroot=/de 82000070: 6d6d2f76 6b6c6263 0a317030 616f6c0a v/mmcblk0p1..loa 82000080: 6d697864 3d656761 64616f6c 636d6d20 dximage=load mmc 82000090: 313a3020 6c7b2420 6164616f 7d726464 0:1 ${loadaddr} 820000a0: 6f622f20 762f746f 6e696c6d 242d7a75 /boot/vmlinuz-$ 820000b0: 616e757b 725f656d 6f6c0a7d 66786461 {uname_r}.loadxf 820000c0: 6c3d7464 2064616f 20636d6d 20313a30 dt=load mmc 0:1 820000d0: 64667b24 64646174 2f207d72 746f6f62 ${fdtaddr} /boot 820000e0: 6274642f 7b242f73 6d616e75 7d725f65 /dtbs/${uname_r} 820000f0: 667b242f 69667464 0a7d656c 64616f6c /${fdtfile}.load
In this manner, we do a memory dump at the address specified by the loadaddr
variable, where we just loaded the /boot/uEnv.txt
file content.
Managing the flash
The flash memories are very useful when we don't need relatively small storage devices and we want to keep the cost of a board very low.
In the past, they represented the only (and valid) solution for reliable mass memory devices for embedded systems due to the fact that they can work in very hostile environments (temperatures under 0° C or above 80° C and dusty air) and they have no moving parts that dramatically increase the life cycle of the system.
Nowadays, they are almost replaced by eMMC memories, but they are still present on really compact and low-power systems. In this book, the only boards where we can find them are SAMA5D3 Xplained, so let's switch to this board again.
Tip
In reality, eMMC or MMC (which is not a soldered version of an eMMC) is flash memory, but it takes a specific name because there is a flash controller inside the chip that actually manages the internal flash memory. So, using these devices, we can unload our embedded kits' CPUs of the duty to manage the flash.
The flash memory in our board is a NAND flash, which is a technology that uses floating gate transistors (just like the NOR flash) but is connected in a way that resembles a NAND gate.
Tip
For further information on these devices, a good starting point can be found at https://en.wikipedia.org/wiki/Flash_memory#NAND_flash .
To get some information on mounted chips, we can use the nand info
command, as follows:
=> nand info Device 0: nand0, sector size 128 KiB Page size 2048 b OOB size 64 b Erase size 131072 b subpagesize 2048 b options 0x 200 bbt options 0x 8000
In this case, we have just one NAND device, so we don't need to use the nand device
command to select one, as we did earlier regarding the MMC devices on our BeagleBone Black.
The check for the bad blocks (that is, those parts of the chip that are broken), we can use the following command:
=> nand bad Device 0 bad blocks: 00c80000 00ca0000
These blocks will never be used to store our data.
Now the last three useful commands to manage the flash content are nand erase
, nand read
, and nand write
. The first command is split into two subcommands: nand erase.part
, which erases an entire MTD partition, and nand erase.chip
, which erases the entire chip.
Tip
As you know for sure, a flash device needs the erase
command because before writing a block, we must erase it! Refer to https://en.wikipedia.org/wiki/Flash_memory#Limitations for an explanation of the problem.
Then, the nand.read
and nand.write
commands are used as they are expected, that is, to read or write a flash block. At the moment, we are not going to add examples for these actions since we still have no valid data to store in the flash; however, we're going to show how these commands can be used in the Managing a MTD device section in Chapter 5, Setting up an Embedded OS .
Also note that in the NAND flash, we can store the current environment in a similar manner as earlier with the MMC/eMMC using the saveenv
command; however, in order to work, this command must be correctly configured inside the U-Boot code by the developer.
Tip
These topics are not covered in this book due to space issues and because they are almost accomplished by the board manufacturer, so we can consider them already-fixed-up. However, you can take a look at the configuration that defines CONFIG_ENV_OFFSET
, CONFIG_ENV_SIZE
and friends in U-Boot's repository for further information.
GPIO management
The General Purpose Input Output (GPIO) signals are input output pins with no special purpose defined; when a developer needs one of them working as an input pin or as an output pin (or another function), they can easily reconfigure the CPU in order to accommodate their needs (GPIOs will be widely presented in Chapter 6, General Purposes Input Output signals - GPIO ).
Managing GPIO from early booting stages can be useful in selecting a specific mode of functioning: for instance, in a system that normally boots from the NAND flash, we can decide to completely erase it rewrite its contents from a file read by the MMC if a GPIO is set; otherwise, we do a normal boot.
The command to manage GPIO is gpio
, and to try usage of this command, we can use the BeagleBone Black board where we can use this command to control the user LEDs. As for the other GPIO lines of the BeagleBone Black, they are mapped as follows:
So we can easily deduce that in order to toggle LED USR0
, we can use the following commands:
=> gpio toggle 53 gpio: pin 53 (gpio 53) value is 1 => gpio toggle 53 gpio: pin 53 (gpio 53) value is 0
Of course, we can turn the LED on and off simply using the set
and clear
options, respectively, while the input
option can be used to read the input status of the related GPIO line.
Tip
You can take a look at what these LEDs are for at: http://beagleboard.org/getting-started .
Accessing an I2C device
Another useful device class to get access to in early booting stages is I2C devices; in fact, these devices are commonly used to expand the CPU's peripheral set and they can be used for a large variety of purposes that, under some circumstances, must be read or set up during the boot (GPIO will be widely presented in Chapter 9, Inter-Integrated Circuit - I2C ).
As for GPIO, I2C devices are completely managed by the i2c
command, and to test this command, we have to continue using the BeagleBone Black since it is the only one that has some onboard I2C devices. The list of this devices can be obtained by some simple steps; first of all, let's display a list of all available I2C buses:
=> i2c bus Bus 0: omap24_0 Bus 1: omap24_1 Bus 2: omap24_2
By taking a look at the board's schematics, we can discover that the bus where these devices are connected to is omap24_0
, so let's set it as the current bus using the following command:
=> i2c dev 0 Setting bus to 0
Now we can ask the system to probe all connected devices for us with the following command:
=> i2c probe Valid chip addresses: 24 34 50
Great! We found three devices; now we can try to read some data from them; in particular, we can try to read the onboard EEPROM content using the i2c md
command at address 50
(which is the hexadecimal EEPROM's address):
=> i2c md 0x50 0x0.2 0x20 0000: aa 55 33 ee 41 33 33 35 42 4e 4c 54 30 30 43 30 .U3.A335BNLT00C0 0010: 33 32 31 34 42 42 42 4b 30 37 31 36 ff ff ff ff 3214BBBK0716....
With the preceding command, we asked to dump data from the device at address 0x50
starting from address 0x0
(expressed as a word thanks to the .2
specifier) displaying 0x20
bytes as the output.
In this output, we can recognize the header (bytes 0xaa 0x55 0x33 0xee
) and then the board version.
Tip
More information on the BeagleBone Black's EEPROM contents can be taken from the BeagleBone Black's user manual.
Loading files from the network
Another useful U-Boot feature is the ability to load a file from a network connection. This feature used during the developing stages helps the developer avoid having to continuously plug and unplug the microSD card from the system; in fact, as we saw in the first chapter, the system needs the bootloaders and kernel images to start up and, in case of errors during the development of these components, we will need to replace them frequently till they are OK. Well, supposing that at least the networking function works in our U-Boot release, we can use it to load a new image in the system memory.
Let's suppose that our kernel image is not functioning as well as we need it to be; we can set up U-Boot in order to load the kernel image from the network and then boot it to do all the required tests.
The command used to do this action is tftp
. This command uses the Trivial File Transfer Protocol (TFTP) protocol to download a file from a remote server.
Tip
You may get more information on the TFTP protocol at: https://it.wikipedia.org/wiki/Trivial_File_Transfer_Protocol .
The remote server, of course, is our host PC where we have to install a proper package with the following command:
$ sudo aptitude install tftpd
Tip
It may happen that during the installation, we get the following message:
Note: xinetd currently is not fully supported by update-inetd. Please consult /usr/share/doc/xinetd/README.De bian and itox(8).
In this case, we have to add a file named tftp
into the /etc/xinetd.d
directory by hand. The file should hold the following code:
# default: yes
# description: The tftp server serves files using
# the Trivial File Transfer
# Protocol. The tftp protocol is often used to
# boot diskless workstations, download
# configuration files to network-aware
# printers, and to start the installation
# process for some operating systems.
service tftp
{
disable = no
socket_type = dgram
protocol = udp
wait = yes
user = root
server = /usr/sbin/in.tftpd
server_args = -s /srv/tftpboot
}
Then, we have to create the /srv/tftpboot
directory, as follows:
$ sudo mkdir /srv/tftpboot
Then, restart the xinetd
daemon with the usual command, as follows:
$ sudo /etc/init.d/xinetd restart [ ok ] Restarting xinetd (via systemctl): xinetd.se rvice.
When the installation is finished, we should have a new process listening on UDP
port 69
:
$ netstat -lnp | grep ':\<69\>' (Not all processes could be identified, non-owned process info will not be shown, you would have to be root to see it all.) udp 0 0 0.0.0.0:69 0.0.0.0:*
Also, the default tftpd
root directory should be /srv/tftpboot
, which is obviously empty:
$ ls -l /srv/tftpboot/ total 0
OK; let's copy our kernel image as we did in Debian 8 (jessie) for Wandboard section in Chapter 1 , Installing the Developing System :
$ sudo cp deploy/4.4.7-armv7-x6.zImage /srv/tftpboot/vmlinuz-4.4.7-arm v7-x6
Tip
Note that the sudo
usage in the preceding command may not be needed in every system. I used it just because my host PC didn't properly install the daemon, as reported in earlier tip section.
Now in our Wandboard, we have to set up the ipaddr
environment variable to be able to ping our host PC first. As an example, my host PC has the following network configuration:
$ ifconfig enp0s3 enp0s3 Link encap:Ethernet HWaddr 08:00:27:22:d2:ed inet addr:192.168.32.43 Bcast:192.168.32.255 Mask:255.255. 255.0 inet6 addr: fe80::a00:27ff:fe22:d2ed/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:986 errors:0 dropped:0 overruns:0 frame:0 TX packets:687 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:226853 (226.8 KB) TX bytes:100360 (100.3 KB)
Tip
Note that on your system, both the Ethernet card name and IP address settings may vary, so you have to change the settings in order to fit your LAN configuration.
Also, my DHCP server leaves the IP addresses from 192.168.32.10
to 192.168.32.40
available for my embedded boards, so we can do the following setting in Wandboard:
=> setenv ipaddr 192.168.32.25
Now, if everything works well, we should be able to ping my host PC:
=> ping 192.168.32.43 Using FEC device host 192.168.32.43 is alive
Great! At this point, we can try to load a file from the host PC, so we have to assign the TFTP server's IP address to the serverip
variable, as follows:
=> setenv serverip 192.168.32.43
Then, we can load our kernel image using the following command:
=> tftpboot ${loadaddr} vmlinuz-4.4.7-armv7-x6 Using FEC device TFTP from server 192.168.32.43; our IP address is 192.168.32.25 Filename 'vmlinuz-4.4.7-armv7-x6'. Load address: 0x12000000 Loading: ############################################################# ############################################################# ... ############################# 688.5 KiB/s done Bytes transferred = 5802912 (588ba0 hex)
Perfect, we did it! Now you can use the just download kernel image to continue your developing.
Tip
At the moment, this mode of operation is not explained here, but it will be explained in detail in the next chapter.
Before ending this chapter, let we address the fact that the Wandboard used only one Ethernet port, so it's quite obvious that whatever settings we do in U-Boot are referred to that device, but what happens if we have more that one device? For example, our SAMA5D3 Xplained has two Ethernet ports; how can we manage this setup if we wish to use the tftp
command described earlier?
To answer this question, we have to switch the developer kit and power up SAMA5D3 Xplained. After the boot, we have to stop U-Boot and then we have to display the environment:
=> print arch=arm baudrate=115200 board=sama5d3_xplained board_name=sama5d3_xplained bootargs=console=ttyS0,115200 root=/dev/mmcblk0p2 ro rootwait bootcmd=if test ! -n ${dtb_name}; then setenv dtb_name at91-${board_na me}.dtb; fi; fatload mmc 0:1 0x21000000 /dtbs/${dtb_name}; fatload mmc 0:1 0x22000000 zImage; bootz 0x22000000 - 0x21000000 bootdelay=1 cpu=armv7 ethact=gmac0 soc=at91 vendor=atmel Environment size: 412/16380 bytes
Looking at the defined variables, we notice that one is named ethact
; this is the variable that specifies the currently used Ethernet port. In the preceding output, we read that the system is set to gmac0
, which is the gigabit Ethernet port (the port is labeled ETH0
/GETH
on the board).
So, if we repeat the preceding setup, we should be able to ping our host PC, as did earlier:
=> setenv ipaddr 192.168.32.25 => ping 192.168.32.43 gmac0: PHY present at 7 gmac0: Starting autonegotiation... gmac0: Autonegotiation complete gmac0: link up, 100Mbps full-duplex (lpa: 0x45e1) host 192.168.32.43 is alive
Tip
If we get the following error, it's because the Ethernet port has no default MAC address:
*** ERROR: `ethaddr' not set ping failed; host 192.168.32.43 is not alive
In this case we, have to set a random one ourselves with the following command:
=> setenv ethaddr 3e:36:65:ba:6f:be
Then, we can repeat the ping
command.
Now we can repeat the ping
command through the other Ethernet port (the one labeled ETH1
on the board) by changing the ethact
variable, as follows:
=> setenv ethact macb0
Tip
The name we have to use is usually specified in the developer kit's documentation.
Now we can repeat the ping
command:
=> ping 192.168.32.43 macb0: PHY present at 0 macb0: Starting autonegotiation... macb0: Autonegotiation complete macb0: link up, 100Mbps full-duplex (lpa: 0x45e1) host 192.168.32.43 is alive
Tip
If we got an error regarding the missing definition of the ethaddr
variable, we should get the following one, which is related to the eth1addr
variable: *** ERROR: `eth1addr' not set
ping failed; host 192.168.32.43 is not alive
This is in case we have to act in the same manner as earlier.
The last note is about the fact that usually, U-Boot will automatically switch the active port in case the autonegotiation fails. If our system has ethact
set as gmac0
but the cable is plugged into the ETH1
port, we get the following output:
=> ping 192.168.32.25 gmac0: PHY present at 7 gmac0: Starting autonegotiation... gmac0: Autonegotiation timed out (status=0x7949) gmac0: link down (status: 0x7949) macb0: PHY present at 0 macb0: Starting autonegotiation... macb0: Autonegotiation complete macb0: link up, 100Mbps full-duplex (lpa: 0x45e1) host 192.168.32.43 is alive
Note
We may experience some troubles regarding the networking support with the U-Boot version we're using in this book with SAMA5D3 Xplained. This is because this U-Boot release is not well aligned with the official one from Atmel. If so, don't worry, we can still use the official U-Boot release at: http://www.at91.com/linux4sam/bin/view/Linux4SAM/Sama5d3XplainedMainPage#Build_U_Boot_from_sources . That will work for sure!
The kernel command line
Before closing our tour of the bootloader, we should take a look at the way U-Boot uses to pass a command line to the kernel. This data is very important because it can be used to configure the kernel and pass some instruction to the user's programs on the root filesystem.
These arguments are stored in the bootargs
variable and its setting depends on the board we are using. For example, if power on our Wandboard and, as done earlier, we stop its bootloader, as shown earlier, wecan see thatthis variable is not set at all:
=> print bootargs ## Error: "bootargs" not defined
This is because its content is set up by the booting scripts that are not executed if we stop the boot. On our system, by carefully reading the U-Boot environment, we can discover that sooner or later, the run mmcargs
command is called.
Note
This is because U-Boot automatically executes the script held in the bootcmd
variable.
This command is written as follows:
=> print mmcargs mmcargs=setenv bootargs console=${console} ${optargs} root=${mmcroot} rootfstype =${mmcrootfstype} ${cmdline}
This is where the kernel command line is built. As a useful exercise, you can now try to understand which are the values used for all the earlier variables; the only thing we wish to add is that we can add our custom settings using the optargs
variable.
For instance, if we wish to set the loglevel
kernel (that is the lower kernel message priority showed on the serial console, as shown in the Managing the kernel messages section), we can set optargs
to this:
=> setenv optargs 'loglevel=8'
And then we ask to continue the boot:
=> boot
Once the system has been restarted, we can verify the new setting by looking into the booting messages of the kernel; we should see a line as shown here:
Kernel command line: console=ttymxc0,115200 loglevel=8 root=/dev/mmcbl k0p1 ro rootfstype=ext4 rootwait
This can be checked by looking at the procfs
file, which holds a copy of the kernel command line, that is, the /proc/cmdline
file using the following command:
root@wb:~# cat /proc/cmdline console=ttymxc0,115200 loglevel=8 root=/dev/mmcblk0p1 ro rootfstype=ex t4 rootwait
Tip
More information regarding the kernel command line and its parameters can be found in the kernel tree in the Documentation/kernel-parameters.txt
file or online at: https://www.kernel.org/doc/Documentation/admin-guide/kernel-parameters.txt .