本文基于helloworld示例,介绍示例代码如何构建和运行,以及介绍关键的目录结构、文件、函数等。
1. 示例代码构建
1.1 代码下载
1.2 代码编译
$ make
2. 示例代码运行
2.1 QEMU安装
示例基于RISC-V virt平台,运行示例程序前需要安装QEMU模拟器,安装命令如下。
$ sudo apt install qemu-system-riscv64
2.2 运行
QEMU运行命令描述在Makefile中
执行命令如下
$ make run
也可以通过如下命令运行
$ qemu-system-riscv64 -nographic -machine virt -m 128M -bios m_mode.bin -device loader,file=s_mode.bin,addr=0x80200000 -kernel s_mode.elf
LOG如下
_____ ____ _____
/ ____| _ \_ _|
| (___ | |_) || |
\ \___ \| _ < | |
____) | |_) || |_
|_|_____/|____/_____|
Hello World!!!
退出QEMU方法
-
ctrl+a
-
x
3. 示例代码介绍
以helloworld为例。
3.1 目录结构介绍
3.1.1 第一级目录结构
.
├── include # 头文件
├── lib # 库
├── Makefile # makefile
├── sbi # sbi,运行在 M mode
└── src # 主函数相关,运行在 S mode
3.1.2 sbi目录结构(M mode程序)
sbi
├── riscv_asm.c # csr寄存器读写
├── sbi_asm_offsets.h # 寄存器偏移定义
├── sbi_boot.S # M mode启动文件
├── sbi_entry.S # 异常和中断处理,汇编部分
├── sbi_error.h # 错误号定义
├── sbi_linker.ld # 链接脚本
├── sbi_main.c # sbi主函数(M mode)
├── sbi_timer.c # timer驱动
├── sbi_timer.h # timer驱动头文件
├── sbi_trap.c # 异常和中断处理,C语言部分
├── sbi_trap.h # 异常号定义
└── uart.c # uart驱动
3.1.3 src目录结构(S mode程序)
src
├── boot.S # S mode启动文件
├── linker.ld # 链接脚本
├── main.c # main函数
└── system.c # 字符打印函数实现
3.2 启动介绍
3.2.1 M mode和 S mode
程序最开始运行在 M mode,经过一些初始化后,会切换到 S mode运行。切换操作详见 sbi/sbi_main.c 的 sbi_main函数中,通过 mret 指令实现。
3.2.2 启动时函数的跳转流程
-
sbi/sbi_boot.S: _start 函数(M mode)
-
sbi/sbi_main.c: sbi_main 函数(M mode)
-
src/boot.S: _start 函数(S mode)
-
src/main.c: main 函数(S mode)
3.3 main介绍
用户编写实验程序可以在 src/main.c 文件中进行。该函数运行在 S mode。
int main(void)
{
printk("Hello World!!!\n");
while (1) {
;
}
return 0;
}