全面解析Linux 内核 3.10.x - 板级初始化 - setup_arch
2017-06-29 08:13
477 查看
From: 全面解析Linux 内核 3.10.x - 本文章完全基于MIPS架构
且看我的ubuntu 12.04的第一条打印语句
内核代码:
linux_banner 是个变长buff位于init/version.c文件
宏的内容位于 include/generated/compile.h
Note: compile.h文件是编译生成的,并不属于内核源码!
不管是移动端,桌面还是服务器市场上,x86独秀一枝花,MIPS系列的CPU都很孤单!曾今的耀眼到如今的孤单,像是看破了人世间的种种! 网络关于这部分基本都是x86 或者 ARM为主的内容,那么我就来说说MIPS吧!
setup_arch
函数做的事情(MIPS,x86,ARM)根据体系架构的不同,初始化也有所不同!
Mips:
总结,setup_arch做了以下几件事情:
1.CPU配置初始化 - cpu_probe()
通过上面代码,可得知:
1>此函数先是读取协处理器0中处理器ID(PRId)寄存器获取版本后,进行对应CPU的处理!
2>获取之后,根据厂商信息进行cpu_probe_xxxx()函数
此函数分两部分:
第一主要通过decode_configs()函数通过协处理器0的16(Config),18(WatchLo),$19(WatchHi)寄存器对CPU进行,如图2,图3!
第二根据厂商信息确定CPU_TYPE,确定指令level,确定tlbsize大小!
对于此部分并不是每个人都需要去了解的,有兴趣的可以See 下面的链接!
1.协处理器0,MIPS控制处理器详解
上述xlp_mmu_init函数开启了外部TLB,通过已知的页表大小配置得到页掩码,来而新刷新TLB!
之后紧接着又获取了一些基地址信息!
关于MMU以及TLB,请戳这里MIPS- TLB介绍
printk console注册流程
上述代码就是要printk 可以将信息打印早当前的console上,如果有兴趣研究console的工作流程,推荐查看Documentation/coonsole/console.txt
因为之前在cpu_probe的时候就已经将相关信息保存到cpuinfo_mips结构体中,在此处将CPU/FPU ID以及name打印出来!
此处一般检查
因为当前没有配置CONFIG_VGA_CONSOLE此宏,故而此处跳过!
其实这里叫板级内存初始化有点牵强,此处其实做了好几件事情!
在当前版本中,此函数主要做了4件事!
a.打印内存映射 - print_memory_map
b.引导内存分配器进行初始化- bootmem_init
要弄清楚上述两个问题需要结合架构进行分析,先来了解下MIPS的地址空间以及映射关系,请分别戳
c.Device Tree 结构初始化 - device_tree_init
何谓DTS,我这里总结了一篇总结,请戳 全面解析Linux 内核 3.10.x -
Device Tree 详解!
d.页表初始化
关于页表以及页框等内容我页将其专门总结到一起!戳
By: Keven - 点滴积累
九层之台,起于垒土 千里之行,始于足下 - 老子
从dmesg的第一条打印信息说起 - Linux banner
且看我的ubuntu 12.04的第一条打印语句Linux version 3.11.0-15-generic (buildd@allspice) (gcc version 4.6.3 (Ubuntu/ Linaro 4.6.3-1ubuntu5) ) #25~precise1-Ubuntu SMP Thu Jan 30 17:39:31 UTC 2014 (Ubuntu 3.11.0-15.25~precise1-generic 3.11.10)
内核代码:
printk(KERN_NOTICE "%s", linux_banner);
linux_banner 是个变长buff位于init/version.c文件
const char linux_banner[] = "Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@" LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION "\n";
宏的内容位于 include/generated/compile.h
Note: compile.h文件是编译生成的,并不属于内核源码!
我叫Mips,可他们都是x86 - setup_arch
不管是移动端,桌面还是服务器市场上,x86独秀一枝花,MIPS系列的CPU都很孤单!曾今的耀眼到如今的孤单,像是看破了人世间的种种! 网络关于这部分基本都是x86 或者 ARM为主的内容,那么我就来说说MIPS吧!setup_arch
函数做的事情(MIPS,x86,ARM)根据体系架构的不同,初始化也有所不同!
Mips:
void __init setup_arch(char **cmdline_p) { cpu_probe(); prom_init(); #ifdef CONFIG_EARLY_PRINTK setup_early_printk(); #endif cpu_report(); check_bugs_early(); #if defined(CONFIG_VT) #if defined(CONFIG_VGA_CONSOLE) conswitchp = &vga_con; #elif defined(CONFIG_DUMMY_CONSOLE) conswitchp = &dummy_con; #endif #endif arch_mem_init(cmdline_p); resource_init(); plat_smp_setup(); cpu_cache_init(); }
总结,setup_arch做了以下几件事情:
1.CPU配置初始化 - cpu_probe()
__cpuinit void cpu_probe(void) { struct cpuinfo_mips *c = ¤t_cpu_data; unsigned int cpu = smp_processor_id(); #1.读取CP0(协处理器0的PRId($15)寄存器获取版本号 c->processor_id = PRID_IMP_UNKNOWN; c->fpu_id = FPIR_IMP_NONE; c->cputype = CPU_UNKNOWN; c->processor_id = read_c0_prid(); switch (c->processor_id & 0xff0000) { case PRID_COMP_LEGACY: cpu_probe_legacy(c, cpu); break; case PRID_COMP_MIPS: cpu_probe_mips(c, cpu); break; case PRID_COMP_ALCHEMY: cpu_probe_alchemy(c, cpu); break; case PRID_COMP_SIBYTE: cpu_probe_sibyte(c, cpu); break; case PRID_COMP_BROADCOM: cpu_probe_broadcom(c, cpu); break; case PRID_COMP_SANDCRAFT: cpu_probe_sandcraft(c, cpu); break; case PRID_COMP_NXP: cpu_probe_nxp(c, cpu); break; case PRID_COMP_CAVIUM: cpu_probe_cavium(c, cpu); break; case PRID_COMP_INGENIC: cpu_probe_ingenic(c, cpu); break; case PRID_COMP_NETLOGIC: cpu_probe_netlogic(c, cpu); break; } BUG_ON(!__cpu_name[cpu]); BUG_ON(c->cputype == CPU_UNKNOWN); /* * Platform code can force the cpu type to optimize code * generation. In that case be sure the cpu type is correctly * manually setup otherwise it could trigger some nasty bugs. */ BUG_ON(current_cpu_type() != c->cputype); if (mips_fpu_disabled) c->options &= ~MIPS_CPU_FPU; if (mips_dsp_disabled) c->ases &= ~(MIPS_ASE_DSP | MIPS_ASE_DSP2P); if (c->options & MIPS_CPU_FPU) { c->fpu_id = cpu_get_fpu_id(); if (c->isa_level == MIPS_CPU_ISA_M32R1 || c->isa_level == MIPS_CPU_ISA_M32R2 || c->isa_level == MIPS_CPU_ISA_M64R1 || c->isa_level == MIPS_CPU_ISA_M64R2) { if (c->fpu_id & MIPS_FPIR_3D) c->ases |= MIPS_ASE_MIPS3D; } } if (cpu_has_mips_r2) { c->srsets = ((read_c0_srsctl() >> 26) & 0x0f) + 1; /* R2 has Performance Counter Interrupt indicator */ c->options |= MIPS_CPU_PCI; } else c->srsets = 1; cpu_probe_vmbits(c); #ifdef CONFIG_64BIT if (cpu == 0) __ua_limit = ~((1ull << cpu_vmbits) - 1); #endif }
通过上面代码,可得知:
1>此函数先是读取协处理器0中处理器ID(PRId)寄存器获取版本后,进行对应CPU的处理!
+----------------+----------------+----------------+----------------+ | Company Options| Company ID | Processor ID | Revision | +----------------+----------------+----------------+----------------+ 31 24 23 16 15 8 7 图1 协处理器0 PRId寄存器
2>获取之后,根据厂商信息进行cpu_probe_xxxx()函数
此函数分两部分:
第一主要通过decode_configs()函数通过协处理器0的16(Config),18(WatchLo),$19(WatchHi)寄存器对CPU进行,如图2,图3!
+----+------+------+----+----+----+----+----+----+----+----+----+---+-----+----+----+----+----+----+ | CM | EC | EP | SB | SS | SW | EW | SC | SM | BE | EM | EB | 0 | IC | DC | IB | DB | CU | KO | +----+------+------+----+----+----+----+----+----+----+----+----+---+-----+----+----+----+----+----+ 31 30 28 27 24 23 22 21 20 19 18 17 16 15 14 13 12 11 9 8 6 5 4 3 2 0 图2 Config 寄存器 +----------------+-------+-----+---------+ | MatchAddr | 0 | R | W | +----------------+-------+-----+---------+ 31 3 2 1 0 图3 WatchLo/Hi 寄存器 Config寄存器主要设置的Bit是 WatchLo/Hi寄存器主要去设置的Bit是
第二根据厂商信息确定CPU_TYPE,确定指令level,确定tlbsize大小!
对于此部分并不是每个人都需要去了解的,有兴趣的可以See 下面的链接!
1.协处理器0,MIPS控制处理器详解
2.简单配置MMU以及获取基地址初始化 - [prom_init]()
void __init prom_init(void) { nlm_io_base = CKSEG1ADDR(XLP_DEFAULT_IO_BASE); xlp_mmu_init(); nlm_node_init(0); #ifdef CONFIG_SMP cpumask_setall(&nlm_cpumask); nlm_wakeup_secondary_cpus(); /* update TLB size after waking up threads */ current_cpu_data.tlbsize = ((read_c0_config6() >> 16) & 0xffff) + 1; register_smp_ops(&nlm_smp_ops); #endif }
上述xlp_mmu_init函数开启了外部TLB,通过已知的页表大小配置得到页掩码,来而新刷新TLB!
之后紧接着又获取了一些基地址信息!
关于MMU以及TLB,请戳这里MIPS- TLB介绍
3.printk console - setup_early_printk
printk console注册流程void __init setup_early_printk(void) { if (early_console) return; early_console = &early_console_prom; register_console(&early_console_prom); }
上述代码就是要printk 可以将信息打印早当前的console上,如果有兴趣研究console的工作流程,推荐查看Documentation/coonsole/console.txt
4.打印CPU版本以及FPU版本信息 - cpu_report
因为之前在cpu_probe的时候就已经将相关信息保存到cpuinfo_mips结构体中,在此处将CPU/FPU ID以及name打印出来!
5. 检查多线程 - cpu_chechbugs
此处一般检查
6. VGA初始化
因为当前没有配置CONFIG_VGA_CONSOLE此宏,故而此处跳过!
7. 板级内存初始化 -arch_mem_init
其实这里叫板级内存初始化有点牵强,此处其实做了好几件事情! 在当前版本中,此函数主要做了4件事!
a.打印内存映射 - print_memory_map
b.引导内存分配器进行初始化- bootmem_init
要弄清楚上述两个问题需要结合架构进行分析,先来了解下MIPS的地址空间以及映射关系,请分别戳
c.Device Tree 结构初始化 - device_tree_init
何谓DTS,我这里总结了一篇总结,请戳 全面解析Linux 内核 3.10.x -
Device Tree 详解!
d.页表初始化
关于页表以及页框等内容我页将其专门总结到一起!戳
8. CPU Cache初始化 - cpu_cache_init
此函数将对cpu的缓存进行初始化配置,这里暂时不去管它!
By: Keven - 点滴积累
相关文章推荐
- 全面解析Linux 内核 3.10.x - 板级初始化 - setup_arch
- 全面解析Linux 内核 3.10.x - 内核进程
- 全面解析Linux 内核 3.10.x - 内存管理 - 伙伴系统算法(Buddy System)
- linux-3.2.36内核启动2-setup_arch中的内存初始化1(arm平台 分析高端内存和初始化memblock)【转】
- linux-3.2.36内核启动4-setup_arch中的内存初始化3(arm平台 bootmem_init源码分析)
- 全面解析Linux 内核 3.10.x - 抉择
- 全面解析Linux 内核 3.10.x - 编译前的准备
- 全面解析Linux 内核 3.10.x - 如何开始
- 全面解析Linux 内核 3.10.x - Pid hash 链表
- 全面解析Linux 内核 3.10.x - start_kernel()
- linux-3.2.36内核启动4-setup_arch中的内存初始化3(arm平台 bootmem_init源码分析)
- linux-3.2.36内核启动2-setup_arch中的内存初始化1(arm平台 分析高端内存和初始化memblock)
- 全面解析Linux 内核 3.10.x - 内存管理 - SLUB分配器
- 全面解析Linux 内核 3.10.x - 内存管理 - 内存模型
- 全面解析Linux 内核 3.10.x - initramfs 启动流程
- 全面解析Linux 内核 3.10.x - 内存管理 - 高端地址的内核映射
- 全面解析Linux 内核 3.10.x - initramfs 启动流程
- 全面解析Linux 内核 3.10.x - 调度算法 - Linux 调度器
- 全面解析Linux 内核 3.10.x - 如何开始
- linux-3.2.36内核启动3-setup_arch中的内存初始化2(arm平台 分析建立页表)