Rockchip RK3399 - 引导流程和准备工作

在这里插入图片描述

系列文章目录




前言

开发板 :NanoPC-T4开发板
eMMC :16GB
LPDDR3:4GB
显示屏 :15.6英寸HDMI接口显示屏
u-boot :2017.09

    NanoPC-T4 开发板,主控芯片是 Rockchip RK3399,big.LITTLE 大小核架构,双 Cortex-A72 大核(up to 2.0GHz) + 四 Cortex-A53 小核结构(up to 1.5GHz);Cortex-A72 处理器是 Armv8-A 架构下的一款高性能、低功耗的处理器。


一、SoC启动流程

1.1 BootROM 介绍

    通常来说,SoC 厂家都会做一个 ROM 在 SoC 的内部,这个 ROM 很小,里面固化了上电启动的代码(一经固化,永不能改,是芯片做的时候,做进去的);这部分代码呢,我们管它叫做 BootROM,也叫作一级启动程序。

1.1.1 初始化硬件

    芯片上电后先接管系统的是 SoC 厂家的 BootROM,它要做些什么事情呢?初始化系统,CPU 的配置,关闭看门狗,初始化时钟,初始化一些外设(比如 USB Controller、MMC Controller,Nand Controller 等);

1.1.2 加载程序到 SRAM

    当我们拿到一款新的 SoC 时,都会进行电路原理图设计,我们一般会在芯片外挂一些存储设备(eMMC、Nand、Nor、SDCard 等)和内存(SDRAM、DDR 等)电路图绘制好了。我们接着会绘制电路板,制作出板子。

    有了板子还不行,我们还得往里面烧写程序。这个烧写程序,其实就是将可执行的二进制文件写到外部的存储设备上(eMMC、Nand、SD 等)。系统上电启动的时候,会将他们读到内存中执行。

    前面我们说了,上电后先接管系统的是 SoC 厂家的 BootROM,其它可执行的程序(u-boot、Kernel)都放(烧写)到了外部存储器上;那么 BootROM 的代码除了去初始化硬件环境以外,还需要去外部存储器上面,将接下来可执行的程序读到内存来执行。

    既然是读到内存执行,那么这个内存可以不可以是我们板载的 DDR 呢?理论上是可以的,但是,SoC 厂家设计的 DDR 控制器呢,一般会支持很多种类型的 DDR 设备,并且会提供兼容性列表,SoC 厂家怎么可能知道用户 PCB 上到底用了哪种内存呢?所以,直接把外部可执行程序读到 DDR 显然是不太友好的,一般来说呢,SoC 都会做一个内部的小容量的 SRAM ,BootROM 将外部的可执行程序从外部存储器中读出来,放到 SRAM 去执行;

    好了,现在我们引出了 SRAM ,引出了 BootROM ;那么 BootROM 从具体哪个存储器读出二进制文件呢?SoC 厂家一般会支持多种启动方式,比如从 eMMC 读取,从 SDCard 读取,从 Nand Flash 读取等等;上电的时候,需要告诉它,它需要从什么样的外设来读取后面的启动二进制文件;

    一般的设计思路是,做一组 Bootstrap Pin,上电的时候呢?BootROM 去采集这几个 IO 的电平,来确认要从什么样的外部存储器来加载后续的可执行文件;比如呢,2 个 IO,2’b00 表示从 Nand 启动,2’b01 表示从 eMMC 启动,2’b10 表示从 SDCard 启动等等;

    当 BootROM 读到这些值后,就会去初始化对应的外设,然后来读取后面要执行的代码;这些 IO 一般来说,会做成板载的拨码开关,用于调整芯片的启动方式;

    这里,读取烧写的二进制的时候呢,需要注意一些细节,比如 SoC 厂家告诉你,你需要先把 SDCard 初始化称为某种文件系统,然后把东西放进去才有效,之类的;因为文件系统是组织文件的方式,并不是裸分区;你按照 A 文件系统的方式放进去,然后 SoC 的 BootROM 也按照 A 文件系统的方式读出来,才能够达成一致;

    如果你对 Mini2440 这款开发板足够了解的话,你应该知道其采用的 SoC 型号为 s3c2440 ,其内部有一个 4kb 的 SRAM 。其有两种启动方式:

    采用 Nor Flash 启动,0x00000000 就是 2MB Nor Flash 实际的起始地址,由于 uboot 程序一般只有几百 kb,可以全部烧录到 Nor Flash 中,因此 uboot 程序完全可以在 Nor Flash 中运行,没有拷贝到 SDRAM 中运行的必要;

    采用 Nand Flash 启动,片内 4KB 的 SRAM 被映射到了 0x00000000 ,s3c2440 的 BootROM 会自动把 Nand Flash 中的前 4kb 代码数据搬到内部 SRAM 中运行,那么问题来了,假设 4KB 代码运行到最后,我想继续运行 Nand Flash 剩余的代码怎么办?为了解决这个问题,uboot 引入了 SPL ,全称 Secondary Program Loader 。

    注意:无论是 Nor Flash 还是 Nand Flash 都是外挂在 s3c2440 上的的存储设备。

