From Fedora Project Wiki

什么是rv64ilp32?

AIoT技术进步推动了对微控制器(MCU)和应用处理器(AP)更高计算能力的需求,凸显了32位架构的局限。内存访问和原子操作指令难以满足现代系统要求,催生了向64位架构的转型。此转型面临挑战:32位软件在64位硬件上运行时,指针与寄存器宽度不匹配影响性能。为应对这一问题,阿里巴巴-达摩院-玄铁团队提出了松弛扩展寻址模式(Relaxed-Addressing Mode),并与中科院软件所-PLCT实验室联合发布了业界首款RISC-V新32位产品级开源工具链(rv64ilp32 toolchain),专为固件、RTOS 和 Linux内核等设计,优化了性能与成本。新32位Linux内核在性能上大幅超越传统方案,ebpf性能提升300%,iperf-tcp提升17%。 Fedora 社区针对 RISC-V 拥有丰富的软件生态,与传统的64位方案相比,新32位构建能够节省39%的内存。这一优势使 Fedora RISC-V 能在嵌入式领域有更广泛的应用。正因为看到了新32位的潜力,在PLCT实验室的协助下,我们尝试了新32位 Fedora Remix移植,目前已可以运行在嘉楠 k230 开发板上:

K230.jpg

Quick Start

CanMV-K230 Fedora 固件下载地址

