零基础上手rt-smart适配bsp

电子说

1.3w人已加入

描述

RT-Thread Smart(简称rt-smart)是基于RT-Thread操作系统衍生,面向带MMU(Memory Management Unit),中高端应用的芯片,例如ARM Cortex-A,MIPS,带MMU的RISC-V芯片等。rt-smart在RT-Thread操作系统的基础上启用独立、完整的进程方式,同时以混合微内核模式执行。

RT-Thread

自 V5.0.0 起,rt-smart 分支已合并至 rt-thread master 分支上,可以在 bsp 下通过 menuconfig 启用Enable RT-Thread Smart (microkernel on kernel/userland)选项即可使用 rt-smart。

目前有 allwinner 下 d1/d1s , bouffalo_lab 下的 bl808/d0 ,raspi4-64,qemu-virt64-aarch64,qemu-virt64-riscv 等多个bsp已经支持 rt-smart。

本文通过介绍 RISC-V64 架构的 BL808,介绍适配 rt-smart 与 rt-thread 区别点,从零开始适配一个支持 rt-smart 的 bsp。

BL808是RISC-V三核异构架构,分别为m0(E907/RV32IMA)、lp(E902/RV32E[M]C)、d0,(C906/RV64IMA[FD]C[V])都采用的是平头哥的玄铁RISC-V核,

RISC-V有3种工作状态,分别为机器模式machine mode(M态)、监督模式supervisor mode(S态)、用户模式user mode(U态)。
RISC-V架构定义机器模式为必选模式,另外两种模式为可选模式,通过不同的模式组合可以实现不同的系统,C906同时支持M/S/U态。

rt-smart工作在S态,需要MMU支持。C906 虚拟内存管理 MMU兼容 RISC-V Sv39 虚拟内存系统。rt-smart和工作在M态的RT-Thread 标准版有较多不同。

启动
在适配RT-Thread标准版本,芯片工作在M态(芯片启动默认状态),启动文件一般采用原厂SDK提供的启动文件完成硬件初始化(操作M态下的寄存器)、bss初始化等软件初始化工作,跳转到entry()函数即可开始rt-thread流程,剩下的工作在rt_hw_board_init()函数中完成。

bl808-d0核运行在S态,芯片启动默认工作在M态,芯片需要通过一些流程,将opensbi、kernel等相关代码从flash上copy到ram上,并通过opensbi芯片切换到S态。opensbi完成一些了配置后跳转到rt-smart(kernel)。

rt-smart此时工作在S态,不能操作任何M态下的寄存器,只能操作S态下的寄存器,否则会发生异常。
C906启动文件startup_gcc.S在libcpu/risc-v/t-head/c906目录下,在bsp下需要完成init_bss()、primary_cpu_entry()两个函数,这两个函数作用为清除bss区、禁止全局中断,调用entry()进入rt-smart主流程。

此外 startupgcc.S 会调用 stack_start 变量和 STACKSIZE 宏,赋值给 sp , STACKSIZE 宏在 Kconfig 配置,内置脚本会自动生成 linkstacksize.lds 文件,并在 link.ld 文件中被调用,__stack_start 在 link.ld 中自动生成。
进入entry后,rt-thread初始化流程基本一致,内核已经通过RT_USING_SMART宏作了处理,在Kconfig开启该宏即可。

ld文件
RT-Thread标准版适配的时候,一般也采用原厂SDK中提供的ld文件,做一些适当的修改后即可使用。
bl808-d0核运行在S态下,启动文件和ld文件都不能使用原厂SDK中的文件。RISC-V可参考 qemu-virt64-riscv 、 allwinner 下 d1/d1s 等bsp,复制对应的 link.ld 文件,并根据自己的芯片、开发板内存修改 Memory layout。

MEMORY
{
SRAM : ORIGIN = 0x50100000, LENGTH = 63M
}
SECTIONS
{
. = 0x50100000 ;
}
该地址为rt-smart程序开始地址,与bootload、opensbi等跳转地址一致。

中断
bl808-d0核工作在S态,中断相关操作与M态不一样,同样不能使用原厂SDK中的相关接口,rt-thread提供相关S态下中断管理的一系列函数。包括:

rt_hw_interrupt_init()
rt_hw_interrupt_install()
rt_hw_interrupt_mask()
rt_hw_interrupt_umask()
操作S态下的外设中断时需使用这一套接口,相关函数实现在libcpu/risc-v/t-head/c906/interrupt.c文件下。

Kconfig 配置
bl808-d0核运行在S态,必须开启ARCH_RISCV64、ARCH_MM_MMU、RT_USING_CACHE这三个宏,否则会编译不过。
bl808相关配置在bsp/bouffalo_lab/bl808/d0/board/Kconfig下。

config BSP_USING_BL808
bool
select ARCH_RISCV64
select RT_USING_COMPONENTS_INIT
select RT_USING_USER_MAIN
select RT_USING_CACHE
select ARCH_MM_MMU
select BL808_CORE_D0
default y
同时在上文启动相关流程中讲到需要配置栈空间大小

config STACKSIZE
int "stack size for interrupt"
default 4096
相关配置在bsp/bouffalo_lab/bl808/d0/Kconfig下。

芯片相关PLIC地址、IRQ数量、STimer频率配置
C906相关中断管理、STimer管理都已经在libcpu/risc-v/t-head/c906下实现,需要对相关地址、数量通过宏配置。相关配置在bsp/bouffalo_lab/bl808/d0/board/Kconfig下
config C906_PLIC_PHY_ADDR
hex
default 0xe0000000
config IRQ_MAX_NR
int
default 64
config TIMER_CLK_FREQ
int
default 1000000
完成以上配置, bl808-d0 核可以正常工作在S态下,可以使用 RT-Thread 标准版,需要使用 rt-smart 版还需要完成一些 rt-smart 对应的 mmu 初始化、页表建立等工作。

