U-Boot's zero source code file, startup phase (TPL, SPL), FALCON, device tree

  Recently, the focus of work has shifted from bare-metal development to embedded Linux system development. In the previous blog post Linux 8. Complete Embedded Linux Environment, (Cross) Compilation Toolchain, CPU Architecture, Embedded System Construction Tools Introduced in detail the embedded Linux environment, the next step is to focus on learning about U-Boot.

source code

  The source code involved in this article is put on my personal Github: https://github.com/ZCShou/BOARD-STM32F769I-EVAL. This warehouse contains all the source codes of the complete embedded Linux environment to be built. Subsequent blog posts will be based on the source codes in this warehouse to learn!
insert image description here

development environment

  The basic development environment I use here is still Ubuntu 22.04.1 LTS + Arm GNU Toolchain 11.3.Rel1 explained many times in previous blog posts, and the corresponding J-link is still J-Link_Linux_V764e_x86_64.deb. The issues that need attention in this environment are as follows:
insert image description here

  1. Since Ubuntu 22.04 LTS comes standard with OpenSSL 3.x by default, and the old version of U-Boot uses OpenSSL 1.x, so when compiling the old version of U-Boot in this environment (relevant processing has been added since commit e927e21c), there will be a bunch of warnings , therefore, the follow-up use of u-boot-v2022.10 is the main version:
    insert image description here
  2. Arm GNU Toolchain 10.2-2022.02 has a BUG, ​​which causes an error when compiling U-Boot. Do not use this version!
    insert image description here
  3. Newer versions (after Arm GNU Toolchain 10.3) of the Arm GNU Toolchain require Python 3.8 support for GDB on Linux. However, Ubuntu 22.04 defaults to Python 3.10. Run it directly and arm-none-eabi-gdbreport the error as follows:
    insert image description here
    The solution is to install Python3.8 manually directly. Legacy Arm GNU Toolchain 10.3 -2021.10 does not require Python support
    sudo add-apt-repository ppa:deadsnakes/ppa -y
    sudo apt install python3.8
    

operating environment

  The embedded environment I use is the STM32F769I-EVAL board. The STM32F769NI MCU used by the STM32F769I-EVAL board uses the ARM Cortex-M7 core, and the instruction set architecture is ARMv7m. In addition, it should be noted that the RX of the serial port on this board is disconnected by default and needs to be connected with a short-circuit cap.
insert image description here

origin

  U-Boot originated from a boot loader for 8xx PowerPC called 8xxROM written by Magnus Damm. In October 1999, Wolfgang Denk made it open source on SourceForge.net. Since the website does not allow the project name to start with a number, it was renamed PPCBoot (the abbreviation of PowerPC Boot). The first public release of PPCBoot-0.4.1 was on July 19, 2000.

  1. Wolfgang Denk is the founder of DENX Software Engineering GmbH (DENX for short), and PPCBoot actually belongs to DENX
  2. Because linus ➔ linux so Denk ➔ DENX?
  3. DENX is a company dedicated to the use of free software

  As PPCBoot has been extended to the ARM architecture, DENX believes that the name PPCBoot is no longer appropriate, so when PPCBoot−2.0.0 was released in October 2002, it decided to rename the project (SourceForge.net new project) to Das U- Boot (short for Universal Boot Loader), where Das is a German definite article, is officially said to create a pun (a nod to the classic 1981 German submarine movie Das Boot).
insert image description here

Except for some official documents called Das U-Boot, almost no one in the outside world uses this name, and everyone directly calls it U-Boot.

  PPCBoot−2.0.0 corresponds to the first version of Das U-Boot U−Boot-0.1.0. And then extended to the x86 processor architecture. Then, other architectural features were added in the following months: MIPS32 in March 2003, MIPS64 in April, Nios II in October, ColdFire in December, and MicroBlaze in April 2004.

