设为首页 加入收藏

TOP

ARM64启动汇编和内存初始化(上) --- (一)(一)
2023-07-23 13:25:41 】 浏览:122
Tags:ARM64 ---
文章代码分析基于linux-5.19.13,架构基于aarch64(ARM64)。
涉及页表代码分析部分:
(1)假设页表映射层级是4,即配置CONFIG_ARM64_PGTABLE_LEVELS=4;
(2)虚拟地址宽度是48,即配置CONFIG_ARM64_VA_BITS=48;
(3)物理地址宽度是48,即配置CONFIG_ARM64_PA_BITS=48;

1. 入口分析

1.1 链接脚本arch/arm64/kernel/vmlinux.lds.S

??这里只列举与内存初始化相关的定义,其它的采用“......”省略。

......
OUTPUT_ARCH(aarch64)    '指定一个特定的输出机器架构为aarch64'                       
ENTRY(_text)            '设置入口地址,实现在arch/arm64/kernel/head.S'
......

SECTIONS
{
        ......
                           '在5.8内核版本发现TEXT_OFFSET没有任何作用,因此,被重新定义为0x0'
	. = KIMAGE_VADDR;  '内核映像虚拟的起始地址(在5.8内核之前这里为KIMAGE_VADDR + TEXT_OFFSET)'

	.head.text : {     '早期汇编代码的text段'
		_text = .; '入口地址'
		HEAD_TEXT   定义在include/asm-generic/vmlinux.lds.h'#define HEAD_TEXT  KEEP(*(.head.text))'
	}
	.text : ALIGN(SEGMENT_ALIGN) {	/* Real text segment		*/   
		_stext = .;		/* Text and read-only data	*/ 'text段起始'
                ......
	}
        ......
	. = ALIGN(SEGMENT_ALIGN);
	_etext = .;			/* End of text section */ 'text段结束'

	/* everything from this point to __init_begin will be marked RO NX */
	RO_DATA(PAGE_SIZE)   '只读数据段'
        ......
	idmap_pg_dir = .;  '恒等映射一级页表地址'
	. += IDMAP_DIR_SIZE;
	idmap_pg_end = .;

#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
	tramp_pg_dir = .;  '熔断(安全漏洞引入)'
	. += PAGE_SIZE;
#endif

	reserved_pg_dir = .;
	. += PAGE_SIZE;

	swapper_pg_dir = .;
	. += PAGE_SIZE;

	. = ALIGN(SEGMENT_ALIGN);
	__init_begin = .;       'init段起始'
	__inittext_begin = .;
        ......
	. = ALIGN(SEGMENT_ALIGN);
	__initdata_end = .;
	__init_end = .;  'init段结束'

	_data = .;
	_sdata = .;      '数据段起始'
	RW_DATA(L1_CACHE_BYTES, PAGE_SIZE, THREAD_ALIGN)


	_edata = .;      '数据段结束'

	BSS_SECTION(SBSS_ALIGN, 0, 0)      --- 'BSS段'

	. = ALIGN(PAGE_SIZE);
	init_pg_dir = .;
	. += INIT_DIR_SIZE;
	init_pg_end = .;
        ......
}

1.2 入口

#arch/arm64/kernel/head.S
/*
 * Kernel startup entry point.
 * ---------------------------
 *
 * The requirements are:
 *   MMU = off, D-cache = off, I-cache = on or off,
 *   x0 = physical address to the FDT blob.
 *
 * This code is mostly position independent so you call this at
 * __pa(PAGE_OFFSET).
 *
 * Note that the callee-saved registers are used for storing variables
 * that are useful before the MMU is enabled. The allocations are described
 * in the entry routines.
 */
	__HEAD          --- 定义在include/linux/init.h中'#define __HEAD		.section	".head.text","ax"',紧接着_text
	/*
	 * DO NOT MODIFY. Image header expected by Linux boot-loaders.
	 */
	efi_signature_nop			// special NOP to identity as PE/COFF executable
	b	primary_entry			// branch to kernel start, magic      '要重点关注分析的启动汇编代码'
        ......

1.3 启动 AArch64 Linux的调用约定

??内核从上电开始到执行到内核入口"_text",中间要经过bootloader或者bios的引导。引导程序会做一些初始化内存,设置device tree,解压内核,跳转到内核等等。在跳转到内核之前,有一些标准的约定,参见Documentation/translations/zh_CN/arm64/booting.txt。这里仅列出在跳转入内核前,必须符合以下章节的状态:

在跳转入内核前,必须符合以下状态:
- 停止所有 DMA 设备,这样内存数据就不会因为虚假网络包或磁盘数据而 被破坏。这可能可以节省你许多的调试时间。
- 主 CPU 通用寄存器设置 x0 = 系统 RAM 中设备树数据块(dtb)的物理地址。
  x1 = 0 (保留,将来可能使用)
  x2 = 0 (保留,将来可能使用)
  x3 = 0 (保留,将来可能使用)
- CPU 模式 所有形式的中断必须在 PSTATE.DAIF 中被屏蔽(Debug、SError、IRQ 和 FIQ)。
  CPU 必须处于 EL2(推荐,可访问虚拟化扩展)或非安全 EL1 模式下。'bootloader来切'
- 高速缓存、MMU MMU 必须关闭。 'mmu关闭,指令高速缓存一般可以打开,数据高速缓存必须关闭'
  指令缓存开启或关闭皆可。 已载入的内核映像的相应内存区必须被清理,以达到缓存一致性点(PoC)。 当存在系统缓存或其他使能缓存的一致性主控器时,通常需使用虚拟地址 维护其缓存,而非 set/way 操作。 遵从通过虚拟地址操作维护构架缓存的系统缓存必须被配置,并可以被使能。 而不通过虚拟地址操作维护构架缓存的系统缓存(不推荐),必须被配置且 禁用。
  *译者注:对于 PoC 以及缓存相关内容,请参考 ARMv8 构架参考手册 ARM DDI 0487A
- 架构计时器 CNTFRQ 必须设定为计时器的频率,且 CNTVOFF 必须设定为对
首页 上一页 1 2 3 4 5 6 7 下一页 尾页 1/8/8
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇沁恒 CH32V208(一): CH32V208WBU6.. 下一篇微控制器实时操作系统实践5选择IDE

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目