From Fedora Project Wiki
No edit summary
No edit summary
Line 137: Line 137:


s64ilp32+u32ilp32  
s64ilp32+u32ilp32  
[[File:Rv64ilp32 free|thumb]]
[[File:Rv64ilp32 free.png|thumb]]

Revision as of 15:59, 4 March 2024

为什么使用32位Linux?

使用32位Linux内核的目的是为了减少内存占用并满足小容量DDR和缓存的要求(例如,64/128MB SIP SoC)。

ilp32的long和指针大小仅为lp64的一半(rv64默认的abi - long和指针都是64位)。 这种数据类型上的显著差异导致了不同的内存和缓存占用成本。 在相同的128MB qemu系统环境中,这里是s32ilp32、s64ilp32和s64lp64之间的比较测量:

根文件系统:

  • 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+u64lp64

Rv64 Free.png

s64ilp32+u32ilp32

Rv64ilp32 free.png