U-boot startup process-based on S3C2410-reproduced from Zhou Ming

Source: Internet
Author: User

 

Source: http://forum.linuxbj.com/node/2

 

U-boot is widely used in embedded system bootloader, the software home page is http://www.denx.de/wiki/U-Boot

 

After the code package is decompressed, the main source code is stored in the following directories.

Board directory-used to place the supported code of the Board, which is equivalent to a bootloader-level BSP. Code related to a specific Board includes frequency synthesis, gpio, board parameters, debugging serial port, energy management, and button processing. In this example, the board-level code

The common directory is used to store public code unrelated to the architecture. It mainly includes various command implementation codes and environment variable implementation codes, such as bootm commands.

CPU directory-used to store specific codes of the processor and SOC, which are stored in subdirectories named by CPU name. For example, the arm1136 processor or the specific code of the system on the S3C2410 chip in this example

Driver directory-stores the hardware driver code. Currently, no clear/unrelated code is available for splitting the architecture. Such as the S3C2410 RTC driver and popular dm9000 mb nic Driver

FS directory-stores the file system code, including fat, ext2, and cramfs.

Include directory -- stores the U-boot header file. A considerable part is the same as that in the Linux kernel.

Lib_xxx directory-contains Code related to the xxx architecture, such as floating point routine and actual boot code. For example, the kernel Boot Code of the ARM architecture

Net directory-stores network protocols unrelated to the architecture, such as TFTP and BOOTP.

Tools directory-the U-Boot Tool running on the local machine, such as the mkimage tool used to create a uimage

 

 

 

 

In this paper, the popular Samsung S3C2410, openmoko platform and u-boot-1.3.2 (2008.5 release) as an ExampleDescribes how to explore the U-boot Startup Process in the zix embedded development environment.

Although U-boot has been widely used, users still encounter difficulties in understanding its internal mechanism and porting U-boot due to its relative complexity. U-boot has some analysis documents, but most of them cannot be synchronized with the real code or the version is outdated, it is difficult to match the concept with the actual code-that is, the code running on the hardware board is not seen in the document, and cannot be closely tracked. The Code involved in this article is based on the mature u-boot-1.3.2 code running in the S3C2410 hardware, the version is newer, provides a wealth of features, and in forum.linuxbj.com can freely browse and download. This U-boot represents a high level in the industry. It can directly build a new version of embedded product design, which has high application value.

The General Startup Process of U-boot is as follows:
-> Reset
-> Set the CPU Mode
-> Disable the watchdog/interrupt function.
-> Set the processor clock/on-chip Bus
-> Initialize and debug the serial port
-> MMU, external bus, and SDRAM Initialization
-> Migrate ROM code/data to ram
-> Initialize the function call stack.
-> Initialize peripheral devices/parameters
-> After the startup is complete, enter the main_loop loop.

Embedded systems are indispensableBootloaderInitialize the hardware and boot the operating system.
Nowadays, dedicated embedded board running embedded Linux systems have become very popular. U-boot is a kind of bootloader that is very suitable for such systems.

U-boot provides the following functions:

  • Set and initialize the hardware parameters of the target board;
  • Transmit necessary information to the operating system;
  • Perform interactive underlying operations;
  • Intelligent loading of the operating system;
  • Boot and run firmware programs;
  • Supports large-capacity storage and USB Interfaces

 

With the zix development environment, you can observe the inside of U-boot in a more intuitive way and debug and analyze the code at the same time. It is a powerful tool for understanding and porting U-boot.

Use arm tool chain to compile U-boot source code to obtain the u-boot.bin file that can be burned.
In the zix development environment, the u-boot.bin can be loaded into the S3C2410 board to run, and GDB debugging can be used.

GDB can access hardware through the JTAG interface or through TCP/IP. After the debugging connection is established, you can use GDB to manipulate the U-boot startup process. Next, you can follow the code execution sequence to find out which operations are executed starting from the above.

