使用 Opensbi 引导自己的操作系统

之前在 使用uboot引导自己的操作系统 中尝试了使用 opensbi 来引导自己的操作系统,但是当时发现无论是制作 fip 时还是 ATF 启动时都对 bl33 的镜像有格式要求。

这段时间学习了下 riscv 的汇编和链接脚本,然后重新看了下 ATF 和 uboot 的代码,发现制作自己的 bl33 镜像其实很简单,只要在程序的最开始处加入以下信息即可:

_start:
	/* BL33 information */
	j real_start
	.balign 4
	.word 0x33334c42  /* b'BL33' */
	.word 0xdeadbeea  /* CKSUM */
	.word 0xdeadbeeb  /* SIZE */
	.quad 0x80200000  /* RUNADDR */
	.word 0xdeadbeec
	.balign 4
	j real_start
	.balign 4
	/* BL33 end */

以下是一个简单的例子:

若没有编译过 sdk 的话需要先编译下 fsbl 来获得 bl2 镜像:

export MILKV_BOARD=milkv-duo
source milkv/boardconfig-milkv-duo.sh

source build/milkvsetup.sh
defconfig cv1800b_milkv_duo_sd

build_fsbl

然后编写一个简单的程序,使用 uart8250 来打印一句字符串:

#define UART0_THR 0x04140000
#define UART0_LSR 0x04140014

	.section .text
	.global _start
_start:
	/* BL33 information */
	j real_start
	.balign 4
	.word 0x33334c42  /* b'BL33' */
	.word 0xdeadbeea  /* CKSUM */
	.word 0xdeadbeeb  /* SIZE */
	.quad 0x80200000  /* RUNADDR */
	.word 0xdeadbeec
	.balign 4
	j real_start
	.balign 4
	/* Information end */

real_start:
	la s0, str
1:
	lbu a0, (s0)
	beqz a0, exit
	jal ra, uart_send
	addi s0, s0, 1
	j 1b

exit:
	j exit

uart_send:
	/* Wait for tx idle */
	li t0, UART0_LSR
	lw t1, (t0)
	andi t1, t1, 0x20
	beqz t1, uart_send
	/* Send a char */
	li t0, UART0_THR
	sw a0, (t0)
	ret

.section .rodata
str: 
	.asciz "Hello Milkv-duo!\n"

编译:

riscv64-unknown-elf-gcc -nostdlib -fno-builtin -march=rv64gc -mabi=lp64f -g -Wall -Ttext=0x80200000 -o bl33.elf start.S

riscv64-unknown-elf-objcopy -O binary bl33.elf bl33.bin

此时可以用 hd 看一下生成的 bin 文件,会发现已经存在了用于校验的两行数据,而 opensbi 实际会跳转到 0x80200020 来执行我们的程序。

00000000  05 a0 01 00 42 4c 33 33  ea be ad de eb be ad de  |....BL33........|
00000010  00 00 20 80 00 00 00 00  ec be ad de 11 a0 01 00  |.. .............|

进入到 fsbl 目录生成 fip.bin 文件:

cd fsbl/

./plat/cv180x/fiptool.py -v genfip \
    'build/cv1800b_milkv_duo_sd/fip.bin' \
    --MONITOR_RUNADDR="0x0000000080000000" \
    --CHIP_CONF='build/cv1800b_milkv_duo_sd/chip_conf.bin' \
    --NOR_INFO='FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF' \
    --NAND_INFO='00000000'\
    --BL2='build/cv1800b_milkv_duo_sd/bl2.bin' \
    --DDR_PARAM='test/cv181x/ddr_param.bin' \
    --MONITOR='../opensbi/build/platform/generic/firmware/fw_dynamic.bin' \
    --LOADER_2ND='/path/to/bl33.bin' \
    --compress='lzma'

最后将 fip.bin 文件放到 tf 卡,使用 128000 比特率连接到板子的串口,就能看到我们的打印信息了:

image

4 Likes

请问我想知道的是,按照标准制作一个fip.bin然后直接开始加载自己的内核会有什么要求,是不是只需要满足fip文件的格式就行?

对的,用 sbi 引导的话只要添加 bl33 校验信息就可以了

我更想了解的是如果我不想使用opensbi呢,我希望自己初始化设备。自制的fip直接加载自己的loader会有什么要求吗

我想我理解了,我可以直接在bl33中加载自己的任何东西,然后直接跳转,bl33之后都可以由我自由发挥。

对的,bl2 阶段官方好像没有开源,没办法进行修改,目前来看 opensbi 应该是必须要的。

Hey, guys
I made a youtube video showing those steps
https://youtu.be/UrKmSipiXpc?si=H8WHHjq7kc-XSJHM

1 Like