u-boot analysis __uboot boot kernel

content

1. Overall structure

2. The concept of partition

 3. Read the kernel

4 uImage format

5. The bootm command starts the kernel

5.1 Setting startup parameters

 5.1.1 setup_start_tag

 5.1.2 setup_memory_tag

 5.1.3 setup_commandline_tag

 5.1.4 setup_end_tag

5.2 Start the kernel

6. Review summary


1. Overall structure

uboot relies on two functions when starting the kernel,

s = getenv("bootcmd") gets the environment variables and then runs the command, where s is here

The meaning of this command is to read the kernel from the kernel partition above the nandflash to the ox30007FC0 address of the SDRAM, and then start from this address.

2. The concept of partition

On our PC, there will be a partition table in front of each hard disk, but in embedded Linux, there is no partition table in Flash, so the boot env kernel and file system partitions in our flash can only be written in the source code Dead, so we don't care about the names of these partitions in falsh, but the addresses of these partitions, so let's see where they are written dead.

 The mtd partition is defined here. This partition is located on the nandflash. The first 256K starting from 0 is the bootloader, the next 128K stores the environment variable parameters, the next 2m is the kernel, and the rest is the file system. For these partitions, the name is not important, what is important is their starting address and size, which are hard-coded in the code.

Let's take a look with mtd

 We can see the starting address and length of the kernel partition, then the read kernel command can be replaced with the following

 3. Read the kernel

 Earlier we saw that the bootm command corresponds to do_bootm in the source code, so there should be a convention here. Our nand command should correspond to do_nand in the source code, so we go to the source code to find the do_nand function,

 Here you can read.jffs2, jffs2 is a file format, but it has nothing to do with the file format. The reason why read.jffs2 is used is because when this command is used, the following partition length 0x00200000 does not need page alignment, you can write it casually, If other suffixes are used, this length requires block alignment or page alignment, and eventually the function nand_read_opts will be called. The internal details of this function will not be seen first.

4 uImage format

The kernel saved in falsh is uImage, this uImage format is header + real kernel, the header structure is as follows

ih_load represents the load address, which is where the kernel should be placed in the SDRAM when the kernel is running.

ih_ep represents the entry address, that is, you can directly jump to this address when running the kernel.

We said before that nand read.jffs2 0x3007FC0 kernel, when reading the kernel from nandflash, you can put it anywhere, not necessarily 0x3007FC0, you can put it at this address, as long as you don't destroy these things at high addresses.

 Why you can put it casually is because uImage has a header, and the header contains the load address and entry address. When we use bootm, we put uImage at an address xxxx, then bootm xxxx, and then bootm will read the header first. Department, know his load address and entry address, if it is found that the current kernel is not located at his load address, that is, xxxx and the load address are not equal, then move the kernel to the load address, and then jump to the entry address to execute , let's see if this is the case in the code.

 This function is to move our kernel data to the load load address. If our data is just in ih_load, then we don't need to move it. That's why we read it from nand and put it in 0x3007FC0, and it's not really casual put an address.

For our development board, the load address of the kernel is 0x3000800, and then we find that 0x3000800-0x3007FC0=64 bytes, because the header of our uImage is exactly 64 bytes, then our real kernel is located at 0x3000800, This eliminates the need to move and speeds up startup.

 Now bootm reads the kernel header information and puts the kernel data data into the load address. The next step is to start the kernel, which is done in the do_boot_linux function.

5. The bootm command starts the kernel

It is said that the kernel has been placed in the load address before, and then it can be directly transferred to the entry address for execution, but there are still some things to do before that. Similar to our X86, when our PC starts, our BIOS will To detect the memory, detect the flash, the BIOS will detect how much memory there is in the computer, and then tell the kernel, there are similar things in our Linux, our uboot needs to tell the kernel some boot parameters, that is, set the boot parameters, and then Transfer to the entry address to start the kernel, let's take a look at the do_boot_linux function next.

5.1 Setting startup parameters

After uboot starts the kernel, it must jump to the kernel, and then uboot does not exist. The easiest way to exchange data between uboot and the kernel is to save the data at a certain address in a certain format. This address is 0x30000100, this format is called TAG, the code to set TAG is here

Let's look at these four

 5.1.1 setup_start_tag

 tag is a structure, he has a head and a union, where the head contains size and tag.

Let's look at the setup_start_tag function, params = (struct tag*) bd->bi_boot_params, bi_boot_params, we can see the code search again

bi_boot_params is 0x30000100, then these parameters are placed here at 0x30000100, and then the size is stored first,

As you can see from the above code, size saves tag_size(tag_core), and tag_size is a macro,

Then size is the length of the header plus the length of tag_core. 

 

Then save is ATAG_CORE,

Then the three values ​​of flags, pagesize, and rootdev in the union are stored, and a total of five variables are stored.

After executing setup_start_tag, the following content is obtained, where size is 5, but the unit is 4 bytes, that is, 5*4=20 bytes,

 5.1.2 setup_memory_tag

 The same head is also size,

Then the tag,

 Then size and start, indicating memory,

 The size and start here are already set in the initialization code at the initial startup.

 After executing setup_memory_tag,

 5.1.3 setup_commandline_tag

setup_commandline_tag enters another additional parameter commandline, which is derived from environment variables.

 This environment variable means that root is located in the third (starting from 0) flash partition with the file system, init indicates that the first application is linuxc, and console indicates that the kernel print information is printed from serial port 0.

Then take a look at the setup_commandline_tag function

After executing setup_commandline_tag, the following content is obtained

 5.1.4 setup_end_tag

This is relatively simple, size and tag are both zero,

5.2 Start the kernel

Let's take a look at the startup kernel function, theKernel is assigned here, and the entry address is directly given to it.

 Then just start it

We can see that this function has three parameters, the third of which is the startup parameter stored at 0x30000100, and the second parameter is the machine id, which we assign in board_init

 Why pass this parameter to the kernel, because the kernel may support many single boards, but whether the kernel can support the single board we are currently using, we need to compare according to the machine ID, uboot is the first to run after power-on A program is responsible for determining the machine ID of the board, and then telling the kernel, and then when the kernel starts, the kernel will compare the machine ID to determine whether the board can be supported.

6. Review summary

The ultimate purpose of our uboot is to start the kernel, and then it is divided into the following steps.

Guess you like

Origin blog.csdn.net/u013171226/article/details/123186059