The submarine

  Now, U-Boot has become the preferred boot loader for embedded devices to package instructions to boot the device operating system kernel, and it is open source based on the GPL protocol. Project address: https://source.denx.de/ u-boot. It is available for many computer architectures including 68k, ARM, Blackfin, MicroBlaze, MIPS, Nios, SuperH, PPC, RISC-V and x86.

  1. Code repository: https://source.denx.de/u-boot
  2. Github repository: https://github.com/u-boot/u-boot

  The code structure and development mode of U-Boot follow the way of Linux Kernel as much as possible, but there are differences in the actual process. For example, similar to the Linux Kernel, there will be a "merge window" of usually 21 days immediately after each version is released, and then, after rc1 is released, it will start to focus on fixing bugs, however, since U-Boot is relatively The Linux kernel is much simpler, so it does not have the Monorepo (Monotree) mode of linux.

The code style is also the same as the Linux Kernel

  Unlike Linux, starting with the October 2008 release, the names of U-Boot releases changed from numerical version numbers with no deeper meaning to timestamp-based numbers, usually in the format where, is the year (eg 2022); U-Boot vYYYY.MM.xis YYYYthe MMmonth (eg 08); .xprobably none, if present, this part is a bugfix release (eg 1) or a release candidate (eg rc1).

  1. As of August 2010, there is no longer a CHANGELOG file in the actual U-Boot source tree, however, it can be dynamically created from the Git log using make CHANGELOGthe command
  2. This article mainly uses the two versions of U-Boot v2021.10 and U-Boot v2022.10

architecture

  U-Boot is actually a bare-metal program with complex functions. The main function of this program is to pass kernel parameters and jump to the kernel . Of course, in addition to jumping to the kernel, U-Boot itself also implements some other functions (U-Boot commands) to facilitate various operations.
insert image description here
  U-Boot supports a variety of CPUs with multiple architectures. Among the many supported architectures, ARM is the most troublesome one. ./arch/armBecause ARM sells IP and has a very high market share, there are a lot of ARM core manufacturers. These manufacturers will have their own changes, which further leads to a lot of mach-xxxfolders the ARM architecture folder ( ) of U-Boot .

  In addition, in U-Boot, boardthis word can be seen everywhere, and most of the codes in U-Boot are related to the board. The internal resources of the CPU (SoC, MCU) are limited. In most cases, the internal resources cannot run the operating system kernel. Therefore, U-Boot must use a lot of resources outside the CPU, and these resources are on the board.

document

  Around July 2021, U-Boot migrated the documentation to the new version, the chapters of the entire documentation system were reorganized, and the interface was refreshed. The new online document address is https://u-boot.readthedocs.io/en/latest/, the old version of the document is no longer accessible!
insert image description here
  The new documentation is built using the Sphinx documentation system. Sphinx is also based on Python and uses the reStructuredText language format. The file extension is usually .rst. Now, the file system is also on par with Linux.

  1. Personally, I think that U-Boot's documentation lacks an introduction to the overall architecture and lacks intuitive examples such as illustrations
  2. U-Boot's articles are still being improved gradually. There are many introduction documents in the code warehouse, but they cannot be found in the online document system.

  The documentation of U-Boot is located in docthe directory . In the root directory of the source code (not supported in docthe directory ), use the command make htmldocsbuild script to automatically create outputa folder , and then generate HTML format documents in this directory ( index.htmlyou can directly open it with a browser).
insert image description here
  Since I upgraded Sphinx to version 5.0.1 in my Ubuntu 22.04 LTS, its configuration is somewhat incompatible with the old version! U-Boot has not yet been adapted, resulting in the inability to generate documents in pdf, epub and other formats.

  1. Minimal dependency tools: sudo apt install python3-pip, sudo pip install -U Sphinx sphinx_rtd_theme, sudo apt install imagemagick, if you build documents in other formats (such as PDF), you also need to install dependencies texlive*such as
  2. According to the construction rules, the following make commands must be run normally one after make xxx_defconfigthe other , otherwise an error will be reported and .configthe file cannot be found

