Allwinner a64 - 通过热复位从 aarch32 切换到 aarch64

Mac*_*ski 2 bare-metal u-boot arm64

我想在 Pine64 板上部署一个简单的裸机软件,托管全志 A64 SoC。配置如下:开机时boot0启动u-boot,将my加载hello.bin到RAM( 0x40000000)并开始执行。问题是它处于 aarch32 执行状态,我想要 aarch64。

我已经找到了一种方法来做到这一点,就像在这个补丁中一样维基上也有一些背景。

我已复制代码并objdump -d hello.o返回与链接中相同的结果:

.text 节的反汇编:

00000000 <_reset>:
   0:   e59f0024        ldr     r0, [pc, #36]   ; 2c <_reset+0x2c>
   4:   e59f1024        ldr     r1, [pc, #36]   ; 30 <_reset+0x30>
   8:   e5801000        str     r1, [r0]
   c:   f57ff04f        dsb     sy
  10:   f57ff06f        isb     sy
  14:   ee1c0f50        mrc     15, 0, r0, cr12, cr0, {2}
  18:   e3800003        orr     r0, r0, #3
  1c:   ee0c0f50        mcr     15, 0, r0, cr12, cr0, {2}
  20:   f57ff06f        isb     sy
  24:   e320f003        wfi
  28:   eafffffe        b       28 <_reset+0x28>
  2c:   017000a0        .word   0x017000a0
  30:   40008000        .word   0x40008000
Run Code Online (Sandbox Code Playgroud)

它应该在 aarch64 执行状态下执行热重置并开始执行0x40008000。但是在运行时我收到未定义的指令错误,它以相同的状态重新启动并从0x0.

## Starting application at 0x40000000 ...                    
undefined instruction                                        
pc : [<40000018>]          lr : [<7ff1d054>]                 
sp : 76eb8a90  ip : 00000030     fp : 7ff1d00c               
r10: 00000002  r9 : 76ed0ea0     r8 : 7ffb5340               
r7 : 77f1bd78  r6 : 40000000     r5 : 00000002  r4 : 77f1bd7c
r3 : 40000000  r2 : 77f1bd7c     r1 : 40008000  r0 : 017000a0
Flags: nZCv  IRQs on  FIQs off  Mode SVC_32                  
Resetting CPU ... 
Run Code Online (Sandbox Code Playgroud)

这是为什么?

编辑:

  1. 下面的@Frant 注意到了第一个问题,二进制文件应该与不同的 .text 部分地址链接,即从而0x40000000不是.text 开始0x0

  2. 它也无法通过 u-boot 加载,即在 EL2 中。为了写入 RMR,需要在 EL3 中。这可以通过 FEL 方法实现。

注意:在遇到这个问题后,我四处寻求帮助,显然我正在使用一种旧的方式来闪烁电路板。一段时间以来,Pine64 得到了更好的支持,现在可以通过两种更方便​​的方式启动它: * 主线 u-boot with atf,这将直接生成一个可以闪存到 SD 卡的二进制文件,然后将您放入 EL2,*使用该sunxi-fel工具,如下所述,如果不想一直重新刷新 SD 卡,这是非常方便的,将您放入 EL3(警告:sunxi wiki 在sunxi-fel命令参数上有点误导,下面的这些适用于我)。

Fra*_*ant 5

我的回答是试图回答以下问题:您使用的 aarch32 状态切换代码是否有效?
好消息是您使用的代码运行良好。坏消息是,在您的环境中,其他东西可能无法正常工作。考虑到所有全志开箱即用 BSP 的糟糕状态,这不会让我感到惊讶。

由于我不知道您使用的是哪个确切版本的 boot0 和 u-boot,我使用 Andre Przywara 的A64/H5 支持FEL 的 SPL 二进制文件测试了您的代码-有关更多详细信息,请参阅A64 条目的FEL 启动部分 - 和sunxi -fel:这确实删除了您用作潜在罪魁祸首的 boot0 和 u-boot。

最小的,完整的和可验证的例子 我为测试您的代码而构建,需要:

  • 从 Pine64 中取出 SD 卡,使其在上电时进入 FEL 模式,
  • A 公 A 公 A USB 2.0 电缆,用于将您的 PC 连接到Pine64的上部 USB 主机插座
  • bash 脚本,build.sh用于构建 sunxi-tools,检索支持 FEL 的 SPL 二进制文件,

  • rmr_switch.S, rmr_switch.S 的一个版本减去注释加上要预处理的符号用于设置起始地址,而不必一直修改文件,

  • rmr_switch2.S,上面提到的 rmr_switch.S 的一个版本,但是使用 r0 和 r1 的方式与您在引用的补丁中使用它们的方式相同。
  • uart-aarch32.s,显示*** Hello from aarch32! ***在 UART0上的 aarch32 程序,
  • uart-aarch64.s,显示*** Hello from aarch64! ***在 UART0上的 aarch64 程序。

    以下是每个必需文件的内容:

  • 构建.sh:

    #!/bin/bash
    
    # usage: 
    # CROSS_COMPILE_AARCH64=/opt/linaro/gcc-linaro-7.2.1-2017.11-x86_64_aarch64-elf/bin/aarch64-elf- CROSS_COMPILE_AARCH32=/opt/linaro/gcc-linaro-7.2.1-2017.11-x86_64_arm-eabi/bin/arm-eabi- ./build.sh
    
    clear
    
    CROSS_COMPILE_AARCH64=${CROSS_COMPILE_AARCH64:-/opt/linaro/gcc-linaro-7.2.1-2017.11-x86_64_aarch64-elf/bin/aarch64-elf-}
    CROSS_COMPILE_AARCH32=${CROSS_COMPILE_AARCH32:-/opt/linaro/gcc-linaro-7.2.1-2017.11-x86_64_arm-eabi/bin/arm-eabi-}
    SOC=${SOC:-a64}
    
    #AARCH32_START_ADDRESS=0x42000000
    #AARCH64_START_ADDRESS=0x42010000
    
    AARCH32_START_ADDRESS=0x40000000 
    AARCH64_START_ADDRESS=0x40008000
    
    SUNXI_FEL=sunxi-tools/sunxi-fel
    
    install_sunxi_tools()
    {
      if [ ! -f ${SUNXI_FEL} ]
      then
        git clone --branch v1.4.2 https://github.com/linux-sunxi/sunxi-tools
        pushd sunxi-tools
        make 
        popd
      fi
    }
    
    retrieve_spl_aarch32()
    {
      if [ ! -f sunxi-a64-spl32-ddr3.bin ]
      then
        wget https://github.com/apritzel/pine64/raw/master/binaries/sunxi-a64-spl32-ddr3.bin
      fi
    
      if [ ! -f sunxi-h5-spl32-ddr3.bin ]
      then
        wget https://github.com/apritzel/pine64/raw/master/binaries/sunxi-h5-spl32-ddr3.bin
      fi
    }
    
    
    test_aarch32()
    {
      # testing aarch32 program
      PROGRAM=uart-aarch32.s
      BASE=${PROGRAM%%.*}
    
      ${CROSS_COMPILE_AARCH32}gcc -O0 -nostdlib -nostartfiles -e ${AARCH64_START_ADDRESS} -Wl,-Ttext=${AARCH32_START_ADDRESS} -o ${BASE}.elf ${BASE}.s
      ${CROSS_COMPILE_AARCH32}objcopy --remove-section .note.gnu.build-id ${BASE}.elf
      ${CROSS_COMPILE_AARCH32}objcopy --remove-section .ARM.attributes ${BASE}.elf
      ${CROSS_COMPILE_AARCH32}objdump -D ${BASE}.elf > ${BASE}.lst
      ${CROSS_COMPILE_AARCH32}objcopy -O binary ${BASE}.elf  ${BASE}.bin
      ${CROSS_COMPILE_AARCH32}objcopy  ${BASE}.elf -O srec ${BASE}.srec
    
      echo "------------------ test uart-aarch32 -----------------------------"
      echo sudo ${SUNXI_FEL} spl sunxi-${SOC}-spl32-ddr3.bin
      echo sudo ${SUNXI_FEL} write ${AARCH32_START_ADDRESS} uart-aarch32.bin
      echo sudo ${SUNXI_FEL} exe ${AARCH32_START_ADDRESS}
      echo "------------------------------------------------------------------"
    }
    
    test_aarch64()
    {
      # testing aarch64 program
      PROGRAM=uart-aarch64.s
      BASE=${PROGRAM%%.*}
    
      ${CROSS_COMPILE_AARCH64}gcc -O0 -nostdlib -nostartfiles -e ${AARCH64_START_ADDRESS} -Wl,-Ttext=${AARCH64_START_ADDRESS} -o ${BASE}.elf ${BASE}.s
      ${CROSS_COMPILE_AARCH64}objcopy --remove-section .note.gnu.build-id ${BASE}.elf
      ${CROSS_COMPILE_AARCH64}objcopy --remove-section .ARM.attributes ${BASE}.elf
      ${CROSS_COMPILE_AARCH64}objdump -D ${BASE}.elf > ${BASE}.lst
      ${CROSS_COMPILE_AARCH64}objcopy -O binary ${BASE}.elf  ${BASE}.bin
      ${CROSS_COMPILE_AARCH64}objcopy  ${BASE}.elf -O srec ${BASE}.srec
    
      echo "------------------ test uart-aarch64 -----------------------------"
      echo sudo ${SUNXI_FEL} spl sunxi-${SOC}-spl32-ddr3.bin
      echo sudo ${SUNXI_FEL} write ${AARCH64_START_ADDRESS} uart-aarch64.bin
      echo sudo ${SUNXI_FEL} reset64 ${AARCH64_START_ADDRESS}
      echo "------------------------------------------------------------------"
    }
    
    test_rmr_switch()
    {
    # compiling rmr_switch.s
      PROGRAM=rmr_switch.s
      BASE=${PROGRAM%%.*}
    
      rm -f ${BASE}.s
      ${CROSS_COMPILE_AARCH64}cpp -DAARCH64_START_ADDRESS=${AARCH64_START_ADDRESS} ${BASE}.S > ${BASE}.s
    
      ${CROSS_COMPILE_AARCH32}gcc -O0 -nostdlib -nostartfiles -e ${AARCH32_START_ADDRESS} -Wl,-Ttext=${AARCH32_START_ADDRESS} -o ${BASE}.elf ${BASE}.s
      ${CROSS_COMPILE_AARCH32}objcopy --remove-section .note.gnu.build-id ${BASE}.elf
      ${CROSS_COMPILE_AARCH32}objcopy --remove-section .ARM.attributes ${BASE}.elf
      ${CROSS_COMPILE_AARCH32}objdump -D ${BASE}.elf > ${BASE}.lst
      ${CROSS_COMPILE_AARCH32}objcopy -O binary ${BASE}.elf  ${BASE}.bin
      ${CROSS_COMPILE_AARCH32}objcopy  ${BASE}.elf -O srec ${BASE}.srec
    
      echo "------------------ test rmr_switch uart-aarch64 ------------------"
      echo sudo ${SUNXI_FEL} spl sunxi-${SOC}-spl32-ddr3.bin
      echo sudo ${SUNXI_FEL} write ${AARCH32_START_ADDRESS} rmr_switch.bin
      echo sudo ${SUNXI_FEL} write ${AARCH64_START_ADDRESS} uart-aarch64.bin
      echo sudo ${SUNXI_FEL} exe ${AARCH32_START_ADDRESS}
      echo "------------------------------------------------------------------"
    }
    
    test_rmr_switch2()
    {
    # compiling rmr_switch2.s
      PROGRAM=rmr_switch2.s
      BASE=${PROGRAM%%.*}
    
      rm -f ${BASE}.s
      ${CROSS_COMPILE_AARCH64}cpp -DAARCH64_START_ADDRESS=${AARCH64_START_ADDRESS} ${BASE}.S > ${BASE}.s
    
      ${CROSS_COMPILE_AARCH32}gcc -O0 -nostdlib -nostartfiles -e ${AARCH32_START_ADDRESS} -Wl,-Ttext=${AARCH32_START_ADDRESS} -o ${BASE}.elf ${BASE}.s
      ${CROSS_COMPILE_AARCH32}objcopy --remove-section .note.gnu.build-id ${BASE}.elf
      ${CROSS_COMPILE_AARCH32}objcopy --remove-section .ARM.attributes ${BASE}.elf
      ${CROSS_COMPILE_AARCH32}objdump -D ${BASE}.elf > ${BASE}.lst
      ${CROSS_COMPILE_AARCH32}objcopy -O binary ${BASE}.elf  ${BASE}.bin
      ${CROSS_COMPILE_AARCH32}objcopy  ${BASE}.elf -O srec ${BASE}.srec
    
      echo "------------------ test rmr_switch2 uart-aarch64 -----------------"
      echo sudo ${SUNXI_FEL} spl sunxi-${SOC}-spl32-ddr3.bin
      echo sudo ${SUNXI_FEL} write ${AARCH32_START_ADDRESS} rmr_switch2.bin
      echo sudo ${SUNXI_FEL} write ${AARCH64_START_ADDRESS} uart-aarch64.bin
      echo sudo ${SUNXI_FEL} exe ${AARCH32_START_ADDRESS}
      echo "------------------------------------------------------------------"
    }
    
    # prerequisites 
    install_sunxi_tools
    retrieve_spl_aarch32
    
    # test
    test_aarch32
    test_aarch64
    test_rmr_switch
    test_rmr_switch2
    
    Run Code Online (Sandbox Code Playgroud)
  • rmr_switch.S:

        .text
        ldr    r1, =0x017000a0               @ MMIO mapped RVBAR[0] register
        ldr    r0, =AARCH64_START_ADDRESS    @ start address, to be replaced
        str    r0, [r1]
        dsb    sy
        isb    sy
        mrc    15, 0, r0, cr12, cr0, 2       @ read RMR register
        orr    r0, r0, #3                    @ request reset in AArch64
        mcr    15, 0, r0, cr12, cr0, 2       @ write RMR register
        isb    sy
    1:  wfi
        b      1b
    
    Run Code Online (Sandbox Code Playgroud)
  • rmr_switch2.S:

        .text
        ldr    r0, =0x017000a0               @ MMIO mapped RVBAR[0] register
        ldr    r1, =AARCH64_START_ADDRESS    @ start address, to be replaced
        str    r1, [r0]
        dsb    sy
        isb    sy
        mrc    15, 0, r0, cr12, cr0, 2       @ read RMR register
        orr    r0, r0, #3                    @ request reset in AArch64
        mcr    15, 0, r0, cr12, cr0, 2       @ write RMR register
        isb    sy
    1:  wfi
        b      1b
    
    Run Code Online (Sandbox Code Playgroud)
  • UART-aarch32.s:

                  .code 32
                  .text
                  ldr  r1,=0x01C28000
                  ldr  r2,=message
    loop:         ldrb r0, [r2]
                  add  r2, r2, #1
                  cmp  r0, #0
                  beq  completed
                  strb r0, [r1]
                  b    loop
    completed:    b .
                  .data
    message:
                  .asciz "*** Hello from aarch32! ***"
                  .end
    
    Run Code Online (Sandbox Code Playgroud)
    • UART-aarch64.s:

                    .text
                    ldr  x1,=0x01C28000
                    ldr  x2,=message
      loop:         ldrb w0, [x2]
                    add  x2, x2, #1
                    cmp  w0, #0
                    beq  completed
                    strb w0, [x1]
                    b    loop
      completed:    b .
                    .data
      message:
                    .asciz "*** Hello from aarch64! ***"
                    .end
      
      Run Code Online (Sandbox Code Playgroud)

一旦所有文件都在同一目录中,测试过程将是:

  1. 执行build.sh:可以在命令行中指定你使用的SOC是A64(默认)还是H5,以及aarch32/aar​​ch64工具链

    CROSS_COMPILE_AARCH64=/opt/linaro/gcc-linaro-7.2.1-2017.11-x86_64_aarch64-elf/bin/aarch64-elf- CROSS_COMPILE_AARCH32=/opt/linaro/gcc-linaro-7.2.1-2017.11-x86_64_arm-eabi/bin/arm-eabi- ./build.sh
    
    Run Code Online (Sandbox Code Playgroud)

输出应如下所示,(我删除了无害警告):

------------------ test uart-aarch32 -----------------------------
sudo sunxi-tools/sunxi-fel spl sunxi-a64-spl32-ddr3.bin
sudo sunxi-tools/sunxi-fel write 0x40000000 uart-aarch32.bin
sudo sunxi-tools/sunxi-fel exe 0x40000000

------------------ test uart-aarch64 -----------------------------
sudo sunxi-tools/sunxi-fel spl sunxi-a64-spl32-ddr3.bin
sudo sunxi-tools/sunxi-fel write 0x40008000 uart-aarch64.bin
sudo sunxi-tools/sunxi-fel reset64 0x40008000

------------------ test rmr_switch uart-aarch64 ------------------
sudo sunxi-tools/sunxi-fel spl sunxi-a64-spl32-ddr3.bin
sudo sunxi-tools/sunxi-fel write 0x40000000 rmr_switch.bin
sudo sunxi-tools/sunxi-fel write 0x40008000 uart-aarch64.bin
sudo sunxi-tools/sunxi-fel exe 0x40000000

------------------ test rmr_switch2 uart-aarch64 -----------------
sudo sunxi-tools/sunxi-fel spl sunxi-a64-spl32-ddr3.bin
sudo sunxi-tools/sunxi-fel write 0x40000000 rmr_switch2.bin
sudo sunxi-tools/sunxi-fel write 0x40008000 uart-aarch64.bin
sudo sunxi-tools/sunxi-fel exe 0x40000000
------------------------------------------------------------------
Run Code Online (Sandbox Code Playgroud)


现在,在输入sunxi-fel四个测试中每一个所需的命令之前,您需要将 Pine64 从其电源和它可能插入的任何 USB 主机插座中拔出(USB TTL uart,公 A 到公 A USB 电缆) . 将 Pine64 重新连接到其电源,然后重新插入 USB 电缆。

lsusb 现在应该显示:

Bus 001 Device 016: ID 1f3a:efe8 Onda (unverified) V972 tablet in flashing mode
Run Code Online (Sandbox Code Playgroud)

四个测试的串行控制台上的输出应为:

  1. 测试 uart-aarch32(验证从 0x40000000 运行的 aarch32 程序):

    U-Boot SPL 2018.01-00007-gdb0ecc9b42 (Feb 23 2018 - 00:50:52)
    DRAM: 512 MiB
    Trying to boot from FEL
    *** Hello from aarch32! ***
    
    Run Code Online (Sandbox Code Playgroud)
  2. 测试 uart-aarch64(验证从 0x40008000 运行的 aarch64 程序):

    U-Boot SPL 2018.01-00007-gdb0ecc9b42 (Feb 23 2018 - 00:50:52)
    DRAM: 512 MiB
    Trying to boot from FEL
    *** Hello from aarch64! ***
    
    Run Code Online (Sandbox Code Playgroud)
  3. test test rmr_switch uart-aarch64(从0x40000000运行rmr_switch,会切换到aarch64状态,从0x40008000开始执行uart-aarch64):

    U-Boot SPL 2018.01-00007-gdb0ecc9b42 (Feb 23 2018 - 00:50:52)
    DRAM: 512 MiB
    Trying to boot from FEL
    *** Hello from aarch64! ***
    
    Run Code Online (Sandbox Code Playgroud)
  4. test test rmr_switch2 uart-aarch64(从0x40000000运行rmr_switch2,会切换到aarch64状态,从0x40008000开始执行uart-aarch64):

    U-Boot SPL 2018.01-00007-gdb0ecc9b42 (Feb 23 2018 - 00:50:52)
    DRAM: 512 MiB
    Trying to boot from FEL
    *** Hello from aarch64! ***
    
    Run Code Online (Sandbox Code Playgroud)

值得一提的是,这些测试可以使用 Linaro mingw32 工具链、sunxi-fel 的 Windows 版本和 Zadig在 Windows上执行。


最重要的是,您使用的代码似乎运行良好,并且我组装的 rmr_switch2.s 代码与您正在使用的代码相同(我猜):

rmr_switch2.elf:     file format elf32-littlearm


Disassembly of section .text:

40000000 <.text>:
40000000:       e59f0024        ldr     r0, [pc, #36]   ; 4000002c <.text+0x2c>
40000004:       e59f1024        ldr     r1, [pc, #36]   ; 40000030 <.text+0x30>
40000008:       e5801000        str     r1, [r0]
4000000c:       f57ff04f        dsb     sy
40000010:       f57ff06f        isb     sy
40000014:       ee1c0f50        mrc     15, 0, r0, cr12, cr0, {2}
40000018:       e3800003        orr     r0, r0, #3
4000001c:       ee0c0f50        mcr     15, 0, r0, cr12, cr0, {2}
40000020:       f57ff06f        isb     sy
40000024:       e320f003        wfi
40000028:       eafffffd        b       40000024 <.text+0x24>
4000002c:       017000a0        cmneq   r0, r0, lsr #1
40000030:       40008000        andmi   r8, r0, r0
Run Code Online (Sandbox Code Playgroud)

这些示例已在基于 H5 的 OrangePI PC2 上成功测试。运行 build.sh 的命令行应该是:

SOC=h5 CROSS_COMPILE_AARCH64=/opt/linaro/gcc-linaro-7.2.1-2017.11-x86_64_aarch64-elf/bin/aarch64-elf- CROSS_COMPILE_AARCH32=/opt/linaro/gcc-linaro-7.2.1-2017.11-x86_64_arm-eabi/bin/arm-eabi- ./build.sh
Run Code Online (Sandbox Code Playgroud)

build.sh 的输出以及要执行的 sunxi-fel 命令将略有不同,因为必须使用不同的、特定于 H5 的、支持 FEL 的 SPL。

我注意到您正在使用的代码和 rmr_switch2 代码之间存在细微差别,但由于它是在状态切换之后/在 wfi 之后出现的,所以我猜应该没有关系 - 我假设您组装的代码本身略有不同:

你的 (.o):

28:   eafffffe        b       28 <_reset+0x28>
Run Code Online (Sandbox Code Playgroud)

我的(.elf):

40000028:       eafffffd        b       40000024 <.text+0x24>
Run Code Online (Sandbox Code Playgroud)

我希望这会有所帮助。