After finishing the bare metal run recently, I started running the system, but thinking that there is a Bootloader between the bare metal run and the system, and I haven't done any in-depth research on it before, I decided to spend one to two weeks to work on U-BOOT.
I referred to the works of two great experts, fzb and Zhao Chunjiang, and also studied the two classic versions, 2010.06 version and 2011.06 version. I also compared the U-BOOT written by TQ (the board I bought was from Tianqian). I learned a lot and discovered many things. I will record my own experience below so that I can refer to it later.
U-BOOT's two-stage boot process: (2010.06 Classic version)
The first stage: start.S is located in archarmcpuarm920t. This assembly code is generally called the first stage initialization code. Its main functions are to initialize the operating environment; initialize the memory; re-place the UBOOT code into the memory; jump into the memory to execute the second stage initialization code
1. Turn off the door dog and shield all interrupts
2. Set the frequency division ratio
3. bl cpu_init_crit() turns off MMU and initializes memory
bl lowlevel_init() configures memory, modifies memory refresh rate parameters, etc.
4. relocate determines whether the current code is in NORFLASH or RAM
copy_loop copies the FLASH code to RAM
5. stack_setup stack settings
clear_bss Clear the data between _bss_start and _bss_end to 0
6. ldr pc, start_armboot jumps to the second stage
//================================================ =====================
Stage 2: board.c is located in arch/arm/lib/board.c. This code is the second stage initialization code of U-BOOT. Its main function is to initialize two important data structures, set the memory allocation of
SDRAM, initialize various peripherals needed, and finally jump into the main_loop() function.
The second stage start_armboot is divided into two parts: board_init_f and board_init_r
The board_init_f part executed first:
1. Assign an address to the gd data structure and clear it
2. Execute each initialization function in the init_fnc_ptr function pointer array, as follows
board_early_init_f , timer_init , env_init init_baudrate serial_init
console_init_f display_banner dram_init
3. A. Allocate the upper 64KB of SDRAM as TLB for U-BOOT
B. Allocate the next SDRAM unit to the U-BOOT code segment, data segment, and BSS segment
(By the way, the BSS segment is used to store uninitialized global variables and static variables)
C. Then open up malloc space to store bd, gd, and 3 words of exception heap space
4. Assign the address value of relorate to the corresponding variable of the gd structure (2011.06 version, used to return start.S)
The board_init_r part executed later:
1. Initialize the gd and bd data structures
2. Initialization of various peripherals:
Initialize NORFLASH, NANDFLASH, initialize ONENAND FLASH
Initialize environment variables Initialize PCI Set IP address Initialize various peripherals: IIC, LCD, keyboard, USB Initialize console Create IRQ interrupt stack Initialize Ethernet
Initialize the jump table (defines the b
asic common function library in U-Boot). . This does not count peripherals
3. An infinite loop executes the main_loop() function
/************************************
Comparison of two versions of U-BOOT startup:
************************************/
In fact, they are similar in general, but compared with the classic version (2010.06 version), the new version has become disgusting.
The main differences are:
1. The stack setup in step 5 of the first phase of the original version was placed before the relorate step 4 (this is nothing)
2. The original second stage board_init_f is placed before the first stage 4 step relorate, which means that after executing
After stack_setup is set up, it enters the second stage of partial initialization, and then returns to the first stage by assigning the address value of relorate to the corresponding variable of the gd structure (2011.06 version, used to return to start.S)... I feel that the new version is very messy and disorganized (open source is updated every year, which is annoying, haha)
//================================================ =
The following lists the paths of the functions that may be used in the two stages for easy reference later: (based on the 2011.06 version)
Phase 1:
The lowlevel_init function is defined in the lowlevel_init.s file in the board/samsung/smdk2410 directory.
Phase 2:
gd is a pointer to the gd_t structure stored in the ARM register r8, which is defined in the global_data.h file in the /include/asm directory
The data prototype of the bd structure is the bd_t data structure, which represents the "board information" structure, which is defined in the u-boot.h file in the /include/asm directory.
Each initialization function in the init_fnc_ptr function pointer array:
The board_early_init_f function is in the smdk2410.c file in the board/samsung/smdk2410 directory. The timer_init function is in the timer.c file in the arch/arm/cpu/arm920t/s3c24x0 directory.
The env_init function is in the env_flash.c file in the common directory
The init_baudrate function is in the board.c file in the arch/arm/lib directory
The serial_init function is in the serial_s3c24x0.c file in the drivers/serial directory, and CONFIG_S3C24X0_SERIAL is defined in include/configs/smdk2410.h
The console_init_f function is in the console.c file in the common directory
The display_banner function is in the board.c file in the arch/arm/lib directory
The dram_init function is in the smdk2410.c file in the board/samsung/smdk2410 directory
Initialization of various peripherals:
The flash_init function is in the cfi_flash.c file in the drivers/mtd directory (because CONFIG_FLASH_CFI_DRIVER is defined in include/configs/smdk2410.h)
The nand_init function is defined in the nand.c file in the divers/mtd/nand directory
The env_relocate function is defined in the env_common.c file in the common directory.
stdio_init() is defined in the stdio.c file in the common directory.
jumptable_init() is defined in the exports.c file in the common directory.
console_init_r() is defined in the console.c file in the common directory
interrupt_init () enable_interrupts () are defined in the interrupts.c file in the arch/arm/lib directory
The eth_initialize() function is defined in lines 209 to 298 of the eth.c file in the net directory.
main_loop() is defined in the main.c file in the common directory
//================================================ ===================
Analysis and understanding of the differences between Tianjian and self-ported U-BOOT
First, let's list the biggest differences between what the R&D staff at Tianqian wrote and what we ported ourselves (a small port):
After comparing, I found that the biggest difference is in the common/main.c file, that is, the two-stage startup process is basically the same
Differences: (rows are embedded in the daily version)
abortboot() function (called in main_loop())
Ln239: printf (“Press Space key to Download Mode!”);
Ln303: When detecting whether a key is pressed, a LOGO display program is added: embedsky_tq_logo();
main_loop() function
Ln 381: LCD initialization procedure
Ln481: Branch selection download OR load mode: if ( BootFrmNORFLASH() )
run_command ("menu",0);
else
{
Printf("Booting Linux");
run_command ("boot_zImage",0);
}
Let’s analyze it:
The previous points are about LCD and LOGO display, so I won’t say much (because I didn’t get the LCD transplant when I transplanted it myself)
Let's talk about Ln481 in the main_loop() function: branch selection download OR load mode
First of all, run_command is the execution command function. As the name suggests, it is also defined in /common/main.c
Let's talk about the most important "menu" and "boot_zImage"
1. If booting from NORFLASH, it is in download mode, then execute the menu() function, which is defined in /common/cmd_menu.c
Open the cmd_menu.c file and you will find that it contains some serial port option lists. The download list we found when we turned on the 2440 power supply was printed out from the main_menu_usage() function, and the selected items were executed through the console through menu_shell(). The execution process of each option is clearly listed, just like running a bare metal machine and following the fzb serial port console to make it yourself.
2. Else boot from NANDFLASH, it is loading mode, configure and start the LINUX system.
In the lib_arm/boot_zImage.c file: the boot_zImage() function
The content of the function execution is roughly as follows:
1. copy kernel image
2. setup linux parameters
3. get machine type
4. GO -> call-linux
Some insights after comparison:
Although I have also transplanted U-BOOT and built my own board support package, which can realize basic functions such as serial console, NAND OR NOR FLASH, DM9000 network, JFFS2 file system, etc., it still has many shortcomings compared with Tianyan, which can download and load modes.
So, transplanting by yourself is just to feel the method. After understanding it, you can do further transplantation based on Tianqian. I don't think it's necessary to do it from beginning to end by yourself. It's enough to understand the method and be familiar with the framework.
//================================================ ===================
A simple example of the migration process:
Because a lot of porting is based on smdk2410, first of all, you need to have a certain understanding of the difference between 2410 and 2440. Secondly, you have written and modified peripheral drivers on a bare metal machine, so that you will be more comfortable with porting. You won't feel empty and learn nothing by just following everything.
Just let U-BOOT support NANDFLASH reading and writing
1. First, add the macro definitions required by your peripherals to the general macro definition header file.
The total macro definition path is /include/configs/XX.h/ (the last .h file is usually named after the board)
Add macro definitions, such as: #define CONFIG_NAND_BASE 0
... etc
How do you know what macro definitions to add? Generally speaking, you can define the ones that are used in the peripheral initialization function and the U-BOOT second-stage startup function. . .
2. Change the corresponding initialization function: such as board_nand_init function and s3c2440_hwcontrol function
Because the initialization function in U-BOOT is basically based on 2410, and the NAND configuration parameters of 2440 are different from it, some parts need to be changed
3. Add the initialization function to the second stage board_init_r. Generally speaking, the basic peripherals have been added. See if you define the macro to compile this function.
Transplantation rules summary:
In fact, after transplanting several times, you will find that the transplantation and modification of UBOOT still follows certain rules, that is, first open the relevant macro definition support in the configuration header file, and add the initialization function that needs to be supported in the board-level initialization code (usually the second stage initialization process).
If the board version corresponding to the initialization function is incompatible or does not exist, you have to write it yourself.
//================================================ ===================
Finally, let's talk about the compilation of U-BOOT
Speaking of compilation, I suggest you read "How to compile uboot from the perspective of butchering an ox", which is a very good explanation.
When it comes to the compilation process, it is recommended to look at
http://hi.baidu.com/serial_story/blog/item/871fc30311670783d53f7c74.html
《Detailed analysis of the specific execution process of the final compilation and linking of make uboot》
Finally, let's talk about the problem of compilation failure. If it is an internal program error, you can find out through the prompt information.
If there are more than a hundred ERRORs, or some arm-linux-ld problems, it should be an incompatible version of the compiler. It is recommended to try a newer or older version.
Well, now we can move on to the next step of system porting and driver writing. Recently, the fat guy from 503 said that he wanted to do a project related to projectors and cameras. It happened that I was more interested in image processing and I thought his idea was very good.
Maybe I'll do it. GO
I feel dizzy. I need to rest for a few days.