opensbi单独构建与GDB仿真调试

文摘   2024-08-25 22:56   湖南  

一. 前言

这一篇分享OpenSBI的单独构建,Kconfig配置以及使用GDB进行仿真。

为了方便编辑阅读,我们安装VSCODE

Windows主机下安装VSCODE,这里略去过程。

进入ubuntu终端

输入code自动安装vscode

qinyunti@LAPTOP-2SG60VPF:~$ codeUpdating VS Code Server to version b1c0a14de1414fcdaa400695b4db1c0799bc3124Removing previous installation...Installing VS Code Server for Linux legacy-x64 (b1c0a14de1414fcdaa400695b4db1c0799bc3124)Downloading: 100%Unpacking: 100%Unpacked 1754 files and folders to /home/qinyunti/.vscode-server/bin/b1c0a14de1414fcdaa400695b4db1c0799bc3124.

安装完后自动打开vscode

.单独构建OpenSBI

官方仓库

https://github.com/riscv-software-src/opensbi.git

玄铁仓库

https://github.com/c-sky/opensbi.git

我们这里使用玄铁的,因为要保证工具链和仓库相对应,opensbi最新的可能玄铁老的工具链一些特性不支持。

https://github.com/c-sky/opensbi.git

下载代码进入目录

git clone https://github.com/c-sky/opensbi.git

cd opensbi

设置工具链

export CROSS_COMPILE=~/buildroot/thead_9xxf_enhanced_5.10_glibc_br_defconfig/host/bin/riscv64-unknown-linux-gnu-

设置平台位宽

export PLATFORM_RISCV_XLEN=64

make

报错

/usr/bin/env: bash\r: No such file or directory

修改makefile文件LFCR改为LF

以上只是编译.a文件 ,位于build/lib

要编译固件则需要配置PLATFORM,并且使用menuconfig进行配置

make PLATFORM=generic menuconfig

报错

/usr/bin/env: ‘python3\r’: No such file or directory

是因为windows下是LFCRlinux下都要用LF,如果在windows下用gitbash下载会自动加LFCR,此时就不能直接在linux下构建。所以避免麻烦,直接在linuxgit clone代码。

默认menuconfig后保存为generic/kconfig/.configKconfig相关配置下一节介绍。

配置完后构建

make PLATFORM=generic 

生成的固件位于

build/platform/generic/firmware/

.Kconfig配置

通过menuconfigKconfig文件可以了解程序的基本组成,即哪些文件会编译。

make PLATFORM=generic menuconfig进行配置

保存的.config位于

build/platform/generic/kconfig/.config

生成的头文件位于

build/platform/generic/kconfig/autoconf.h

Makefile中如下语句会自动包含该头文件

export KCONFIG_AUTOHEADER=$(KCONFIG_DIR)/autoconf.h

ifdef PLATFORMGENFLAGS    +=  -include $(KCONFIG_AUTOHEADER)endif

3.1主菜单

先从根目录的Kconfig开始

mainmenu显示的主菜单内容

但是OPENSBI_SRC_DIR,OPENSBI_PLATFORM,OPENSBI_PLATFORM_SRC_DIR

三个字符串配置没有显示,因为string后面是空的。

option env=""  表示选项值来源于””里的环境变量值。

我们修改如下

config OPENSBI_SRC_DIR  string "OPENSBI_SRC_DIR"  option env="OPENSBI_SRC_DIR"
config OPENSBI_PLATFORM string OPENSBI_PLATFORM option env="OPENSBI_PLATFORM"
config OPENSBI_PLATFORM_SRC_DIR string "OPENSBI_PLATFORM_SRC_DIR" option env="OPENSBI_PLATFORM_SRC_DIR"

Makefile中设置了这几个环境变量

export OPENSBI_SRC_DIR=$(src_dir)export OPENSBI_PLATFORM=$(PLATFORM)export OPENSBI_PLATFORM_SRC_DIR=$(platform_src_dir)

其中

src_dir=$(CURDIR)

PLAFROM来源于命令中的PLATFORM=generic

export platform_subdir=$(PLATFORM)export platform_src_dir=$(platform_parent_dir)/$(platform_subdir)
ifdef PLATFORM_DIR  platform_dir_path=$(shell $(READLINK) -f $(PLATFORM_DIR))  ifdef PLATFORM    platform_parent_dir=$(platform_dir_path)  else    PLATFORM=$(shell basename $(platform_dir_path))    platform_parent_dir=$(shell realpath ${platform_dir_path}/..)  endifelse platform_parent_dir=$(src_dir)/platformendif

这里没定义PLATFORM_DIR所以

platform_parent_dir=$(src_dir)/platform

即当前目录下/platform/generic

显示如下

可以指定选项回车,再修改

我们继续看下一项

前面看到OPENSBI_PLATFORM_SRC_DIR

