ARM LINUX启动代码笔记―――启动

ARM 86浏览

ARM LINUX启动代码笔记―――启动

Kernel 2.6.22

S3C2440

 

内核的入口为stext

 

位置在文件/arch/arm/kernel/head.S

...

       .section
".text.head", "ax"

       .type       stext, %function

ENTRY(stext)

....

 

vmlinux.lds.SENTRY值为stext

/arch/arm/kernel/vmlinux.lds.S

.....

OUTPUT_ARCH(arm)

ENTRY(stext)

.....

 

下面看文件/arch/arm/kernel/head.S

....

       .section
".text.head", "ax"

       .type       stext, %function

ENTRY(stext)

       msr  cpsr_c, #PSR_F_BIT | PSR_I_BIT | SVC_MODE @
ensure svc mode

                                          @
and irqs disabled

       mrc p15, 0, r9, c0, c0          @ get processor id

       bl     __lookup_processor_type             @ r5=procinfo r9=cpuid

       movs      r10, r5                         @
invalid processor (r5=0)?

       beq  __error_p                     @
yes, error 'p'

       bl     __lookup_machine_type        @ r5=machinfo

       movs      r8, r5                           @
invalid machine (r5=0)?

       beq  __error_a                     @
yes, error 'a'

       bl     __create_page_tables

 

       /*

        * The following calls CPU specific code in a
position independent

        * manner. 
See arch/arm/mm/proc-*.S for details. 
r10 = base of

        * xxx_proc_info structure selected by __lookup_machine_type(注释错误)

        * above. 
On return, the CPU will be ready for the MMU to be

        * turned on, and r0 will hold the CPU control
register value.

        */

       ldr   r13, __switch_data        @ address to jump to after

                                          @
mmu has been enabled

       adr   lr, __enable_mmu          @ return (PIC) address

       add  pc, r10, #PROCINFO_INITFUNC

...

 

stext代码主要进行如下操作

1.禁止中断

2.获取CPU型号

3.获取machine类型

4.创建页表

5.Enable MMU

6.程序跳到r10+PROCINFO_INITFUNC

 

认真看了代码,比较有趣

 

2.获取CPU型号

文件/arch/arm/kernel/head-common.S

       .type       __lookup_processor_type, %function

__lookup_processor_type:

       adr   r3, 3f
 

       ldmda      r3, {r5 - r7}

       sub  r3, r3, r7               @
get offset between virt&phys

       add  r5, r5, r3               @
convert virt addresses to

       add  r6, r6, r3               @
physical address space

1:     ldmia       r5, {r3, r4}                   @ value, mask

       and  r4, r4, r9               @
mask wanted bits

       teq   r3, r4

       beq  2f

       add  r5, r5, #PROC_INFO_SZ             @ sizeof(proc_info_list)

       cmp r5, r6

       blo   1b

       mov r5, #0                           @
unknown processor

2:     mov pc, lr

 

一句句来看

adr   r3,
3f
中的3f

/arch/arm/kernel/head-common.S

….

* Look in
include/asm-arm/procinfo.h and arch/arm/kernel/arch.[ch] for

 * more information about the __proc_info and
__arch_info structures.

 */

       .long       __proc_info_begin

       .long       __proc_info_end

3:    .long       .

       .long       __arch_info_begin

       .long       __arch_info_end

r3就指到
3:  .long       .

 

接下来

       ldmda      r3, {r5 - r7}

       sub  r3, r3, r7               @
get offset between virt&phys

       add  r5, r5, r3               @
convert virt addresses to

       add  r6, r6, r3               @
physical address space

 

r7 = [r3]

r6 = [r3-4] 即为__proc_info_end

r5 = [r3-8] 即为__proc_info_begin

 

接着VA转化为PA

       sub  r3, r3, r7               @
get offset between virt&phys

       add  r5, r5, r3               @
convert virt addresses to

       add  r6, r6, r3               @
physical address space

 

__proc_info_begin查找与r9相符合的CPUr5指向该PROC_INFO,然后返回

 

 

       movs      r10, r5                         @
invalid processor (r5=0)?

r5保存到r10

 

3.获取machine类型

 

       bl     __lookup_machine_type        @ r5=machinfo

__lookup_processor_type类似

 

