本文轉(zhuǎn)載自:coldnew's blog
在 zybo board 開發(fā)記錄: Zynq 與 LED 閃爍控制 一文中我們談到了如何透過(guò) C 語(yǔ)言撰寫?yīng)毩⒌某绦?,讓它控?Zynq 的處理器系統(tǒng) (Processing System, PS) 去閃爍 LED 的亮暗。既然 Zynq 的處理器系統(tǒng) (Processing System, PS) 使用的是 ARM Cortex-A9 的處理器,那當(dāng)然也可以讓我們跑 Linux 在 Zybo Board 上。
本文將簡(jiǎn)述如何自行編譯 u-boot 以及 Linux Kernel,并搭配 Busybox 制作簡(jiǎn)單的 RootFS 執(zhí)行于 Zybo Board 上。
開發(fā)目標(biāo)
在這次的開發(fā)中,我們要編譯 u-boot、Linux,并使用 Busybox 制作簡(jiǎn)單的 Rootfs 后,透過(guò)制作 SD 卡來(lái)讓 Zybo Board 透過(guò) SD 卡開機(jī)。
要注意到的是,由于我們要透過(guò) SD 卡開機(jī)進(jìn)入到 Linux 系統(tǒng),因此我們要透過(guò) JP5 去更改開機(jī)模式。
了解開機(jī)流程
既然我們要讓 Zybo board 執(zhí)行 Linux 系統(tǒng),就要先來(lái)了解一下開機(jī)流程,才知道我們大概需要準(zhǔn)備哪些東西。從Zynq-7000 All Programmable SoC: Embedded Design Tutorial - A Hands-On Guide to Effective Embedded System Design (UG1165) 可以看到 Zynq-7000 執(zhí)行 Linux 系統(tǒng)的開機(jī)流程圖。
也就是說(shuō),當(dāng)開始提供電源給 Zynq 處理器系統(tǒng) (Processing System, PS) 并完成重置(reset) 后,Zynq 內(nèi)建的 Boot ROM 會(huì)去加載 第一階段開機(jī)程序 (First Stage Boot Loader, FSBL) ,接著加載 比特流 (bitstream) 去初始化整個(gè) 可程序邏輯(Programmable Logic, PL) 。 完成后,接下來(lái)就是透過(guò) U-Boot 去加載 Linux Kernel、Device Tree 以及 Root File System。
了解了這個(gè),我們就知道我們大概要準(zhǔn)備哪些東西了。
設(shè)定好環(huán)境
在安裝玩 Vivado 與 Xilinx SDK 后,實(shí)際上包含 Zynq 在用的 ARM toolchain 亦同時(shí)被安裝到系統(tǒng)中,我們只要使用 source 命令即可讓當(dāng)前的環(huán)境知道 xilinx-arm toolchain 的路徑。這邊以 Viavdo 2016.2 作為范例。
coldnew@gentoo ~ $ source /opt/Xilinx/Vivado/2016.2/settings64.sh
這樣就可以獲得 arm-xilinx-* toolchain 的命令,實(shí)際上有哪些呢? 輸入個(gè) arm-xilinx- 按下 TAB 看看
如果你系統(tǒng)上已經(jīng)有其他的 ARM toolchain 的話,可以考慮跳過(guò)這一步驟,接下來(lái)要格式化 Micro SD 卡。
格式化 MicroSD 卡
在這次的開發(fā)中,我們要設(shè)定 MicroSD 卡片成兩個(gè)分區(qū),第一個(gè)是 fat32 格式,第二個(gè)則使用 ext4 格式,若不會(huì)使用 fdisk 命令的話,可以透過(guò) gparted 來(lái)進(jìn)行格式化,以下是我格式化卡片的范例 (8GB 卡片)。
(實(shí)際上在本文的范例中,只會(huì)用到第一個(gè)分區(qū),第二個(gè)分區(qū)是為了往后文章要開機(jī)到大一點(diǎn)的 rootfs 準(zhǔn)備的。)
編譯 u-boot
我們首先去 GitHub 下載 DigilentInc 加入 zybo board 后的 u-boot 版本,要注意這邊要選擇 master-next 分支。
git clone https://github.com/DigilentInc/u-boot-Digilent-Dev.git -b master-next
完成后進(jìn)入到該文件夾
coldnew@gentoo ~ $ cd u-boot-Digilent-Dev
編譯 u-boot,記得指派編譯目標(biāo)為 zynq_zybo_config
coldnew@gentoo ~/u-boot-Digilent-Dev $ CROSS_COMPILE=arm-xilinx-linux-gnueabi- make zynq_zybo_config
coldnew@gentoo ~/u-boot-Digilent-Dev $ CROSS_COMPILE=arm-xilinx-linux-gnueabi- make
編譯完成后,注意一下 u-boot 這個(gè)檔案,他就是我們等等要用到的 u-boot 執(zhí)行檔,不過(guò)由于 Xilinx Tool 要找有 .elf 擴(kuò)展名的檔案,因此我們把它復(fù)制成 u-boot.elf 。
coldnew@gentoo ~/u-boot-Digilent-Dev $ cp u-boot u-boot.elf
編譯 Linux kernel
編譯好 u-boot 后,接下來(lái)就是編譯 Linux Kernel 了,我們一樣選擇 DigilentInc 加入 zybo board 后的 Linux Kernel 版本,記得要選 master-next 分支。
git clone https://github.com/DigilentInc/Linux-Digilent-Dev.git -b master-next
接著,當(dāng)然就是編譯了,不過(guò)在這之前請(qǐng)先確定你有裝 u-boot-tools 這套件,我們需要里面的 mkimage 指令,Gentoo Linux 可以直接用以下命令來(lái)安裝。
coldnew@gentoo ~ $ sudo emerge dev-embedded/u-boot-tools
完成后進(jìn)入 Linux Kernel 文件夾
coldnew@gentoo ~ $ cd Linux-Digilent-Dev
編譯我們需要的 uImage 文件,記得要指定 config 為 xilinx_zynq_defconfig 以及設(shè)定 UIMAGE_LOADADDR為 0x8000 。
coldnew@gentoo ~/Linux-Digilent-Dev $ ARCH=arm CROSS_COMPILE=arm-xilinx-linux-gnueabi- make xilinx_zynq_defconfig
coldnew@gentoo ~/Linux-Digilent-Dev $ ARCH=arm CROSS_COMPILE=arm-xilinx-linux-gnueabi- make
coldnew@gentoo ~/Linux-Digilent-Dev $ ARCH=arm CROSS_COMPILE=arm-xilinx-linux-gnueabi- make UIMAGE_LOADADDR=0x8000 uImage
coldnew@gentoo ~/Linux-Digilent-Dev $ ARCH=arm CROSS_COMPILE=arm-xilinx-linux-gnueabi- make zynq-zybo.dtb
編譯完后,我們會(huì)需要 arch/arm/boot/uImage 以及 arch/arm/boot/dts/zynq-zybo.dtb 這兩個(gè)檔案,后者就是 device tree 編譯出來(lái)的數(shù)據(jù)文件。
由于放入到 SD 卡上的 device tree 文件名為 devicetree.dtb ,因此這邊將 zynq-zybo.dtb 改一下名。
coldnew@gentoo ~/Linux-Digilent-Dev $ cp arch/arm/boot/dts/zynq-zybo.dtb devicetree.dtb
如果你想手動(dòng)修改 Device Tree 并再重新編譯的話,也可以這樣去產(chǎn)生我們要的 devicetree.dtb 。
coldnew@gentoo ~/Linux-Digilent-Dev $ ./scripts/dtc/dtc -I dts -O dtb -o devicetree.dtb arch/arm/boot/dts/zynq-zybo.dts
編譯 BusyBox
Busybox 是一個(gè)非常有趣的程序,舉凡我們?cè)?Linux 下最常用的命令如 ls、cd 等到 sed、vi 他都具有相對(duì)應(yīng)的簡(jiǎn)單實(shí)現(xiàn),此外,這些命令實(shí)際上都只是一個(gè)軟連結(jié) (symlink) 連結(jié)到名為 busybox 的執(zhí)行檔,也就是說(shuō),如果我們將 busybox 進(jìn)行靜態(tài)編譯 (static link),則制作出來(lái)的系統(tǒng)整體大小大約為 2 MB (kernel) + 1.4 MB (busybox),而這個(gè)系統(tǒng)卻又可以具有許多 UN*X 下的常用命令,也因此 busybox 很常用于空間有限的系統(tǒng)。
我們?cè)谶@個(gè)開發(fā)過(guò)程中,由于只是驗(yàn)證執(zhí)行 Linux 系統(tǒng)的功能,因此選用 Busybox 來(lái)作為我們的 rootfs。
首先先下載 Busybox 的原始碼,這里選用 1_25_stable 這個(gè)穩(wěn)定分支
git clone git://git.busybox.net/busybox -b 1_25_stable
進(jìn)行我們自己的設(shè)定
coldnew@gentoo ~/busybox $ ARCH=arm CROSS_COMPILE=arm-xilinx-linux-gnueabi- make menuconfig
在進(jìn)行設(shè)定時(shí)有以下幾點(diǎn)要確實(shí)注意,我們要將 busybox 編譯為靜態(tài)鏈接,并且增加 init 功能,主要設(shè)定如下:
Busybox Settings --->
Build Options --->
[*] Build BusyBox as a static binary (no shared libs)
Init Utilities --->
[*] init
Login/Password Management Utilities --->
[*] getty
Shells --->
[*] ash
設(shè)定完成后開始進(jìn)行編譯
coldnew@gentoo ~/busybox $ ARCH=arm CROSS_COMPILE=arm-xilinx-linux-gnueabi- make
編譯完成后透過(guò) make install 命令,會(huì)將編譯出來(lái)的 busybox 與軟連結(jié)(symlink)產(chǎn)生在 _install 文件夾內(nèi)
coldnew@Rosia ~/busybox $ ARCH=arm CROSS_COMPILE=arm-xilinx-linux-gnueabi- make install
建立一些缺少的文件夾 (/dev、/sys …etc)
coldnew@gentoo ~/busybox $ cd _install && mkdir -p proc sys dev etc/init.d root
建立 etc/init.d/rcS 作為啟動(dòng)腳本,并添加以下內(nèi)容
coldnew@gentoo ~/busybox/_install $
vim etc/init.d/rcS
#!/bin/sh
mount -t proc none /proc
mount -t sysfs none /sys
/sbin/mdev -s
將 etc/init.d/rcS 加入可執(zhí)行權(quán)限
coldnew@gentoo ~/busybox/_install $ chmod +x etc/init.d/rcS
建立 etc/inittab ,這會(huì)讓我們可以透過(guò) UART 登入 zybo board
coldnew@gentoo ~/busybox/_install $
vim etc/inittab
#!/bin/sh
#
Init script
::sysinit:/etc/init.d/rcS
#
Start shell on the serial ports
::respawn:/sbin/getty -L ttyPS0 115200 vt100
#
What to do when restarting the init process
::restart:/sbin/init
#
What to do before rebooting
::shutdown:/bin/umount -a -r
設(shè)定默認(rèn)的 /etc/passwd 檔案,我們要讓 root 用戶登入時(shí)不用輸入密碼
coldnew@gentoo ~/busybox/_install $
vim etc/passwd
root::0:0:root:/root:/bin/sh
建立 /init 并軟連結(jié)到 /sbin/init ,避免 Linux Kernel 開機(jī)時(shí)找不到 rootfs 的 init。
coldnew@gentoo ~/busybox/_install $ ln -s /sbin/init init
接下來(lái),由于這次我們只是要開機(jī)到 ramdisk 上的 rootfs, 因此將 busybox 做出的 rootfs 打包成 cpio 格式。
coldnew@gentoo ~/busybox/_install $ find . | cpio -H newc -o | gzip -9 > ../uramdisk.cpio.gz
再透過(guò) mkimage 將這個(gè) uramdisk.cpio.gz 檔案轉(zhuǎn)成 uboot 用的 uramdisk.image.gz
coldnew@gentoo ~/busybox/_install $ mkimage -A arm -T ramdisk -C gzip -d ../uramdisk.cpio.gz ../uramdisk.image.gz
Image Name:
Created:
Sun Jul 17 19:02:08 2016
Image Type: ARM Linux RAMDisk Image (gzip compressed)
Data Size: 1042106 Bytes = 1017.68 kB = 0.99 MB
Load Address: 00000000
Entry Point: 00000000
在這邊的這個(gè) uramdisk.image.gz 就是我們開機(jī)會(huì)進(jìn)入到的 rootfs,也是我們等等要放到 SD 卡第一個(gè)扇區(qū)的檔案。
編譯比特流 (bitstream)
在 zybo board 開發(fā)記錄: 升級(jí) Digilent 提供的設(shè)計(jì)檔 一文中,我們提到了怎樣升級(jí) Digilent 提供的預(yù)先定義好接腳的配置文件 (zybo_base_system) ,這次的項(xiàng)目,我們就直接用這個(gè)配置文件案來(lái)進(jìn)行 Linux 開機(jī)的動(dòng)作。
首先你必須根據(jù)該篇文章,將你的 Zybo board 配置文件案升級(jí)到你用的 Vivado 版本,完成后我們重新建立一個(gè)干凈的項(xiàng)目。
首先先把先前生成的舊項(xiàng)目清掉:
coldnew@gentoo ~/ZYBO/Projects/linux_bd/proj $ sh cleanup.sh
接下來(lái)用 Vivado 2016.2 重新生出新的項(xiàng)目 ~
coldnew@gentoo ~/ZYBO/Projects/linux_bd/proj $ /opt/Xilinx/Vivado/2016.2/bin/vivado -mode batch -source create_project.tcl
完成后,會(huì)看到 ZYBO/Projects/linux_bd/proj 目錄變成這樣:
coldnew@gentoo ~/ZYBO/Projects/linux_bd/proj $
tree -L 1
.
├── cleanup.cmd
├── cleanup.sh
├── create_project.tcl
├── ip_upgrade.log
├── linux_bd.cache
├── linux_bd.hw
├── linux_bd.ip_user_files
├── linux_bd.sim
├── linux_bd.srcs
├── linux_bd.xpr
├── vivado.jou
└── vivado.log
5 directories, 7 files
我們使用 Vivado 打開 linux_bd.xpr 這個(gè)專案。
如果你有興趣看他生出來(lái)的 Block Design 是怎樣的,也可以切到 Block Design 那頁(yè)看看
我們直接點(diǎn)選 Program and Debug -> Generate Bitstream 產(chǎn)生我們要的比特流 (bitstream)
建立 FSBL
到此,我們除了 第一階段開機(jī)程序 (First Stage Boot Loader, FSBL) 外,其他的程序都已經(jīng)編譯出執(zhí)行檔了,讓我們來(lái)處理 FSBL 吧。
首先點(diǎn)選 File -> Export -> Export hardware
記得要勾選 Include bitstream
完成后,執(zhí)行 Xilinx SDK
透過(guò) File -> New -> Application Project 去建立我們的新項(xiàng)目
設(shè)定這個(gè)項(xiàng)目為 standalone 的項(xiàng)目
選擇樣板為 Zynq FSBL
選擇我們剛剛建立的 FSBL 項(xiàng)目,按下右鍵選擇 Build Project 進(jìn)行編譯
建立 BOOT.bin
編譯完 FSBL 后,選擇 Xilinx Tools -> Create Boot Image 去建立我們的 BOOT.bin
在 Boot image partitions 那邊,加入我們的 bitstream 以及 u-boot 檔案,記得要按照順序加入。
完成后,點(diǎn)選 Create Image 就會(huì)產(chǎn)生我們要的 BOOT.bin 到指定路徑。
在這個(gè)步驟中,如果你是指令控的話,我們也可以在產(chǎn)生 FSBL.elf 后,建立一個(gè)名為 boot.bif 的檔案,其內(nèi)容如下
//arch = zynq; split = false; format = BIN
the_ROM_image:
{
[bootloader]/path/to/fsbl-build/fsbl.elf
/path/to/linux_bd/linux_bd.sdk/linux_bd_wrapper.bit
/path/to/u-boot/u-boot.elf
}
接下來(lái)透過(guò) bootgen 這個(gè)命令去產(chǎn)生 BOOT.bin
coldnew@gentoo ~ $ bootgen -image boot.bif -w on -o i boot.bin
將檔案復(fù)制到 Micro SD 卡
好了,我們已經(jīng)完成了所有準(zhǔn)備動(dòng)作,是時(shí)候?qū)n案放到 Micro SD 卡并看看結(jié)果了,在本文中我們會(huì)將以下幾個(gè)檔案放到 第一個(gè)分割區(qū) (fat32) 。
coldnew@gentoo /tmp/sdc1 $
tree -L 1
.
├── BOOT.bin
├── devicetree.dtb
├── uImage
└── uramdisk.image.gz
0 directories, 4 files
也就是說(shuō)我們的 SD 卡有的東西,要像 The Zynq Book p.439 這張圖那樣
測(cè)試開機(jī)與結(jié)果
是時(shí)候來(lái)測(cè)試結(jié)果了,要注意到你的 Zybo Board 的 JP5 要設(shè)定成下面這樣,這樣給電時(shí),Zynq 才會(huì)讀取 SD 卡上面的 u-boot 并將比特流 (bitstream) 刻錄到 FPGA 中。
插入剛剛建立好的 SD 卡,并提供電源后,我們可以使用可以接收 UART 相關(guān)的程序,如 gtkterm、teraterm、screen、emacs 等,啟動(dòng)它并開啟 /dev/ttyUSB1 后,設(shè)定 baudrate 為 115200 ,就可以看到開機(jī)到 rootfs 的狀態(tài)。
取得程序代碼
本文的范例已經(jīng)放置于 GitHub 上,你可以到以下的 repo 去尋找,具體項(xiàng)目對(duì)應(yīng)的教學(xué)名稱,則請(qǐng)參考README.md 檔案
延伸閱讀[1] Zynq-7000 All Programmable SoC: Embedded Design Tutorial - A Hands-On Guide to Effective Embedded System Design (UG1165)
[2] ZYBO Zync-7000 Development Board Work - Booting Linux on the ZYBO
[3] The Zynq Book
評(píng)論
查看更多