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)
原文地址:https://www.cnblogs.com/guanglun/p/10730971.html