日期:2014-05-16  浏览次数:20770 次

linux内存管理初始化
内存管理子系统是linux内核最核心最重要的一部分,内核的其他部分都需要在内存管理子系统的基础上运行。而对其初始化是了解整个内存管理子系统的基础。对相关数据结构的初始化是从全局启动例程start_kernel开始的。本文详细描述了从bootloader跳转到linux内核内存管理子系统初始化期间所做的操作,从而来加深对内存管理子系统知识的理解和掌握。

内核的入口是stext,这是在arch/arm/kernel/vmlinux.lds.S中指定的。而符号stext是在arch/arm/kernel/head.S中定义的。整个初始化分为两个阶段,首先是在head.S中用汇编代码执行一些平台相关的初始化,完成后跳转到start_kernel函数用C语言代码执行剩余的通用初始化部分。整个初始化流程图如下图所示:


一、     启动条件
通常从系统上电到运行到linux kenel这部分的任务是由boot loader来完成。Boot loader在跳转到kernel之前要完成一些限制条件:

1、CPU必须处于SVC(supervisor)模式,并且IRQFIQ中断必须是禁止的;

2、MMU(内存管理单元)必须是关闭的, 此时虚拟地址对应物理地址;

3、数据cache(Data cache)必须是关闭的;

4、指令cache(Instruction cache)没有强制要求;

5、CPU通用寄存器0(r0)必须是0;

6、CPU通用寄存器1(r1)必须是ARM Linux machine type

7、CPU通用寄存器2(r2)必须是kernel parameter list的物理地址;

二、     汇编代码初始化部分

汇编代码部分主要完成的工作如下所示,下文只是概述head.S中各个函数完成的主要

功能,具体的技术细节,本文不再赘述。

? 确定processor type

? 确定machine type

? 创建页表

? 调用平台特定的__cpu_flush函数

? 开启mmu

? 切换数据

? 最终跳转到start_kernel

三、     C语言代码初始化部分

C语言代码初始化部分主要负责建立结点和内存域的数据结构、初始化页表、初始化用

于内存管理的伙伴系统。在启动过程中,尽管内存管理模块尚未初始化完成,但内核仍然需要分配内存以创建各种数据结构。bootmem分配器用于在启动阶段分配内存。所有涉及的实现都是在start_kernel函数中实现的,其中涉及到内存初始化的函数如下:

1、 build_all_zonelist用于结点和内存域的初始化。

在linux系统中,内存划分结点,每个结点关联到系统中的一个处理器。各个结点又划分内存域,主要包括ZONE_DMA、ZONE_NOR