***************************************************************************************************************************
作者:EasyWave 时间:2012.02.18
类别:linux驱动开发 声明:转载,请保留链接
***************************************************************************************************************************
一: Linux kernel内存存布局
在ARM平台中zImage.bin是一个压缩镜像,它用于将被压缩的kernel解压缩到KERNEL_RAM_PADDR开始的一段内存中,接着跳进真正的kernel去执行。该kernel的执行起点是stext函数,定义于arch/arm/kernel/head.S。在分析ENTRY(stext)前,先介绍此时内存的布局如下图所示:
图一:内存布局[此处借用下网络上已有的图片,自己不想弄图片了]
在我的YL-E2410的平台上,SDRAM的开始内存地址是0x30000000,大小为64M,即0x20000000。 Linux2.6.38.8 ARM kernel将SDRAM的开始地址定义为PHYS_OFFSET。经bootloader加载kernel并由自解压部分代码运行后,最终kernel被放置到KERNEL_RAM_PADDR(=PHYS_OFFSET + TEXT_OFFSET,即0x30008000)地址上的一段内存,经此放置后,kernel代码以后均不会被移动。在arch\arm\mach-s3c2410\Makefile.boot文件,其内容如下:
zreladdr-y := 0x30008000
params_phys-y := 0x30000100
这也验证了为什么内核会被放置在0x30008000的地方了,这个地址必须由Makefile.boot指定。而params_phys-y则是linux Kernel的taglist等参数的起始地址。在进入kernel代码前,即自解压缩阶段,ARM未开启MMU功能。因此启动代码一个重要功能是设置好相应的页表,并开启MMU功能。为了支持MMU功能,kernel镜像中的所有符号,包括代码段和数据段的符号,在链接时都生成了它在开启MMU时,所在物理内存地址映射到的虚拟内存地址。Kernel第一个符号stext为例,在编译链接,它生成的虚拟地址是0xc0008000,而放置它的物理地址为0x30008000。实际上这个变换可以利用简单的公式进行表示:va = pa – PHYS_OFFSET + PAGE_OFFSET。Arm linux最终的kernel空间的页表,就是按照这个关系来建立。之所提及linux的内存映射,原因是在进入kernel代码,里面所有符号地址值为0xCxxxxxxx地址,而此时ARM未开启MMU功能,故在执行stext函数第一条执行时,它的PC值就是stext所在的内存地址(即物理地址,0x30008000)。
二:stext函数详解
stext函数定义在arch/arm/kernel/head.S,它的功能是获取处理器类型和机器类型信息,并创建临时的页表,然后开启MMU功能,并跳进第一个C语言函数start_kernel。stext函数的在前置条件是:MMU, D-cache, 关闭; r0 = 0, r1 = machine nr, r2 = atags prointer.
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Kernel startup code for all 32-bit CPUs
*/
#include <linux/linkage.h>
#include <linux/init.h>
#include <asm/assembler.h>
#include <asm/domain.h>
#include <asm/ptrace.h>
#include <asm/asm-offsets.h>
#include <asm/memory.h>
#include <asm/thread_info.h>
#include <asm/system.h>
#ifdef CONFIG_DEBUG_LL
#include <mach/debug-macro.S&g