文章目录

  • 1. AARCH64编译环境搭建
  • 2. ArmPlatformPriPeiCore
    • 2.1 QEMU_EFI.fd包含了什么
    • 2.2 QEMU virt aarch64相关
    • 2.3 从第一条指令到ArmPlatformPrePeiCore入口
    • 2.4 ArmPlatformPrePeiCore做了点什么
      • _ModuleEntryPoint
      • CEntryPoint
      • PrimaryMain

1. AARCH64编译环境搭建

git clone https://github.com/tianocore/edk2-platforms.git
git clone https://github.com/acpica/acpica.git
git clone https://github.com/tianocore/edk2.gitcd edk2
git submodule update --init
cd ..sudo apt-get install gcc-aarch64-linux-gnu
sudo apt-get install qemu-system-aarch64export WORKSPACE=$PWD
export PACKAGES_PATH=$WORKSPACE/edk2:$WORKSPACE/edk2-platforms
export IASL_PREFIX=$WORKSPACE/acpica/generate/unix/bin/
export GCC5_AARCH64_PREFIX=/usr/bin/aarch64-linux-gnu-source edk2/edksetup.sh
build -a AARCH64 -t GCC5 -p edk2/ArmVirtPkg/ArmVirtQemu.dsc -b DEBUG

编译完之后会生成UEFI文件:Build/ArmVirtQemu-AARCH64/DEBUG_GCC5/FV/QEMU_EFI.fd

运行命令如下

 qemu-system-aarch64 -M virt -cpu cortex-a57 -bios Build/ArmVirtQemu-AARCH64/DEBUG_GCC5/FV/QEMU_EFI.fd -net none -serial stdio

2. ArmPlatformPriPeiCore

大部分教程都是用OVMF来做示例,OVMF中第一个运行的UEFI模块是SEC。但AARCH64中的SEC是这个ArmPlatformPriPeiCore。所以在edk2的AARCH64示例中,ArmPlatformPriPeiCore是第一个运行的模块。

2.1 QEMU_EFI.fd包含了什么

我们用UEFITool NE 打开QEMU_EFI.fd,可以看到如下图

  1. ArmPlatformPrePeiCore,充当的SEC core的模块。从0x1000存放
  2. PeiCore,PEI Core的代码
  3. 7个PEIM
    PEIM 功能
    PlatformPei 初始化SOC平台相关的代码
    MemoryInit 初始化内存
    CpuPei 初始化ARM cortex a57 cluster
    PcdPeim 提供动态Pcd
    PeiVariablePei 没用到
    DxeIplPei 提供加载DXE的功能
  4. 最后是一个Volumn image,这个是一个压缩卷,里面包含PEI后面阶段的image,如DXE, BSD等等。需要在PEI中进行解压然后运行。

2.2 QEMU virt aarch64相关

  • ROM的空间是0x00000000 - 0x3FFFFFFF
  • RAM的空间在0x40000000 - 0x7FFFFFFF
  • CPU第一条指令是在0地址运行,即在ROM上
  • QEMU_EFI.fd文件存放在ROM上,即从0地址开始

2.3 从第一条指令到ArmPlatformPrePeiCore入口

从2.2中知道CPU第一条指令从0地址执行,那么QEMU_EFI.fd里的第一个word存放了什么东西?用二进制编辑器查看QEMU_EFI.fd可以看到在0地址存放了一个word:0x14000400。

这是一条跳转指令,根据armv8a的手册来看,这条指令是b pc+0x1000。CPU刚启动的时候,PC寄存器是0,所以这条指令会直接跳转到0x1000地址。

然后同样看一下0x1000地址的数据。又是一条跳转指令0x14000d16。解析出来就是b pc+0x3458,当前pc是0x1000,因此他就跳转到了0x4458。

那么0x4458存放的是什么东西?
首先通过反汇编ArmPlatformPrePeiCore.debug,可以得到0x3458是ArmPlatformPrePeiCore的_ModuleEntryPoint

然后我们查看QEMU_EFI.fd的0x4458的地址存放的数据,就是对应_ModuleEntryPoint的第一条指令。我们知道ArmPlatformPrePeiCore是从0x1000存放的,因此实际上0x4458就是ArmPlatformPrePeiCore的_ModuleEntryPoint。而ArmPlatformPrePeiCore编译出来的代码是位置无关代码,所以通过0地址和0x1000地址的两次跳转,最终就跳转到ArmPlatformPrePeiCore的_ModuleEntryPoint中。

2.4 ArmPlatformPrePeiCore做了点什么

ArmPlatformPrePeiCore非常简单,主要初始化CPU,设置栈指针, 初始化PEI阶段需要的参数SecCoreData最后跳转到PEI core中去。

函数调用栈如下:

_ModuleEntryPoint_SetupPrimaryCoreStack_PrepareArgumentsCEntryPointPrimaryMain(PeiCoreEntryPoint)(&SecCoreData, PpiList);

_ModuleEntryPoint

