在QEMU上运行OpenSBI+Linux+Rootfs

在QEMU上运行OpenSBI+Linux+Rootfs

  • 1 编译QEMU
  • 2 安装交叉编译工具
  • 3 编译OpenSBI
  • 4 编译Linux
  • 5 创建根文件系统
    • 5.1 编译busybox
    • 5.2 创建目录结构
    • 5.3 制作文件系统镜像
      • 5.3.1 创建 ext2 文件
      • 5.3.2 将目录结构拷贝进 ext2 文件
      • 5.3.3 取消挂载
  • 6 运行OpenSBI+Linux+Rootfs

本文所使用的版本,如下:

  • qemu-7.1.0
  • 交叉编译工具:riscv64-glibc-ubuntu-20.04-nightly-2023.01.31-nightly
  • opensbi v1.2
  • linux 5.15.158
  • busybox 1.36.1

1 编译QEMU

下载qemu-7.1.0源码

wget https://download.qemu.org/qemu-7.1.0.tar.xz

解压

tar xvJf qemu-7.1.0.tar.xz

进入目录

cd qemu-7.1.0

配置qemu

./configure --target-list=riscv64-softmmu,riscv64-linux-user --prefix=/opt/qemu

riscv64-softmmu 指定生成riscv64 system emulator
riscv64-linux-user 指定生成riscv64 user mode emulator

执行编译

make -j`nproc`

在qemu-7.1.0/build/目录下,生成了可执行程序qemu-system-riscv64

查看qemu版本

./qemu-system-riscv64 --version

可以看到版本号为:QEMU emulator version 7.1.0

安装(可选)

sudo make install

安装时,会将可执行程序qemu-system-riscv64,以及头文件等其他文件,拷贝至/opt/qemu目录下。

到这里,模拟器已经准备好了,我们还需要准备OpenSBI(Bootloader)、Linux Kernel以及文件系统(busybox)。
接下来,我们继续。

2 安装交叉编译工具

我们先安装交叉编译工具,以便后续编译OpenSBI、Linux Kernel以及busybox。

下载编译好的RISC-V交叉编译器:
riscv64-glibc-ubuntu-20.04-nightly-2023.01.31-nightly.tar.gz

解压

tar -xvzf riscv64-glibc-ubuntu-20.04-nightly-2023.01.31-nightly.tar.gz

编辑.bashrc

vim ~/.bashrc

将编译器bin路径(/home/tools/riscv/bin替换为自己的路径),加入.bashrc文件末尾。

export PATH=/home/tools/riscv/bin:$PATH

使路径生效

source ~/.bashrc

最后,查看编译器版本,以验证安装

riscv64-unknown-linux-gnu-gcc -v

编译器环境搭建好了。

3 编译OpenSBI

下载源码

git clone https://github.com/riscv-software-src/opensbi.git

进入目录

cd opensbi/

获取V1.2版本源码

git checkout v1.2

实验时,使用最新版本,会报错,因此这里使用V1.2版本。
具体报错信息,如下:
qemu-system-riscv64: Some ROM regions are overlapping
These ROM regions might have been loaded by direct user request or by default.
They could be BIOS/firmware images, a guest kernel, initrd or some other file loaded into guest memory.
Check whether you intended to load all this guest code, and whether it has been built to load to the correct addresses.
The following two regions overlap (in the memory address space):
fw_jump.elf ELF program header segment 1 (addresses 0x0000000000000000 - 0x0000000000023940)
mrom.reset (addresses 0x0000000000001000 - 0x0000000000001028)

设置环境变量

export CROSS_COMPILE=riscv64-unknown-linux-gnu-

执行编译

make PLATFORM=generic

编译完后,在opensbi/build/platform/generic/firmware/目录下
生成的固件,如下所示:
在这里插入图片描述

生成的固件有三种类型:dynamic、jump和payload

  • dynamic:带有动态信息的固件
  • jump:指定下一级的boot地址跳转
  • payload:包含下一级boot的二进制内容,通常是uboot/linux

