关于RISC-V OS开发 1 OS启动,开始起飞

2022-05-19   大方老师单片机

原标题:关于RISC-V OS开发 1 OS启动,开始起飞

关于RISC-V OS 1 OS启动开始起飞

///插播一条:我自己在今年年初录制了一套还比较系统的入门单片机教程,想要的同学找我拿就行了免费的,私信我就可以~点我头像黑色字体加我地球呺也能领取哦。最近比较闲,带做毕设,带学生参加省级或以上比///

QEMU模拟的是整SoC,我们需要验证并调OS,外设是必不可少的QEMUbootloader映射到物理地址空间0x1000-0xf000的这ROM中,RAM映射0x8000000处。剩下主要是各种外设和支QEMU自身。

xv6的结构:

xv6是宏内核kernel下的文件.c/.h/.S)会被编译成一个叫kernel的二进制文件,然后这个二进制文件会被运行kernle mode中。

第二个部分user。这基本上是运行user mode的程序。这也是为什么一个目录称kernel,另一个目录称user的原因。

第三部分叫mkfs。它会使fs.img创建一个空的文件镜像,我们会将这个镜像存在磁盘上,这样我们就可以直接使用一个空的文件系统。

makefilekernel下的文件编译.o文件,之后会使ld链接成可执行文kernel,并使objdumpkernel.asm便于调试。

最后会调qemu来运行起xv6

xv6编译过程

qemu有两个依赖文件$K/kernelfs.img。其$K/kernel这样生成:

$K/kernel: $(OBJS) $K/kernel.ld $U/initcode

$(LD) $(LDFLAGS) -T $K/kernel.ld -o $K/kernel $(OBJS)

$(OBJDUMP) -S $K/kernel > $K/kernel.asm

$(OBJDUMP) -t $K/kernel | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > $K/kernel.sym

$K/kernel就是整xv6内核的二进制文件。它的依赖文件就/kernel下的所有内容.c.S文件由隐含规则自动生.o文件xv6的编译首先就是编/kernel下的所.c.S文件生成相.o文件,之后再根kernel.ld进行链接生kernel二进制文件,并将其反汇编成用于调试的汇编文件。此外对$U/initcode.S这个文件也要编译、链接、反汇编,具体作用见后文。

再之后是user文件夹下的用户程序进行编译、链接、反汇编。然后使makefs把这些用户程序的二进制文件写fs.img这个磁盘镜像上。最后就可以使qemu-system-riscv64命令启动虚拟机了。这里本质上是通C语言来模拟仿RISC-V处理器。

qemu-system-riscv64 -machine virt -bios none -kernel kernel/kernel -m 128M -smp 3 -nographic

-drive file=fs.img,if=none,format=raw,id=x0 -device virtio-blk-device,drive=x0,bus=virtio-mmio-bus.0

我们来看传QEMU的几个参数:

-kernel:这里传递的是内核文件kernel目录下kernel文件),这是QEMU中运行的程序文件

-m:这里传递的RISC-V虚拟机将会使用的内存数量

-smp:这里传递的是虚拟机可以使用CPU核数

-drive:传递的是虚拟机使用的磁盘驱动,这里传入的fs.img文件

这样XV6QEMU中启动了QEMU就是C程序,它通C语言来完全模拟硬件的行为。

xv6启动过程

RISC-V采用内存映I/O的方式,主板的设计人员决定了,在完成了虚拟到物理地址的翻译之后,如果得到的物理地址大0x80000000会走DRAM芯片,如果得到的物理地址低0x80000000会走向不同I/O设备。这是由这个主板的设计人员决定的物理结构。如果你想要查看这里的物理结构,你可以阅读主板的手册,手册中会一一介绍物理地址对应关系QEMU也会默0x80000000是物理内存的起始处,它会从这里开始执行指令。kernel/kernel.ldkernel/entry.S中的指令放0x80000000处,让每CPU都从这里开始执行kernel/entry.S的作用就是为每CPU接下来运C程序设置4KB大小的栈。之后会跳kernel/start.cstart()函数。它M模式下进行一些初始化,然后通mretS模式进入main.c中。main()CPU0会完成绝大多数初始化并且分init进程。接着等CPU1CPU2完成自己的一per-CPU初始化之后,进scheduler()中,开始选择进程来执行。从此就进入OS死循当中,永远不会返回了。