linux内核启动第二阶段之setuparch2636.docx
- 文档编号:12388866
- 上传时间:2023-04-18
- 格式:DOCX
- 页数:46
- 大小:36.16KB
linux内核启动第二阶段之setuparch2636.docx
《linux内核启动第二阶段之setuparch2636.docx》由会员分享,可在线阅读,更多相关《linux内核启动第二阶段之setuparch2636.docx(46页珍藏版)》请在冰豆网上搜索。
linux内核启动第二阶段之setuparch2636
linux内核启动第二阶段之setup_arch()函数分析-2.6.362011-08-2608:
24:
44
分类:
LINUX
执行setup_arch()函数
回到start_kernel当中,569行,调用setup_arch函数,传给他的参数是那个未被初始化的内部变量command_line。
这个setup_arch()函数是start_kernel阶段最重要的一个函数,每个体系都有自己的setup_arch()函数,是体系结构相关的,具体编译哪个体系的setup_arch()函数,由顶层Makefile中的ARCH变量决定:
它首先通过检测出来的处理器类型进行处理器内核的初始化,然后通过bootmem_init()函数根据系统定义的meminfo结构进行内存结构的初始化,最后调用paging_init()开启MMU,创建内核页表,映射所有的物理内存和IO空间。
start_kernel()
-->setup_arch()
-->paging_init()
-->bootmem_init()
-->alloc_bootmem_low_pages()
第569行setup_arch(&command_line)在arch/arm/kernel/setup.c定义如下:
767void__initsetup_arch(char**cmdline_p)
768{
769structtag*tags=(structtag*)&init_tags;
770structmachine_desc*mdesc;
771char*from=default_command_line;
772
773unwind_init();
774
775setup_processor();
776mdesc=setup_machine(machine_arch_type);
777machine_name=mdesc->name;//machine_name在126行定义staticconstchar*machine_name;
778
779if(mdesc->soft_reboot)//这个变量初始值为"h",如果这里设置成softboot,它会将这个初始值变为"s"
780reboot_setup("s");
781
782if(__atags_pointer)//检查BootLoader是否传入参数
783tags=phys_to_virt(__atags_pointer);
784elseif(mdesc->boot_params)//machinedescriptor中设置的启动参数地址(arch/arm/mach-s3c2410/mach-smdk2410.c)
785tags=phys_to_virt(mdesc->boot_params);
786
787#ifdefined(CONFIG_DEPRECATED_PARAM_STRUCT)
788/*
789*Ifwehavetheoldstyleparameters,convertthemto
790*ataglist.
791*/
792if(tags->hdr.tag!
=ATAG_CORE)//内核参数列表第一项必须是ATAG_CORE类型,如果不是,则需要转换成新的内核参数类型,新的内核参数类型用下面structtag结构表示,由bootloader[u-boot-1.1.5]传递到物理地址0x30000100处的参数类型是taglist结构,在u-boot-1.1.6后是采用了新的内核参数类型structtag结构
793convert_to_tag_list(tags);//此函数完成新旧参数结构转换,将参数结构转换为taglist结构
794#endif
795if(tags->hdr.tag!
=ATAG_CORE)//如果没有内核参数
796tags=(structtag*)&init_tags;//则选用默认的内核参数,init_tags文件中有定义。
797
798if(mdesc->fixup)//用内核参数列表填充meminfo,fixup函数出现在注册machine_desc中,即MACHINE_START、MACHINE_END定义中,这个函数,有些板子有,但在2410中没有定义这个函数。
799mdesc->fixup(mdesc,tags,&from,&meminfo);
800
801if(tags->hdr.tag==ATAG_CORE){
802if(meminfo.nr_banks!
=0)//说明内存被初始化过
803squash_mem_tags(tags);//如果是taglist,那么如果系统已经创建了默认的meminfo.nr_banks,清除tags中关于MEM的参数,以免再次被初始化
804save_atags(tags);
805parse_tags(tags);//做出一些针对各个tags的处理
806}
807//下面是记录内核代码的起始,结束虚拟地址
808init_mm.start_code=(unsignedlong)_text;
809init_mm.end_code=(unsignedlong)_etext;
810init_mm.end_data=(unsignedlong)_edata;
811init_mm.brk=(unsignedlong)_end;
812
813/*parse_early_paramneedsaboot_command_line*/
814strlcpy(boot_command_line,from,COMMAND_LINE_SIZE);
815
816/*populatecmd_linetooforlateruse,preservingboot_command_line*/
817strlcpy(cmd_line,boot_command_line,COMMAND_LINE_SIZE);
818*cmdline_p=cmd_line;
819
820parse_early_param();//解释命令行参数,见后
821
822arm_memblock_init(&meminfo,mdesc);
823
824paging_init(mdesc);
825request_standard_resources(&meminfo,mdesc);//将设备实体登记注册到总线空间链表
826
827#ifdefCONFIG_SMP
828smp_init_cpus();
829#endif
830reserve_crashkernel();//要配置CONFIG_KEXEC,否则为空函数,2410中没有配置
831
832cpu_init();//对用到的IRQ,ABT,UND模式的SP都作了初始化
833tcm_init();//在ARM中是个空函数
834
835/*根据arch/arm/mach-s3c2410/mach-smdk2410.c中machine_desc结构,
设置各种特定于体系结构的指针
836*Setupvariousarchitecture-specificpointers
837*/
838arch_nr_irqs=mdesc->nr_irqs;//在arch/arm/kernel/irq.c第171行,由nr_irqs=arch_nr_irqs?
arch_nr_irqs:
NR_IRQS;引用,而nr_irqs在init_IRQ、asm_do_IRQ、set_irq_flags中都有引用
839init_arch_irq=mdesc->init_irq;//在init_IRQ函数第165行调用
840system_timer=mdesc->timer;
841init_machine=mdesc->init_machine;
842
843#ifdefCONFIG_VT
844#ifdefined(CONFIG_VGA_CONSOLE)
845conswitchp=&vga_con;
846#elifdefined(CONFIG_DUMMY_CONSOLE)
847conswitchp=&dummy_con;
848#endif
849#endif
850early_trap_init();//见后
851}
852
769行tag数据结构在arch/arm/include/asm/setup.h中定义如下:
structtag{
structtag_headerhdr;
union{
structtag_corecore;
structtag_mem32mem;
structtag_videotextvideotext;
structtag_ramdiskramdisk;
structtag_initrdinitrd;
structtag_serialnrserialnr;
structtag_revisionrevision;
structtag_videolfbvideolfb;
structtag_cmdlinecmdline;
/*
*Acornspecific
*/
structtag_acornacorn;
/*
*DC21285specific
*/
structtag_memclkmemclk;
}u;
};
其中init_tags在arch/arm/kernel/setup.c文件下定义如下
662staticstructinit_tags{
663structtag_headerhdr1;
664structtag_corecore;
665structtag_headerhdr2;
666structtag_mem32mem;
667structtag_headerhdr3;
668}init_tags__initdata={
669{tag_size(tag_core),ATAG_CORE},
670{1,PAGE_SIZE,0xff},
671{tag_size(tag_mem32),ATAG_MEM},
672{MEM_SIZE,PHYS_OFFSET},
673{0,ATAG_NONE}
674};
675
676staticvoid(*init_machine)(void)__initdata;
770行完整的machine_desc结构描述如下:
arch/arm/include/asm/mach/arch.h
13structtag;
14structmeminfo;
15structsys_timer;
16
17structmachine_desc{
18/*
19*Note!
Thefirstfourelementsareused
20*byassemblercodeinhead.S,head-common.S
21*/
22unsignedintnr;/*开发板的机器类型ID*/
23unsignedintnr_irqs;/*numberofIRQs*/
24unsignedintphys_io;/*起始IO物理地址*/
25unsignedintio_pg_offst;/*byteoffsetforio
26*pagetabeentry*/
27
28constchar*name;/*开发板名称*/
29unsignedlongboot_params;/*taggedlist内核启动参数的地址*/
30
31unsignedintvideo_start;/*startofvideoRAM*/
32unsignedintvideo_end;/*endofvideoRAM*/
33
34unsignedintreserve_lp0:
1;/*neverhaslp0*/
35unsignedintreserve_lp1:
1;/*neverhaslp1*/
36unsignedintreserve_lp2:
1;/*neverhaslp2*/
37unsignedintsoft_reboot:
1;/*softreboot*/
38void(*fixup)(structmachine_desc*,
39structtag*,char**,
40structmeminfo*);
41void(*reserve)(void);/*reservememblocks*/
42void(*map_io)(void);/*IO映射函数(在这里修改时钟频率)*/
43void(*init_irq)(void);/*中断初始化函数*/
44structsys_timer*timer;/*systemticktimer*/
45void(*init_machine)(void);
46};
771行default_command_line在setup.c文件129行中定义如下:
staticchardefault_command_line[COMMAND_LINE_SIZE]__initdata=CONFIG_CMDLINE;
其中CONFIG_CMDLINE在“.config”配置文件中定义的。
773行arch/arm/kernel/unwind.c
439int__initunwind_init(void)
440{
441structunwind_idx*idx;
442
443/*Convertthesymboladdressestoabsolutevalues*/
444for(idx=__start_unwind_idx;idx<__stop_unwind_idx;idx++)
445idx->addr=prel31_to_addr(&idx->addr);
446
447pr_debug("unwind:
ARMstackunwindinginitialised\n");
448
449return0;
450}
structunwind_idx{
unsignedlongaddr;
unsignedlonginsn;
};
776行,machine_arch_type在arch/arm/tools/gen-mach-types中第69行定义,
printf("#definemachine_arch_type\t__machine_arch_type\n")
它最后会被转换成一个头文件include/generated/mach-types.h,包含在arch/arm/include/asm/mach-types.h文件中,__machine_arch_type在arch/arm/kernel/head-common.S定义
27.long__machine_arch_type@r5
并通过arch/arm/kernel/head-common.S第60行命令
60strr1,[r5]@Savemachinetype
将bootloader通过r1传递过来的机器码保存到__machine_arch_type。
下面我们来看setup_machine函数,在在arch/arm/kernel/setup.c文件下定义如下
391staticstructmachine_desc*__initsetup_machine(unsignedintnr)
392{
393structmachine_desc*list;
394
395/*
396*locatemachineinthelistofsupportedmachines.
397*/
398list=lookup_machine_type(nr);
399if(!
list){
400printk("Machineconfigurationbotched(nr%d),unable"
401"tocontinue.\n",nr);
402while
(1);
403}
404
405printk("Machine:
%s\n",list->name);
406
407returnlist;
408}
在这个函数中就是查找你是什么版本的处理器架构,最后就是调用了lookup_processor_type这个函数,它在汇编部分也提到过,在arch/arm/kernel/head-common.S定义
230ENTRY(lookup_machine_type)
231stmfdsp!
{r4-r6,lr}
232movr1,r0
233bl__lookup_machine_type
234movr0,r5
235ldmfdsp!
{r4-r6,pc}
236ENDPROC(lookup_machine_type)
可见最后调用的是__lookup_machine_type,这个函数在汇编中我们已经分析过了。
这里再来分析一下:
内核中对于每种支持的开发板都会使用宏MACHINE_START、MACHINE_END来定义一个machine_desc结构,它定义开发板相关的一些属性及函数,比如机器类型ID、起始I/O物理地址、Bootloader传入的参数的地址、中断初始化函数、I/O映射函数等,比如对于SMDK2410开发板,在arch/arm/mach-s3c2410/mach-smdk2410.c中定义如下:
MACHINE_START(SMDK2410,"SMDK2410")/*@TODO:
requestanewidentifierandswitch
*toSMDK2410*/
/*Maintainer:
JonasDietsche*/
.phys_io=S3C2410_PA_UART,
.io_pg_offst=(((u32)S3C24XX_VA_UART)>>18)&0xfffc,
.boot_params=S3C2410_SDRAM_PA+0x100,
.map_io=smdk2410_map_io,
.init_irq=s3c24xx_init_irq,
.init_machine=smdk2410_init,
.timer=&s3c24xx_timer,
MACHINE_END
而宏MACHINE_START、MACHINE_END在arch/arm/include/asm/mach/arch.h中定义如下:
52#defineMACHINE_START(_type,_name)\
53staticconststructmachine_desc__mach_desc_##_type\
54__used\
55__attribute__((__section__(".arch.info.init")))={\
56.nr=MACH_TYPE_##_type,\
57.name=_name,
58
59#defineMACHINE_END\
60};
所以以下展开后如下:
staticconststructmachine_desc__mach_desc_SMDK2410
__used
__attribute__((__section__(".arch.info.init")))={
.nr=MACH_TYPE_SMDK2410,
.name=SMDK2410,
.phys_io=S3C2410_PA_UART,
.io_pg_offst=(((u32)S3C24XX_VA_UART)>>18)&0xfffc,
.boot_params=S3C2410_SDRAM_PA+0x100,
.map_io=smdk2410_map_io,
.init_irq=s3c24xx_init_irq,
.init_machine=smdk2410_init,
.timer=&s3c24xx_timer,
};
对照前面完整的machine_desc结构描述就能找到系统定义开发板相关的一些属性及函数
所有machine_desc结构体初始化后被编译连接到“.arch.info.init”段中,在连接内核时,它们被组织在一起,开始地址为__arch_info_begin,结束地址为__arch_info_end,从连接脚本“arch/arm/kernel/vmlinux.lds.S”中可以看出:
37__arch_info_begin=.;//machine_desc结构体的开始地址
38*(.arch.info.init)//所有machine_desc都在这里面
39__arch_info_end=.;//machine_desc结构体的开始地址
不同的machine_desc结构用于不同的开发板,U-BOOT调用内核时,会在r1寄存器中给出开发板的标记(机器类型ID);对于S3C2410、S3C2440开发板,U-Boot传入的机器类型ID为MACH_TYPE_SMDK2410、MACH_TYPE_S3C2440,它们对应的machine_desc结构分别在arch/arm/mach-s3c2410/mach-smdk2410.c和
arch/arm/mach-s3c2440/mach-smdk2440.c中定义,现在再来看看__lookup_machine_type函数。
它在arch/arm/kernel/head-common.S中定义如下:
1964:
.long.//当前行编译链接后的虚拟地址
197.long__arch_info_begin//machine_desc结构体的开始地址(虚拟地址)
198.long__arc
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- linux 内核 启动 第二阶段 setuparch2636