0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看威廉希尔官方网站 视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

RT-Smart riscv64汇编注释

RTThread物联网操作系统 来源:未知 2023-02-08 21:40 次阅读

以rt-smart在全志D1上的代码为例,主要注释了rt-smart在riscv64上的系统初始化和异常处理的代码仓库地址https://gitee.com/rtthread/rt-thread/tree/rt-smart

启动

代码路径

libcpu isc-v -headc906startup_gcc.S

/*
*Copyright(c)2006-2018,RT-ThreadDevelopmentTeam
*
*SPDX-License-Identifier:Apache-2.0
*
*ChangeLogs:
*DateAuthorNotes
*2018/10/01BernardThefirstversion
*2018/12/27JesvenAddSMPsupport
*2020/6/12XimPorttoQEMUandremoveSMPsupport
*/


#define__ASSEMBLY__
#defineSSTATUS_FS0x00006000U/*initialstateofFPU,cleartodisable*/
#include

.global_start
.section".start","ax"
_start:
j1f
.word0xdeadbeef
.align3
.globalg_wake_up
g_wake_up:
.dword1
.dword0
1:
csrwsie,0/*超级用户模式中断使能关闭*/
csrwsip,0/*超级用户模式中断等待关闭*/
lat0,trap_entry/*将trap_entry的地址放入t0寄存器*/
csrwstvec,t0/*配置异常服务程序的入口地址*/

lix1,0
/*...........*//*初始化通用寄存器*/
lix31,0

/*settodisableFPU*/
lit0,SSTATUS_FS/*将FS的bit位写入t0寄存器*/
csrcsstatus,t0/*清除sstatus中的FSbit,关闭浮点单元*/
lit0,0x40000/*当SUM=1时,超级用户模式下,加载、存储和取指令请求可以访问标记为用户态的虚拟内存空间*/
csrssstatus,t0/*置位sstatus中的SUM位*/

.optionpush
.optionnorelax
lagp,__global_pointer$
.optionpop

//removedSMPsupporthere
lasp,__stack_start__/*栈指针的值来自于链接脚本中的__stack_start*/
lit0,__STACKSIZE__
addsp,sp,t0/*栈自上到下增长*/
csrwsscratch,sp/*sscratch存储栈顶的地址*/
jprimary_cpu_entry/*跳转到board中的C程序入口*/
//BSP的C入口
voidprimary_cpu_entry(void)
{
externvoidentry(void);

//初始化BSS
init_bss();
//关中断
rt_hw_interrupt_disable();
rt_assert_set_hook(__rt_assert_handler);
//启动RT-ThreadSmart内核
entry();
}

异常处理

异常处理流程图



异常处理上半部分

/*libcpu
isc-v	-headc906interrupt_gcc.S*/

#define__ASSEMBLY__
#include"cpuport.h"
#include"encoding.h"
#include"stackframe.h"

.section.text.entry
.align2
.globaltrap_entry
.extern__stack_cpu0
.externget_current_thread_kernel_stack_top
trap_entry:/*异常处理函数的入口*/
//backupsp
csrrwsp,sscratch,sp/*将当前栈与sscratch做交换*/
//loadinterruptstack
lasp,__stack_cpu0/*sp指向cpu0的中断栈的栈顶*/
//backupcontext
SAVE_ALL/*CPU寄存器入栈,使能浮点的情况下浮点相关的寄存器也要入栈并且要保存sstatus中浮点的运算状态*/

RESTORE_SYS_GP/*gp操作不用了解*/

//checksyscall
csrrt0,scause/*读取scaue到t0*/
lit1,8//environmentcallfromu-mode/*用户模式环境调用异常*/
beqt0,t1,syscall_entry/*如果是系统调用则跳转到系统调用处理函数,这个函数最终会调用sret*/

csrra0,scause/*读取scause到a0,机器模式异常事件向量寄存器(MCAUSE)用于保存触发异常的异常事件向量号,用于在异常服务程序中处理对应事件*/
csrrca1,stval,zero/*读取stval到a1,发生异常或者中断,且在机器模式响应时,处理器会更新pc到MEPC,并根据异常类型更新MTVAL*/
csrra2,sepc/*读取sepc到a2,超级用户模式异常保留程序计数器(SEPC)用于存储程序从异常服务程序退出时的程序计数器值(即
PC值)*/

