--- title: Raspberry Pi Introduction (樹莓派介紹) - 從零開始的開源地下城 tags: Linux, Linux讀書會, Kernel, 從零開始的開源地下城, COMBO-tw description: 介紹與Linux Kernel相關基本知識 lang: zh-Hant GA: G-2QY5YFX2BV --- # Raspberry Pi Introduction (樹莓派介紹) ###### tags: `Linux` ## 目錄 [TOC] ## 開發板介紹 * 樹莓派與GPIO腳位 * 樹莓派是一塊入門款的嵌入式系統開發板 ![](https://hackmd.io/_uploads/ByEebobL3.png) --- * 週邊設備(下圖為PI4,僅供參考) ![](https://hackmd.io/_uploads/rkne-iZ8n.png) * 配備有 * USB - USB TypeA * Display - HDMI * Network - Ethernet RJ45 or WIFI * GPIO(General-purpose input/output) - 通用型輸入輸出 * I2C * UART * SPI * Normal Input/Output --- * 使用示意圖 * 你須要將放有系統的SD Card與要使用到的裝置插入(例如:鍵盤、滑鼠、網路線、螢幕線、電源線...等) ![](https://projects-static.raspberrypi.org/projects/raspberry-pi-getting-started/c75872d60ab3464aadd28acbd466c0eaaa5be402/en/images/pi-plug-in.gif) --- * 設定SD Card * 將[官方](https://www.raspberrypi.org/downloads/)或自製的系統燒錄到SD Card中 ![](https://hackmd.io/_uploads/HyDfZib82.png) ## 編譯QEMU 由於使用 apt 工具安裝的 QEMU 並不支援 Pi 3,因此我們要自己手動編譯 2.12.0 版本的 QEMU * 安裝相關工具 * `apt-get install gcc build-essential automake gcc-arm-linux-gnueabihf vim git wget python pkg-config zlib1g-dev libglib2.0-dev libpixman-1-dev flex bison unzip libncurses5-dev` * 下載 [QEMU source code](https://download.qemu.org/qemu-2.12.0-rc3.tar.xz) * `$ wget https://download.qemu.org/qemu-2.12.0-rc3.tar.xz` * 解壓縮 * `$ tar xvf qemu-2.12.0-rc3.tar.xz` * 配置設定 * `$ cd qemu-2.12.0-rc3` * `$ ./configure --target-list=arm-softmmu,aarch64-softmmu` * 相關設定 * `--target-list`: 指令想要編譯的模擬器 * `--prefix`: 指定程式要安裝的路徑 * 其他設定與選項皆可從 `./configure --help` 得知 * 編譯及安裝 * `$ make -j$(nproc)` * `$ make install` * 設定路徑 * `$ echo "export PATH=$(pwd)/aarch64-softmmu:\$PATH" >> ~/.bashrc` * `$ source ~/.bashrc` ## 取得 Raspbian Image * 下載 [Raspbian disk image 的 zip 檔](https://downloads.raspberrypi.org/raspbian/images/raspbian-2018-11-15/2018-11-13-raspbian-stretch.zip) * `$ wget https://downloads.raspberrypi.org/raspbian/images/raspbian-2018-11-15/2018-11-13-raspbian-stretch.zip` * 解壓縮 * `$ unzip 2018-11-13-raspbian-stretch.zip` * 解壓縮後的檔名為 `2018-11-13-raspbian-stretch.img` ## 編譯 Raspberry Pi Kernel 由於 QEMU 和真實的 Pi 還是有些不同的,因此無法使用 2018-11-13-raspbian-stretch.zip 裡面提供的 kernel 來開機,需要自行編出 QEMU 用的 kernel * 下載 [kernel source code](https://github.com/raspberrypi/linux/tree/rpi-4.9.y) * `$ git clone git://github.com/raspberrypi/linux.git --branch raspberrypi-kernel_1.20180619-1 --single-branch --depth 1` * 修正編譯上的錯誤 * 到 [dhruvvyas90/qemu-rpi-kernel](https://github.com/dhruvvyas90/qemu-rpi-kernel/tree/master/tools) 上取得 `linux-arm.patch` * `$ wget https://raw.githubusercontent.com/dhruvvyas90/qemu-rpi-kernel/master/tools/linux-arm.patch` * 打上 patch * `$ cd linux` * `$ patch -p1 < ./linux-arm.patch` * 編譯 kernel * 編譯 kernel7.img * `$ KERNEL=kernel7` * 初始化 config * `$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- versatile_defconfig` * 設定 config * 到 [dhruvvyas90/qemu-rpi-kernel](https://github.com/dhruvvyas90/qemu-rpi-kernel/tree/master/tools) 上取得 `config_file` 和 `config_ip_tables` * `$ wget https://raw.githubusercontent.com/dhruvvyas90/qemu-rpi-kernel/master/tools/config_file` * `$ wget https://raw.githubusercontent.com/dhruvvyas90/qemu-rpi-kernel/master/tools/config_ip_tables` * 添加 config * ```SHELL $ cat >> .config << EOF CONFIG_CROSS_COMPILE="arm-linux-gnueabihf" EOF ``` * `$ cat ./config_file >> .config` * `$ cat ./config_ip_tables >> .config` * 開啟 menuconfig * `$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig` * 編譯 kernel 和 dtb * `$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- bzImage dtbs` * 設定路徑 * `$ cd ..` * `$ cp linux/arch/arm/boot/zImage ./kernel7.img` * `$ cp linux/arch/arm/boot/dts/versatile-pb.dtb ./versatile-pb.dtb` * `$ cp linux/vmlinux ./vmlinux` ## 交叉編譯器(Cross Compiler) 有沒有發現上面[編譯Raspberry Pi Kernel](#編譯-Raspberry-Pi-Kernel)時有個參數`CROSS_COMPILE=arm-linux-gnueabihf-`呢? ![](https://hackmd.io/_uploads/HkGXboW82.png) * 一般的編譯器 ![](https://hackmd.io/_uploads/rkPQZibL3.png) * 那甚麼是交叉編譯器呢? 你會將你在電腦上跑的程式直接放到手機上去跑嗎?不會吧 ![](https://hackmd.io/_uploads/rJzEZsZU3.png) * 為什麼我們要交叉編譯器呢? [Code Ref](https://godbolt.org/z/CAas_U) * Hello World C Code ```cpp= #include <stdio.h> int main(void) { printf("Hello World\n"); } ``` * 我們一般的PC(x86_64) ```cpp= .LC0: .string "Hello World" main: push rbp mov rbp, rsp mov edi, OFFSET FLAT:.LC0 call puts mov eax, 0 pop rbp ret ``` * 樹莓派(ARM) ```cpp= .LC0: .ascii "Hello World\000" main: stmfd sp!, {fp, lr} add fp, sp, #4 ldr r0, .L3 bl puts mov r3, #0 mov r0, r3 sub sp, fp, #4 ldmfd sp!, {fp, lr} bx lr .L3: .word .LC0 ``` * 額外補充 ![](https://hackmd.io/_uploads/ByoEZsZU3.png) ## 執行 QEMU with Raspberry Pi 3 * 如果你在Docker中執行 ```SHELL $ sudo qemu-system-arm \ -M versatilepb \ -cpu arm1176 \ -m 256 \ -hda 2018-11-13-raspbian-stretch.img \ -kernel kernel7.img \ -dtb versatile-pb.dtb \ -net nic \ -net user,hostfwd=tcp::5022-:22 \ --append "root=/dev/sda2 panic=1" \ -vnc :0 \ -no-reboot ``` * 到外面Host執行 `$ vncviewer 0:5900` * 如果沒裝的話 `$ sudo apt-get install vncviewer` * 如果是在有圖型桌面環境下的話 ```SHELL $ sudo qemu-system-arm \ -M versatilepb \ -cpu arm1176 \ -m 256 \ -hda 2018-11-13-raspbian-stretch.img \ -kernel kernel7.img \ -dtb versatile-pb.dtb \ -net nic \ -net user,hostfwd=tcp::5022-:22 \ --append "root=/dev/sda2 panic=1" \ -no-reboot ``` * 如果是想要輸出到終端機的話 ```SHELL $ sudo qemu-system-arm \ -M versatilepb \ -cpu arm1176 \ -m 256 \ -hda 2018-11-13-raspbian-stretch.img \ -kernel kernel7.img \ -dtb versatile-pb.dtb \ -net nic \ -net user,hostfwd=tcp::5022-:22 \ --append "rw console=ttyAMA root=/dev/sda2 panic=1" \ -nographic \ -no-reboot ``` * Raspberry Pi 預設帳號密碼 * 帳號︰`pi` * 密碼︰`raspberry` * 離開 QEMU * `Ctrl-A + X` ## 編譯GDB 由於使用 apt 工具安裝的 GDB 並不支援 ARM,因此我們要自己手動編譯 8.1 版本的 GDB * 下載 [GDB soure code](http://ftp.gnu.org/gnu/gdb/gdb-8.1.tar.gz) * 解壓縮 * `$ tar zxvf gdb-8.1.tar.gz` * 配置設定 * `$ cd gdb-8.1` * `$ ./configure --target=arm-linux-gnueabihf` * 相關設定 * `--target-list`: 目標架構 * `--prefix`: 指定程式要安裝的路徑 * 其他設定與選項皆可從 `./configure --help` 得知 * 編譯及安裝 * `$ make -j$(nproc)` * `$ sudo make install` * 設定路徑 * `$ echo "export PATH=$(pwd)/bin:\$PATH" >> ~/.bashrc` * `$ source ~/.bashrc` ## 執行 QEMU with GDB * 啟動QEMU Debug Mode ```SHELL $ sudo qemu-system-arm \ -M versatilepb \ -cpu arm1176 \ -m 256 \ -hda 2018-11-13-raspbian-stretch.img \ -kernel kernel7.img \ -dtb versatile-pb.dtb \ -net nic \ -net user,hostfwd=tcp::5022-:22 \ --append "root=/dev/sda2 panic=1" \ -no-reboot \ -serial stdio -S -s ``` * 進行Debug * 啟動GDB `$ arm-linux-gnueabihf-gdb vmlinux` * 連線QEMU `(gdb) target remote localhost:1234` ## Debug Tool - GDB 簡易教學 * QEMU端參數 `qemu {OTHER_OPTION} -S -s(or -gdb tcp::1234)` * -s(小寫 s):運行虛擬機時將 1234 端口開啟成調試端口,供 gdb 遠端除錯時使用 * -S(大寫 S):啟動虛擬機時要「凍住」虛擬機,等待除錯器發出繼續運行的命令 * -gdb tcp::1234:與-s相同 * GDB指令 * 連接到遠端:`(gdb) target remote localhost:1234` * 下中斷點:`(gdb) b` * 列出目前中斷點:`(gdb) info b` or `(gdb) i b` * 繼續執行直到下一個中斷點或結束:`(gdb) continue` or `(gdb) c` * 列出目前上下文:`(gdb) list` or `(gdb) l` * 單步 (會進入 funciton):`(gdb) step` or `(gdb) s` * 組語單步 (會進入 funciton):`(gdb) si` * 單步 (不會進入 funciton):`(gdb) next` or `(gdb) n` * 跳離一個 while for 迴圈:`(gdb) until` or `(gdb) u` * 顯示某變數:`(gdb) print` or `(gdb) p`,如 p str * 顯示 CPU 的 register:`(gdb) info register` or `(gdb) i r` * 顯示記憶體位置內容 * 格式為`x/nyz` * 參數說明 ``` n: 要印出的數量 y: 顯示的格式,可為C(char), d(整數), x(hex) z: 單位,可為 b(byte), h(16bit), w(32bit) ``` ## 本章節練習與反思 * 請大家試著編譯其它版本的Kernel執行看看吧 * 請大家去瞭解"[執行 QEMU with Raspberry Pi 3](#執行-QEMU-with-Raspberry-Pi-3)"的指令中,各個參數的用途吧 ## 參考資料 * [樹莓派 Raspberry Pi 編譯 Linux 核心(Kernel)步驟教學](https://blog.gtwang.org/iot/raspberry-pi-compile-linux-kernel/) * [自己動手編譯 Raspberry Pi 的 Kernel](https://coldnew.github.io/f5873b3f/) * [Tools](https://github.com/raspberrypi/tools) * [Firmware](https://github.com/raspberrypi/firmware) * [Kernel](https://github.com/raspberrypi/linux/) * [使用 gdb+qemu 來執行/除錯 raspberry pi linux kernel ](https://descent-incoming.blogspot.com/2017/03/raspberry-pix86-linux-kernel-debug-by.html) * [編譯 linux 0.11,並且使用 QEMU + GDB 調試 kernel ( Ubuntu 11.04, GCC 4.5.2) ](https://wwssllabcd.github.io/blog/2012/08/03/compile-linux011/) * [Ken-Dai的Raspberry Pi Introduction](https://hackmd.io/@Ken-Dai/ByZCIVJzr) * [几种linux内核文件的区别(vmlinux、zImage、bzImage、uImage、vmlinuz、initrd )](https://blog.csdn.net/hanxuefan/article/details/7454352) * [Linux 執行時尋找 symbol 的流程以及 shared library 相關知識](https://medium.com/fcamels-notes/linux-%E5%9F%B7%E8%A1%8C%E6%99%82%E5%B0%8B%E6%89%BE-symbol-%E7%9A%84%E6%B5%81%E7%A8%8B%E4%BB%A5%E5%8F%8A-shared-library-%E7%9B%B8%E9%97%9C%E7%9F%A5%E8%AD%98-b0cf1e19cbf3) * [利用 buildroot 與 Qemu 建構簡易 Embedded Linux 環境](https://hackmd.io/@VIRqdo35SvekIiH4p76B7g/Skj9UCo2?type=view)