1.2 SPL 介绍

    前面说了,芯片上电后 BootROM 会根据 Bootstrap Pin 去确定从某个存储器来读可执行的二进制文件到 SRAM 并执行;理论上来说,这个二进制文件就可以是我们的 u-boot.bin 文件了;也就是 BootROM 直接加载 u-boot.bin ;

    理论上是这样的,但是这里有一个问题,就是 SRAM 很贵,一般来说,SoC 的片上 SRAM 都不会太大,一般 4KB、8KB、16KB … 256KB 不等;但是呢,u-boot 编译出来却很大,好几百 KB,放不下,就像我上面说的 s3c2440 的例子那样。

    放不下怎么办?有两种办法:

  • 假设片内 SRAM 为 4KB,uboot 的前 4KB 程序实现 uboot 的重定位,即将 uboot 拷贝到 SDRAM 中运行;
  • 做一个小一点的 boot 程序,先让 BootROM 加载这个小的程序,后面再由这个小 boot 去加载 uboot ;

1.2.1 方案一

    比如,我们的 uboot 有 400KB ,SRAM 有 4KB ,外部 SDRAM 有 64MB :如果使用第一种方案的话,uboot 的前面 4KB 被加载进入 SRAM 执行,uboot 被截断,我们就需要保证在 uboot 的前 4KB 代码,把板载的 SDRAM 初始化好,把整个 uboot 拷贝到 SDRAM ,然后跳转到 SDRAM 执行;

    比如我们之前介绍的 Mini2440 开发板从 Nand Flash 启动时,uboot 程序就是采用的这种实现方式:Mini2440 之 uboot 移植之实践 NAND 启动。

1.2.2 方案二

    第二种方案的话,我们做一个小的 uboot ,这个 uboot 就叫做 SPLSecondary Program Loader),它很小很小(小于 SRAM 大小),它先被 BootROM 加载到 SRAM 运行,那么这个 SPL 要做什么事情呢?最主要的就是要初始化内存控制器,然后将真正的大 u-boot 从外部存储器读取到 SDRAM 中,然后跳转到大 uboot 。

1.3 启动流程

在这里插入图片描述

    如上图所示:

  • (0) 上电后,BootROM 开始执行,初始化时钟,关闭看门狗,关 Cache ,关中断等等,根据 Bootstrap Pin 来确定启动设备,初始化外设;
  • (1) 使用外设驱动,从存储器读取 SPL;
  • ---------------- 以上部分是 SoC 厂家的事情,下面是用户要做的事情 ----------------
  • (2) SPL 被读到 SRAM 执行,此刻,控制权以及移交到我们的 SPL 了;
  • (3) SPL 初始化外部 SDRAM;
  • (4) SPL 使用驱动从外部存储器读取 uboot 并放到 SDRAM ;
  • (5) 跳转到 SDRAM 中的 uboot 执行;
  • (6) 加载内核;

    实际情况中,还需注意很多问题:

  • 编译阶段的链接地址,是否需要地址无关?
  • SPL 的代码和 uboot 的代码是否有重合的地方?如果有,是否意味着 SPL 执行过的,跳转到 uboot 又要在执行一次?
  • 具体情况下,需要配置哪些硬件?怎么配置?

二、RK3399 地址空间分布

2.1 地址映射

    RK3399 支持从内部 BootROM 启动,并且支持通过软件编程进行地址重映射。重映射是通过 SGRF_PMU_CON0[15] 控制的,当重映射设置为 0 时,地址 0xFFFF0000 被映射到 BootROM ,当重映射设置为 1 时,0xFFFF0000 被映射到片内 SRAM 。

