Chinaunix首页 | 论坛 | 博客
  • 博客访问: 6846
  • 博文数量: 5
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 10
  • 用 户 组: 普通用户
  • 注册时间: 2021-05-28 14:33
文章分类
文章存档

2021年(5)

我的朋友
最近访客

分类: LINUX

2021-05-28 14:36:51

执行setup_arch()函数
回到start_kernel当中,488行,调用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 ()

arch/arm/kernel/setup.c
 877 void __init setup_arch(char **cmdline_p)
 878 {
 879         struct machine_desc *mdesc;
 880
 881         unwind_init(); //本架构中没有用
 882
 883         setup_processor();//汇编的CPU初始化部分
 884         mdesc = setup_machine_fdt(__atags_pointer);//__atags_pointer是bootloader传递参数的物理地址
 885         if (!mdesc)
 886                 mdesc = setup_machine_tags(machine_arch_type);
 887         machine_desc = mdesc;
 888         machine_name = mdesc->name;
 889
 890         if (mdesc->soft_reboot)
 891                 reboot_setup("s");
 892
 893         init_mm.start_code = (unsigned long) _text;
 894         init_mm.end_code   = (unsigned long) _etext;
 895         init_mm.end_data   = (unsigned long) _edata;
 896         init_mm.brk        = (unsigned long) _end;
 897
 898         /* populate cmd_line too for later use, preserving boot_command_line */
 899         strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);
 900         *cmdline_p = cmd_line;
 901
 902         parse_early_param();
 903
 904         sanity_check_meminfo();
 905         arm_memblock_init(&meminfo, mdesc);
 906
 907         paging_init(mdesc);
 908         request_standard_resources(mdesc);
 909
 910         unflatten_device_tree();
 911
 912 #ifdef CONFIG_SMP
 913         if (is_smp())
 914                 smp_init_cpus();
 915 #endif
 916         reserve_crashkernel();
 917
 918         cpu_init();//此函数为空
 919         tcm_init();
 920
 921 #ifdef CONFIG_MULTI_IRQ_HANDLER
 922         handle_arch_irq = mdesc->handle_irq;
 923 #endif
 924
 925 #ifdef CONFIG_VT
 926 #if defined(CONFIG_VGA_CONSOLE)
 927         conswitchp = &vga_con;
 928 #elif defined(CONFIG_DUMMY_CONSOLE)
 929         conswitchp = &dummy_con;
 930 #endif
 931 #endif
 932         early_trap_init();//重定位中断向量,将中断向量代码拷贝到中断向量页,并把信号处理代码指令拷贝到向量页中
 933
 934         if (mdesc->init_early)
 935                 mdesc->init_early();
 936 }


 879行完整的machine_desc结构描述如下:arch/arm/include/asm/mach/arch.h
 13 struct tag;
 14 struct meminfo;
 15 struct sys_timer;
 16
 17 struct machine_desc {
 18         unsigned int            nr;             /* 开发板的机器类型ID*/
 19         const char              *name;          /* 开发板名称 */
 20         unsigned long           boot_params;    /* 内核启动参数的地址*/
 21         const char              **dt_compat;    /* array of device tree
 22                                                  * 'compatible' strings */
 23
 24         unsigned int            nr_irqs;        /* number of IRQs */
 25
 26         unsigned int            video_start;    /* start of video RAM   */
 27         unsigned int            video_end;      /* end of video RAM     */
 28
 29         unsigned int            reserve_lp0 :1; /* never has lp0        */
 30         unsigned int            reserve_lp1 :1; /* never has lp1        */
 31         unsigned int            reserve_lp2 :1; /* never has lp2        */
 32         unsigned int            soft_reboot :1; /* soft reboot          */
 33         void                    (*fixup)(struct machine_desc *,
 34                                          struct tag *, char **,
 35                                          struct meminfo *);
 36         void                    (*reserve)(void);/* reserve mem blocks  */
 37         void                    (*map_io)(void);/* IO映射函数(在这里修改时钟频率)*/
 38         void                    (*init_early)(void);
 39         void                    (*init_irq)(void);  /*中断初始化函数*/
 40         struct sys_timer        *timer;         /* system tick timer    */
 41         void                    (*init_machine)(void);
 42 #ifdef CONFIG_MULTI_IRQ_HANDLER
 43         void                    (*handle_irq)(struct pt_regs *);
 44 #endif
 45 };

884行__atags_pointer是bootloader传递参数的物理地址,见第一阶段启动源码第100行(str r2, [r6]),此处r6就是__atags_pointer的地址,它将bootloader通过r2传递过来的地址参数存放到__atags_pointer。

