Allwinner a64 - переключение с aarch32 на aarch64 путем горячего сброса

Я хочу развернуть простое программное обеспечение на голом железе на плате Pine64, на которой размещается Allwinner A64 SoC. Конфигурация следующая: при включении boot0 запускает u-boot, который загружает мой hello.bin в ОЗУ (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

Предполагается, что он выполнит теплый сброс и запустит выполнение в 0x40008000 в состоянии выполнения aarch64. Но при запуске я получаю ошибку Неопределенная инструкция, и она перезапускается в том же состоянии и начинается с 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 ... 

Это почему?

РЕДАКТИРОВАТЬ:

  1. Первую проблему заметил @Frant ниже, двоичный файл, который должен быть связан с другим адресом раздела .text, то есть с 0x40000000 вместо 0x0.

  2. Он также не мог работать при загрузке u-boot, то есть в EL2. Чтобы писать в RMR, нужно быть в EL3. Это возможно с помощью метода ЛСЭ.

ПРИМЕЧАНИЕ. После того, как я столкнулся с этой проблемой, я стал просить кого-то о помощи и, по-видимому, использовал старый способ перепрошивки платы. С тех пор, как Pine64 получил гораздо лучшую поддержку, теперь его можно загрузить двумя более удобными способами: * mainline u-boot с atf, который напрямую сгенерирует двоичный файл, который можно прошить на SD-карту, и сбросить вас в EL2, * использование инструмента sunxi-fel, как описано ниже, что очень удобно, если кто-то не хочет постоянно перепрограммировать SD-карту, приводит к падению уровня EL3 (ВНИМАНИЕ: sunxi wiki немного вводит в заблуждение аргументы команды sunxi-fel, эти ниже работал у меня).


person Maciej Bielski    schedule 01.05.2018    source источник


Ответы (1)


Мой ответ - это попытка ответить на следующий вопрос: работает ли код переключения состояния aarch32, который вы используете?
Хорошая новость заключается в том, что код, который вы используете, работает нормально. Плохая новость заключается в том, что что-то еще может не работать должным образом в вашей среде. Это меня не сильно удивит, учитывая ужасное состояние всех готовых BSP Allwinner.

Так как я не знал, какие точные версии boot0 и u-boot, которые вы использовали, я протестировал ваш код с помощью FEL- совместимые двоичные файлы SPL для A64 / H5 - см. раздел Загрузка FEL в записи A64 для получения дополнительной информации - и sunxi-fel: это удаляет boot0 и u-boot вас используются в качестве потенциальных виновников.

Минимальный, полный и проверяемый пример, который я построил для тестирования вашего кода требует:

  • Извлечение SD-карты из Pine64, чтобы она перешла в режим FEL при включении,
  • Кабель USB 2.0 «папа-А-папа-А» для подключения компьютера к верхнему разъему USB-хоста сосны64.
  • Сценарий bash, build.sh, для создания sunxi-инструментов, получения двоичных файлов SPL с поддержкой FEL,

  • rmr_switch.S, версия rmr_switch. S минус комментарии плюс символ, который необходимо предварительно обработать для установки начального адреса без необходимости постоянно изменять файл,

  • rmr_switch2.S, версия rmr_switch.S, упомянутая выше, но использующая r0 и r1 так, как они используются в патче, на который вы ссылались.
  • uart-aarch32.s, программа aarch32, отображающая *** Hello from aarch32! *** на UART0,
  • uart-aarch64.s, программа aarch64, отображающая *** Hello from aarch64! *** на UART0.

    Вот содержание каждого из необходимых файлов:

  • build.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
    
  • 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
    
  • 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
    
  • 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
    
    • 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
      

Когда все файлы будут в одном каталоге, процедура тестирования будет следующей:

  1. Выполнить build.sh: вы можете указать SOC, который вы используете, A64 (по умолчанию) или H5, а также aarch32 / aarch64 toolchains в командной строке:

    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
    

Результат должен выглядеть так (я удалил безобидные предупреждения):

------------------ 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
------------------------------------------------------------------


Теперь, прежде чем вводить sunxi-fel команды, необходимые для каждого из четырех тестов, вам нужно отключить Pine64 от источника питания и от любой розетки USB-хоста, к которой он может быть подключен (USB TTL uart, папа-A-папа -USB-кабель). Снова подключите Pine64 к источнику питания, затем снова подключите USB-кабели.

lsusb должен теперь отображать:

Bus 001 Device 016: ID 1f3a:efe8 Onda (unverified) V972 tablet in flashing mode

Вывод на последовательную консоль для четырех тестов должен быть:

  1. test uart-aarch32 (проверка того, что программа aarch32 запускается с 0x40000000):

    U-Boot SPL 2018.01-00007-gdb0ecc9b42 (Feb 23 2018 - 00:50:52)
    DRAM: 512 MiB
    Trying to boot from FEL
    *** Hello from aarch32! ***
    
  2. test uart-aarch64 (проверка того, что программа aarch64 запускается с 0x40008000):

    U-Boot SPL 2018.01-00007-gdb0ecc9b42 (Feb 23 2018 - 00:50:52)
    DRAM: 512 MiB
    Trying to boot from FEL
    *** Hello from aarch64! ***
    
  3. test test rmr_switch uart-aarch64 (запуск rmr_switch из 0x40000000, который переключится в состояние aarch64 и выполнит uart-aarch64 из 0x40008000):

    U-Boot SPL 2018.01-00007-gdb0ecc9b42 (Feb 23 2018 - 00:50:52)
    DRAM: 512 MiB
    Trying to boot from FEL
    *** Hello from aarch64! ***
    
  4. test test rmr_switch2 uart-aarch64 (запуск rmr_switch2 из 0x40000000, который переключится в состояние aarch64 и выполнит uart-aarch64 из 0x40008000):

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

Стоит отметить, что эти тесты могут быть выполнены в Windows с помощью наборов инструментов Linaro mingw32, версия sunxi-fel для Windows и Zadig.


В итоге, код, который вы использовали, похоже, работает хорошо, а код 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

Примеры были успешно протестированы на OrangePI PC2 на базе H5. Командная строка для запуска 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

Вывод для build.sh и, следовательно, выполняемых команд sunxi-fel будет немного отличаться, поскольку придется использовать другой, специфичный для H5, FEL-совместимый SPL.

Я заметил небольшую разницу между кодом, который вы используете, и кодом rmr_switch2, но поскольку он идет после переключения состояния / после wfi, я думаю, это не имеет значения - я предполагаю, что код, который вы собрали, сам немного отличался:

Ты так):