在这里插入图片描述

    从这张图我们可以看到在进行重映射前:

  • 0x0000 0000  ~ 0xF800 0000:为 DDR 内存空间;
  • 0xFF8C 0000 ~ 0xFF98 0000:片内 SRAM 内存空间,一共 192KB ;
  • 0xFFFF 0000 ~ 0xFFFF 8000:为 BootROM 内存空间,一共 32KB ;
  • 其它空间:用于一些特定功能;

如果进行了地址重映射:

  • BootROM 被映射到地址 0xFFFD 0000;
  • 片内 SRAM 被映射到地址 0xFFFF 0000;

2.2 系统启动

    RK3399 提供从片外设备启动系统,如 serial nand or nor flash、eMMC、SD/MMC 卡。当这些设备中的启动代码没有准备好时,还可以通过 USB OTG 接口将系统代码下载到各个外设存储中。

    所有引导代码都将存储在内部 BootROM 中。其中支持以下功能:

  1. 支持安全启动模式和非安全启动模式;

  2. 支持系统从以下设备启动;

    • SPI 接口;
    • eMMC 接口;
    • SD/MMC 卡;
  3. 支持系统代码通过 USB OTG 下载;
    以下是存储在BootROM中的启动代码的整个启动过程:

在这里插入图片描述

    从图中可以得到以下几个结论:

  1. 上电后, A53 核心从 0xffff0000 这个地址读取第一条指令,这个内部 BootROM 在芯片出货的时候已经由原厂烧写;

  2. 然后依次从 Nor Flash、Nand Flash、eMMC、SD/MMC 获取 ID BLOCK,ID BLOCK 正确则启动,都不正确则从 USB 端口下载;

    • 如果 eMMC 启动,则先读取 SDRAM(DDR)初始化代码到内部 SRAM,由于 SRAM 只有 192KB ,因此最多只能读取那么多,然后初始化 DDR ,再将 eMMC 上的代码(剩下的用户代码)复制到 DDR 运行;
    • 如果从 USB 下载,则先获取 DDR 初始化代码,下载到内部 SRAM 中,然后运行代码初始化 DDR ,再获取 loader 代码(用户代码),加载到 DDR 中并运行;

三、Rockchip 引导流程

    针对不同的解决方案,Rockchip 提供了两种不同的启动加载程序方法,其步骤和生成的镜像文件也是完全不同的。

  • TPL/SPL 加载:使用 Rockchip 官方提供的 TPL/SPL U-boot(就是我们上面说的小的 uboot ),该方式完全开源;
  • 官方固件加载:使用 Rockchip idbLoader,它由 Rockchip rkbin project 的 Rockchip ddr init bin和 miniloader bin 组合而成,该方式不开源;

    需要注意的是:并不是所有平台都支持这两种启动加载程序方法。

    上面我们介绍了 SPL,那什么是 TPL ?实际上将我们上面所说的 SPL 初始化 SDRAM 等硬件工作的部分独立出去,就是 TPL 。那么我们总结一下:

  • TPLTarger Program Loader,就是芯片级的初始化过程,这个时候的代码都是基于芯片平台的部分,它在启动过程中进行 DDR 初始化和一些其他的系统配置,以便后续的 SPL 能够正确地运行;
  • SPLSecondary Program Loader,它从存储设备中读取 trust(如 ATF/OP-TEE )和 uboot 二进制文件,将它们加载到系统内存中并运行它们,进而启动完整的操作系统;

    TPL 和 SPL 的区别在于它们的职责不同。TPL 主要负责初始化系统硬件,而 SPL 负责加载和运行其它软件组件,如 trust 和 uboot 。此外,在一些特殊情况下,如加密启动或安全启动模式下,TPL 还可能执行其他额外的任务。

3.1 启动阶段

    Rockchip 处理器启动可以划分为 5 个阶段:

