历史上的今天
返回首页

历史上的今天

今天是:2025年01月20日(星期一)

正在发生

2020年01月20日 | ARMv8 Linux内核head.S源码分析

2020-01-20 来源:eefocus

ARMv8Linux内核head.S主要工作内容:


1、 从el2特权级退回到el1


2、 确认处理器类型


3、 计算内核镜像的起始物理地址及物理地址与虚拟地址之间的偏移


4、 验证设备树的地址是否有效


5、 创建页表,用于启动内核


6、 设置CPU(cpu_setup),用于使能MMU


7、 使能MMU


8、 交换数据段


9、 跳转到start_kernel函数继续运行。


/*


 *Low-level CPU initialisation


 *Based on arch/arm/kernel/head.S


 *


 *Copyright (C) 1994-2002 Russell King


 *Copyright (C) 2003-2012 ARM Ltd.


 *Authors:     Catalin Marinas


 *             Will Deacon


 *


 *This program is free software; you can redistribute it and/or modify


 * itunder the terms of the GNU General Public License version 2 as


 *published by the Free Software Foundation.


 *


 *This program is distributed in the hope that it will be useful,


 *but WITHOUT ANY WARRANTY; without even the implied warranty of


 *MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the


 *GNU General Public License for more details.


 *


 *You should have received a copy of the GNU General Public License


 *along with this program.  If not, see.


 */


#include


#include


#include


#include


#include


#include


#include


#include


#include


#include


/*


 *swapper_pg_dir is the virtual address of the initial page table. We place


 *the page tables 3 * PAGE_SIZE below KERNEL_RAM_VADDR. The idmap_pg_dir has


 * 2pages and is placed below swapper_pg_dir.


 */


#define KERNEL_RAM_VADDR      (PAGE_OFFSET + TEXT_OFFSET)


#if (KERNEL_RAM_VADDR & 0xfffff) !=0x80000


#error KERNEL_RAM_VADDR must start at0xXXX80000


#endif


#define SWAPPER_DIR_SIZE  (3 * PAGE_SIZE)


#define IDMAP_DIR_SIZE                (2 * PAGE_SIZE)


         .globl       swapper_pg_dir


         .equ swapper_pg_dir, KERNEL_RAM_VADDR -SWAPPER_DIR_SIZE


         .globl       idmap_pg_dir


         .equ idmap_pg_dir, swapper_pg_dir - IDMAP_DIR_SIZE


         .macro     pgtbl, ttb0, ttb1, phys


         add  ttb1, phys, #TEXT_OFFSET - SWAPPER_DIR_SIZE


         sub   ttb0, ttb1, #IDMAP_DIR_SIZE


         .endm


#ifdef CONFIG_ARM64_64K_PAGES


#define BLOCK_SHIFT    PAGE_SHIFT


#define BLOCK_SIZE       PAGE_SIZE


#else


#define BLOCK_SHIFT    SECTION_SHIFT


#define BLOCK_SIZE       SECTION_SIZE


#endif


#define KERNEL_START KERNEL_RAM_VADDR


#define KERNEL_END     _end


/*


 *Initial memory map attributes.


 */


#ifndef CONFIG_SMP


#define PTE_FLAGS         PTE_TYPE_PAGE | PTE_AF


#define PMD_FLAGS       PMD_TYPE_SECT | PMD_SECT_AF


#else


#define PTE_FLAGS         PTE_TYPE_PAGE | PTE_AF | PTE_SHARED


#define PMD_FLAGS       PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S


#endif


#ifdef CONFIG_ARM64_64K_PAGES


#define MM_MMUFLAGS      PTE_ATTRINDX(MT_NORMAL) | PTE_FLAGS


#define IO_MMUFLAGS PTE_ATTRINDX(MT_DEVICE_nGnRE) | PTE_XN | PTE_FLAGS


#else


#define MM_MMUFLAGS      PMD_ATTRINDX(MT_NORMAL) | PMD_FLAGS


#define IO_MMUFLAGS PMD_ATTRINDX(MT_DEVICE_nGnRE) | PMD_SECT_XN | PMD_FLAGS


#endif


/*


 *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 + TEXT_OFFSET).


 *


 *Note that the callee-saved registers are used for storing variables


 *that are useful before the MMU is enabled. The allocations are described


 * inthe entry routines.


 */


         __HEAD                    //这是一个宏定义;#define__HEAD          .section         ".head.text","ax"; .section是伪指令ax代表允许执行


         /*


          * DO NOT MODIFY. Image header expected byLinux boot-loaders.


          */


         b       stext                                   //branch to kernel start, magic


         .long        0                                 //reserved


         .quad       TEXT_OFFSET                   // Image load offset from start of RAM


         .quad       0                                 //reserved


         .quad       0                                 //reserved


