## UART    可以使用 mini usb 供電,不用另外買 DC supply!! 如果要在開機時從sd card,請上電前長按 S2 按鈕 ## 編譯的準備 我是使用 Virtualbox + ubuntu 22.04 編譯相關 toolchain ```bash= liang@ubuntu:~/Desktop/beagle_black$ uname -a Linux ubuntu 6.8.0-49-generic #49~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Wed Nov 6 17:42:15 UTC 2 x86_64 x86_64 x86_64 GNU/Linux ``` 其他編譯工具安裝指令 ```bash= sudo apt install make git gcc-arm-none-eabi gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf gcc bison flex libssl-dev dpkg-dev lzop libncurses5-dev ``` 再有遇到問題就直接裝吧 ( sudo apt install xxx ) [arm交叉編譯器gnueabi、none-eabi、arm-eabi、gnueabihf、gnueabi區別](https://github.com/jasonblog/note/blob/master/toolchain/173.md) ### u-boot ```bash= git clone https://github.com/u-boot/u-boot cd u-boot/ export CC=arm-linux-gnueabihf- make ARCH=arm CROSS_COMPILE=${CC} distclean make ARCH=arm CROSS_COMPILE=${CC} am335x_evm_defconfig make menuconfig make ARCH=arm CROSS_COMPILE=${CC} ``` 這邊在 menuconfig 需要先修改成 am335x_boneblack   這邊要關注2個檔案。`MLO` and `u-boot.img` (編譯完會產生) 另外 export 只會在這一次開機中加入而已,要永久需要下 `vim ~/.bashrc` 再最後加入 `CC=arm-linux-gnueabi-` ```javascript= (以上省略) AR spl/net/built-in.o LDS spl/u-boot-spl.lds LD spl/u-boot-spl OBJCOPY spl/u-boot-spl-nodtb.bin COPY spl/u-boot-spl.bin MKIMAGE MLO MKIMAGE MLO.byteswap SYM spl/u-boot-spl.sym COPY u-boot.dtb MKIMAGE u-boot-dtb.img OFCHK .config ``` ## SD Card 的準備 先談談 sd 卡分幾個區域,一共兩個 ```txt= 格式:FAT32 大小:至少 64MB or 128MB 應該就夠了 用途:存放開機文件 (MLO, u-boot.img) ``` ```txt= 格式:ext4 大小:剩餘空間 用途:Linux 根文件系統 (rootfs),我也把 zImage dtb 放到這邊 /boot/ ``` 操作 ```bash= export DISK=/dev/sdb # 查看 blk lsblk # 0.完全清除 10M sudo dd if=/dev/zero of=${DISK} bs=1M count=10 # 1. 進入 fdisk sudo fdisk /dev/sdb # 2. 建立第一個分區 (FAT32) n # 新分區 p # primary 1 # 分區號碼 1 Enter # 預設起始位置 +64M # 分配 64MB # 3. 建立第二個分區 (ext4) n # 新分區 p # primary 2 # 分區號碼 2 Enter # 預設起始位置 Enter # 使用剩餘所有空間 # 4. 更改第一個分區類型為 FAT32 t # 改變分區類型 1 # 選擇第一個分區 c # FAT32 類型代碼 # 5. 寫入並退出 w # 6. 格式化分區 sudo mkfs.vfat -F 32 -n "BOOT" /dev/sdb1 sudo mkfs.ext4 -L "rootfs" /dev/sdb2 # 查看 lsblk 會出現如下 #sdb 8:16 1 14.5G 0 disk #├─sdb1 8:17 1 64M 0 part #└─sdb2 8:18 1 14.4G 0 part /media/liang/rootfs # 7. 燒入 MLO u-boot.img sudo dd if=./u-boot/MLO of=${DISK} count=1 seek=1 bs=128k sudo dd if=./u-boot/u-boot.img of=${DISK} count=4 seek=1 bs=384k // seek = 1 的 384KB 位置開始,每次寫入 384KB 的資料 // 總共寫入 4 次,所以會寫入 384KB × 4 = 1536KB 的空間 // u-boot.img = 1461412 bytes ≈ 1.46 MB ≈ 1.4 MB // 要寫入的區塊數計算:1461412 bytes / (384 * 1024) bytes ≈ 3.7 區塊 // 設為 count=4 比較安全 // 其它指令 sync //強制同步 lsblk //後方就會出現mountpoints sudo mount /dev/sdb1 /media/liang/rootfs //掛載 sudo umount /dev/sdb1 //移除掛載 hexdump ./u-boot/MLO sudo dd if=/dev/sdb bs=128k count=2 | hexdump -C -n 160 sudo dd if=/dev/sdb bs=128k skip=3 count=5 | hexdump -C -n 160 ``` :::info 建議使用 dd 指令來操作,這樣可以 dump 記憶體方便觀察,如果使用 mount + cp 複製檔案,address 會由檔案系統來管理,較難觀察 ::: > [!NOTE]說明一下 linux 中的 dd 指令 > dd [if=input_file] [of=output_file] [options] > if=: 輸入文件或設備(如 /dev/sda)。 > of=: 輸出文件或設備。 > bs=: 塊大小(單位如 KB、MB),影響每次讀寫的數據量。 > count=: 複製的塊數。 > skip=: 跳過輸入文件中的塊數。 > seek=: 跳過輸出文件中的塊數。 ``` sdb 8:16 1 14.5G 0 disk ├─sdb1 8:17 1 64M 0 part └─sdb2 8:18 1 14.4G 0 part /media/liang/rootfs sudo dd if=/dev/sdb bs=128k count=2 | hexdump -C -n 160 sudo dd if=/dev/sdb1 bs=128k count=2 | hexdump -C -n 160 這兩者差異? 在您的系統中: /dev/sdb 是一個 14.5GB 的完整磁盤 /dev/sdb1 是其上的 64MB 分區 所以這兩個命令會顯示完全不同的內容: 第一個命令會顯示磁盤的引導扇區和分區表信息,MBR(主引導記錄)或 GPT(GUID 分區表) ``` 檔案大小概念(才發現其實linux編完也沒有很大,精華中的精華) ```markdown= MLO: 約 100KB u-boot.img: 約 400KB-1.46 MB uImage: 約 4MB-8MB,功能更多可以到25MB之類的 dtb: 約 30KB-50KB ``` 假設你只有燒入 MLO u-boot.img 應該可以開到 uboot 的 cmd狀態(uboot 會自己倒數,按下任意見進入 shell 交談)  uboot 開起來後最後是 "=>" 的樣子  這邊另外多提一下 rootfs 這件事 > Question 請問 sd card boot 起來帶進 linux kernel 後,他所使用的 rootfs 其實是 sd card 中 rootfs mount 上去的嗎 ? 所以如果再 shell 中操作mkdir 其實會存在 sd card 上 ? 是。當 BeagleBone Black 從 SD 卡啟動後: 1. 開機流程: ``` MLO -> u-boot.img -> uImage (Linux kernel) -> mount rootfs ``` 2. rootfs 掛載: - Kernel 會將 SD 卡上的第二個分區(ext4)掛載為根文件系統 - 這個分區就變成了系統的 `/` 目錄 3. 文件操作: ```bash= mkdir /test # 這個目錄會被創建在 SD 卡的第二個分區上 touch /file # 這個文件也會被保存在 SD 卡上 ``` 4. 持久性: - 所有的文件操作都會直接寫入到 SD 卡 - 關機後這些更改會被保留 - 下次開機時這些文件還會存在 所以,你在==shell 中的所有操作實際上都是在操作 SD 卡上的文件系統==。這邊也呼應sdb2 之所以框比較大就是儲存用 (==) ## rootfs 的製作 當我們在一台 linux 主機上 cd 到 / 會看到好多熟悉的資料夾,主要是這些事已經製作好的 rootfs檔案結構,可以自己一個資料夾自己做,並且設定權限,或載其它 linux 發行好的 rootfs 來應用 ```bash= // https://rcn-ee.com/rootfs/eewiki/minfs/ 裡面可以找到別人做好的 rootfs sudo tar xfvp ./armhf-rootfs-ubuntu-focal.tar -C /media/liang/rootfs/ sync sudo chown root:root /media/liang/rootfs/ sudo chmod 755 /media/liang/rootfs/ # 切到 linux 資料夾中 cd linux kernel_version=`make kernelversion` echo $kernel_version sudo sh -c "echo 'uname_r=${kernel_version}' >> /media/liang/rootfs/boot/uEnv.txt" ``` :::info * tar 指令請背 * sync 指令確保 linux 在緩衝區的資料都會寫入硬碟,通常要等很久 可以使用指令監看 watch -n 1 "cat /proc/meminfo | grep -i dirty" 它會 1s 查看 dirty 一次,數值為 0 代表處理完了  * "sudo chown root:root" 這行有必要嗎 ? 有必要因為一般 / 的owner 以及 group 都應該是 root  * "sudo chmod " 有必要嗎 ? 有必要很多系統目錄使用 755 ls -l / drwxr-xr-x 2 root root 4096 Jan 1 00:00 bin drwxr-xr-x 2 root root 4096 Jan 1 00:00 etc 只有 root 可以 rwx ,其它 group 跟 other 只能 r-x ::: ``` liang@ubuntu:/$ ll total 2097248 drwxr-xr-x 20 root root 4096 三 11 2023 ./ drwxr-xr-x 20 root root 4096 三 11 2023 ../ lrwxrwxrwx 1 root root 7 三 11 2023 bin -> usr/bin/ drwxr-xr-x 4 root root 4096 二 18 23:10 boot/ drwxrwxr-x 2 root root 4096 三 11 2023 cdrom/ drwxr-xr-x 19 root root 4440 二 20 07:33 dev/ drwxr-xr-x 133 root root 12288 二 20 07:37 etc/ drwxr-xr-x 3 root root 4096 三 11 2023 home/ lrwxrwxrwx 1 root root 7 三 11 2023 lib -> usr/lib/ lrwxrwxrwx 1 root root 9 三 11 2023 lib32 -> usr/lib32/ lrwxrwxrwx 1 root root 9 三 11 2023 lib64 -> usr/lib64/ lrwxrwxrwx 1 root root 10 三 11 2023 libx32 -> usr/libx32/ drwx------ 2 root root 16384 三 11 2023 lost+found/ drwxr-xr-x 3 root root 4096 三 6 2024 media/ drwxr-xr-x 3 root root 4096 一 1 17:28 mnt/ drwxr-xr-x 3 root root 4096 三 11 2023 opt/ dr-xr-xr-x 331 root root 0 二 20 07:32 proc/ drwx------ 6 root root 4096 一 1 16:44 root/ drwxr-xr-x 34 root root 1000 二 20 07:37 run/ lrwxrwxrwx 1 root root 8 三 11 2023 sbin -> usr/sbin/ drwxr-xr-x 15 root root 4096 五 24 2023 snap/ drwxr-xr-x 2 root root 4096 八 9 2022 srv/ -rw------- 1 root root 2147483648 三 11 2023 swapfile dr-xr-xr-x 13 root root 0 二 20 07:32 sys/ drwxrwxrwt 18 root root 12288 二 20 07:42 tmp/ drwxr-xr-x 15 root root 4096 一 1 16:36 usr/ drwxr-xr-x 14 root root 4096 八 9 2022 var/ liang@ubuntu:/$ ``` ## Linux 編譯與安裝到 rootfs ```bash= git clone https://github.com/torvalds/linux cd linux export CC=arm-linux-gnueabi- make ARCH=arm multi_v7_defconfig make -j6 ARCH=arm CROSS_COMPILE=${CC} zImage make ARCH=arm dtbs make -j6 ARCH=arm CROSS_COMPILE=${CC} modules #開始安裝複製到 rootfs kernel_version=`make kernelversion` sudo sh -c "echo 'uname_r=${kernel_version}' >> /media/liang/rootfs/boot/uEnv.txt" sudo cp -v arch/arm/boot/zImage /media/liang/rootfs/boot/vmlinuz-${kernel_version} sudo mkdir -p /media/liang/rootfs/boot/dtbs/${kernel_version} sudo cp -v arch/arm/boot/dts/ti/omap/am3 35x-boneblack.dtb /media/liang/rootfs/boot/dtbs/${kernel_version} sudo make -j6 ARCH=arm CROSS_COMPILE=${CC} INSTALL_MOD_PATH=/media/liang/rootfs modules_install # 設定系統檔案表 (?) sudo sh -c "echo '/dev/mmcblk0p1 / auto errors=remount-ro 0 1' >> /media/liang/rootfs/etc/fstab" # 新增加網路設定 sudo nano /media/liang/rootfs/etc/network/interfaces > auto lo > iface lo inet loopback > > auto eth0 > iface eth0 inet dhcp # 到這邊可以先啟動到 u-boot 畫面,剩下部分會在 u-boot裡面介紹 ``` :::info Image: vmlinux的二進位檔案。 zImage: 壓縮過的映像檔,並自帶解壓縮。 uImage: 加了64位元U-boot標頭檔的zImage。 ::: :::info 關於 dtbs 那一行 sudo cp -v arch/arm/boot/dts/*.dtb /media/liang/rootfs/boot/dtbs/${kernel_version} 發現會出現錯誤,原因是在新的 linux 版本中存放位置已經更動,先查詢 liang@ubuntu:~/Desktop/beagle_black/linux$ find ./ -name am335x-boneblack.dtb ./arch/arm/boot/dts/ti/omap/am335x-boneblack.dtb 重新複製要的 dtb 進 sd card ::: > Question 先編譯 zImage 再編譯 modules ? 是。模組可以在系統運行時動態載入/卸載,不會被包含在 zImage 中。 ```bash= # 1. 編譯核心映像 make ARCH=arm CROSS_COMPILE=${CC} zImage # 2. 分開編譯模組 make ARCH=arm CROSS_COMPILE=${CC} modules # 3. 安裝模組(到指定目錄) make ARCH=arm CROSS_COMPILE=${CC} INSTALL_MOD_PATH=/path/to/rootfs modules_install ``` 編譯 dts `make ARCH=arm dtbs`  這是 Linux 內核配置選單中關於記憶體初始化的選項: 三個選項代表不同的堆疊(stack)變數初始化策略: no automatic stack variable initialization: * 最弱的保護 * 不會自動初始化堆疊變數 * 性能最好但最不安全 pattern-init everything: * 使用特定模式初始化所有堆疊變數 * 可以幫助偵測未初始化的變數使用 * 適合除錯 zero-init everything: * 最強且最安全的選項 * 將所有堆疊變數初始化為零 * 可以預防一些安全漏洞 * 性能開銷最大 選擇建議: 開發/除錯時可以選 2 或 3 生產環境如果性能重要可以選 1 安全性要求高的系統建議選 3 > Question dts 用途跟他到底要在哪邊選擇跟執行 ? 最重要的就是 1. 相同的 SoC 但不同開發板: ``` AM335x SoC: - BeagleBone Black (am335x-boneblack.dtb) - BeagleBone Green (am335x-bonegreen.dtb) - Custom Board (am335x-custom.dtb) 都可以使用相同的 zImage,只需要更換對應的 .dtb 文件 ``` 2. 啟動參數設定: 參考 https://hackmd.io/@waterdog/SkHjns_Xyg 優點: - 同一個核心支援多種硬體配置 - 不需要重新編譯核心 - 降低維護成本 - 方便硬體擴展 這就是為什麼 Device Tree 在嵌入式 Linux 開發中如此重要的原因之一。所以在編譯的時候幾本上會針對這個 arch/arm 整個 dts 全部都編譯進去,畢竟檔案大概也才約 30KB-50KB ## 參考連結 文件 * [datasheet](https://docs.beagleboard.org/beaglebone-black.pdf) * [AM335x and AMIC110 Sitara™ Processors](https://www.ti.com/lit/ug/spruh73q/spruh73q.pdf?ts=1735692016626&ref_url=https%253A%252F%252Fwww.ti.com%252Fproduct%252FAM3358) * [Linux DTS(Device Tree Source)设备树详解之一(背景基础知识篇)](https://e-mailky.github.io/2019-01-14-dts-1) * [BeagleBone Black 从零到一 (2 MLO、U-Boot)](https://blog.csdn.net/yuntongsf/article/details/78087717) 影片 * [Building Linux Kernel and Preparing bootable SD CARD for Beaglebone Board](https://www.youtube.com/watch?v=l0746JYroOg) * [Embedded Linux Booting Process (Multi-Stage Bootloaders, Kernel, Filesystem)](https://www.youtube.com/watch?v=DV5S_ZSdK0s) ## 學習歷程建議(滾動式調整)
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up