www.久久久久|狼友网站av天堂|精品国产无码a片|一级av色欲av|91在线播放视频|亚洲无码主播在线|国产精品草久在线|明星AV网站在线|污污内射久久一区|婷婷综合视频网站

當(dāng)前位置:首頁 > 公眾號精選 > 嵌入式IoT

RISC-V64 opensbi啟動過程

  • 1.說明

  • 2.環(huán)境準(zhǔn)備

    • 2.1 交叉編譯工具鏈

    • 2.2 源代碼準(zhǔn)備

  • 3.riscv架構(gòu) gdb調(diào)試方法

  • 4.opensbi底層初始化流程

    • 4.1 從qemu的加載執(zhí)行開始

    • 4.2 opensbi底層初始化

    • 4.2 opensbi設(shè)備初始化

    • 4.3 二級boot的跳轉(zhuǎn)

  • 5.小結(jié)

1.說明

最近有一些riscv的項目做,雖然以前也用過例如k210之類的riscv架構(gòu)的芯片,但是都止于能夠做一些應(yīng)用,并未特別關(guān)注其芯片的體系架構(gòu)方面的東西,但是隨著接觸的芯片架構(gòu)的種類的逐漸的增加,發(fā)現(xiàn)要想使用一款好芯片的,僅僅做上層應(yīng)用并不能完全發(fā)揮出特定架構(gòu)芯片的全部優(yōu)勢。比如aarch64的el層級和虛擬化的模型,mips的mmu特性,以及sparc的窗口寄存器等等,芯片架構(gòu)的特點要是能夠完全的發(fā)揮出來,寫起應(yīng)用起來,那真是覺得很爽的事情。

目前在工作上做一些riscv項目,發(fā)現(xiàn)自己的積累的知識不夠了,還是需要深入到底層去理解,于是需要瘋狂的惡補(bǔ)相關(guān)的知識,看文檔、讀代碼、每天就這樣深入其中,看的多了,想法也很多,很容易就忘記了,有時也做做筆記,晚上下班后再將資料整理一下,如果覺得有些價值的東西,就編寫成文章,分享經(jīng)驗。

學(xué)習(xí)使用riscv64的芯片的架構(gòu),首先可以了解學(xué)習(xí)opensbi,作為芯片啟動的Bios,其作用不言而喻。工欲善其事,必先利其器。一個良好高效的開發(fā)環(huán)境將會使得分析代碼變得得心應(yīng)手。本文在Ubuntu18.04環(huán)境下進(jìn)行測試,在riscv64的qemu上進(jìn)行g(shù)db的單步調(diào)試,主要分析的階段是qemu啟動后,執(zhí)行到opensbi,直到啟動uboot的階段。

opensbi是研究和學(xué)習(xí)riscv底層的一個比較優(yōu)秀的項目,代碼量小,質(zhì)量也很高,很值得推薦的一個開源項目。

關(guān)于opensbi與qemu的環(huán)境搭建,我前面的文章中已經(jīng)提及,這里就不贅述了。

riscv64 qemu上進(jìn)行Linux環(huán)境搭建與開發(fā)記錄

2.環(huán)境準(zhǔn)備

2.1 交叉編譯工具鏈

如果按照之前的文章下載的Linux版本的交叉編譯工具鏈?zhǔn)遣粠в術(shù)db工具,所以可以下載一個bare/rtos版本的gcc。建議下載sifive的riscv的交叉編譯工具鏈

https://www.sifive.com/software

也可以到網(wǎng)盤下載:

https://pan.baidu.com/s/1_C-cFBD3ADVjVFm94bYzNw 
提取碼: v38x 

下載完成后解壓至自定義的文件夾中即可。

2.2 源代碼準(zhǔn)備

1.qemu最新版

2.opensbi

3.uboot

這些都可以參考文章:

riscv64 qemu上進(jìn)行Linux環(huán)境搭建與開發(fā)記錄

3.riscv架構(gòu) gdb調(diào)試方法

首先需要編譯安裝完成qemu-system-riscv64。

編譯uboot,進(jìn)入uboot:

make CROSS_COMPILE=riscv64-linux- qemu-riscv64_smode_defconfig
make CROSS_COMPILE=riscv64-linux- -j4

可見在uboot目錄生成u-boot.bin文件。

編譯opensbi,進(jìn)入opensbi:

git clone https://github.com/riscv/opensbi.git export CROSS_COMPILE=riscv64-linux-
make PLATFORM=generic FW_PAYLOAD_PATH=/u-boot.bin

可以生成build/platform/generic/firmware/fw_payload.elf文件。

