浅析armlinux-setup_arch()->setup_arch()函数-最终
文章来源:http://gliethttp.cublog.cn
建议首先参考《浅析armlinux2_4_19启动程序[head-armv.s文件]》与[http://gliethttp.cublog.cn]
《浅析setup_arch()函数tag_list的uboot[u-boot]由来》 《浅析armlinux-setup_arch()->setup_processor()函数1》 《浅析armlinux-setup_arch()->setup_machine()函数2 》 《浅析armlinux-setup_arch()->convert_to_tag_list()函数3 》 《浅析armlinux-setup_arch()->bootmem_init()函数4》 《浅析armlinux-setup_arch()->paging_init()函数5》 《浅析armlinux-seup_arch-alloc_bootmem_low_pages函数5-1》 《浅析armlinux-setup_arch()-memtable_init()函数5-2》 《浅析armlinux-setup_arch()-clear_mapping()函数5-2-1》 《浅析armlinux-setup_arch()-create_mapping()函数5-2-2》 《我看Buddy(伙伴)算法-为什么要有除2操作》 《浅析armlinux-paging_init()->at91rm9200_map_io()函数5-3》 《浅析armlinux-paging_init()->free_area_init_core()函数5-4》 《浅析armlinux-setup_arch()->request_standard_resources()函数6》 《浅析armlinux-setup_arch()->init_arch_irq()函数7》
//1.arch/arm/kernel/Setup.c->setup_arch() void __init setup_arch(char **cmdline_p) { struct tag *tags = (struct tag *)&init_tags; struct machine_desc *mdesc; char *from = default_command_line;
ROOT_DEV = MKDEV(0, 255);//ROOT_DEV = 0xff; //见《浅析armlinux-setup_arch()->setup_processor()函数1》[http://gliethttp.cublog.cn] setup_processor(); //见《浅析armlinux-setup_arch()->setup_machine(machine_arch_type)函数2》[http://gliethttp.cublog.cn] mdesc = setup_machine(machine_arch_type);//mdesc指向机器描述空间单元 //++++++++++++++ //arch/arm/mach-at91rm9200/Core.c //位于.arch.info段 //MACHINE_START(AT91RM9200, "ATMEL AT91RM9200")//.nr = MACH_TYPE_##_type=MACH_TYPE_AT91RM9200=251 //与上面从u-boot传到r1中的一样[gliethttp] //MAINTAINER("SAN People / ATMEL") //BOOT_MEM(AT91_SDRAM_BASE, AT91C_BASE_SYS, AT91C_VA_BASE_SYS) //BOOT_PARAMS(AT91_SDRAM_BASE + 0x100)//tag list存放的物理地址0x20000100[gliethttp] //FIXUP(at91rm9200_fixup) //MAPIO(at91rm9200_map_io) //INITIRQ(at91rm9200_init_irq) //MACHINE_END[gliethttp] //-------------- machine_name = mdesc->name;//machine_name="ATMEL AT91RM9200"
if (mdesc->soft_reboot)//mdesc->soft_reboot初值为1 reboot_setup("s");//分析见后
if (mdesc->param_offset)//mdesc->param_offset=AT91_SDRAM_BASE + 0x100=物理地址0x20000100 tags = phys_to_virt(mdesc->param_offset);//将tag list物理地址转换成虚拟地址,以便访问
if (mdesc->fixup)//调用at91rm9200_fixup()修正函数,分析见后 mdesc->fixup(mdesc, (struct param_struct *)tags, &from, &meminfo); //很明显由bootloader[u-boot-1.1.5]传递到物理地址0x20000100处的参数是tag list结构[gliethttp] if (tags->hdr.tag != ATAG_CORE) convert_to_tag_list(tags); //对于tag list的生成,请参考《浅析setup_arch()函数tag_list的uboot[u-boot]由来》[http://gliethttp.cublog.cn]
if (tags->hdr.tag == ATAG_CORE) { if (meminfo.nr_banks != 0)//如果是tag list,那么如果系统已经创建了默认的meminfo.nr_banks squash_mem_tags(tags);//那么使用squash_mem_tags失效所有ATAG_MEM初始化的东东为ATAG_NONE,tag->hdr.size不变 parse_tags(tags); }
if (meminfo.nr_banks == 0) {//如果tag list中没有传递ATAG_MEM参数,那么采用编译时的默认配置值 meminfo.nr_banks = 1; meminfo.bank[0].start = PHYS_OFFSET;//0x20000000 meminfo.bank[0].size = MEM_SIZE;//32M } //_text,_etext,_edata,_end参见arch/arm/vmlinux-armv.lds.in链接脚本 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;
memcpy(saved_command_line, from, COMMAND_LINE_SIZE); saved_command_line[COMMAND_LINE_SIZE-1] = '\0';//追0,防止非法字符串越界 //parse_cmdline,主要完成phys_initrd_start,phys_initrd_size和mem的解析,并将*cmdline_p=command_line全局量 parse_cmdline(&meminfo, cmdline_p, from); //将kernel自身和位图管理页占用的页对应的页位图置1,标识相应页已被占用 //将initrd占用的页对应的页位图置1,标识相应页已被占用[gliethttp] bootmem_init(&meminfo); //清空页目录项,建立at91rm9200中断向量表空间和io寄存器空间从虚拟地址到物理地址的映射表 //建立map位图和page页管理空间,以及free_area.map位图管理空间等 paging_init(&meminfo, mdesc); request_standard_resources(&meminfo, mdesc);//登记注册所有需要登记注册的cpu总线上的设备实体 init_arch_irq = mdesc->init_irq;//中断初始化函数指针
#ifdef CONFIG_VT #if defined(CONFIG_VGA_CONSOLE) conswitchp = &vga_con;//显示设备指针conswitchp指向vga_con设备 #elif defined(CONFIG_DUMMY_CONSOLE)//frambuffer选中后,就会使用dummy_con设备 conswitchp = &dummy_con;//显示设备指针conswitchp指向dummy_con设备 #endif #endif } //2.arch/arm/kernel/Process.c->reboot_setup() static char reboot_mode = 'h'; int __init reboot_setup(char *str) { //reboot_mode将在machine_restart()系统重启时arch_reset()使用 reboot_mode = str[0];//reboot_mode='s'; return 1; } //3.arch/arm/mach-at91rm9200/Core.c->at91rm9200_fixup static void __init at91rm9200_fixup(struct machine_desc *desc, struct param_struct *unused, char **cmdline, struct meminfo *mi) { #ifdef CONFIG_BLK_DEV_INITRD//CONFIG_BLK_DEV_INITRD = 1
//设置根目录为ramdisk ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);//0x100 //由make menuconfig产生CONFIG_BLK_DEV_RAM_SIZE = 15360k = 15M setup_ramdisk(1, 0, 0, CONFIG_BLK_DEV_RAM_SIZE); // setup_initrd(0xc0100000, 3*1024*1024); #endif } void __init setup_ramdisk(int doload, int prompt, int image_start, unsigned int rd_sz) { #ifdef CONFIG_BLK_DEV_RAM extern int rd_size, rd_image_start, rd_prompt, rd_doload; rd_image_start = image_start; rd_prompt = prompt; rd_doload = doload; if (rd_sz) rd_size = rd_sz;//15M #endif } //4.解析tag list中各个元素,进而改变内核全局量,来影响内核 //arch/arm/kernel/Setup.c->parse_tags() static void __init parse_tags(const struct tag *t) { for (; t->hdr.size; t = tag_next(t)) if (!parse_tag(t))//解析该t printk(KERN_WARNING "Ignoring unrecognised tag 0x%08x\n", t->hdr.tag); } //5.arch/arm/kernel/Setup.c->parse_tag() static int __init parse_tag(const struct tag *tag) { extern struct tagtable __tagtable_begin, __tagtable_end; struct tagtable *t; for (t = &__tagtable_begin; t < &__tagtable_end; t++) if (tag->hdr.tag == t->tag) { t->parse(tag); break; } return t < &__tagtable_end;//找到匹配项,1;否则0 } //arch/arm/vmlinux-armv.lds.in链接脚本中有如下定以 //... //__tagtable_begin = .; //*(.taglist) //__tagtable_end = .; //... //在include/asm-arm/Setup.h中有如下定义 #define __tag __attribute__((unused, __section__(".taglist"))) #define __tagtable(tag, fn) \ static struct tagtable __tagtable_##fn __tag = { tag, fn } __tagtable(ATAG_CORE, parse_tag_core);//ATAG_CORE解析函数parse_tag_core __tagtable(ATAG_MEM, parse_tag_mem32);//ATAG_MEM解析函数parse_tag_mem32 __tagtable(ATAG_RAMDISK, parse_tag_ramdisk);//ATAG_RAMDISK解析函数parse_tag_ramdisk __tagtable(ATAG_INITRD, parse_tag_initrd);//ATAG_INITRD解析函数parse_tag_initrd __tagtable(ATAG_SERIAL, parse_tag_serialnr);//ATAG_SERIAL解析函数parse_tag_serialnr __tagtable(ATAG_CMDLINE, parse_tag_cmdline);//ATAG_CMDLINE解析函数parse_tag_cmdline ......等
|