Armlinux bootloader details

Source: Internet
Author: User

Introduction

There are a lot of articles on Linux bootloader on the Internet, but most of them are relatively large programs such as Vivi and blob, which are not easy to read and the compiled files are also relatively large, in addition, it is more development-oriented guiding code that needs to be reduced when made into a product, which affects the development speed to a certain extent, and has a relatively high learning overhead for beginners, here we analyze a simple bootloader, which is a slightly modified result on 2410 bootloader provided by Samsung. The size of the compiled file cannot exceed 4 kb, which is helpful to everyone.

1. Several important concepts

Compressed kernel and decompressed Kernel

The compressed kernel, according to the documentation, does not advocate the use of decompressed kernel, but uses the compressed kernel, which includes understanding of the pressure. therefore, we need to provide sufficient space for the compressed and decompressed Kernel During Ram allocation so that they will not overlap.

After the command is executed to jump to the compressed kernel, The decompress starts to work. If the decompressed code is detected by the decompress, it overwrites the compressed kernel, and then directly jumps to the compressed kernel to store data, and re-locate the kernel, so if there is not enough space, an error will occur.

Jffs2 File System

The data generated in the armlinux application can be stored in flash, which is not used on my board.

Ramdisk

Ramdisk enables the root file system to start without other devices. generally, there are two loading methods. I will introduce the most commonly used method. Put the compressed ramdisk image to the specified address, and then the bootloader will pass the address atag_initrd2 to the kernel through the startup parameter. for more information, see code analysis.

Startup parameters (from IBM Developer)

Before calling the kernel, make one step of preparation, that is, set the Linux kernel startup parameters. Linux 2.4.x and later kernels all expect to pass startup parameters in the form of tagged list. Start the parameter tag list to mark atag_core and end with atag_none. Each tag consists of the tag_header structure that identifies the passed parameter and the subsequent parameter value data structure. The data structure tag and tag_header are defined in the include/ASM/setup. h header file of the Linux kernel source code.

In Embedded Linux systems, the following common startup parameters are required by Bootloader: atag_core, atag_mem, atag_cmdline, atag_ramdisk, and atag_initrd.

(Note) parameters can also be set using CommandLine. In my bootloader, I use both of them.

2. Development Environment and Development Board Configuration:

CPU: S3C2410 and bank6 have 64 MB of SDRAM (two blocks), 32 MB of nor flash on bank0, and the serial port cannot be escaped. In this way, according to the data manual, the address allocation is as follows:

0x4000_0000 is a 4 K in-chip dram.

0x0000_0000 start with 32 M Flash 16bit width

0x3000_0000 start with 64 m sdram 32bit width

Note: The bank6 and bank7 in the control register must be the same.

0x4000_0000 (in-chip Dram) Stores bootloader image within 4 K

0x3000_0100 start to store startup parameters

0x3120_0000 store compressed kernel Image

0x3200_0000 store compressed ramdisk

0x3000_8000 is specified as decompressed kernel image address

0x3040_0000 is specified as decompressed ramdisk image address

Development Environment: RedHat Linux, armgcc toolchain, and armlinux Kernel

How to Build the compilation environment of armgcc: We recommend that you use toolchain instead of compiling armgcc by yourself. If you have tried it many times, it will end with a failure.

First download arm-GCC 3.3.2 toolchain

Extract arm-linux-gcc-3.3.2.tar.bz2 to/toolchain

# Tar jxvf arm-linux-gcc-3.3.2.tar.bz2

# Mv/usr/local/ARM/3.3.2/toolchain

In makefile, set arch = arm cross_compile to the toolchain path.

Also, include =-I ../include-I/root/My/usr/local/ARM/3.3.2/include. Otherwise, the library function cannot be used.

3. Startup method:

It can be started in flash or a JTAG simulator. due to the use of nor flash, according to The 2410 manual, the 4 k DRAM in the chip can be directly used without any configuration, and other memory must be initialized first, such as telling memory controller, in bank6, there are two SDRAM blocks, with the data width being 32bit, =. otherwise, memory control processes the memory according to the default value after resetting. in this way, read/write errors will occur.

So the first step is to put the Execution Code in 0x4000_0000 through the simulator (during compilation, set text_bas

E = 0x40000000)

Step 2: Use axd to place the Linux kernel image in the target address (SDRAM) and wait for the call

Step 3: Execute the bootloader code to obtain debugging data from the serial port and guide armlinux

4. Code Analysis

After talking about so many execution steps, I want to give everyone a general impression on the startup, followed by the analysis of the code inside the bootloader. The content of the bootloader article is a lot online, and I have simplified it here, unnecessary functions are deleted.

Bootloader is generally divided into two parts: the Assembly part and the C language part. The Assembly part performs simple hardware initialization. The C part is responsible for copying data, setting startup parameters, serial communication, and other functions.