platform/generic/所以

$(OPENSBI_PLATFORM_SRC_DIR)/Kconfig

对应platform/generic/Kconfig文件

相应的后面两个

$(OPENSBI_SRC_DIR)/lib/sbi/Kconfig

对应

lib/sbi/Kconfig

$(OPENSBI_SRC_DIR)/lib/utils/Kconfig

对应

lib/utils/Kconfig

$(OPENSBI_SRC_DIR)/firmware/Kconfig

对应

firmware/Kconfig

该文件为空,所以无显示

3.2platform/generic/Kconfig

首先来看,以下内容并没有显示,因为bool后面是空

config PLATFORM_GENERIC    bool    select FDT    select FDT_DOMAIN    select FDT_PMU    default y

修改如下

config PLATFORM_GENERIC    bool PLATFORM_GENERIC    select FDT    select FDT_DOMAIN    select FDT_PMU    default y

此时可以看到选项,默认default y是选中的

其中select表示PLATFORM配置y了,自动配置FDTFDT_DOMINFDT_PMUy

上下箭头移动,选中PLATFORM_GENERIC,按Y选中显示*,按N不选中显示空。

不选中时,后面的内容全无,因为后面都是需要PLATFORM_GENERICy

if PLATFORM_GENERIC

....

endif

如下字符串

config PLATFORM_GENERIC_NAME

  string "Platform default name"

  default "Generic"

对应如下

以下部分

config PLATFORM_GENERIC_MAJOR_VER    int "Platform major version"    range 0 65535    default 0
config PLATFORM_GENERIC_MINOR_VER    int "Platform minor version"    range 0 65535    default 1

两个版本整数,默认值分别为0,1,范围0~65535

以下部分

config PLATFORM_ALLWINNER_D1    bool "Allwinner D1 support"    depends on FDT_IRQCHIP_PLIC    default n
config PLATFORM_ANDES_AE350    bool "Andes AE350 support"    select SYS_ATCSMU    default n
config PLATFORM_RENESAS_RZFIVE    bool "Renesas RZ/Five support"    select ANDES45_PMA    select ANDES_SBI    default n
config PLATFORM_SIFIVE_FU540    bool "SiFive FU540 support"    default n
config PLATFORM_SIFIVE_FU740    bool "SiFive FU740 support"    depends on FDT_RESET && FDT_I2C    default n
config PLATFORM_STARFIVE_JH7110    bool "StarFive JH7110 support"    default n

对应如下

config PLATFORM_ALLWINNER_D1    bool "Allwinner D1 support"    depends on FDT_IRQCHIP_PLIC    default n

表示FDT_IRQCHIP_PLICyPLATFORM_ALLWINNER_D1y

config PLATFORM_ANDES_AE350    bool "Andes AE350 support"    select SYS_ATCSMU    default n

表示PLATFORM_ANDES_AE350ySYS_ATCSMUy

config PLATFORM_RENESAS_RZFIVE    bool "Renesas RZ/Five support"    select ANDES45_PMA    select ANDES_SBI    default n

表示PLATFORM_RENESAS_RZFIVEy

ANDES45_PMAANDES_SBIy

config PLATFORM_SIFIVE_FU540    bool "SiFive FU540 support"    default n

PLATFORM_SIFIVE_FU540默认为0

config PLATFORM_SIFIVE_FU740    bool "SiFive FU740 support"    depends on FDT_RESET && FDT_I2C    default n

表示

FDT_RESETFDT_I2CyPLATFORM_SIFIVE_FU740才为y

config PLATFORM_STARFIVE_JH7110    bool "StarFive JH7110 support"    default n

PLATFORM_STARFIVE_JH7110默认为0

最后

source "$(OPENSBI_SRC_DIR)/platform/generic/andes/Kconfig"

前面PLATFORM_RENESAS_RZFIVEy,则ANDES45_PMAANDES_SBIy

所以此时不可选默认选中,

-*- 表示由于其他条件强制选中,不可手动改,[*]表示可以手动改。

config PLATFORM_RENESAS_RZFIVE    bool "Renesas RZ/Five support"    select ANDES45_PMA    select ANDES_SBI    default n

如果要可配,则前面PLATFORM_RENESAS_RZFIVE要取消选中

3.3lib/sbi/Kconfig

几个bool选项,默认都是y

menu "SBI Extension Support"
config SBI_ECALL_TIME    bool "Timer extension"    default y
config SBI_ECALL_RFENCE    bool "RFENCE extension"    default y
config SBI_ECALL_IPI    bool "IPI extension"    default y
config SBI_ECALL_HSM    bool "Hart State Management extension"    default y
config SBI_ECALL_SRST    bool "System Reset extension"    default y
config SBI_ECALL_SUSP    bool "System Suspend extension"    default y
config SBI_ECALL_PMU    bool "Performance Monitoring Unit extension"    default y
config SBI_ECALL_DBCN    bool "Debug Console extension"    default y
config SBI_ECALL_CPPC    bool "CPPC extension"    default y
config SBI_ECALL_LEGACY    bool "SBI v0.1 legacy extensions"    default y
config SBI_ECALL_VENDOR    bool "Platform-defined vendor extensions"    default y
endmenu

