milkv-duo啟動流程分析:手動構建fip.bin [1/2]

来源:https://www.cnblogs.com/maomaotou-thu/archive/2023/10/15/17765721.html
-Advertisement-
Play Games

目錄構建riscv64-unknown-linux-musl編譯工具鏈直接下載官方工具鏈嘗試自己編譯T-head Gcc下載編譯binutils編譯交叉gcc編譯musl手動合成fip.bin和boot.sd編譯u-boot生成cvi_board_memmap.h,cvipart.h和imgs.h繼 ...


目錄

Milk-V Duo是一個基於CV1800B晶元的超緊湊嵌入式開發平臺。它可以運行Linux和RTOS,為專業人士、工業ODM、AIoT愛好者、DIY愛好者和創作者提供了一個可靠、低成本和高性能的平臺。在這樣一個平臺上跑上buildroot就變得意義非凡。

構建riscv64-unknown-linux-musl編譯工具鏈

直接下載官方工具鏈

MilkV Duo官方給了我們工具鏈的下載地址,但是由於存sdk的倉庫內容被清空,不再被維護,並且下載地址被隱藏在release裡邊,太難找了,所以我就假裝我沒找到官方的工具鏈,看看軟體源里有沒有riscv64的編譯器。

嘗試自己編譯T-head Gcc

使用

apt search riscv64

一搜,還真有結果。

binutils-riscv64-linux-gnu/jammy-updates,jammy-security 2.38-4ubuntu2.3 amd64
  GNU binary utilities, for riscv64-linux-gnu target

gcc-riscv64-linux-gnu/jammy 4:11.2.0--1ubuntu1 amd64
  GNU C compiler for the riscv64 architecture

於是安裝了這倆,然後做了點測試,發現它並不支持平頭哥c906fdv架構,所以我們還是需要使用官方給出的編譯鏈。但是由於我假裝看不見官方的release下載地址,就抱著play的心態,嘗試自己構建一個工具鏈。riscv64是我們的目標架構,unknown是vendor,即廠商名,這裡被指定為unknown。linux就是OS平臺,musl是一種新的c庫。既然官方用musl,那我也跟著用吧。

平頭哥魔改過的包含c906fdv處理器的gcc源代碼在T-head-Semi/gcc,我們把它clone下來

git clone https://github.com/T-head-Semi/gcc.git

下載編譯binutils

Binutils是一組開源的二進位工具集合,用於創建、操作和分析可執行文件、目標文件和庫文件。它由一系列工具組成,包括彙編器(as)、鏈接器(ld)、目標文件工具(objdump、readelf等)和調試器(gdb)等。這些工具被廣泛用於開發和維護各種操作系統、編譯器和軟體工具鏈。Binutils可以用於多種體繫結構和操作系統,包括x86、ARM、MIPS、PowerPC等,支持多種操作系統如Linux、Windows、macOS等。它們提供了一些核心功能,如將彙編代碼轉換為可執行文件、將目標文件鏈接為可執行文件、提取和修改目標文件的符號和節(sections)信息,以及執行調試操作。通過使用Binutils,開發人員可以進行底層的二進位文件操作和分析,包括反彙編、符號表查看、調試信息提取等。它們對於編譯器開發、操作系統開發、嵌入式系統開發等方面非常有用,也是構建軟體工具鏈的重要組成部分。

在編譯GCC(GNU Compiler Collection)之前,需要準備Binutils,原因如下:

  • 鏈接器(ld):GCC在編譯過程中需要使用鏈接器將編譯後的目標文件(.o文件)鏈接成最終的可執行文件。鏈接器負責解析符號引用、符號重定位以及生成最終可執行文件的各個節(sections)。Binutils中的ld是一個功能強大的鏈接器,被GCC用作預設的鏈接器。

  • 彙編器(as):GCC在編譯源代碼時,會將源代碼翻譯成彙編代碼。然後,彙編器將彙編代碼轉換成相應的機器碼,並生成目標文件。Binutils中的as是GCC預設使用的彙編器。

  • 目標文件工具(objdump、readelf等):在編譯過程中,可能需要查看、分析和調試目標文件的內容。Binutils提供了一些工具,如objdump和readelf,用於查看目標文件的符號表、節表、重定位信息等。這些工具對於調試編譯器生成的目標文件或庫文件非常有用。

