iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 2
1

環境建置


今天就為各位讀者解析建置檔案的主要內容。按照這些步驟做完之後,即使只有 x86 的普通主機,也能夠模擬出 RISC-V 的開發環境來玩啦!

概覽

筆者所使用的開發環境的重點元件可依建置順序,列出如下:

  • gnu-toolchain
    • glibc
    • binutils
    • gcc
  • busybox
  • Linux
  • bbl
  • spike

這個思維與直覺剛好相反,就以倒過來的順序講解。對開發者而言,在整個生態已經很完備的情況,如 x86 架構,相關硬體非常容易取得;稍微次級的,如 ARM,開發者也有許多開發版或 FPGA 可以選擇;至於 RISC-V 這種較新的架構,我們就只能選擇模擬器這個方案了。最知名的模擬器當然是 qemu,但有鑑於筆者還未測試過 RISC-V 版 qemu 的功能,於是這裡使用的是官方支援良好的 spike。Spike 不像 qemu 那樣使用動態轉譯的技術,而是一條一條機器碼去如實執行的,當然效能會比較差一些,但是系統的行為也較穩定,易追蹤錯誤。雖然說僅僅是模擬器,但這就是我們手頭上緊有的硬體了。

這個硬體該怎麼啟動呢?也許有讀者第一時間想到的是作業系統這個答案,其實也相去不遠了,但要讓傳統作業系統正常開機,尤其是筆者欲使用的 Linux,我們還需要一個 bootloader 才行。是的,由柏克萊大學團隊開發的 Berkeley bootloader 就是這個 bbl。Bbl 會初始化機器狀態,然後將裝置的資訊傳遞給作業系統知道。目前 bbl 專案已經相當成熟,能夠成功開啟 Linux 與 FreeBSD。

目前的 RISC-V 標準定義三組模式,bbl 運行在最底層的機器模式之中。

Linux 運行在機器模式之上的 Supervisor mode。

使用者空間的程式,運行在 Supervisor mode 之上的 User mode。

接下來的元件,對於有嵌入式系統經驗的讀者想必不陌生。整個環境運行到 Linux 之後,這個作業系統終究要將指揮全繼續移交給使用者空間程式。一般的 x86 伺服器是將服務啟動,安卓手機則是開進他的運行環境;目前的 RISC-V 主要以嵌入式系統為目標,所以使用的是經典的短小精悍 busybox,以連結的形式身兼 shell、init 啟動程式以及多數的 Unix utils。

bbl、Linux 和 busybox 當然都是 RISC-V 軟體,否則怎麼能夠運行在 RISC-V 硬體之上呢?那麼,這些軟體又要如何從原本的 C 語言程式轉換成 ELF 格式的可執行檔?這就是首要建置元件必須是工具鏈的原因。這裡列出三個主要元件,建置順序是 glibc、binutils 以及 gcc,到這裡應該就不難倒過來理解了:為了要能夠使用 gcc 編譯上述軟體專案,過程中必須要有許多二進位工具(如組譯器與連結器)參與,這當然是 binutils 軟體包的責任;在編譯軟體時,也會需要 glibc 作為目標平台的基本函式庫,是最基礎的部份。

目前在 RISC-V 的軟體生態地景之中,GNU 計畫的工具鏈仍然是最穩定的;BSD 世界的話,llvm 編譯器和 lld 連結器都還在追求穩定版本。

以下就分別描述建置各個工具的步驟。

各位讀者請自行設定一個環境變數 RISCV 代表想要安裝以下這些開發工具的路徑,如:
$ export RISCV=/opt/riscv
之類的。

GNU toolchain

$ git clone https://github.com/riscv/riscv-gnu-toolchain # 從上游抓取整個專案
$ cd riscv-gnu-toolchain 				 # 進入目錄
$ git submodule update --init --recursive                # 更新子專案,包含之前提及的 glibc、binutils 以及 gcc
$ mkdir build-linux                                      # 創建一個建置用的資料夾,這樣就不會讓建置過程檔案散落在原始資料夾中
$ ../configure --preifx=$RISCV                           # 使用 autotool 生成 Makefile
$ make -j4 linux && make install                         # 生成 Linux ABI 專用的工具鏈
$ cd .. && mkdir build-elf                               # 創建一個建置用的資料夾,這樣就不會讓建置過程檔案散落在原始資料夾中
$ ../configure --preifx=$RISCV                           # 使用 autotool 生成 Makefile
$ make -j4 && make install                               # 生成 baremetal 專用的工具鏈

這樣一來,在 RISCV 指定的位置就會有這兩套工具鏈安裝完成了。

busybox

$ curl -L https://busybox.net/downloads/busybox-1.27.2.tar.bz2 > busybox.tar.bz2 # 下載 busybox 1.27.2 或更新的版本    
$ tar xvjf busybox.tar.bz2 # 解壓縮
$ cd /busybox-1.27.2       # 進入目錄
$ make menuconfig          # 設置 .config 檔,請參考後續說明
$ make -j4                 # 建置 busybox

那個 menuconfig 琳瑯滿目,如何設定好呢?讀者請參考這個設定,也可以直接將之複製到 busybox 目錄之下並重新命名為 .config,只是要特別注意以下三個組態:

  • CONFIG_CROSS_COMPILER_PREFIX,應該對應到 $RISCV/bin
  • CONFIG_SYSROOT,應該對應到 $RISCV/sysroot
  • CONFIG_PREFIX,應該指定一個作為根目錄的路徑,於後節介紹

