armlinux从入口到startkernel代码详细分析2.docx
- 文档编号:18566956
- 上传时间:2023-08-19
- 格式:DOCX
- 页数:17
- 大小:54.12KB
armlinux从入口到startkernel代码详细分析2.docx
《armlinux从入口到startkernel代码详细分析2.docx》由会员分享,可在线阅读,更多相关《armlinux从入口到startkernel代码详细分析2.docx(17页珍藏版)》请在冰点文库上搜索。
armlinux从入口到startkernel代码详细分析2
1.确定processortype
arch/arm/kernel/head.S中:
00075:
mrcp15,0,r9,c0,c0 @getprocessorid
00076:
bl__lookup_processor_type @r5=procinfor9=cpuid
00077:
movsr10,r5 @invalidprocessor(r5=0)?
00078:
beq__error_p @yes,error'p'
75行:
通过cp15协处理器的c0寄存器来获得processorid的指令.关于cp15的详细内容可参考相关的arm手册
76行:
跳转到__lookup_processor_type.在__lookup_processor_type中,会把processortype存储在r5中
77,78行:
判断r5中的processortype是否是0,如果是0,说明是无效的processortype,跳转到__error_p(出错)
__lookup_processor_type函数主要是根据从cpu中获得的processorid和系统中的proc_info进行匹配,将匹配到的proc_info_list的基地址存到r5中,0表示没有找到对应的processortype.
下面我们分析__lookup_processor_type函数
arch/arm/kernel/head-common.S中:
00145:
.type__lookup_processor_type,%function
00146:
__lookup_processor_type:
00147:
adrr3,3f
00148:
ldmdar3,{r5-r7}
00149:
subr3,r3,r7 @getoffsetbetweenvirt&phys
00150:
addr5,r5,r3 @convertvirtaddressesto
00151:
addr6,r6,r3 @physicaladdressspace
00152:
1:
ldmiar5,{r3,r4} @value,mask
00153:
andr4,r4,r9 @maskwantedbits
00154:
teqr3,r4
00155:
beq2f
00156:
addr5,r5,#PROC_INFO_SZ @sizeof(proc_info_list)
00157:
cmpr5,r6
00158:
blo1b
00159:
movr5,#0 @unknownprocessor
00160:
2:
movpc,lr
00161:
00162:
00165:
ENTRY(lookup_processor_type)
00166:
stmfdsp!
{r4-r7,r9,lr}
00167:
movr9,r0
00168:
bl__lookup_processor_type
00169:
movr0,r5
00170:
ldmfdsp!
{r4-r7,r9,pc}
00171:
00172:
00176:
.long__proc_info_begin
00177:
.long__proc_info_end
00178:
3:
.long.
00179:
.long__arch_info_begin
00180:
.long__arch_info_end
145,146行是函数定义
147行:
取地址指令,这里的3f是向前symbol名称是3的位置,即第178行,将该地址存入r3.
这里需要注意的是,adr指令取址,获得的是基于pc的一个地址,要格外注意,这个地址是3f处的"运行时地址",由于此时MMU还没有打开,也可以理解成物理地址(实地址).(详细内容可参考arm指令手册)
148行:
因为r3中的地址是178行的位置的地址,因而执行完后:
r5存的是176行符号__proc_info_begin的地址;
r6存的是177行符号__proc_info_end的地址;
r7存的是3f处的地址.
这里需要注意链接地址和运行时地址的区别.r3存储的是运行时地址(物理地址),而r7中存储的是链接地址(虚拟地址).
__proc_info_begin和__proc_info_end是在arch/arm/kernel/vmlinux.lds.S中:
00031:
__proc_info_begin=.;
00032:
*(.proc.info.init)
00033:
__proc_info_end=.;
这里是声明了两个变量:
__proc_info_begin和__proc_info_end,其中等号后面的"."是locationcounter(详细内容请参考ld.info)
这三行的意思是:
__proc_info_begin的位置上,放置所有文件中的".proc.info.init"段的内容,然后紧接着是__proc_info_end的位置.
kernel使用structproc_info_list来描述processortype.
在include/asm-arm/procinfo.h中:
00029:
structproc_info_list{
00030:
unsignedint cpu_val;
00031:
unsignedint cpu_mask;
00032:
unsignedlong __cpu_mm_mmu_flags;
00033:
unsignedlong __cpu_io_mmu_flags;
00034:
unsignedlong __cpu_flush;
00035:
constchar *arch_name;
00036:
constchar *elf_name;
00037:
unsignedint elf_hwcap;
00038:
constchar *cpu_name;
00039:
structprocessor*proc;
00040:
structcpu_tlb_fns*tlb;
00041:
structcpu_user_fns*user;
00042:
structcpu_cache_fns*cache;
00043:
};
我们当前以at91为例,其processor是926的.
在arch/arm/mm/proc-arm926.S中:
00464:
.section".proc.info.init",#alloc,#execinstr
00465:
00466:
.type__arm926_proc_info,#object
00467:
__arm926_proc_info:
00468:
.long0x41069260 @ARM926EJ-S(v5TEJ)
00469:
.long0xff0ffff0
00470:
.long PMD_TYPE_SECT|\
00471:
PMD_SECT_BUFFERABLE|\
00472:
PMD_SECT_CACHEABLE|\
00473:
PMD_BIT4|\
00474:
PMD_SECT_AP_WRITE|\
00475:
PMD_SECT_AP_READ
00476:
.long PMD_TYPE_SECT|\
00477:
PMD_BIT4|\
00478:
PMD_SECT_AP_WRITE|\
00479:
PMD_SECT_AP_READ
00480:
b__arm926_setup
00481:
.longcpu_arch_name
00482:
.longcpu_elf_name
00483:
.longHWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_VFP|HWCAP_EDSP|HWCAP_JAVA
00484:
.longcpu_arm926_name
00485:
.longarm926_processor_functions
00486:
.longv4wbi_tlb_fns
00487:
.longv4wb_user_fns
00488:
.longarm926_cache_fns
00489:
.size__arm926_proc_info,.-__arm926_proc_info
从464行,我们可以看到__arm926_proc_info被放到了".proc.info.init"段中.
对照structproc_info_list,我们可以看到__cpu_flush的定义是在480行,即__arm926_setup.(我们将在"4.调用平台特定的__cpu_flush函数"一节中详细分析这部分的内容.)
从以上的内容我们可以看出:
r5中的__proc_info_begin是proc_info_list的起始地址,r6中的__proc_info_end是proc_info_list的结束地址.
149行:
从上面的分析我们可以知道r3中存储的是3f处的物理地址,而r7存储的是3f处的虚拟地址,这一行是计算当前程序运行的物理地址和虚拟地址的差值,将其保存到r3中.
150行:
将r5存储的虚拟地址(__proc_info_begin)转换成物理地址
151行:
将r6存储的虚拟地址(__proc_info_end)转换成物理地址
152行:
对照structproc_info_list,可以得知,这句是将当前proc_info的cpu_val和cpu_mask分别存r3,r4中
153行:
r9中存储了processorid(arch/arm/kernel/head.S中的75行),与r4的cpu_mask进行逻辑与操作,得到我们需要的值
154行:
将153行中得到的值与r3中的cpu_val进行比较
155行:
如果相等,说明我们找到了对应的processortype,跳到160行,返回
156行:
(如果不相等),将r5指向下一个proc_info,
157行:
和r6比较,检查是否到了__proc_info_end.
158行:
如果没有到__proc_info_end,表明还有proc_info配置,返回152行继续查找
159行:
执行到这里,说明所有的proc_info都匹配过了,但是没有找到匹配的,将r5设置成0(unknownprocessor)
160行:
返回
本文来自:
()详细出处参考:
一、编译安装流程
以linux_2.6.36在i386下编译为例
获取源码
最新kernel下载:
http:
//www.kernel.org。
解压$tarxvjflinux-x.y.z.tar.bz2或者$tarxvzflinux-x.y.z.tar.gz。
注意不要把源码放到/usr/src/linux下。
编译时不要用root用户,仅在安装时用root。
源码树
arch Architecture-specificsource 不同cpu
block
crypto CryptoAPI
Documentation Kernelsourcedocumentation 看HOWTO,Changes,Codingstyle
drivers Devicedrivers
fireware
fs TheVFSandindividualfilesystems 文件系统
include Kernelheaders 头文件
init Kernelbootandinitialization 核引导和初始化
ipc Interprocesscommunicationcode 进程间通讯
kernel Coresubsystems,suchasthescheduler 核子系统,如调度器
lib Helperroutines 一些基本函数,因为kernel不依赖任何c库
mm Memorymanagement 存储管理
net Networkingsubsystem 网络
samples
scripts Scriptsusedtobuildkernel 编译核用的脚本
security Linuxsecuritymoduler
sound Soundsubsystem
tools
usr Earlyuserspacecode(calledinitramfs) 引导用
virt
根目录下的文件
COPYING kernellicense(theGNUGPLv2)
CREDITS alistingofdevelopers
MAINTAINERS individualswhomaintainsubsystemsanddriversinthekernel
看帮助文件
根目录下README
Doucmentation的HOWTO,Chages
编译核(在核源码目录下工作)
$makehelp 查看帮助
1.$makemrproper 清除原来的编译产生的文件。
2.可选
(1)$makedefconfig 用默认的config生成.config文件,如果不用默认的,可跳过这步。
实质上是把arch\x86\configs\i386_defconfig拷贝到核目录下,改名为.config。
ls-a查看目录。
最好是
(2)cp/boot/config-`uname-r`.config把原系统中的配置文件拿来用。
(这次用的fedora13live的)
3. $makelocalmodconfig 可选,精简不需要的模块,只保留系统当前加载的模块。
不过这个只能精简模块[M],对应[*]编译进内核的选项要还是要手动配置。
makelocalmodconfig只保留系统当前加载的模块,要注意一些模块可能之后要用到时才会加载,如一些usb设备的驱动,手动选回来。
在这个命令之前,最好先makemenuconfig,不做修改保存,防止出现一长串的选项。
(注意:
makelocalmodconfig之后要把选项CryptographicAPI--->
还有CryptographicAPI--->
4.$makemenuconfig 以菜单的方式配置核,保存到.config。
配置时选择需要的选项即可,节省编译时间。
(直接用fedora13live的.config害得我的破机子编译用了7小时!
只能说很安全啦!
主要是很多模块是没必要的啦。
)
注意:
如果是同版本的内核编译,还需要备份下当前模块
cd/lib/modules
mv2.6.312.6.31_old
指定内核识别码
vimMakefile
EXTRAVERSION=.custom-1(第4行)
5.$makeall 编译,大概要一个小时。
生成的主要文件是vmlinuz,System.map和arch/x86/boot/bzImage。
要快一点的话可以用$makeall-j2>/dev/null,单核接j2,双核接j4。
6.$makemodules_install 安装模块到/lib/modules/2.6.36。
7.$makeinstall /boot目录下出现vmlinuz-2.6.36,System.map-2.6.36,initramfs-2.6.36.img。
引导配置文件/boot/grub/grub.conf被修改,加上了新的kernel:
----------------------------------------------------------------------------------------------------------------
default=1 //改成default=0
timeout=0 //改成timeout=10,显示多内核选择菜单的延时
hiddenmenu//改成#hiddenmenu,注释掉,预防新内核失败无法再启动系统
...
titleFedora(2.6.36)
root(hd0,0)
kernel/vmlinuz-2.6.36vga=773roroot=/dev/mapper/VolGroup-lv_rootrd_LVM_LV=VolGroup/lv_rootrd_LVM_LV=VolGroup/lv_swaprd_NO_LUKSrd_NO_MDrd_NO_DMLANG=en_US.UTF-8SYSFONT=latarcyrheb-sun16KEYBOARDTYPE=pcKEYTABLE=usrhgbquiet
initrd/initramfs-2.6.36.img
titleFedora(2.6.33.3-85.fc13.i686)
root(hd0,0)
kernel/vmlinuz-2.6.33.3-85.fc13.i686vga=773roroot=/dev/mapper/VolGroup-lv_rootrd_LVM_LV=VolGroup/lv_rootrd_LVM_LV=VolGroup/lv_swaprd_NO_LUKSrd_NO_MDrd_NO_DMLANG=en_US.UTF-8SYSFONT=latarcyrheb-sun16KEYBOARDTYPE=pcKEYTABLE=usrhgbquiet
initrd/initramfs-2.6.33.3-85.fc13.i686.img
----------------------------------------------------------------------------------------------------------------
修改启动配置文件
/boot/grub/menu.lst它指向grub.conf
grub.conf文件中,把default=改成新生成核的顺序数
显示多内核选项菜单,timeout=10,#hiddenmenu
保存grub.conf。
重启reboot。
PASS 过关!
关键在于内核配置。
tips:
如果机器破的话,编译的时候不要用电脑,否则资源被占了本来编译1小时会变成几小时。
----------------------------------------------------------------------------------------------------------------
二、其它的详细说明
清除之前内核编译痕迹
makeclean-deleteeverythingnotneededforbuildingexternalmodules
makem
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- armlinux 入口 startkernel 代码 详细 分析