+--------+----------------+----------+-------------+---------+
| Boot   | Terminology #1 | Actual   | Rockchip    | Image   |
| stage  |                | program  |  Image      | Location|
| number |                | name     |   Name      | (sector)|
+--------+----------------+----------+-------------+---------+
| 1      |  Primary       | ROM code | BootROM     |         |
|        |  Program       |          |             |         |
|        |  Loader        |          |             |         |
|        |                |          |             |         |
| 2      |  Secondary     | U-Boot   |idbloader.img| 0x40    | pre-loader
|        |  Program       | TPL/SPL  |             |         |
|        |  Loader (SPL)  |          |             |         |
|        |                |          |             |         |
| 3      |  -             | U-Boot   | u-boot.itb  | 0x4000  | including u-boot and atf
|        |                |          | uboot.img   |         | only used with miniloader
|        |                |          |             |         |
|        |                | ATF/TEE  | trust.img   | 0x6000  | only used with miniloader
|        |                |          |             |         |
| 4      |  -             | kernel   | boot.img    | 0x8000  |
|        |                |          |             |         |
| 5      |  -             | rootfs   | rootfs.img  | 0x40000 |
+--------+----------------+----------+-------------+---------+

    当我们讨论从 eMMC/SD/U盘/网络启动时,它们涉及到不同的概念:

  • 第一阶段始终在 BootROM 中,它加载第二阶段并可能加载第三阶段(当启用SPL_BACK_TO_BROM 选项时);
  • SPI 闪存启动意味着第二阶段和第三阶段固件(仅限 SPL 和 U-Boot )在 SPI 闪存中,第四/五阶段在其他位置;
  • eMMC 启动意味着所有固件(包括第二、三、四、五阶段)都在 eMMC 中;
  • SD Card 启动意味着所有固件(包括第二、三、四、五阶段)都在 SD Card 中;
  • U盘 启动意味着第四和第五阶段的固件(不包括 SPL 和 U-Boot )在磁盘中,可选地仅包括第五阶段;
  • Net/TFTP 启动意味着第四和第五阶段的固件(不包括 SPL 和 U-Boot )在网络上。

    启动阶段涉及到了多个镜像文件:

  • 阶段一中的 BootROM 这个是 SoC 厂商提供的,我们不用关心;
  • 阶段二方式需要提供一个 idbloader.img ,这个我们后面具体说说;
  • 阶段三实际上就是 uboot 的镜像文件了,这里又搞出了两种,uboot.img(还需要搭配trust.img)和 u-boot.itb(这个是因为它已经把 ATF 打包进去了);这两个文件里面除了都包含 u-boot.bin 原始二进制文件,又放了点其他东西,可以被 idbloader.img 识别,然后加载,这个我们后面具体说说;
  • 阶段四和阶段五是内核镜像和根文件系统;

    这里我们具体说一下阶段二,阶段三涉及到的几个镜像文件。

3.1.1 idbloader.img

    idbloader.img 文件是一个 Rockchip 格式的预加载程序,在 SoC 启动时工作,它包含:

  • Rockchip BootROM 知道的 IDBlock 头;
  • DDR 初始化程序,由 BootROM 加载到 SRAM ,运行在 SRAM 内部;
  • 下一级加载程序,由 BootROM 加载并运行在 DDR 上;

3.1.2 u-boot.img

    u-boot.bin 是 uboot 源码编译后生成的原始二进制映像,可以直接烧录到设备的闪存中。而 u-boot.img 则是通过 mkimage 工具在 u-boot.bin 基础上增加了一个头部信息,这个头部信息可能也包括一些额外的数据,例如启动参数和内核映像地址等。

    因此,通过使用 u-boot.img 而不是 u-boot.bin,可以使引导 ROM 更容易地识别 uboot 映像,并更好地指导 uboot 在设备上正确启动。

3.1.3 u-boot.itb

    u-boot.itb 实际上是 u-boot.img 的另一个变种,也是通过 mkimage 构建出来的,里面除了 u-boot.dtbu-boot-nodtb.bin 这两个 uboot 源码编译出来的文件之外,还包含了 bl31.elfbl32.bintee.binARM trust 固件。其中 bl31.elf 是必须要有的,bl32.bin、tee.bin 是可选的,可以没有。

3.1.4 trust.img

    因为 RK3399 是 ARM64 ,所以我们还需要编译 ATF (ARM Trust Firmware),ATF 主要负责在启动 uboot 之前把 CPU 从安全的 EL3 切换到 EL2,然后跳转到 uboot,并且在内核启动后负责启动其他的 CPU。

    ATF 将系统启动从最底层进行了完整的统一划分,将 secure monitor 的功能放到了 bl31 中进行,这样当系统完全启动之后,在 CA 或者 TEE OS 中触发了 smc 或者是其他的中断之后,首先是遍历注册到 bl31 中的对应的 service 来判定具体的 handle ,这样可以对系统所有的关键 smc 或者是中断操作做统一的管理和分配。ATFcode boot 整个启动过程框图如下:

在这里插入图片描述

3.2 引导流程

    Rockchip 提供了外部 uboot 加载的流程图,如下图示:

在这里插入图片描述

    如上图所示:

  • 引导流程 1 是典型的使用 Rockchip miniloader 的 Rockchip 引导流程;
  • 引导流程 2 用于大多数 SoC,使用 U-Boot TPL 进行 DDR 初始化,使用 SPL 加载加载 u-boot.itb 文件;

    注1:如果 loader1 具有多个阶段,则程序将返回到 BootROM,BootROM 将载入并运行到下一个阶段。例如,如果 loader1 是 TPLSPL ,则 BootROM 将首先运行到 TPL,TPL 初始化 DDR 并返回到 BootROM,BootROM 然后将加载并运行到 SPL 。

    注2:如果启用了 trust,在安全模式(armv8 中的 EL3)下,loader1 需要同时加载 trust 和 U-Boot,然后运行到 trust 中,trust 在非安全模式(armv8 中的 EL2 )下进行初始化,并运行到 U-Boot 。

    注3:对于 trust(在 trust.img 或 u-boot.itb 中),armv7 仅有一个带或不带 TA 的 tee.bin,armv8 具有 bl31.elf 并且可选包含 bl32 。

    注4:在 boot.img 中,内容可以是 Linux 的 zImage 和其 dtb ,可以选择 grub.efi ,也可以是 AOSP boot.img,ramdisk 可选。

3.2.1 TPL/SPL 方式

    在 TPL/SPL 加载方式中,我们基于 uboot 源码编译出 TPL/SPL,其中:TPL 负责实现 DDR 初始化,TPL 初始化结束之后会回跳到 BootROM 程序,BootROM 程序继续加载 SPL ,由 SPL 加载 u-boot.itb 文件。

    TPL:被 BootROM 加载到内部 SRAM,起始地址为 0xff8c2000;结束地址不能超过 0xff980000,所以 TPL 程序最大不能超过 184KB ;

    SPL:被 BootROM 加载到 DDR ,起始地址为 0x00000000;结束地址绝对不能超过 0x00040000, 因为 0x00040000 地址被用来加载 bl31_0x00040000.bin, 因此 SPL 程序最大不能超过 256KB:反汇编如下:

0000000000000000 <__image_copy_start>:
       0:       14000001        b       4 <__image_copy_start+0x4>
       4:       14000009        b       28 <reset>

0000000000000008 <_TEXT_BASE>:
        ...

0000000000000010 <_end_ofs>:
      10:       0001c618        .inst   0x0001c618 ; undefined
      14:       00000000        udf     #0

0000000000000018 <_bss_start_ofs>:
      18:       00400000        .inst   0x00400000 ; undefined
      1c:       00000000        udf     #0

0000000000000020 <_bss_end_ofs>:
      20:       004003c0        .inst   0x004003c0 ; undefined
      24:       00000000        udf     #0

0000000000000028 <reset>:
      28:       1400010a        b       450 <save_boot_params>

000000000000002c <save_boot_params_ret>:
      2c:       10007ea0        adr     x0, 1000 <vectors>
      ......

    这里我们具体说一下采用这种方式 RK3399 的启动流程:

  • BootROM 首先将 eMMC0x40 扇区开始的 184KB 数据加载到片内 SRAM 中;由于 TPL 和 SPL 加在一起是超过 184KB 的,所以无法全部加载到 SRAM,但是把 TPL 全部加载到 SRAM 中还是绰绰有余的,这里加载地址为 0xff8c2000;

  • BootROM 跳转到 0xff8c2000 执行 TPL 代码,主要是 DDR 的初始化,当然还有一些其他硬件的初始化;需要注意的是,执行完 TPL 代码之后,会返回到 BootROM 程序,你把它当做汇编指令 bl TPL 那样会更好理解;

  • BootROM 加载 SPL 代码到 DDR 中,这里加载地址为 0x00000000,然后跳转到地址 0x00000000 去执行,需要注意的是这个时候不会再返回到 BootROM 了,因此 SPL 会初始化 eMMC 并将 eMMC 中 0x4000 扇区的 uboot 加载到 0x00200000 地址处,然后跳转到该处执行 uboot 程序;

    补充说明:上面描述的只是一个大概流程,当然中间 SPL 还会加载 bl31.bin(bl32.bin、tee.bin 非必须)去执行,但是这不是重点,所以就不做概述。

    由于 BootROM 不是开源的,我们没法去研究 BootROM 源码,当然我们也可以修改 common/spl/spl.c 文件 board_init_r 函数在 SPL 代码执行时将地址 0x000000000、0xff8c2000、0x40000000 等地址数据打印出来(printf 函数要加在 boot_from_devices 函数执行之后),和源二进制文件进行比对来验证自己的猜想:

