废话少说,接着上一篇继续分析我们的__create_page_tables函数。回顾一下前面的分析可以知道目前r8中存放的是machine_desc结构的地址,r9中存放的是cpu主标识,r10中存放的是proc_info_list结构的地址。
pgtbl r4
mov r3, #0
add r6, r0, #0x4000
1: str r3, [r0], #4
str r3, [r0], #4
str r3, [r0], #4
str r3, [r0], #4
teq r0, r6
bne 1b
mov r6, pc, lsr #20
orr r3, r7, r6, lsl #20
str r3, [r4, r6, lsl #2]
add r0, r4, #(KERNEL_START & 0xff000000) >> 18
str r3, [r0, #(KERNEL_START & 0x00f00000) >> 18]!
ldr r6, =(KERNEL_END - 1)
add r0, r0, #4
add r6, r4, r6, lsr #18
1: cmp r0, r6
add r3, r3, #1 << 20
strls r3, [r0], #4
bls 1b
add r0, r4, #PAGE_OFFSET >> 18
orr r6, r7, #(PHYS_OFFSET & 0xff000000)
.if (PHYS_OFFSET & 0x00f00000)
orr r6, r6, #(PHYS_OFFSET & 0x00f00000)
.endif
str r6, [r0]
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
arm920_crval:
crval clear=0x00003f3f, mmuset=0x00003135, ucset=0x00001130
#ifdef CONFIG_MMU
.word \clear
.word \mmuset
#else
.word \clear
.word \ucset
#endif
.endm
C1中的控制位 | 含义 |
M(bit[0]) | 0 :禁止 MMU 或者 PU 1 :使能 MMU 或者 PU 如果系统中没有MMU及PU,读取时该位返回0,写入时忽略该位 |
A(bit[1]) | 0 :禁止地址对齐检查 1 :使能地址对齐检查 |
C(bit[2]) | 当数据cache和指令cache分开时,本控制位禁止/使能数据cache。当数据cache和指令cache统一时,该控制位禁止/使能整个cache。 0 :禁止数据 / 整个 cache 1 :使能数据 / 整个 cache 如果系统中不含cache,读取时该位返回0.写入时忽略 当系统中不能禁止cache 时,读取时返回1.写入时忽略 |
W(bit[3]) | 0 :禁止写缓冲 1 :使能写缓冲 如果系统中不含写缓冲时,读取时该位返回0.写入时忽略 当系统中不能禁止写缓冲时,读取时返回1.写入时忽略 |
P(bit[4]) | 对于向前兼容26位地址的ARM处理器,本控制位控制PROG32控制信号 0 :异常中断处理程序进入 32 位地址模式 1 :异常中断处理程序进入26 位地址模式 如果本系统中不支持向前兼容26位地址,读取该位时返回1,写入时忽略 |
D(bit[5]) | 对于向前兼容26位地址的ARM处理器,本控制位控制DATA32控制信号 0 :禁止 26 位地址异常检查 1 :使能 26 位地址异常检查 如果本系统中不支持向前兼容26位地址,读取该位时返回1,写入时忽略 |
L(bit[6]) | 对于ARMv3及以前的版本,本控制位可以控制处理器的中止模型 0 :选择早期中止模型 1 :选择后期中止模型 |
B(bit[7]) | 对于存储系统同时支持big-endian和little-endian的ARM系统,本控制位配置系统的存储模式 0 : little endian 1 : big endian 对于只支持little-endian的系统,读取时该位返回0,写入时忽略 对于只支持big-endian的系统,读取时该位返回1,写入时忽略 |
S(bit[8]) | 在基于 MMU 的存储系统中,本位用作系统保护 |
R(bit[9]) | 在基于 MMU 的存储系统中,本位用作 ROM 保护 |
F(bit[10]) | 由生产商定义 |
Z(bit[11]) | 对于支持跳转预测的ARM系统,本控制位禁止/使能跳转预测功能 0 :禁止跳转预测功能 1 :使能跳转预测功能 对于不支持跳转预测的ARM系统,读取该位时返回0,写入时忽略 |
I(bit[12]) | 当数据cache和指令cache是分开的,本控制位禁止/使能指令cache 0 :禁止指令 cache 1 :使能指令 cache 如果系统中使用统一的指令cache和数据cache或者系统中不含cache,读取该位时返回0,写入时忽略。当系统中的指令cache不能禁止时,读取时该位返回1,写入时忽略 |
V(bit[13]) | 对于支持高端异常向量表的系统,本控制位控制向量表的位置 0 :选择低端异常中断向量 0x0~0x1c 1 :选择高端异常中断向量0xffff0000~ 0xffff001c 对于不支持高端异常向量表的系统,读取时该位返回0,写入时忽略 |
PR(bit[14]) | 如果系统中的cache的淘汰算法可以选择的话,本控制位选择淘汰算法 0 :常规的 cache 淘汰算法,如随机淘汰 1 :预测性淘汰算法,如round-robin 淘汰算法 如果系统中cache的淘汰算法不可选择,写入该位时忽略。读取该位时,根据其淘汰算法是否可以比较简单地预测最坏情况返回0或者1 |
L4(bit[15]) | 对于ARM版本5及以上的版本,本控制位可以提供兼容以前的ARM版本的功能 0 :保持 ARMv5 以上版本的正常功能 1 :将 ARMv5 以上版本与以前版本处理器 兼容,不根据跳转地址的 bit[0] 进行 ARM 指令和 Thumb 状态切换: bit[0] 等于 0 表示 ARM 指令,等于 1 表示 Thumb 指令 |
Bits[31:16]) | 这些位保留将来使用,应为UNP/SBZP |
__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
#define CR_C (1 << 2) /* Dcache enable */
#define CR_I (1 << 12) /* Icache enable */
#define DOMAIN_TABLE 2
#define DOMAIN_USER 1
#define DOMAIN_IO 0
#define DOMAIN_CLIENT 1
#define DOMAIN_MANAGER 3
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
.long __mmap_switched
.long __data_loc @ r4 存放数据的位置
.long __data_start @ r5 数据段起始的位置
.long __bss_start @ r6 bss段起始地址
.long _end @ r7 bss段结束地址
.long processor_id @ r4
.long __machine_arch_type @ r5
.long cr_alignment @ r6
.long init_thread_union + THREAD_START_SP @ sp
adr r3, __switch_data + 4
cmp r4, r5 @ 比较数据存放位置和数据起始位置
1: cmpne r5, r6 @不相等的话,比较数据段和bss段的起始地址是否相同
ldrne fp, [r4], #4 @如果数据存放位置和数据起始位置不等且数据段起始位置
strne fp, [r5], #4 @和bss段起始位置也不等则搬运数据
bne 1b
1: cmp r6, r7 @ 空
strcc fp, [r6],#4 @ bss
bcc 1b @ 段
str r9, [r4] @ r9中是processor_id,先存放到__switch_data结构的processor_id成员指向的地址
str r1, [r5] @ r1是bootloader传过来的machine type,现存放到__switch_data结构的__machine_arch_type成员指向的地址
bic r4, r0, #CR_A @ r0中存放的cp15中c1寄存器的值,现在打开地址对齐并保存到r4中
stmia r6, {r0, r4} @ cr_aligment和cr_no_alignment是定义在arch/arm/kernel/entry-armv.S中地址连续的两个全局变量
b start_kernel