linux内核启动流程
时间:11-22
来源:互联网
点击:
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
锁的处理器可以进入内核,如中断处理程序等。在任何一对 lock_kernel/unlock_kernel函数里至多可以有一个程序占用CPU。 进程的lock_depth成员初始化为-1,在 kerenl/fork.c文件中设置。在它小于0时
(恒为 -1),进程不拥有内核锁;当大于或等于0时,进程得到内核锁。
要涉及下列主要函数及代码。
5.2.1 setup_processor()
该函数主要通过
中设置。
MACHINE_START (xxx, “xxx”)
MAINTAINER ("xxx"
BOOT_MEM (xxx, xxx, xxx)
FIXUP (xxx)
MAPIO (xxx)
INITIRQ (xxx)
meminfo结构表明内存情况,是对物理内存结构meminfo的默认初始化。 nr_banks指定内存块的数量,
bank指定每块内存的范围,PHYS _OFFSET指定某块内存块的开始地址,MEM_SIZE指定某块内存块长度。
PHYS _OFFSET和MEM_SIZE都定义在include/asm-armnommu/arch-XXX/memory.h文件中,其中
PHYS _OFFSET是内存的开始地址,MEM_SIZE就是内存的结束地址。这个结构在接下来内存的初始化代码中
起重要作用。
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定义了整个内核的
内存空间,内核线程属于内核代码,同样使用内核空间,其访问内存空间的权限与内核一样。
用 reserve_node_zero(bootmap_pfn, bootmap_pages) 函数,这个函数的作用是保留一部分内存使之
不能被动态分配。这些内存块包括:
reserve_bootmem_node(pgdat, __pa(&_stext), &_end - &_stext); /*内核所占用地址空间*/
reserve_bootmem_node(pgdat, bootmap_pfn /*bootmem结构所占用地址空间*/
体系结构的存储系统及MMU相关的概念。
在ARM存储系统中,使用内存管理单元(MMU)实现虚拟地址到实际物理地址的映射。利用MMU,可把SDRAM的
地址完全映射到0x0起始的一片连续地址空间,而把原来占据这片空间的FLASH或者ROM映射到其他不相冲突
的存储空间位置。例如,FLASH的地址从0x0000 0000~0x00FFFFFF,而SDRAM的地址范围是
0x3000 0000~0x3lFFFFFF,则可把SDRAM地址映射为0x0000 0000~0xlFFFFFF,而FLASH的地址可以
映射到0x9000 0000~0x90FFFFFF(此处地址空间为空闲,未被占用)。映射完成后,如果处理器发生异常,
假设依然为IRQ中断,PC指针指向0xl8处的地址,而这个时候PC实际上是从位于物理地址的0x3000 0018处
读取指令。通过MMU的映射,则可实现程序完全运行在SDRAM之中。在实际的应用中.可能会把两片不连续的
物理地址空间分配给SDRAM。而在操作系统中,习惯于把SDRAM的空间连续起来,方便内存管理,且应用程序
申请大块的内存时,操作系统内核也可方便地分配。通过MMU可实现不连续的物理地址空间映射为连续的虚拟
地址空间。操作系统内核或者一些比较关键的代码,一般是不希望被用户应用程序访问。通过MMU可以控制地
址空间的访问权限,从而保护这些代码不被破坏。
MMU的实现过程,实际上就是一个查表映射的过程。建立页表是实现MMU功能不可缺少的一步。页表位于系统的
内存中,页表的每一项对应于一个虚拟地址到物理地址的映射。每一项的长度即是一个字的长度(在ARM中,
一个字的长度被定义为4Bytes)。页表项除完成虚拟地址到物理地址的映射功能之外,还定义了访问权限和缓
冲特性等。
MMU的映射分为两种,一级页表的变换和二级页表变换。两者的不同之处就是实现的变换地址空间大小不同。
一级页表变换支持1 M大小的存储空间的映射,而二级可以支持64 kB,4 kB和1 kB大小地址空间的映射。
动态表(页表)的大小=表项数*每个表项所需的位数,即为整个内存空间建立索引表时,需要多大空间存放索
引表本身。
表项数=虚拟地址空间/每页大小
每个表项所需的位数=Log(实际页表数)+适当控制位数
实际页表数 =物理地址空间/每页大小
该文件是内核最先执行的一个文件,包括内核入口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
[cpp]view plaincopyprint?
- /*部分源代码分析*/
- /*内核入口点*/
- ENTRY(stext)
- /*程序状态,禁止FIQ、IRQ,设定SVC模式*/
- movr0,#F_BIT|I_BIT|MODE_SVC@makesuresvcmode
- /*置当前程序状态寄存器*/
- msrcpsr_c,r0@andallirqsdisabled
- /*判断CPU类型,查找运行的CPUID值与Linux编译支持的ID值是否支持*/
- bl__lookup_processor_type
- /*跳到__error*/
- teqr10,#0@invalidprocessor?
- moveqr0,#p@yes,errorp
- beq__error
- /*判断体系类型,查看R1寄存器的ArchitectureType值是否支持*/
- bl__lookup_architecture_type
- /*不支持,跳到出错*/
- teqr7,#0@invalidarchitecture?
- moveqr0,#a@yes,errora
- beq__error
- /*创建核心页表*/
- bl__create_page_tables
- adrlr,__ret@returnaddress
- addpc,r10,#12@initialiseprocessor
- /*跳转到start_kernel函数*/
- bstart_kernel
1. start_kernel()函数分析
下面对start_kernel()函数及其相关函数进行分析。1.1 lock_kernel()
[cpp]view plaincopyprint?
- /*Gettingthebigkernellock.
- *Thiscannothappenasynchronously,
- *soweonlyneedtoworryaboutother
- *CPUs.
- */
- extern__inline__voidlock_kernel(void)
- {
- if(!++current->lock_depth)
- spin_lock(&kernel_flag);
- }
锁的处理器可以进入内核,如中断处理程序等。在任何一对 lock_kernel/unlock_kernel函数里至多可以有一个程序占用CPU。 进程的lock_depth成员初始化为-1,在 kerenl/fork.c文件中设置。在它小于0时
(恒为 -1),进程不拥有内核锁;当大于或等于0时,进程得到内核锁。
1.2 setup_arch()
setup_arch()函数做体系相关的初始化工作,函数的定义在arch/arm/kernel/setup.c文件中,主要涉及下列主要函数及代码。
5.2.1 setup_processor()
该函数主要通过
[cpp]view plaincopyprint?
- for(list=&__proc_info_begin;list<&__proc_info_end;list++)
- if((processor_id&list->cpu_mask)==list->cpu_val)
- break;
中设置。
1.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
1.2.3内存设置代码
[cpp]view plaincopyprint?
- 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就是内存的结束地址。这个结构在接下来内存的初始化代码中
起重要作用。
1.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定义了整个内核的
内存空间,内核线程属于内核代码,同样使用内核空间,其访问内存空间的权限与内核一样。
1.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
1.2.6 paging_init(&meminfo, mdesc)
创建内核页表,映射所有物理内存和IO空间,对于不同的处理器,该函数差别比较大。下面简单描述一下ARM体系结构的存储系统及MMU相关的概念。
在ARM存储系统中,使用内存管理单元(MMU)实现虚拟地址到实际物理地址的映射。利用MMU,可把SDRAM的
地址完全映射到0x0起始的一片连续地址空间,而把原来占据这片空间的FLASH或者ROM映射到其他不相冲突
的存储空间位置。例如,FLASH的地址从0x0000 0000~0x00FFFFFF,而SDRAM的地址范围是
0x3000 0000~0x3lFFFFFF,则可把SDRAM地址映射为0x0000 0000~0xlFFFFFF,而FLASH的地址可以
映射到0x9000 0000~0x90FFFFFF(此处地址空间为空闲,未被占用)。映射完成后,如果处理器发生异常,
假设依然为IRQ中断,PC指针指向0xl8处的地址,而这个时候PC实际上是从位于物理地址的0x3000 0018处
读取指令。通过MMU的映射,则可实现程序完全运行在SDRAM之中。在实际的应用中.可能会把两片不连续的
物理地址空间分配给SDRAM。而在操作系统中,习惯于把SDRAM的空间连续起来,方便内存管理,且应用程序
申请大块的内存时,操作系统内核也可方便地分配。通过MMU可实现不连续的物理地址空间映射为连续的虚拟
地址空间。操作系统内核或者一些比较关键的代码,一般是不希望被用户应用程序访问。通过MMU可以控制地
址空间的访问权限,从而保护这些代码不被破坏。
MMU的实现过程,实际上就是一个查表映射的过程。建立页表是实现MMU功能不可缺少的一步。页表位于系统的
内存中,页表的每一项对应于一个虚拟地址到物理地址的映射。每一项的长度即是一个字的长度(在ARM中,
一个字的长度被定义为4Bytes)。页表项除完成虚拟地址到物理地址的映射功能之外,还定义了访问权限和缓
冲特性等。
MMU的映射分为两种,一级页表的变换和二级页表变换。两者的不同之处就是实现的变换地址空间大小不同。
一级页表变换支持1 M大小的存储空间的映射,而二级可以支持64 kB,4 kB和1 kB大小地址空间的映射。
动态表(页表)的大小=表项数*每个表项所需的位数,即为整个内存空间建立索引表时,需要多大空间存放索
引表本身。
表项数=虚拟地址空间/每页大小
每个表项所需的位数=Log(实际页表数)+适当控制位数
实际页表数 =物理地址空间/每页大小
linux内核启动流 相关文章:
- ARM Linux内核启动流程(11-21)
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)