3.4lib/utils/Kconfig

又包含每个子文件夹下的kconfig

menu "Utils and Drivers Support"
source "$(OPENSBI_SRC_DIR)/lib/utils/fdt/Kconfig"
source "$(OPENSBI_SRC_DIR)/lib/utils/gpio/Kconfig"
source "$(OPENSBI_SRC_DIR)/lib/utils/i2c/Kconfig"
source "$(OPENSBI_SRC_DIR)/lib/utils/ipi/Kconfig"
source "$(OPENSBI_SRC_DIR)/lib/utils/irqchip/Kconfig"
source "$(OPENSBI_SRC_DIR)/lib/utils/libfdt/Kconfig"
source "$(OPENSBI_SRC_DIR)/lib/utils/regmap/Kconfig"
source "$(OPENSBI_SRC_DIR)/lib/utils/reset/Kconfig"
source "$(OPENSBI_SRC_DIR)/lib/utils/serial/Kconfig"
source "$(OPENSBI_SRC_DIR)/lib/utils/sys/Kconfig"
source "$(OPENSBI_SRC_DIR)/lib/utils/timer/Kconfig"
endmenu

3.4.1fdt

source "$(OPENSBI_SRC_DIR)/lib/utils/fdt/Kconfig"


menuconfig FDT bool "Flattened Device Tree (FDT) support" select LIBFDT default n

platform/generic/Kconfig

PLATFORM_GENERICy,所以select FDTFDT也为y

config PLATFORM_GENERIC    bool PLATFORM_GENERIC    select FDT    select FDT_DOMAIN    select FDT_PMU    default y

所以对应-*-如下

菜单内容如下

依赖FDTy

if FDT
config FDT_DOMAIN bool "FDT domain support" default n
config FDT_PMU bool "FDT performance monitoring unit (PMU) support" default n
endif

也是前面config PLATFORM_GENERIC时自动选中的,所以也都是-*-

3.4.2Gpio

lib/utils/gpio/Kconfig

menu "GPIO Support"
config FDT_GPIO bool "FDT based GPIO drivers" depends on FDT select GPIO default n
if FDT_GPIO
config FDT_GPIO_DESIGNWARE bool "DesignWare GPIO driver" default n
config FDT_GPIO_SIFIVE bool "SiFive GPIO FDT driver" default n
config FDT_GPIO_STARFIVE bool "StarFive GPIO FDT driver" default nendif
config GPIO bool "GPIO support" default n
endmenu

FDT_GPIO必须要为y后面的FDT_GPIO_DESIGNWAREFDT_GPIO_SIFIVE

FDT_GPIO_STARFIVE才有

FDT_GPIOyGPIOy

FDT_GPIO需要FDTy

前面看到FDTconfig PLATFORM_GENERICFDT selecty

可以不选中这些gpio驱动,实现自己gpio驱动

比如可以自己实现一个FDT_GPIO_XXX驱动

Kconfig添加一个配置config FDT_GPIO_XXX

实现一个fdt_gpio_xxx.c文件

lib/utils/gpio/objects.mk

添加

carray-fdt_gpio_drivers-$(CONFIG_FDT_GPIO_XXXX) += fdt_gpio_xxxxlibsbiutils-objs-$(CONFIG_FDT_GPIO_XXXX) += gpio/fdt_gpio_xxxx.o

这里驱动的实现

lib/utils/gpio/objects.mk中,添加到数组中

carray-fdt_gpio_drivers-$(CONFIG_FDT_GPIO_DESIGNWARE) += fdt_gpio_designware

lib/utils/gpio/fdt_gpio_designware.c

定义了结构体,数组成员

extern struct fdt_gpio fdt_gpio_designware;
struct fdt_gpio fdt_gpio_designware = {    .match_table = dw_gpio_match,    .xlate = fdt_gpio_simple_xlate,    .init = dw_gpio_init_bank,};

gpio/fdt_gpio_drivers.carray

HEADER: sbi_utils/gpio/fdt_gpio.h

TYPE: struct fdt_gpio

NAME: fdt_gpio_drivers

相当于定义了数组

lib/utils/gpio/fdt_gpio.c中遍历数组

extern struct fdt_gpio *fdt_gpio_drivers[];
static struct fdt_gpio *fdt_gpio_driver(struct gpio_chip *chip){    int pos;
    if (!chip)        return NULL;
    for (pos = 0; pos < fdt_gpio_drivers_size; pos++) {        if (chip->driver == fdt_gpio_drivers[pos])            return fdt_gpio_drivers[pos];    }
    return NULL;}