根目錄檔案系統的準備

咦?不是應該輪到 Linux 了嗎?筆者必須澄清的是,一般的嵌入式裝置有支援儲存裝置,如 SD 卡,因而可以讓 Linux 核心根據那些儲存裝置內的檔案系統來開機,但是我們的這個開發環境沒有這樣子的硬體條件。因此,我們必須使用 initramfs 的技術,預先編輯好一個根目錄檔案系統,好讓 Linux 內嵌在核心之中,並在開機過程的尾端將之載入記憶體,進入使用者環境。

所以,這裡請各位讀者執行以下步驟:

$ cp -r $RISCV/sysroot $RISCV/rootfs      # 複製一份 sysroot 當作未來 rootfs 的基底     
$ cd $RISCV/rootfs                        # 進入該資料夾
$ mkdir bin dev tmp proc sys              # 創建一些系統目錄
$ cp inittab $RISCV/rootfs/etc/inittab    # 置入 inittab 檔案,可於 repo 中找到
$ ln -s ../bin/busybox sbin/init          # 設定 init 起始檔連結到 busybox
$ ln -s bin/busybox linuxrc               #
$ ln -s sbin/init init                    # 
$ mknod dev/console c 5 1                 # 設置一些必要的虛擬字元裝置
$ mknod dev/null c 1 3                    #

所需的 inittab 請參考 repo 中的設定。接下來就可以回到之前存放busybox 專案目錄並,將 CONFIG_PREFIX 設為 $RISCV/rootfs 之後,執行 make install

Linux

$ git clone https://github.com/riscv/riscv-linux -b linux-4.14            
$ cd riscv-linux                                                          
$ make ARCH=riscv menuconfig
$ wget https://raw.githubusercontent.com/NonerKao/inception/master/initramfs.txt
$ make -j4 ARCH=riscv CROSS_COMPILE=$RISCV/bin/riscv64-unknown-linux-gnu-

同樣的,第三步中的組態設定,可以參考repo 中的設定取得,只要將之命名為 .config 並置放在源碼資料夾內即可。

第四步的檔案是組態中的 CONFIG_INITRAMFS_SOURCE 變數所需要的兩個參數之一。請將之更改為符合 $RISCV 的設定。

bbl

$ git clone https://github.com/riscv/riscv-pk && cd riscv-pk
$ ../configure PATH=$RISCV/bin:$PATH --host=riscv64-unknown-linux-gnu --with-payload=/riscv-linux/vmlinux --prefix=$RISCV
$ make && make install

其中,第二步的 with-payload 代表前一步已經編譯好的 Linux 核心二進位檔 vmlinux,請務必自行調整為正確的路徑。至此,我們已經有了一整個包含 bootloader、OS 以及 busybox 運行環境的統一映像檔,萬事具備,只欠模擬器了!

spike

在這之前可能會需要依發行版的命名原則安裝 device-tree-compiler軟體包。

先安裝一個 front-end 函式庫,這是 spike 執行檔必須的函式庫:

$ git clone https://github.com/riscv/riscv-fesvr && cd riscv-fesvr
$ configure --prefix=$RISCV && make && make install

然後可以安裝 spike :

$ git clone https://github.com/riscv/riscv-isa-sim && cd riscv-isa-sim
$ configure --prefix=$RISCV --with-fesvr=$RISCV && make && make install

執行!


如果一切順利的話,

$ $RISCV/bin/spike $RISCV/riscv64-unknown-elf/bin/bbl

應該就會有 Linux 開機的畫面出現,這就是我們的開發環境了!當然,除了本系列主題之外,讀者諸君也能夠天馬行空地使用這個環境作 RISC-V 相關的研究開發,若是能夠方便各位縮短取得穩定開發環境的時間那就太令人開心了。

接下來等著我們的就是 go 語言與 ELF 的領域了。我們明天再會!

如果安裝遇到問題,請不要猶豫,立刻留言向筆者反應吧!畢竟筆者光是環境架設也已經吃過不少苦頭了...算是久病成良醫吧!


上一篇
第一日:系列文規劃與介紹
下一篇
第三日:go 語言環境建置與 go-binutils 專案簡介
系列文
與妖精共舞:在 RISC-V 架構上使用 GO 語言實作 binutils 工具包30

1 則留言

0
debby83729
iT邦新手 5 級 ‧ 2018-01-05 15:55:19

感謝筆者撰寫如此詳細的文章
有兩個問題想詢問一下筆者

  1. 執行spike bbl後,應該出現怎樣的畫面才是有成功的?
    下圖是我照著以上步驟變異後執行的結果,不知道是否正確?
    https://ithelp.ithome.com.tw/upload/images/20180105/20108187dFwvXSHNqR.png

  2. 以上方式編譯出來的bbl檔案可以給RISCV-QEMU使用嗎?因為目前自己是想要編譯出給RISCV-QEMU使用的riscv-linux image,但github上給的方法是使用較舊的版本,riscv-linux已經沒有該版本的source code了,且他們也說他們的文章已out-of-date,不知道筆者有沒有建議使用哪種方式編譯可以給RISCV-QEMU使用的riscv-linux image,謝謝!!

恭喜您成功了!這個畫面表示 busybox 的 ash 有起來。如果需要 qemu 的設置,請參考另外一篇拙作:
https://ithelp.ithome.com.tw/articles/10194447

感謝您的回饋!

我要留言

立即登入留言