---
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)