Bootloader lifecycle:

1. initialize the hardware, for example, set UART (at least one) and check memory =.

2. Set the startup parameters to inform the kernel hardware, for example, which startup interface is used, the baud rate =.

3. Jump to the first address of Linux kernel.

4. Extinction

Of course, virtual addresses are used in the pilot phase, such as Vivi. If you are bored, real addresses are the same.

Let's look at the Code:

2410init. s

. Global _ start // execution start

_ Start:

// The following is the interrupt vector.

B reset @ supervisor mode // jump after restart

......

......

Reset:

LDR r0, = wtcon/wtcon address: 53000000, watchdog control register */

LDR R1, = 0x0/* off watchdog */

STR R1, [R0]

LDR r0, = intmsk

LDR R1, = 0 xffffffff/* shield all interrupts */

STR R1, [R0]

LDR r0, = intsubmsk

LDR R1, = 0x3ff/* sub-interrupt is the same */

STR R1, [R0]

/* Initialize ports... for display led .*/

LDR r0, = gpfcon

LDR R1, = 0x55aa

STR R1, [R0]

LDR r0, = gpfup

LDR R1, = 0xff

STR R1, [R0]

LDR r0, = gpfdat

LDR R1, = poweroffled1

STR R1, [R0]

/* Setup clock divider control register

* You must configure clkdivn before locktime or mpll upll

* Because default clkdivn 1, 1 set the sdmram timing conflict

NOP

* Fclk: hclk: pclk = in this case

*/

LDR r0, = clkdivn

LDR R1, = 0x3

STR R1, [R0]

/* To reduce PLL lock time, adjust the locktime register .*/

LDR r0, = locktime

LDR R1, = 0 xffffff

STR R1, [R0]

/* Configure mpll */

LDR r0, = mpllcon

LDR R1, = (m_mdiv <12) + (m_pdiv <4) + m_sdiv) // fin = 12 MHz, fout = 203 MHz

STR R1, [R0]

LDR R1, = gstatus2

LDR R10, [R1]

Tst R10, # offrst

BNE 1000f

// In the above section, I did not change it, so I wrote it using Samsung. below is the main point to be changed.

/* Memory c0ntroller (MC) setting */

Add r0, PC, # McDATA-(. + 8) // R0 points to the McDATA address, where the data required for MC Initialization is stored.

LDR R1, = bwscon // R1 points to the first address of the MC controller register

Add R2, R0, #52 // number of copies, offset 52 characters

1: // perform cyclic replication according to the offset

LDR R3, [R0], #4

STR R3, [R1], #4

CMP R2, R0

BNE 1b

. Align 2

McDATA:

. Word (0 + (bda-bwscon <4) + (b2_bwscon <8) + (b3_bwscon <12) + (b4_bwscon <16) + (b5_bwscon <20) + (b6_bwscon <24) + (b7_bwscon <28 ))

The above line is the data of bwscon. The specific parameter meanings are as follows:

You need to set both dw6 and dw7 to 10, namely, 32bit, and dw0 to 01, that is, 16bit.

The following table lists the Controller data of each bank, most of which are clock-related. You can use the default value. After setting MC, jump to the part that calls the main function.

. Word (b0_tacs <13) + (b0_tcos <11) + (b0_tacc <8) + (b0_tcoh <6) + (b0_tah <4) + (b0_tacp <2) + (b0_pmc ))

. Word (b1_tacs <13) + (b1_tcos <11) + (b1_tacc <8) + (b1_tcoh <6) + (b1_tah <4) + (bw.tacp <2) + (bw.pmc ))

. Word (b2_tacs <13) + (b2_tcos <11) + (b2_tacc <8) + (b2_tcoh <6) + (b2_tah <4) + (b2_tacp <2) + (b2_pmc ))

. Word (b3_tacs <13) + (b3_tcos <11) + (b3_tacc <8) + (b3_tcoh <6) + (b3_tah <4) + (b3_tacp <2) + (b3_pmc ))

. Word (b4_tacs <13) + (b4_tcos <11) + (b4_tacc <8) + (b4_tcoh <6) + (b4_tah <4) + (b4_tacp <2) + (b4_pmc ))

. Word (b5_tacs <13) + (b5_tcos <11) + (b5_tacc <8) + (b5_tcoh <6) + (b5_tah <4) + (b5_tacp <2) + (b5_pmc ))

. Word (b6_mt <15) + (b6_trcd <2) + (b6_scan ))

. Word (b7_mt <15) + (b7_trcd <2) + (b7_scan ))

. Word (refen <23) + (trefmd <22) + (Trp <20) + (TRC <18) + (TCHR <16) + refcnt)

. Word 0xb2/* refresh control register */

. Word 0x30/* banksize register: burst mode */

. Word 0x30/* SDRAM mode register */

