zoukankan      html  css  js  c++  java
  • linux head-common.s分析(转)

    供head.S调用,其中__mmap_switched的b start_kernel跳转到C执行,且永不返回。

    跳转到start_kernel时寄存器值:

    R0 = cp#15 control register

    R1 = machine id

    R2 = atags/dtb pointer

    R9 = processor ID

    stext->__enable_mmu->__turn_mmu_on->ldr pc, __mmap_switched
    ->__mmap_switched(head-common.S)
    ->b start_kernel(init/main.c)

    http://blog.chinaunix.net/uid-20451980-id-1945242.html

    Linux kernel分析(二)
    注:本文为Stephen Du原创,转载请注明

      这里开始讲解head-common.S的内容。另,我的讲解顺序是按照源码的顺序来进行的而不是按照函数调用的顺序进行,所以读者要注意函数的入口以及返回地址。

     这里定义了atag数据的存放地址

     14 #define ATAG_CORE 0x54410001

     15 #define ATAG_CORE_SIZE ((2*4 + 3*4) >> 2)

     这个部分head.S里面开启MMU后执行。此处开始准备执行C代码做准备:主要是text段,初始化数据段的定位!起始kernel本身的段结构跟普通进程大致相同,这也是为什么它被成文宏内核的原因!
     __data_loc是kernel的text段的开始
     __bss_start是__data_loc的结束也是bss段的开始

     

      从上图看得出,kernel必须将text段跟初始化数据段准备好,对于未初始化数据段跟stack段,heap段都是不需要进行准备的!只需要设置stack指针以及heap起始地址就好!因此到了22行后未出现stack跟heap段的定义!

     

     17         .type   __switch_data, %object

     18 __switch_data:

     19         .long   __mmap_switched

     20         .long   __data_loc                      @ r4

     21         .long   __data_start                    @ r5

     22         .long   __bss_start                     @ r6

     23         .long   _end                            @ r7
     该内存位置存储了处理器的id,也就是r4寄存器的内容,以防后面的代码丢弃r4的内容

     24         .long   processor_id                    @ r4
     该内存位置存储了machine type的信息也是放置r5的内容被丢弃

     25         .long   __machine_arch_type             @ r5
     该内存存储了atag的地址指针,同理防止r6被丢弃了

     26         .long   __atags_pointer                 @ r6

     27         .long   cr_alignment                    @ r7
     这个内存位置放置了kernel的stack & heap的内存位置信息以后,只要将pc pointer指向这里就能执行C代码了!

     28         .long   init_thread_union + THREAD_START_SP @ sp

     29 

     

     此前的代码可能在NOR flash中以XIP方式运行(其实Nand flash也可以XIP,只是有点技术障碍),但是kernel的代码不能总在flash内运行,该函数会进行kernel段的搬移以及处理!

     39         .type   __mmap_switched, %function

     40 __mmap_switched:
     

     41         adr     r3, __switch_data + 4   // r3 point to __mmap_switched本处的注释错误!r3指向__data_loc!

     将代码段,初始化数据段以及未初始化的数据段地址分别加载进入r4~r7

     43         ldmia   r3!, {r4, r5, r6, r7}   // load the function's addr into r4~r7;r3 point to processor_id
     此处比较难以理解,r4=__data_loc是物理上段的存储位置(可能在flash中而不是在RAM中);r5=_data_start是数据在内存的地址,如果二者相等说明已经在RAM中不必做copy,如果不在RAM中则执行copy使之在内存中运行!

     44         cmp     r4, r5                  // Copy data segment if needed __data_start is the destination and __data_loc is the src!

     copy相关操作

     45 1:      cmpne   r5, r6                  // if __data_start and __data_loc is not the same start the transfer session

     46         ldrne   fp, [r4], #4

     47         strne   fp, [r5], #4

     48         bne     1b

     
     清空未初始化数据段,为执行C代码扫清障碍

     50         mov     fp, #0                          @ Clear BSS (and zero fp)

     51 1:      cmp     r6, r7

     52         strcc   fp, [r6],#4

     53         bcc     1b


     执行保存操作。此处最重要的是sp指针的加载!该语句后sp已经指向了kernel的stack上,执行C代码的条件就绪了(代码段ok,初始化数据段ok,未初始化数据段ok,stack ok)

     55         ldmia   r3, {r4, r5, r6, r7, sp}

     56         str     r9, [r4]                        @ Save processor ID

     57         str     r1, [r5]                        @ Save machine type

     58         str     r2, [r6]                        @ Save atags pointer

     59         bic     r4, r0, #CR_A                   @ Clear 'A' bit

     60         stmia   r7, {r0, r4}                    @ Save control register values

     61                                                 @Now we will enter the world of C code and the MMU is on now!

     62         b       entry_for_C_call

     63         //b     start_kernel                    @For ARM start_kernel is defined in the init/main.c we will never return from start_kernel at all

    144 

    145 /*

    146  * Read processor ID register (CP#15, CR0), and look up in the linker-built

    147  * supported processor list.  Note that we can't use the absolute addresses

    148  * for the __proc_info lists since we aren't running with the MMU on

    149  * (and therefore, we are not in the correct address space).  We have to

    150  * calculate the offset.

    151  *

    152  *      r9 = cpuid

    153  * Returns:

    154  *      r3, r4, r6 corrupted

    155  *      r5 = proc_info pointer in physical address space

    156  *      r9 = cpuid (preserved)

    157  */

    158         .type   __lookup_processor_type, %function

    159 __lookup_processor_type:

    160         adr     r3, 3f

    161         ldmda   r3, {r5 - r7}

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

    163         add     r5, r5, r3                      @ convert virt addresses to

    164         add     r6, r6, r3                      @ physical address space

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

    166         and     r4, r4, r9                      @ mask wanted bits

    167         teq     r3, r4

    168         beq     2f

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

    170         cmp     r5, r6

    171         blo     1b

    172         mov     r5, #0                          @ unknown processor

    173 2:      mov     pc, lr

    174 

    175 /*

    176  * This provides a C-API version of the above function.

    177  */

    178 ENTRY(lookup_processor_type)

    179         stmfd   sp!, {r4 - r7, r9, lr}

    180         mov     r9, r0

    181         bl      __lookup_processor_type

    182         mov     r0, r5

    183         ldmfd   sp!, {r4 - r7, r9, pc}

    184 

    185 /*

    186  * Look in and arch/arm/kernel/arch.[ch] for

    187  * more information about the __proc_info and __arch_info structures.

    188  */

    189         .long   __proc_info_begin

    190         .long   __proc_info_end

    191 3:      .long   .

    192         .long   __arch_info_begin

    193         .long   __arch_info_end

    194 

    195 /*

    196  * Lookup machine architecture in the linker-build list of architectures.

    197  * Note that we can't use the absolute addresses for the __arch_info

    198  * lists since we aren't running with the MMU on (and therefore, we are

    199  * not in the correct address space).  We have to calculate the offset.

    200  *

    201  *  r1 = machine architecture number

    202  * Returns:

    203  *  r3, r4, r6 corrupted

    204  *  r5 = mach_info pointer in physical address space

    205  */

    206         .type   __lookup_machine_type, %function

    207 __lookup_machine_type:

    208         adr     r3, 3b

    209         ldmia   r3, {r4, r5, r6}

    210         sub     r3, r3, r4                      @ get offset between virt&phys

    211         add     r5, r5, r3                      @ convert virt addresses to

    212         add     r6, r6, r3                      @ physical address space

    213 1:      ldr     r3, [r5, #MACHINFO_TYPE]        @ get machine type

    214         teq     r3, r1                          @ matches loader number?

    215         beq     2f                              @ found

    216         add     r5, r5, #SIZEOF_MACHINE_DESC    @ next machine_desc

    217         cmp     r5, r6

    218         blo     1b

    219         mov     r5, #0                          @ unknown machine

    220 2:      mov     pc, lr

    221 

    222 /*

    223  * This provides a C-API version of the above function.

    224  */

    225 ENTRY(lookup_machine_type)

    226         stmfd   sp!, {r4 - r6, lr}

    227         mov     r1, r0

    228         bl      __lookup_machine_type

    229         mov     r0, r5

    230         ldmfd   sp!, {r4 - r6, pc}

    231 

    232 /* Determine validity of the r2 atags pointer.  The heuristic requires

    233  * that the pointer be aligned, in the first 16k of physical RAM and

    234  * that the ATAG_CORE marker is first and present.  Future revisions

    235  * of this function may be more lenient with the physical address and

    236  * may also be able to move the ATAGS block if necessary.

    237  *

    238  * r8  = machinfo

    239  *

    240  * Returns:

    241  *  r2 either valid atags pointer, or zero

    242  *  r5, r6 corrupted

    243  */

    244 

    245         .type   __vet_atags, %function

    246 __vet_atags:

    247         tst     r2, #0x3                        @ aligned?

    248         bne     1f

    249 

    250         ldr     r5, [r2, #0]                    @ is first tag ATAG_CORE?

    251         subs    r5, r5, #ATAG_CORE_SIZE

    252         bne     1f

    253         ldr     r5, [r2, #4]

    254         ldr     r6, =ATAG_CORE

    255         cmp     r5, r6

    256         bne     1f

    257 

    258         mov     pc, lr                          @ atag pointer is ok

    259 

    260 1:      mov     r2, #0

    261         mov     pc, lr

  • 相关阅读:
    ScheduledThreadPoolExecutor源码解读
    Spring事务源码阅读笔记
    Spring AOP的实现研究
    cglib之Enhancer
    Spring IOC容器创建bean过程浅析
    CompletionService简讲
    Spring Boot:关于“No converter found for return value of type: class xxx”的解决方法
    java关于Date转换成字符串格式以及Date的增加
    jsp中文乱码六种情况---解决方案
    MYSQL给表添加字段
  • 原文地址:https://www.cnblogs.com/embedded-linux/p/5861053.html
Copyright © 2011-2022 走看看