作者

彭东林

pengdonglin137@163.com

平台

TQ2440

Qemu+vexpress-ca9

Linux-4.10.17

正文

继续分析head.S:

     ldr    r13, =__mmap_switched        @ address to jump to after
@ mmu has been enabled
badr lr, 1f @ return (PIC) address
mov r8, r4 @ set TTBR1 to swapper_pg_dir
ldr r12, [r10, #PROCINFO_INITFUNC]
add r12, r12, r10
ret r12
: b __enable_mmu

第1行将__mmp_switched标号的虚拟地址赋给r13,后面从__turn_mmu_on返回时会用到

第3行将1f标号的物理地址赋给lr,后面从__arm920_setup返回时会用到

第4行将段式页表的物理起始地址赋给r8,对于TQ2440来说,是0x3000_4000,对于vexpress是0x6000_4000

第5行,因为r10指向匹配到的proc_info_list结构体的首地址,对于TQ2440来说,偏移#PROCINFO_INITFUNC得到的是__arm920_setup 与__arm920_proc_info的差值,存放到r12中,此时r10存放的就是__arm920_proc_info物理地址

第6行,r10加r12就得到了__arm920_setup的物理地址,对于vexpress来说是__v7_ca9mp_setup

第7行,开始执行__arm920_setup,定义在arch/arm/mm/proc-arm920.S中

     .type    __arm920_setup, #function
__arm920_setup:
mov r0, #
mcr p15, , r0, c7, c7 @ invalidate I,D caches on v4
mcr p15, , r0, c7, c10, @ drain write buffer on v4 mcr p15, , r0, c8, c7 @ invalidate I,D TLBs on v4 adr r5, arm920_crval
ldmia r5, {r5, r6}
mrc p15, , r0, c1, c0 @ get control register v4
bic r0, r0, r5
orr r0, r0, r6
ret lr
.size __arm920_setup, . - __arm920_setup /*
* R
* .RVI ZFRS BLDP WCAM
* ..11 0001 ..11 0101
*
*/
.type arm920_crval, #object
arm920_crval:
crval clear=0x00003f3f, mmuset=0x00003135, ucset=0x00001130

这个函数执行一些开启MMU之前的准备工作。上面对cache、tlb的操作可以参考手册 ARM920T Technical Reference Manual 的2.3.11 Register 7, cache operations register和2.3.12 Register 8, TLB operations register

第14行执行完毕后,会跳转到前面所说的head.S中的1f标号处,也就是   b __enable_mmu

关于MMU的操作,可以参考手册 ARM920T Technical Reference Manual 的2.3.5 Register 1, control register

回到head.S继续分析。

 __enable_mmu:
#if defined(CONFIG_ALIGNMENT_TRAP) && __LINUX_ARM_ARCH__ < 6
orr r0, r0, #CR_A
#else
bic r0, r0, #CR_A
#endif mov r5, #DACR_INIT
mcr p15, , r5, c3, c0, @ load domain access register
mcr p15, , r4, c2, c0, @ load page table pointer b __turn_mmu_on

第10行将段表的物理起始地址设置到CP15的C2寄存器中,即0x30004000或者0x60004000,可以参考ARM920T Technical Reference Manual 的2.3.6 Register 2, translation table base (TTB) register

第12行准备打开MMU

下面开始打开MMU:

     .align
.pushsection .idmap.text, "ax"
ENTRY(__turn_mmu_on)
mov r0, r0
instr_sync
mcr p15, , r0, c1, c0, @ write control reg
mrc p15, , r3, c0, c0, @ read id reg
instr_sync
mov r3, r3
mov r3, r13
ret r3
__turn_mmu_on_end:
ENDPROC(__turn_mmu_on)
.popsection

第6行开启MMU, 由于之前已经建立了映射这部分的段表,所以程序可以继续执行,不会出错

第10行,r13中存放的是__mmap_switched的虚拟地址

第11行,开始跳到__mmap_switched处执行,自此以后的虚拟地址就跟链接地址相同了

__mmap_switched定义在arch/arm/kernel/head-common.S中:

 __mmap_switched:
adr r3, __mmap_switched_data ldmia r3!, {r4, r5, r6, r7}
cmp r4, r5 @ Copy data segment if needed
: cmpne r5, r6
ldrne fp, [r4], #
strne fp, [r5], #
bne 1b mov fp, # @ Clear BSS (and zero fp)
: cmp r6, r7
strcc fp, [r6],#
bcc 1b ARM( 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
cmp r7, #
strne r0, [r7] @ Save control register values
b start_kernel
ENDPROC(__mmap_switched) .align
.type __mmap_switched_data, %object
__mmap_switched_data:
.long __data_loc @ r4
.long _sdata @ 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
.size __mmap_switched_data, . - __mmap_switched_data

这里主要关注一下第16到第23行,这里将r9中存放的CPU ID赋给processor_id, 将dtb所在的物理地址赋给__atags_pointer,将sp设置为init_thread_union + THREAD_START_SP, 这里init_thread_union定义在init/init_task.c中,THREAD_START_SP的值是(8KB-8),也就是sp指向init进程的内核栈。然后第23行跳转到init/main.c中的start_kernel。

完。

Linux内存管理学习3 —— head.S中的段页表的建立的更多相关文章

  1. Linux内存管理学习1 —— head.S中的段页表的建立

    作者 彭东林 pengdonglin137@163.com 平台 TQ2440 Qemu+vexpress-ca9 Linux-4.10.17 概述 在Linux自解压完毕后,开始执行arch/arm ...

  2. Linux内存管理学习2 —— head.S中的段页表的建立

    作者 彭东林 pengdonglin137@163.com 平台 TQ2440 Qemu+vexpress-ca9 Linux-4.10.17 正文 继续分析head.S: 此时r2存放的是设备树镜像 ...

  3. Linux内存管理学习资料

    下面是Linux内存管理学习的一些资料. 博客 mlock() and mlockall() system calls. All about Linux swap space 逆向映射的演进 Linu ...

  4. Linux内存管理学习笔记 转

    https://yq.aliyun.com/articles/11192?spm=0.0.0.0.hq1MsD 随着要维护的服务器增多,遇到的各种稀奇古怪的问题也会增多,要想彻底解决这些“小”问题往往 ...

  5. Linux内存管理学习笔记——内存寻址

    最近开始想稍微深入一点地学习Linux内核,主要参考内容是<深入理解Linux内核>和<深入理解Linux内核架构>以及源码,经验有限,只能分析出有限的内容,看完这遍以后再更深 ...

  6. 郝健: Linux内存管理学习笔记-第1节课【转】

    本文转载自:https://blog.csdn.net/juS3Ve/article/details/80035751 摘要 MMU与分页机制 内存区域(内存分ZONE) LinuxBuddy分配算法 ...

  7. 郝健: Linux内存管理学习笔记-第2节课【转】

    本文转载自:https://blog.csdn.net/juS3Ve/article/details/80035753 摘要 slab./proc/slabinfo和slabtop 用户空间mallo ...

  8. Linux内存管理学习笔记--物理内存分配

    http://blog.chinaunix.net/uid-20321537-id-3466022.html

  9. C++内存管理学习笔记(7)

    /****************************************************************/ /*            学习是合作和分享式的! /* Auth ...

随机推荐

  1. MySQL多源复制【转】

    什么是多源复制? 首先,我们需要清楚 multi-master 与multi-source 复制不是一样的. Multi-Master 复制通常是环形复制, 你可以在任意主机上将数据复制给其他主机. ...

  2. 关于RestFul API 介绍与实践

    之前演示的PPT,直接看图...     •参考链接: •RESTful API 设计最佳实践 •RESTful API 设计指南 •SOAPwebserivce和RESTfulwebservice对 ...

  3. selenium之 chromedriver与chrome版本映射表(更新至v2.34)

    看到网上基本没有最新的chromedriver与chrome的对应关系表,便兴起整理了一份如下,希望对大家有用: chromedriver版本 支持的Chrome版本 v2.34 v61-63 v2. ...

  4. ScheduledThreadExecutor定时任务线程池

    ScheduledThreadPoolExecutor 继承自ThreadPoolExecutor实现了ScheduledExecutorService接口.主要完成定时或者周期的执行线程任务. 代码 ...

  5. 测试开发之Django——No2.Django的安装以及项目创建

    开发平台:Mac Python版本:3.7 Django版本:2.0.5 一.Django的安装 1.pip安装 输入命令pip install Django==2.0.5 说明:不指定版本,则安装的 ...

  6. 面试经典---数据库索引B+、B-树

    大型数据库数据都是存在硬盘中的,为了操作的速度,需要设计针对外存的数据结构.而数据库索引技术就是在面试中反复被问到的一个问题:数据库索引是怎么实现的?数据库索引越大越好吗? 需要详细了解下这方面的知识 ...

  7. RandomForest随机森林总结

    1.随机森林原理介绍 随机森林,指的是利用多棵树对样本进行训练并预测的一种分类器.该分类器最早由Leo Breiman和Adele Cutler提出,并被注册成了商标.简单来说,随机森林就是由多棵CA ...

  8. SqlServer批量Sql一个表的数据导入到另一个数据

    一个表的导入: SET IDENTITY_INSERT [master_new].[dbo].[OpinionList] ON INSERT INTO [master_new].[dbo].[Opin ...

  9. Java编程的逻辑 (11) - 初识函数

    本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http:/ ...

  10. hdu 2923 map+Floyd 拉破车

    有向图 具体方向看箭头 从起点到指定城市拉破车,一个城市可能有多个破车,一次只能拉一辆破车 也就是到了指定地点后要回到起点 假如有100辆破车 但是只有一个城市有 就得在起点与这个城市间往返100次所 ...