Skip to main content

本文基于helloworld示例,介绍示例代码如何构建和运行,以及介绍关键的目录结构、文件、函数等。

1. 示例代码构建

1.1 代码下载

hello world示例下载

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方法

  1. ctrl+a

  2. 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 启动时函数的跳转流程

  1. sbi/sbi_boot.S: _start 函数(M mode)

  2. sbi/sbi_main.c: sbi_main 函数(M mode)

  3. src/boot.S: _start 函数(S mode)

  4. 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;
}