本文是基于arm平台。例子都是以tiny210(s5pv210 armv7)为基础的。
[kernel 启动流程]系列:
- [kernel 启动流程] 前篇——vmlinux.lds分析
- [kernel 启动流程] (第一章)概述
- [kernel 启动流程] (第二章)第一阶段之——设置SVC、关闭中断
- [kernel 启动流程] (第三章)第一阶段之——proc info的获取
- [kernel 启动流程] (第四章)第一阶段之——dtb的验证
- [kernel 启动流程] (第五章)第一阶段之——临时内核页表的创建
- [kernel 启动流程] (第六章)第一阶段之——打开MMU
- [kernel 启动流程] (第七章)第一阶段之——跳转到start_kernel
建议参考文档:
================================================
零、说明
本文是《[kernel 启动流程] (第一章)概述》的延伸,
阅读本文前建议先阅读《[kernel 启动流程] (第一章)概述》
1、kernel启动流程第一阶段简单说明
arch/arm/kernel/head.S
- kernel入口地址对应stext
ENTRY(stext)
第一阶段要做的事情,也就是stext的实现内容
- 设置为SVC模式,关闭所有中断
- 获取CPU ID,提取相应的proc info
- 验证tags或者dtb
- 创建临时内核页表的页表项
- 配置r13寄存器,也就是设置打开MMU之后要跳转到的函数。
- 使能MMU
- 跳转到start_kernel,也就是跳转到第二阶段
本文要介绍的是“创建临时内核页表的页表项”的部分。
2、疑问
主要带着以下几个问题去理解
- 什么是MMU?以及其和页表之间的关系?
- 页表内容?页表格式?如何进行创建?
3、对应代码实现
__HEAD
ENTRY(stext)
ldr r8, =PLAT_PHYS_OFFSET @ always constant in this case
/*
* r1 = machine no, r2 = atags or dtb,
* r8 = phys_offset, r9 = cpuid, r10 = procinfo
*/
bl __create_page_tables
__create_page_tables的工作就是创建临时内核页表。而创建临时内核页表则是为了打开MMU功能。
一、MMU和页表简单介绍
以下只是为了理解很简单地进行介绍。
并且主要介绍段式管理的工作原理。
1、MMU简单介绍
MMU是Memory Management Unit的缩写,中文名是内存管理单元,它是中央处理器(CPU)中用来管理虚拟存储器、物理存储器的控制线路。
其主要功能如下:
将线性地址映射为物理地址
所谓线性地址就是指虚拟地址,而物理地址就是指实际在RAM上的地址提供硬件机制的内存访问授权
2、页表介绍
MMU工作的核心是页表,也就是其根据页表来找到映射关系以及权限。
页表由页表项构成,每一个虚拟地址映射区都会有一个对应的页表项。
arm的页表有如下分类(在本章中使用的是段式管理,所以这里只说明段式管理):
- 段式管理页表
在arm打开MMU初期,使用的是临时内核页表,其类型就是段式页表。
段式页表将4GB的地址空间(32bit系统)划分成4096个1MB的段,因此段式页表有4096个页表项,每个页表项有32bit(4 byte),故段式页表需要16KB的空间
页表项格式如下:
位号 | 功能 |
---|---|
31:20 bit | 段序号 |
20: 0 bit | MMU flag |
3、arm上MMU的工作原理
arm将页表基地址存放在协处理器cp15的c2寄存器上,具体参考《ARM的CP15协处理器的寄存器》。
如下说明:
CP15 中的寄存器 C2 保存的是页表的基地址,即一级映射描述符表的基地址。
arm的MMU会根据虚拟地址计算出其相应页表项的偏移,从cp15的c2寄存器中获取页表基址之后,加上偏移得到对应的页表项地址。后续操作就是根据页表结构来做的。这些动作都是MMU硬件处理!
如果是段式页表的话,再根据段内偏移以及页表项中的物理段基址最终得到对应的物理地址。
段式管理页表工作举例(先不关心MMU flag):
假设
(1) 页表基地址为0x0(存放在CP15的c2寄存器上).
(2) 0xc0000000所在段(也就是段序号为0xc00)的页表项地址0x3000,
(3) 页表项地址0x3000的值为0x20000000(也就是段序号为0x300).
当虚拟地址为0xc0001000,计算方式如下
(1) 左移20位的得到虚拟地址所在段序号为0xc00,获取低20位得到段内偏移为0x1000
(2) 计算对应页表项地址=页表基地址0x0+段序号0xc00*页表项长度4=0x3000.
(3) 0x3000地址上的值为0x20000000,提取高12位得到0x200,所以对应物理段基址为0x20000000
(