source code

  The source code can be obtained git clone https://source.denx.de/u-boot/u-boot.gitdirectly . It can also be obtained through U-Boot's mirror repository on Github git clone https://github.com/u-boot/u-boot. We usually use a specific version of Tags: git checkout v2020.10.
insert image description here
  The structure of U-Boot's source code is basically in line with Linux (part of the code comes from the Linux kernel), but it is not as complicated as the Linux code. Today, the U-Boot source code changes a lot every day, and the latest version has more than 14,000 files and nearly 3 million lines of code. The hierarchical structure of each file in the source code can refer to the following figure:
insert image description here

directory file

The following is an introduction to each directory in the U-Boot source code:

  • api : An architecture- or device-independent API for use by external applications. For example, standardized input and output, display, network API, storage API, etc., provide support for CMD
  • arch : Architecture-specific source code files. Realize the abstraction of CPUs with different architectures, instruction sets, and device trees, and use link binding to keep the relative position of symbol entries unchanged, so that the function of copying the kernel image to memory and then booting can be realized
    • arc : general architecture file
    • arm : ARM architecture
      • lib : implements the initialization of the C runtime environment (initialization of stack/heap pointers, etc.)
      • dts : implements the specific abstraction stripping of the underlying architecture of the device tree
      • cpu : CPUs with different ARM instruction sets are processed separately
      • mach-xxx : Since the same core is the same, the peripherals of each chip are different, so the implementation of each individuality is separated here. This is mainly based on the chip of the ARM system. Since ARM sells IP, each chip manufacturer is in the On the basis of the core, different chips are extended, so the differences need to be stripped to achieve
    • m68k : m68k architecture
    • microblaze : microblaze architecture
    • mips : MIPS architecture
    • nds32 : NDS32 architecture
    • nios2 : Altera NIOS2 architecture
    • powerpc : PowerPC architecture
    • riscv : RISC-V architecture
    • sandbox : A hardware-independent "sandbox" mode. U-Boot can run on a Linux host using a "sandbox" board. This allows for feature development on the native platform that is not board or architecture specific. Sandbox is also used to run some tests of U-Boot.
    • sh : SH architecture
    • x86 : x86 architecture
    • xtensa : Xtensa architecture
  • board : The development board relies on files to realize the differences in the downstream of the industry chain and equipment manufacturers. For product design, it is necessary to put the implementations that require strict initialization in the boot stage here, such as the initialization of IO ports. Most of the products The IO port must explicitly set its initial state
  • boot : images and booting files
  • cmd : U-Boot command related interface
  • common : some common files that have nothing to do with the architecture. It is the main body of U-Boot. If the system stays in the U-Boot stage, the CPU is always executing an endless loop:run_main_loop()
  • configs : The default configuration file of the development board. The format is:开发板名_defconfig
  • disk : The code for disk drive partition processing. Implements lightweight disk management
  • doc : This directory contains U-Boot documents, and the Sphinx document system is used now. Sphinx is also Python-based and uses the reStructuredText language format, usually with a file extension of .rst.
      The Sphinx documentation system uses the make command to generate published documentation, which can generate html, pdf and other formats. For example, execute the make html command under the source code directory /documentation/, a _build directory will be generated, which contains the generated documentation.
  • drivers : device driver, here implements the necessary device drivers in the boot phase, such as network port, display, etc.
  • dts : implements the device tree. Makefile for building the internal U-Boot fdt
  • env : environment support
  • examples : sample code
  • fs : file system code (cramfs, ext2, jffs2, etc.)
  • include : header file
  • lib : Library routines common to all architectures. Such as CRC algorithm, encryption algorithm, compression algorithm, string operation, etc.
  • Licenses : various license files
  • net : Network code, implementing the network protocol layer
  • post : power-on self-test
  • scripts : Various build scripts and Makefiles. Files related to the graphics drawing of the make menuconfig configuration interface, we as users do not need to care about the contents of this folder
  • test : various unit test files
  • tools : Contains a series of source codes for tools used to build U-Boot

