设为首页 加入收藏

TOP

ARM64启动汇编和内存初始化(上) --- (一)(三)
2023-07-23 13:25:41 】 浏览:129
Tags:ARM64 ---
SYM_INNER_LABEL(init_el1, SYM_L_LOCAL) mov_q x0, INIT_SCTLR_EL1_MMU_OFF msr sctlr_el1, x0 isb '因为前面修改了系统控制器' mov_q x0, INIT_PSTATE_EL1 msr spsr_el1, x0 msr elr_el1, lr mov w0, #BOOT_CPU_MODE_EL1 eret 'Return from exception' SYM_INNER_LABEL(init_el2, SYM_L_LOCAL) --- 'EL2切向EL1' ...... msr elr_el1, x0 eret 1: ...... mov w0, #BOOT_CPU_MODE_EL2 eret __cpu_stick_to_vhe: mov x0, #HVC_VHE_RESTART hvc #0 mov x0, #BOOT_CPU_MODE_EL2 ret SYM_FUNC_END(init_kernel_el)

2.3 set_cpu_boot_mode_flag

??根据w0中传递的cpu启动模式设置__boot_cpu_mode标志。

/*
 * Sets the __boot_cpu_mode flag depending on the CPU boot mode passed
 * in w0. See arch/arm64/include/asm/virt.h for more info.
 */
SYM_FUNC_START_LOCAL(set_cpu_boot_mode_flag)
	adr_l	x1, __boot_cpu_mode             //x1记录__boot_cpu_mode[]的地址
	cmp	w0, #BOOT_CPU_MODE_EL2          //w0记录启动时的异常等级
	b.ne	1f                              //如果不是从EL2启动,则跳转到1处
	add	x1, x1, #4                      // 如果是从EL2启动,地址指向__boot_cpu_mode[1]
1:	str	w0, [x1]			// Save CPU boot mode 保存启动模式到x1指向的地址,如果是从EL1启动,地址指向__boot_cpu_mode[0]
	dmb	sy                              // 保证str指令执行完成
	dc	ivac, x1			// Invalidate potentially stale cache line 使高速缓存失效
	ret
SYM_FUNC_END(set_cpu_boot_mode_flag)

2.4 __create_page_tables

/*
 * Setup the initial page tables. We only setup the barest amount which is
 * required to get the kernel running. The following sections are required:
 *   - identity mapping to enable the MMU (low address, TTBR0)    (1)恒等映射
 *   - first few MB of the kernel linear mapping to jump to once the MMU has
 *     been enabled                                               (2)内核image映射
 */
SYM_FUNC_START_LOCAL(__create_page_tables)
 ...
SYM_FUNC_END(__create_page_tables)

2.4.1 保存LR值

mov	x28, lr                                         //#把LR的值存放到X28

2.4.2 使初始化页表无效、并清空初始化页表

	/*
	 * Invalidate the init page tables to avoid potential dirty cache lines
	 * being evicted. Other page tables are allocated in rodata as part of
	 * the kernel image, and thus are clean to the PoC per the boot
	 * protocol.
	 */
	adrp	x0, init_pg_dir   //把init_pg_dir的物理地址赋值给x0
	adrp	x1, init_pg_end   //把init_pg_end的物理地址赋值给x1
	bl	dcache_inval_poc  //把init_pg_dir页表对应的高速缓存清掉(入参是x0和x1)


	/*
	 * Clear the init page tables.//把这个页表内容清零
	 */
	adrp	x0, init_pg_dir
	adrp	x1, init_pg_end
	sub	x1, x1, x0
1:	stp	xzr, xzr, [x0], #16 //xzr是零寄存器
	stp	xzr, xzr, [x0], #16
	stp	xzr, xzr, [x0], #16
	stp	xzr, xzr, [x0], #16
	subs	x1, x1, #64
	b.ne	1b

(1)init_pg_dir和init_pg_end定义在arch/arm64/kernel/vmlinux.lds.S链接文件中:

#arch/arm64/kernel/vmlinux.lds.S
	. = ALIGN(PAGE_SIZE);
	init_pg_dir = .;
	. += INIT_DIR_SIZE;
	init_pg_end = .;

(2)adrp指令

作用:以页为单位的大范围的地址读取指令,这里的P就是page的意思。
原理:符号扩展一个21位的offset(immhi+immlo), 向左移动12位,PC的值的低12位清零,然后把这两者相加,结果写入到Xd寄存器,用来得到一块含有lable的4KB对齐内存区域的base地址(也就是说lable所在的地址,一定落在这个4KB的内存区域里,指令助记符里Page也就是这个意思), 可用来寻址 +/- 4GB的范围(2^33次幂)。
通俗来讲,ADRP指令就是先进行PC+imm(偏移值)。然后找到lable所在的一个4KB的页,然后取得label的基址,再进行偏移去寻址。

ADRP {cond} Rd label

其中:Rd加载的目标寄存器。lable为地址表达式。

(3)使用adrp指令获取init_pg_dir和init_pg_end的地址,页大小为4KB,由于内核启动的时候MMU还未打开(PC为物理地址),因此此时获取的地址也为物理地址。
(4)adrp通过当前PC地址的偏移地址计算目标地址,和实际的物理地址无关,因此属于位置无关码
?

2.4.3 保存SWAPPER_MM_MMUFLAGS到x7寄存器

mov_q	x7, SWAPPER_MM_MMUFLAGS  

SWAPPER_MM_MMUFLAGS宏描述了段映射的属性,它实现在arch/arm64/include/asm/kernel-pgtable.h头文件中:

/*
 * Initial memory map attributes.
 */
#define SWAPPER_PTE_FLAGS	(PTE_TYPE_PAGE | PTE_AF | PTE_SHARED | PTE_UXN)
#define SWAPPER_PMD_FLAGS	(PMD_TYPE_SECT
首页 上一页 1 2 3 4 5 6 7 下一页 尾页 3/8/8
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇沁恒 CH32V208(一): CH32V208WBU6.. 下一篇微控制器实时操作系统实践5选择IDE

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目