Listing 7-3. Source Definition of .resetvec
/* Copyright MontaVista Software Incorporated, 2000 */
#include
.section .resetvec, "ax"
#if defined(CONFIG_440)
b _start_440
#else
#if defined(CONFIG_BOOT_PCI) && defined(CONFIG_MIP405)
b _start_pci
#else
b _start
#endif
#endif
This assembly language file is very easy to understand, even if you have no assembly language programming experience. Depending on the particular configuration (as specified by the CONFIG_* macros), an unconditional branch instruction (b in PowerPC assembler syntax) is generated to the appropriate start location in the main body of code. This branch location is a 4-byte PowerPC instruction, and as we saw in the snippet from the linker command script in Listing 7-2, this simple branch instruction is placed in the absolute Flash address of 0xFFFF_FFFC in the output image. As mentioned earlier, the PPC 405GP processor fetches its first instruction from this hard-coded address. This is how the first sequence of code is defined and provided by the developer for this particular architecture and processor combination.
The other primary reason for bootloader image complexity is the lack of execution context. When the sequence of instructions from Listing 7-3 starts executing (recall that these are the first machine instructions after power-on), the resources available to the running program are nearly zero. Default values designed into the hardware ensure that fetches from Flash memory work properly and that the system clock has some default values, but little else can be assumed. [57] The details differ, depending upon architecture, processor, and details of the hardware design.
The reset state of each processor is usually well defined by the manufacturer, but the reset state of a board is defined by the hardware designers.
Indeed, most processors have no DRAM available at startup for temporary storage of variables or, worse, for a stack that is required to use C program calling conventions. If you were forced to write a "Hello World" program with no DRAM and, therefore, no stack, it would be quite different from the traditional "Hello World" example.
This limitation places significant challenges on the initial body of code designed to initialize the hardware. As a result, one of the first tasks the bootloader performs on startup is to configure enough of the hardware to enable at least some minimal amount of RAM. Some processors designed for embedded use have small amounts of on-chip static RAM available. This is the case with the PPC 405GP we've been discussing. When RAM is available, a stack can be allocated using part of that RAM, and a proper context can be constructed to run higher-level languages such as C. This allows the rest of the processor and platform initialization to be written in something other than assembly language.
7.3. A Universal Bootloader: Das U-Boot
Many open-source and commercial bootloaders are available, and many more one-of-a-kind home-grown designs are in widespread use today. Most of these have some level of commonality of features. For example, all of them have some capability to load and execute other programs, particularly an operating system. Most interact with the user through a serial port. Support for various networking subsystems (such as Ethernet) is less common but a very powerful feature.
Many bootloaders are specific to a particular architecture. The capability of a bootloader to support a wide variety of architectures and processors can be an important feature to larger development organizations. It is not uncommon for a single development organization to have multiple processors spanning more than one architecture. Investing in a single bootloader across multiple platforms ultimately results in lower development costs.
In this section, we study an existing bootloader that has become very popular in the embedded Linux community. The official name for this bootloader is Das U-Boot. It is maintained by Wolfgang Denk and hosted on SourceForge at http://u-boot.sourceforge.net/. U-Boot has support for multiple architectures and has a large following of embedded developers and hardware manufacturers who have adopted it for use in their projects and have contributed to its development.
7.3.1. System Configuration: U-Boot
For a bootloader to be useful across many processors and architectures, some method of configuring the bootloader is necessary. As with the Linux kernel itself, configuration of a bootloader is done at compile time. This method significantly reduces the complexity of the bootloader, which, in itself, is an important characteristic.
In the case of U-Boot, board-specific configuration is driven by a single header file specific to the target platform, and a few soft links in the source tree that select the correct subdirectories based on target board, architecture, and CPU. When configuring U-Boot for one of its supported platforms, issue this command:
$ make _config
Here, platform is one of the many platforms supported by U-Boot. These platform-configuration targets are listed in the top level U-Boot makefile. For example, to configure for the Spectrum Digital OSK, which contains a TI OMAP 5912 processor, issue this command:
$ make omap5912osk_config
This configures the U-Boot source tree with the appropriate soft links to select ARM as the target architecture, the ARM926 core, and the 5912 OSK as the target platform.
The next step in configuring U-Boot for this platform is to edit the configuration file specific to this board. This file is found in the U-Boot ../include/configs subdirectory and is called omap5912osk.h. The README file that comes with the U-Boot distribution describes the details of configuration and is the best source for this information.
Configuration of U-Boot is done using configuration variables defined in a board-specific header file. Configuration variables have two forms. Configuration options are selected using macros in the form of CONFIG_XXXX. Configuration settings are selected using macros in the form of CFG_XXXX. In general, configuration options (CONFIG_XXX) are user configurable and enable specific U-Boot operational features. Configuration settings (CFG_XXX) are usually hardware specific and require detailed knowledge of the underlying processor and/or hardware platform. Board-specific U-Boot configuration is driven by a header file dedicated to that specific platform that contains configuration options and settings appropriate for the underlying platform. The U-Boot source tree includes a directory where these board-specific configuration header files reside. They can be found in .../include/configs from the top-level U-Boot source directory.
Numerous features and modes of operation can be selected by adding definitions to the board-configuration file. Listing 7-4 contains a partial configuration header file for a fictitious board based on the PPC 405GP processor.
Listing 7-4. Partial U-Boot Board-Configuration Header File
#define CONFIG_405GP /* Processor definition */
#define CONFIG_4XX /* Sub-arch specification, 4xx family */
#define CONFIG_SYS_CLK_FREQ 33333333 /* PLL Frequency */
#define CONFIG_BAUDRATE 9600
#define CONFIG_PCI /* Enable support for PCI */
...
#define CONFIG_COMMANDS (CONFIG_CMD_DFL | CFG_CMD_DHCP)
Читать дальше