はじめに
Raspberry Pi 5 については、今週の日曜部のブログに書きました。
その後も継続して Raspberry Pi 5 に関して、色々と調べています。ソースは、Raspberry Pi 用の linux kernel です。
今回は、PSCI についてです。
PSCI とは?
PSCI はARMが定義した省エネインターフェースです。
64ビットLinuxでは、PSCIをDevice Tree Sourceファイル内のCPUノードのenable-methodパラメータに設定するものとしています。
Raspberry Pi 4 では、arch/arm/boot/dts/bcm2711.dtsi に cpu のところを見てみると、enable-method = "spin-table" でした。
cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-a72"; reg = <0>; enable-method = "spin-table"; cpu-release-addr = <0x0 0x000000d8>; d-cache-size = <0x8000>; d-cache-line-size = <64>; d-cache-sets = <256>; // 32KiB(size)/64(line-size)=512ways/2-way set i-cache-size = <0xc000>; i-cache-line-size = <64>; i-cache-sets = <256>; // 48KiB(size)/64(line-size)=768ways/3-way set next-level-cache = <&l2>; };
一方、Rasberry Pi 5では、arch/arm/boot/dts/bcm2711.dtsi に cpu のところを見てみると、enable-method = "psci" です。
cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-a76"; reg = <0x000>; enable-method = "psci"; next-level-cache = <&l2_cache>; };
Raspberry Pi 4/5 のブートシーケンス
Raspberry Pi 4 では、
- 1st Level Boot Loader : 内部ROM (GPUが内部ROMを実行が FAT32フォーマットのSDカード内から bootcode.bin を GPU の L2キャッシュにロードする)
- 2nd Level Boot Loader : bootcode.bin (GPUがbootcode.binを実行し、SDRAMを初期化し、SDカード内のstart4.elfをロードする)
- 3rd Level Boot Loader : start4.elf (GPUがstart.elfを実行し、SDカード内のkernel8.img をロードする。dtbファイルもSDRAMにロードする)
- Linux Kernel : kernel8.img (GPUがCPUコアのリセットを解除し、CPUがkernel8.imgを実行して、Linux Kernelを起動する)
です。1st から 3rd までは、GPUが実行しています。
Raspberry Pi 5 では、Raspberry Pi 4と同じように 下記のように、Linux Kernel を起動しているのだと思います。
- 1st Level Boot Loader : 内部ROM (GPUが内部ROMを実行が FAT32フォーマットのSDカード内から bootcode.bin を GPU の L2キャッシュにロードする)
- 2nd Level Boot Loader : bootcode.bin (GPUがbootcode.binを実行し、SDRAMを初期化し、SDカード内のstart4.elfをロードする)
- 3rd Level Boot Loader : start4.elf (GPUがstart.elfを実行し、SDカード内のkernel_2712.img をロードする。dtbファイルもSDRAMにロードする)
- Linux Kernel : kernel8.img (GPUがCPUコアのリセットを解除し、CPUがkernel_2712.imgを実行して、Linux Kernelを起動する)
Rasberry Pi 4 との違いは、Linux Kernel が kernel8.img から kernel_2712.img になりました。
一般的なArm64なSoCのブートシーケンス
一般的な Arm64なCPUコアを搭載しているSoCでのブートシーケンスは、
- 1st Level Boot Loader : 内部ROM
- 2nd Level Boot Loader : Arm Trusted Firmware
- 3rd Level Boot Loader : Arm Trusted Firmware runtime + UBoot
- Linux Kernel
のようになっています。Linux Kernel を起動する前に、Arm Trusted Firmware という runtime をロードします。
Raspberry Pi 5のブートシーケンスでは、Arm Trusted Firmware runtime をロードしているところはありません。
では、Arm Trusted Firmware runtime はどこでロードするのでしょうか?
ヒントは、arch/arm/boot/dts/bcm2712.dtsi の rmem のところに下記のようなものがありました。
rmem: reserved-memory { #address-cells = <2>; #size-cells = <1>; ranges; atf@0 { reg = <0x0 0x0 0x80000>; no-map; };
reserved-memory (Linux Kernelでは使わないようにする)の領域に、atf@0 というエントリがあります。アドレス 0x0 から 0x80000 (512KB) を atf として予約しています。
rmem は、arch/arm/boot/dts/bcm2712-rpi.dtsi に下記のように追記されています。
&rmem { /* * RPi4's co-processor will copy the board's bootloader configuration * into memory for the OS to consume. It'll also update this node with * its placement information. */ blconfig: nvram@0 { compatible = "raspberrypi,bootloader-config", "nvmem-rmem"; #address-cells = <1>; #size-cells = <1>; reg = <0x0 0x0 0x0>; no-map; status = "disabled"; }; };
raspberrypi,bootloader-config に対しては何も出てこなかったのですが、nvmem-rmem については、drivers/nvmem/rmem.c がありました。
rmem_probe関数が下記のようになっています。
static int rmem_probe(struct platform_device *pdev) { struct nvmem_config config = { }; struct device *dev = &pdev->dev; struct reserved_mem *mem; struct rmem *priv; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; priv->dev = dev; mem = of_reserved_mem_lookup(dev->of_node); if (!mem) { dev_err(dev, "Failed to lookup reserved memory\n"); return -EINVAL; } priv->mem = mem; config.dev = dev; config.priv = priv; config.name = "rmem"; config.id = NVMEM_DEVID_AUTO; config.size = mem->size; config.reg_read = rmem_read; return PTR_ERR_OR_ZERO(devm_nvmem_register(dev, &config)); }
これは妄想ですが、nvmemからmemory(0x0)に 512KB コピーしているのではないでしょうか?
おわりに
Linux Kernelが起動中に、GPU が nvmem から memory (DRAM) に Arm Trusted Firmware BL31 をコピーすることで、Raspberry Pi 4 の ブートシーケンスと同じでも PSCI をサポートできるようにしているのでは?ということが分かりました。
本当かな?