Ppcboot for ARM Linux

Source: Internet
Author: User

Author-------Dansen-----xzd2734@163.com

Not every line of code must be understood. I just went through the process.
After all, these are relatively mature codes that do not need to be modified.
It is for my own board. The hardware configuration is as follows:
CPU is S3C2410
Board type is smdk2410
16 m nor flash Address is 0x0 --- 0 xffffff
64 m sdram address is 0x30000000 --- 0x33ffffff
The software is of the huaheng version.
Ppcboot 2.0 and Linux 2.4.18
Carefully analyzed the startup process to better understand the cooperation between hardware and software.
Ease of migration.
We burned ppcboot. bin at the beginning of flash, which is an executable binary file.
Note that it is different from the executable ELF File.
After the CPU is powered on, you can run the command directly from the flash Address 0.
Starting code in ppcboot-2.0.0/CPU/ARM920T/start. s
Here we need to mention a very important link file used for compiling links.
Ppcboot-2.0.0/board/smdk2410/ppcboot. LDS
This file provides the base address of each label in the Code and the link sequence of each segment.
Entry (_ start)
Sections
{
. = 0x00000000;

. = Align (4 );
. Text:
{
CPU/ARM920T/start. O (. Text)
* (. Text)
}

. = Align (4 );
. Rodata: {* (. rodata )}

. = Align (4 );
. Data: {* (. Data )}

. = Align (4 );
. Got: {* (. Got )}

Armboot_end_data = .;

. = Align (4 );
. BSS: {* (. BSS )}

Armboot_end = .;
}
The entry of the program is indicated by the _ start label, while the CPU/ARM920T/start. o
It is arranged at the beginning of the program. This label is in start. S.
But there is another point that requires special attention. At first, I didn't understand the program well because of this.
Although the ". = 0x00000000" clause in lDs indicates the link base address, this clause does not actually work,
The real link base address is specified in the ppcboot-2.0.0/config. mk
Ldflags + =-bstatic-T $ (ldscript)-ttext $ (text_base)
-Ttext $ (text_base) indicates the value of the specified link address text_base.
So it is variable, text_base is defined in ppcboot-2.0.0/board/smdk2410/config. mk
Text_base = 0x33f00000
Ppcboot-2.0.0/config. mk is included in makefile,
$ (LD) $ (ldflags) $ (objs) $ (libs)-map ppcboot. Map-O ppcboot in makefile
So the real link address is 0x33f00000. In fact, you can achieve seamless jump by copying ppcboot to ram.
. Globl _ start
_ Start: B Reset
Jump to renset
Reset: LDR r0, = pwtcon
MoV R1, #0x0
STR R1, [R0]
..........................
BL cpu_init_crit // BL jump back
Relocate: // copy ppcboot to ram.
ADR r0, _ start/* R0 <-current position of code */
LDR R2, _ armboot_start
LDR R3, _ armboot_end
Sub R2, R3, R2/* R2 <-size of armboot */
LDR R1, _ text_base/* R1 <-Destination Address */
Add R2, R0, R2/* R2 <-source end address */
Note the difference between ADR and LDR in the above Code.
ADR obtains the offset address related to the current PC. Here the program is still running in flash.
Therefore, the obtained address is based on 0x0.
LDR uses the value specified by _ armboot_start.
. Globl _ armboot_start
_ Armboot_start:
. Word _ start
We can see that its value is also the address of _ start, but here we take the absolute address, which is determined by the link
Text_base is the base address. Since the offset of _ start is 0, R0 is 0, and R2 is text_base.
Copy_loop:
Ldmia R0 !, {R3-r10}
Stmia R1 !, {R3-r10}
CMP r0, r2
Ble copy_loop
Cyclic copy
LDR r0, _ armboot_end/* set up the stack */
Add r0, R0, # config_stacksize
Sub sp, R0, #12/* Leave 3 words for abort-stack */

Ldr pc, _ start_armboot
_ Start_armboot:. Word start_armboot

