2018年8月13日

如何編譯 RPi kernel

以下紀錄如何編譯 Raspberry Pi Kernel

查詢 RPi 上安裝的 kernel 版本號碼

$ uname -a
Linux raspberrypi 4.14.34-v7+ #1110 SMP Mon Apr 16 15:18:51 BST 2018 armv7l GNU/Linux

找一台 x86 linux 電腦,以 cross-compile 方式重新編譯 RPi kernel,雖然可以直接在 RPi 編譯,但速度會很慢,因此還是選擇用 cross-compile 方式編譯。

RPi kernel 存放在 git repository 裡面

cd
mkdir raspberry
cd raspberry

確認有安裝 git, 並更新一些套件(需要安裝nss 相關和更新curl)

yum update git
yum update nss nss-util nspr
yum update curl

下載 kernel source

git clone https://github.com/raspberrypi/linux.git

下載 cross-compilers tools

git clone https://github.com/raspberrypi/tools

使用 tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian,設定環境變數 CCPREFIX

export CCPREFIX=/root/raspberry/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin/arm-linux-gnueabihf-

${CCPREFIX}gcc -v

在 GitHub 上面的 kernel 有許多不同的 branch,請選擇你想要使用的 branch 來使用。

cd linux
git branch -a

目前版本為

* rpi-4.14.y
  remotes/origin/HEAD -> origin/rpi-4.14.y

由 RPi 取得目前的 kernel 設定,因為 RPi 上沒有 config.gz,用以下指令產生 /proc/config.gz

sudo modprobe configs

將 /proc/config.gz 複製到要編譯 kernel 的機器上的 /root/raspberry/linux 目錄中

cd /root/raspberry/linux
scp pi@192.168.1.15:/proc/config.gz . 
gunzip -c config.gz > .config

用以下指令產生新的 kernel configuration,如果遇到新的功能,就會問你要不要支援

ARCH=arm CROSS_COMPILE=${CCPREFIX} make oldconfig

reset .config 裡面的 debug symbols,Enable the ‘DEBUGINFO’ option and don’t enable the DEBUGINFO_REDUCED option.

grep -v DEBUG_INFO < .config > newconfig 
mv newconfig .config 
ARCH=arm CROSS_COMPILE=${CCPREFIX} make oldconfig

以 menuconfig 微調設定,調整 kernel modules support。

make -j4 ARCH=arm CROSS_COMPILE=${CCPREFIX} menuconfig

編譯 kernel,如果是 multi-core cpu,可加上 -j<amount of cores> 加速編譯

ARCH=arm CROSS_COMPILE=${CCPREFIX} make

如果編譯過程中,有發生 compile error,打開錯誤的 source code,在發生錯誤的 function 前面加上

#pragma GCC optimize("-g0")

編譯完成後,必須檢查 symbols,用以下指令,查看 initutsns.name.release 的值

${CCPREFIX}gdb vmlinux 
print init_uts_ns.name.release

確認 kernel 有包含 symbols 後,將 RPi 需要的 modules 放在 modules 目錄

ARCH=arm CROSS_COMPILE=${CCPREFIX} INSTALL_MOD_PATH=../modules make modules_install

建立 uncompressed kernel image,並放到 RPi 的 tmp 目錄中

cd <raspberry pi downloads>/tools/mkimage 
./imagetool-uncompressed.py ../../linux/arch/arm/boot/zImage
scp kernel.img pi@raspberrypi:/tmp

將 modules 目錄,壓縮後,傳送到 RPi 的 tmp 目錄中

cd <raspberry pi downloads>/tools/modules 
tar czf modules.tgz * 
scp modules.tgz pi@raspberrypi:/tmp

最後 ssh 到 RPi,安裝新的 kernel 及 modules

cd / 
sudo mv /tmp/kernel.img /boot/ 
sudo tar xzf /tmp/modules.tgz 
rm /tmp/modules.tgz

reboot RPi

sudo shutdown -r now

以 uname 檢查是否使用了新版的 kernel

uname -r

如果要 debug kernel ,可參考 Preparing Raspberry PI for JTAG Debugging 的說明

References

https://sysprogs.com/VisualKernel/tutorials/raspberry/buildkernel/

https://blog.gtwang.org/iot/raspberry-pi-compile-linux-kernel/

https://www.raspberrypi.com.tw/528/compiling-kernel-for-raspberry-pi/

https://coldnew.github.io/f5873b3f/