After S3C2410 is reset, the PC Pointer Points to the 0x0 address. In the U-boot code, the 0x0 address is a vector table,
First Command jumpBranchTo reset the code start_code. Line 5 of the CPU/ARM920T/start. s assembly language file:

.globl _start  _start:  b start_code      ldr pc, _undefined_instruction     ldr pc, _software_interrupt     ldr pc, _prefetch_abort     ldr pc, _data_abort     ldr pc, _not_used     ldr pc, _irq     ldr pc, _fiq

After the reset command jumps to the 154th line, the basic initialization of the ARM920T processor is started.
First, modify the current program status register CPSR so that the processor enters the supervisor | 32-bit arm mode,
And disable arm9tdmi interrupt and quick interrupt. This is achieved by setting the corresponding CPSR mask:

start_code: 
/*
* set the cpu to SVC32 mode
*/
mrs r0,cpsr
bic r0,r0,#0x1f
orr r0,r0,#0xd3
msr cpsr,r0

Then, the unique wtcon register of S3C2410 is cleared, which is only used to disable the watchdog. The code is located at 234 rows:

    ldr r0, =pWTCON 
mov r1, #0x0
str r1, [r0]

Then, in the second row, set the intmsk register of the S3C2410 interrupt controller to full 1,
Intsubmsk is set to 0x7ff to prohibit all source interruptions. This is described in detail on page 1 of the S3C2410 manual:

    mov r1, #0xffffffff  
ldr r0, =INTMSK
str r1, [r0]
# if defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442) || /
defined(CONFIG_S3C2443)
ldr r1, =INTSUBMSK_val
ldr r0, =INTSUBMSK
str r1, [r0]
# endif

Next, access the ARM920T control register CP15 in the second row, and the Union bit is up to two [259].
After the two locations are 0b11, the processor clock is set to asynchronous mode, allowing the processor to access the bus asynchronously:

    mrc p15, 0, r1, c1, c0, 0 
orr r1, r1, #0xc0000000
mcr p15, 0, r1, c1, c0, 0

Now the ARM920T-related configuration is complete, and the S3C2410 clock merging parameters are set later.
By setting the upll, mpll, and clkdivn registers ),
Obtain the expected processor operating frequency, which is in the 308 rows:

    ldr r0, =UPLLCON  
ldr r1, =UPLLCON_val
str r1, [r0]

Row 3:

    ldr r1, =MPLLCON_val  