28:   eafffffe        b       28 <_reset+0x28>

Мой (.elf):

40000028:       eafffffd        b       40000024 <.text+0x24>

Надеюсь, это поможет.

person Frant    schedule 04.05.2018
comment
Ух ты, потрясающая работа, очень интересно. Я лучше посмотрю на это. Между тем мне сказали, что писать в RMR с уровня SVC не получится, это можно сделать только в режиме монитора. Более того, следуя рекомендациям других людей, я перешел на основную u-boot с поддержкой SPL - мне удалось дойти до запуска u-boot с моей пользовательской средой. Но для этого нужна карта SC. После вики sunxi я не смог загрузиться в режиме FEL, хотя это было бы здорово для моих нужд. Спасибо за ваш пост! - person Maciej Bielski; 06.05.2018
comment
Нет причин, по которым ваш Pine64 не перешел бы в режим FEL, когда нет SD-карты и используется USB-кабель «папа-А-папа», а не кабель micro-USB. Опять же, убедитесь, что он включен, когда к вашему компьютеру больше ничего не подключено. Адаптера USB-TTL достаточно для некоторого питания Pine64 и предотвращения «чистого» цикла питания, следовательно, срабатывания режима FEL. Поверьте, раз уж вы его используете, вы не сможете вернуться назад при тестировании низкоуровневого кода. Спасибо за ваш комментарий - в основном я строил на чужих работах. - person Frant; 06.05.2018
comment
Я добавил немного дополнительных пояснений к своему вопросу. Во-первых, хороший улов по разным адресам в rmr.s программе. Но что еще более важно, этот ответ помог мне правильно использовать подход FEL, чего я не смог сделать с вики sunxi, и я отказался от него. Теперь это работает, и это намного удобнее. Спасибо за ваше время. - person Maciej Bielski; 06.05.2018
comment
Рад слышать, что FEL теперь работает на вас. Еще одно преимущество подхода FEL заключается в том, что вы должны приземлиться в состоянии aarch64 на уровне EL3. Обычно это бесполезно, если вы не хотите экспериментировать и изучать без помощи рук на aarch64, что является моим случаем. Использование ATF и mainline u-boot приводит к запуску u-boot на EL2. - person Frant; 07.05.2018