[Release 2024.03.03-128m · ruyisdk/mkimg-k230-rv64ilp32 (github.com)](https://github.com/ruyisdk/mkimg-k230-rv64ilp32/releases/tag/2024.03.03-128m)

其中 rv64-canmv-rv64 (s64lp64+u64lp64) rv32-canmv-rv64 (s64lp64+u32ilp32) rv32-canmv-rv64ilp32 (s64ilp64 + u32ilp32) 以下是各个版本的内存开销对比 (相比传统64位 k230,新32位Linux避免39%的内存开销): s64lp64 + u64lp64: free -h

    total used free shared buff/cache available

Mem: 107Mi 39Mi 15Mi 1.0Mi 52Mi 53Mi

s64lp64 + u32ilp32: free -h

    total used free shared buff/cache available

Mem: 107Mi 33Mi 31Mi 1.0Mi 41Mi 67Mi

s64ilp32 + u32ilp32: free -h

    total used free shared buff/cache available

Mem: 108Mi 28Mi 41Mi 1.0Mi 38Mi 73Mi

(used: 39MB -> 33MB -> 28MB, Prevent 39% memory waste in s64ilp32 + u32ilp32 固件烧录 首先解压zst文件 zstd -d k230-sdcard-fedora_rv32-canmv-rv64ilp32.img.zst 使用 lsblk 查看TF卡设备路径,假设为/dev/sdb,执行以下指令烧录(谨慎) wipefs -a /dev/sdb dd if=k230-sdcard-fedora_rv32-canmv-rv64ilp32.img of=/dev/sdb bs=1M status=progress sync eject Linux 内核编译: 访问 https://github.com/ruyisdk/riscv-gnu-toolchain-rv64ilp32 获取工具链。

获取 Linux 内核: git clone https://github.com/ruyisdk/k230-rv64ilp32-linux-kernel.git -b k230-6.6-ilp32-128M --depth=1 cd k230-rv64ilp32-linux-kernel 构建传统 s64lp64 Linux 内核: make ARCH=riscv CROSS_COMPILE=<YOUR PATH>/riscv/bin/riscv64-unknown-elf- k230_evb_linux_enable_vector_defconfig all 构建新32位Linux 内核,只需在以上命令附上 64ilp64.config 配置即可,示例如下: make ARCH=riscv CROSS_COMPILE=<YOUR PATH>/riscv/bin/riscv64-unknown-elf- k230_evb_linux_enable_vector_defconfig 64ilp32.config all



根文件系统:

  • u32ilp32 - 使用相同的32位用户空间rootfs.ext2(UXL=32)二进制文件,来自buildroot 2023.02-rc3,qemu_riscv32_virt_defconfig。

Linux:

要启用64ilp32十分简单,只需要在编译内核的时候make xxxdefconfig的同时make xxxdefconfig 64ilp32.config就可以,并无其他代码需求。 s64ilp32 内核编译非常简单,在 s64lp64 内核编译的基础上加上 64ilp32.config 即可 s64lp64: make ARCH=riscv CROSS_COMPILE=riscv-unknow-elf- defconfig all s64ilp32: make ARCH=riscv CROSS_COMPILE=riscv-unknow-elf- defconfig 64ilp32.config all

开发正常按 s64lp64 即可,最后轻松切换到 s64ilp32 上。

  • s32ilp32 - Linux version 6.3.0-rc1 (124MB) rv32_defconfig:
           $(Q)$(MAKE) -f $(srctree)/Makefile defconfig 32-bit.config
  • s64lp64 - Linux version 6.3.0-rc1 (126MB) defconfig:
           $(Q)$(MAKE) -f $(srctree)/Makefile defconfig
  • s64ilp32 - Linux version 6.3.0-rc1 (126MB) rv64ilp32_defconfig:
          $(Q)$(MAKE) -f $(srctree)/Makefile defconfig 64ilp32.config

Opensbi:

  • m64lp64 - (2MB) OpenSBI v1.2-80-g4b28afc98bbe
  • m32ilp32 - (4MB) OpenSBI v1.2-80-g4b28afc98bbe


64ilp32.png


为什么选择s64ilp32?

当前的RISC-V具有RVA20S64、RVA22S64和 RVA23S64 配置文件,但不存在RVA**S32配置文件,也没有进行中的计划。这意味着当供应商想要生产一个32位的s模式RISC-V应用处理器时,他们没有可遵循的模型。因此,许多便宜的riscv芯片已经出现,但遵循RVA2xS64配置文件,例如全志D1/D1s/F133、SOPHGO CV1800B/SG2000、嘉楠科技Kendryte K230 和Bouffalo Lab BL808,这些通常对标cortex a7/a35/a53产品场景。D1、CV1800B和BL808不支持UXL=32(32位U模式),因此它们需要一个新的u64ilp32用户空间ABI,目前还没有软件生态系统。因此,s64ilp32的首次登陆将是在嘉楠科技Kendryte k230上,该芯片具有c908,支持rv64gcv和兼容用户模式(sstatus.uxl=32/64),能够支持现有的rv32用户空间软件生态系统。

发明s64ilp32的另一个原因是性能好处和简化64位CPU硬件设计(与s32ilp32相比)。

为什么s64ilp32性能更好?

一般来说,我们应该在64位处理器上构建一个32位硬件s模式来运行32位Linux(例如在cortex-a53上运行Linux-arm32)。 或者只在64位机器上使用旧的32ilp32-abi(例如mips SYS_SUPPORTS_32BIT_KERNEL)。这些不能重用64位硬件的性能相关特性和指令,例如64位ALU、AMO和LD/SD,这会在许多Linux功能上造成显著的性能差距:

- memcpy/memset/strcmp(s64ilp32的指令计数是s32ilp32的一半,加载/存储指令的带宽是s32ilp32的两倍。)
- ebpf JIT是一个64位虚拟ISA,不适合映射到s32ilp32。
- Atomic64(s64ilp32具有与s64lp64完全相同的原生指令映射,但s32ilp32只使用generic_atomic64,这是一个折衷和有限的软件解决方案。)
- 支持"long long"类型的64位原生算术指令
- 支持slub的cmxchg_double(第二个支持该功能的32位Linux,第一个是i386。)

... 与用户空间生态系统相比,32位Linux内核更迫切地需要64ilp32来提高性能,因为Linux内核不能利用ISA的浮点/向量特性。

让我们从另一个角度看性能(s64ilp32对比s64lp64)。如前所述,ilp32的指针大小是lp64的一半,它减小了关键数据结构(例如,页面、列表等)的大小。这意味着使用ilp32的缓存可以在相同的缓存容量下包含lp64的两倍数据,这是32位的天生优势。

为什么 s64ilp32 可以简化 CPU 设计?

s64ilp32简化了CPU设计的原因主要有两个方面。首先,与传统的32位模式相比,s64ilp32模式允许RISC-V硬件在64位机器模式(MXL=SXL=64)下运行,同时支持32位用户空间(UXL=32)。这样,CPU厂商就无需实现专门的32位机器模式和管理模式,从而简化了硬件的设计和实现。传统上,例如在ARM架构中,为了支持32位Linux,需要实现32位的EL1/EL2/EL3硬件模式,这增加了设计和验证的复杂度。

其次,s64ilp32模式利用了64位硬件的性能优势,同时保持了与现有的32位软件生态系统的兼容性。这种模式下,虽然处理器在硬件层面上运行在64位模式,但是通过支持32位的用户空间ABI(应用程序二进制接口),使得现有的基于RV32的软件能够无缝运行。这种方法避免了混合32位CSR(控制和状态寄存器)功能到64位硬件中的复杂性,同时也保留了64位处理器的性能优势。

s64ilp32如何工作?

s64ilp32模式从硬件角度看与s64lp64兼容模式相同,即MXL=SXL=64加上UXL=32。由于s64ilp32使用Linux的CONFIG_32BIT配置,它仅支持u32ilp32 abi用户空间,即当前标准的rv32软件生态系统,目前还不能与u64lp64 abi兼容(这被认为是复杂且无用的)。但是,未来可能支持u64ilp32;现在,s64ilp32依赖于硬件的UXL=32特性。

对于地址变量的生成,64ilp32 gcc仍然使用带符号扩展的lw和auipc指令,因为插入用于屏蔽最高32位的零扩展指令会导致代码大小和性能问题。因此,通过操作系统方法来解决这个问题:

- 当satp=bare且启动物理地址小于2GB时,不存在带符号扩展的地址问题。
- 当satp=bare且启动物理地址大于2GB时,需要类似zjpm的硬件扩展来屏蔽高32位。(幸运的是,所有现有的SoC(D1/D1s/F133, CV1800B, k230, BL808)的启动物理地址都小于2GB。)
- 当satp=sv39时,通过双重映射使带符号扩展的虚拟地址与零扩展的虚拟地址相同,解决了地址扩展问题。

这种方法简化了对64位硬件的设计和实现,同时为32位软件提供了在64位硬件上运行的能力,无需牺牲性能。


如何运行 s64ilp32?

GNU 工具链

请使用Fedora中的 riscv64-linux-gnu- 工具链 

Opensbi

git clone https://github.com/riscv-software-src/opensbi.git
CROSS_COMPILE=riscv64-linux-gnu- make PLATFORM=generic

Linux kernel

git clone https://github.com/guoren83/linux.git -b s64ilp32
cd linux
make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- rv64ilp32_defconfig
make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- menuconfig
make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- all

Fedora Rootfs

WIP


Qemu

git clone https://github.com/plctlab/plct-qemu.git -b plct-s64ilp32-dev
cd plct-qemu
mkdir build
cd build
../qemu/configure --target-list="riscv64-softmmu riscv32-softmmu"
make

运行

./qemu-system-riscv64 -cpu rv64 -M virt -m 128m -nographic -bios fw_dynamic.bin -kernel Image -drive file=rootfs.ext2,format=raw,id=hd0 -device virtio-blk-device,drive=hd0 -append "rootwait root=/dev/vda ro console=ttyS0 earlycon=sbi" -netdev user,id=net0 -device virtio-net-device,netdev=net0


这是基于当前默认配置(未做任何修改)的大致测量结果,32位(s32ilp32、s64ilp32)比64位(s64lp64)节省了超过17%的内存。 但s32ilp32和s64ilp32的内存占用相似(大约只有0.33%的差异),这意味着s64ilp32很有可能在64位机器上替代s32ilp32。

在 K230 的测试中

 - ebpf 测试对比,性能提升 300%+
 - Fedora 在 k230 上运行新32位,并且内存开销降低 39%,以下是数据:
             s64lp64+u64lp64 -> s64lp64+u32ilp32 -> s64ilp32+u32ilp32 
used memory: 39MB            -> 33MB             -> 28MB

s64lp64+u32ilp32 Rv64 Free.png

s64ilp32+u32ilp32 Rv64ilp32 free.png