Arm-Linux kernel porting (1)-kernel Startup Process Analysis
K-style
Reprinted please indicate from Hengyang Normal College 08 electric 2 k-style http://blog.csdn.net/ayangke,QQ:843308498 mailbox: yangkeemail@qq.com
Kernel version: 2.6.22 why is it necessary to use such a lower version for transplantation, because Wei Dongshan said that the lower version can learn something, the higher the version, the less work you need to transplant, and the less you will learn.
Kernel boot is divided into three phases, the first is to run the head. s file and head-common.S, the third is to allow the second is to run the main. c file
For arm processors, the first startup file in the kernel is the head. s file under ARC/ARM/kernel. Of course, this file is also available under ARC/ARM/boot/compress. This file is slightly different from the above file. When zimage is used to generate a compressed kernel, the latter is started, when the latter is different from the former, the code above it is self-extracted, and the code behind it is the same. Here we will analyze the head. s file under ARC/ARM/kernel. After the head. s completes the work, it will jump to the start_kernel function of Main. c In the init/directory drop to start execution.
Stage 1:
First, part of the head. s file is intercepted.
Entry (stext)
MSR cpsr_c, # psr_f_bit | psr_ I _bit | svc_mode @ ensure SVC Mode
@ Andirqs disabled
MRC P15, 0, R9, C0, C0 @ get processor ID
BL _ lookup_processor_type @ R5 = procinfo R9 = cpuid
Movs R10, R5 @ invalidprocessor (R5 = 0 )?
Beq _ error_p @ Yes, error 'P'
BL _ lookup_machine_type @ R5 = machinfo
Movs R8, R5 @ invalidmachine (R5 = 0 )?
Beq _ error_a @ Yes, error 'A'
BL _ create_page_tables
/*
* The following cils cpu specific code in a position independent
* Manner. See arch/arm/mm/proc-*. S fordetails. r10 = base
* Xxx_proc_info structure selected by _ lookup_machine_type
* Above. On return, the CPU will be readyfor the MMU to be
* Turned on, and r0 will hold the CPU control register value.
*/
Ldr r13 ,__ switch_data @ address to jump toafter
@ Mmuhas been enabled
Adr lr ,__ enable_mmu @ return (PIC) Address
The first step is to run _ lookup_processor_type. This function is used to check the processor model. It reads the CPU model of your circuit board and compares it with the processor supported by the kernel to see if it can be processed. We don't care about the specific implementation process, because the mainstream processor kernel now provides support.
Step 2: Execute _ lookup_machine_type. This function is used to check the machine model, it will compare the machine ID passed in by your bootloader with the machine ID that it can process to see if it can be processed. The kernel ID is defined in the mach_type_xxxx macro definition in the ARC/ARM/tool/mach_types file. How does the kernel check whether it supports machines? In fact, each machine has a data structure that describes a specific machine in the/ARC/ARM/Mach-xxxx/smdk-xxxx.c file, as shown below
MACHINE_START(S3C2440,"SMDK2440") /* Maintainer: Ben Dooks<ben@fluff.org> */ .phys_io =S3C2410_PA_UART, .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc, .boot_params = S3C2410_SDRAM_PA + 0x100, .init_irq =s3c24xx_init_irq, .map_io =smdk2440_map_io, .init_machine = smdk2440_machine_init, .timer =&s3c24xx_timer,MACHINE_END
Machine_start and machine_end are actually expanded into a struct.
#defineMACHINE_START(_type,_name) \staticconst struct machine_desc __mach_desc_##_type \ __used \ __attribute__((__section__(".arch.info.init")))= { \ .nr =MACH_TYPE_##_type, \ .name =_name, #defineMACHINE_END \};
The above data structure is expanded
staticconst struct machine_desc __mach_desc_S3C2440 \ __used \ __attribute__((__section__(".arch.info.init")))= { \ .nr =MACH_TYPE_S3C2440, \ .name =”SMDK2440”,};.phys_io = S3C2410_PA_UART, .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc, .boot_params = S3C2410_SDRAM_PA + 0x100, .init_irq =s3c24xx_init_irq, .map_io =smdk2440_map_io, .init_machine = smdk2440_machine_init, .timer =&s3c24xx_timer, }
Each machine has a machine_desc _ mach_desc structure. The kernel checks the NR number of each machine_desc _ mach_desc and compares it with the ID passed by bootloader, the kernel is considered to support this machine, and the kernel will call the machine_desc _ mach_desc _ structure method in the subsequent work to perform some initialization work.
Step 3: create a level-1 page table.
Step 4: Save the address of the _ switch_data function in R13. After enabling MMU in Step 4, the function will be executed.
Step 5: Execute _ enable_mmu, which enables MMU. This function calls the _ turn_mmu_on function, after _ turn_mmu_on, the value assigned to R13 in step 3 is passed to the PC pointer (mov PC, R13), so the kernel starts to jump to the _ switch_data function to start execution.
Let's look at the _ switch_data function in the arch/ARM/kenel/head-common.S file.
__switch_data: .long __mmap_switched .long __data_loc @ r4 .long __data_start @ r5 .long __bss_start @ r6 .long _end @ r7 .long processor_id @ r4 .long __machine_arch_type @ r5 .long cr_alignment @ r6 .long init_thread_union+ THREAD_START_SP @ sp /* * The following fragment of code is executedwith the MMU on in MMU mode, * and uses absolute addresses; this is notposition independent. * * r0 =cp#15 control register * r1 = machine ID * r9 = processor ID */ .type __mmap_switched,%function__mmap_switched: adr r3,__switch_data + 4 ldmia r3!,{r4, r5, r6, r7} cmp r4,r5 @ Copy datasegment if needed1: cmpne r5,r6 ldrne fp,[r4], #4 strne fp,[r5], #4 bne 1b mov fp,#0 @ Clear BSS(and zero fp)1: cmp r6,r7 strcc fp,[r6],#4 bcc 1b ldmia r3,{r4, r5, r6, sp} str r9, [r4] @ Save processor ID str r1, [r5] @ Save machine type bic r4,r0, #CR_A @ Clear 'A' bit stmia r6,{r0, r4} @ Save controlregister values b start_kernel
This function is used to copy the data segment clearly into the BBS segment, set the heap pointer, save the Processing Kernel and machine kernel, and finally jump to the start_kernel function. So the kernel starts the second stage of execution.
Stage 2:
Let's take a look at the start_kernel function of Main. c In the init/directory. Here I only have some.
asmlinkage void __init start_kernel(void){ ……………………. …………………….. printk(KERN_NOTICE); printk(linux_banner); setup_arch(&command_line); setup_command_line(command_line); parse_early_param(); parse_args("Booting kernel",static_command_line, __start___param, __stop___param - __start___param, &unknown_bootoption);……………………………………………… init_IRQ(); pidhash_init(); init_timers(); hrtimers_init(); softirq_init(); timekeeping_init(); time_init(); profile_init();……………………………………………………… console_init();……………………………………………………………… rest_init();}
From the above we can see that start_kernel first prints the kernel information, then processes some parameters passed in by bootloader, and then executes various initialization operations, where the console will be initialized. Finally, rest_init ();
Let's take a look at the rest_init () function.
static void noinline __init_refok rest_init(void)__releases(kernel_lock){int pid;kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);............}
He started the kernel_init function. Let's look at the kerne_init function.
static int __init kernel_init(void * unused){..............................if (!ramdisk_execute_command)ramdisk_execute_command = "/init";if (sys_access((const char __user *) ramdisk_execute_command, 0) != 0) {ramdisk_execute_command = NULL;prepare_namespace();}/* * Ok, we have completed the initial bootup, and * we're essentially up and running. Get rid of the * initmem segments and start the user-mode stuff.. */init_post();return 0;}
Kernel_init first calls prepare_namespace (); then calls the init_post function.
void __init prepare_namespace(void){..........................mount_root();.....................}
We can see that prepare_namespace calls mount_root to mount the root file system. Then run kernel_init and init_post.
Static int noinline init_post (void) {....................................... /* Open the dev/console and set it to standard input and output */If (sys_open (const char _ User *) "/dev/console", o_rdwr, 0) <0) printk (kern_warning "Warning: Unable to open an initial console. \ n "); (void) sys_dup (0); (void) sys_dup (0); If (ramdisk_execute_command) {run_init_process (ramdisk_execute_command ); printk (kern_warning "failed to execute % s \ n", ramdisk_execute_command);}/** we try each of these until one succeeds. ** The Bourne shell can be used instead of init if we are * trying to recover a really broken machine. * // If bootloader specifies the init parameter, start the process specified by the init parameter if (execute_command) {run_init_process (execute_command); printk (kern_warning "failed to execute % S. attempting "" defaults... \ n ", execute_command);} // If the init parameter is not specified, start the INIT process run_init_process ("/sbin/init ") in the sbin, etc, and bin directories "); run_init_process ("/etc/init"); run_init_process ("/bin/init"); run_init_process ("/bin/sh"); panic ("No init found. try passing init = option to kernel. ");}
Note that the above run_init_process will be executed only after the INIT process returns. Once it finds an init executable file, it will never go.
To sum up, the kernel startup process is roughly as follows:
1. Check the CPU and Machine Type
2. initialize the key tasks of the stack, MMU, and other programs.
3. Print kernel information
4. initialize various modules
5. Mount the root file system
6. Start the first INIT process