在控制臺輸入

../riscv64-unknown-elf-gcc-8.3.0-2020.04.0-x86_64-linux-ubuntu14/bin/riscv64-unknown-elf-gdb build/platform/generic/firmware/fw_payload.elf -s -S

即可進(jìn)入調(diào)試模式。其中需要知道的是-s -S,如果不加這兩個參數(shù),系統(tǒng)會直接運(yùn)行起來??勺鳛榄h(huán)境搭建是否成功的判斷依據(jù)。

當(dāng)進(jìn)入調(diào)試模式后,當(dāng)前代碼會hold住,可以ctrl+t另外開一個窗口,輸入

../riscv64-unknown-elf-gcc-8.3.0-2020.04.0-x86_64-linux-ubuntu14/bin/riscv64-unknown-elf-gdb build/platform/generic/firmware/fw_payload.elf

然后輸入

(gdb) target remote localhost:1234

如下圖所示:

gdb的命令很多,這里就不展開進(jìn)行細(xì)致的描述了,這里只演示一些基本的操作。

首先可以看到當(dāng)程序加載完成后,已經(jīng)hold等待gdb命令進(jìn)行操作。

輸入list可以列出當(dāng)前的代碼,每次list可以展示10行源代碼。

輸入si可以進(jìn)行匯編級別的單步調(diào)試。

直接回車是繼續(xù)執(zhí)行上一條執(zhí)行的命令。

繼續(xù)向下跳轉(zhuǎn)可以看到函數(shù)的入口和函數(shù)的名稱。

輸入info all-registers可以看到riscv所有寄存器的值的狀態(tài),這里剛到入口處寄存器怎么會有初值呢?這里就是很關(guān)鍵的問題,后面再分析代碼的時候,會詳細(xì)分析這些問題。另外可以分析得出當(dāng)前的函數(shù)的入口0x80000000。

另外經(jīng)常使用的就是打斷點

b 10

表示打斷點在第10行。

b main

表示斷點在main函數(shù)處。

輸入c可以讓程序連續(xù)運(yùn)行,直到遇到斷點才停下來。

這些功能在跟蹤代碼的運(yùn)行流程的時候比較實用,gdb還有許多功能,這里就不介紹了。

4.opensbi底層初始化流程

上面做了這么多環(huán)境搭建方面的工作,目的就是為了方便的分析opensbi的底層初始化步驟和流程。從而更加深刻的了解riscv的架構(gòu)和初始化流程。

4.1 從qemu的加載執(zhí)行開始

首先需要從qemu的源代碼開始進(jìn)行加載分析起,當(dāng)前qemu-system-riscv64支持下面的開發(fā)板:

而在qemu的源代碼中也有一些

這里我們就拿virt進(jìn)行分析。

根據(jù)hw/riscv/virt.c來看,首先可以分析得到外設(shè)分布的地址。

上述可以得到DRAM的地址空間是從0x80000000處開始的,而大小是我們傳遞參數(shù)時傳遞進(jìn)去的。另外也記錄了一些外設(shè)的布局。

qemu加載程序之前的時候,與具體板子相關(guān)的部分,首先進(jìn)入了hw/riscv/virt.c的virt_machine_init。

1.注冊PLIC中斷設(shè)備

這里需要注意的是VIRT_PLIC,在PLIC core這部分與riscv的中斷處理相關(guān)。

2.注冊系統(tǒng)內(nèi)存

這部分的內(nèi)存大小由外部傳遞

3.創(chuàng)建設(shè)備樹

qemu也使用fdt創(chuàng)建了設(shè)備樹,該設(shè)備樹用于opensbi和uboot,這里的設(shè)備樹放在qemu分配的內(nèi)存的尾部。并且會將該參數(shù)傳遞,這就是為什么前面進(jìn)行g(shù)db調(diào)試時,入口處會發(fā)現(xiàn)寄存器上有參數(shù)。

根據(jù)riscv的寄存器的規(guī)則

寄存器a0-a7是用于傳遞函數(shù)參數(shù)的。另外這個設(shè)備樹的參數(shù)會直接傳遞到opensbi進(jìn)行解析和適配。同時uboot也會使用這個設(shè)備樹。

4.2 opensbi底層初始化

最先進(jìn)來的是opensbi/firmware/fw_payload.S的_start函數(shù)。

1.判斷hart id

在riscv模式中會將riscv的core稱為hart

2.代碼重定位

會判斷_load_start與_start是否一致,若不一致,則需要將代碼重定位,該項目不用重定位。