SMART初始化
bl808-d0核可以正常工作在S态下,可以通过在Kconfig中选中 RT-Thread Kernel -> Enable RT-Thread Smart (microkernel on kernel/userland) 即可是能rt-smart。
使能 rt-smart 后,在Kconfig根选项中,会显示 The virtural address of kernel start 选项,该地址为内核虚拟地址起始地点,bl808-d0核配置为0x50000000。

heap和页表地址配置
在board.h中根据实际芯片或开发板当前RAM情况做配置

extern unsigned int __bss_start;
extern unsigned int __bss_end;
#ifndef RT_USING_SMART
#define KERNEL_VADDR_START 0x0
#endif
#define RT_HW_HEAP_BEGIN ((void *)&__bss_end)
#define RT_HW_HEAP_END ((void *)(RT_HW_HEAP_BEGIN + 16 * 1024 * 1024))
#define RT_HW_PAGE_START RT_HW_HEAP_END
#define RT_HW_PAGE_END ((void *)(KERNEL_VADDR_START + 64 * 1024 * 1024))
bl808芯片内封了64M高速psarm,将64M内存做了适当划分,分给heap和page。
并在board.c中做了相关page映射:

rt_region_t init_page_region = {(rt_size_t)RT_HW_PAGE_START, (rt_size_t)RT_HW_PAGE_END};
mmu页表相关地址配置
struct mem_desc platform_mem_desc[] = {
{KERNEL_VADDR_START, (rt_size_t)RT_HW_PAGE_END - 1, (rt_size_t)ARCH_MAP_FAILED, NORMAL_MEM},
{0x1000, ((KERNEL_VADDR_START - 1) & 0xfffff000) - 1, (rt_size_t)ARCH_MAP_FAILED, DEVICE_MEM},
};
#define NUM_MEM_DESC (sizeof(platform_mem_desc) / sizeof(platform_mem_desc[0]))
其中DEVICE_MEM项将0x1000~0x4FFF1000做了1:1映射,这样操作 bl808 外设的时候,在 0x50000000 之前的寄存器就不需要在做 ioremap 了。否则会出现如下异常

Unhandled Exception 7:Store/AMO Access Fault
scause:0x0000000000000007,stval:0x0000000010201000,sepc:0x00000000500248b4
--------------Dump Registers-----------------
Function Registers:
ra(x1) = 0x0000000050024cca user_sp = 0x000000005003f840
gp(x3) = 0x000000005003c0a0 tp(x4) = 0x0000000000000000
Temporary Registers:
t0(x5) = 0x0000000000004000 t1(x6) = 0x0000000000000000
t2(x7) = 0x0000000000000001
t3(x28) = 0x0000000000000000 t4(x29) = 0x0000000000000000
t5(x30) = 0x0000000000000000 t6(x31) = 0x0000000000000000
Saved Registers:
s0/fp(x8) = 0x000000005003f860 s1(x9) = 0x0000000000000000
s2(x18) = 0x0000000000000000 s3(x19) = 0x0000000000000000
s4(x20) = 0x0000000000000000 s5(x21) = 0x0000000000000000
s6(x22) = 0x0000000000000000 s7(x23) = 0x0000000000000000
s8(x24) = 0x0000000000000000 s9(x25) = 0x0000000000000000
s10(x26) = 0x0000000000000000 s11(x27) = 0x0000000000000000
Function Arguments Registers:
a0(x10) = 0x0000000000000000 a1(x11) = 0x0000000010201000
a2(x12) = 0x0000000000000004 a3(x13) = 0x0000000000000080
a4(x14) = 0x0000000000000000 a5(x15) = 0x0000000010201000
a6(x16) = 0xfefefefefefefeff a7(x17) = 0x0000000000000007
sstatus = 0x0000000200040100
Supervisor Interrupt Disabled
Last Time Supervisor Interrupt Disabled
Last Privilege is Supervisor Mode
Permit to Access User Page
Not Permit to Read Executable-only Page
satp = 0x800000000005006f
Current Page Table(Physical) = 0x000000005006f000
Current ASID = 0x0000000000000000
Mode = Page-based 39-bit Virtual Addressing Mode
-----------------Dump OK---------------------
--------------Thread list--------------
current thread: (NULL)
--------------Backtrace--------------
riscv64-unknown-linux-musl-addr2line -e rtthread.elf -a -f 00000000500248b0
在rt_hw_board_init()函数中,进入函数后,添加
#ifdef RT_USING_SMART
/* init data structure */
rt_hw_mmu_map_init(&rt_kernel_space, (void *)(IOREMAP_VEND - IOREMAP_SIZE), IOREMAP_SIZE, (rt_size_t )MMUTable, PV_OFFSET);
/
init page allocator /
rt_page_init(init_page_region);
/
setup region, and enable MMU */
rt_hw_mmu_setup(&rt_kernel_space, platform_mem_desc, NUM_MEM_DESC);
#endif
对mmu做地址映射,建立页表等初始化工作,并在最后启动 mmu。
然后与RT-Thread标准版流程一致,完成heap、interrupt、uart等硬件初始化后,就可以正常启动rt-smart了。

bl808 rt-thread bsp
当前 bl80 8的 bsp 已实现三核同时启动,位于 bsp/bouffalo_lab/bl808,三核分别采用了不同的 RT-Thread 版本。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分