这里记录了我学习Linux kernel的历程和心得.是对我的学习的一个总结,也是对我的一种鞭策.
Vim_Chinese_Documentation
前面我们介绍了高速缓存的基本概念,下面我们将介绍它和memory中的页框是如何关联到一起的.
slab alloctor是通过buddy alloctor来申请页框的.
这在 kmem_cache_alloc()
中,通过调用kmem_getpages();而kmem_getpages()又会相应的调用alloc_pages().
当一个页框被分配给slab之后,page->flag 中的 PG_slab会被置位.同时,该page描述符的lru会分别指向相应的cache和slab, 如下图所示:
主要数据结构:
struct kmem_cache_s {
Char Device Driver
相关数据结构:
struct cdev {
};
struct kobj_map {
};
static struct char_device_struct {
}
6. 切换数据
00014:
00015: __switch_data:
00016:
00017:
00018:
00019:
00020:
00021:
00022:
00023:
00024:
00025:
00026:
00034:
00035: __mmap_switched:
00036:
00037:
00038:
5. 开启mmu
r0 = c1 parameters
r4 =
pgtbl
r8 = machine info
r9 = cpu
id
4. 调用平台特定的 __cpu_flush 函数
当 __create_page_tables 返回之后
此时,一些特定寄存器的值如下所示:
r4 =
pgtbl
r8 = machine info
r9 = cpu
id
r10 =
procinfo
在我们需要在开启mmu之前,做一些必须的工作:清除ICache, 清除 DCache, 清除 Writebuffer,
清除TLB等.
这些一般是通过cp15协处理器来实现的,并且是平台相关的. 这就是 __cpu_flush 需要做的工作.
00091:
00092: &nb
3. 创建页表
通过前面的两步,我们已经确定了processor type 和 machine type.
此时,一些特定寄存器的值如下所示:
r8 = machine info
r9 = cpu
id
r10 =
procinfo
创建页表是通过函数 __create_page_tables 来实现的.
这里,我们使用的是arm的L1主页表,L1主页表也称为段页表(section page table)
L1 主页表将4 GB 的地址空间分成若干个1 MB的段(section),因此L1页表包含4096个页表项(section
entry). 每个页表项是32 bits(4 bytes)
因而L1主页表占用 4096 *4 = 16k的内存空间.
2. 确定 machine type
00079:
00080:
00081:
79行: 跳转到__lookup_machine_type函数,在__lookup_machine_type中,会把struct
machine_desc的基地址(machine type)存储在r5中
80,81行: 将r5中的 machine_desc的基地址存储到r8中,并判断r5是否是0,如果是0,说明是无效的machine
type,跳转到__error_a(出错)
__lookup_machine_type 函数
下面我们分析__lookup_machine_type 函数:
00176:
00177:
00178: 3:
0
1. 确定 processor type
00075:
00076:
00077:
00078:
75行: 通过cp15协处理器的c0寄存器来获得processor id的指令. 关于cp15的详细内容可参考相关的arm手册
76行:
跳转到__lookup_processor_type.在__lookup_processor_type中,会把processor
type 存储在r5中
77,78行: 判断r5中的processor type是否是0,如果是0,说明是无效的processor
type,跳转到__error_p(出错)
__lookup_processor_type 函数主要是根据从cpu中获得的processor id和系统中的proc_info进行匹配,将匹配到的proc_info_list的
本文针对arm linux, 从kernel的第一条指令开始分析,一直分析到进入start_kernel()函数.
我们当前以linux-2.6.19内核版本作为范例来分析,本文中所有的代码,前面都会加上行号以便于和源码进行对照.
例:
在文件init/main.c中:
00478: asmlinkage void __init start_kernel(void)
前面的'00478:' 表示478行,冒号后面的内容就是源码了.
在分析代码的过程中,我们使用缩进来表示各个代码的调用层次.
由于启动部分有一些代码是平台特定的,虽然大部分的平台所实现的功能都比较类似,但是为了更好的对code进行说明,对于平台相关的代码,我们选择at91(ARM926EJS)平台进行分析.
另外,本文是以uncompressed kernel开始讲解的.对于内核解压缩部分的code,在 arch/arm/boot/compressed中,本文不做讨论.
一. 启动条件
新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 会员注册 | 产品答疑
Copyright © 1996 - 2008 SINA Corporation, All Rights Reserved