. Align 2

. Global call_main // call the main function. All function parameters are 0.

Call_main:

LDR sp, stack_start

MoV FP, #0/* no previous frame, so fp = 0 */

MoV A1, #0/* Set argc to 0 */

MoV A2, #0/* Set argv to NUL */

BL main/* Call Main */

Stack_start:

. Word stack_base

Undefined_instruction:

Software_interrupt:

Prefetch_abort:

Data_abort:

Not_used:

IRQ:

FIQ:

/* The above is the main assembly part. The clock settings are implemented, the watchdog function is set for the serial port, and the shutdown function is interrupted (if necessary, downgrading can be used), and then transferred to main */

2410init. c file

Int main (INT argc, char ** argv)

{

U32 test = 0;

Void (* Thekernel) (INT zero, Int Arch, unsigned long params_addr) = (void (*) (INT, Int, unsigned long) ram_compressed_kernel_base; // The compressed image address

Int I, K = 0;

// Downpt = (ram_compressed_kernel_base );

Chkbs = (_ ram_startaddress); // The place where the SDRAM starts.

// Frompt = (flash_linuxkernel );

Mmu_enableicache ();

Changeclockdivider (); //

Changempllvalue (m_mdiv, m_pdiv, m_sdiv); // fin = 12 MHz fclk = 200 MHz

Port_init (); // set the I/O port. You must call this function before using the comport. Otherwise, the communication chip cannot obtain data.

Uart_init (pclk, 115200); // use the default 200000 value for pclk, with a dial rate of 115200.

/******************* (Check the ram space) *******************/

Uart_sendstring ("/n/tlinux S3C2410 nor bootloader/N ");

Uart_sendstring ("/n/tchecking SDRAM 2410loader. C.../N ");

For (; chkbs <0x33fa0140; chkbs = chkbs + 0x4, test ++ )//

// Based on my experience, it is best to increase by one byte. Our board is okay during the 256byte incremental detection,

// An error occurs when the increment value is 1 byte. If the increment value of 13th and the number of data lines increases by 1, the error is detected as a hardware problem. The symptoms are as follows:

// Use the code in the simulator to test the SDRAM. The 28f128a3j flash film is not pasted at first. The test result is good. However, after the flash film is installed //, the test data (data) when 0x00000400 is used for writing and reading data in batches, an error occurs when the memory size is about 1 kb. The error data always changes to 0x00002400, and the 10-bit and 13-bit data bus are not short-circuited. Use other data // for testing, such as 0x00000200; 0x00000800. DX help.

// Not solved so far, so I cannot use flash.

{

Chkpt1 = chkbs;

* (U32 *) chkpt1 = test; // write data

If (* (u32 *) chkpt1 = 1024) // is the data read and written the same?

{

Chkpt1 + = 4;

Led_display (1 );

Led_display (2 );

Led_display (3 );

Led_display (4 );

}

Else

Goto error;

}

Uart_sendstring ("/n/tsdram check successful! /N/tmemory maping ...");

Get_memory_map ();

// Obtain available memory information and make it a list, which will be passed to the kernel as the startup parameter.

// Memory ing refers to the address ranges allocated in the 4 GB physical address space to address the system's Ram unit.

Uart_sendstring ("/n/tmemory map successful! /N ");

// I use the simulator to directly place the kernel and ramdisk on the SDRAM, so the following section is not required, but if the kernel and ramdisk are in the flash, then we need.

/******************* (Copy Linux kernel) *******************/

Uart_sendstring ("/tloading kernel image from flash.../N ");

Uart_sendstring ("/Tand copy kernel image to SDRAM at 0x31000000/N ");

Uart_sendstring ("/T/tby leijun Dong dongleijun4000@hotmail.com/N ");

For (k = 0; k <196608; k ++, downpt + = 1, frompt + = 1) // 3*1024*1024/32 Linux kernel des, SRC, length = 3 m

* (U32 *) downpt = * (u32 *) frompt;

/******************* (Load ramdisk) *******************/

Uart_sendstring ("/T/tloading compressed ramdisk.../N ");

Downpt = (ram_compressed_ramdisk_base );

Frompt = (flash_ramdisk_base );

For (k = 0; k <196608; k ++, downpt + = 1, frompt + = 1) // 3*1024*1024/32 Linux kernel des, SRC, length = 3 m

* (U32 *) downpt = * (u32 *) frompt;

/****** Jffs2 file system. If Flash is not used during development, do not ********/

Uart_sendstring ("/T/tloading jffs2. ../N ");

Downpt = (ram_jffs2 );

Frompt = (flash_jffs2 );

For (k = 0; k <(1024*1024/32); k ++, downpt + = 1, frompt + = 1)

* (U32 *) downpt = * (u32 *) frompt;

Uart_sendstring ("load success... run.../N ");

/******************** (Setup PARAM) *******************/

Setup_start_tag (); // start to set the startup Parameter

Setup_memory_tags (); // memory impression

Setup_commandline_tag ("console = ttys0, 115200n8"); // start the command line

Setup_initrd2_tag (); // root device

Setup_ramdisk_tag (); // ramdisk Image

Setup_end_tag ();

/* Turn Off I-Cache */

ASM ("MRC P15, 0, % 0, C1, C0, 0": "= r" (I ));

I & = ~ 0x1000;

ASM ("MCR P15, 0, % 0, C1, C0, 0": "R" (I ));

/* Flush I-Cache */

ASM ("MCR P15, 0, % 0, C7, C5, 0": "R" (I ));

// The following line jumps to the first address of the compressed kernel.

Thekernel (0, arch_number, (unsigned long *) (ram_boot_params ));

// When the kernel is started, I-Cache can be enabled or disabled. R0 must be 0 and R1 must be the CPU model.

(This can be found in Linux/ARCH/ARM/tools/Mach-types). R2 must be the physical start address of the parameter.

/******************* End *******************/

Error:

Uart_sendstring ("/n/npanic SDRAM check error! /N ");

Return 0;

}

Static void setup_start_tag (void)

{

Params = (struct tag *) ram_boot_params; // address at which the startup parameter starts

Params-> HDR. Tag = atag_core;

Params-> HDR. size = tag_size (tag_core );

Params-> U. Core. Flags = 0;

Params-> U. Core. pagesize = 0;

Params-> U. Core. rootdev = 0;

Params = tag_next (Params );

}

Static void setup_memory_tags (void)

{

Int I;

For (I = 0; I <num_mem_areas; I ++ ){

If (memory_map [I]. Used ){

Params-> HDR. Tag = atag_mem;

Params-> HDR. size = tag_size (tag_mem32 );

Params-> U. mem. Start = memory_map [I]. Start;

Params-> U. mem. size = memory_map [I]. Len;

Params = tag_next (Params );

}

}

}

Static void setup_commandline_tag (char * CommandLine)

{

Int I = 0;

/* Skip non-existent command lines so the kernel will still

* Use its default command line.

*/

Params-> HDR. Tag = atag_cmdline;

Params-> HDR. size = 8;

// Console = ttys0, 115200n8

Strcpy (Params-> U. marshline. marshline, P );

Params = tag_next (Params );

}

Static void setup_initrd2_tag (void)

{

/* An atag_initrd node tells the kernel where the compressed

* Ramdisk can be found. atag_rdimg is a better name, actually.

*/

Params-> HDR. Tag = atag_initrd2;

Params-> HDR. size = tag_size (tag_initrd );

Params-> U. initrd. Start = ram_compressed_ramdisk_base;

Params-> U. initrd. size = 2047; // K byte

Params = tag_next (Params );

}

Static void setup_ramdisk_tag (void)

{

/* An atag_ramdisk node tells the kernel how large

* Decompressed ramdisk will become.

*/

Params-> HDR. Tag = atag_ramdisk;

Params-> HDR. size = tag_size (tag_ramdisk );

Params-> U. ramdisk. Start = ram_decompressed_ramdisk_base;

Params-> U. ramdisk. size = 7.8*1024; // K byte

Params-> U. ramdisk. Flags = 1; // automatically load ramdisk

Params = tag_next (Params );

}

Static void setup_end_tag (void)

{

Params-> HDR. Tag = atag_none;

Params-> HDR. size = 0;

} Void uart_init (INT pclk, int baud) // the serial port is very important.

{

Int I;

If (pclk = 0)

Pclk = pclk;

Rufcon0 = 0x0; // UART channel 0 FIFO control register, FIFO disable

Rumcon0 = 0x0; // UART chaneel 0 modem control register, AFC disable

// Uart0

Rulcon0 = 0x3; // line control register: normal, no parity, 1 stop, 8 bits

The following section of Samsung is not quite correct, but I calculated it as 0x245 according to normal, no parity, 1 stop, and 8 bits.

// [10] [9] [8] [7] [6] [5] [4] [3: 2] [1:0]

// Clock Sel, TX int, RX int, RX time out, RX err, loop-back, send break, transmit mode, receive mode

// 0 1 0, 0 1 0 0, 01 01

// Pclk Level Pulse disable generate normal interrupt or polling

Rucon0 = 0x245; // control register

Rubrdiv0 = (INT) (pclk/16./baud)-1); // baud rate divisior register 0

Delay (10 );

}

After the above tossing, the next step is the kernel activity. Whether or not you can start the kernel depends on the level of kernel compilation.

This bootloader does not require interactive information like blob. It uses virtual addresses, which are very concise and clear in general.

------------------------------

Source: http://www.palmheart.net/modules.php? OP = modload & name = News & file = article & SID = 197

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.