Linux arm 启动 c语言部分详解第一讲(from Start kernel) 下载本文

内容发布更新时间 : 2024/11/9 7:01:59星期一 下面是文章的全部内容请认真阅读。

[原创]Linux arm 启动 c语言部分详解第一讲(from Start kernel)

?? ??

??written by leeming ??

??作为我们实验室的一个学术交流,我顺着fp的linux arm启动汇编部分继续下去。我们可以看到其实linux汇编部分的启动大量的工作是对zimage的解压,重定位等操作,如果是image(也就是zimage解压重定位结束后)来说,其实主要就做了以下这么几件事情:1.建立启动时的一级页表,2.打开mmu,3.保存机器号等参数。 ??

??因此对于整个处理器系统来说还需要做大量的工作,对于移植内核来说,只有真正了解了这部分你才会明白在arch/arm/mach-sep4020这个目录中的文件为什么需要这样写。进入正题: ??

??1.进入start_kernel,详解setup_arch(处理器的移植,页表建立都在这里实现的) ??

??asmlinkage void __init start_kernel(void) ?? ??{ ??

??       char * command_line; ??

??       extern struct kernel_param __start___param[], __stop___param[]; ?? ??/* ??

?? * Interrupts are still disabled. Do necessary setups, then ??

?? * enable them ?? ?? */ ??

??       lock_kernel(); ?? ?? ??

??       //这里是和高端内存相关的操作,arm中不涉及 ??

??       page_address_init(); ??

??       //这个只是printk的等级,但是为什么在控制台不显示,待看 ??

??       //这时候控制台还没有初始化,因此所有的信息都是在

log_buf里 ??

??       printk(KERN_NOTICE); ??

??       printk(linux_banner); ??

??       setup_arch(&command_line); ??

??       …… ??

??       …… ?? ?? ??

??到这里就碰到了我们详解start kernel的第一道坎,setup_arch(&command_line);别看就一句话,其实这个函数本身是非常庞大的,下面我们来具体看完整的setup_arch函数。 ??

??void __init setup_arch(char **cmdline_p) ?? ??{ ??

??       struct tag *tags = (struct tag *)&init_tags; ??

?? struct machine_desc *mdesc; ??

??//in the arch/arm/kernel/setup.c ??

??//static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE; ??

??//在我们的配置中#define CONFIG_CMDLINE "root=/dev/ram0 rw console=ttyS0,115200" ??

?? char *from = default_command_line; ??

?? //就是查找你是什么版本的处理器架构,最后就是调用 ??

?? //了lookup_processor_type这个函数,它在汇编部分也提到过 ??

?? setup_processor(); ??

?? //machine_arch_type 就是我们的机器号0xc2 ??

?? mdesc = setup_machine(machine_arch_type);

??

?? machine_name = mdesc->name; ??

?? //这个变量初始值为"h",如果这里设置成softboot,它会将这个初始值变为"s" ??

?? if (mdesc->soft_reboot) ??

??  reboot_setup("s"); ??

?? //boot_params 如果为0则表示bootloader没有传参数 ??

?? //一般默认为0x30000100位置 ??

?? if (mdesc->boot_params) ??

??  tags = phys_to_virt(mdesc->boot_params); ?? ?? /* ??

??  * If we have the old style parameters, convert them to ??

??  * a tag list. ??

??  */ ??

?? if (tags->hdr.tag != ATAG_CORE) ??

??  convert_to_tag_list(tags); ??

?? if (tags->hdr.tag != ATAG_CORE) ??

??  tags = (struct tag *)&init_tags; ??

?? if (mdesc->fixup) ??

??  mdesc->fixup(mdesc, tags, &from, &meminfo); ??

?? //是通过标签0x544100**来辨别的,因此uboot中有相应的标签字 ??

?? if (tags->hdr.tag == ATAG_CORE) { ??

??  //已经被fixup函数修改,则将atag中的mem段置为none ??

??  if (meminfo.nr_banks != 0) ??

??   squash_mem_tags(tags); ??

??  //继续把atag的参数传递结束,在这里将把uboot传递进来的commandline覆盖 ??

??  parse_tags(tags); ?? ?? } ??

??//下面几个参数是由vmlinux.lds文件决定的 ??

?? 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; ??

?? //因此在这里已经是我们uboot的参数了。 ??

?? memcpy(saved_command_line, from, COMMAND_LINE_SIZE); ??

?? saved_command_line[COMMAND_LINE_SIZE-1] = ‘\\0’; ??

??//分析cmdline,这里只分析了当中的mem部分。 ??

??//内核参数的解析一共有两处,一处是setup_arch()->parse_cmdline() ??

??//用于解析内核参数中关于内存的部分,另外一处是start_kernel()->parse_option()用于解析其余部分 ??

?? parse_cmdline(cmdline_p, from); ?? ?? ??

??//非常重要的部分,页表建立,根据meminfo,也就是我们在4020.c中的mache_start何mache_end之间的内容,它其实就是一个类型是machine_desc的结构体,这里就是把这个结构体中的内存信息(fixup函数中指定的),寄存器信息(sep4020_map_io指定的)建立相应的一二级页表 ??

??/*************************************/

??

??       paging_init(&meminfo, mdesc); ??

??/*************************************/ ??

??       request_standard_resources(&meminfo, mdesc); ?? ?? ??

??#ifdef CONFIG_SMP ??

??       smp_init_cpus(); ??

??#endif ?? ?? ??

??//设置不同模式的堆栈,包括3种模式,irq,abort,undefine,每种模式的堆栈是12个字节 ??

??       cpu_init(); ?? ??{ ??

??       //gcc内嵌汇编的格式是__asm(汇编代码:输入:输出:破坏描述部分); ??

??       //下面的限制字符"r" "I"是把变量放进通用寄存器,立即数的意思 ??

??       __asm__ ( ??

??       "msr       cpsr_c, %1\\n\\t" ??

??       "add      sp, %0, %2\\n\\t" ??

??       "msr       cpsr_c, %3\\n\\t" ??

??       "add      sp, %0, %4\\n\\t" ??

??       "msr       cpsr_c, %5\\n\\t" ??

??       "add      sp, %0, %6\\n\\t" ??

??       "msr       cpsr_c, %7"