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

这篇具有很好参考价值的文章主要介绍了UEFI源码学习01-ARM AARCH64编译、ArmPlatformPriPeiCore(SEC)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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.git
 
cd edk2
git submodule update --init
cd ..

sudo apt-get install gcc-aarch64-linux-gnu
sudo apt-get install qemu-system-aarch64

export 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,可以看到如下图
UEFI源码学习01-ARM AARCH64编译、ArmPlatformPriPeiCore(SEC)

  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。
UEFI源码学习01-ARM AARCH64编译、ArmPlatformPriPeiCore(SEC)
这是一条跳转指令,根据armv8a的手册来看,这条指令是b pc+0x1000。CPU刚启动的时候,PC寄存器是0,所以这条指令会直接跳转到0x1000地址。
UEFI源码学习01-ARM AARCH64编译、ArmPlatformPriPeiCore(SEC)
然后同样看一下0x1000地址的数据。又是一条跳转指令0x14000d16。解析出来就是b pc+0x3458,当前pc是0x1000,因此他就跳转到了0x4458。
UEFI源码学习01-ARM AARCH64编译、ArmPlatformPriPeiCore(SEC)
那么0x4458存放的是什么东西?
首先通过反汇编ArmPlatformPrePeiCore.debug,可以得到0x3458是ArmPlatformPrePeiCore的_ModuleEntryPoint
UEFI源码学习01-ARM AARCH64编译、ArmPlatformPriPeiCore(SEC)
然后我们查看QEMU_EFI.fd的0x4458的地址存放的数据,就是对应_ModuleEntryPoint的第一条指令。我们知道ArmPlatformPrePeiCore是从0x1000存放的,因此实际上0x4458就是ArmPlatformPrePeiCore的_ModuleEntryPoint。而ArmPlatformPrePeiCore编译出来的代码是位置无关代码,所以通过0地址和0x1000地址的两次跳转,最终就跳转到ArmPlatformPrePeiCore的_ModuleEntryPoint中。
UEFI源码学习01-ARM AARCH64编译、ArmPlatformPriPeiCore(SEC)

2.4 ArmPlatformPrePeiCore做了点什么

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

函数调用栈如下:

_ModuleEntryPoint
	_SetupPrimaryCoreStack
		_PrepareArguments
			CEntryPoint
				PrimaryMain
					(PeiCoreEntryPoint)(&SecCoreData, PpiList);

_ModuleEntryPoint

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

