2016年10月30日 星期日

如何編譯 ARM HF 核心

如何編譯 ARM HF 核心

最新版的 Linux 核心資訊在 kernel.org 中可以看到,目前為止第三版最新的核心版本為 linux-3.18.44,我們以此版本作為「虛擬 ARM」版的開機核心。我們所使用的「虛擬 ARM」版為 vexpress-a9,qemu 所支援的虛擬 ARM 資訊可以執行底下指令來觀看:

$ qemu-system-arm -machine help
Supported machines are:
akita                Sharp SL-C1000 (Akita) PDA (PXA270)
borzoi               Sharp SL-C3100 (Borzoi) PDA (PXA270)
canon-a1100          Canon PowerShot A1100 IS
cheetah              Palm Tungsten|E aka. Cheetah PDA (OMAP310)
collie               Sharp SL-5500 (Collie) PDA (SA-1110)
connex               Gumstix Connex (PXA255)
cubieboard           cubietech cubieboard
highbank             Calxeda Highbank (ECX-1000)
imx25-pdk            ARM i.MX25 PDK board (ARM926)
integratorcp         ARM Integrator/CP (ARM926EJ-S)
kzm                  ARM KZM Emulation Baseboard (ARM1136)
lm3s6965evb          Stellaris LM3S6965EVB
lm3s811evb           Stellaris LM3S811EVB
mainstone            Mainstone II (PXA27x)
midway               Calxeda Midway (ECX-2000)
musicpal             Marvell 88w8618 / MusicPal (ARM926EJ-S)
n800                 Nokia N800 tablet aka. RX-34 (OMAP2420)
n810                 Nokia N810 tablet aka. RX-44 (OMAP2420)
netduino2            Netduino 2 Machine
none                 empty machine
nuri                 Samsung NURI board (Exynos4210)
palmetto-bmc         OpenPOWER Palmetto BMC
raspi2               Raspberry Pi 2
realview-eb          ARM RealView Emulation Baseboard (ARM926EJ-S)
realview-eb-mpcore   ARM RealView Emulation Baseboard (ARM11MPCore)
realview-pb-a8       ARM RealView Platform Baseboard for Cortex-A8
realview-pbx-a9      ARM RealView Platform Baseboard Explore for Cortex-A9
sabrelite            Freescale i.MX6 Quad SABRE Lite Board (Cortex A9)
smdkc210             Samsung SMDKC210 board (Exynos4210)
spitz                Sharp SL-C3000 (Spitz) PDA (PXA270)
sx1                  Siemens SX1 (OMAP310) V2
sx1-v1               Siemens SX1 (OMAP310) V1
terrier              Sharp SL-C3200 (Terrier) PDA (PXA270)
tosa                 Sharp SL-6000 (Tosa) PDA (PXA255)
verdex               Gumstix Verdex (PXA270)
versatileab          ARM Versatile/AB (ARM926EJ-S)
versatilepb          ARM Versatile/PB (ARM926EJ-S)
vexpress-a15         ARM Versatile Express for Cortex-A15
vexpress-a9          ARM Versatile Express for Cortex-A9
virt-2.6             QEMU 2.6 ARM Virtual Machine
virt                 QEMU 2.7 ARM Virtual Machine (alias of virt-2.7)
virt-2.7             QEMU 2.7 ARM Virtual Machine
xilinx-zynq-a9       Xilinx Zynq Platform Baseboard for Cortex-A9
z2                   Zipit Z2 (PXA27x)

其中有一行如下:

vexpress-a9          ARM Versatile Express for Cortex-A9

這是我們要玩的虛擬 ARM 開發板,請把 linux 核心放在 /usr/src/ 目錄下,其完整路徑為

/usr/src/linux-3.18.44.tar.xz


=======================底下流程請全部以一般使用者來執行========================

接下來在本地端要解開 linux 原始碼,並準備編譯。請在 ~/qemu_image/arm2 目錄新增 kernel 目錄

~/qemu_image/arm2 $ mkdir kernel
~/qemu_image/arm2 $ cd kernel
~/qemu_image/arm2/kernel $ tar xfva linux-3.18.44.tar.xz
~/qemu_image/arm2/kernel $ cd linux-3.18.44
~/qemu_image/arm2/kernel/linux-3.18.44 $ makerpi vexpress_defconfig
~/qemu_image/arm2/kernel/linux-3.18.44 $ makerpi menuconfig

此時會進入核心設定選單,請選擇

