当前位置: 首页 > 科技观察

说说Linux内核入门分析

时间:2023-03-19 17:25:28 科技观察

本文转载自微信公众号《嵌入式Linux系统开发》,作者Jasonangel。转载本文请联系嵌入式Linux系统开发公众号。从bootloader(uboot)跳转到Linux内核后,Linux内核启动。今天我们就来分析下Linux内核的启动入口。跳转到过去,初始化肯定在汇编文件里。可以根据架构选择不同的平台。这里有一个汇编文件的链接:linux4.14/arch/arm/kernel/vmlinux.lds.S这里可以看到链接时的linux入口是stext段,这里是bootloader的第一段linux代码跳转到:Linux入口地址我们先看入口地址来判断,同一个文件。SECTIONS{/**XXX:当存在多个语句*匹配相同的输入部分名称时,链接器未定义如何将输出部分*分配给输入部分。没有记录*匹配顺序。**unwindexit部分必须在其他*unwind部分被包含之前被丢弃。*//DISCARD.exittext/:{*x.exit.ARMtext)ARM_CPU_DISCARDit..text))ARM_CPU_DISCARD(*(.ARM.extab.cpuexit.text))ARM_EXIT_DISCARD(EXIT_TEXT)ARM_EXIT_DISCARD(EXIT_DATA)EXIT_CALL#ifndefCONFIG_MMU*(.text.fixup)*(__ex_table)#endif#ifndefCONFIG_SMP_ON_UP*(.alt.smp.init)#endif*(.discard)*(.discard.*)}.=PAGE_OFFSET+TEXT_OFFSET;.head.text:{_text=.;HEAD_TEXT}这个SECTIONS比较长,只放一部分。这里有一个比较重要的东西:.=PAGE_OFFSET+TEXT_OFFSET;这句话表示Linux系统真正的启动地址。PAGE_OFFSET是Linux内核空间的虚拟起始地址,定义在:linux4.14/arch/arm64/include/asm/memory.h注意这里的地址很重要,很多地方都会用到。当然,这里的地址可能会随着Linux内核版本的不同,硬件的不同而不同。这里没有具体的数字,因为VA_BITS中的数字是可选的,大家可以根据自己的平台来计算。TEXT_OFFSET定义在:linux4.14/arch/arm/Makefile:这个值一般是0x00008000,计算PAGE_OFFSET后加上这个值就是Linux内核的起始地址。修改这个偏移量可以将Linux内核拷贝到不同的地址,自己修改要注意内存对齐。由上面的ENTRY(stext)可以知道stext段,stext段是在最开始运行的,这一段的代码是start_kernel函数之前的汇编环境的初始化。linux4.14/arch/arm64/kernel/head.Spreserve_boot_args保存了bootloader传过来的参数。el2_setup是设置linux启动模式为EL2。Linux有四种异常启动模式:EL0、EL1、EL2、EL3。这里的设置一开始是EL2,EL2支持虚拟内存技术,然后注释后返回EL1,在EL1中启动内核。EL3一般只在安全模式下使用。set_cpu_boot_mode_flag保存了上述cpu的启动模式。__create_page_tables创建页表。__cpu_setup初始化CPU,这里主要初始化与MMU内存相关的CPU部分。__primary_switch会跳转到这里。在同一个文件中,会跳转到这里,第739行打开MMU。然后最重要的就是跳转到__primary_switched函数。先将__primary_switched地址放入x8寄存器,然后跳转到x8,即跳转到__primary_switched。接下来分析__primary_switched函数:324-327初始化init进程的内存信息,开辟内存空间。329-334设置向量表。336-340保存FDT,也就是平面设备树。342-348清空了BSS段,我们知道内存一般有四个区域:堆区、栈区、全局区、代码区。全局区又可以分为数据段和BSS段。BSS段存储未初始化的变量。此处,BSS段被清除。否则,内存中的值是不确定的。这是一个传统的操作。