str r1, [r0, #-4] /* MPLLCON */

/* FCLK:HCLK:PCLK = 1:2:4 */
ldr r0, =CLKDIVN
mov r1, #CLKDIVN_val
str r1, [r0]

The uart0 of S3C2410 is initialized to print information through uart0 as soon as possible.
This code starts from line 1. For the involved register readers, refer to page 332 of the S3C2410 manual:

    /* enable uart */
ldr r0, =0x4c00000c /* clkcon */
ldr r1, =0x7fff0 /* all clocks on */
str r1, [r0]
/* gpio UART0 init */
ldr r0, =0x56000070
mov r1, #0xaa
str r1, [r0]
/* init uart */
ldr r0, =0x50000000
mov r1, #0x03
str r1, [r0]
ldr r1, =0x245
str r1, [r0, #0x04]
mov r1, #0x01
str r1, [r0, #0x08]
mov r1, #0x00
str r1, [r0, #0x0c]
mov r1, #0x1a
str r1, [r0, #0x28]

After uart0 is set, the code will go to the corresponding branch in line 1 based on different compilation options and runtime parameters, which are

  1. Starting from NAND, the Code executes lowlevel_init, which is used to clear the CPU cache and disable MMU and I-cache,
    Initialize the external memory bus and gpio according to the hardware configuration of the board, and finally copy the code from the NAND Flash to Ram and continue execution.
  2. Started from nor. Compared to the 1st cases, the Code copy part is simplified, and the data segment is copied from flash to ram. The rest are the same.
  3. Start from Ram because u-boot is already in the configured Ram,
    Therefore, all the cache, MMU, SDRAM, Nand, and nor code will be skipped and the done_relocate will be executed.

The following uses the most complex NAND startup as an example. First, the system will jump to the 572 line and execute cpu_init_crit,
Perform CP15 to complete the flush processor ARM920T cache and TLB, and disable MMU and I-Cache:

cpu_init_crit:
/*
* flush v4 I/D caches
*/
mov r0, #0
mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */
mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */
/*
* disable MMU stuff and caches
 */
mrc p15, 0, r0, c1, c0, 0
bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS)
bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM)
orr r0, r0, #0x00000002 @ set bit 2 (A) Align
orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache
mcr p15, 0, r0, c1, c0, 0

Then jump to the 139 line of the Board/neo1973/common/lowlevel_init.s file for execution,
Configure the bus data width, timing, SDRAM control, and gpio. After the configuration is complete, start. S is returned for continued execution.
Because the code is related to the Board, it is placed in the Board directory. Because there are many codes, paste the start part only:

    /* memory control configuration */  
/* make r0 relative the current location so that it */
/* reads SMRDATA out of FLASH rather than memory ! */
adr r0, SMRDATA
ldr r1, =BWSCON /* Bus Width Status Controller */
add r2, r0, #13*4

After completing the board-level settings, you can determine the execution position of the Code on the second line of CPU/ARM920T/start. S. If it is executed from stepping stone,
If u-boot is configured in the NAND boot mode, the system will jump to the nand_load copy code:

    ldr r1, =BWSCON /* Z = CPU booted from NAND */ 
ldr r1, [r1]
tst r1, #6 /* BWSCON[2:1] = OM[1:0] */
teqeq r0, #0 /* Z &= running at address 0 */
beq nand_load

In line 2, The nand_load code will jump to line 3 and execute may_resume.
Checks whether the system is awakened from the standby mode or powered on. If a wake-up event is triggered, the event will be processed based on the previously stored event,
This article does not describe more; if it is started, nand_load will be returned to continue the execution. Initialize the S3C2410 NAND controller in nand_load,
For information about memory ing and register nfconf, see page 215 of the S3C2410 manual. Similarly, paste only the starting part of the Code:

    mov r1, #S3C2410_NAND_BASE 
ldr r2, =0xf842 @ initial value enable tacls=3,rph0=6,rph1=0
str r2, [r1, #oNFCONF]
ldr r2, [r1, #oNFCONF]
bic r2, r2, #0x800 @ enable chip

Set the stack pointer according to the configuration in Row 3 to prepare for calling the C function to execute the copy operation:

    ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */ 
sub r0, r0, #CFG_MALLOC_LEN /* malloc area */
sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */
#ifdef CONFIG_USE_IRQ
sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
sub sp, r0, #12 /* leave 3 words for abort-stack */

Then, in Row 3, store the target address in SDRAM to r0, 0x0 address to R1, and U-boot length to R2,
Jump to the 154th line of the CPU/ARM920T/s3c24x0/nand_read.c file and execute the nand_read_ll function. This function accepts the values in the previous three registers as parameters and puts the returned values back to R0:

    ldr r0, _TEXT_BASE 
mov r1, #0x0
mov r2, #CFG_UBOOT_SIZE
bl nand_read_ll

The nand_read_ll function implements the NAND Flash access code and supports automatic skipping of Bad blocks. The function cyclically reads the NAND page and saves it to the SDRAM until all the copies of the U-boot are completed, and return 0. The C code is left for readers to read. After nand_read_ll returns 0, it will jump to OK _nand_read and check the copied 4 K bytes in row 482:

    @ verify 
mov r0, #0
@ldr r1, =0x33f00000
ldr r1, _TEXT_BASE
mov r2, #0x400
@ 4 bytes * 1024 = 4K-bytes
go_next:
ldr r3, [r0], #4
ldr r4, [r1], #4
teq r3, r4
bne notmatch
subs r2, r2, #4
beq done_nand_read
bne go_next

After the verification is passed, the code runs in line 2 and stores 1 in the sdram location of _ booted_from_nand to inform the upper-layer software that the boot is from NAND:

done_nand_read: 
ldr r0, _booted_from_nand
mov r1, #1
strb r1, [r0]

Then, in Row 3, copy the interrupted table to 0x0:

    mov r0, #0 
ldr r1, _TEXT_BASE
mov r2, #0x40
irqvec_cpy_next:
ldr r3, [r1], #4
str r3, [r0], #4
subs r2, r2, #4
bne irqvec_cpy_next

In row 532, set the stack pointer:

    ldr r0, _TEXT_BASE    /* upper 128 KiB: relocated uboot */ 
sub r0, r0, #CFG_MALLOC_LEN /* malloc area */
sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */
#ifdef CONFIG_USE_IRQ
sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
sub sp, r0, #12 /* leave 3 words for abort-stack */

In row 3, clear the BSS segment and jump to the real C function start_armboot to enter more advanced hardware initialization code,Assembly initialization also completes the mission:

    ldr r0, _bss_start /* find start of bss segment */ 
ldr r1, _bss_end /* stop here */
mov r2, #0x00000000 /* clear */
clbss_l:
str r2, [r0] /* clear loop... */
add r0, r0, #4
cmp r0, r1
ble clbss_l
ldr pc, _start_armboot

The start_armboot function is located in row 277th of the lib_arm/board. c file. First, initialize the globel_data variable GD. This variable is a structure and most of its members are basic settings of the Board, such as serial number, IP address, MAC address, etc. (for the prototype of the structure, see include/ASM-arm/globel_data.h and include/ASM-arm/u-boot.h ):

         gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));
/* compiler optimization barrier needed for GCC >= 3.4 */
__asm__ __volatile__("": : :"memory");

memset ((void*)gd, 0, sizeof (gd_t));
gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));
memset (gd->bd, 0, sizeof (bd_t));

Then, start from the init_sequence address in a for loop and call the initialization C function one by one until null. These routine functions are called in the order

  1. Cpu_init () -- initialize the interrupt stack in the common/Main. c file.
  2. Board_init () -- in the Board/neo1973/gta01/gta01.c file, execute board-level initialization, mainly to update gpio and PLL settings
  3. Interrupt_init () -- initialize the clock interruption in the/CPU/ARM920T/s3c24x0/interrupts. c file
  4. Env_init () -- in the common/env_nand.c file, set the default environment variable
  5. Init_baudrate () -- In the lib_arm/board. c file, save the baudrate in the environment variable to the bd_info structure BD.
  6. Serial_init () -- in the common/serial. c file, call the true Init () in the driver to initialize the serial port
  7. Console_init_f () -- in the common/console. c file, update the have_console of the global_data structure GD to 1.
  8. Display_banner () -- In the lib_arm/board. c file, print the U-boot banner, output version, run address, and other information. For example
  9. Init_func_i2c () -- initialize the I2C bus in the lib_arm/board. c file
  10. Dram_init () -- fill in the start and size members of BD-> bi_dram [0] In the Board/neo1973/gta01/gta01.c file to describe the available ram of U-boot
  11. Display_dram_config () -- print the current ram configuration in the Board/neo1973/gta01/gta01.c file. On the console, you can see the corresponding DRAM: 128 MB.

Using GDB, you can clearly see the call process:

         for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { 
if ((*init_fnc_ptr)() != 0) {
hang ();
}
}

Next, initialize some optional peripherals, such as the display screen, nor, Nand, dataflash, and nic.All Initialization is complete. Paste only the nor code below:

#ifndef CFG_NO_FLASH 
/* configure available FLASH banks */
size = flash_init ();
display_flash_config (size);
#endif /* CFG_NO_FLASH */

Then, enter the infinite loop in line 3, call the main_loop () function of Line 3 in the common/Main. c file, and U-boot completes the startup process. Main_loop provides an interactive command line, which can be operated through the serial port or USB console, or the operating system can be further guided:

         for (;;) { 
main_loop ();
}

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.