如何为 Raspberry pi 3 编译 ARMv8 代码

Posted

技术标签:

【中文标题】如何为 Raspberry pi 3 编译 ARMv8 代码【英文标题】:How to compile ARMv8 code for Raspberry pi 3 【发布时间】:2019-04-07 15:26:33 【问题描述】:

我一直在按照here 的教程为我的树莓派编写基本操作系统。我已经阅读了文档并更改了寄存器,以便它们应该运行,但由于树莓派 3 是 64 位,因此使用 ARMv8,lsl 超出了范围。我使用的是 mac,所以一直在使用 YAGARTO,但真的不知道如何或在哪里获得另一个 64 位编译器。

任何感兴趣的人的代码:

.section .init
.globl _start
_start:

ldr r0,=0x3f200000


mov r1,#1
lsl r1,#21
str r1,[r0,#16]


mov r1,#1
lsl r1,#47
str r1,[r0,#28]

loop$: 
b loop$

【问题讨论】:

这仍然是 32 位 ARM 代码。 64 位 ARM(ARM64,AArch64)代码看起来有点不同。这不像在 x86 上只是寄存器的大小发生了变化。 ARM64 是一个完全不同的架构,具有不同的寄存器和指令。 可以通过 raspberrypi.org 裸机论坛找到许多示例。 aarch32 和 aarch64。 与其他不兼容的指令集一样,gcc 是为特定目标构建的,因此它是针对 aarch64 和 aarch32 的单独 gcc 构建。 你自己搞定了mandelbrot的事情吗?我正要发表评论。您重复使用了 y 变量。 @Blorgbeard,感谢您的关注。在我更改了一些数字并获得了无限循环之后,我注意到了。谢谢:) 【参考方案1】:

我建议查看 David Welch 的 RaspberryPi 3 here 的 aarch64 示例。为了方便起见,他的引导加载程序允许上传 .hex 格式的文件。 作为记录,您可以使用以下命令从已编译的可执行文件创建 .hex:

aarch64-none-objcopy program.elf -O ihex example.elf example.hex

关于工具链,据我所知,Linaro 和 ARM 只为 Linux 和 mingw 提供工具链。但是您可以使用个人为 OSX 构建的工具链,例如 Sergio Benitez 提供的this one。

更新:一个方便的替代方法是根据here 描述的出色程序在您的 SD 卡上安装 u-boot。

假设您在 /opt 中安装了 aarch64-none 工具链,因此 aarch64-none-gcc 的路径为:

/opt/aarch64-none/bin/aarch64-none-gcc

适合您需要的简化程序是:

在您的 SD 卡上创建一个最小的 config.txt,

enable_uart=1
arm_control=0x200
kernel=u-boot.bin

将bootcode.bin、fixup.dat和start.elf复制到SD卡,

构建u-boot,

wget ftp://ftp.denx.de/pub/u-boot/u-boot-2019.01.tar.bz2
tar Jxf u-boot-2019.01.tar.bz2
cd u-boot-2019.01
make CROSS_COMPILE=/opt/aarch64-none/bin/aarch64-none- ARCH=arm64  rpi_3_defconfig all

将 u-boot.bin 复制到 SD 卡 - 它现在应该包含以下文件:

2019-04-08  06:03 PM               108 config.txt
2019-04-08  04:11 PM         2,873,444 start.elf
2019-04-08  04:11 PM            52,296 bootcode.bin
2019-04-08  04:11 PM             6,701 fixup.dat
2019-04-08  04:08 PM           479,872 u-boot.bin

将 SD 卡安装到 Raspberry-pi3 中, 假设您安装了串口转 USB 加密狗,并且终端仿真器配置为使用具有以下设置的 USB 串口:

115200 bps, 8 data bits, 1 stop bit, no parity, no hardware flow control

您现在可以启动您的设备,并尽快按CTRL+C 以中断启动过程:

U-Boot 2019.01 (Apr 08 2019 - 16:07:23 -0400)

DRAM:  948 MiB
RPI 3 Model B (0xa22082)
MMC:   mmc@7e202000: 0, sdhci@7e300000: 1
Loading Environment from FAT... *** Warning - bad CRC, using default environment

In:    serial
Out:   vidconsole
Err:   vidconsole
Net:   No ethernet found.
starting USB...
USB0:   scanning bus 0 for devices... 3 USB Device(s) found
       scanning usb for storage devices... 0 Storage Device(s) found
Hit any key to stop autoboot:  0
U-Boot> <INTERRUPT>

bootdelay环境变量设置为2(秒),为了避免每次开机都使用CTRL+C,需要设置为-1(无限):

U-Boot> printenv bootdelay
bootdelay=2
U-Boot> setenv bootdelay -1
U-Boot> saveenv
Saving Environment to FAT... OK
U-Boot>

如果输入reset命令,pi会重启,但u-boot会停止:

U-Boot> reset
resetting ...
U

‡t-Boot 2019.01 (Apr 08 2019 - 16:07:23 -0400)

DRAM:  948 MiB
RPI 3 Model B (0xa22082)
MMC:   mmc@7e202000: 0, sdhci@7e300000: 1
Loading Environment from FAT... OK
In:    serial
Out:   vidconsole
Err:   vidconsole
Net:   No ethernet found.
starting USB...
USB0:   scanning bus 0 for devices... 3 USB Device(s) found
       scanning usb for storage devices... 0 Storage Device(s) found
U-Boot>

您现在可以使用所有可用的 u-boot 命令来检查/更改内存,以及加载/执行程序:

创建一个名为hello-aarch64.s 的文件,内容如下:

                  .title "hello-aarch64.s"
                  .arch  armv8-a
                  .equ   AUX_MU_IO_REG, 0x3F215040  
                  .equ   AUX_MU_LSR_REG, 0x3F215054 
                  .text
                  .section .text.startup,"ax"    
                  .globl Reset_Handler
Reset_Handler:    stp  x29, x30,  [sp, #-16]!        
                  adr  x19, msg
                  ldr  x20,= AUX_MU_IO_REG
                  ldr  x21,= AUX_MU_LSR_REG
loop:             ldrb w0, [x19], 1                  
                  cbz  w0, done               
wait:             ldrb w1, [x21]
                  tbz  w1, #5, wait
                  strb w0, [x20]
                  b    loop
done:             ldp  x29,x30,  [sp], #16                 
                  ret
                  .balign 16
msg:              .asciz "Hello, aarch64 bare-metal world!\r\n"
                  .end

因为我们将从 u-boot 调用程序并且不想让它崩溃,所以程序应该符合ARM Procedure Call Standard for the ARM 64-bit Architecture - 这在这里有点矫枉过正,因为我们没有调用任何函数,但它没有问题。

可以使用以下命令编译程序并创建一个s-record文件:

CROSS_COMPILE= /opt/aarch64-none/bin/aarch64-none-
AS=$CROSS_COMPILEas
LD=$CROSS_COMPILEld
OBJCOPY=$CROSS_COMPILEobjcopy
OBJDUMP=$CROSS_COMPILEobjdump
$AS -o hello-aarch64.o hello-aarch64.s
$LD -e Reset_Handler --section-start .text=0x00200000 -Map=hello-aarch64.map -o hello-aarch64.elf hello-aarch64.o 
$OBJCOPY hello-aarch64.elf -O srec hello-aarch64.srec

现在可以上传并执行程序: 在u-boot中输入以下命令:

U-Boot> loads
## Ready for S-Record download ...

从终端模拟器,将hello-aarch64.srec 文件发送到u-boot(没有x-modem,没有kermit,文件原样)。

## First Load Addr = 0x00200000
## Last  Load Addr = 0x00200067
## Total Size      = 0x00000068 = 104 Bytes
## Start Addr      = 0x00200000
U-Boot>

使用 u-boot 中的 go 命令执行您的程序(go 命令实际上是 call 之一)。

U-Boot> go 0x00200000
## Starting application at 0x00200000 ...
Hello, aarch64 bare-metal world!
## Application terminated, rc = 0x0
U-Boot>

就是这样,你现在应该有一个很好的标准环境来学习 aarch64 汇编语言了。

很抱歉,我已经冗长了,但我们的目标是为需要的人提供一个简约但完整的程序。

【讨论】:

以上是关于如何为 Raspberry pi 3 编译 ARMv8 代码的主要内容,如果未能解决你的问题,请参考以下文章

如何为 Raspberry Pi 编写简单的 UART Linux 设备驱动程序?

为 Raspberry Pi 选择交叉编译器

使用单声道时的 Serial.IO.Ports 问题,适用于 dotnet core 3.1 / arm / raspberry pi 4

在 ARM / Raspberry PI 上的多个内核上运行 Eigen 密集矩阵乘法时性能下降

raspberry Pi 3 --- eclipse development establishment

Raspberry Pi 上的浮点性能(ARM 架构,BCM2835)