General setup  --->
        Kernel compression mode (XZ)  --->

System Type  --->
        [ ] Enable the L2x0 outer cache controller
        請把原有的 * 取消,否則開機會有問題

完全上述設定後離開設定畫面,然後執行:

~/qemu_image/arm2/kernel/linux-3.18.44 $ makerpi uImage LOADADDR=0x60000000 -j 8

作完之後其訊息如下:

..
  LD      arch/arm/boot/compressed/vmlinux
  OBJCOPY arch/arm/boot/zImage
  Kernel: arch/arm/boot/zImage is ready
  UIMAGE  arch/arm/boot/uImage
Image Name:   Linux-3.18.44
Created:      Mon Oct 31 11:22:50 2016
Image Type:   ARM Linux Kernel Image (uncompressed)
Data Size:    2437760 Bytes = 2380.62 kB = 2.32 MB
Load Address: 60000000
Entry Point:  60000000
  Image arch/arm/boot/uImage is ready


接著可以用 qemu 來試開機,請執行:

~/qemu_image/arm2 $ qemu-system-arm -M vexpress-a9 -m 256 -nographic -kernel
./kernel/linux-3.18.44/arch/arm/boot/zImage

此時會進入核心開機畫面,但是因為我們還沒有給這個核心 rootfs 的緣故,因此開機開到一半會出現底下錯誤:

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?)
Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)
CPU: 0 PID: 1 Comm: swapper/0 Not tainted 3.18.44 #2
[<80014824>] (unwind_backtrace) from [<800116d0>] (show_stack+0x10/0x14)
[<800116d0>] (show_stack) from [<80477c64>] (dump_stack+0x98/0xac)
[<80477c64>] (dump_stack) from [<80475b10>] (panic+0x9c/0x200)
[<80475b10>] (panic) from [<805ec228>] (mount_block_root+0x1d0/0x260)
[<805ec228>] (mount_block_root) from [<805ec3c0>] (mount_root+0x108/0x110)
[<805ec3c0>] (mount_root) from [<805ec520>] (prepare_namespace+0x158/0x19c)
[<805ec520>] (prepare_namespace) from [<805ebeb4>] (kernel_init_freeable+0x244/0x254)
[<805ebeb4>] (kernel_init_freeable) from [<80473f60>] (kernel_init+0x8/0xe8)
[<80473f60>] (kernel_init) from [<8000e500>] (ret_from_fork+0x14/0x34)
---[ end Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)


這是正常的,請按 Ctrl+a 然後再按 x 即可離開 qemu 模擬畫面,之後我們將會為此虛擬 ARM 主機加上 rootfs 及 bootloader 使其可以開機。

如何下載 Raspberry Pi 3 之影像檔及安裝至記憶卡

Raspberry Pi3 是目前唯一一塊使用 64 位元 ARM 版 CPU 的嵌入式開發板,官網所提
供的開機影像檔只有 32 位元。目前 64 位元版作業系統仍在開發中,要在 RPI3 上開
機必須使用 SD 記憶卡,因此需要自行下載並安裝開機影像檔至記憶卡中。

要下載 RPI3 的影像檔,請至其官方網頁,連結選單 DOWNLOADS -> RASPBIAN 下載:

RASPBIAN JESSIE LITE ->
         這是最小的開機影像檔,沒有桌面環境,其大小為 292 MB

RASPBIAN JESSIE WITH PIXEL ->
         這是內建桌面環境的開機影像檔,其大小為 1.4 G

考慮到我們開發嵌入式系統多半沒有螢幕,因此在一般情況下只需下載 LITE 版本即可。
下載完會出現一個檔案,其檔名是 YYYY-MM-DD-raspbian-jessie-lite.zip,其中 YYYY
是指西元,MM 是指月份,DD 是指日期,舉例來說在 2016-09-23 官方網站有推出一個
版本,因此其檔名為 2016-09-23-raspbian-jessie-lite.zip。

要解開此檔,請執行:

unzip 2016-09-23-raspbian-jessie-lite.zip

此時會出現一個影像檔,其檔名是:2016-09-23-raspbian-jessie-lite.img

下載/解壓縮完影像檔後,要將此影像檔轉植至 SD 卡,為了減少容量不足的問題,請選
一片 8GB 以上之 SD 卡來轉植影像檔。

要轉植影像檔可以參考官檔說明,其網址如下:

https://www.raspberrypi.org/documentation/installation/installing-images/README.md

轉植方式如下:

1. 請先把 SD 記憶卡插入讀卡機,再接上電腦,並執行 dmesg 來觀察其硬碟代號,例如
[94457.081710] scsi 7:0:0:0: Direct-Access     FNK TECH  USB CARD READER 2.33 PQ: 0 ANSI: 2
[94457.086175] sd 7:0:0:0: Attached scsi generic sg2 type 0
[94457.086291] sd 7:0:0:0: [sdb] 15759360 512-byte logical blocks: (8.07 GB/7.51 GiB)
[94457.086412] sd 7:0:0:0: [sdb] Write Protect is off
[94457.086415] sd 7:0:0:0: [sdb] Mode Sense: 03 00 00 00
[94457.086537] sd 7:0:0:0: [sdb] No Caching mode page found
[94457.086541] sd 7:0:0:0: [sdb] Assuming drive cache: write through
[94457.088724]  sdb: sdb1
[94457.089589] sd 7:0:0:0: [sdb] Attached SCSI removable disk

可以看到記憶卡的硬碟代號是 /dev/sdb

2. 請以 root 權限,在 2016-09-23-raspbian-jessie-lite.img 的目錄下執行:

# time dd bs=4M if=2016-09-23-raspbian-jessie-lite.img of=/dev/sdb
sie-lite.img of=/dev/sdb
331+1 records in
331+1 records out
1389363200 bytes (1.4 GB) copied, 193.759 s, 7.2 MB/s

real    3m13.762s
user    0m0.000s
sys     0m2.068s

請注意上面指令的 /dev/sdb 要確定是你的記憶卡硬碟代號,千萬不要打錯,以免不小
心把你的 windows 硬碟甚至是系統碟洗掉。

如果一切都沒作錯的話,此時讀卡機會開始閃,等它閃完理論上就作好 RPI3 的開機碟。
此時執行 lsblk 可以看到目前 SD 卡上有兩個分割區:

sdb                           8:16   1   7.5G  0 disk
├─sdb1                        8:17   1    63M  0 part
└─sdb2                        8:18   1   1.2G  0 part

2016年10月23日 星期日

如何建立 rootfs (新版 2020)

如何建立 rootfs
#2020/05/05 改版

Q. 什麼是 rootfs ?

嵌入式系統所使用的 Linux,如同工作站版本的 Linux 一樣,都有一個 / 目錄,這個目錄就是所謂的 rootfs。X86 主機的 / 目錄是我們在安裝 Debian Linux 時所建立,但是嵌入式系統的 Linux,其安裝流程十分不一樣,它沒有開機光碟/隨身碟等作為安裝工具,因此必須手動進行安裝。

需要工具:

debootstrap qemu-user-static

請執行:

# apt-get install debootstrap qemu-user-static

*** 我們預計先作一個虛擬的 ARM 系統,以 qemu 來執行,未來各位買 raspberry pi 來進行實作時,要安裝原廠所提供的嵌入式 Linux 作業系統 ***

安裝完畢後,我們要將之前所建立的 sd.img 再掛到 /mnt/sdcard1 /mnt/sdcard2 目錄,其中:

/mnt/sdcard1 - 大小:80M/ 檔案系統:VFAT/ 主要功能:放系統開機核心。
/mnt/sdcard2 - 大小:*  / 檔案系統:EXT4/ 主要功能:放 rootfs 及應用程式。


確定掛載後,我們要在 /mnt/sdcard2 目錄下建立新的 rootfs,指令如下:

# debootstrap \
  --arch=armhf \
  --keyring=/usr/share/keyrings/debian-archive-keyring.gpg \
  --verbose \
  --foreign \
  buster \
  /mnt/sdcard2 \
  file:///home/ftp/debian

其中

--arch=armhf 是指我們 arm 的版本是 hf (Hard Float)
--keyring    是告訴 debootstrap 其 keyring.pgp 檔的位置
--verbose    是將過程全部顯示出來
--foreign    是指使用 armel 這個架構,一般都是在 x86_64 主機上實作其它平台的
             rootfs,所以要加上此參數。
buster       是指我們現在要安裝的 debian 版本為 buster,以後若升級至 bullseye
             的話必須要把 buster 改成 bullseye。