source file filtering

  Because there are many U-Boot source code files, we don't need most of them after a specific platform (development board). For the convenience of learning, eliminating useless files and keeping only the files we need will be of great help to our learning. If you can sort out the required source code normally, you can basically grasp the file structure of U-Boot. The following is the filtering configuration when viewing the code in VSCode:

{
    
    
    "files.exclude": {
    
    
        "**/.git": true,
        "**/.svn": true,
        "**/.hg": true,
        "**/CVS": true,
        "**/.DS_Store": true,
        "u-boot-v2021.10":true,
        // arch
        "**/mips": true,
        "**/powerpc": true,
        "**/riscv": true,
        "**/ti": true,
        "**/x86": true,
        "**/sandbox": true,
        "**/arch/{arc,m68k,microblaze,mips,nios2,powerpc,riscv,sandbox,sh,x86,xtensa,um,sparc,s390,parisc,openrisc,nds32,ia64,hexagon,h8300,csky,arm64,alpha}": true,
        // cpu
        "**/arch/arm/cpu/{arm11,arm720t,arm920t,arm926ejs,arm946es,arm1136,arm1176,armv7,armv8}": true,
        // machine
        "**/arch/arm/mach-[^s]*": true,
        "**/arch/arm/mach-s[^t]*": true,
        "**/arch/arm/mach-st[^m]*": true,
        "**/arch/arm/mach-stm32[$^m]*": true,
        // dts
        "**/dts/[^s|^M|^i|^a|^d|^.]*": true,
        "**/dts/d[^t]*": true,
        "**/dts/i[^n]*": true,
        "**/dts/in[^c]*": true,
        "**/dts/a[^r]*": true,
        "**/dts/ar[^m]*": true,
        "**/dts/arm[^v]*": true,
        "**/dts/s[^t]*": true,
        "**/dts/st[^m|^-]*": true,
        "**/dts/stm32[^f]*": true,
        "**/dts/stm32f[^7]*": true,
        "**/dts/stm32f7[^6|4|^-]*": true,
        "**/dts/stm32f769-[^e|d|p]*": true,
        // configs
        "**/configs/[^s]*": true,
        "**/configs/s[^t]*": true,
        "**/configs/st[^m]*": true,
        "**/configs/stm[^3]*": true,
        // "**/configs/stm3[^2]*": true,
        "**/configs/stm32[^f|^_]*": true,
        "**/configs/stm32f[^7]*": true,
        // "**/configs/stm32f7[^6|^4]*": true,
        // "**/configs/stm32f769-[^e]*": true,
        // board
        "**/board/[^s]*": true,
        "**/board/s[^t]*": true,
        "**/board/ste": true,
        "**/board/sto*": true,
        "**/board/st/st[^m]*": true,
        "**/board/st/stm32[^f]*": true,
        // "**/board/st/stm32f[^7]*": true,
        // "**/board/st/stm32f7[^6|^4]*": true,
    }
}

  Since many files of U-Boot are generated during compilation, how to filter valid files is a problem. I saw on the Internet that a netizen made a script that can extract the source code according to the compilation process: https://github.com/tonyho/Generate_Kernel_Uboot_Project_forIDE, but after I tried it, I found that it was not very accurate, but it was basically usable.

configuration

  The configuration of the U-Boot source code uses the Kconfig configuration system of the Linux system. For the detailed configuration process description, see the detailed explanation of the independent blog post U-Boot 4th Construction Process (Kconfig Configuration + Kbuild Compilation) . All development boards supported by U-Boot will have a default configuration file in ./configsthe directory , and the configuration items in it are introduced in the independent blog post U-Boot six most complete configuration items (CONFIG_BOARD, CONFIG_SYS) .
  
  U-Boot's support for many architectures has reached the development board level. For some commonly used development boards, U-Boot directly supports them, which means that U-Boot can run directly on these development boards. Note that the development board may need to be modified to use all resources.

