🗒️linux内核源码解析01–启动代码分析之汇编部分
2024-7-25
| 2024-11-4
字数 4373阅读时长 11 分钟
type
status
date
slug
summary
tags
category
icon
password
URL

linux内核源码解析01–启动代码分析之汇编部分

首先是引导程序,即bootloader,简单说即bootloader会做如下事情:(1)初始化物理内存;(2)设置设备树;(3)解压缩内核映像,将其加载到内核运行地址(可选);(4)跳转到内核入口地址; 下面进入Linux范畴:

链接脚本vmlinux.lds.S

第一个要看的文件,“arch/arm64/kernel/vmlinux.lds.S”, Linux内核的链接脚本
Linux内核的内存布局定义
查看vmlinux文件
notion image
补充:用gdb单步调试内核时,启用MMU之前的代码,无法单步,究其原因,qemu默认的内存地址是0x40000000与链接脚本默认的KIMAGE_VADDR不一致,需要做一个重定位; 从以上vmlinux文件可知,几个重要段相对偏移是:
加上qemu运行物理内存地址0x40000000,加载vmlinux时,设置如下 导入vmlinux命令为:
notion image
设置PC值 这样就可以对启用MMU之前的代码,正常设置断点,单步调试; ## 确认内核入口地址的方法
notion image
反汇编vmlinux文件
notion image
notion image

head.S文件

Bootload初始化完毕后,会跳转到内核入口处; 从head.S文件的
可看出入口代码位于.init.text段,因此当设置PC值
pc指针跳到
下面正式进入Linux单步运行环境; 首先,启动Linux对软硬件的需求如下:
进入Linux内核,汇编部分主要完成以下工作:
下面细看每个函数内容 # preserve_boot_args()函数

init_kernel_el函数

设置ARM64运行等级

set_cpu_boot_mode_flag

__create_page_tables

///创建恒等映射页表,以及内核映像映射页表

恒等映射

(1)CPU启动时,MMU是关闭的,CPU访问的是物理地址,而MMU开启后,访问的是虚拟地址;(2)现代处理器大多支持多级流水线,处理器会提前预取多条指令到流水线中,当打开MMU时,CPU已经预取多条指令到流水线中,并且这些指令都是用物理地址预取的; MMU开启后,将以虚拟地址访问,这样继续访问流水线中预取的指令(按物理地址预取),就很容易出错; 为解决这个问题,引入“恒等映射”,即将虚拟地址映射到相等的物理地址,可以巧妙的解决上述问题; 这里建立的恒等映射是小范围的,一般内核镜像占用的空间就几M; 恒等映射完毕,开启MMU,CPU进入虚拟地址访问阶段;

map_memory宏分析

compute_indices 宏

populate_entries宏

综上,.idmap.text段的虚拟地址映射到了相同的物理地址上,这个映射表在idmap_pg_dir中;

问题:那些函数在这个映射的2MB内存中?

由head.s中的定义知
__enable_mmu, __primary_switch, __cput_setup等汇编函数都在.idmap.text段中; 可以从System.map文件中得到验证; 这些函数在Linux“自举”过程中会用到;

粗粒度的内核镜像映射

问题:为什么要创建第二个页表?

CPU刚启动时,物理内存一般都在低地址(不会超过256T大小),恒等映射的地址实际在用户空间了,即MMU启用后idmap_pg_dir会填入TTBR0; 而内核空间的链接地址都是在高地址(内核空间在高地址),需要填入TTBR1; 因此,这里再建一张表,映射整个内核镜像,且虚拟地址空间是在高地址区0xffffxxxx xxxx xxxx

__cpu_setup函数

// initialise processor ///为打开MMU做一些处理器相关的初始化

__primary_switch函数

///启动MMU,并跳转到start_kernel()函数(进入内核的C语言部分)

__enable_mmu函数

__primary_switched函数

 
 
  • linux kernel
  • 必看精选
  • C3U升V 正式签名版本不开机linux内核源码解析02–启动代码分析之固定映射
    Loading...