/mnt/sdcard2 是指要建立的 rootfs 目錄
file:///home/ftp/debian 是指建立 rootfs 時要下載的鏡像站來源,一般來說如果使用
             網路鏡像站的話,其參數為:
             ftp://debian.csie.nctu.edu.tw/debian
             或
             ftp://opensource.nchc.org.tw/debian
             等等諸如此類的鏡像站來源,使用網路鏡像站有很多缺點,最主的缺點是
             下載套件的時間是跟網路速度有關,因此先前帶大家自行建立網路鏡像站
             就是為了解決這個問題,所以請使用 file:///home/ftp/debian 即可不上
             網下載而是使用本機硬碟之鏡像站來下載,速度會非常快。

執行上述指令會出現底下訊息:

I: Retrieving Release
I: Retrieving Release.gpg
I: Checking Release signature
I: Valid Release signature (key id 75DDC3C4A499F1A18CB5F3C8CBF8D6FD518E17E1)
I: Retrieving Packages
I: Validating Packages
I: Resolving dependencies of required packages...
I: Resolving dependencies of base packages...
..
I: Extracting libmount1...
I: Extracting libsmartcols1...
I: Extracting libuuid1...
I: Extracting mount...
I: Extracting util-linux...
I: Extracting liblzma5...
I: Extracting zlib1g...

這樣表示 debootstrap 的第一階段告一段落,接著請執行:

# cp /usr/bin/qemu-arm-static /mnt/sdcard2/usr/bin/

然後進入 chroot 環境:

# chroot /mnt/sdcard2 /bin/bash
bash: warning: setlocale: LC_ALL: cannot change locale (zh_TW.UTF8)
I have no name!@120:/#

看到 I have no name! 的提示符號就表示我們已經進入 chroot 環境,請再執行:

# /debootstrap/debootstrap --second-stage
I: Keyring file not available at /usr/share/keyrings/debian-archive-keyring.gpg; switching to https mirror https://mirrors.kernel.org/debian
I: Installing core packages...
I: Unpacking required packages...
I: Unpacking acl...
I: Unpacking libacl1:armel...
..
I: Configuring tasksel...
I: Configuring tasksel-data...
I: Configuring libc-bin...
I: Configuring systemd...
I: Base system installed successfully.

看到最後一行有 Base system installed successfully 表示最原本的 rootfs 已經作好。

作完等待下次再來進行設定,請先將 sd.img 整個解除掉 (umount, losetup -d)。。

安裝 ARM toolchain (2016 年版)

安裝 Cross toolchain

目前 ARM 的平台已經有 64 位元 CPU,其 Debian 架構是 aarch64,為了兼顧傳統 32 位元之 armel/armhf 支援,及最新的 aarch64 架構支援,我們必須安裝這三者之 toolchain,並分別設定其指令才能使用。要編譯 ARM 平台的程式,必須安裝 Cross toolchain,所謂的 Cross toolchain 就是 在 X86 平台上編譯 ARM 的可執行檔。要安裝這些 toolchain 必須使用 Embedded Debian Project 所提供資源,所以我們要修改 /etc/apt/sources.list 這個檔案,新增底下設定:

#armhf toolchain
deb http://emdebian.org/tools/debian/ jessie main

新增完畢之後,請執行:

# apt-get update

然後執行:
# dpkg --print-foreign-architectures
armel
i386

這裡可以看到目前我們的系統支援 armel 以及 i386 等非 x86_64 平台的架構,現在請
執行:

# dpkg --add-architecture armhf
# dpkg --add-architecture arm64

來新增 armhf 及 arm64 架構,作完之後再重新執行剛剛的指令可以看到目前已經有
armhf 架構了,指令如下:
# dpkg --print-foreign-architectures

其輸出至少會有三行:
armel                   - armel 架構
armhf                   - armhf 架構
arm64                   - arm64 架構


接著安裝 armhf 以及 arm64 的 gcc 套件,請執行:

# apt-get update
# apt-get install crossbuild-essential-armhf
# apt-get install crossbuild-essential-arm64


為了方便未來我們使用這三個不同版本的工具,請在 ~/.bashrc 中新增底下設定:

alias makearm='make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi-'
alias makerpi='make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-'
alias makearm64='make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu-'

然後安裝

# apt-get install qemu-user qemu-user-static

接下來執行底下指令來驗證 armhf 版本之編譯工具是否已安裝完成:

$ arm-linux-gnueabihf-gcc -v
$ arm-linux-gnueabihf-cpp -v
$ arm-linux-gnueabihf-g++ -v


然後請再執行底下指令來驗證 arm64 版本之編譯工具是否已安裝完成:

$ aarch64-linux-gnu-gcc -v
$ aarch64-linux-gnu-cpp -v
bash: aarch64-linux-gnu-cpp:命令找不到