// Jump to the start_armboot function in ppcboot-2.0.0/lib_arm/board. C to execute
The absolute address of start_armboot is also based on text_base, so seamless jump can be achieved smoothly.
The next step is a series of initialization work.
First, a global data structure gd_t gd_data is defined;
The macro declare_global_data_ptr defines a global gd_t pointer GD
GD = & gd_data;
In this way, you can use GD to access the data structure of gd_data.
For (init_fnc_ptr = init_sequence; * init_fnc_ptr; ++ init_fnc_ptr ){
If (* init_fnc_ptr )()! = 0 ){
Hang ();
}
}
Init_fnc_ptr is a pointer to a series of initialization functions.
Init_fnc_t * init_sequence [] = {
Cpu_init,/* Basic CPU dependent setup */
Board_init,/* Basic board dependent setup */
Interrupt_init,/* set up exceptions */
Env_init,/* initialize environment */
Init_baudrate,/* initialze baudrate settings */
Serial_init,/* serial communications setup */
Display_banner,
Dram_init,/* configure available Ram banks */
Display_dram_config,

Null,
};
Basically, after serial_init, we can use the printf function to print information.
For (;;){
Main_loop ();
}
Enters the main loop, in M:/ppcboot-2.0.0/common/Main. c
{
Char c = 'y ';
Unsigned long timedata;
Printf ("START Linux now (y/N ):");
Timedata = 0;
For (;;){
While (! Tstc () {/* While no incoming data */
If (timedata ++> 3000*100*3)
Goto bootm;/* timed out */
}
C = GETC ();
}
Tstc () is to test whether the serial port has data input. Otherwise, it will wait for time out to jump out.
Bootm:
If (C = 'y' | C = 'y '){
Strcpy (lastcommand, "bootm 30008000 30800000/R ");
Flag = 0;
Rc = run_command (lastcommand, flag );
If (RC <= 0 ){
/* Invalid command or not repeatable, forget it */
Lastcommand [0] = 0;
}
}
Else {
Printf ("/n ");
}
}
In this way, if the serial port is not input or Y is input, the bootm 30008000 30800000/R command will be executed.
Otherwise, the command line of ppcboot will wait for the input.
Executing the bootm 30008000 30800000/R command will call
Do_bootm function, how to break down the specific commands, I will not talk about the Function calling mechanism, just chase run_command
Do_bootm calls the do_bootm_linux function in ppcboot-2.0.0/lib_arm/armlinux. C.
Ret = memcpy (void *) 0x30008000, (void *) 0x40000, 0x100000 );
If (Ret! = (Void *) 0x30008000)
Printf ("Copy kernel failed/N ");
Else
Printf ("Copy kernel done/N ");

Ret = memcpy (void *) 0x30800000, (void *) 0x140000, 0x440000 );
If (Ret! = (Void *) 0x30800000)
Printf ("Haha failed/N ");
Else
Printf ("Copy ramdisk done/N ");

First, copy the kernel and ramdisk to the corresponding place in Ram.
Setup_linux_param (0x30000000 + linux_param_offset); // It is also in armlinux. C.
# Define linux_param_offset 0x100
The parameters to be passed to the kernel are fixed, so the kernel also knows to get the parameters here.
The parameter format is complex. It seems that there are not many parameters here.
Void setup_linux_param (ulong param_base)
{
Struct param_struct * Params = (struct param_struct *) param_base;
...............
}
Only parameters are passed through a param_struct struct, but now we usually use another tag-marked parameter passing method.
For a major parameter, char linux_cmd [] = "initrd = 0x30800000,0x440000 root =/dev/Ram init =/linuxrc console = ttys0 ";
If (linux_cmd = NULL ){
Printf ("wrong magic: cocould not found Linux Command Line/N ");
} Else {
Memcpy (Params-> CommandLine, linux_cmd, strlen (linux_cmd) + 1 );
Printf ("Linux Command Line is:/" % S/"/N", linux_cmd );
}
It is important. You often need to modify it during migration.
Then call_linux (0, 0xc1, 0x30008000); it turns out that it is ready to be transferred to Linux.
0xc1 is the machine type. These three parameters are respectively given to r0, R1, and R2. These are the kernel call conventions.
Void call_linux (long A0, long A1, long A2)
{
_ ASM __(
"Mov r0, % 0/N"
"Mov R1, % 1/N"
"Mov R2, % 2/N"
"Mov IP, #0/N"
"MCR P15, 0, IP, C13, C0, 0/N"/* zero PID */
"MCR P15, 0, IP, C7, C7, 0/N"/* invalidate I, d caches */
"MCR P15, 0, IP, C7, C10, 4/N"/* drain write buffer */
"MCR P15, 0, IP, C8, C7, 0/N"/* invalidate I, d tlbs */
"MRC P15, 0, IP, C1, C0, 0/N"/* Get control register */
"Bic IP, IP, #0x0001/N"/* disable MMU */
"MCR P15, 0, IP, C1, C0, 0/N"/* write control register */
"Mov PC, R2/N"
"NOP/N"
"NOP/N"
:/* No outpus */
: "R" (A0), "R" (A1), "R" (A2)
);
}
MoV PC, R2. That's it. It's called 30008000 to execute the kernel.

Next we will go to the kernel.

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.