RT-Thread Smart(簡稱rt-smart)是基于RT-Thread操作系統衍生,面向帶MMU(Memory Management Unit),中高端應用的芯片,例如ARM Cortex-A,MIPS,帶MMU的RISC-V芯片等。rt-smart在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 版本。
-
ARM處理器
+關注
關注
6文章
360瀏覽量
41721 -
虛擬機
+關注
關注
1文章
914瀏覽量
28160 -
MMU
+關注
關注
0文章
91瀏覽量
18283 -
RT-Thread
+關注
關注
31文章
1285瀏覽量
40085 -
RISC-V
+關注
關注
45文章
2270瀏覽量
46130
發布評論請先 登錄
相關推薦
評論