Construct

  The construction process of the U-Boot source code uses the Kbuild build system of the Linux system. For the detailed description of Kbuild, see the independent blog post U-Boot 4th Construction Process (Kconfig Configuration + Kbuild Compilation) . For the detailed construction process, see one of the independent blog posts U-Boot: Zero-Basic Compilation U-Boot Process Detailed Explanation, Image Mirroring Introduction and Instructions, and DTB File Instructions . The brief construction process is as follows:

  1. Get the source code:git clone https://github.com/ZCShou/BOARD-STM32F769I-EVAL.git
  2. Build configuration:ARCH=arm CROSS_COMPILE=arm-none-eabi- make O=build_stm32 stm32f769-eval_defconfig
  3. cropping:ARCH=arm CROSS_COMPILE=arm-none-eabi- make O=build_stm32 menuconfig
  4. Compile:ARCH=arm CROSS_COMPILE=arm-none-eabi- make O=build_stm32 -j$(nproc)
  5. Burn the generated Image to the development board for verification

Debug parameters

  In one of the blog posts U-Boot, the detailed explanation of the U-Boot compilation process, the introduction and usage instructions of Image mirroring, and the usage instructions of DTB files, I have detailed introductions, so I won’t go into details here. The following highlights several configurations (or parameters) that are useful in construction.

  1. O=<dir>: By specifying this parameter during the build process, all (including) files generated during the build process can be .configplaced in <dir>this directory, thereby avoiding pollution to the source code files. It should be noted that this parameter must be added to each command.
  2. V=1: Output detailed information during the build process. After opening, the output content is very large.
  3. NO_LTO=1: Disable LTO (Link-time optimization). U-Boot supports link time optimization, which reduces the size of the final U-Boot binary. Currently, ARM boards can enable this feature CONFIG LTO=yby . Other architectures are not supported.

    LTO is enabled by default for the sandbox.

chip

  When building image files, XIP is also an important concept we encountered. XIP is the abbreviation of Execute In Place, which means that the generated Image can be run directly on Nor FLASH without copying to memory to run.
insert image description here
  In addition, when compiling the Linux Kernel, there is also an XIP configuration item. If we choose the XIP function, there will be an Image file such as xipImage. Of course, most chips do not have enough internal FLASH to store Linux Kernel image files, so it is rarely used.

start-up phase

  In order to adapt to the limited resources (FLASH and RAM size) of various CPUs, the startup phase of U-Boot itself is divided into several different phases: TPLVPLSPLU-Boot. In source code design, SPL is actually a framework, TPLand VPLboth are part of the SPL framework.
insert image description here

TPL

  TPL (Tertiary Program Loader, the third program loader) is used for early initialization, and as small as possible, it is responsible for loading VPL or SPL. According to the official document, TPL itself belongs to the simplification of SPL, and the code is in the SPL code, which is distinguished CONFIG_TPL_BUILDby , and now only the mpc85xx of powerpc has this requirement and will implement it.

VPL

  VPL is an optional secure boot verification process. From the point of view of bare metal functions, VPL is an independent process, which is responsible for verifying the two SPLs of A/B and selecting the correct one to execute; in terms of code implementation, VPL is also a part of SPL. Currently, the details of the VPL are still being designed and implemented, and now it will jump directly to the SPL.
insert image description here

SPL

  SPL (Secondary Program Loader, the second program loader), the second program here actually refers to U-Boot, that is, SPL is the first program, which is executed first, and then he loads U-Boot. Then U-Boot itself is already a bootloader, why does there exist such a thing as SPL?

  The main reason is that for some MCUs, its internal SRAM may be relatively small, too small to load a complete U-Boot image, then SPL is needed, which is mainly responsible for initializing the external RAM operating environment and loading the real U-Boot is mirrored to external RAM for execution.