上述錯誤是指在 /usr/bin 目錄沒有底下連結,請自行建立:

lrwxrwxrwx 1 root root 25 10月 24 10:07 aarch64-linux-gnu-cpp -> aarch64-linux-gnu-cpp-4.9

建立完再重新執行一次:

$ aarch64-linux-gnu-cpp -v

此時應該就沒有問題了,請再執行最後一個程式的驗證:

$ aarch64-linux-gnu-g++ -v

看看是否已安裝完畢,接著可以作編譯 arm 版 hello.c 的程式,指令如:

~/prog $ arm-linux-gnueabihf-gcc hello.c -o hello_arm

接著檢查 hello_arm 是否為 ARM 之可執行檔:

~/prog $ file hello_arm
hello_arm: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.3, for GNU/Linux 2.6.18, BuildID[sha1]=ff5f6feea2e9b6d69384e8983758eb78c629276a, not stripped

確定有上面的檔案是 ARM 版可執行檔後,我們可以執行底下指令來驗證:

~/prog $ qemu-arm hello_arm
Hello World

接下來請執行底下指令,將 hello.c 編譯成 arm64 位元版本:

~/prog $ aarch64-linux-gnu-gcc hello.c -o hello_arm64


此時會編出一個 hello_arm64 的檔案,請執行底下指令來觀看此檔格式:

~/prog $ file hello_arm64
hello_arm64: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, for GNU/Linux 3.7.0, BuildID[sha1]=6a5f0a968cea7ef12c8dfb9873772f1660ea0b6c, not stripped

要驗證此檔是否可執行,請執行:

~/prog $ qemu-aarch64 hello_arm64
Hello World


截至目前為止,我們已完成 armhf、arm64 之編譯工具安裝及驗收,這些工具將成為未來編譯 arm 核心、u-boot 的基本工具。


Q:什麼是 armel ? 什麼是 armhf ? 什麼是 arm64 ?






請依照
https://wiki.debian.org/CrossToolchains
https://wiki.debian.org/EmdebianToolchain
https://wiki.debian.org/Embedded_Debian
來安裝,20 分鐘驗收。


如何用 qemu 安裝虛擬機

# apt-get install qemu-system-x86

新增一個 ~/centos,並切換至此目錄:

$ mkdir ~/centos

$ cd ~/centos

作 centos 安裝硬碟檔,容量 10G

底下指令是 raw 格式:
~/centos$ qemu-img create centos.img 10G
Formatting 'centos.img', fmt=raw size=10737418240

或生 qcow2 格式
~/centos$ qemu-img create centos_qcow2.img 10G -f qcow2
Formatting 'centos_qcow2.img', fmt=qcow2 size=10737418240 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16

上述任一格式均可安裝 centos,目前 centos 最新的 ISO 檔名為:

CentOS-7-x86_64-DVD-1511.iso

我們將此檔複製至 ~/centos 目錄中,然後執行底下指令確定系統是否有載入 kvm 模組:

$ lsmod |grep kvm
kvm_intel             163840  0
kvm                   438272  1 kvm_intel

接著開始安裝,請執行底下指令:

~/centos$ qemu-system-x86_64  -enable-kvm -m 4096 -drive file=centos.img,format=raw -cdrom CentOS-7-x86_64-DVD-1511.iso -boot d

此時會進入 CentOS 安裝畫面,選擇:

Software Selection -> Server with GUI

Begin Installation 畫面中要設定 root 密碼及一般使用,此時會進行 centos 的安裝
流程,等安裝完畢後重新開機並在原啟動畫面按 Ctrl+C 中斷虛擬機。

我們再執行底指令重啟虛擬機:

~/centos$ qemu-system-x86_64  -enable-kvm -m 4096 -drive file=centos.img,format=raw -cdrom CentOS-7-x86_64-DVD-1511.iso -boot c


接著就有虛擬機可用,那麼目前 centos.img 就是我們所安裝的虛擬 linux 環境,如果要
作備份,請先把虛擬機關閉,然後執行:

~/centos$ qemu-img convert -O raw centos.img centos_backup.img

執行完畢後會出現一個 centos_backup.img 檔,這就是我們虛擬機的備份檔,以後玩虛
擬機是玩 centos.img 這個檔案,萬一玩死掉了可以執行底下指令來復原:

~/centos$ qemu-img convert -O raw centos_backup.img centos.img

復原之後就可以繼續玩 centos.img 檔。