Debian 支援三個不同版本的 ARM 架構,分別是
armel - 沒有 FPU 的 ARM CPU
armhf - 有 FPU,可以硬體執行浮點運算的 ARM CPU
arm64 - 64 位元的 ARM CPU
以本學期的課程來說,我們以 armhf 架構為主來進行工具鏈 (toolchain) 的安裝,這些工具鏈一樣是用來編譯 ARM 版本的 Linux 核心以及其它應用程式,是建構嵌入式系統的基本工具。
1. 安裝
請以 root 權限安裝底下套件:
gcc-arm-linux-gnueabihf
cpp-arm-linux-gnueabihf
g++-arm-linux-gnueabihf
安裝完畢後可以測試這三個套件的可執行檔,指令如下:
$arm-linux-gnueabihf-gcc -v
$arm-linux-gnueabihf-cpp -v
$arm-linux-gnueabihf-g++ -v
上述的輸出有一個非常重要的重點在此:
Using built-in specs.
COLLECT_GCC=arm-linux-gnueabihf-g++
COLLECT_LTO_WRAPPER=/usr/lib/gcc-cross/arm-linux-gnueabihf/6/lto-wrapper
Target: arm-linux-gnueabihf
其中的 Target: arm-linux-gnueabihf 這行告訴我們這是針對 armhf 平台所開發的編譯器。如果你用之前教的 gcc -v 會看到其內容如下:
Target: x86_64-linux-gnu
這表示其編譯目標平台是 x86_64。
2. 測試 armhf 編譯器
2.1 建立 hello.c
請建立 hello.c,其內容如下:
#include <stdio.h>
void main(void)
{
printf("Hello World\n");
}
2.2 編譯 hello.c 為 armhf 之可執行檔
$ arm-linux-gnueabihf-gcc hello.c -o hello.arm
此時會出現 hello.arm 這個可執行檔,其檔案資訊如下:
$ file hello.arm
hello.arm: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamicall
y linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 3.2.0, BuildID[sha
1]=155090b58f9384c7e128b74e743a7993155658fc, not stripped
這個可執行檔是 arm 32 位元版本的可執行檔,從 X86 平台編譯出 ARM 平台可執行檔的流程稱為 cross compile (交叉編譯器)。
此時如果我們要執行 hello.arm 這個程式的話,我們會看到底下輸出:
$ ./hello.arm
bash: ./hello.arm: 無法執行二進位檔案: 可執行檔格式錯誤
(或是英文顯示)
./hello.arm
bash: ./hello.arm: cannot execute binary file: Exec format error
這表示我們的平台目前沒有支援 ARM 32 的可執行檔,必須另外再進行處理才可以支援。
2.3 將 Debian 新增 armhf 架構
Debian 支援硬體架構:
https://wiki.debian.org/SupportedArchitectures
首先我們要觀察目前系統所支援的外掛架構 (非原生 x86_64 架構) 有哪些,請執行:
# dpkg --print-foreign-architectures
理論上不會有任何輸出,因為我們還沒加入 armhf 架構的支援。在大一 Linux 課程中有教大家如何加入 i386 架構的支援,其說明在 157 頁第六章。
要新增 armhf 架構的話,請以 root 權限執行:
# dpkg --add-architecture armhf
此時再執行 dpkg --print-foreign-architectures 指令時會看到有新增一個 armhf
架構,如底下所示:
# dpkg --print-foreign-architectures
armhf
接下來要安裝支援的軟體,請執行
# apt-get update
# apt-get upgrade
# apt install qemu-system:armhf qemu-user:armhf qemu-user-static
安裝所需要的軟體,然後就可以準備執行 hello.arm 這個可執行檔。
2.4 測試 armhf 可執行檔
要在 X86_64 系統中執行 arm 的可執行檔,請執行底下指令:
$ qemu-arm ./hello.arm
Hello World
3. 編 ARM 版 Linux 核心
3.1 下載
請在家目錄建立 ~/qemu_image/arm 目錄,然後在底下建立 kernel 目錄並將 linux-4.4.268.tar.xz 這個檔案解壓縮並放入此目錄,指令如下:
$ mkdir -p ~/qemu_image/arm/kenel
$ tar xfva linux-4.4.268.tar.xz -C ~/qemu_image/arm/kenel
此時會出現一個 linux-4.4.268 目錄,接下來要設定編譯參數。
3.3 設定核心編譯參數 (依照預設值即可)
3.3.1 虛擬 ARM 平台介紹
核心編譯與 ARM 平台有密切的關係,如果沒有編對平台則無法開機,我們這學期所使用的虛擬 ARM 平台為 qemu-system-arm 已支援的平台,要查詢支援平台的指令如下:
$ qemu-system-arm -M ?
其輸出中有一行:
vexpress-a9
這是指 Versatile Express 平台,其 CPU 為 Cortex A9。
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.subset.boards.express/index.html
我們這學期以此虛擬平台作為上課使用的開發平台。
3.3.2 設定核心編譯參數
請切換至 linux-3.18.123 目錄,然後執行:
~/qemu_image/arm/kernel/linux-3.18.123 $ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- vexpress_defconfig
其輸出如下:
ROSS_COMPILE=arm-linux-gnueabihf- vexpress_defconfig
HOSTCC scripts/basic/fixdep
HOSTCC scripts/kconfig/conf.o
SHIPPED scripts/kconfig/zconf.tab.c
SHIPPED scripts/kconfig/zconf.lex.c
SHIPPED scripts/kconfig/zconf.hash.c
HOSTCC scripts/kconfig/zconf.tab.o
HOSTLD scripts/kconfig/conf
#
# configuration written to .config
#
接著要手動執行核心編譯參數設定
~/qemu_image/arm/kernel/linux-3.18.123 $ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
請執行底下修改,否則之後無法開機:
General setup --->
[*] open by fhandle syscalls
System Type --->
[ ] Enable the L2x0 outer cache controller
-*- Enable the block layer --->
[*] Support for large (2TB+) block devices and files
接著離開核心編譯環境,並儲存參數設定。
3.4 編譯核心
請執行:
~/qemu_image/arm/kernel/linux-4.4.268 $ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- uImage LOADADDR=0x60000000 -j 8
~/qemu_image/arm/kernel/linux-4.4.268 $ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- dtbs modules -j 8
** 如果嫌每次都要打 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- 這串指令太長的話,也可以把這串指令設定在 .bashrc 中,請在 .bashrc 中新增底下設定:
alias makearmhf='make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-'
之後,我們只要打 makearmhf 就等於 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- 這串指令。
=============================================================================
故障排除:
如果在編譯核心時遇上以下錯誤:
"mkimage" command not found - U-Boot images will not be built
arch/arm/boot/Makefile:79: recipe for target 'arch/arm/boot/uImage' failed
make[1]: *** [arch/arm/boot/uImage] Error 1
arch/arm/Makefile:314: recipe for target 'uImage' failed
make: *** [uImage] Error 2
這是因為沒有 mkimage 這個指令,請上 packages.debian.org 查詢此指令的套件並安裝,安裝完畢後再執行一次 make uImage 指令。
# apt-get install u-boot-tools
=============================================================================
成果驗收:
1. 核心編譯完畢後會出現底下訊息:
Image Name: Linux-4.4.268
Created: Fri Apr 30 11:29:49 2021
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 3512976 Bytes = 3430.64 KiB = 3.35 MiB
Load Address: 60000000
Entry Point: 60000000
Image arch/arm/boot/uImage is ready
我們可以驗收一下 uImage 這個檔案,指令如下:
~/qemu_image/arm/kernel/linux-4.4.268 $ file arch/arm/boot/uImage
arch/arm/boot/uImage: u-boot legacy uImage, Linux-4.4.268, Linux/ARM, OS Kernel Image (Not compressed), 3512976 bytes, Fri Apr 30 03:29:49 2021, Load Address: 0x60000000, Entry Point: 0x60000000, Header CRC: 0x45384E4C, Data CRC: 0x07228E4B
從上面的檔案可以看到這是一個 Linux/ARM 的 OS 核心,版本為 4.4.268
**** 請注意,核心編好 !===== 核心可以用,我們之後會驗證這個核心能不能開機 ****
3.5 編譯核心模組
核心要正常工作必須要有相對應的核心模組,否則無法載入驅動程式,
# Compile Kernel Modules
time make -s ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- modules -j $CPU_CORE
# Install Kernel Modules
time make -s ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- modules_install INSTALL_MOD_PATH=../modules/ -j $CPU_CORE
cd ../modules
time tar cfa ../modules-$KERNEL_VERSION.tar.xz lib
編譯完成後我們會有一個名為 modules-核心編號.tar.xz 的檔案,此檔案可以用來取代原始 rootfs 中 /lib/modules 目錄中舊版的驅動核心模組。因此我們必須將舊版驅動核心模組移除,再放入我們剛剛編完之驅動核心模組。
3.6 測試編好的 Linux 核心模組能否開機
請切換到 linux-KERNEL_VERSION/arch/arm/boot 底下,然後執行:
$ qemu-system-arm -M vexpress-a9 -m 256 -nographic -kernel zImage
$ qemu-system-arm -M vexpress-a9 -m 256M -dtb dts/vexpress-v2p-ca9.dtb -nographic -kernel zImage -append "console=ttyAMA0"
此時會出現開機畫面,然後當掉,如底下所示:
3.6 測試編好的 Linux 核心模組能否開機
請切換到 linux-KERNEL_VERSION/arch/arm/boot 底下,然後執行:
$ qemu-system-arm -M vexpress-a9 -m 256M -dtb dts/vexpress-v2p-ca9.dtb -nographic -kernel zImage -append "console=ttyAMA0"
此時會出現開機畫面,然後當掉,如底下所示:
pulseaudio: set_sink_input_volume() failed
pulseaudio: Reason: Invalid argument
pulseaudio: set_sink_input_mute() failed
pulseaudio: Reason: Invalid argument
Booting Linux on physical CPU 0x0
Initializing cgroup subsys cpuset
Linux version 4.4.268 (herman@120-117-72-71) (gcc version 8.3.0 (Debian 8.3.0-2) ) #1 SMP Fri Apr 30 11:24:29 CST 2021
CPU: ARMv7 Processor [410fc090] revision 0 (ARMv7), cr=10c5387d
CPU: PIPT / VIPT nonaliasing data cache, VIPT nonaliasing instruction cache
Machine model: V2P-CA9
Memory policy: Data cache writeback
CPU: All CPU(s) started in SVC mode.
PERCPU: Embedded 11 pages/cpu @8fdc1000 s13964 r8192 d22900 u45056
Built 1 zonelists in Zone order, mobility grouping on. Total pages: 65024
Kernel command line: console=ttyAMA0
..
ALSA device list:
#0: ARM AC'97 Interface PL041 rev0 at 0x10004000, irq 33
input: ImExPS/2 Generic Explorer Mouse as /devices/platform/smb/smb:motherboard/smb:motherboard:iofpga@7,00000000/10007000.kmi/serio1/input/input2
VFS: Cannot open root device "(null)" or unknown-block(0,0): error -6
Please append a correct "root=" boot option; here are the available partitions:
1f00 131072 mtdblock0 (driver?)
1f01 32768 mtdblock1 (driver?)
Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)
CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.4.268 #1
Hardware name: ARM-Versatile Express
[<80015ab0>] (unwind_backtrace) from [<80012604>] (show_stack+0x10/0x14)
[<80012604>] (show_stack) from [<804b4510>] (dump_stack+0x94/0xa8)
[<804b4510>] (dump_stack) from [<804b0624>] (panic+0x9c/0x1f4)
[<804b0624>] (panic) from [<8063e2b4>] (mount_block_root+0x1c0/0x250)
[<8063e2b4>] (mount_block_root) from [<8063e444>] (mount_root+0x100/0x108)
[<8063e444>] (mount_root) from [<8063e59c>] (prepare_namespace+0x150/0x198)
[<8063e59c>] (prepare_namespace) from [<8063deac>] (kernel_init_freeable+0x24c/0x25c)
[<8063deac>] (kernel_init_freeable) from [<804b60f8>] (kernel_init+0x8/0xe4)
[<804b60f8>] (kernel_init) from [<8000f390>] (ret_from_fork+0x14/0x24)
---[ end Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)
此時表示 kernel 可以開機,但是因為還沒有跟整個系統整合在一起,所以會當機,我們按 Ctrl-a 再按 x 即可退出。
4. 放到你的「虛擬」嵌入式 ARM 平台,並使其開機
待續
沒有留言:
張貼留言