board_init_r
addr 0x00000000 = 0x14000001   # 和 u-boot-spl.bin 前 4 字节匹配
addr 0x00000004 = 0x14000009   # 和 u-boot-spl.bin 文件偏移 0x4 处的 4 个字节匹配
addr 0x00000008 = 0x0          # 同样匹配
addr 0x00040000 = 0xaa0003f4   # 和 bl31_0x00040000.bin 文件前 4 字节匹配
addr 0x00050018 = 0xb8656883   # 和 bl31_0x00040000.bin 文件偏移 0x10018 处的 4 个字节匹配
addr 0xff8c2000 = 0x33334b52   # 这个地址数据和 u-boot-tpl.bin 有点对不上,可能后期被改变了?
							   # 可以尝试在 TPL 阶段代码执行时输出这个看看

    在该方式(TPL/SPL )中,我们需要用到以下源代码:

  • uboot 源码:编译生成 u-boot-spl.bin、u-boot-tpl.bin、u-boot-nodtb.bin、u-boot.dtb;
  • ATF 源码:编译生成 bl31.elf ;

    通过编译和工具我们最终可以生成:

  • idbloader.img :由 u-boot-spl.binu-boot-tpl.bin 通过工具合并得到;
  • u-boot.itb:由 bl32.elfu-boot-nodtb.binu-boot.dtbu-boot.its 通过工具合并得到;

3.2.1 官方固件方式

    在官方固件加载方式中,我们基于 Rockchip rkbin 官方给的 ddr.binminiloader.bin 来实现的;

  1. 通过 tools/mkimage 将官方固件 ddr, miniloader 打包成 BootROM 程序可识别的、带有 ID Block header 的文件 idbloader.img

    • ddr.bin:等价于上面说的 TPL,用于初始化 DDR
    • miniloader.bin:Rockchip 修改的一个 bootloader,等价于上面说的 SPL,用于加载 uboot

    这个文件打包出来实际上也是超过 192KB 的,因此也是分为二阶段执行的。

  1. 通过 tools/loaderimage 工具将 u-boot.bin 打包成 u-boot.img ;其中 u-boot.bin 是由 uboot 源码编译生成;

    补充说明:使用 Rockchip miniloader 的 idbloader 时,需要将 u-boot.bin 通过 tools/loaderimage 转换为可加载的 miniloader 格式。

  1. 使用 Rockchip 工具 tools/trust_mergebl31.bin 打包成 trust.img ;其中 bl31.bin 由 ATF 源码编译生成;

    补充说明:使用 Rockchip miniloader 的 idbloader 时,需要将 bl31.bin 通过 tools/trust_merge 转换为可加载的 miniloader 格式。

四、安装交叉编译工具链

    既然我们想向开发板处理器中烧录程序,交叉编译工具是必不可少的。选择交叉编译工具这一步需要慎重,我们首先要知道我们自己使用的开发板采用的 ARM 架构是哪一个?ARM 目前总共发布了 8 种架构:ARMv1、ARMv2、ARMv3、ARMv4、ARMv5、ARMv6、ARMv7、ARMv8。

    确认了 ARM 架构之后,选择支持该架构的交叉编译环境。可以参考 GNU Arm Embedded Toolchain 官网中的文档和说明来确定 march 支持的版本。在 ARM 官方提供的文档中,可以查看到 march 选项支持的处理器架构和对应的版本。例如,使用 aarch64-linux-gnu-gcc -march=armv8-a 命令编译代码时,表示编译针对于 Cortex-A53 处理器。

    除了 GNU Arm Embedded Toolchain 官网提供的交叉编译工具外, LINARO 也提供了交叉编译工具,下载地址 https://releases.linaro.org/components/toolchain/binaries/ 。具体有什么差异可以参考:ARM CPU 汇总 & 编译链选择

