milk-v duo 还是去年买的,又是esp32 又是rp2040 的,搞搞lcd 又搞搞墨水屏 又弄弄 memory lcd,乱得狠,啥都想玩玩,玩不过来,最近抽空看看 这块duo 想裸机跑下rust 试试。
找了一圈总算是有些眉目,找到一些在 uboot 或 opensbi 后引导的方法,随即尝试了一下,成功通过串口打印出信息,记录一下。
主要两个部分,先用rust 加汇编构建出程序的bin文件,后在 duo-buildroot-sdk 中修改fsbl 中的构建 fip.bin 的.mk文件后 再构建fip.bin 。
目录
通过 rust + 汇编 创建自己的程序
1、先用cargo 生成一个rust 项目,修改 config.toml 文件,设置target 和指定链接脚本
// .cargo/config.toml
[build]
target = "riscv64gc-unknown-none-elf"
[target.riscv64gc-unknown-none-elf]
rustflags = [
"-Clink-arg=-Tsrc/linker.ld", "-Cforce-frame-pointers=yes"
]
2、增加链接脚本 src/linker.ld 如下
OUTPUT_ARCH(riscv)
ENTRY(_start)
BASE_ADDRESS = 0x80200000;
SECTIONS
{
. = BASE_ADDRESS;
skernel = .;
stext = .;
.text : {
*(.text.entry)
*(.text .text.*)
}
. = ALIGN(4K);
etext = .;
srodata = .;
.rodata : {
*(.rodata .rodata.*)
*(.srodata .srodata.*)
}
. = ALIGN(4K);
erodata = .;
sdata = .;
.data : {
*(.data .data.*)
*(.sdata .sdata.*)
}
. = ALIGN(4K);
edata = .;
.bss : {
*(.bss.stack)
sbss = .;
*(.bss .bss.*)
*(.sbss .sbss.*)
}
. = ALIGN(4K);
ebss = .;
ekernel = .;
/DISCARD/ : {
*(.eh_frame)
}
}
3、修改main.rs 、增加 panic_handler ,panic_handler 内部没有做处理,但没有panic_handler 无法编译
#![no_std]
#![no_main]
use core::panic::PanicInfo;
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
loop {}
}
use core::arch::global_asm;
global_asm!(include_str!("entry.asm"));
#[no_mangle]
pub fn rust_main() -> ! {
clear_bss();
loop {
prints("hello rust in milkv duo \r\n".as_bytes());
}
}
const UART0_THR: u32 = 0x04140000;
const UART0_LSR: u32 = 0x04140014;
fn prints(bytes:&[u8]){
for byte in bytes {
print(byte);
}
}
fn print(byte: &u8) {
unsafe {
let state_ptr = UART0_LSR as *const u32;
let ptr = UART0_THR as *mut u8;
let mut state = 0;
while state == 0 {
state = core::ptr::read_volatile(state_ptr) & 0x20 ;
}
core::ptr::write_volatile(ptr, *byte);
}
}
fn clear_bss() {
unsafe extern "C" {
fn sbss();
fn ebss();
}
(sbss as usize..ebss as usize).for_each(|a| unsafe { (a as *mut u8).write_volatile(0) });
}
4、创建 entry.asm 并加入如下代码, _start 通过 .global 导出符号以将其放置到编译后的二进制程序的最开始处,其中包含bl33相关的验证信息要保持位置正确。这段代码功能只是通过串口打印一段字符 ,输出字符串后跳转到 rust_main 进入到 rust 程序中 ,在最后定义了一段 栈区。
.equ UART0_THR,0x04140000
.equ 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:
la sp, boot_stack_top
call rust_main
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"
.section .bss.stack
.globl boot_stack_lower_bound
boot_stack_lower_bound:
.space 4096 * 16
.globl boot_stack_top
boot_stack_top:
修改 duo-buildroot-sdk 相关
1、修改 fsbl/make_helpers/fip.mk 下的 fip-all 构建目标,将其中的 –LOADER_2ND 指向自己的程序 ,如下
--LOADER_2ND='/home/ubuntu/workspace/rust_boot/target/riscv64gc-unknown-none-elf/release/rust_boot.bin' \
2、执行 fip 构建 ,可以创建一个 build_fip.sh 保存如下内容,或直接执行这些命令,构建完成后会在 fsbl/build/cv1800b_milkv_duo_sd 中生成 fip.bin ,将这个复制到sd卡中再启动开发板则可以通过串口查看到我们的打印信息
#!/bin/bash
source device/milkv-duo-sd/boardconfig.sh
source build/milkvsetup.sh
defconfig cv1800b_milkv_duo_sd
build_fsbl
3、最后会持续打印一段字符串

用户今天 : 15
用户昨天 : 27
用户最近的7天 : 145
用户最近的30天 : 687
用户这个月 : 632
用户这一年 : 2079
合计用户 : 8748
查看今天 : 67
查看昨天 : 33
查看最近7天 : 206
查看最近30天的 : 837
查看这个月 : 779
查看这一年 : 2765
合计查看 : 10929
谁是在线的 : 0