logo资料库

基于smp模式的linux多核启动分析.docx

第1页 / 共6页
第2页 / 共6页
第3页 / 共6页
第4页 / 共6页
第5页 / 共6页
第6页 / 共6页
资料共6页,全文预览结束
1.概述
2.kernel启动基本流程介绍
kernel 启动分析讲解 文件状态:  草稿  正式发布  正在修改 作 者: john 当前版本: V0.1 完成日期: 审 定:
版本历史 版本/状态 V0.1 作者 参与者 起止日期 2015.11.11 新建 备注
1. 概述 本文档的目的是帮助理解 zynq 底层 kernel 启动过程,本项目采用的是 SMP 的系统架构模式,从而了解单板在内核系统启动阶段多核加载,总线初始化,外 设初始化的过程。本文重点介绍对单板关键外设初始化注册与调用分析,例如 NAND FLASH,以太网,串口, USB 协议栈等做了介绍。下面就围绕以上几个 关键外设进行分析。 2. kernel 启动基本流程介绍 系统启动过程极为复杂,可以分为以下几个重要环境分别分析 图 1 kernel 启动过程流程图 1) start.S 文件 系统启动阶段,首先定义了内核存放的实际物理地址为 0x8000,堆栈向上 增长的方式, * 0x0 - 0x4000 - reserving below not to be used by DMA * 0x4000 - 0x8000 swapper page table 并且定义了 #define PG_DIR_SIZE 0x4000 //4k page size #define PMD_ORDER 2 //2 order
每页的大小为 4K,并且页目录为 2 级目录,而后获取 cpu type,然后利用 __create_page_tables 函数建立 PGD,PMD 目录项。 __create_page_tables //head.S __mmap_switched //head_common.S 文件中 start_kernel //main.c 文件中 以上的代码均在汇编语言中完成,从 start_kernel 函数,开始 C 语言的函数执行。 2) main.c 文件 在该文件中对内核的初始化工作非常多,也非常复杂,下面挑出和多核 cpu 启动相关的部分,以及和设备驱动的部分讲解。 多核 CPU 启动过程中,首先是 CPU0 启动,包括 uboot 阶段,以及在 main.c 函数之前的部分都是在 CPU0 上执行的。在 main.c 函数中的 setup_arch 函数中, 一个 cpu 执行的情况将彻底结束。下面是函数调用的关系。 setup_arch//初始化与当前 cpu 相关的部分,每个 cpu 厂家,初始化代码不同 setup_processor//查询当前 cpu id 是否支持 lookup_processor_type//调用 head_common.S 文件中的代码获取 cpu id setup_machine_tags// for_each_machine_desc//查询 arch_info 结构体定义,查找与 machine_nr 一致的 cpu 此处应该重点说明的是对于每种 cpu 在 arch/arm/mach-zynq 的 common.c 文件中,通常会声 明一个重要结构体: DT_MACHINE_START(XILINX_EP107, "Xilinx Zynq Platform") .smp = smp_ops(zynq_smp_ops), .map_io = zynq_map_io, .init_irq = zynq_irq_init, .init_machine = zynq_init_machine, .init_late = zynq_init_late, .init_time = zynq_timer_init, .dt_compat = zynq_dt_match, .reserve = zynq_memory_init, .restart = zynq_system_reset, MACHINE_END 其中宏定义 MACHINE_START 属性如下: #define MACHINE_START(_type,_name) static const struct machine_desc __mach_desc_##_type \
__used \ __attribute__((__section__(".arch.info.init"))) = { \ .nr = MACH_TYPE_##_type, \ .name = _name, #define MACHINE_END \ }; 该结构体通过连接脚本 vmlinux.lds 链接,编译的时候,编译器根据链接脚 本的指定,将此部分结构体统一放在.arch.info.init 部分。系统启动阶段通过链接 脚本加载,查询是否支持当前 cpu,并且调用相关函数。 setup_arch//初始化与当前 cpu 相关的部分,每个 cpu 厂家,初始化代码不同 setup_processor//查询当前 cpu id 是否支持 lookup_processor_type//调用 head_common.S 文件中的代码获取 cpu id setup_machine_tags// for_each_machine_desc//查询 arch_info 结构体定义,查找与 machine_nr 一致的 cpu parse_early_param//早期参数初始化 paging_init //页表初始化 else if (mdesc->smp)//由于此处的 zynq 函数有定义所以执行 smp_set_ops smp_set_ops(mdesc->smp); 其中 mdesc->smp 在此处定义 DT_MACHINE_START(XILINX_EP107, "Xilinx Zynq Platform") .smp = smp_ops(zynq_smp_ops), 而 zynq_smp_ops 定义如下 struct smp_operations zynq_smp_ops __initdata = { .smp_init_cpus = zynq_smp_init_cpus, 设置相关 smp 相关结构体,最终的 CPU0 外的其他核启动是在 rest_init kernel_init kernel_init_freeable(); smp_init(); for_each_present_cpu(cpu) //对于每个 cpu 都会调用 cpu_up,是一个循环 cpu_up(cpu); __cpu_up boot_secondary
if (smp_ops.smp_boot_secondary) return smp_ops.smp_boot_secondary(cpu, idle); 对于 zynq 在初始化阶段.smp_boot_secondary = zynq_boot_secondary, zynq_boot_secondary zynq_cpun_start(virt_to_phys(zynq_secondary_startup), cpu); ENTRY(zynq_secondary_startup) bl b v7_invalidate_l1 secondary_startup ENDPROC(zynq_secondary_startup) 经过下面的初始化后,CPU0 外的其他 CPU 才真正的启动。
分享到:
收藏