Whether to use SPL depends on your own chip, if the resources are sufficient, you can use it or not!

  The object files for the SPL are built separately and placed in splthe directory . It should be noted here that when constructing SPL, fdtgreptools filter out some attributes in the device tree, thereby generating a relatively small device tree file spl/u-boot-spl.dtb.

Falcon Mode

  Falcon Mode refers to the mode of directly starting the operating system kernel by SPL, which is mainly used to reduce the time of Bootloader stage. U-Boot itself provides many functions. For some chips (application environments), many functions of U-Boot will not be used basically.
insert image description here

U-Boot

  The U-Boot stage contains complete U-Boot functionality, eg, boot logic, various U-Boot commands.

device tree

  U-Boot uses the same device tree as Linux Kernel, but the boot loader environment is not the same as Linux Kernel's requirements, so U-Boot adds some necessary things. The way to add is not to change the original Linux Kernel device tree, but to introduce a U-Boot special file *-u-boot.dtsinamed .
insert image description here
  In addition, the added by U- *-u-boot.dtsiBoot will not be *.dtsreferenced by any other files, because these *-u-boot.dtsifiles are directly introduced in the Makefile. Only in this way can U-Boot completely avoid modifying the device tree files from the Linux Kernel.
insert image description here
  When compiling a *.dtsfile , U-Boot will automatically *.dtssearch for and include one (only one) in*-u-boot.dtsi the directory where the to-be-compiled is located, and the priority of inclusion is from high to low as follows:*.dts

<orig_filename>-u-boot.dtsi    # <orig_filename> 就是要编译的 .dts 对应的名字
<CONFIG_SYS_SOC>-u-boot.dtsi
<CONFIG_SYS_CPU>-u-boot.dtsi
<CONFIG_SYS_VENDOR>-u-boot.dtsi
u-boot.dtsi

  In actual use, sometimes we have to specify a private for our own development board xxx.dtsi, and this is xxx.dtsiusually not public, so it is*.dts not advisable to directly edit include . #include xxx.dtsiAt this time, U-Boot provides CONFIG_DEVICE_TREE_INCLUDESthis configuration item to specify our own private xxx.dtsi.

  The device tree source files are finally compiled into a binary DTB file, and the original DTB file is located arch/arm/dts/xxx.dtbbelow , which the build system will copy to ./dts/dt.dtb, further renamed to ./u-boot.dtb. u-boot supports two ways to compile dtb into u-boot image:

  • The bin files of dtb and u-boot are separated

    • CONFIG_OF_SEPARATEMacros need to be turned on to enable.
    • In this way, the compiling of u-boot and dtb are separated, the bin file of u-boot is generated first, and then the dtb file is generated separately.
    • dtb will be automatically appended to the end of the u-boot bin file eventually. Therefore, the address of dtb can be obtained through the end address symbol of u-boot, that is, the _end symbol.
  • dtb is integrated into the bin file of u-boot

    • CONFIG_OF_EMBEDMacros need to be turned on to enable.
    • In this way, dtb will also be compiled during the process of compiling u-boot.
    • Finally, dtb is included in the bin file of u-boot. dtb will be located in the .dtb.init.rodata section of u-boot, and its symbol can be obtained through the __dtb_dt_begin symbol in the code.

    This method is not officially recommended, it is only recommended for debugging

  • In addition, the address of dtb can also be specified through fdtcontroladdrenvironment variables. The purpose of dynamically specifying dtb can be achieved by directly loading dtb to a certain location in the memory and fdtcontroladdrsetting .

reference

  1. U-Boot Official Documentation

Guess you like

Origin blog.csdn.net/ZCShouCSDN/article/details/128700328