str r9, [r6]//将r9处理器ID值转存入变量processor_id中,供c程序调用
str r1, [r7]//将r7体系结构指针的machine_desc转存入变量__machine_arch_type中,供c程序调用
#ifdef CONFIG_ALIGNMENT_TRAP
orr r0, r0, #2//r0为cp15协处理器c1中控制值
#endif
bic r2, r0, #2//取消掉故障校验后的数值存入r2
stmia r8, {r0, r2}//cr_alignment = r0;其后存储(init_task_union)+8192数值的空间存入r2
b SYMBOL_NAME(start_kernel)
//好了,我的分析到此结束,由u-boot1.1.5完成解压的启动部分,转入c代码start_kernel,作更复杂的启动[gliethttp 2007-07-25]
__create_page_tables:
//通过前面的分析已知r5 = 体系结构指针下对应的machine_desc->phys_ram物理内存地址
//但pgtbl宏并没有使用到r5,而是直接使用stext,
pgtbl r4, r5
//所以此时r4=物理地址=0x2000
mov r0, r4
mov r3, #0
add r2, r0, #0x4000//r2=0x20008000
1: str r3, [r0], #4
str r3, [r0], #4
str r3, [r0], #4
str r3, [r0], #4//将0x20004000~0x20008000这16k空间清0
teq r0, r2
bne 1b
//ok,清0结束[gliethttp]
krnladr r2, r4, r5//bic r2,r4,#0x000ff000;将ff处对应的1数据清0
//所以r2 = 0x20000000
//通过前面的分析r8=0x00000c1e
//在进行下面的分析之前,最好先看看另一篇文章
//《linux2.4.19下__ioremap函数中remap_area_pages虚拟地址映射建立函数的代码分析》[http://gliethttp.cublog.cn]
//熟悉一下MMU的表结构
//MMU对4种大小进行映射管理,
//1)微页:构成1k的存储区
//2)小页:构成4k的存储区
//3)大页:构成64k的存储区
//4)节:构成1M的存储区
add r3, r8, r2
//r2=0x20000000
//r3=0x20000000+0x00000c1e=0x20000c1e
//r4=0x20004000
//r2>>18剩下的高14位,即16K地址,4k个4字节组地址单元,用于一级表映射bit31~bit20节基址匹配
str r3, [r4, r2, lsr #18]//r4为转换表基
//>>18位,剩余14位,而不是12位,是高12位节基址*4字节存储地址的结果,是bit31~bit20节基址索引×4字节的结果
//表示虚拟地址节0x20000000~0x200fffff对应物理地址节0x20000000~0x200fffff
add r0, r4, #(TEXTADDR & 0xff000000) >> 18
bic r2, r3, #0x00f00000
//r2 = 0x20000c1e
str r2, [r0]
//表示虚拟地址节0xc0000000~0xc00fffff对应物理地址节0x20000000~0x200fffff
add r0, r0, #(TEXTADDR & 0x00f00000) >> 18
//接下来开始依次线性节映射[gliethttp 2007-07-25]
str r3, [r0], #4
//表示虚拟地址节0xc0000000~0xc00fffff对应物理地址节0x20000000~0x200fffff
//r3=0x20000c1e表项值,r0=r0+4,r0指向下一个连续的虚拟地址1M节基址
add r3, r3, #1 << 20
//r3=r3+1M指向下一物理地址节基址
str r3, [r0], #4
//表示虚拟地址节0xc0100000~0xc01fffff对应物理地址节0x20100000~0x201fffff
//r0指向下一个连续的虚拟地址1M节基址
add r3, r3, #1 << 20
//r3=r3+1M指向下一物理地址节基址
str r3, [r0], #4
//表示虚拟地址节0xc0200000~0xc02fffff对应物理地址节0x20200000~0x202fffff
//r0指向下一个连续的虚拟地址1M节基址
add r3, r3, #1 << 20
//r3=r3+1M指向下一物理地址节基址
str r3, [r0], #4
//表示虚拟地址节0xc0300000~0xc03fffff对应物理地址节0x20300000~0x203fffff
//r0指向下一个连续的虚拟地址1M节基址
//这样0xc0000000~0xc03fffff 4M虚拟地址空间和0x20000000~0x200fffff 1M虚拟地址空间
//都线性的映射到了0x20000000~0x203fffff 4M物理地址空间
bic r0, r0, #0x01f00000 >> 18//0x1f=32M空间对齐
and r2, r5, #0xfe000000//对于传递的参数r5-物理内存地址空间
add r3, r8, r2
str r3, [r0]//最后还是0x20000000~0x200fffff虚拟地址到0x20000000~0x200fffff物理地址映射
//如果r5的值和内核拷贝到的内存中的位置值不符,真不知会是什么想象,不过还好,他们相等.
bic r8, r8, #0x0c
#ifdef CONFIG_DEBUG_LL
add r0, r4, r7//r7为debug串口显示物理寄存器对应的虚拟地址对应的节基址
rsb r3, r7, #0x4000//r3=0x4000-r3=距离0x3fff还有多少个地址空间
cmp r3, #0x0800//0xE0000000空间
addge r2, r0, #0x0800//r7对应的虚拟空间<=0xE0000000,加上0x20000000,
//调整到0xE0000000~0xFFFFFFFF虚拟空间
addlt r2, r0, r3//r7对应的虚拟空间>0xE0000000,r2=计算出的io虚拟地址映射的大小
orr r3, r6, r8//r6对应串口物理寄存器的物理地址|| r8这个节标志
1: str r3, [r0], #4//将虚拟地址r0所在的1M空间映射到物理地址r3所在的1M空间中,之后r0虚拟地址1M节索引r0+4指向下一节
add r3, r3, #1 << 20//进入物理地址空间的下一个1M节
teq r0, r2//是否映射完毕
bne 1b//
#if defined(CONFIG_ARCH_NETWINDER) || defined(CONFIG_ARCH_CATS)
teq r1, #MACH_TYPE_NETWINDER//非该类型,是MACH_TYPE_AT91RM9200类型
teqne r1, #MACH_TYPE_CATS//也非该类型
bne 1f//跳到下一个标号1:处
add r0, r4, #0x3fc0
mov r3, #0x7c000000
orr r3, r3, r8
str r3, [r0], #4
add r3, r3, #1 << 20
str r3, [r0], #4
1:
#endif
#endif
#ifdef CONFIG_ARCH_RPC//未定义
add r0, r4, #0x80
mov r3, #0x02000000
orr r3, r3, r8
str r3, [r0]
add r0, r4, #0x3600
str r3, [r0]
#endif
mov pc, lr//返回
__error:
#ifdef CONFIG_DEBUG_LL//实现了串口输出,那么将错误信息打印到串口终端
mov r8, r0
adr r0, err_str
bl printascii//打印"\nError: "字符串
mov r0, r8
bl printch//打印
#endif
#ifdef CONFIG_ARCH_RPC
mov r0, #0x02000000
mov r3, #0x11
orr r3, r3, r3, lsl #8
orr r3, r3, r3, lsl #16
str r3, [r0], #4
str r3, [r0], #4
str r3, [r0], #4
str r3, [r0], #4
#endif
1: mov r0, r0//系统因为错误halt在此处
b 1b
#ifdef CONFIG_DEBUG_LL
err_str: .asciz "\nError: "
.align
#endif
__lookup_processor_type:
adr r5, 2f//伪指令adr,读取下面第一个2:标号处的和pc相对的物理地址
ldmia r5, {r7, r9, r10}
//r7=虚拟地址__proc_info_end
//r9=虚拟地址__proc_info_begin
//r10=虚拟地址2b=标号2处的地址值[虚拟地址-反汇编得0xc00081b8]
//所以r5=0x200081b8
sub r5, r5, r10//计算标号2物理地址和虚拟地址的间距r5 = 0x200081b8-0xc00081b8;
add r7, r7, r5 //将r7中的线性虚拟地址转换成与之线性对应的物理地址,结果存入r7
add r10, r9, r5//同样计算r9中存放的虚拟地址,对应的物理地址,结果存入r10
mrc p15, 0, r9, c0, c0//通过协处理器cp15,获取cpu的型号,对于at91rm9200,r9=0x41129200
//r7 = __proc_info_end结束的物理地址
//r9 = 处理器ID
//r10 = 处理器结构体的指针
1: ldmia r10, {r5, r6, r8}//读取编译进r10为起始物理地址的__proc_info_begin结构体信息
//++++++++++++++
//arch/arm/mm/proc-arm9200.S中定义了该结构体信息
// .section ".proc.info", #alloc, #execinstr
// .type __arm920_proc_info,#object
//__arm920_proc_info:
// .long 0x41009200
// .long 0xff00fff0
// .long 0x00000c1e @ mmuflags
// b __arm920_setup
// .long cpu_arch_name
// .long cpu_elf_name
// .long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB
// .long cpu_arm920_info
// .long arm920_processor_functions
// .size __arm920_proc_info, . - __arm920_proc_info
//--------------
//所以r5 = 0x41009200
//r6 = 0xff00fff0
//r8 = 0x00000c1e
and r6, r6, r9//r6 = r6 & r9 = 0x41009200
teq r5, r6
moveq pc, lr//因为处理器类型匹配,返回
add r10, r10, #36//如果多处理器,那sizeof(__arm920_proc_info)=0x24=36,r10指向下一个处理器单元
cmp r10, r7
blt 1b//如果没有遍历所有处理器类型,那么跳到标号1:处,继续匹配
mov r10, #0//没有找到匹配的处理器
mov pc, lr
2: .long __proc_info_end
.long __proc_info_begin
.long 2b
.long __arch_info_begin
.long __arch_info_end
__lookup_architecture_type:
adr r4, 2b//伪指令,读取上面第一个2:标号处的和pc相对的物理地址
ldmia r4, {r2, r3, r5, r6, r7}
//r2 = 虚拟地址__proc_info_end
//r3 = 虚拟地址__proc_info_begin
//r5 = 虚拟地址标号2:
//r6 = 虚拟地址__arch_info_begin
//r7 = 虚拟地址__arch_info_end
sub r5, r4, r5//和__lookup_processor_type一样,计算虚拟地址和物理地址的线性偏移量
add r4, r6, r5//r4=__arch_info_begin的物理地址
add r7, r7, r5//r7=__arch_info_end的物理地址
//++++++++++++++
//arch/arm/mach-at91rm9200/Core.c
//MACHINE_START(AT91RM9200, "ATMEL AT91RM9200")//.nr = MACH_TYPE_##_type=MACH_TYPE_AT91RM9200=251
//与上面从u-boot传到r1中的一样[gliethttp]
//MAINTAINER("SAN People / ATMEL")
//BOOT_MEM(AT91_SDRAM_BASE, AT91C_BASE_SYS, AT91C_VA_BASE_SYS)
//BOOT_PARAMS(AT91_SDRAM_BASE + 0x100)//tag list存放的物理地址0x20000100[gliethttp]
//FIXUP(at91rm9200_fixup)
//MAPIO(at91rm9200_map_io)
//INITIRQ(at91rm9200_init_irq)
//MACHINE_END
//--------------
1: ldr r5, [r4]
teq r5, r1//与r1传入的MACH_TYPE_AT91RM9200=251数值匹配
beq 2f//匹配上,则跳到下一个标号2:处,退出
add r4, r4, #SIZEOF_MACHINE_DESC//r4+sizeof(machine_desc),指向下一个体系结构体的物理地址
cmp r4, r7
blt 1b//.arch.info体系结构是否已经遍历结束
mov r7, #0//没有找到与r1类型匹配的体系结构
mov pc, lr
2: ldmib r4, {r5, r6, r7}//先加后装载
//所以r5 = machine_desc->phys_ram
//r6 = machine_desc->phys_io
//r7 = machine_desc->io_pg_offst
mov pc, lr