这里我们使用jump类型固件(fw_jump.elf),OpenSBI运行后,可以直接跳转到kernel运行。

因为opensbi本身就是一个bootloader,因此可以不使用uboot引导kernel,通过opensbi的jump固件,可以直接跳转到kernel启动。

4 编译Linux

Linux内核官网:https://www.kernel.org,进去找到linux-5.15.158版。

这里,可直接下载linux-5.15.158源码:
https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.158.tar.xz

解压

tar -xf linux-5.15.158.tar.xz

进入目录

cd linux-5.15.158

配置环境变量

export ARCH=riscv
export CROSS_COMPILE=riscv64-unknown-linux-gnu-

使用linux默认配置

make defconfig

执行编译

make -j`nproc`

编译完成后,在linux-5.15.158/arch/riscv/boot下生成可执行文件Image

5 创建根文件系统

5.1 编译busybox

下载busybox源码

git clone https://git.busybox.net/busybox
cd busybox

打开busybox配置界面

make ARCH=riscv CROSS_COMPILE=riscv64-unknown-linux-gnu- menuconfig

配置为生成静态二进制可执行程序,选择“Build static binary (no shared libs)”

在这里插入图片描述

如果是动态编译,那么在kernel中运行时,需要携带运行库。
没有运行库,就会报错: Starting init: /sbin/init exists but couldn’t execute it (error -8)

执行编译与安装

make ARCH=riscv CROSS_COMPILE=riscv64-unknown-linux-gnu- -j`nproc`
make ARCH=riscv CROSS_COMPILE=riscv64-unknown-linux-gnu- install -j`nproc`
cd ..

源码目录下,生成了二进制文件: busybox

5.2 创建目录结构

创建主要目录

mkdir root && cd root
mkdir -p bin etc etc/init.d dev lib proc opt sbin sys tmp usr usr/bin usr/lib usr/sbin

将busybox文件,复制到bin目录中

cp /path/to/busybox/busybox bin/busybox

生成指向init文件的符号链接

ln -s ../bin/busybox sbin/init
ln -s sbin/init init
ln -s ../bin/busybox bin/sh

接下来,解释这些命令。

  • ln -s ../bin/busybox sbin/init:表示在sbin目录下创建一个名为 init 的符号链接,该链接指向父目录中的 bin 子目录下的 busybox 文件。
    在标准的 Linux 发行版中,/sbin/init 是初始化系统的入口点,即这个init文件,就是init进程,它是内核启动的第一个用户级进程。
    因此,需要使用 BusyBox 替代标准的 init 进程。
    需要将 BusyBox 的路径链接到 /sbin/init 或 /init,以便在系统启动时能够找到并执行它。
  • ln -s sbin/init init:表示在当前目录下创建一个名为init的符号链接,该链接指向sbin/init文件。
  • ln -s ../bin/busybox bin/sh:表示在bin目录下创建一个名为sh的符号链接,该链接指向父目录中的 bin 子目录下的 busybox 文件。
    许多脚本和程序都依赖于 /bin/sh 的存在。
    通过创建这个链接,可以确保这些脚本能够在使用BusyBox的系统中正常运行。
    比如,当 init 进程先执行,然后会调用 /etc/init.d/rcS 启动脚本,此时如果没有/bin/sh的话,就会报错:can’t run ‘/etc/init.d/rcS’: No such file or directory


    若没有找到init文件时,会报以下错误:
    [ 0.584936] Run /sbin/init as init process
    [ 0.593521] Run /etc/init as init process
    [ 0.594686] Run /bin/init as init process
    [ 0.595995] Run /bin/sh as init process
    [ 0.596717] Kernel panic - not syncing: No working init found.

创建必要设备节点

sudo mknod dev/sda b 8 0 
sudo mknod dev/console c 5 1

创建初始化脚本