ENTRY(stext)


         mov x21, x0                               //x21=FDT,x21中保存的是由Uboot传进来的,设备树在内存中的地址。


         bl      el2_setup                          //Drop to EL1,从当前特权级跳入EL1,具体函数内容请看下面el2_setup函数。


         mrs  x22, midr_el1                   //x22=cpuid,x22中保存着cpuid,用以判断运行当前这段代码的CPU是哪一个。


         mov x0, x22                               //x0=cpuid,用于传送参数给函数lookup_processor_type。


         bl      lookup_processor_type //查看处理器类型,见后面具体定义


         mov x23, x0                               //x23=current cpu_table       把函数lookup_processor_type返回的cpu_table地址给x23


         cbz   x23, __error_p                          // invalid processor (x23=0)?


         bl      __calc_phys_offset                 //计算起始物理地址,返回的值中x24=PHYS_OFFSET, x28=PHYS_OFFSET-PAGE_OFFSET


         bl      __vet_fdt                                   //返回后的x21中要么是无效保存0,要么是有效地fdt地址


         bl      __create_page_tables            //为内核创建临时页表 x25=TTBR0,x26=TTBR1,本函数所建立的页表在后面paging_init会销毁重建。


         /*


          * The following calls CPU specific code in aposition independent


          * manner. See arch/arm64/mm/proc.S fordetails. x23 = base of


          * cpu_info structure selected bylookup_processor_type above.


          * On return, the CPU will be ready for the MMUto be turned on and


          * the TCR will have been set.


          */


         ldr    x27, __switch_data                 //由函数__enable_mmu中调用,此时MMU已经开启


         adr   lr, __enable_mmu           //返回“地址无关”的地址,由函数__cpu_setup返回时调用,该函数中执行brx27调用__switch_data函数


         ldr    x12, [x23,#CPU_INFO_SETUP]


         add  x12, x12, x28                    // __virt_to_phys


         br     x12                             //x12中存放的是cpu_info结构体的cpu_setup字段


                                                     //该字段在cpu_table中被初始化为__cpu_setup函数,所里这里调用cpu_setup,不在本文件中暂不分析


                                                     //该函数返回后会把lr给pc,即直接调用上面的__enable_mmu


ENDPROC(stext)


/*


 * If we're fortunate enough to boot at EL2,ensure that the world is


 * sane before dropping to EL1.


 */


ENTRY(el2_setup)


         mrs  x0, CurrentEL                                     //获得当前特权级


         cmp x0, #PSR_MODE_EL2t                      //对比当前特权级是否为EL2


         ccmp        x0,#PSR_MODE_EL2h, #0x4, ne   //NZCV= if notequal then CMP(x0,# PSR_MODE_EL2h) else 0x4


         b.eq 1f


         ret

推荐阅读

史海拾趣

Chip Supply Micro Devices公司的发展小趣事

在微电子器件领域,Chip Supply Micro Devices凭借一项创新技术,成功打破了市场格局。公司研发出了一种新型低功耗芯片,不仅提高了电子设备的性能,还降低了能源消耗。这一技术突破使得Chip Supply Micro Devices迅速获得了市场的认可,产品销量激增。公司借此机会扩大生产规模,加大研发投入,进一步巩固了其在微电子器件市场的地位。

Fermionics Lasertech Inc公司的发展小趣事

随着公司规模的不断扩大,Fermionics Lasertech Inc公司开始寻求国际合作与全球布局。他们与国外的知名企业和研究机构建立了紧密的合作关系,共同开展技术研发和市场拓展。同时,公司还在海外设立了多个分支机构和办事处,以便更好地服务当地客户。这些举措不仅提升了公司的国际影响力,还为公司的长期发展提供了有力保障。

Cyrix Corp公司的发展小趣事

在被VIA收购后的一段时间里,Cyrix继续寻求市场扩张的机会。例如,在1998年,Cyrix与北京大船电子技术公司签订了总代理协议,以扩大其在中国的分销网络。这一策略帮助Cyrix进一步打开了中国市场的大门,为其在全球市场的发展奠定了基础。

以上五个故事描绘了Cyrix Corp公司在电子行业中的发展历程。从初创时期的挑战英特尔到被多次收购后的市场策略调整和市场扩张尝试,Cyrix的发展之路充满了曲折和变革。

FCI / Amphenol公司的发展小趣事

Amphenol公司成立于1932年,最初由Arthur J. Schmitt和Gordon K. Klapmeier共同创办,专注于电磁线缆的制造。然而,随着技术的进步和市场需求的变化,Amphenol公司逐渐将重心转向电缆连接器的制造。凭借高品质的产品和服务,Amphenol公司的电缆连接器在市场上获得了广泛的认可,并逐渐发展成为全球最大的电缆连接器制造商之一。

CONTEC公司的发展小趣事

1996年,CONTEC公司在秦皇岛经济技术开发区成立,初期便自主掌握了心电、脑电生产技术。这一技术的掌握为公司奠定了坚实的基础,使得其在医疗行业设备领域开始崭露头角。随着技术的不断进步和市场的扩大,公司逐渐发展成为国内领先的医疗设备供应商之一。

AIM公司的发展小趣事

AIM公司自创立以来,便以其前瞻性的视野和独特的技术理念,在电子行业中崭露头角。创始团队凭借对市场的敏锐洞察和对技术的深刻理解,将公司定位为提供创新解决方案的引领者。在创立初期,AIM便投入大量资源进行技术研发,逐渐在行业中建立了自己的技术优势和品牌形象。

问答坊 | AI 解惑

CANopen主节点的设计方案

CANopen主节点的设计方案 - 基于IXXAT公司 CANopen Master API for Windows CANopen主节点除具备CANopen设备的基本条件外,还需具备NMT Master的功能,即对CANopen网络进行管理。对CANopen主节点的实现提出三种方案: ?? 方案1:在CANopen-Chip ...…

查看全部问答>

你的第一部手机是什么型号的?

先说说我的: NOKIA 3310 像板砖一样的家伙 呵呵  不过在01年的时候也算稀罕物。 经过多次高空坠落试验,都完好无损, 后来从一个酒瓶高的容器上坠落,液晶屏里的蓝色液体流出,彻底退休了。当时在工资还不高的情况下,流的不是液晶, ...…

查看全部问答>

MAX485通信同步问题?求解???

       初次搞485的多机通信(一主多从),现在遇到的问题令我很困惑。        我的通信思路是,从机逐个与主机通信,即主机发送一帧数据(8字节,包含数据信息),呼叫从 ...…

查看全部问答>

新手提问:学习单片机需要有多少电气知识?

我大学里是学软件的,对C#之类的比较熟,C/C++也还行,汇编了解一些,电气电路和硬件几乎一点不懂。 现在有个工作是从事激光仪器里的单片机开发,请问需要学习多少电气知识?线路应该有人设计好的,我写程序要看懂电路吗?有哪里方面是要与设计电 ...…

查看全部问答>

对话框最小化就不见了。

ce5.0 evc4.2. 我要在对话框中加个最小化按钮,用ShowWindow(SW_MINIMIZE)来实现,但对话框最小化就不见了.而在xp系统中就行。 感觉是任务栏没有显示,造成最小化后程序不能回到任务栏,所以不见了。 …

查看全部问答>

一个简短程序放在AT89C55WD中好象不工作了,是否与程序有关?

问题1: 全部程序如下: #include sbit Fscx = P3^4; sbit CW   = P3^5; void main() {    int i;    CW = 0;    while(1)    {        Fscx = 1;   ...…

查看全部问答>

CE5.0大内存支持问题

CE里默认为64M,IMGRAM128=1设置后对128M支持没有问题,但是设置IMGRAM256=1之后,就不能进入系统了 所以想问一下CE里怎么添加对256M的支持,多谢!…

查看全部问答>

PCB板前期定位注意

  上周周一(6月13号)开始为一块电路板做定位工作,由于自己没有详细考虑PCB设计时的显示位置与实际模具的接口的位置关系,导致周二、三、四的布局布线工作全都白做了,实在是悲惨,只能怪自己前期考虑的不周,这也算是一次学习的机会吧 ...…

查看全部问答>

欢迎下载德仪2012年电源管理指南

这套电源管理方案指南中提供了线电源和移动设备电源的全套解决方案,而且设计目前TI最新的产品系列,对于电源方案的制定非常有参考意义。 [ 本帖最后由 wstt 于 2012-6-16 00:43 编辑 ]…

查看全部问答>

【Nucleo+BLUENRG心得】—— 验身

   今天早上刚到公司打卡看到EEWORLD寄来的快递 估计就是蓝牙板  迫不及待拆开看一下 比想象中小不少 这样可能看不出来 这样就能感觉出mini了吧 简单上个电 看下功耗 2.367mA 应该主要是有源晶振的功耗 晚 ...…

查看全部问答>