edk2/ArmPlatformPkg/PrePeiCore/AArch64/PrePeiCoreEntryPoint.S
这里面首先调用了ArmPlatformPeiBootAction,这个函数是个空实现,实际没什么用。接着调用SetupExceptionLevel1设置EL1的环境,然后跳转到MainEntryPoint。

ASM_FUNC(_ModuleEntryPoint)// Do early platform specific actionsbl    ASM_PFX(ArmPlatformPeiBootAction)EL1_OR_EL2(x0)
1:bl    ASM_PFX(SetupExceptionLevel1)b     ASM_PFX(MainEntryPoint)

MainEntryPoint里就读出CPU ID去配置一下栈指针,如果是primary core就设置primary 栈,如果是secondary core就设置secondary栈。后面都只讨论primary core。栈指针从FIX PCD中获取

ASM_PFX(MainEntryPoint):MOV64 (x1, FixedPcdGet64(PcdCPUCoresStackBase) + FixedPcdGet32(PcdCPUCorePrimaryStackSize))// x0 is equal to 1 if I am the primary corecmp   x0, #1b.eq   _SetupPrimaryCoreStack

_SetupPrimaryCoreStackz中主要配置了一下栈寄存器SP,然后跳转到_PrepareArguments

_SetupPrimaryCoreStack:mov   sp, x1...b     _PrepareArguments

_PrepareArguments从PCD里拿到PEI CORE的entry,然后传给CEntryPoint,后面就是C代码了

_PrepareArguments:// The PEI Core Entry Point has been computed by GenFV and stored in the second entry of the Reset VectorMOV64 (x2, FixedPcdGet64(PcdFvBaseAddress))ldr   x1, [x2, #8]// Move sec startup address into a data register// Ensure we're jumping to FV version of the code (not boot remapped alias)ldr   x3, =ASM_PFX(CEntryPoint)

CEntryPoint

edk2/ArmPlatformPkg/PrePeiCore/PrePeiCore.c
CEntryPoint主要就初始化了一些ARM CPU的一些东西,关闭cache,打开VFP, 设置VBAR之类的,然后就跳转到 PrimaryMain中去了。

CEntryPoint (IN  UINTN                     MpId,IN  EFI_PEI_CORE_ENTRY_POINT  PeiCoreEntryPoint)
{//关闭所有DcacheArmDisableDataCache ();// Invalid所有ICacheArmInvalidateInstructionCache ();// 使能ICACHEArmEnableInstructionCache ();// 刷下栈上的DcacheInvalidateDataCacheRange ((VOID *)(UINTN)PcdGet64 (PcdCPUCoresStackBase),PcdGet32 (PcdCPUCorePrimaryStackSize));//设置VBAR到PeiVectorTable --> PEI的异常向量表ArmWriteVBar ((UINTN)PeiVectorTable);//使能浮点单元ArmEnableVFP ();PrimaryMain (PeiCoreEntryPoint);
}

PrimaryMain

edk2/ArmPlatformPkg/PrePeiCore/MainMPCore.c
PrimaryMain里主要建立了SEC阶段传给PEI的PPI list,然后配置好SecCoreData结构体,跳转到PeiCore中去。

VOID
EFIAPI
PrimaryMain (IN  EFI_PEI_CORE_ENTRY_POINT  PeiCoreEntryPoint)
{...//创建SEC阶段的PPICreatePpiList (&PpiListSize, &PpiList);//使能GICArmGicEnableDistributor (PcdGet64 (PcdGicDistributorBase));...//从PCD中获取TempStack的base,TempStack在永久内存初始化之前的临时内存TemporaryRamBase = (UINTN)PcdGet64 (PcdCPUCoresStackBase) + PpiListSize;//从PCD中获取TempStack的大小TemporaryRamSize = (UINTN)PcdGet32 (PcdCPUCorePrimaryStackSize) - PpiListSize;SecCoreData.DataSize               = sizeof (EFI_SEC_PEI_HAND_OFF);//从PCD中获取PEI的FV地址和长度并存入SecCoreData中SecCoreData.BootFirmwareVolumeBase = (VOID *)(UINTN)PcdGet64 (PcdFvBaseAddress);SecCoreData.BootFirmwareVolumeSize = PcdGet32 (PcdFvSize);SecCoreData.TemporaryRamBase       = (VOID *)TemporaryRamBase; // We run on the primary core (and so we use the first stack)SecCoreData.TemporaryRamSize       = TemporaryRamSize;SecCoreData.PeiTemporaryRamBase    = SecCoreData.TemporaryRamBase;SecCoreData.PeiTemporaryRamSize    = ALIGN_VALUE (SecCoreData.TemporaryRamSize / 2, CPU_STACK_ALIGNMENT);SecCoreData.StackBase              = (VOID *)((UINTN)SecCoreData.TemporaryRamBase + SecCoreData.PeiTemporaryRamSize);SecCoreData.StackSize              = (TemporaryRamBase + TemporaryRamSize) - (UINTN)SecCoreData.StackBase;// Jump to PEI core entry pointPeiCoreEntryPoint (&SecCoreData, PpiList);
}

我们在PeiCore的入口的地方加入了打印,把SecCoreData dump出来如下