下面我们来看setup_machine_fdt函数,它在arch/arm/kernel/devtree.c中定义如下:
 71 struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys)
 72 {
 73         struct boot_param_header *devtree;
 74         struct machine_desc *mdesc, *mdesc_best = NULL;
 75         unsigned int score, mdesc_score = ~1;
 76         unsigned long dt_root;
 77         const char *model;
 78
 79         if (!dt_phys)
 80                 return NULL;
 81
 82         devtree = phys_to_virt(dt_phys);//由于MMU单元已打开,此处__atags_pointer是物理地址,需要转换成虚拟地址才能访问,因为此时CPU访问的都是虚拟地址
 83
 84         /* check device tree validity */
 85         if (be32_to_cpu(devtree->magic) != OF_DT_HEADER)
 86                 return NULL;
 87
 88         /* Search the mdescs for the 'best' compatible value match */
 89         initial_boot_params = devtree;
 90         dt_root = of_get_flat_dt_root(); 该函数用来查找在dtb中的根节点
 91         for_each_machine_desc(mdesc) {
 92                 score = of_flat_dt_match(dt_root, mdesc->dt_compat);
 93                 if (score > 0 && score < mdesc_score) {
 94                         mdesc_best = mdesc;
 95                         mdesc_score = score;
 96                 }
 97         }
 98         if (!mdesc_best) {
 99                 const char *prop;
100                 long size;
101
102                 early_print("\nError: unrecognized/unsupported "
103                             "device tree compatible list:\n[ ");
104
105                 prop = of_get_flat_dt_prop(dt_root, "compatible", &size);
106                 while (size > 0) {
107                         early_print("'%s' ", prop);
108                         size -= strlen(prop) + 1;
109                         prop += strlen(prop) + 1;
110                 }
111                 early_print("]\n\n");
112
113                 dump_machine_table(); /* does not return */
114         }
115
116         model = of_get_flat_dt_prop(dt_root, "model", NULL);
117         if (!model)
118                 model = of_get_flat_dt_prop(dt_root, "compatible", NULL);
119         if (!model)
120                 model = "";
121         pr_info("Machine: %s, model: %s\n", mdesc_best->name, model);
122
123         /* Retrieve various information from the /chosen node */
124         of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line);
125         /* Initialize {size,address}-cells info */
126         of_scan_flat_dt(early_init_dt_scan_root, NULL);
127         /* Setup memory, calling early_init_dt_add_memory_arch */
128         of_scan_flat_dt(early_init_dt_scan_memory, NULL);
129
130         /* Change machine number to match the mdesc we're using */
131         __machine_arch_type = mdesc_best->nr;
132
133         return mdesc_best;
134 }
boot_param_header结构在include/linux/of_fdt.h第44行定义如下:
struct boot_param_header {
    __be32    magic;            /* magic word OF_DT_HEADER */
    __be32    totalsize;        /* total size of DT block */
    __be32    off_dt_struct;        /* offset to structure */
    __be32    off_dt_strings;        /* offset to strings */
    __be32    off_mem_rsvmap;        /* offset to memory reserve map */
    __be32    version;        /* format version */
    __be32    last_comp_version;    /* last compatible version */
    /* version 2 fields below */
    __be32    boot_cpuid_phys;    /* Physical CPU id we're booting on */
    /* version 3 fields below */
    __be32    dt_strings_size;    /* size of the DT strings block */
    /* version 17 fields below */
    __be32    dt_struct_size;        /* size of the DT structure block */
};
第89行initial_boot_params在同文件下第436行有定义struct boot_param_header *initial_boot_params;
第90行of_get_flat_dt_root()函数用来查找在dtb中的根节点(drivers/of/fdt.c)
unsigned long __init of_get_flat_dt_root(void)
{
    unsigned long p = ((unsigned long)initial_boot_params) +
        be32_to_cpu(initial_boot_params->off_dt_struct);

    while (be32_to_cpup((__be32 *)p) == OF_DT_NOP)
        p += 4;
    BUG_ON(be32_to_cpup((__be32 *)p) != OF_DT_BEGIN_NODE);
    p += 4;
    return ALIGN(p + strlen((char *)p) + 1, 4);
}

第91行在arch/arm/include/asm/mach/arch.h中定义如下
 55 extern struct machine_desc __arch_info_begin[], __arch_info_end[];
 56 #define for_each_machine_desc(p)                        \
 57         for (p = __arch_info_begin; p < __arch_info_end; p++)
 58
 59 /*
 60  * Set of macros to define architecture features.  This is built into
 61  * a table by the linker.
 62  */
 63 #define MACHINE_START(_type,_name)                      \
 64 static const struct machine_desc __mach_desc_##_type    \
 65  __used                                                 \
 66  __attribute__((__section__(".arch.info.init"))) = {    \
 67         .nr             = MACH_TYPE_##_type,            \
 68         .name           = _name,
 69
 70 #define MACHINE_END                             \
 71 };

int __init of_flat_dt_match(unsigned long node, const char **compat)
{
    return of_fdt_match(initial_boot_params, node, compat);
}
如果node与兼容表中的值匹配则返回真
int of_fdt_match(struct boot_param_header *blob, unsigned long node,
                 const char **compat)
{
    unsigned int tmp, score = 0;

    if (!compat)
        return 0;

    while (*compat) {
        tmp = of_fdt_is_compatible(blob, node, *compat);
        if (tmp && (score == 0 || (tmp < score)))
            score = tmp;
        compat++;
    }

    return score;
}
阅读(739) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~