免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2762 | 回复: 1
打印 上一主题 下一主题

Linux内核启动流程 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-05-17 12:57 |只看该作者 |倒序浏览

Linux内核启动流程
arch/arm/kernel/head-armv.S
该文件是内核最先执行的一个文件,包括内核入口ENTRY(stext)到start_kernel间的初始化代码,主要作用是检查CPU ID, Architecture Type,初始化BSS等操作,并跳到start_kernel函数。在执行前,处理器应满足以下状态:
r0 - should be 0
r1 - unique architecture number
MMU - off
I-cache - on or off
D-cache – off
/* 部分源代码分析 */
/* 内核入口点 */
ENTRY(stext)
/* 程序状态,禁止FIQ、IRQ,设定SVC模式 */
mov r0, #F_BIT | I_BIT | MODE_SVC@ make sure svc mode
/* 置当前程序状态寄存器 */
msr cpsr_c, r0 @ and all irqs disabled
/* 判断CPU类型,查找运行的CPU ID值与Linux编译支持的ID值是否支持 */
bl __lookup_processor_type
/* 跳到__error */
teq r10, #0 @ invalid processor?
moveq r0, #'p' @ yes, error 'p'
beq __error
/* 判断体系类型,查看R1寄存器的Architecture Type值是否支持 */
bl __lookup_architecture_type
/* 不支持,跳到出错 */
teq r7, #0 @ invalid architecture?
moveq r0, #'a' @ yes, error 'a'
beq __error
/* 创建核心页表 */
bl __create_page_tables
adr lr, __ret @ return address
add pc, r10, #12 @ initialise processor
/* 跳转到start_kernel函数 */
b start_kernel
5. start_kernel()函数分析
下面对start_kernel()函数及其相关函数进行分析。
5.1 lock_kernel()
/* Getting the big kernel lock.
* This cannot happen asynchronously,
* so we only need to worry about other
* CPU's.
*/
extern __inline__ void lock_kernel(void)
{
if (!++current->lock_depth)
spin_lock(&kernel_flag);
}
kernel_flag 是一个内核大自旋锁,所有进程都通过这个大锁来实现向内核态的迁移。只有获得这个大自旋
锁的处理器可以进入内核,如中断处理程序等。在任何一对 lock_kernel/unlock_kernel函数里至多可以有一个程序占用CPU。 进程的lock_depth成员初始化为-1,在 kerenl/fork.c文件中设置。在它小于0时
(恒为 -1),进程不拥有内核锁;当大于或等于0时,进程得到内核锁。
5.2 setup_arch()
setup_arch()函数做体系相关的初始化工作,函数的定义在arch/arm/kernel/setup.c文件中,主
要涉及下列主要函数及代码。
5.2.1 setup_processor()
该函数主要通过
for (list = &__proc_info_begin; list cpu_mask) == list->cpu_val)
break;
这样一个循环来在.proc.info段中寻找匹配的processor_id,processor_id在head_armv.S文件
中设置。
5.2.2 setup_architecture(machine_arch_type)
该函数获得体系结构的信息,返回mach-xxx/arch.c 文件中定义的machine结构体的指针,包含以下内容
MACHINE_START (xxx, “xxx”)
MAINTAINER ("xxx"
BOOT_MEM (xxx, xxx, xxx)
FIXUP (xxx)
MAPIO (xxx)
INITIRQ (xxx)
MACHINE_END
5.2.3内存设置代码
if (meminfo.nr_banks == 0)
{
meminfo.nr_banks = 1;
meminfo.bank[0].start = PHYS_OFFSET;
meminfo.bank[0].size = MEM_SIZE;
}
meminfo结构表明内存情况,是对物理内存结构meminfo的默认初始化。 nr_banks指定内存块的数量,
bank指定每块内存的范围,PHYS _OFFSET指定某块内存块的开始地址,MEM_SIZE指定某块内存块长度。
PHYS _OFFSET和MEM_SIZE都定义在include/asm-armnommu/arch-XXX/memory.h文件中,其中
PHYS _OFFSET是内存的开始地址,MEM_SIZE就是内存的结束地址。这个结构在接下来内存的初始化代码中
起重要作用。
5.2.4 内核内存空间管理
init_mm.start_code = (unsigned long) &_text; 内核代码段开始
init_mm.end_code = (unsigned long) &_etext; 内核代码段结束
init_mm.end_data = (unsigned long) &_edata; 内核数据段开始
init_mm.brk = (unsigned long) &_end; 内核数据段结束
每一个任务都有一个mm_struct结构管理其内存空间,init_mm 是内核的mm_struct。其中设置成员变量
* mmap指向自己, 意味着内核只有一个内存管理结构,设置 pgd=swapper_pg_dir,
swapper_pg_dir是内核的页目录,ARM体系结构的内核页目录大小定义为16k。init_mm定义了整个内核的
内存空间,内核线程属于内核代码,同样使用内核空间,其访问内存空间的权限与内核一样。
5.2.5 内存结构初始化
bootmem_init (&meminfo)函数根据meminfo进行内存结构初始化。bootmem_init(&meminfo)函数中调
用 reserve_node_zero(bootmap_pfn, bootmap_pages) 函数,这个函数的作用是保留一部分内存使之
不能被动态分配。这些内存块包括:
reserve_bootmem_node(pgdat, __pa(&_stext), &_end - &_stext); /*内核所占用地址空间*/
reserve_bootmem_node(pgdat, bootmap_pfn

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u3/96958/showart_1931688.html

论坛徽章:
0
2 [报告]
发表于 2011-12-31 18:52 |只看该作者
X86平台的内核也是从arch/arm/kernel/目录开始执行的吗?mips的也是?
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP