我是靠谱客的博主 欣慰导师,最近开发中收集的这篇文章主要介绍x210:uboot和系统移植扩展--内核启动之汇编初始化阶段,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

链接脚本分析

  • kernel的连接脚本并不是直接提供的,而是提供了一个汇编文件vmlinux.lds.S,然后在编译的时候再去编译这个汇编文件得到真正的链接脚本vmlinux.lds。
  • vmlinux.lds.S在arch/arm/kernel/目录下。
  • 为什么linux kernel不直接提供vmlinux.lds而要提供一个vmlinux.lds.S然后在编译时才去动态生成vmlinux.lds呢?猜测:.lds文件中只能写死,不能用条件编译。但是我们在kernel中链接脚本确实有条件编译的需求(但是lds格式又不支持),于是乎kernel工作者找了个投机取巧的方法,就是把vmlinux.lds写成一个汇编格式,然后汇编器处理的时候顺便条件编译给处理了,得到一个不需要条件编译的vmlinux.lds。 
  • 从vmlinux.lds中ENTRY(stext)可以知道入口符号是stext,可知kernel的起始是在arch/arm/kernel/head.S中
  • 链接脚本的SECTIONS里面的开头有一句. = 0xC0000000 + 0x00008000;可知其链接地址为0xC0008000,因为内核运行时需要开启MMU,所以这是一个虚拟地址。那么它的物理地址是多少呢,见下面head.S文件分析。

head.S文件分析

(1)内核运行的物理地址与虚拟地址

#define KERNEL_RAM_VADDR	(PAGE_OFFSET + TEXT_OFFSET)
#define KERNEL_RAM_PADDR	(PHYS_OFFSET + TEXT_OFFSET)

KERNEL_RAM_VADDR,这个宏定义了内核运行时的虚拟地址。值为0xC0008000

KERNEL_RAM_PADDR,这个宏定义内核运行时的物理地址。值为0x30008000


 以下是解析过程 

PAGE_OFFSET定义在arch/arm/include/asm/memory.h中

#ifdef CONFIG_MMU

/*
 * PAGE_OFFSET - the virtual address of the start of the kernel image
 * TASK_SIZE - the maximum size of a user space task.
 * TASK_UNMAPPED_BASE - the lower boundary of the mmap VM area
 */
#define PAGE_OFFSET		UL(CONFIG_PAGE_OFFSET)
......
#else /* CONFIG_MMU */
......
#ifndef PAGE_OFFSET
#define PAGE_OFFSET		(PHYS_OFFSET)
#endif
#endif /* !CONFIG_MMU */

从make生成的.config文件可以看出我们有定义CONFIG_MMU,所以PAGE_OFFSET的值等于CONFIG_PAGE_OFFSET,在.config中可以看到CONFIG_PAGE_OFFSET的值为0xC0000000,所以PAGE_OFFSET的值为0xC000000

在linux下使用grep命令搜索TEXT_OFFSET可知它的值为0x00008000

PHYS_OFFSET定义在arch/arm/mach-s5pv210/include/mach/memory.h中

#define PHYS_OFFSET		UL(0x30000000)

(2)CONFIG_XIP_KERNEL与就地执行有关,一般用于Norflash

(3)注释详解

/*
 * Kernel startup entry point.
 * ---------------------------
 *
 * This is normally called from the decompressor code.  The requirements
 * are: MMU = off, D-cache = off, I-cache = dont care, r0 = 0,
 * r1 = machine nr, r2 = atags pointer.
 *
 * This code is mostly position independent, so if you link the kernel at
 * 0xc0008000, you call this at __pa(0xc0008000).
 *
 * See linux/arch/arm/tools/mach-types for the complete list of machine
 * numbers for r1.
 *
 * We're trying to keep crap to a minimum; DO NOT add any machine specific
 * crap here - that's what the boot loader (or in extreme, well justified
 * circumstances, zImage) is for.
 */
  • 内核的起始部分代码是被解压代码调用的。回忆之前讲zImage的时候,uboot启动内核后实际调用运行的是zImage前面的那段未经压缩的解压代码,解压代码运行时先将zImage后段的内核解压开,然后再去调用运行真正的内核入口。 
  • uboot中最后theKernel (0, machid, bd->bi_boot_params);执行内核时,运行时实际把0放入r0中,machid放入到了r1中,bd->bi_boot_params放入到了r2中。ARM的这种处理技巧刚好满足了kernel启动的条件和要求。
  • kernel启动时MMU是关闭的,因此硬件上需要的是物理地址。但是内核是一个整体(zImage)只能被连接到一个地址(不能分散加载),这个连接地址肯定是虚拟地址。因此内核运行时前段head.S中尚未开启MMU之前的这段代码就很难受。所以这段代码必须是位置无关码,而且其中涉及到操作硬件寄存器等时必须使用物理地址
  • 在arch/arm/tools/mach-types中保存着linux所支持的所有开发板的机器码
  • 这段代码应该尽量的小,不要把机器有关的代码放在这里,而应该在bootloader中执行

(4)__HEAD定义了后面的代码属于段名为.head.text的段

内核启动的汇编阶段

  • 关闭IRQ和FIQ中断并设置为SVC模式
  • 从cp15协处理器的c0中读取cpu的id号到寄存器r9
  • 执行__lookup_processor_type函数,进行CPU合法性检验

(1)我们从cp15协处理器的c0寄存器中读取出硬件的CPU ID号,然后调用这个函数来进行合法性检验。如果合法则继续启动,如果不合法则停止启动,转向__error_p启动失败。

(2)该函数检验cpu id的合法性方法是:内核会维护一个本内核支持的CPU ID号码的数组,然后该函数所做的就是将从硬件中读取的cpu id号码和数组中存储的各个id号码依次对比,如果没有一个相等则不合法,如果有一个相等的则合法。

  • 执行__lookup_machine_type函数进行机器码检验
  • 执行__vet_atags函数校验uboot给内核的传参ATAGS格式是否正确
  • 执行__create_page_tables函数建立段式页表

(1)kernel建立页表其实分为2步。第一步,kernel先建立了一个段式页表(和uboot中之前建立的页表一样,页表以1MB为单位来区分的),这里的函数就是建立段式页表的。段式页表本身比较好建立(段式页表1MB一个映射,4GB空间需要4096个页表项,每个页表项4字节,因此一共需要16KB内存来做页表),坏处是比较粗不能精细管理内存;第二步,再去建立一个细页表(4kB为单位的细页表),然后启用新的细页表废除第一步建立的段式映射页表。

(2)内核启动的早期建立段式页表,并在内核启动前期使用;内核启动后期就会再次建立细页表并启用。等内核工作起来之后就只有细页表了。

  • 保存__switch_data的地址到寄存器r13中
__switch_data:
	.long	__mmap_switched
	.long	__data_loc			@ r4
	.long	_data				@ r5
	.long	__bss_start			@ r6
	.long	_end				@ r7
	.long	processor_id			@ r4
	.long	__machine_arch_type		@ r5
	.long	__atags_pointer			@ r6
	.long	cr_alignment			@ r7
	.long	init_thread_union + THREAD_START_SP @ sp

(1)__switch_data类似于一个long类型的数组,每个元素占4个字节。他里面包含了函数的首地址、一些段的地址以及一些数据

  • 保存__enable_mmu的地址到寄存器lr中
  •  

最后

以上就是欣慰导师为你收集整理的x210:uboot和系统移植扩展--内核启动之汇编初始化阶段的全部内容,希望文章能够帮你解决x210:uboot和系统移植扩展--内核启动之汇编初始化阶段所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(42)

评论列表共有 0 条评论

立即
投稿
返回
顶部