# 在 WSL2 上 Compile Raspberry Pi 4B 的 Kernel
## Topic: [Modified OV5647 CMOS Camera](https://github.com/bluehomewu/rpi-linux/commit/c57793d39319dbc0995bcef11534594835123995)
Ref1: [Raspberry Pi Documentation](https://www.raspberrypi.com/documentation/computers/linux_kernel.html#cross-compiling-the-kernel)
Ref2: [Raspberry Pi GitHub](https://github.com/raspberrypi)
Ref3: [Applying Patches To The Linux Kernel](https://www.kernel.org/doc/html/next/process/applying-patches.html)
Cross-Compiling the Kernel
---
### 安裝必要的編譯套件 && Toolchain
#### 所需的依賴項
```shell=
$ sudo apt install git bc bison flex libssl-dev make libc6-dev libncurses5-dev -y
```
#### Toolchain
32 位元 Kernel
```shell=
$ sudo apt install crossbuild-essential-armhf -y
```
64 位元 Kernel
```shell=
$ sudo apt install crossbuild-essential-arm64 -y
```
### 下載 kernel source
```shell=
$ cd < path >
$ git clone git@github.com:raspberrypi/linux.git -b < branch name >
```
### Build Source
#### 32 位元 configs
For Raspberry Pi 1, Zero and Zero W, and Raspberry Pi Compute Module 1:
```shell=
$ cd linux
$ KERNEL=kernel
$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- bcmrpi_defconfig
```
For Raspberry Pi 2, 3, 3+ and Zero 2 W, and Raspberry Pi Compute Modules 3 and 3+:
```shell=
$ cd linux
$ KERNEL=kernel7
$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- bcm2709_defconfig
```
For Raspberry Pi 4 and 400, and Raspberry Pi Compute Module 4:
```shell=
$ cd linux
$ KERNEL=kernel7l
$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- bcm2711_defconfig
```
#### 64 位元 configs
For Raspberry Pi 3, 3+, 4, 400 and Zero 2 W, and Raspberry Pi Compute Modules 3, 3+ and 4:
```shell=
$ cd linux
$ KERNEL=kernel8
$ make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- bcm2711_defconfig
```
For Raspberry Pi 5:
```shell=
$ cd linux
$ KERNEL=kernel_2712
$ make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- bcm2712_defconfig
```
:::success
##### Note:
標準的 bcm2711_defconfig 基於的核心 (kernel8.img) 也可以在 Raspberry Pi 5 上使用。不過為了獲得最佳效能,您應該使用 kernel_2712.img,但對於需要 4KB 頁面大小的情況,則應使用 kernel8.img (kernel=kernel8.img)
:::
#### Customising the Kernel Version Using `LOCALVERSION`
除了核心配置變更之外,您可能還想調整 LOCALVERSION 以確保新核心不會收到與上游核心相同的版本字串。 這不僅表明您在 uname 的輸出中運行自己的內核,也確保 /lib/modules 中的現有模組不會被覆蓋。
為此,請更改 .config 中的以下行:
```
CONFIG_LOCALVERSION="-v8-Edward_Kernel"
```
### Build with Configs
#### For all 32-bit Builds
```shell=
$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- zImage modules dtbs
```
#### For all 64-bit Builds
:::success
#### Note:
Note the difference between Image target between 32 and 64-bit.
```shell=
$ make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- Image modules dtbs
```
:::
Installing Kernel to SDCard
---
Ref4: [Windows Mount Linux Partition in WSL 掛載 存取 Linux USB SD Card 隨身碟 EXT4](https://casparting.github.io/windows/Windows_mount_Linux_partition_wsl/)
Ref5: [編譯 替換 Windows WSL Kernel 方法 步驟](https://casparting.github.io/windows/Windows_wsl_build_kernel/)
## 使用 USBIPD 來掛載 USB Drive/ SD Card
#### 列出目前 USB bus 狀態
```powershell=
PS C:\Users\EdwardWu> usbipd list
Connected:
BUSID VID:PID DEVICE STATE
1-3 13d3:56ff Integrated Camera Not shared
2-2 03f0:028e USB 輸入裝置 Not shared
2-3 27c6:5503 Goodix fingerprint Not shared
2-4 8087:0032 Intel(R) Wireless Bluetooth(R) Not shared
3-1 0b95:1790 ASIX AX88179 USB 3.0 to Gigabit Ethernet Adapter #3 Not shared
3-3 05e3:0749 USB Mass Storage Device Not shared
```
#### Allow Share USB bus 3-3
```powershell=
PS C:\Users\EdwardWu> usbipd bind -b 3-3
PS C:\Users\EdwardWu> usbipd list
Connected:
BUSID VID:PID DEVICE STATE
1-3 13d3:56ff Integrated Camera Not shared
2-1 2109:2817 Generic USB Hub Not shared
2-2 03f0:028e USB 輸入裝置 Not shared
2-3 27c6:5503 Goodix fingerprint Not shared
2-4 8087:0032 Intel(R) Wireless Bluetooth(R) Not shared
3-1 0b95:1790 ASIX AX88179 USB 3.0 to Gigabit Ethernet Adapter #3 Not shared
3-3 05e3:0749 USB Mass Storage Device Shared
```
#### 向 WSL 轉送 usb bus 3-3 device
```powershell=
PS C:\Users\EdwardWu> usbipd attach --wsl --busid 3-3
usbipd: info: Using WSL distribution 'Ubuntu-22.04' to attach; the device will be available in all WSL 2 distributions.
usbipd: info: Using IP address 172.19.112.1 to reach the host.
```
#### 關閉 WSL
```powershell=
PS C:\Users\EdwardWu> wsl --shutdown
```
#### 列出 USB 裝置
```powershell=
PS C:\Users\EdwardWu> usbipd list
Connected:
BUSID VID:PID DEVICE STATE
1-3 13d3:56ff Integrated Camera Not shared
2-2 03f0:028e USB 輸入裝置 Not shared
2-3 27c6:5503 Goodix fingerprint Not shared
2-4 8087:0032 Intel(R) Wireless Bluetooth(R) Not shared
3-1 0b95:1790 ASIX AX88179 USB 3.0 to Gigabit Ethernet Adapter #3 Not shared
3-3 05e3:0749 USB Mass Storage Device Attached
```
#### 移除 USB bus 3-3
```powershell=
PS C:\Users\EdwardWu> usbipd detach --busid 3-3
```
## 將 Raspberry Pi 4B 的 SDCard 分割區掛載到資料夾
```shell=
$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
sda 8:0 0 389.8M 1 disk
sdb 8:16 0 3G 0 disk [SWAP]
sdc 8:32 0 256G 0 disk /mnt/wslg/distro
/
```
```shell=
$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
sda 8:0 0 389.8M 1 disk
sdb 8:16 0 3G 0 disk [SWAP]
sdc 8:32 0 256G 0 disk /mnt/wslg/distro
/
sdd 8:48 1 0B 0 disk
sde 8:64 1 59.5G 0 disk
├─sde1 8:65 1 512M 0 part
└─sde2 8:66 1 59G 0 part
```
#### 掛載分割區
:::warning
您應該根據您的設定適當調整磁碟代號,例如,如果您的 SD 卡顯示為 而 /dev/sdc 不是 /dev/sdb。
:::
```shell=
$ sudo mount /dev/sde1 ../mnt/fat32
$ sudo mount /dev/sde2 ../mnt/ext4
```
```shell=
$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
sda 8:0 0 389.8M 1 disk
sdb 8:16 0 3G 0 disk [SWAP]
sdc 8:32 0 256G 0 disk /mnt/wslg/distro
/
sdd 8:48 1 0B 0 disk
sde 8:64 1 59.5G 0 disk
├─sde1 8:65 1 512M 0 part /home/edwardwu/rpi-kernel/mnt/fat32
└─sde2 8:66 1 59G 0 part /home/edwardwu/rpi-kernel/mnt/ext4
```
#### Install the Kernel Modules
```shell=
$ sudo env PATH=$PATH make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- INSTALL_MOD_PATH=../mnt/ext4 modules_install
```
#### 備份原先的 Kernel
```shell=
$ sudo cp ../mnt/fat32/kernel8.img ../mnt/fat32/kernel8-backup.img
```
#### Copy Kernel & Device Tree blobs
```shell=
$ sudo cp arch/arm64/boot/Image ../mnt/fat32/kernel8.img
$ sudo cp arch/arm64/boot/dts/broadcom/*.dtb ../mnt/fat32/
$ sudo cp arch/arm64/boot/dts/overlays/*.dtb* ../mnt/fat32/overlays/
$ sudo cp arch/arm64/boot/dts/overlays/README ../mnt/fat32/overlays/
```
#### 移除掛載分割區
```shell=
$ sudo umount ../mnt/fat32
$ sudo umount ../mnt/ext4
```
#### 測試鏡頭
```shell=
libcamera-hello
```
#### 拍照
```shell=
libcamera-jpeg -o test.jpg
```
Build Script
---
```shell=
#!/bin/bash
# 定義 kernel tree 的路徑
LINUX_DIR="/home/edwardwu/rpi-kernel/linux"
echo "選擇要編譯的 Raspberry Pi 版本:"
echo "1. Raspberry Pi 4"
echo "2. Raspberry Pi 5"
read -p "請輸入選擇 (1 或 2): " choice
# 提問是否需要執行 make clean
read -p "是否需要執行 make clean? (y/n): " clean_choice
start_time=$(date +%s) # 記錄開始時間
case $choice in
1)
echo "正在編譯 Raspberry Pi 4 的 Kernel..."
cd $LINUX_DIR
if [ "$clean_choice" == "y" ]; then
echo "正在執行 make clean..."
make clean -j$(nproc)
fi
KERNEL=kernel8
#CONFIG_LOCALVERSION="-v8-Edward_Kernel"
make -j$(nproc) ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- bcm2711_defconfig
sed -i 's/CONFIG_LOCALVERSION="-v8"/CONFIG_LOCALVERSION="-v8-Edward_Kernel"/' .config
make -j$(nproc) ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- Image modules dtbs | tee ../build.log
cd -
;;
2)
echo "正在編譯 Raspberry Pi 5 的 Kernel..."
cd $LINUX_DIR
if [ "$clean_choice" == "y" ]; then
echo "正在執行 make clean..."
make clean -j$(nproc)
fi
KERNEL=kernel_2712
#CONFIG_LOCALVERSION="-v2712-Edward_Kernel"
make -j$(nproc) ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- bcm2712_defconfig
sed -i 's/CONFIG_LOCALVERSION="-v8-16k"/CONFIG_LOCALVERSION="-v2712-Edward_Kernel"/' .config
make -j$(nproc) ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- Image modules dtbs
cd -
;;
*)
echo "無效的選擇"
;;
esac
end_time=$(date +%s) # 記錄結束時間
elapsed=$((end_time - start_time)) # 計算總耗時
minutes=$((elapsed / 60))
seconds=$((elapsed % 60))
echo "編譯完成,總耗時: ${minutes}分鐘 ${seconds}秒"
```
Install Script
---
```shell=
#!/bin/bash
:<<comment
Reference: https://hackmd.io/9f2GysWvR5eA1Y_t56Vtmw?view#Installing-Kernel-to-SDCard
comment
# 定義掛載點目錄
MOUNT_POINT="/home/edwardwu/rpi-kernel/mnt"
# 定義 kernel tree 的路徑
LINUX_DIR="/home/edwardwu/rpi-kernel/linux"
# 顯示選單
echo "選擇要刷入的 Raspberry Pi 版本:"
echo "1. Raspberry Pi 4"
echo "2. Raspberry Pi 5"
read -p "請輸入選擇 (1 或 2): " choice
# 根據選擇設置 kernel 和 device tree blobs 的目標路徑
if [ "$choice" -eq 1 ]; then
KERNEL_IMG="kernel8.img"
DEVICE="Raspberry Pi 4"
elif [ "$choice" -eq 2 ]; then
KERNEL_IMG="kernel_2712.img"
DEVICE="Raspberry Pi 5"
else
echo "無效的選擇,請輸入 1 或 2."
exit 1
fi
echo "檢查 SD 卡是否已掛載到 WSL..."
lsblk
# 檢查是否有可掛載的 SD 卡分割區
if lsblk | grep -q 'sde'; then
echo "找到 SD 卡分割區,準備掛載..."
else
echo "未找到 SD 卡分割區,請確認 SD 卡已正確插入並重試。"
exit 1
fi
# 建立掛載目錄
# mkdir -p $MOUNT_POINT/fat32
# mkdir -p $MOUNT_POINT/ext4
# 掛載分割區
echo "掛載 FAT32 分割區到 $MOUNT_POINT/fat32"
sudo mount /dev/sde1 $MOUNT_POINT/fat32
echo "掛載 EXT4 分割區到 $MOUNT_POINT/ext4"
sudo mount /dev/sde2 $MOUNT_POINT/ext4
# 檢查掛載是否成功
mount | grep sde
start_time=$(date +%s) # 記錄開始時間
# 安裝 kernel 模組
echo "安裝 kernel 模組..."
cd $LINUX_DIR
pwd
sudo env PATH="$PATH" make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- INSTALL_MOD_PATH=$MOUNT_POINT/ext4 modules_install
cd $LINUX_DIR/../
pwd
# 複製 Kernel 和 Device Tree blobs
echo "複製 Kernel 和 Device Tree blobs..."
sudo cp $LINUX_DIR/arch/arm64/boot/Image $MOUNT_POINT/fat32/$KERNEL_IMG
sudo cp $LINUX_DIR/arch/arm64/boot/dts/broadcom/*.dtb $MOUNT_POINT/fat32/
sudo cp $LINUX_DIR/arch/arm64/boot/dts/overlays/*.dtb* $MOUNT_POINT/fat32/overlays/
sudo cp $LINUX_DIR/arch/arm64/boot/dts/overlays/README $MOUNT_POINT/fat32/overlays/
# 移除掛載
echo "移除掛載分割區..."
sudo umount $MOUNT_POINT/fat32
sudo umount $MOUNT_POINT/ext4
# 計算總耗時
end_time=$(date +%s) # 記錄結束時間
elapsed=$((end_time - start_time)) # 計算總耗時
minutes=$((elapsed / 60))
seconds=$((elapsed % 60))
echo "刷寫完畢,總耗時: ${minutes}分鐘 ${seconds}秒"
# 輸出完成訊息
echo "已經完成 $DEVICE kernel 的刷寫"
```
Finally !!
---