vim etc/init.d/rcS

在rcS中填入如下内容

#!/bin/sh
/bin/busybox mount -o remount rw /
/bin/busybox --install -smount -t proc proc /proc
mount -t sysfs sys /sys

接下来,解释这些命令。

  • /bin/busybox mount -o remount rw /:使用 BusyBox 中的 mount 命令,来重新挂载(remount)根文件系统(/)为读写模式(rw)。
    从Kernel日志:VFS: Mounted root (ext2 filesystem) readonly on device 254:0,发现默认按照只读挂载,因此本命令就是,以可读写重新挂载。
  • /bin/busybox --install -s :将 BusyBox 安装到当前系统中,包括在/bin目录下,创建大量常用命令的符号链接(可作为单独命令使用),会进行写入操作,因此需要文件系统可写。

赋予rcS文件可执行权限

chmod +x etc/init.d/rcS

此时root目录结构,如下所示:

在这里插入图片描述

到这里,root目录下,已经具备了一个linux文件系统的基本目录了。

5.3 制作文件系统镜像

我们,将上述root目录结构,打包成ext2镜像文件。

5.3.1 创建 ext2 文件

生成4M大小的,空白镜像文件rootfs.ext2

dd if=/dev/zero of=rootfs.ext2 bs=1M count=4

将镜像文件rootfs.ext2,格式化为ext2文件系统

mkfs.ext2 rootfs.ext2

5.3.2 将目录结构拷贝进 ext2 文件

创建目录

mkdir /mnt/ext2/

将rootfs.ext2,挂载到/mnt/ext2/目录

mount -t ext2 rootfs.ext2 /mnt/ext2/

挂载到/mnt/ext2/目录后,当你在 /mnt/ext2/ 下写入文件或修改文件时,这些更改会反映到 rootfs.ext2 文件中。

拷贝root目录内容,至/mnt/ext2/

