• linux kernel mini2440 start.S head-common.S 部分注释


    内核版本:2.6.32.2(mini2440光盘源码)

    github地址:https://github.com/guanglun/mini2440_uboot_linux (for_len分支 https://github.com/guanglun/mini2440_uboot_linux/tree/for_learn

      1 /*
      2  *  linux/arch/arm/kernel/head.S
      3  *
      4  *  Copyright (C) 1994-2002 Russell King
      5  *  Copyright (c) 2003 ARM Limited
      6  *  All Rights Reserved
      7  *
      8  * This program is free software; you can redistribute it and/or modify
      9  * it under the terms of the GNU General Public License version 2 as
     10  * published by the Free Software Foundation.
     11  *
     12  *  Kernel startup code for all 32-bit CPUs
     13  */
     14 #include <linux/linkage.h>
     15 #include <linux/init.h>
     16 
     17 #include <asm/assembler.h>
     18 #include <asm/domain.h>
     19 #include <asm/ptrace.h>
     20 #include <asm/asm-offsets.h>
     21 #include <asm/memory.h>
     22 #include <asm/thread_info.h>
     23 #include <asm/system.h>
     24 
     25 #if (PHYS_OFFSET & 0x001fffff)
     26 #error "PHYS_OFFSET must be at an even 2MiB boundary!"
     27 #endif
     28 
     29 /*
     30 PAGE_OFFSET            0xC0000000     页表偏移地址
     31 PHYS_OFFSET            0x30000000     物理内存偏移地址
     32 TEXT_OFFSET            0x00008000
     33 KERNEL_RAM_VADDR    0xC0008000     内核虚拟映射地址
     34 KERNEL_RAM_PADDR      0x30008000     内核物理(RAM)地址
     35 */
     36 
     37 #define KERNEL_RAM_VADDR    (PAGE_OFFSET + TEXT_OFFSET)
     38 #define KERNEL_RAM_PADDR    (PHYS_OFFSET + TEXT_OFFSET)
     39 
     40 
     41 /*
     42  * swapper_pg_dir is the virtual address of the initial page table.
     43  * We place the page tables 16K below KERNEL_RAM_VADDR.  Therefore, we must
     44  * make sure that KERNEL_RAM_VADDR is correctly set.  Currently, we expect
     45  * the least significant 16 bits to be 0x8000, but we could probably
     46  * relax this restriction to KERNEL_RAM_VADDR >= PAGE_OFFSET + 0x4000.
     47  */
     48 
     49  /*
     50  swapper_pg_dir是初始化页表的虚拟地址
     51  我们把页表放在KERNEL_RAM_VADDR下面,因此我们必须保证KERNEL_RAM_VADDR设置得正确。
     52  当前我们要求最低有效的16位数值位0x8000,
     53  但我们可能放宽此限制为KERNEL_RAM_VADDR >= PAGE_OFFSET + 0x4000
     54  */
     55 
     56 #if (KERNEL_RAM_VADDR & 0xffff) != 0x8000
     57 #error KERNEL_RAM_VADDR must start at 0xXXXX8000
     58 #endif
     59 
     60 /*
     61 
     62     .equ 虽然数据段主要用于定义变量数据,但是也可以在这里声明静态数据符号。
     63     .equ 命令用于把常量值设置为可以在文本段中使用的符号
     64 */
     65     .globl    swapper_pg_dir
     66     .equ    swapper_pg_dir, KERNEL_RAM_VADDR - 0x4000
     67 //定义rgtbl 宏 功能是将KERNEL_RAM_PADDR - 0x4000复制给rd寄存器
     68     .macro    pgtbl, rd
     69     ldr    
    d, =(KERNEL_RAM_PADDR - 0x4000)
     70     .endm
     71 
     72 /*CONFIG_XIP_KERNEL未设置
     73 *#define KERNEL_START    KERNEL_RAM_VADDR
     74 *#define KERNEL_END        _end
     75 */
     76 
     77 //XIP片上执行
     78 #ifdef CONFIG_XIP_KERNEL
     79 #define KERNEL_START    XIP_VIRT_ADDR(CONFIG_XIP_PHYS_ADDR)
     80 #define KERNEL_END    _edata_loc
     81 #else
     82 #define KERNEL_START    KERNEL_RAM_VADDR
     83 #define KERNEL_END    _end
     84 #endif
     85 
     86 /*
     87  * Kernel startup entry point.
     88  * ---------------------------
     89  *
     90  * This is normally called from the decompressor code.  The requirements
     91  * are: MMU = off, D-cache = off, I-cache = dont care, r0 = 0,
     92 
     93  * 0xc0008000, you call this at __pa(0xc0008000).
     94  *
     95  * See linux/arch/arm/tools/mach-types for the complete list of machine
     96  * numbers for r1.
     97  *
     98  * We're trying to keep crap to a minimum; DO NOT add any machine specific
     99  * crap here - that's what the boot loader (or in extreme, well justified
    100  * circumstances, zImage) is for.
    101  */
    102  /**
    103  内核运行入口
    104  MCR指令将ARM处理器的寄存器中的数据传送到协处理器的寄存器中。如果协处理器不能成功地执行该操作,将产生未定义的指令异常中断。
    105  MRC指令将协处理器的寄存器中数值传送到ARM处理器的寄存器中。如果协处理器不能成功地执行该操作,将产生未定义的指令异常中断。
    106  **/
    107     .section ".text.head", "ax"
    108 ENTRY(stext)
    109     setmode    PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode
    110                         @ and irqs disabled
    111     mrc    p15, 0, r9, c0, c0        @ get processor id            //获取处理器ID            r9 = cpuid
    112     bl    __lookup_processor_type        @ r5=procinfo r9=cpuid     //处理器类型是否支持
    113 
    114     beq    __error_p            @ yes, error 'p'
    115     bl    __lookup_machine_type        @ r5=machinfo            //机器(板子)类型是否支持
    116     movs    r8, r5                @ invalid machine (r5=0)?                            r8 = machinfo
    117     beq    __error_a            @ yes, error 'a'
    118     bl    __vet_atags                //确定r2 atags指针的有效性   无参数???
    119 
    120     //r8 = machinfo 
    121     //r9 = cpuid 
    122     //r10 = procinfo
    123     bl    __create_page_tables
    124 
    125     /*
    126      * The following calls CPU specific code in a position independent
    127      * manner.  See arch/arm/mm/proc-*.S for details.  r10 = base of
    128      * xxx_proc_info structure selected by __lookup_machine_type
    129      * above.  On return, the CPU will be ready for the MMU to be
    130      * turned on, and r0 will hold the CPU control register value.
    131      */
    132     ldr    r13, __switch_data        @ address to jump to after      r13 = __mmap_switched(虚拟地址)
    133                         @ mmu has been enabled
    134     adr    lr, BSYM(__enable_mmu)        @ return (PIC) address
    135  ARM(    add    pc, r10, #PROCINFO_INITFUNC    )
    136  THUMB(    add    r12, r10, #PROCINFO_INITFUNC    )
    137  THUMB(    mov    pc, r12                )
    138 ENDPROC(stext)
    139 
    140 #if defined(CONFIG_SMP)
    141 ENTRY(secondary_startup)
    142     /*
    143      * Common entry point for secondary CPUs.
    144      *
    145      * Ensure that we're in SVC mode, and IRQs are disabled.  Lookup
    146      * the processor type - there is no need to check the machine type
    147      * as it has already been validated by the primary processor.
    148      */
    149     setmode    PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9
    150     mrc    p15, 0, r9, c0, c0        @ get processor id
    151     bl    __lookup_processor_type
    152     movs    r10, r5                @ invalid processor?
    153     moveq    r0, #'p'            @ yes, error 'p'
    154     beq    __error
    155 
    156     /*
    157      * Use the page tables supplied from  __cpu_up.
    158      */
    159     adr    r4, __secondary_data
    160     ldmia    r4, {r5, r7, r12}        @ address to jump to after
    161     sub    r4, r4, r5            @ mmu has been enabled
    162     ldr    r4, [r7, r4]            @ get secondary_data.pgdir
    163     adr    lr, BSYM(__enable_mmu)        @ return address
    164     mov    r13, r12            @ __secondary_switched address
    165  ARM(    add    pc, r10, #PROCINFO_INITFUNC    ) @ initialise processor
    166                           @ (return control reg)
    167  THUMB(    add    r12, r10, #PROCINFO_INITFUNC    )
    168  THUMB(    mov    pc, r12                )
    169 ENDPROC(secondary_startup)
    170 
    171     /*
    172      * r6  = &secondary_data
    173      */
    174 ENTRY(__secondary_switched)
    175     ldr    sp, [r7, #4]            @ get secondary_data.stack
    176     mov    fp, #0
    177     b    secondary_start_kernel
    178 ENDPROC(__secondary_switched)
    179 
    180     .type    __secondary_data, %object
    181 __secondary_data:
    182     .long    .
    183     .long    secondary_data
    184     .long    __secondary_switched
    185 #endif /* defined(CONFIG_SMP) */
    186 
    187 
    188 
    189 /*
    190  * Setup common bits before finally enabling the MMU.  Essentially
    191  * this is just loading the page table pointer and domain access
    192  * registers.
    193  */
    194 __enable_mmu:
    195 #ifdef CONFIG_ALIGNMENT_TRAP
    196     orr    r0, r0, #CR_A            //执行
    197 #else
    198     bic    r0, r0, #CR_A
    199 #endif
    200 #ifdef CONFIG_CPU_DCACHE_DISABLE
    201     bic    r0, r0, #CR_C            //未执行
    202 #endif
    203 #ifdef CONFIG_CPU_BPREDICT_DISABLE
    204     bic    r0, r0, #CR_Z            //未执行
    205 #endif
    206 #ifdef CONFIG_CPU_ICACHE_DISABLE
    207     bic    r0, r0, #CR_I            //未执行
    208 #endif
    209     mov    r5, #(domain_val(DOMAIN_USER, DOMAIN_MANAGER) | 
    210               domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | 
    211               domain_val(DOMAIN_TABLE, DOMAIN_MANAGER) | 
    212               domain_val(DOMAIN_IO, DOMAIN_CLIENT))    
    213 
    214 //MRC:协处理器寄存器到ARM处理器寄存器的数据传送指令(读出协处理器寄存器)。
    215 //MCR:ARM处理器寄存器到协处理器寄存器的数据传送指令(写入协处理器寄存器)。
    216 
    217     //c3 DOMAIN ACCESS CONTROL REGISTER
    218     mcr    p15, 0, r5, c3, c0, 0        @ load domain access register
    219     //r4 = 30004000 放进协处理器c2
    220     mcr    p15, 0, r4, c2, c0, 0        @ load page table pointer
    221 
    222     b    __turn_mmu_on
    223 ENDPROC(__enable_mmu)
    224 
    225 /*
    226  * Enable the MMU.  This completely changes the structure of the visible
    227  * memory space.  You will not be able to trace execution through this.
    228  * If you have an enquiry about this, *please* check the linux-arm-kernel
    229  * mailing list archives BEFORE sending another post to the list.
    230  *
    231  *  r0  = cp#15 control register
    232  *  r13 = *virtual* address to jump to upon completion
    233  *
    234  * other registers depend on the function called upon completion
    235  */
    236     .align    5
    237 __turn_mmu_on:
    238     mov    r0, r0
    239     mcr    p15, 0, r0, c1, c0, 0        @ write control reg
    240     mrc    p15, 0, r3, c0, c0, 0        @ read id reg
    241     mov    r3, r3
    242     mov    r3, r13
    243     mov    pc, r3
    244 ENDPROC(__turn_mmu_on)
    245 
    246 
    247 /*
    248  * Setup the initial page tables.  We only setup the barest
    249  * amount which are required to get the kernel running, which
    250  * generally means mapping in the kernel code.
    251  *
    252  * r8  = machinfo
    253  * r9  = cpuid
    254  * r10 = procinfo
    255  *
    256  * Returns:
    257  *  r0, r3, r6, r7 corrupted
    258  *  r4 = physical page table address
    259  */
    260  //创建页表
    261 __create_page_tables:
    262 /* 
    263 *宏定义 *.macro pgtbl, rd *ldr 
    d, =(KERNEL_RAM_PADDR - 0x4000) *.endm * 
    264 *分析:内存为 4G = 4*1024 MB;需要4096个表单表示,每一页表单为4bytes;因此需要16K内存,即0x4000; 
    265 *根据 =(KERNEL_RAM_PADDR - 0x4000)得,页表存放于-内核在内存中的物理地址之前。 
    266 */
    267 
    268 //定义rgtbl 宏 功能是将KERNEL_RAM_PADDR - 0x4000复制给rd寄存器
    269     pgtbl    r4                @ page table address       //r4 = 30004000
    270 
    271     /*
    272      * Clear the 16K level 1 swapper page table
    273      */
    274      /* * 按16个bytes一次,将页表清空 */
    275     mov    r0, r4        //r0 = 30004000
    276     mov    r3, #0        //r3 = 0
    277     add    r6, r0, #0x4000 //r6 = 30008000
    278     //将30004000-30008000 的空间置0
    279 1:    str    r3, [r0], #4
    280     str    r3, [r0], #4
    281     str    r3, [r0], #4
    282     str    r3, [r0], #4
    283     teq    r0, r6
    284     bne    1b
    285 
    286 /* *r10 = proc_info_list类型结构体的基地址 *PROCINFO_MM_MMUFLAGS 8 /* offsetof(struct proc_info_list, __cpu_mm_mmu_flags) @ */
    287     ldr    r7, [r10, #PROCINFO_MM_MMUFLAGS] @ mm_mmuflags   r7 = 00000C1E __cpu_mm_mmu_flags
    288 
    289     /*
    290      * Create identity mapping for first MB of kernel to
    291      * cater for the MMU enable.  This identity mapping
    292      * will be removed by paging_init().  We use our current program
    293      * counter to determine corresponding section base address.
    294      */
    295 
    296      /*
    297      
    298      为第一个MB内核创建标识映射,以满足MMU启用。 此标识映射将通过paging_init()删除。 我们使用当前的程序计数器来确定相应的部分基址。
    299 
    300      */
    301 
    302 /* 
    303 *下面代码建立kernel对应的section页表项。 * 
    304 *1. 通过PC值的高12位(右移20位),得到kernel的section,并存储在r6中。 
    305 *2. 获取32bit的页表表单值 
    306 *3. 将页表表单值存放在页表内存区中。 * 
    307 *注意点: *a. lsr 20 因为虚拟地址分区中,后20位为相对地址,前12位为段地址 
    308 *b. lsl 2 因为每一个页表项为4字节,所以需要左移2位 
    309 */
    310 
    311 /*页表将4GB的地址空间分成若干个1MB的段(section),因此页表包含4096个页表项(section entry)。
    312 每个页表项是32bits(4 bytes),因而页表占用4096*4=16k的内存空间。下面的代码是将这16k的页表清0。
    313 */
    314 
    315     mov    r6, pc   //r6= 3000xxxx 通过pc值的高12位(右移20位),得到kernel的section,并存储到r6中.因为当前是通过运行时地址得到的kernel的section,因而是物理地址. 
    316     mov    r6, r6, lsr #20            @ start of kernel section  r6 = 00000300
    317     orr    r3, r7, r6, lsl #20        @ flags + kernel base   r3 = 30000C1E = r7 | (r6 << 20); flags + kernel base,得到页表中需要设置的值. 
    318     str    r3, [r4, r6, lsl #2]        @ identity mapping  //设置页表: mem[r4 + r6 * 4] = r3   r4 = 30004000
    319                                                         //         mem(30004000 + 300 << 2) = 30000C1E
    320                                                         //         mem(30004000 + 300 * 4)  = 30000C1E
    321                                                         //            mem(30004C00) = 30000C1E
    322                                                         //这里,因为页表的每一项是32 bits(4 bytes),所以要乘以4(<<2). 
    323 
    324     /*
    325      * Now setup the pagetables for our kernel direct
    326      * mapped region.
    327      */
    328 /* 
    329 * 下面的 add r0, r4, #(KERNEL_START & 0xff000000) >> 18 涉及到一个立即数的概念: 
    330 * 关于arm汇编立即数,可以参考下面网站:http://blog.csdn.net/a99778800/article/details/6759825 * 
    331 * 下面这段代码就是存储kernel物理地址。建立页表,虚拟地址和物理地址之间建立连接。 
    332 * 即:将内核中所有的物理地址(1M为单位)都存放到了页表中,与虚拟地址一一对应。 */     
    333 
    334 //KERNEL_START = 0xC0008000
    335 //这样分开写是由于arm的立即数只能是8位表示。
    336     add    r0, r4,  #(KERNEL_START & 0xff000000) >> 18     //r0 = 30007000 R4 =30004000
    337     str    r3, [r0, #(KERNEL_START & 0x00f00000) >> 18]!
    338     ldr    r6, =(KERNEL_END - 1)
    339     add    r0, r0, #4
    340     add    r6, r4, r6, lsr #18
    341 1:    cmp    r0, r6
    342     add    r3, r3, #1 << 20
    343     strls    r3, [r0], #4
    344     bls    1b
    345 
    346 /*
    347 运行到此 段表在内存中如下:
    348 
    349 J-Link>mem32 30007000 10
    350 30007000 = 30000C1E 30100C1E 30200C1E 30300C1E 
    351 30007010 = 30400C1E 00000000 00000000 00000000 
    352 30007020 = 00000000 00000000 00000000 00000000 
    353 30007030 = 00000000 00000000 00000000 00000000 
    354 J-Link>h
    355 PC: (R15) = 300080D8, CPSR = 200000D3 (SVC mode, ARM FIQ dis. IRQ dis.)
    356 Current:
    357      R0 =30007014, R1 =000007CF, R2 =00000000, R3 =30500C1E
    358      R4 =30004000, R5 =00000000, R6 =30007013, R7 =00000C1E
    359      R8 =3001EF70, R9 =41129200, R10=3001EF3C, R11=00000020, R12=306EFD84
    360      R13=3049D990, R14=30008028, SPSR=00000010
    361 USR: R8 =3001EF70, R9 =41129200, R10=3001EF3C, R11=00000020, R12=306EFD84
    362      R13=00000000, R14=00000000
    363 FIQ: R8 =00000000, R9 =00000000, R10=00000000, R11=00000000, R12=00000000
    364      R13=00000000, R14=00000000, SPSR=00000010
    365 IRQ: R13=00000000, R14=00000000, SPSR=00000010
    366 SVC: R13=3049D990, R14=30008028, SPSR=00000010
    367 ABT: R13=00000000, R14=00000000, SPSR=00000010
    368 UND: R13=00000000, R14=00000000, SPSR=00000010
    369 
    370 
    371 */
    372 
    373 
    374 /* 
    375 * XIP介绍: 
    376 * XIP是指 (EXECUTE IN PLACE) 是指直接从存放代码的位置上启动运行。 
    377 * 非XIP方式是指在运行之前需对代码进行重定位。该类型的内核以非压缩方式存放在Flash中,启动时由Bootloader加载到内存后运行。 * 
    378 * 如果是XIP技术的内核,上面的映射只能映射内核代码和只读数据部分 
    379 * 这里我们再映射一些RAM来作为.data and .bss空间。 
    380 */
    381 
    382 #ifdef CONFIG_XIP_KERNEL XIP 未定义
    383     /*
    384      * Map some ram to cover our .data and .bss areas.
    385      */
    386     orr    r3, r7, #(KERNEL_RAM_PADDR & 0xff000000)
    387     .if    (KERNEL_RAM_PADDR & 0x00f00000)
    388     orr    r3, r3, #(KERNEL_RAM_PADDR & 0x00f00000)
    389     .endif
    390     //这样分开写是由于arm的立即数只能是8位表示。
    391     add    r0, r4,  #(KERNEL_RAM_VADDR & 0xff000000) >> 18
    392     str    r3, [r0, #(KERNEL_RAM_VADDR & 0x00f00000) >> 18]!
    393     ldr    r6, =(_end - 1)
    394     add    r0, r0, #4
    395     add    r6, r4, r6, lsr #18
    396 1:    cmp    r0, r6
    397     add    r3, r3, #1 << 20
    398     strls    r3, [r0], #4
    399     bls    1b
    400 #endif
    401 
    402     /*
    403      * Then map first 1MB of ram in case it contains our boot params.
    404      * 然后映射第一个1MB的RAM,以防它包含我们的引导参数。
    405      */
    406 /* 
    407 * 下面的代码用来设置RAM中大小为1M虚拟地址的页表。之所以要设置这个页表项的原因是该区域存储着boot params。 
    408 * 因此需要为它建立map,这样开启MMU后就可以访问 
    409 */     
    410 
    411 //这样分开写是由于arm的立即数只能是8位表示。
    412 
    413 /*
    414 *下面的代码用来设置RAM中起始地址为0x30000000、大小为1M虚拟地址的页表,之所以要设置这个页表项的原因是该区域起始地址为0x30000100存
    415 *储着boot params。因此需要为它建立map,这样开启MMU后就可以访问这些参数了。
    416 */
    417     add    r0, r4, #PAGE_OFFSET >> 18
    418     orr    r6, r7, #(PHYS_OFFSET & 0xff000000)
    419     .if    (PHYS_OFFSET & 0x00f00000)
    420     orr    r6, r6, #(PHYS_OFFSET & 0x00f00000)
    421     .endif
    422     str    r6, [r0]
    423 
    424 
    425 #ifdef CONFIG_DEBUG_LL
    426     ldr    r7, [r10, #PROCINFO_IO_MMUFLAGS] @ io_mmuflags
    427     /*
    428      * Map in IO space for serial debugging.
    429      * This allows debug messages to be output
    430      * via a serial console before paging_init.
    431      */
    432     ldr    r3, [r8, #MACHINFO_PGOFFIO]
    433     add    r0, r4, r3
    434     rsb    r3, r3, #0x4000            @ PTRS_PER_PGD*sizeof(long)
    435     cmp    r3, #0x0800            @ limit to 512MB
    436     movhi    r3, #0x0800
    437     add    r6, r0, r3
    438     ldr    r3, [r8, #MACHINFO_PHYSIO]
    439     orr    r3, r3, r7
    440 1:    str    r3, [r0], #4
    441     add    r3, r3, #1 << 20
    442     teq    r0, r6
    443     bne    1b
    444 #if defined(CONFIG_ARCH_NETWINDER) || defined(CONFIG_ARCH_CATS)
    445     /*
    446      * If we're using the NetWinder or CATS, we also need to map
    447      * in the 16550-type serial port for the debug messages
    448      */
    449     add    r0, r4, #0xff000000 >> 18
    450     orr    r3, r7, #0x7c000000
    451     str    r3, [r0]
    452 #endif
    453 #ifdef CONFIG_ARCH_RPC
    454     /*
    455      * Map in screen at 0x02000000 & SCREEN2_BASE
    456      * Similar reasons here - for debug.  This is
    457      * only for Acorn RiscPC architectures.
    458      */
    459     add    r0, r4, #0x02000000 >> 18
    460     orr    r3, r7, #0x02000000
    461     str    r3, [r0]
    462     add    r0, r4, #0xd8000000 >> 18
    463     str    r3, [r0]
    464 #endif
    465 #endif
    466     mov    pc, lr
    467 ENDPROC(__create_page_tables)
    468     .ltorg
    469 
    470 #include "head-common.S"
      1 /*
      2  *  linux/arch/arm/kernel/head-common.S
      3  *
      4  *  Copyright (C) 1994-2002 Russell King
      5  *  Copyright (c) 2003 ARM Limited
      6  *  All Rights Reserved
      7  *
      8  * This program is free software; you can redistribute it and/or modify
      9  * it under the terms of the GNU General Public License version 2 as
     10  * published by the Free Software Foundation.
     11  *
     12  */
     13 
     14 #define ATAG_CORE 0x54410001
     15 #define ATAG_CORE_SIZE ((2*4 + 3*4) >> 2)
     16 #define ATAG_CORE_SIZE_EMPTY ((2*4) >> 2)
     17 
     18     .align    2
     19     .type    __switch_data, %object
     20 __switch_data:
     21     .long    __mmap_switched
     22     .long    __data_loc            @ r4
     23     .long    _data                @ r5
     24     .long    __bss_start            @ r6
     25     .long    _end                @ r7
     26     .long    processor_id            @ r4
     27     .long    __machine_arch_type        @ r5
     28     .long    __atags_pointer            @ r6
     29     .long    cr_alignment            @ r7
     30     .long    init_thread_union + THREAD_START_SP @ sp
     31 
     32 /*
     33  * The following fragment of code is executed with the MMU on in MMU mode,
     34  * and uses absolute addresses; this is not position independent.
     35  *
     36  *  r0  = cp#15 control register
     37  *  r1  = machine ID
     38  *  r2  = atags pointer
     39  *  r9  = processor ID
     40  */
     41  /*
     42 R0~R15 和 r0~r15 (16 个通用寄存器);
     43 a1~a4(参数,结果或临时寄存器,同 R0~R3);
     44 v1~v8(变量寄存器,同 R4~R11);
     45 SB 和 sb(静态基址,同 R9);
     46 SL 和 sl(堆栈限制,同 R10);
     47 FP 和 fp(帧指针);
     48 IP 和 ip(过程调用中间临时寄存器,同 R12);
     49 SP 和 sp(堆栈指针,同 R13);
     50 LR 和 lr(链接寄存器,同 R14);
     51 PC 和 pc(程序计数器,同 R15).
     52  */
     53 __mmap_switched:
     54     adr    r3, __switch_data + 4
     55 
     56 //R4 =C0460000, R5 =C0460000, R6 =C049D8E0, R7 =C04D1D38
     57     ldmia    r3!, {r4, r5, r6, r7} 
     58     cmp    r4, r5                @ Copy data segment if needed
     59     //以下ne都不会执行
     60 1:    cmpne    r5, r6
     61     ldrne    fp, [r4], #4
     62     strne    fp, [r5], #4
     63     bne    1b
     64 
     65     mov    fp, #0                @ Clear BSS (and zero fp)
     66 1:    cmp    r6, r7
     67     strcc    fp, [r6],#4
     68     bcc    1b
     69 
     70  ARM(    ldmia    r3, {r4, r5, r6, r7, sp})
     71  THUMB(    ldmia    r3, {r4, r5, r6, r7}    )
     72  THUMB(    ldr    sp, [r3, #16]        )
     73     str    r9, [r4]            @ Save processor ID
     74     str    r1, [r5]            @ Save machine type
     75     str    r2, [r6]            @ Save atags pointer
     76     bic    r4, r0, #CR_A            @ Clear 'A' bit
     77     stmia    r7, {r0, r4}            @ Save control register values
     78     b    start_kernel
     79 ENDPROC(__mmap_switched)
     80 
     81 /*
     82  * Exception handling.  Something went wrong and we can't proceed.  We
     83  * ought to tell the user, but since we don't have any guarantee that
     84  * we're even running on the right architecture, we do virtually nothing.
     85  *
     86  * If CONFIG_DEBUG_LL is set we try to print out something about the error
     87  * and hope for the best (useful if bootloader fails to pass a proper
     88  * machine ID for example).
     89  */
     90 __error_p:
     91 #ifdef CONFIG_DEBUG_LL
     92     adr    r0, str_p1
     93     bl    printascii
     94     mov    r0, r9
     95     bl    printhex8
     96     adr    r0, str_p2
     97     bl    printascii
     98     b    __error
     99 str_p1:    .asciz    "
    Error: unrecognized/unsupported processor variant (0x"
    100 str_p2:    .asciz    ").
    "
    101     .align
    102 #endif
    103 ENDPROC(__error_p)
    104 
    105 __error_a:
    106 #ifdef CONFIG_DEBUG_LL
    107     mov    r4, r1                @ preserve machine ID
    108     adr    r0, str_a1
    109     bl    printascii
    110     mov    r0, r4
    111     bl    printhex8
    112     adr    r0, str_a2
    113     bl    printascii
    114     adr    r3, 4f
    115     ldmia    r3, {r4, r5, r6}        @ get machine desc list
    116     sub    r4, r3, r4            @ get offset between virt&phys
    117     add    r5, r5, r4            @ convert virt addresses to
    118     add    r6, r6, r4            @ physical address space
    119 1:    ldr    r0, [r5, #MACHINFO_TYPE]    @ get machine type
    120     bl    printhex8
    121     mov    r0, #'	'
    122     bl    printch
    123     ldr     r0, [r5, #MACHINFO_NAME]    @ get machine name
    124     add    r0, r0, r4
    125     bl    printascii
    126     mov    r0, #'
    '
    127     bl    printch
    128     add    r5, r5, #SIZEOF_MACHINE_DESC    @ next machine_desc
    129     cmp    r5, r6
    130     blo    1b
    131     adr    r0, str_a3
    132     bl    printascii
    133     b    __error
    134 ENDPROC(__error_a)
    135 
    136 str_a1:    .asciz    "
    Error: unrecognized/unsupported machine ID (r1 = 0x"
    137 str_a2:    .asciz    ").
    
    Available machine support:
    
    ID (hex)	NAME
    "
    138 str_a3:    .asciz    "
    Please check your kernel config and/or bootloader.
    "
    139     .align
    140 #endif
    141 
    142 __error:
    143 #ifdef CONFIG_ARCH_RPC
    144 /*
    145  * Turn the screen red on a error - RiscPC only.
    146  */
    147     mov    r0, #0x02000000
    148     mov    r3, #0x11
    149     orr    r3, r3, r3, lsl #8
    150     orr    r3, r3, r3, lsl #16
    151     str    r3, [r0], #4
    152     str    r3, [r0], #4
    153     str    r3, [r0], #4
    154     str    r3, [r0], #4
    155 #endif
    156 1:    mov    r0, r0
    157     b    1b     //1b b指back 1为标号
    158 ENDPROC(__error)
    159 
    160 
    161 /*
    162  * Read processor ID register (CP#15, CR0), and look up in the linker-built
    163  * supported processor list.  Note that we can't use the absolute addresses
    164  * for the __proc_info lists since we aren't running with the MMU on
    165  * (and therefore, we are not in the correct address space).  We have to
    166  * calculate the offset.
    167  *
    168  *    r9 = cpuid
    169  * Returns:
    170  *    r3, r4, r6 corrupted
    171  *    r5 = proc_info pointer in physical address space 物理内存中的proc_info指针
    172  *    r9 = cpuid (preserved)
    173  */
    174  //ADR : 小范围的地址读取伪指令.ADR 指令将基于 PC 相对偏移的地址值读取到寄存器中.
    175  //LDMIA 和 STMIA 批量加载/存储指令可以实现在一组寄存器和一块连续的内存单元之间传输数据
    176 __lookup_processor_type:
    177     adr    r3, 3f    //3f f指forward 3为标号                
    178     ldmia    r3, {r5 - r7} 
    179 /*    
    180     r5 __proc_info_begin     地址
    181     r6 __proc_info_end        地址
    182     r7 .                    当前地址
    183 
    184 
    185     R0 =00000000, R1 =000007CF, R2 =016F2818, R3 =300081B8
    186     R4 =30008000, R5 =C001EF3C, R6 =C001EF70, R7 =C00081C0
    187     R8 =016F2818, R9 =41129200, R10=00000004, R11=00000020, R12=306EFD84
    188     R13=3049D990, R14=3000800C, SPSR=00000010
    189 
    190 */
    191 
    192     add    r3, r3, #8
    193     sub    r3, r3, r7            @ get offset between virt&phys  R3 = 70000000 = 300081C0 - C00081C0
    194     add    r5, r5, r3            @ convert virt addresses to
    195     add    r6, r6, r3            @ physical address space
    196 1:    ldmia    r5, {r3, r4}            @ value, mask
    197     and    r4, r4, r9            @ mask wanted bits
    198     teq    r3, r4
    199     beq    2f                    //ID正确,跳转回去
    200     add    r5, r5, #PROC_INFO_SZ        @ sizeof(proc_info_list) ID不正确的话,寻找下一个list对比
    201     cmp    r5, r6                //比较是否小于__proc_info_end的地址,如果小于则说明还有list可以比较,否则就已经没有了
    202     blo    1b
    203     mov    r5, #0                @ unknown processor  返回r5 = 0表示没有对应的处理器
    204 2:    mov    pc, lr
    205 ENDPROC(__lookup_processor_type)
    206 
    207 /*
    208  * This provides a C-API version of the above function.
    209  */
    210 ENTRY(lookup_processor_type)
    211     stmfd    sp!, {r4 - r7, r9, lr}
    212     mov    r9, r0
    213     bl    __lookup_processor_type
    214     mov    r0, r5
    215     ldmfd    sp!, {r4 - r7, r9, pc}
    216 ENDPROC(lookup_processor_type)
    217 
    218 /*
    219  * Look in <asm/procinfo.h> and arch/arm/kernel/arch.[ch] for
    220  * more information about the __proc_info and __arch_info structures.
    221  */
    222 
    223 
    224 //proc_info和arch_info位置
    225     .align    2
    226 3:    .long    __proc_info_begin
    227     .long    __proc_info_end
    228 4:    .long    .
    229     .long    __arch_info_begin
    230     .long    __arch_info_end
    231 
    232 /*
    233  * Lookup machine architecture in the linker-build list of architectures.
    234  * Note that we can't use the absolute addresses for the __arch_info
    235  * lists since we aren't running with the MMU on (and therefore, we are
    236  * not in the correct address space).  We have to calculate the offset.
    237  *
    238  *  r1 = machine architecture number
    239  * Returns:
    240  *  r3, r4, r6 corrupted
    241  *  r5 = mach_info pointer in physical address space
    242  */
    243 __lookup_machine_type:
    244     adr    r3, 4b       //将 .long    . 的物理地址加载至r3寄存器 R3 =300081C0
    245     ldmia    r3, {r4, r5, r6} //R4 =C00081C0, R5 =C001EF70, R6 =C001EFA4,
    246 
    247     //将r5  r6的__arch_info_begin和__arch_info_end地址由虚拟地址转换成物理地址
    248     sub    r3, r3, r4            @ get offset between virt&phys
    249     add    r5, r5, r3            @ convert virt addresses to
    250     add    r6, r6, r3            @ physical address space        
    251     
    252 1:    ldr    r3, [r5, #MACHINFO_TYPE]    @ get machine type
    253     teq    r3, r1                @ matches loader number?
    254     beq    2f                @ found
    255     add    r5, r5, #SIZEOF_MACHINE_DESC    @ next machine_desc
    256     cmp    r5, r6
    257     blo    1b
    258     mov    r5, #0                @ unknown machine
    259 2:    mov    pc, lr
    260 ENDPROC(__lookup_machine_type)
    261 
    262 /*
    263  * This provides a C-API version of the above function.
    264  */
    265 ENTRY(lookup_machine_type)
    266     stmfd    sp!, {r4 - r6, lr}
    267     mov    r1, r0
    268     bl    __lookup_machine_type
    269     mov    r0, r5
    270     ldmfd    sp!, {r4 - r6, pc}
    271 ENDPROC(lookup_machine_type)
    272 
    273 /* Determine validity of the r2 atags pointer.  The heuristic requires
    274  * that the pointer be aligned, in the first 16k of physical RAM and
    275  * that the ATAG_CORE marker is first and present.  Future revisions
    276  * of this function may be more lenient with the physical address and
    277  * may also be able to move the ATAGS block if necessary.
    278  *
    279  * r8  = machinfo
    280  *
    281  * Returns:
    282  *  r2 either valid atags pointer, or zero
    283  *  r5, r6 corrupted
    284  */
    285 __vet_atags:
    286     tst    r2, #0x3            @ aligned?
    287     bne    1f
    288 
    289     ldr    r5, [r2, #0]            @ is first tag ATAG_CORE?
    290     cmp    r5, #ATAG_CORE_SIZE
    291     cmpne    r5, #ATAG_CORE_SIZE_EMPTY
    292     bne    1f
    293     ldr    r5, [r2, #4]
    294     ldr    r6, =ATAG_CORE
    295     cmp    r5, r6
    296     bne    1f
    297 
    298     mov    pc, lr                @ atag pointer is ok
    299 
    300 1:    mov    r2, #0
    301     mov    pc, lr
    302 ENDPROC(__vet_atags)
  • 相关阅读:
    Subversion 1.5.5 与 Apache 2.2 结合
    IE6 式样表 Bug
    Dreamweaver 禁止自动换行
    错误:Internet Explorer cannot open the Internet site
    Html Agility Pack – XPath 基本语法
    不要安装 CodeSmith 5.2
    控件包含代码块,因此无法修改控件集合
    单例模式
    第一篇博文
    包与导入的概念
  • 原文地址:https://www.cnblogs.com/guanglun/p/10730971.html
Copyright © 2020-2023  润新知