4.创建页表

以后分析

 

5.Enable
MMU

       ldr   r13, __switch_data        @ address to jump to after

                                          @
mmu has been enabled

       adr   lr, __enable_mmu          @ return (PIC) address

 

a. r13指向__switch_data,即指向      .long       __mmap_switched

__switch_data/arch/arm/kernel/head-common.S

...

       .type       __switch_data, %object

__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

...

 

b.lr 指向__enable_mmu

 

6.程序跳到r10+PROCINFO_INITFUNC

/arch/arm/mm/proc-arm920.S

….

       .section
".proc.info.init", #alloc, #execinstr

 

       .type       __arm920_proc_info,#object

__arm920_proc_info:

       .long       0x41009200

       .long       0xff00fff0

       .long   PMD_TYPE_SECT |

              PMD_SECT_BUFFERABLE
|

              PMD_SECT_CACHEABLE
|

              PMD_BIT4
|

              PMD_SECT_AP_WRITE
|

              PMD_SECT_AP_READ

       .long   PMD_TYPE_SECT |

              PMD_BIT4
|

              PMD_SECT_AP_WRITE
|

              PMD_SECT_AP_READ

       b     __arm920_setup

 

/arch/arm/kernel/head.S

       add  pc, r10, #PROCINFO_INITFUNC

即把PC指到b      __arm920_setup

 

7.执行__arm920_setup

/arch/arm/mm/proc-arm920.S

       .type       __arm920_setup, #function

__arm920_setup:

       mov r0, #0

       mcr p15, 0, r0, c7, c7          @ invalidate I,D caches on v4

       mcr p15, 0, r0, c7, c10, 4            @ drain write buffer on v4

#ifdef CONFIG_MMU

       mcr p15, 0, r0, c8, c7          @ invalidate I,D TLBs on v4

#endif

       adr   r5, arm920_crval

       ldmia       r5, {r5, r6}

       mrc p15, 0, r0, c1, c0          @ get control register v4

       bic   r0, r0, r5

       orr   r0, r0, r6

       mov pc, lr

做一些设置后,把lr赋给pc.

lr指向    adr   lr, __enable_mmu          @ return (PIC) address

 

8.执行__enable_mmu

/arch/arm/kernel/head.S

       .type       __enable_mmu, %function

__enable_mmu:

#ifdef CONFIG_ALIGNMENT_TRAP

       orr   r0, r0, #CR_A

#else

       bic   r0, r0, #CR_A

#endif

#ifdef CONFIG_CPU_DCACHE_DISABLE

       bic   r0, r0, #CR_C

#endif

#ifdef CONFIG_CPU_BPREDICT_DISABLE

       bic   r0, r0, #CR_Z

#endif

#ifdef CONFIG_CPU_ICACHE_DISABLE

       bic   r0, r0, #CR_I

#endif

       mov r5, #(domain_val(DOMAIN_USER, DOMAIN_MANAGER) |

                    domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER)
|

                    domain_val(DOMAIN_TABLE, DOMAIN_MANAGER)
|

                    domain_val(DOMAIN_IO, DOMAIN_CLIENT))

       mcr p15, 0, r5, c3, c0, 0             @ load domain access register

       mcr p15, 0, r4, c2, c0, 0             @ load page table pointer

       b     __turn_mmu_on

设置一下MMU,跳转到     b     __turn_mmu_on

9.执行__turn_mmu_on

/arch/arm/kernel/head.S

       .type       __turn_mmu_on, %function

__turn_mmu_on:

       mov r0, r0

       mcr p15, 0, r0, c1, c0, 0             @ write control reg

       mrc p15, 0, r3, c0, c0, 0             @ read id reg

       mov r3, r3

       mov r3, r3

       mov pc, r13

最好pc指向r13,即指向    ldr   r13, __switch_data        @ address to jump to after

最终执行__mmap_switched

 

10.执行__mmap_switched

/arch/arm/kernel/head-common.S

 

       .type       __mmap_switched, %function

__mmap_switched:

       adr   r3, __switch_data + 4

 

       ldmia       r3!, {r4, r5, r6, r7}

       cmp r4, r5                           @
Copy data segment if needed

1:     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 control register values

       b     start_kernel

 

最后调用start_kernel