cp -pr root/* /mnt/ext2/

也就是,将目录结构拷贝进 rootfs.ext2 文件中了。

5.3.3 取消挂载

umount /mnt/ext2/
sync		# 强制内容立刻写入文件

到这里,我们已经对rootfs.ext2文件写入完毕,写入的内容,主要包括busybox、目录结构、rcS文件等。

rootfs.ext2,即为可供 Linux kernel 挂载所用的根文件系统。

6 运行OpenSBI+Linux+Rootfs

将fw_jump.elf、Image、rootfs.ext2,拷贝到qemu-7.1.0/build/目录下。

新建start-qemu.sh脚本,输入以下内容:

#!/bin/sh./qemu-system-riscv64 -M virt \
-bios fw_jump.elf \
-kernel Image \
-append "rootwait root=/dev/vda ro" \
-drive file=rootfs.ext2,format=raw,id=hd0 \
-device virtio-blk-device,drive=hd0 \
-netdev user,id=net0 -device virtio-net-device,netdev=net0 -nographic
  • bios,指定OpenSBI可执行文件fw_jump.elf
  • kernel,指定Linux镜像Image
  • drive,指定根文件系统rootfs.ext2

修改权限

chmod 777 start-qemu.sh

在QEMU中,运行OpenSBI+Linux+Rootfs

./start-qemu.sh

运行效果,如下所示:

在这里插入图片描述

成功进入Linux!

在这里插入图片描述

基本命令可用,使用poweroff命令可关机。

如果Kernel,发生panic异常时,通过Ctrl+C无法退出。
可以通过以下命令,来退出qemu:
kill $(ps aux | grep qemu | grep -v grep | awk '{print $2}')


参考链接:

  • 《手把手教你在QEMU上运行RISC-V Linux》
  • 《在 QEMU 上运行 RISC-V 64 位版本的 Linux》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/675641.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Facebook革命:数字社交的全新篇章

随着互联网的不断普及和科技的飞速发展,社交媒体已经成为现代社会不可或缺的一部分。在众多社交媒体平台中,Facebook以其广泛的用户群体和强大的功能而备受瞩目。然而,Facebook并非止步于现状,而是正在掀起一场数字社交的革命&…

环保访谈|浙江双视专注红外机器视觉及智能化应用,保障安全生产

近期,中联环保圈希姐采访了浙江双视科技股份有限公司环保行业销售总监孙波,深入了解了双视科技的发展历程、产品和解决方案、合作流程、核心竞争力以及未来规划。 双视于2014年创立,专注于红外机器视觉、人工智能技术与应用开发,…

矩阵相关运算1

矩阵运算是线性代数中的一个核心部分,它包含了许多不同类型的操作,可以应用于各种科学和工程问题中。 矩阵加法和减法 矩阵加法和减法需要两个矩阵具有相同的维度。操作是逐元素进行的: CAB or CA−B其中 A,B 和 C 是矩阵,且 C…

简单了解泛型

基本数据类型和对应的包装类 在Java中, 基本数据类型不是继承自Object, 为了在泛型代码中可以支持基本类型, Java给每个基本类型都对应了一个包装类型. 简单来说就是让基本数据类型也能面向对象.基本数据类型可以使用很多方法, 这就必须让它变成类. 基本数据类型对定的包装类…

HDLC协议

目录 1.概念 2.配置 3.HDLC帧结构 4.HDLC帧类型 1.概念 HDLC(High-level Data Link Control)高级数据链路控制位于链路层协议,传输单位是帧,它是一组用于在网络结点间传送数据的协议。其特点是各项数据和控制信息都以比特为单位&#xff…

神经网络极简入门

神经网络是深度学习的基础,正是深度学习的兴起,让停滞不前的人工智能再一次的取得飞速的发展。 其实神经网络的理论由来已久,灵感来自仿生智能计算,只是以前限于硬件的计算能力,没有突出的表现,直至谷歌的A…

bfs之八数码

文章目录 八数码解题思路图解举例算法思路 代码CPP代码Java代码 八数码 在一个 33的网格中,1∼8这 8个数字和一个 x 恰好不重不漏地分布在这 33 的网格中。 例如: 1 2 3 x 4 6 7 5 8在游戏过程中,可以把 x 与其上、下、左、右四个方向之一…

leetcode-字符串的排列-100

题目要求 思路 1.因为只涉及到字符,因此可以进行排序 2.创建临时字符串,当临时字符串temp的长度等于str的长度,作为判出条件。 3.创建一个标记的数组,每次在temp中插入一个字符,便在对应的数组下标设置为1&#xff0c…

初期Linux

一,系统分为 1.1window系统 个人 :win7,win8,Win10,Win11服务器版:window server 2003,window server 2008 1.2Linux系统 centos7redhatubantukali 1.3什么是Linux? Linux是基…

C++变量的作用域与存储类型

一 变量的作用域和存储类型 1 变量的作用域(Scope) 指在源程序中定义变量的位置及其能被读写访问的范围分为局部变量(Local Variable)和全局变量(Global Variable) 1)局部变量(Local Variable) 在语句块内定义的变量 形参也是局部变量 特点: 生存期是…

YzmCMS 7.0任意函数调用RCE 漏洞研究分析

YzmCMS是一款基于YZMPHP开发的一套轻量级开源内容管理系统,YzmCMS简洁、安全、开源、免费,可运行在Linux、Windows、MacOSX、Solaris等各种平台上,专注为公司企业、个人站长快速建站提供解决方案。 YzmCMS 某些接口调用了 db_pdo类的where方法 导致了远程命令执行漏洞&#xf…

python菜鸟级安装教程 -下篇(安装编辑器)

来来~接着上篇的来~ 安装好python.exe之后,我们可以根据cmd命令窗口,码代码。 这算最简单入门了~ 如果我们在安装个编辑器。是什么效果,一起体验一下吧 第一步,下载编辑器,选择官网,下载免费版本入门足…