4.1 下载

    因此我们必须选择一个支持 Armv8-A 架构的交叉编译工具,即在 Linux 上编译 ARM64 Linux 程序,本文采用 GNU Arm Embedded Toolchain 官网提供的交叉编译工具链。

    这里我们直接选择最新版本的交叉编译工具:

在这里插入图片描述

    arm-gnu-toolchain-12.2.rel1-x86_64-aarch64-none-linux-gnu.tar.xz,该文件名称意为:在 x86 平台的 linux 主机进行编译,生成的文件为 aarch64 平台可运行的文件,这里宿主机和目标平台都是 64 位机器。

    如何您使用 LINARO 提供的交叉编译工具,可以选择 gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu.tar.xz

    注意:最新版本可能存在各种坑,因此推荐您安装 11.3 版本。

    复制下载地址,下载在 /work/sambashare/tools/ 路径:

wget https://developer.arm.com/-/media/Files/downloads/gnu/12.2.rel1/binrel/arm-gnu-toolchain-12.2.rel1-x86_64-aarch64-none-linux-gnu.tar.xz

4.2. 安装

    使用如下命令进行解压:

tar -xvf arm-gnu-toolchain-12.2.rel1-x86_64-aarch64-none-linux-gnu.tar.xz -C /usr/local/arm

    执行该命令,将把 arm-linux-gcc 自动安装到 /usr/loca/arm/arm-gnu-toolchain-12.2.rel1-x86_64-aarch64-none-linux-gnu 目录。

    由于路径名太长,我们重命名:

mv arm-gnu-toolchain-12.2.rel1-x86_64-aarch64-none-linux-gnu 12.2.1

    接下来配置系统环境变量,把交叉编译工具链的路径添加到环境变量 PATH 中去,这样就可以在任何目录下使用这些工具:

vim /etc/profile
export PATH=$PATH:/usr/local/arm/12.2.1/bin

    注意:如果配置了其它版本的交叉编译环境,需要将其屏蔽掉。

    接下来使用以下命令使修改后的 profile 文件生效:

source /etc/profile

    由于在 /usr/local/arm/12.2.1/bin 下没有 arm-linux-gcc、arm-linux-ld、arm-linux-strip 链接,所以我们进入 bin 路径:

cd 12.2.1/bin/
ln -s aarch64-none-linux-gnu-gcc arm-linux-gcc
ln -s aarch64-none-linux-gnu-ld arm-linux-ld
ln -s aarch64-none-linux-gnu-objdump arm-linux-objdump
ln -s aarch64-none-linux-gnu-objcopy arm-linux-objcopy
ln -s aarch64-none-linux-gnu-strip arm-linux-strip
ln -s aarch64-none-linux-gnu-cpp arm-linux-cpp
ln -s aarch64-none-linux-gnu-ar arm-linux-ar
ln -s aarch64-none-linux-gnu-as arm-linux-as
ln -s aarch64-none-linux-gnu-strings arm-linux-strings
ln -s aarch64-none-linux-gnu-readelf arm-linux-readelf
ln -s aarch64-none-linux-gnu-size arm-linux-size
ln -s aarch64-none-linux-gnu-c++ arm-linux-c++
ln -s aarch64-none-linux-gnu-gdb arm-linux-gdb
ln -s aarch64-none-linux-gnu-nm arm-linux-nm
ln -s aarch64-none-linux-gnu-g++ arm-linux-g++

参考文章

[1] rk3399移植 u-boot

[2] ARM CPU汇总 & 编译链选择

[3] u-boot (3) —— spl

[4] Rockchip Boot option

[5] U-Boot 之零 源码文件、启动阶段(TPL、SPL)、FALCON、设备树

[6] RK3399 TRM

[7] RK3399 Datasheet

[8] Rockchip RK3399TRM V1.3 Part1.pdf

[9] Rockchip RK3399TRM V1.3 Part2.pdf

转自:Rockchip RK3399 - 引导流程和准备工作

   
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值