3.清除寄存器值

這里會清除sp、gp、tp、t1-t6、s0-s11、a3-a7。注意保存設(shè)備數(shù)地址的a1、a2不會清除。

5.清除bss段

如果要想c語言執(zhí)行起來,必須要做的事情有兩個,一個是設(shè)置sp棧地址,另外就是清除bss段。

6.設(shè)置sp棧指針

這里棧的指針的地址也很有意思,設(shè)置的bss結(jié)尾,由于棧是向上增加的,所以預(yù)留棧的空間大小為2000。

7.讀取設(shè)備樹中的設(shè)備信息

執(zhí)行call fw_platform_init函數(shù),前面分析過該函數(shù)的原型在opensbi/platform/generic/platform.c。

帶四個參數(shù)。

unsigned long fw_platform_init(unsigned long arg0, unsigned long arg1,
 unsigned long arg2, unsigned long arg3,
 unsigned long arg4)
{
 const char *model;
 void *fdt = (void *)arg1;
 u32 hartid, hart_count = 0;
 int rc, root_offset, cpus_offset, cpu_offset, len;

 root_offset = fdt_path_offset(fdt, "/"); if (root_offset < 0)
 goto fail;

 fw_platform_lookup_special(fdt, root_offset);

 model = fdt_getprop(fdt, root_offset, "model", &len); if (model)
 sbi_strncpy(platform.name, model, sizeof(platform.name)); if (generic_plat && generic_plat->features)
 platform.features = generic_plat->features(generic_plat_match);

 cpus_offset = fdt_path_offset(fdt, "/cpus");

攜帶四個參數(shù),根據(jù)匯編規(guī)則,正好傳遞a0,a1,a2,a3這四個參數(shù),a0是0,a1是設(shè)備樹地址,a2是設(shè)備樹大小,a3是0。

正好將這些信息利用起來了,然后從設(shè)備樹中解析qemu中設(shè)定相關(guān)的信息。

這樣的好處是只要入口地址一致,就算設(shè)備地址不一樣,也不用重新編譯opensbi了。這就是有了設(shè)備樹的好處。

8.fdt重定位

按照riscv的寄存器使用規(guī)則,a0-a7都是用于存放C語言函數(shù)參數(shù)的,下次執(zhí)行c語言參數(shù)就清除掉了,所以需要把設(shè)備樹從定位,從而讓uboot也知道。

9.跳轉(zhuǎn)到sbi_init

到這里,一些底層初始化的關(guān)鍵性細(xì)節(jié)就結(jié)束了,進(jìn)入sbi的正式的程序中去了。

首先執(zhí)行的opensbi/lib/sbi/sbi_init.c的sbi_init函數(shù)

4.2 opensbi設(shè)備初始化

在進(jìn)入sbi_init會首先判斷是通過S模式還是M模式啟動,這里先知道在qemu的設(shè)備樹中是以S模式啟動。

所以直接會執(zhí)行init_coldboot(scratch, hartid);,該函數(shù)的實現(xiàn)在opensbi/lib/sbi/sbi_scratch.c中。

看一下冷啟動會做那些初始化工作。主要關(guān)注

1.sbi_domain_init

初始化動態(tài)加載的鏡像的模塊

2.sbi_platform_early_init

平臺的早期初始化

3.sbi_console_init

控制臺初始化,從這里開始,就可以使用串口輸出了。

4.sbi_platform_irqchip_init

irq中斷初始化

5.sbi_ipi_init

核間中斷初始化

6.sbi_tlb_init

mmu的tlb表的初始化

7.sbi_timer_init

timer初始化

8.sbi_hsm_prepare_next_jump

準(zhǔn)備下一級的boot

4.3 二級boot的跳轉(zhuǎn)

上述條件為二級boot的跳轉(zhuǎn)準(zhǔn)備了環(huán)境,此時可以加載uboot,或者rtos,或者Linux了。

5.小結(jié)

對于riscv的opensbi的大致的執(zhí)行流程就分析到這里,基本上概括了一個整體的執(zhí)行的流程,具體的細(xì)節(jié)可以通過閱讀代碼,加上代碼注釋進(jìn)行理解。本文只是一個map,大致的流程圖,很多細(xì)節(jié)沒有涉及到。如果去專研具體的細(xì)節(jié)部分,感覺還是有很多東西值得學(xué)習(xí)。opensbi是一個很好的開源項目,對于研究riscv的底層實現(xiàn),以及代碼的通用性上都很值得借鑒和學(xué)習(xí)。


本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內(nèi)容真實性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除。
關(guān)閉