樹莓派(Raspberry Pi 4 Model B)編譯64位核心Kernel(64位系統)
樹莓派系統預設安裝的是ARM32位的系統,但是從樹莓派3開始是支援ARM64位系統的,官方既然不給64位系統, 那隻好我們自己來編譯了。
網上其實有很多樹莓派3B的編譯64位核心,我都試了一遍,全部啟動不了,也不是說寫得不對,只不過好像不適用於我,搞了我三四天,很愁人;所以我下面的步驟也不保證每個人都可以成功,因為每個人的情況都不一樣,造成的問題也不一樣,所以出現問題只能靠自己百度或者Google了。
而且有很多筆記只是把核心編譯為64位,但是檔案系統還是官方的32位,並不能稱為真正的64位系統,所以我後面也把根檔案系統也構建為64位的了。
筆記在記載的時候難免有遺漏的,如果有哪個步驟不太對,歡迎留言,及時修改。
如果不想這麼麻煩,想直接使用64位的系統,可以下載已經開源的64位系統:Debian-Pi-Aarch64,這個是第三方的,不是樹莓派官方提供的。
編譯環境
通過vm虛擬機器器安裝的虛擬環境Linux,如何安裝網上一搜就有了,按照步驟安裝即可。
編譯機:Ubuntu 18.04-desktop-amd64
想要編譯64位的核心,只能在64位的機器上來編譯。
交叉編譯器
通過交叉編譯器生成64位的核心(Kernel)
定義:交叉編譯器(英語:Cross compiler)是指一個在某個系統平臺下可以產生另一個系統平臺的可執行檔案的編譯器
這句話我的理解形象一點解釋就是:
-
Ubuntu 18.04-amd64:定製服裝加工工廠(某個系統平臺)
-
交叉編譯器:製作衣服的機器(編譯器)
-
linux原始碼(kernel):服裝材料(可執行檔案的原始碼)
-
樹莓派4B:人(另一個平臺)
有了以上,現在我要給人做一件衣服,那麼我需要找一個專門給人做衣服的工廠,把服裝材料給工廠後,製作衣服的機器做出來的衣服,人就可以穿了。
每個人理解的都不一樣,只要記住上面專業的定義就好了,自己怎麼理解按自己的來就可以了。
編譯核心(kernel)
就如上面定義的一樣,那四樣我們都需要先獲取到才可以製作;Ubuntu肯定先要安裝好;樹莓派當然也要準備好。
可以用普通使用者,儘量不要用root使用者來執行,等需要用到root使用者時,再切換到root使用者來執行
編譯核心前準備
- 獲取交叉編譯器並配置
下載上面連結中的 gcc-linaro-7.4.1-2019.02-x86_64_aarch64-linux-gnu.tar.xz,有可能更新了,日期和版本會變化。 或者用命令下載
$ sudo wget https://releases.linaro.org/components/toolchain/binaries/latest-7/aarch64-linux-gnu/gcc-linaro-7.4.1-2019.02-x86_64_aarch64-linux-gnu.tar.xz
複製程式碼
建立一個工作目錄,後續的操作都在工作目錄中操作
$ mkdir ~/build && cd ~/build
$ sudo apt-get install lrzsz
# 把下載好的檔案上傳並解壓
$ rz
$ sudo tar -xvf gcc-linaro-7.4.1-2019.02-x86_64_aarch64-linux-gnu.tar.xz -C /usr/src/
$ cd /usr/src/ && sudo mv gcc-linaro-7.4.1-2019.02-x86_64_aarch64-linux-gnu aarch64-linux-gnu
$ sudo vi /etc/profile
or
$ sudo vi ~/.bashrc
# 末尾新增以下內容
export ARCH_HOME=/usr/src/aarch64-linux-gnu
export PATH=$PATH:$ARCH_HOME/bin
$ source /etc/profile
or
$ source ~/.bashrc
複製程式碼
Note:如果是在普通使用者下,還需要切換到root下再配置一遍,普通使用者也需要配置
- 獲取Raspberry Kernel原始碼
raspberry現在預設的就是4.19版本,不過更高的版本也是有的,看自己下載哪個更改一下版本就可以了,Raspberry官方的github下載超級慢,我是把Raspberry Linux遷移到了國內碼雲上,這樣下載起來就很快了;有區別的就是官方更新,不會更新到我的碼雲的倉庫上,想要最新的程式碼,可以先把官方的fork到自己的github,再遷移到自己的碼雲,把連結更換成自己的就可以了,下面的命令選擇一個下載就可以了
$ cd ~/build
$ sudo apt-get install git
# 官方的github地址
$ git clone --depth=1 --branch rpi-4.19.y https://github.com/raspberrypi/linux
# 碼雲的地址
$ git clone --depth=1 --branch rpi-4.19.y https://gitee.com/nzwxl/linux
複製程式碼
- 安裝編譯環境所需的依賴
$ sudo apt-get install git bison flex libssl-dev zip libncurses-dev make
複製程式碼
libncurses-dev依賴是支援後面menuconfig的
核心(kernel)編譯開始
# 如果原始碼檔案不叫linux,可以mv 改成linux或者你想要的的名字
$ cd linux
# 在編譯之前可以先進行清除命令,以保證清潔的環境,如果在編譯的環節出錯或者操作失誤,可以執行此命令重新開始。
$ make distclean
# 編譯.config,ARCH要配置成arm64,如果不配置則預設為開發機的x86了,CROSS_COMPILE指定編譯器
# bcm2711_defconfig在 arch/arm64/configs/bcm2711_defconfig,它會自己根據Makefile自己去找這個檔案
$ make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- bcm2711_defconfig
# 在當前的.config基礎上開始裁剪核心,如果沒有要裁剪的按ESC兩次退出即可,主要是我也沒太瞭解,等我瞭解了再記
$ make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- menuconfig
# 開始編譯核心,引數-j5的意思是 使用多處理器同時編譯核心,數字最大為:cpu的核數 × 1.5,可自行修改
$ make -j5 ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu-
複製程式碼
中間不報錯的話,大概會在1個小時左右,會在目錄 arch/arm64/boot 中生成 Image 二進位制核心檔案;如果製作的是32為核心,會在 arch/arm/boot 生成zImage 二進位制核心;同時會在linux目錄中生成最原始的核心檔案vmlimux。
vmlinunx:最原始的linux核心檔案。
zImage: 經過壓縮和去掉除錯資訊的可載入二進位制核心檔案。
Image:沒有經過壓縮的可載入二進位制核心檔案。
有關更多關於核心檔案可Google。
安裝kernel modules
這個modules在後面的根檔案系統(rootfs)中用的到,先安裝到 ~/build 工作目錄中,記得把 [user] 替換為自己的使用者名稱
$ cd ~/build/linux
# 切換到root使用者下
$ su
$ make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- INSTALL_MOD_PATH=/home/[user]/build/ modules_install
$ su [user]
複製程式碼
樹梅派boot檔案
因為樹莓派官方的 bootloader 是不開源的,但是提供了可以使用的boot目錄下所有的東西,同樣的我因為網速的原因下載太慢,遷移到了碼雲上。
$ cd ~/build
$ git clone --depth=1 https://github.com/raspberrypi/firmware/
or
$ git clone --depth=1 https://gitee.com/nzwxl/firmware/
# firmware/boot 下就是需要的檔案了
$ ls firmware/boot
複製程式碼
製作ARM64架構的rootfs
如何製作ARM64的rootfs我在另一篇筆記中記錄了,到此步驟可以繼續按照那篇筆記順序操作,等rootfs製作完,回到此筆記與下一個步驟銜接
kernel、uboot、rootfs打包進映象
製作映象檔案
- 建立一個大小為 1000M 的根檔案系統映像檔案,然後對映像檔案分割槽
經燒錄後顯示,1000M的話已經使用了90%,所以要是有許多要做的事情,或者上傳一些東西的話,最好建立個比較大一點的映像檔案
$ cd ~/build
$ fallocate -l 1000M rootfs.img
# 分割槽
$ fdisk rootfs.img
a.輸入o。這將清除映像檔案上的任何分割槽。
b.鍵入p以列出分割槽。應該沒有分割槽。
c.鍵入n,然後p為primary,1表示驅動器上的第一個分割槽,按ENTER接受預設的第一個扇區,然後為最後一個扇區鍵入+ 100M。
d.鍵入t,然後c將第一個分割槽設定為鍵入W95 FAT32(LBA)。
e.鍵入n,然後p表示主驅動器,2表示驅動器上的第二個分割槽,然後按兩次ENTER鍵接受預設的第一個和最後一個扇區。
f.寫入分割槽表並鍵入w退出。
# 可通過命令檢視設定好的分割槽
$ fdisk -l rootfs.img
複製程式碼
- 使用kpartx掛載映象到loopX
在linux中,如果映像檔案(.img)含有分割槽表的話,使用mount是掛在不上的;可以使用kpartx掛載; X是你顯示的數字,Y也是數字,每個人不一定相同,第一個 loopXpY 是上面分割槽後的第一個分割槽,第二個就是第二個分割槽
$ sudo apt-get install kpartx
$ sudo kpartx -av rootfs.img
add map loopXpY (254:0): 0 204800 linear 7:0 2048
add map loopXpY (254:1): 0 407552 linear 7:0 206848
# 這兩個裝置可以在 /dev/mapper/ 目錄中看到
$ ls /dev/mapper/
複製程式碼
- 格式化分割槽並指定分割槽LABEL名字
$ sudo mkfs.vfat -n BOOT /dev/mapper/loop5p1
$ sudo mkfs.ext4 -F -L ROOTFS -O "^has_journal" /dev/mapper/loop5p2
# 第一個命令中的-n 引數就是指定LABEL,可以通過 man mkfs.vfat 檢視引數詳情
# 第二個命令的 -F 是強制的意思(理解的不對可以糾正我),-L 指定LABEL 同樣可以通過man mkfs.ext4 檢視引數詳情
複製程式碼
- 建立掛載點並掛載
經過格式化分割槽後,現在我們可以掛載loopXpY裝置到檔案
$ sudo mkdir {/mnt/loopXp1,/mnt/loopXp2}
$ sudo mount /dev/mapper/loop5p1 /mnt/loopXp1
$ sudo mount /dev/mapper/loop5p2 /mnt/loopXp2
複製程式碼
複製核心和boot所需檔案
$ cd ~/build
# 複製boot所需檔案
$ sudo cp -r firmware/boot/* /mnt/loopXp1/
$ sudo cp linux/arch/arm64/boot/dts/broadcom/*.dtb /mnt/loopXp1
$ sudo cp linux/arch/arm64/boot/dts/overlays/*.dtb* /mnt/loopXp1/overlays/
$ sudo cp linux/arch/arm64/boot/dts/overlays/README /mnt/loopXp1/overlays/
# 複製核心
$ sudo cp linux/arch/arm64/boot/Image /mnt/loopXp1/kernel8.img
複製程式碼
編寫cmdline.txt和 config.txt
編寫cmdline.txt
# 新增內容並儲存退出
$ sudo vim /mnt/loopXp1/cmdline.txt
console=serial0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 rw rootwait fsck.repair=yes
複製程式碼
- console=serial0,115200:串列埠使用哪個裝置,以及傳輸速率
- console=tty1:控制檯輸出使用tty1裝置
- root=/dev/mmcblk0p2:將記憶體卡第二分割槽設定為根分割槽
- rootfstype=ext4:根分割槽型別 f2fs應更換為f2fs
- rw:可寫掛載跟分割槽
- rootwait:等待核心識別根分割槽裝置後再掛載
- sck.repair=yes:啟動時自動檢查修復檔案系統錯誤
編寫config.txt
# 新增內容並儲存退出
$ sudo vim /mnt/loopXp1/config.txt
# 以64位讀取核心
arm_64bit=1
# 想要以ARMV8的模式啟動,設定此選項
arm_control=0x200
# 核心的名字
kernel=kernel8.img
# u-boot進行引導kernel時延遲幾秒
boot_delay=1
# 關閉藍芽功能
# See /boot/overlays/README for all available options
dtoverlay=disable-bt
# 開啟音訊snd_bcm2835
dtparam=audio=on
複製程式碼
同步rootfs進映象第二分割槽
$ sudo apt-get install rsync
$ cd ~/build/linux-rootfs/
# 開始同步
$ sudo rsync -HPavz -q ./ /mnt/loopXp2
複製程式碼
rsync引數詳解: rsync命令
編寫fstab檔案
如果想要第一分割槽中的boot目錄在系統啟動後顯示檔案,需要在 /etc/fstab 中新增以下內容:
$ sudo vim /mnt/loopXp2/etc/fstab
<file system> <mount point> <type> <options> <dump> <pass>
LABEL=BOOT /boot vfat defaults 0 1
複製程式碼
- file system: 可以是實際分割槽名,也可以是實際分割槽的卷標(Lable),卷標名上面已經規定過了
- mount point: 是掛載點
- type: 為此分割槽的檔案系統型別,vfat位fat32的型別應該是
- options: 是掛載的選項,用於設定掛載的引數,常見的有以下引數
- defaults: rw,suid,dev,exec,auto,nouser,and async.
- auto: 系統自動掛載,fstab預設就是這個選項
- noauto 開機不自動掛載
- nouser 只有超級使用者可以掛載
- ro 按只讀許可權掛載
- rw 按可讀可寫許可權掛載
- user 任何使用者都可以掛載
- dump: 是備份設定 當其值設定為1時,將允許dump備份程式備份;設定為0時,忽略備份操作;
- pass: 是fsck磁碟檢查設定; 其值是一個順序。當其值為0時,永遠不檢查;而 / 根目錄分割槽永遠都為1。其它分割槽從2開始,數字越小越先檢查,如果兩個分割槽的數字相同,則同時檢查。
安裝核心模組
因為在編譯kernel時已經把modules安裝到了工作目錄build中了,直接複製到第二分割槽中就可以了,如果不放心,可以用安裝modules的命令安裝到第二分割槽下,更改下路徑就可以了。
$ cd ~/build
$ sudo cp -r lib/modules/ /mnt/loopXp2/lib/
複製程式碼
解除安裝燒錄IMG檔案到SD卡
$ cd ~/build
$ sync
$ sudo umount /mnt/loopXp1/
$ sudo umount /mnt/loopXp2/
$ sudo kpartx -dv rootfs.img
複製程式碼
把 rootfs.img 下載到windowns下 燒錄到SD卡中,燒錄SD卡的方式可參考:
啟動Raspberry後通過命令檢視核心版本為64位