通过 Linux 的构建系统,即 Linux 源代码的根目录下的 Makefile,能够找到 vmlinux 的链接文件,从而能够查看其入口代码 head.S:_start, 如下:
Linux 构建系统主Makefile:
vmlinux.lds:
head.S:
找到该入口后,就可以开始读汇编代码了。
head.S 的代码解析有很多相关文章,感兴趣的读者可以自行搜索,这里就不一一细说了,因为本系列的文章主要关注在虚拟内存的机制,head.S 是一个铺垫。
推荐:
RISCVlinuxkernel启动代码分析之一:启动汇编部分代码
Linux内核riscv head.S分析
即,在 relocate_enable_mmu中的 csrw CSR_SATP, a0 前,linux 都是使用物理地址的,之后全使用虚拟地址。
简单来说,从 _start 开始,linux kernel 做了以下动作:
1. 跳入 _start_kernel:
2. 屏蔽所有中断:
3. 使能 S mode 下的 time CSR。
4. 加载 global pointer
5. 失效浮点和向量操作
6. 零化(zero initialize) BSS:
7. 保存 启动核 id:
8. 初始化页表:其中,
tp 为 (task_struct *) init_task,即第一个进程描述结构, PID = 0。
sp 为其栈地址,为了调用 c 函数 setup_vm。
a0 为 dtb地址 。
setup_vm 的函数原型为 asmlinkage void __init setup_vm(uintptr_t dtb_pa); 。
setup_vm 主要是初始化了:
1. struct kernel_mapping kernel_map __ro_after_init;
2. pgd_t early_pg_dir[PTRS_PER_PGD] __initdata __aligned(PAGE_SIZE);
3. pgd_t trampoline_pg_dir[PTRS_PER_PGD] __page_aligned_bss;
9. 启动虚拟地址访问:
10. 设置中断异常入口,准备C环境,调用 soc 初始化,最终进入 start_kernel (Linux 的 main 函数)。
至此,head.S 的功能大致如此,下一篇文章就开始详细地描述 setup_vm 函数,以及 trampoline_pg_dir 、early_pg_dir 的作用。