因此,為了編譯GCC,需要安裝並準備Binutils,以確保編譯器能夠正確地使用其中的鏈接器、彙編器和目標文件工具。Binutils提供了一套強大的二進位工具,為GCC的編譯過程提供了必要的支持。

我們不可以直接使用apt安裝的binutils,因為預設的binutils提供的ld的生成的目標文件是x86架構的。如果直接安裝binutils-riscv64-linux-gnu,我們還需要手動把頭文件複製一遍,把二進位文件也改名一遍,這樣做很麻煩,所以我們應當直接make -j64&&make install,這樣還能順便把頭文件都給我們塞好。

首先我們把binutils的代碼wget下來,然後創建一個build目錄,專門用於編譯,再創建一個目錄,用於存放install的結果。

# 進入binutils目錄
cd binutils
# 創建build目錄
mkdir build
cd build
# 配置binutils,prefix是install的時候生成文件的存放地址
../configure --prefix=/opt/riscv --target=riscv64-unknown-linux-musl
make -j64&&make install

這樣之後,/opt/riscv目錄下就出現了bin、include等不少文件。

編譯交叉gcc

同樣,我們進入平頭哥gcc的目錄,創建一個build目錄,然後配置

../configure --prefix=/opt/riscv --target=riscv64-unknown-linux-musl --with-sysroot=/opt/riscv
make all-gcc
make install-gcc

在編譯GCC時,--with-sysroot選項用於指定系統根目錄(sysroot)。系統根目錄是一個包含完整系統文件層次結構的目錄,通常用於交叉編譯環境中。

設置--with-sysroot選項的目的是告訴GCC編譯器在指定的系統根目錄下查找頭文件、庫文件和其他系統資源,以便正確地構建和鏈接目標程式。這在交叉編譯環境中特別重要,其中編譯器和目標平臺的操作系統不匹配。

通過將--with-sysroot選項設置為系統根目錄的路徑,GCC將使用該路徑作為基準,查找和引用目標平臺所需的系統文件。這包括標準C庫、頭文件、共用庫、鏈接器腳本等。使用--with-sysroot選項可以確保編譯器能夠正確地定位和使用目標平臺的系統資源。

在交叉編譯環境中,你還需要設置其他相關的選項,如--target選項指定目標平臺體繫結構,以及--prefix選項指定安裝位置等。這些選項的設置將根據你的具體需求和目標平臺而有所變化。

需要註意的是,--with-sysroot選項並不適用於本地編譯,因為本地編譯時GCC可以直接使用主機操作系統的系統資源。它主要用於交叉編譯環境,以確保編譯器在正確的系統根目錄下查找和使用目標平臺的系統文件。

在編譯的過程中,我們遇到了報錯,提示缺少/opt/riscv/usr/include的頭文件。因此,我們還需要編譯musl

編譯musl

去官網下載musl的代碼,然後編譯。

mkdir build
cd build
../configure --prefix=/opt/riscv
make
make install

此時繼續編譯gcc,仍然會遇到報錯,提示缺少/opt/riscv/usr/include的頭文件。我們把/opt/riscv/include下的文件直接複製過去就行。
然後再次make install-gcc

此時就完成了工具鏈的編譯

手動合成fip.bin和boot.sd

為了扔進buildroot,先要摸透每個流程。

編譯u-boot

官方sdk給出了魔改過的uboot,有關的代碼也scatter在不知道什麼地方。根據目前的探查,我們需要把build目錄下的

  • build/boards/cv180x/cv1800b_milkv_duo_sd/u-boot/cvi_board_init.c複製到u-boot/board/cvitek/目錄下
  • build/boards/cv180x/cv1800b_milkv_duo_sd/u-boot/cvitek.h複製到u-boot/include/cvitek/目錄下
  • build/boards/cv180x/cv1800b_milkv_duo_sd/u-boot/cvitek_cv1800b_milkv_duo_sd_defconfig複製到u-boot/configs目錄下

生成cvi_board_memmap.hcvipart.himgs.h

執行make -j64,報錯,提示沒有cvi_board_memmap.h。進入build目錄,找到scripts/mmap_conv.py,執行

./build/scripts/mmap_conv.py --type h ./build/boards/cv180x/cv1800b_milkv_duo_sd/memmap.py u-boot/include/cvi_board_memmap.h