最终经过以下脚本

compile_carray = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \         echo " CARRAY    $(subst $(build_dir)/,,$(1))"; \         $(eval CARRAY_VAR_LIST := $(carray-$(subst .c,,$(shell basename $(1)))-y)) \         $(src_dir)/scripts/carray.sh -i $(2) -l "$(CARRAY_VAR_LIST)" > $(1)

调用

scripts/carray.sh

生成c文件

build/platform/generic/lib/utils/gpio/fdt_gpio_drivers.c

自动编译该文件

#include <sbi_utils/gpio/fdt_gpio.h>
extern struct fdt_gpio fdt_gpio_designware;extern struct fdt_gpio fdt_gpio_sifive;extern struct fdt_gpio fdt_gpio_starfive;
struct fdt_gpio *fdt_gpio_drivers[] = {    &fdt_gpio_designware,    &fdt_gpio_sifive,    &fdt_gpio_starfive,};
unsigned long fdt_gpio_drivers_size = sizeof(fdt_gpio_drivers) / sizeof(struct fdt_gpio *);

3.4.3I2C/IPI/REGMAP/IRQCHIP/RESET/SERIAL/TIMER

都和GPIO一样

3.4.4SYS

3.4.5Libquad

3.4.6Libfdt

.Qemu仿真

开一个终端

~/buildroot/thead_9xxf_enhanced_5.10_glibc_br_defconfig/host/csky-qemu/bin/qemu-system-riscv64 -M virt -cpu c910 -bios build/platform/generic/firmware/fw_dynamic.bin -S -s

显示如下

VNC server running on 127.0.0.1:5900

另开一个终端

~/buildroot/thead_9xxf_enhanced_5.10_glibc_br_defconfig/host/bin/riscv64-buildroot-linux-gnu-gdb -f ~/opensbi/build/platform/generic/firmware/fw_payload.elf

target extended-remote localhost:1234

加载程序

load

(gdb) loadLoading section .text, size 0x16428 lma 0x80000000Loading section .rodata, size 0x2670 lma 0x80017000Loading section .dynstr, size 0x2bf lma 0x80019670Loading section .hash, size 0xd0 lma 0x80019930Loading section .gnu.hash, size 0xf0 lma 0x80019a00Loading section .dynsym, size 0x318 lma 0x8001a000Loading section .rela.dyn, size 0x1440 lma 0x8001a318Loading section .data, size 0xc70 lma 0x80020000Loading section .dynamic, size 0x110 lma 0x80020c70Loading section .got, size 0x100 lma 0x80020d80Loading section .got.plt, size 0x10 lma 0x80020e80Loading section .htif, size 0x10 lma 0x80020e90Loading section .payload, size 0x2128 lma 0x80200000Start address 0x0000000080000000, load size 120375Transfer rate: 7836 KB/sec, 1770 bytes/write.(gdb)

在入口处打断点

b *0x80000000

(gdb) b *0x80000000

Breakpoint 1 at 0x80000000: file /home/qinyunti/opensbi/firmware/fw_base.S, line 51.

输入c回车,运行断点处

(gdb) cContinuing.
Breakpoint 1, _start () at /home/qinyunti/opensbi/firmware/fw_base.S:51/home/qinyunti/opensbi/firmware/fw_base.S:51:1129:beg:0x8000000051 MOV_3R s0, a0, s1, a1, s2, a2(gdb)

单步运行

输入s回车

(gdb) s

/home/qinyunti/opensbi/firmware/fw_base.S:52:1160:beg:0x8000000c

52 call    fw_boot_hart

(gdb)

info reg查看寄存器

查看内存

x /10xw 0x80000000
0x80000000 <_start>: 0x00050433 0x000584b3 0x00060933 0x56c000ef0x80000010 <_start+16>: 0x00050833 0x00040533 0x000485b3 0x000906330x80000020 <_start+32>: 0x046358fd 0x1a630118(gdb)

bt查看函数执行调用

五. 总结

以上通过kconfig文件,了解了Opensbi的源文件组成,同时分享了使用gdb进行调试,其中fdt驱动代码的设计值得参考,即所有驱动都设计通用的数据结构,不同平台实现类似的数据结构即可。而make时自动将上述数据结构写入一个数组中,通过这个数组即可访问不同的驱动实现,这里通过脚本去做这个事情,和uboot中通过链接脚本去查找驱动思想类似,实现有点区别,都值得借鉴。















嵌入式Lee
嵌入式软硬件技术:RTOS,GUI,FS,协议栈,ARM,总线,嵌入式C,开发环境 and blablaba....多年经验分享,非硬货不发,带你扒开每一个技术背后的根本原理。
 最新文章