ASM_FUNC(_ModuleEntryPoint)
  // Do early platform specific actions
  bl    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 core
  cmp   x0, #1
  b.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 Vector
  MOV64 (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
  )
{
  //关闭所有Dcache
  ArmDisableDataCache ();
  // Invalid所有ICache
  ArmInvalidateInstructionCache ();
  // 使能ICACHE
  ArmEnableInstructionCache ();
  // 刷下栈上的Dcache
  InvalidateDataCacheRange (
    (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阶段的PPI
  CreatePpiList (&PpiListSize, &PpiList);
  //使能GIC
  ArmGicEnableDistributor (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 point
  PeiCoreEntryPoint (&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阶段的执行了文章来源地址https://www.toymoban.com/news/detail-400977.html

到了这里,关于UEFI源码学习01-ARM AARCH64编译、ArmPlatformPriPeiCore(SEC)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • debian 11 arm64 aarch64 D2000 平台编译 box86 box64 笔记

    参考资料 https://github.com/ptitSeb/box86/blob/master/docs/COMPILE.md 源码地址 GitHub - ptitSeb/box86: Box86 - Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices deb在线源地址(打不开): Itai\\\'s box86 apt repo 源码编译 apt install gcc-arm-linux-gnueabihf mkdir build; cd build; cmake .. -DPHYTIUM=1 -DCMAKE_BUILD_TY

    2024年01月16日
    浏览(40)
  • 在Linux、Ubuntu中跨平台编译ARM(AARCH64)平台的binutils

    Binutils 是GNU(https://www.gnu.org/)提供的一组二进制工具的集合。通常,在已经安装了Linux操作系统的个人电脑上,系统就已经自带了这个工具集。但在进行嵌入式开发的时候,可能会用到支持ARM64平台的Binutils,这时就需要用到交叉编译。 此前,在【1】我们已经介绍过Ubuntu中交

    2024年02月05日
    浏览(51)
  • D2000 debian 11 arm64 aarch64 wine-ce编译安装,运行win32程序 笔记 【失败】

    下载源码 yeqiang@debian:~/Downloads$ git clone https://gitee.com/wine-ce/wine-ce Cloning into \\\'wine-ce\\\'... remote: Enumerating objects: 102, done. remote: Counting objects: 100% (89/89), done. remote: Compressing objects: 100% (83/83), done. remote: Total 102 (delta 54), reused 1 (delta 1), pack-reused 13 Receiving objects: 100% (102/102), 32.75 KiB | 56

    2024年01月18日
    浏览(36)
  • SPEC CPU 2006 1.2 D2000 ARM64 aarch64平台 docker 环境下的编译 宿主机测试

    由于spec cpu 2006版本太老,现代操作系统gcc版本远高于gcc4.3,且tools也没有提供arm64架构程序文件,导致安装编译会报大量编译错误,难以适配。故采用docker方式尝试编译。 https://download.csdn.net/download/hknaruto/86608404 验证可用 ---------------------------------------------------------------------

    2024年02月16日
    浏览(36)
  • arm64和aarch64之间的区别

    直接给出结论:arm64已经与aarch64合并,因为aarch64和arm64指的是同一件事。 AArch64是ARMv8 架构的一种执行状态。 为了更广泛地向企业领域推进,需要引入 64 位构架。同时也需要在 ARMv8 架构中引入新的 AArch64 执行状态。AArch64 不是一个单纯的 32 位 ARM 构架扩展,而是 ARMv8 内全新

    2024年02月11日
    浏览(25)
  • arm/aarch64架构安装conda环境

    首先找到一个下载conda的地址 清华源anaconda地址 可以看到conda在不同系统环境下有如下版本 鉴别不同国产系统可参考:国产的开源操作系统都有哪些? 这里用阿里arm/aarch64架构 所以下载连接为 https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/Anaconda3-2023.03-Linux-aarch64.sh 可以手动下载上

    2024年02月14日
    浏览(26)
  • 服务器基础知识:aarch64 arm64 arm x86有什么区别

    aarch64 和 arm64 是指基于ARM架构的64位处理器,而 arm 是指基于ARM架构的32位处理器。 x86 则是指基于x86架构的处理器。 架构: aarch64 、 arm64 和 arm 都属于ARM架构,而 x86 属于x86架构。 位数: aarch64 和 arm64 是64位处理器架构,能够使用64位的寄存器和指令集。 arm 是32位处理器架构

    2024年02月08日
    浏览(40)
  • libreoffice 7 ( arm64 ubuntu20.04 环境) 源码编译

    基础环境 cpu os docker Dockerfile

    2024年02月13日
    浏览(51)
  • 虚幻引擎UE4源码编译安装(x86,arm64平台)

    (1)关于运行Setup.sh脚本,mono报错,详情截图如下: 分析:不能执行二进制文件mono,根据错误提示找到源码中涉及到具体执行语句为: “mono Engine/Binaries/DotNET/GitDependencies.exe $ARGS”         GitDependencies.exe可执行文件的作用在线下载UE依赖库,而mono是跨平台.net运行环境,

    2024年02月06日
    浏览(83)
  • Swupdate的aarch64交叉编译

    上一篇博客我们简单测试了swupdate的基础功能,当时使用的是buildroot进行编译的,依赖关心有buildroot进行处理了。今天我自己手动编译一些swupdate。下面记录了编译swupdate的过程。 基本过程就是下载源码,配置选项,然后进行编译。 swupdate是在github上下载的,下载地址为: l

    2024年02月12日
    浏览(51)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包