先日、以下のパッチをU-Bootに投稿し、マージされました。
[U-Boot] [PATCH] armv7m: Disable D-cache when booting nommu(ARMv7M) Linux kernel
忘れないように、なぜこのパッチを投稿したかを残しておこうと思います。
前回のあらすじ
ARM Cortex-M7マイコンの乗ったSTM32F746G-discovery board上でnommuなLinux kernelを動かすために色々頑張ってます。
解決したい課題
U-Bootからnommu Linux kernelのImageを起動すると、proc-v7m.Sの以下のsvc命令を実行するところで落ちる問題がありました。
cpsie i svc #0 1: cpsid i
linux/proc-v7m.S at master · torvalds/linux · GitHub
原因の心当たり
じつはこの問題のところ、以前私が触っていたときにも問題を起こした部分です。
当時はキャッシュを無効にした状態でcpsieとsvcの間にnopを10個ほど挟むと問題が解決するので、キャッシュかパイプラインが悪さをしているのではないかと考えていました。
その後、この問題は他の方が解決し、パッチを投稿し、マージされています。
今回はこのパッチがマージされた後の話ですが、前回の問題と似通っているので、今回も多分キャッシュとかパイプラインに問題があるのではとあたりをつけました。
問題の原因
nommu Linux起動の条件
MMUの無いARMv7MアーキテクチャのCPUで動作するnommu Linuxは、起動時にいくつか満たしていなければならない条件があり、その条件は linux/head-nommu.S at master · torvalds/linux · GitHub の頭にかかれています。その記述の一部を引用します。
The requirements are: MMU = off, D-cache = off, I-cache = dont care
ここで述べられているように、nommuなARMのLinux kernelはエントリポイントの時点ではMMUがoffかつデータ(D)キャッシュがoffである必要があります(命令(I)キャッシュは不問)。
なので、U-BootなどのブートローダーからLinux Kernelのエントリポイントに分岐する際は、データキャッシュをoffにしておく必要があります。
一方、U-Bootは……
U-Bootは2017年3月頃にARMv7MアーキテクチャのCPUでcacheを有効にするパッチが投稿・マージされたようで、現在は起動時に自動でデータ及び命令キャッシュの両方が有効になります。
[U-Boot] [PATCH 0/2] add armv7m cache support
しかし、Linux kernelのエントリポイントに飛ぶ処理を担当するboot_jump_linux関数を arch/arm/lib/bootm.c
より読んでみると、ARMv7M上でLinuxを起動する場合にデータキャッシュを無効化を行っていませんでした。
解決方法
boot_jump_linux関数内にはARMv7Mアーキテクチャの場合はThumb命令を考慮してエントリポイントアドレスの下1桁を1にする処理が入っていました。なので、その部分にデータキャッシュを無効化するdcache_disable関数を追加しました。
これにより、ARMv7MアーキテクチャのCPU上でnommu Linux kernelが起動するようになりました。
投稿したパッチは既にU-Bootに取り込まれているため、Masterブランチのコードを使えば、キャッシュのあるARMv7Mマイコン上でもU-Bootを使ってLinuxを問題なく起動できるはずです。
以上です。