`

Android培训班(103)内核入口汇编3

 
阅读更多

从前面可知由CPU的初始化函数里把MMU相关寄存器的值保存到r0寄存器,这样就传送给函数__enable_mmu,以便设置到MMU的寄存器里。函数__enable_mmu的代码如下:

__enable_mmu:

#ifdefCONFIG_ALIGNMENT_TRAP

orr r0, r0, #CR_A

#else

bic r0, r0, #CR_A

#endif

#ifdefCONFIG_CPU_DCACHE_DISABLE

bic r0, r0, #CR_C

#endif

#ifdefCONFIG_CPU_BPREDICT_DISABLE

bic r0, r0, #CR_Z

#endif

#ifdefCONFIG_CPU_ICACHE_DISABLE

bic r0, r0, #CR_I

#endif

这段代码是设置r0寄存器里MMU相关的参数。


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

这里是把页目录地址r4寄存器的设置到页目录寄存器C2


b __turn_mmu_on

这里跳到MMU打开的函数运行。


ENDPROC(__enable_mmu)


这个函数主要修改r0寄存器里MMU相关的参数,设置页目录访问的权限,设置页目录的地址到C2寄存器,最后跳到函数__turn_mmu_on里继续执行打开MMU的操作。函数__turn_mmu_on的代码如下:

__turn_mmu_on:

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

ENDPROC(__turn_mmu_on)

这段代码比较简单,主要把r0MMU参数设置到C1寄存器里,然后再读取到r3寄存器,这样就把CPU设置为打开MMU了,进入虚拟地址变换处理。在设置后面进行两条无用的指令,以便TLB可以加载页目录到缓存里,最后通过mov pc,r13指令,就把__mmap_switched函数的虚拟地址切换到当前执行指令寄存器里,因为__switch_data结构的第一个参数就是函数__mmap_switched的地址。


由前面可知,已经把函数__mmap_switched地址给PC寄存器,那么就会运行这个函数的代码,这个函数的代码如下:

.type __switch_data,%object

__switch_data:

.long __mmap_switched

.long __data_loc @r4

.long __data_start @r5

.long __bss_start @r6

.long _end @ r7

.long processor_id @r4

.long __machine_arch_type @r5

.long __atags_pointer @r6

.long cr_alignment @r7

.long init_thread_union+ THREAD_START_SP @ sp

这段代码是定义切换分页的数据结构。


/*

* The followingfragment of code is executed with the MMU on in MMU mode,

* and uses absoluteaddresses; this is not position independent.

*

* r0 = cp#15control register

* r1 = machine ID

* r2 = atagspointer

* r9 = processorID

*/

__mmap_switched:

adr r3,__switch_data + 4


ldmia r3!, {r4, r5,r6, r7}

获取数据段和全局数据段的开始位置。


cmp r4, r5 @ Copydata segment if needed

1: cmpne r5, r6

ldrne fp, [r4], #4

strne fp, [r5], #4

bne 1b

如果数据段需要重定位,就拷贝数据段的内容。


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

1: cmp r6, r7

strcc fp, [r6],#4

bcc 1b

清空BSS段的内容。


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

str r9, [r4] @Save processor ID

str r1, [r5] @Save machine type

str r2, [r6] @Save atags pointer

保存参数到__switch_data结构里。


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

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

保存控制寄存器。


b start_kernel

这里就跳到C语言的开始函数start_kernel运行了。

ENDPROC(__mmap_switched)


从这个函数就开始进入C语言初始化函数start_kernel,终于完成汇编代码的初始化动作,并且进入简单的分页内存管理机制。而start_kernel函数是在文件kernel/init/mail.c里定义,下一次继续这个文件里开始分析。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics