开发一个RISC-V上的操作系统(一)—— 环境搭建

在前面我们使用Verilog实现了一个简易的RISC-V处理器,并且能烧录到板子上跑一些简单C程序,传送门:

RISC-V处理器的设计与实现(一)—— 基本指令集_risc_v处理器_Patarw_Li的博客-CSDN博客

RISC-V处理器的设计与实现(二)—— CPU框架设计_Patarw_Li的博客-CSDN博客

RISC-V处理器的设计与实现(三)—— 上板验证_Patarw_Li的博客-CSDN博客

接下来我会开始编写一个riscv上的简易操作系统,然后放到我们做的riscv处理器上运行,参考的资料和视频链接如下:

[完结] 循序渐进,学习开发一个RISC-V上的操作系统 - 汪辰 - 2021春

riscv-operating-system-mooc: 开放课程《循序渐进,学习开发一个 RISC-V 上的操作系统》配套教材代码仓库。mirror to https://github.com/plctlab/riscv-operating-system-mooc

一、开发环境配置

使用的开发环境如下:

$ lsb_release -a
No LSB modules are available.
Distributor ID:    Ubuntu
Description:    Ubuntu 20.04.2 LTS
Release:    20.04
Codename:    focal

$ uname -r
5.15.0-76-generic

安装Ubuntu 20.04官方提供的 GNU工具链和 QEMU 模拟器:

sudo apt update
sudo apt install build-essential gcc make perl dkms git gcc-riscv64-unknown-elf gdb-multiarch qemu-system-misc

其中 gcc-riscv64-unknown-elf 就是我们的交叉编译工具,可以把程序编译成riscv上的可执行文件; gdb为debug工具;qemu是一个模拟器,可以模拟出riscv系统。

二、测试

在配置好开发环境后,我们可以用一个程序来测试一下,下面是前面用到的led流水灯程序,我们会在Ubuntu上把这个C程序利用交叉编译工具链编译成二进制.bin文件,然后通过串口将.bin文件烧录到处理器的rom中:

// led流水灯程序
int main(){
    int* point;
    int sum1 = 1; // 0001
    int sum2 = 2; // 0010
    int sum4 = 8; // 1000
    point = (int*) 0x00000000;
    *point = sum1;
    while(1){
        // 第一个灯亮起
        *point = sum1;
        for(int i = 0; i < 1000000; i++); // delay

        // 第二个灯亮起
        *point = sum2;
        for(int i = 0; i < 1000000; i++); // delay

        //第四个灯亮起
        *point = sum4;
        for(int i = 0; i < 1000000; i++); // delay
    }
    return 0;
}

然后我们需要编译我们的led程序:

riscv64-unknown-elf-gcc -c -nostdlib -march=rv32i -mabi=ilp32 led_ctr.c -o main.o
  • c 选项是编译、汇编到目标代码,但不进行链接。
  • nostdlib 告诉编译器不要把标准库编译进去。
  • march=rv32i -mabi=ilp32 用于指定指令集架构和 ABI,因为我们只实现了部分整数指令,所以使用rv32i。

编译后,我们可以得到 main.o,它是一个 ELF 文件。我们只需要 .text 部分的机器指令,所以用 objcopy 对它进行处理:

riscv64-unknown-elf-objcopy -O binary -j .text main.o main.bin
  • O binary 选项用于输出纯二进制文件。
  • j .text 是告诉它只保留 .text 部分。

经过处理,生成的二进制文件只含有机器指令。但此时的程序并不能直接运行。我们用 objdump 进行反编译,看看生成的汇编是怎么样的:

riscv64-unknown-elf-objdump -D -b binary main.bin -mriscv

然后编写串口上位机发送Python程序(串口发送程序已经更新至gitee仓库:cpu_prj: 一个基于RISC-V指令集的CPU实现):

    import serial

    try:
        ser = serial.Serial("COM3", 9600, timeout=0.5)
        if ser.is_open:
            print("COM3" + " open success!")
            with open('./main.bin', 'rb') as f:
                a = f.read()
            print("sending bin file")
            count = ser.write(a)
            print("send over, the number of byte: ", count)

    except Exception as e:
        print("---error---: ", e)


    # 如果报错ModuleNotFoundError: No module named 'serial',则执行 pip install pyserial

将编译好的.bin文件移动到和串口发送程序同目录下,记得修改串口,我这里用的串口为COM3,将烧录了riscv处理器的开发板与pc连接,然后点击运行,然后点击板子上的复位按键,即可看到3个流水灯开始轮流闪烁:

知道如何烧录程序到处理器上的话,之后操作系统的开发和验证都会方便很多。

三、开发前需要了解的知识

在进行操作系统的开发前,你应该要熟悉如下知识:

  1. 交叉编译
  2. 调试器GDB
  3. 模拟器QEMU
  4. 项目构造工具Make