繼續生成cvipart.h

python3 build/tools/common/image_tool/mkcvipart.py build/boards/cv180x/cv1800b_milkv_duo_sd/partition/partition_sd.xml u-boot/include

繼續生成imgs.h

python3 build/tools/common/image_tool/mk_imgHeader.py build/boards/cv180x/cv1800b_milkv_duo_sd/partition/partition_sd.xml u-boot/include

這個cvi_board_memmap.h在後續開發中也很重要,要記住位置。

繼續編譯u-boot

執行make -j64 CROSS_COMPILE=riscv64-unknown-linux-gnu-,編譯時發現彙編器不認csrr寄存器。

board/cvitek/cv180x/board.c: Assembler messages:
board/cvitek/cv180x/board.c:327: Error: unrecognized opcode `csrr a5,0xc01', extension `zicsr' required

所以我們進入arch/riscv/Makefile,做出以下改動

ARCH_EX = _zicsr_zifencei

ARCH_FLAGS = -march=$(ARCH_BASE)$(ARCH_A)$(ARCH_C)$(ARCH_EX) -mabi=$(ABI) \
	     -mcmodel=$(CMODEL)

再次編譯,發現又報錯了

common/command.c:586:20: error: conflicting types for ‘cmd_process’ due to enum/integer mismatch; have ‘enum command_ret_t(int,  int,  char * const*, int *, ulong *)’ {aka ‘enum command_ret_t(int,  int,  char * const*, int *, long unsigned int *)’} [-Werror=enum-int-mismatch]
  586 | enum command_ret_t cmd_process(int flag, int argc, char *const argv[],
      |                    ^~~~~~~~~~~
In file included from common/command.c:13:
include/command.h:234:5: note: previous declaration of ‘cmd_process’ with type ‘int(int,  int,  char * const*, int *, long unsigned int *)’
  234 | int cmd_process(int flag, int argc, char *const argv[], int *repeatable,
      |     ^~~~~~~~~~~

找到common/command.c:586,把返回值類型改成int,問題解決。繼續編譯,又遇到

riscv64-buildroot-linux-musl-ld.bfd: warning: u-boot has a LOAD segment with RWX permissions
  OBJCOPY u-boot.srec
  OBJCOPY u-boot-nodtb.bin
  SYM     u-boot.sym
make[2]: *** No rule to make target 'arch/riscv/dts/_.dtb', needed by 'dtbs'.  Stop.
make[1]: *** [dts/Makefile:45: arch-dtbs] Error 2
make: *** [Makefile:1145: dts/dt.dtb] Error 2
make: *** Waiting for unfinished jobs....

我們首先把build/boards/下的設備樹都複製到uboot/arch/riscv/dts

  • build/boards/default/dts/cv180x/cv180x_base.dtsi
  • build/boards/default/dts/cv180x_riscv/cv180x_base_riscv.dtsi
  • build/boards/default/dts/cv180x/cv180x_asic_qfn.dtsi
  • build/boards/default/dts/cv180x/cv180x_asic_sd.dtsi
  • build/boards/default/dts/cv180x/cv180x_default_memmap.dtsi
  • build/boards/cv180x/cv1800b_milkv_duo_sd/dts_riscv/cv1800b_milkv_duo_sd.dts

然後在u-boot-2021.10/arch/riscv/dts/Makefile中,修改:

dtb-$(CONFIG_TARGET_CVITEK) += cv1800b_milkv_duo_sd.dtb

然後在u-boot-2021.10/dts/Makefile中,取消註釋,修改:

DTB := arch/$(ARCH)/dts/$(DEVICE_TREE).dtb

同時,進入make menuconfig,設置CONFIG_DEFAULT_DEVICE_TREE=cv1800b_milkv_duo_sd

再次嘗試編譯,編譯通過

LD      u-boot
riscv64-unknown-linux-gnu-ld.bfd: warning: u-boot has a LOAD segment with RWX permissions
  OBJCOPY u-boot.srec
  OBJCOPY u-boot-nodtb.bin
  SYM     u-boot.sym
  CAT     u-boot-dtb.bin
  COPY    u-boot.bin
  LD      u-boot.elf

編譯opensbi

根據:

opensbi: export CROSS_COMPILE=$(CONFIG_CROSS_COMPILE_SDK)
opensbi: u-boot-build
  $(call print_target)
  ${Q}$(MAKE) -j${NPROC} -C ${OPENSBI_PATH} PLATFORM=generic \
      FW_PAYLOAD_PATH=${UBOOT_PATH}/${UBOOT_OUTPUT_FOLDER}/u-boot-raw.bin \
      FW_FDT_PATH=${UBOOT_PATH}/${UBOOT_OUTPUT_FOLDER}/arch/riscv/dts/${CHIP}_${BOARD}.dtb

翻譯成人話,我們推測,我們應該執行:

make -j64 CROSS_COMPILE=riscv64-buildroot-linux-musl- PLATFORM=generic \
  FW_PAYLOAD_PATH=../u-boot-2021.10/u-boot.bin \
  FW_FDT_PATH=../u-boot-2021.10/arch/riscv/dts/cv1800b_milkv_duo_sd.dtb

編譯後,又報錯:

Error: unrecognized opcode `fence.i', extension `zifencei' required

修改Makefile

ifndef PLATFORM_RISCV_ISA
  ifneq ($(PLATFORM_RISCV_TOOLCHAIN_DEFAULT), 1)
    PLATFORM_RISCV_ISA = rv$(PLATFORM_RISCV_XLEN)imafdc_zicsr_zifencei
  else
    PLATFORM_RISCV_ISA = $(OPENSBI_CC_ISA)
  endif
endif

此時編譯通過,生成

 OBJCOPY   platform/generic/firmware/payloads/test.bin
 OBJCOPY   platform/generic/firmware/fw_dynamic.bin
 OBJCOPY   platform/generic/firmware/fw_jump.bin
 OBJCOPY   platform/generic/firmware/fw_payload.bin

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • for遍歷 一:常規方式 1.遍曆數組 int arr[10] = {1,2,3,4,5,6,7,8,9,10}; for(int i = 0;i<10;i++) { cout<<arr[i]; } 3.遍歷容器類(迭代器) vector<int> s = {0,1,2,3,4,5,6,7,8,9} ...
  • 基本數據類型 標準數據類型 常見數據類型: Number(數字) String(字元串) bool(布爾類型) List(列表) Tuple(元組) Set(集合) Dictionary(字典) 六個標準數據類型中: 不可變數據(3 個):Number(數字)、String(字元串)、Tuple(元 ...
  • 本文介紹在Anaconda中,為Python的虛擬環境安裝第三方庫與Spyder等配套軟體的方法。 在文章創建Anaconda虛擬Python環境的方法中,我們介紹了在Anaconda環境下,創建、使用與刪除Python虛擬環境的方法;而創建虛擬環境後,就需要在對應的環境內配置各類庫與軟體,本文就對 ...
  • 代碼地址: https://gitee.com/Aes_yt/middleware-demo/tree/master/rabbitmq 安裝RabbitMq 1. docker拉取鏡像 docker pull rabbitmq:3.9.29-management 2. 創建rabbitmq容器 do ...
  • 自從開始搞YouTube中文配音以來,我們一直是7*24小時,夜以繼日的在批量處理一些優質的學習資源,一方面是翻譯,另一方面是配音。這樣用戶在打開的時候,就能獲得經過我們優化的翻譯和配音了。 這次我們剛剛處理完一個油管上非常火爆的​IT類學習頻道:Edureka。 該頻道內全是IT行業的免費學習視頻 ...
  • math庫常用函數+產生隨機數總結 1.對x開平方 double sqrt(x);//返回值為double類型,輸入的x類型隨意,只要是數的類型 2.求常數e的x次方 double exp(x);//返回值為double類型,輸入的x類型隨意,只要是數的類型 3.求x的y次方 double pow( ...
  • TLS雙向認證的基本原理及示意流程圖,幫助更好的理解TLS的加密功能,及安全能力,此外還給出了部分源碼的實現及Token實現在的方案及能力 ...
  • 在我們WPF應用端的時候,和WInform開發或者Vue前端開發一樣,有時候也需要對內容進行轉義處理,如把一些0,1數值轉換為具體含義的文本信息,或者把一些布爾變數轉換為是否等,都是常見的轉換處理,本篇隨筆介紹在WPF應用端對內容使用Converter類實現內容的轉義處理的操作。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...