mva3,sp/*读取sp的值到a3*/

/*scause,stval,sepc,sp*/
callhandle_trap/*进行中断处理*/

中断处理

/*libcpu
isc-v	-headc906	rap.c*/
/*Trapentry*/
voidhandle_trap(rt_size_tscause,rt_size_tstval,rt_size_tsepc,structrt_hw_stack_frame*sp)
{
/*
SCAUSE
bit63Interrupt-中断标记位
当 Interrupt 位为0时,表示触发异常的来源不是中断, Exception Code 按照异常解析。当 Interrupt 位为 1 时,表示触发异常的来源是中断, Exception Code 按照中断解析。该位会被 reset 置为 1’ b0。
bit0~4ExceptionCode-异常向量号位
在处理器响应异常或中断时,该域会被更新为对应异常号,具体请参考表3.9异常和中断向量分
配。该位会被 reset 置为 5’ b0。
*/



/*我理解这里是想获取ExceptionCode,但是ExceptionCode是bit0~bit4,这里用__MASK(5UL)更合适吧*/
rt_size_tid=__MASKVALUE(scause,__MASK(63UL));
constchar*msg;

/*supervisorexternalinterrupt*/
/*如果scause的bit63是1,scause的bit0~4是9超级用户模式外部中断*/
if((SCAUSE_INTERRUPT&scause)&&SCAUSE_S_EXTERNAL_INTR==(scause&0xff))
{
rt_interrupt_enter();
plic_handle_irq();
rt_interrupt_leave();
return;
}/*如果scause的bit63是1,scause的bit0~4是超级用户模式计时器中断*/
elseif((SCAUSE_INTERRUPT|SCAUSE_S_TIMER_INTR)==scause)
{
/*supervisortimer*/
rt_interrupt_enter();
tick_isr();
rt_interrupt_leave();
return;
}/*其他中断*/
elseif(SCAUSE_INTERRUPT&scause)
{
if(id< sizeof(Interrupt_Name)/sizeof(constchar*))
{
msg=Interrupt_Name[id];
}
else
{
msg="UnknownInterrupt";
}
LOG_E("UnhandledInterrupt%ld:%s ",id,msg);
}
else/*异常处理*/
{
#ifdefRT_USING_USERSPACE
/*pagefault缺页异常处理*/
if(id==EP_LOAD_PAGE_FAULT||
id==EP_STORE_PAGE_FAULT)
{
arch_expand_user_stack((void*)stval);
return;
}
#endif/*其他异常处理,走到这里后打印一些必要信息,最终会走到while(1),进入死循环*/
if(id< sizeof(Exception_Name)/sizeof(constchar*))
{
msg=Exception_Name[id];
}
else
{
msg="UnknownException";
}

rt_kprintf("UnhandledException%ld:%s ",id,msg);
}

rt_kprintf("scause:0x%p,stval:0x%p,sepc:0x%p ",scause,stval,sepc);
dump_regs(sp);
while(1);
}

在rt-smart中任务切换有三个相关的线程函数

  • rt_hw_context_switch_to():没有来源线程,切换到目标线程,在调度器启动第一个线程的时候 被调用
  • rt_hw_context_switch():在线程环境下,从当前线程切换到目标线程
  • rt_hw_context_switch_interrupt ():在中断环境下,从当前线程切换到目标线程。

rt_hw_context_switch_interrupt ()会将rt_thread_switch_interrupt_flag置为1,真正的线程切换动作在异常处理函数中完成。

异常处理下半部分

/*needtoswitchnewthread查询线程切换的flag是否被置位为1*/
las0,rt_thread_switch_interrupt_flag/*读取rt_thread_switch_interrupt_flag*/
lws2,0(s0)
beqzs2,spurious_interrupt/*rt_thread_switch_interrupt_flag如果为0那么直接跳转到spurious_interrupt进行寄存器恢复,并调用sret回到异常之前的状态*/
swzero,0(s0)/*rt_thread_switch_interrupt_flag=0*/

.globalrt_hw_context_switch_interrupt_do
rt_hw_context_switch_interrupt_do:

//swaptothreadkernelstack
csrrt0,sstatus/*读取sstatus到t0*/
andit0,t0,0x100/*bit8超级用户模式保留特权状态位*/
/*
该位用于保存处理器在降级到超级用户模式进入异常服务程序前的特权状态。
•当 SPP 为 2’ b00时,表示处理器进入异常服务程序前处于用户模式;
•当 SPP 为 2’ b01 时,表示处理器进入异常服务程序前处于超级用户模式;
该位会被 reset 置 2’ b01。
*/

beqzt0,__restore_sp_from_tcb_interrupt/*如果是内核态发生异常*/

__restore_sp_from_sscratch_interrupt:
csrrt0,sscratch/*获取发生异常时的上下文数据*/
j__move_stack_context_interrupt/*如果是用户态发生异常*/

/*获取当前线程的栈顶位置存到t0中*/
__restore_sp_from_tcb_interrupt:
las0,rt_interrupt_from_thread
LOADa0,0(s0)
jalrt_thread_sp_to_thread
jalget_thread_kernel_stack_top
mvt0,a0

__move_stack_context_interrupt:
mvt1,sp//src/*当前栈,当前栈存储的是发生异常时的通用寄存器信息*/
mvsp,t0//switchstack/*将发生异常时的栈的值写回到sp寄存器*/
addisp,sp,-CTX_REG_NR*REGBYTES/*栈指针向下移动CTX_REG_NR*REGBYTES*/
//copycontext
lis0,CTX_REG_NR//cnt/*需要恢复的寄存器的个数加载到s0*/
mvt2,sp//dst/*栈指针加载到t2*/
/*总结就是,当前CPU的中断栈存储了当前线程的通用寄存器的信息,如果发生任务切换,需要把这些信息拷贝到线程的栈里*/

copy_context_loop_interrupt:
LOADt0,0(t1)/*t1的值放到t0*/
STOREt0,0(t2)/*t0的值放到t2*/
addis0,s0,-1/*要恢复的寄存器个数-1*/
addit1,t1,8/*t1的地址加8*/
addit2,t2,8/*t2的地址加8*/
bnezs0,copy_context_loop_interrupt/*如果s0不为0就重复拷贝*/

las0,rt_interrupt_from_thread
LOADs1,0(s0)
STOREsp,0(s1)/*更新from线程的sp指针*/

las0,rt_interrupt_to_thread
LOADs1,0(s0)
LOADsp,0(s1)/*恢复to线程的sp*/

#ifdefRT_USING_USERSPACE
mva0,s1
jalrt_thread_sp_to_thread
jallwp_mmu_switch/*切换mmu,函数内部会判断from线程和to线程是不是在同一个lwp中,不是的话就会切换MMU*/
#endif

spurious_interrupt:
RESTORE_ALL/*恢复寄存器*/
sret/*超级用户模式异常返回指令*/

———————End———————


你可以添加微信:rtthread2020 为好友,注明:公司+姓名,拉进RT-Thread官方微信交流群!



爱我就给我点在看

点击阅读原文


原文标题:RT-Smart riscv64汇编注释

文章出处:【微信公众号:RTThread物联网操作系统】欢迎添加关注!文章转载请注明出处。

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

    关注

    31

    文章

    1293

    浏览量

    40198

原文标题:RT-Smart riscv64汇编注释

文章出处:【微信号:RTThread,微信公众号:RTThread物联网操作系统】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    RT-Smart首次线下培训,锁定2024 RT-Thread开发者大会!

    2024年RT-Thread开发者大会将于12月21日正式拉开帷幕!本次大会以“开源共生商业共赢”为主题,RT-Thread将携手合作伙伴、客户伙伴、行业专家,以及全球开发者,共同探索如何在开源
    的头像 发表于 12-11 18:41 393次阅读
    <b class='flag-5'>RT-Smart</b>首次线下培训,锁定2024 <b class='flag-5'>RT</b>-Thread开发者大会!

    RISCV 操作常见问题集 - v4

    /riscv-xpack-toolchain_8.3.0-2.3_windows/bin/../lib/gcc/riscv-none-embed/8.3.0/../../../../riscv-none-embed/bin/ld
    的头像 发表于 11-01 11:06 309次阅读

    RK3568平台RT-smart系统跑不起来,为什么?

    RK3568平台RT-smart系统跑不起来
    发表于 09-13 07:28

    RISCV的主流指令集有哪些?

    如题,就像X86中指令集有MMX,SSE,SSE2等,就像ARM指令集有ARM和Thumb等,但是总是感觉RISCV特别乱,可能是厂商比较多的缘故吧,我知道的有WCH的青稞RISC-V,玄铁
    发表于 08-29 13:49

    RISC-V 汇编语言程序的调试

    编译,生成二进制代码: riscv64-unknown-elf-c++ -c -nostdlib -nostdinc -static -g -Ttext 0x80000000 -o sum.elf
    发表于 07-19 16:27

    在ubuntu 24.04下尝试使用riscv64-linux-musleabi_for_x86_64-pc-linux-gnu工具链编译cv1800大核出现报错的原因?

    在ubuntu 24.04下尝试使用riscv64-linux-musleabi_for_x86_64-pc-linux-gnu工具链编译cv1800大核,结果出现如下报错: /home
    发表于 07-16 08:20

    ART-PI Smart User运行LED程序崩溃的原因?怎么处理?

    done! open em failed! hello rt-smart 在userapps中添加led_test.c,代码如下: #include \"led_test.h
    发表于 07-05 08:21

    在 ART-Pi Smart 体验 RT-Thread Smart v5.1.0

    1.引言RT-ThreadSmartv5.1.0已经正式发布。这一版本在内核和功能上做了大量的改进与增强。我们可以在ART-PiSmart开发板尽情探索这一新版更完善更强
    的头像 发表于 06-14 08:35 630次阅读
    在 ART-Pi <b class='flag-5'>Smart</b> 体验 <b class='flag-5'>RT</b>-Thread <b class='flag-5'>Smart</b> v5.1.0

    使用msys2 mingw64编译nuclei openocd源码出错的原因?

    :msys64homeAdministratorbuildnuclei-riscv-openocdbuild/../src/jtag/drivers/mpsse.c:358:(.text+0xc71): undefined reference
    发表于 05-29 07:52

    谷歌安卓系统即将取消对RISC-V架构的支持

    负责安卓Linux核心分支开发的谷歌高级工程师向AOSP提交了一系列补丁,其中显示“已去除ACK对riscv64的支持”。这些补丁详细描述指出“对risc64 GKI内核的支持已停止”。
    的头像 发表于 04-30 15:40 1552次阅读

    国产riscv芯片大汇总?

    请问有统计国产的riscv芯片的吗?能汇总一下吗?
    发表于 04-27 11:53

    RISCV soft JTAG调试_v1.2

    因为目前软件的限制,RISCV的逻辑不能同时共用JTAG,所以如果想要同时去调试逻辑和RISCV的话,可以通过RISCV的soft Jtag来实现。soft Jtag就是通过GPIO来实现的软件
    的头像 发表于 04-23 08:38 1098次阅读

    RISCV soft JTAG调试_v1.1

    因为目前软件的限制,RISCV的逻辑不能同时共用JTAG,所以如果想要同时去调试逻辑和RISCV的话,可以通过RISCV的soft Jtag来实现。soft Jtag就是通过GPIO来实现的软件
    的头像 发表于 02-23 16:16 682次阅读
    <b class='flag-5'>RISCV</b> soft JTAG调试_v1.1

    rtthread d1s编译报错的原因是什么?如何处理?

    我使用使用的是现在git上的rtthread的最新的master分支,因为rt-smart已经并入主线,所以我想在windows下用env工具编译。 因为要编译riscv架构的全志D1S,我下载了
    发表于 02-22 06:43

    【昉·星光 2 高性能RISC-V单板计算机体验】为 Ubuntu 安装 Docker 及常用软件

    : 获取镜像 通常来说,RISC-V 架构的开发板不能使用基于其他架构开发的镜像,下面是一些基于 RISC-V 镜像的合集:https://hub.docker.com/u/riscv64/ 安装其他常用软件 sudo apt install vim htop net-tools 根据所需即可。
    发表于 02-21 17:54