DataSize:48
BootFirmwareVolumeBase:00000001000
BootFirmwareVolumeSize:000001FF000
TemporaryRamBase:0004007C030
TemporaryRamSize:00000003FD0
PeiTemporaryRamBase:0004007C030
PeiTemporaryRamSize:00000001FF0
StackBase:0004007E020
StackSize:00000001FE0

至此,SEC就运行完了,后面就是PEI阶段的执行了

UEFI源码学习01-ARM AARCH64编译、ArmPlatformPriPeiCore(SEC)相关推荐

  1. UEFI源码学习3 - DXE

    目录 UEFI源码学习3.1 - DXE Dispatcher UEFI源码学习3.2 - DXE Protocol实现 UEFI源码学习3.3 - DXE Event实现 UEFI源码学习3.4 - ...

  2. PostgreSQL源码学习(一)编译安装与GDB入门

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 PostgreSQL源码学习(一)编译安装与GDB入门 前言 一.安装PostgreSQL 1.获取源码 2.配置 3.编译 3.安装 ...

  3. 【iScroll源码学习01】准备阶段 - 叶小钗

    [iScroll源码学习01]准备阶段 - 叶小钗 时间 2013-12-29 18:41:00 博客园-原创精华区 原文  http://www.cnblogs.com/yexiaochai/p/3 ...

  4. Dart源码学习01

    1.Dart历史 2.dart设计基础思想 3.Dart的编译模式 Dart VM 支持五种编译模式: 1, :最常见的 JIT 模式,可以直接在虚拟机中执行 Dart 源码,像解释型语言一样使用.通 ...

  5. *迟来的爱*——《Foursquare》应用源码学习(一) 下载、编译、运行

    做Android项目做到好几年的程序,发现技术进步很慢,逐渐往管理发展..于是, 要看开源项目,学习别人的成功经验,来解决项目中遇到的棘手问题. 于是看到了别人推荐的android的开源源码,找了一个 ...

  6. OBS源码学习(三)-编译updater工程

    由于项目要求要将OBS更新功能迁到公司自己的服务器上,OBS默认的是不编译updater工程,现将OBS更新工程编译步骤如下: 一.下载解压并使用 CMake 生成编译 zlib https://do ...

  7. JDK11源码学习05 | HashMap类

    JDK11源码学习05 | HashMap类 JDK11源码学习01 | Map接口 JDK11源码学习02 | AbstractMap抽象类 JDK11源码学习03 | Serializable接口 ...

  8. VUE源码学习第一篇--前言

    一.目的 前端技术的发展,现在以vue,react,angular为代表的MVVM模式以成为主流,这三个框架大有三分天下之势.react和angular有facebook与谷歌背书,而vue是以一己之 ...

  9. 博通Broadcom SDK源码学习与开发1——SDK源码探究与Cable Modem 系统编译

    声明:原创作品,严禁用于商业目的. 本系列文章将全面剖析以Bcm33xxx芯片开发Cablemodem产品的SDK源码为例,从编译系统到各个功能模块进行分析与探讨. 文章目录 0.写在前篇 1. 博通 ...

最新文章

  1. fond+html属性,JQuery 干货篇之选择元素
  2. python链表的创建_Python——新建链表
  3. DL之ShuffleNetV2:ShuffleNetV2算法的简介(论文介绍)、架构详解、案例应用等配图集合之详细攻略
  4. (转)怎样完全用 GNU/Linux 工作
  5. MySql中添加用户/删除用户
  6. php安装 pear,php pear / pecl 扩展工具的安装和使用
  7. C#获取电脑IP、MAC地址示例代码
  8. spring中context:property-placeholder标签详解
  9. Nitrozme Animation Studio Packages Mac(AE插件拓展包)
  10. Windows系统克隆***与防范
  11. mysql alert longtext_mysql数据类型介绍(含text,longtext,mediumtext说明)
  12. 第三章·MySQL版本区别及管理
  13. 深入浅出CChart 每日一课——快乐高四第九课 于无声处,CChart内置功能介绍之数据存取篇...
  14. AS-实践《第一行代码》中的出现的问题
  15. 电阻参数_电阻器的主要技术参数、分类和选用
  16. 电子密码锁的设计(Verilog HDL实现)
  17. 码农的奋斗之路 富爸爸穷爸爸系列--提高你的财商 读后感
  18. 今天准备出发去珠海横琴,去长隆海洋乐园看鲨鱼宝宝了
  19. 小米适配android o机型,小米公布部分机型安卓O/P适配进度及新适配计划
  20. 手把手教你制作自己的小程序

热门文章

  1. VMware Horizon 8 设置 Linux 桌面
  2. Google Chrome打开后是桔梗网处理方案
  3. systemctl restart network重启网卡失败
  4. ppwjs之bootstrap文字排版:引用元素
  5. Python中msgpack库的使用
  6. 快速安装Pytorch——下载镜像分分钟安装
  7. 我想我是不是该选择离开?
  8. dtw语音识别代码 java_DTW算法(语音识别)
  9. 日本医学博士总结容易早死的十大特征
  10. Android PackageManagerService中LI,LP等函数后缀的含义