前言
最近在对RISC-V架构比较感兴趣,正好手头有《RISC-V体系结构编程与实践》的书籍,就打算跟随笨叔将这块的知识学习起来,最开始当然是需要搭建一个基础的实验平台,本来笨叔是贴心的提供了VMare的环境,奈何天生叛逆的我就不下他的大镜像(我就不说我百度网盘没会员),就拿手头的wsl搭建了一套基于vscode的调试环境,可以直接一键调试,感觉还是蛮方便的。这里就进行一下记录。
参考连接:
优雅的调试在vscode上完美调试xv6
笨叔RISC-V官方示例代码仓库
文章目录
- 前言
- WSL基础环境的安装
- 环境搭建
- 1. 基础软件包安装
- 2.示例源码的下载
- 问题解决
- PMP未开启导致无法进入benos
- VScode调试问题
- 理解调试方法
- 配置lanuch.json
- 配置tasks.json
- 成果展示
- 小插曲
- .S文件不能打断点
- 最后
WSL基础环境的安装
我曾经写过两篇文章来完善这块内容,可以参考:
利用windows自带的虚拟机安装ubuntu的记录用来完成基础环境的安装
[linux学习记录]win下子系统ubuntu体验记录用来记录其中遇到的问题以及对应的解决方案,会不定时更新
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/95c97de674eb434da495e9cef2202a7a.png
环境搭建
1. 基础软件包安装
QEMU Virt实验平台模拟的是一款通用的RISC-V开发板。
软件环境:
- WSL(ubuntu22.04)
- qemu(QEMU emulator version 6.2.0 (Debian 1:6.2+dfsg-2ubuntu6.15))
- riscv64-linux-gnu-gcc-9 (Ubuntu 9.5.0-1ubuntu1~22.04) 9.5.0
- gdb-multiarch(GNU gdb (Ubuntu 12.1-0ubuntu1~22.04) 12.1)
安装参考指令:
sudo apt install qemu-system-misc libncurses5-dev build-essential git bison flex libssl-dev
sudo apt install gcc-9-riscv64-linux-gnu
sudo ln -s /usr/bin/riscv64-linux-gnu-gcc-9 /usr/bin/riscv64-linux-gnu-gcc #切换默认版本
sudo apt install gdb-multiarch
其他版本比较叛逆直接安装,但是对于gcc的版本还是要慎重,之前编译oe的5.10内核的时候如果用过高的编译器版本会导致链接出现问题,所以此处尽量与笨叔要求一致。
2.示例源码的下载
git clone 笨叔RISC-V官方示例代码仓库
大致命令如下:
git clone https://github.com/runninglinuxkernel/riscv_programming_practice
cd riscv_programming_practice/chapter_2/benos
make
即可完成基础命令的执行。
运行命令如下:
make debug
然后就会看到如下的画面
这个其实是可以正常跑并且进入到sbi内了,只不过按照笨叔的说明文档,我们遇到了PMP未开启的问题导致无法进入到benos内。所以接下来我们有两个问题待解决:
- 如何解决PMP问题
- 如何使用vscode进行调试
问题解决
PMP未开启导致无法进入benos
根据笨叔的介绍:
那我们就以毒攻毒,把第十章的一部分代码直接CV过来不就好了?虽然我看不懂但是CV我在行(不是),这块其实就先解决问题,等到学到了再认真研究就好了,初学者Hello个world还是有必要的。
根据我的观察大概需要改4个文件:
//include/asm/csr.h
+/* Machine Memory Protection
+ * 暂时支持8个pmpcfg
+*/
+#define RISCV_XLEN 64
+#define MAX_CSR_PMP 8
+#define CSR_PMPCFG0 0x3a0
+#define CSR_PMPADDR0 0x3b0
+#define CSR_PMPADDR1 0x3b1
+#define CSR_PMPADDR2 0x3b2
+#define CSR_PMPADDR3 0x3b3
+#define CSR_PMPADDR4 0x3b4
+#define CSR_PMPADDR5 0x3b5
+#define CSR_PMPADDR6 0x3b6
+#define CSR_PMPADDR7 0x3b7
+#define PMP_R 0x01UL
+#define PMP_W 0x02UL
+#define PMP_X 0x04UL
+#define PMP_A 0x18UL
+#define PMP_A_TOR 0x08UL
+#define PMP_A_NA4 0x10UL
+#define PMP_A_NAPOT 0x18UL
+#define PMP_L 0x80UL
+#define PMP_RWX (PMP_R | PMP_W | PMP_X)
+#define PMP_SHIFT 2
+#ifdef __ASSEMBLY__
+#define __ASM_STR(x) x
+#else
+#define __ASM_STR(x) #x
+#endif
#define read_csr(csr) \
({ \
register unsigned long __v; \
- __asm__ __volatile__ ("csrr %0, " #csr \
+ __asm__ __volatile__ ("csrr %0, " __ASM_STR(csr) \
: "=r" (__v) : \
: "memory"); \
__v; \
#define write_csr(csr, val) \
({ \
unsigned long __v = (unsigned long)(val); \
- __asm__ __volatile__ ("csrw " #csr ", %0" \
+ __asm__ __volatile__ ("csrw "__ASM_STR(csr)", %0" \
: : "rK" (__v) \
: "memory"); \
})
上面其实是diff的部分输出,就是在对应文件进行修改,+就是增加,-就是删除,对照修改即可。
另外需要将第十章的sbi_lib.c
以及sbi_lib.h
拷贝到对应目录,以及对sbi_main.c进行如下修改:
//sbi/sbi_main.c
{
unsigned long val;
+ /*
+ * 配置PMP
+ * 所有地址空间都可以访问
+ */
+ sbi_set_pmp(0, 0, -1UL, PMP_RWX);
+ sbi_set_pmp(1, 0x80000000, 0x40000, PMP_RWX);
其中sbi_set_pmp
函数也需要从第十章的sbi_main.c
内拷贝而来。
如果嫌弃麻烦的话也可以访问我的gitee分支: https://gitee.com/gaoxinglei/risc-v_practice
VScode调试问题
由于我是采用WSL的实验方式,VScode采用ssh远程连接,需要以下插件:
- Remote-SSH(Host用于连接WSL)
- C/C++(Ubuntu22.04 用于代码高亮跳转等)
理解调试方法
书上以及相关资料采用的其实是使用gdb-multiarch
选择选择对应的elf进行调试的,使用remote的方式ip+port的形式。一般的调试形式如下:
gdb-multiarch benos.elf
target remote localhost:1234
然后我们可以配置这些手动的过程到launch.json
,并且观察也更加方便。
配置lanuch.json
理解了上面的过程我们再来看这份lanuch.json就更加方便了
//launch.json
{
"version": "0.2.0",
"configurations": [
{
"name": "riscvkernel",
"type": "cppdbg",
"request": "launch",
"program": "${fileDirname}/../benos.elf",
"args": [],
"stopAtEntry": true,
"cwd": "${workspaceFolder}",
"miDebuggerServerAddress": "127.0.0.1:1234",
"miDebuggerPath": "gdb-multiarch",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"preLaunchTask": "riscvbuild",
"setupCommands": [
{
"description": "pretty printing",
"text": "-enable-pretty-printing",
"ignoreFailures": true,
},
],
},
]
}
其中的miDebuggerServerAddress
就是对应我们qemu的地址,然后miDebuggerPath
来选择我们的gdb工具。program
对应我们的命令后接的要调试的程序,我们这里选择benos.elf
,如果需要调试书籍里面的sbi
也可以换成对应的文件,再建一个调试即可,具体参考我的gitee。这里我发现参考代码都是源码上一级就是Makefile,所以我可以简单的写成../benos.elf
这种形式,其他的可能需要思考更合理的判断方式。但注意到我们其实还有一个preLaunchTask
预处理,这块就是帮助我们敲make解放双手。
配置tasks.json
上面说到的preLaunchTask
,其实就是在这里进行定义的,具体内容如下:
// tasks.json
{
"version": "2.0.0",
"tasks": [
{
"label": "riscvbuild",
"type": "shell",
"isBackground": true,
"command": "cd ${fileDirname}/..;make;make debug",
"problemMatcher": [
{
"pattern": [
{
"regexp": ".",
"file": 1,
"location": 2,
"message": 3
}
],
"background": {
"beginsPattern": ".*-kernel benos.elf -S -s",
"endsPattern": "."
}
}
]
}
]
}
主要注意label要和launch.json文件进行对应,command就是编译指令,我们这里也是因为目录层级简单可以这么简单书写。
beginsPattern
是屏幕识别到相关代码才开始调试,否则认为编译失败,类似于下图:
就是未识别到对应信息,我们这里采用Makefile会输出的一句话即可
成果展示
经过上面的配置,我们就可以对远程gdb进行调试了,也符合我们日常的使用习惯。
小插曲
这个地方不定时更新遇到的问题
.S文件不能打断点
需要打开这个设置,注意打开的是WSL的设置而不是本地设置哦。
最后
相关源码可以在 https://gitee.com/gaoxinglei/risc-v_practice进行获取哦