在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 -s

mount -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》

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

PVZ2 植物克僵尸【第二期】

众所周知,PVZ2(植物大战僵尸2)中有许多恶心的僵尸,而我们不得不派出它们的————克星!(*为建议方法) 5.战机小鬼 战机小鬼,恶心会发射子弹,所以: 1&…

(三)JSP教程——JSP动作标签

JSP动作标签 用户可以使用JSP动作标签向当前输出流输出数据&#xff0c;进行页面定向&#xff0c;也可以通过动作标签使用、修改和创建对象。 <jsp:include>标签 <jsp:include>标签将同一个Web应用中静态或动态资源包含到当前页面中。资源可以是HTML、JSP页面和文…

【解决】:git clone项目报错fatal: fetch-pack: invalid index-pack output

象&#xff1a;之前一直使用gitee将个人学习和工作相关记录上传到个人gitee仓库&#xff0c;一直没出现过问题。直到有一天换电脑重新拉取代码发现出了问题&#xff0c;具体如下图&#xff1a; 原因分析&#xff1a; 经过查询发现主要原因是因为git clone的远程仓库的项目过大…

【强化学习】公平性Actor-Critic算法

Bringing Fairness to Actor-Critic Reinforcement Learning for Network Utility Optimization 阅读笔记 Problem FormulationLearning AlgorithmLearning with Multiplicative-Adjusted RewardsSolving Fairness Utility Optimization Evaluations 在网络优化问题中&#xff…

懒人网址导航源码v3.9源码及教程

懒人网址导航源码v3.9源码及教程 效果图使用方法部分源码领取源码下期更新预报 效果图 使用方法 测试环境 宝塔Nginx -Tengine2.2.3的PHP5.6 MySQL5.6.44为防止调试错误&#xff0c;建议使用测试环境运行的php与mysql版本首先用phpMyAdmin导入数据库文件db/db.sql 如果导入不…

QT-TCP通信

网上的资料太过于书面化&#xff0c;所以看起来有的让人云里雾里&#xff0c;看不懂C-tcpsockt和S-tcpsocket的关系 所以我稍微画了一下草图帮助大家理解两个套接字之间的关系。字迹有的飘逸勉强看看 下面是代码 服务端&#xff1a; MainWindow::MainWindow(QWidget *parent) …

Kubernetes 教程:在 Containerd 容器中使用 GPU

原文链接:Kubernetes 教程:在 Containerd 容器中使用 GPU 云原生实验室本文介绍了如何在使用 Containerd 作为运行时的 Kubernetes 集群中使用 GPU 资源。https://fuckcloudnative.io/posts/add-nvidia-gpu-support-to-k8s-with-containerd/ 前两天闹得沸沸扬扬的事件不知道…

Golang | Leetcode Golang题解之第67题二进制求和

题目&#xff1a; 题解&#xff1a; func addBinary(a string, b string) string {ans : ""carry : 0lenA, lenB : len(a), len(b)n : max(lenA, lenB)for i : 0; i < n; i {if i < lenA {carry int(a[lenA-i-1] - 0)}if i < lenB {carry int(b[lenB-i-1…

6W 1.5KVDC. 单、双输出 DC/DC 电源模块——TP2L-6W 系列

TP2L-6W系列是一款高性能、超小型的电源模块&#xff0c;2:1电压输入&#xff0c;输出有稳压和连续短路保护功能&#xff0c;隔离电压为1.5KVDC、作温度范围为–40℃到85℃。特别适合对输出电压的精度有严格要求的地方&#xff0c;外部遥控功能对您的设计又多一项选择&#xff…

Liunx磁盘管理(中)

Liunx磁盘管理(上)-CSDN博客 目录 查看块设备信息 lsblk&#xff08;list block devices&#xff09; fdisk gdisk parted blkid df&#xff08;disk free&#xff09; 虚拟机添加硬盘 步骤&#xff1a; 磁盘分区 MBR格式创建分区 使用方法 替代工具 GPT分区格式…

【C 数据结构-动态内存管理】2. 边界标识法管理动态内存

文章目录 【 1. 边界标识法的结构设计 】【 2. 分配算法 】【 3. 回收算法 】3.1 空闲块两侧是占用块3.2 空闲块左侧是空闲块3.3 空闲块右侧是空闲块3.3 空闲块两侧是空闲块 边界标识法 可以解决系统中内存碎片过多而无法使用的问题。 【 1. 边界标识法的结构设计 】 使用边界…

绘唐ai工具怎么获取

这款产品的最大亮点在于其高度精准的语音克隆能力&#xff0c;利用先进的模型&#xff0c;能够捕捉到用户独特的音调、音高和调制方式&#xff0c;使用户能够以前所未有的方式复制和利用自己的声音。仅需10秒钟的录制时间&#xff0c;即可实现声音的克隆&#xff0c;相当便捷。…

Spring Cloud 整合Sentinel

1、引入依赖 版本说明 alibaba/spring-cloud-alibaba Wiki GitHub 父pom <spring.cloud.version>Hoxton.SR12</spring.cloud.version> <spring.cloud.alibaba.version>2.2.10-RC1</spring.cloud.alibaba.version>Sentinel应用直接引用starter <…

基于FPGA的数字密码锁电路Verilog代码Quartus仿真

名称&#xff1a;基于FPGA的数字密码锁电路Verilog代码Quartus仿真(文末获取&#xff09; 软件&#xff1a;Quartus 语言&#xff1a;Verilog 代码功能&#xff1a; 数字密码锁电路的设计 1.设计任务:设计并制作数字密码锁电路 2.设计要求 1.用EDA实训仪的I/设备和PLD志…

纯血鸿蒙APP实战开发——折叠屏扫描二维码方案

折叠屏扫描二维码方案 介绍 本示例介绍使用自定义界面扫码能力在折叠屏设备中实现折叠态切换适配。自定义界面扫码使用系统能力customScan&#xff0c;其提供相机流的初始化、启动扫码、识别、停止扫码、释放相机流资源等能力。折叠屏折叠状态通过监听display的foldStatusCha…

Hive3.0新特性:Materialized Views 物化视图

Materialized Views 物化视图 在 Apache Hive 3.0 中引入了物化视图&#xff08;Materialized Views&#xff09;的支持&#xff0c;它们是预先计算并缓存了查询结果的数据结构&#xff0c;以提高查询性能和降低延迟。物化视图通过将查询的结果存储在物理表中来实现&#xff0…

深入理解指针1

目录 如对您有帮助&#xff0c;还望三连支持&#xff0c;谢谢&#xff01;&#xff01;&#xff01; 1.内存和地址 计算机中常⻅的单位&#xff08;补充&#xff09;&#xff1a; 如何理解编址 2.指针变量和地址 2.1取地址操作符&#xff08;&&#xff09; 2.2指针变…

数据结构学不会?数据结构可视化网站来了

目录 前言 图码网站 算法可视化 算法编辑器 数据结构全书 数据结构课程 总结 前言 数据结构与算法在计算机的学习中应该是许多小白最头疼的东西&#xff0c;明明听的时候那么容易&#xff0c;为什么转换成代码就那么抽象呢&#xff1f; 有没有一个网站可以数据结构与算…

【RabbitMQ 三】Java客户端开发

本文引用的代码源自《RabbitMQ实战指南》 关键的类和接口主要有Channel、Connection、ConnectionFactory、Consumer等&#xff0c;它们主要的作用如下&#xff1a; Channel&#xff1a;实现AMQP协议层的操作Connection&#xff1a;开启信道&#xff08;Channel&#xff09;、注…

k8s集群统一设置时间

1 安装时间同步需要软件 yum install -y ntpdate2 设置时间 2.1 手动设置时间 date -s "20190712 18:30:50" hwclock --systohc2.2 在线更新时间 ntpdate 0.asia.pool.ntp.org # 强制把系统时间写入CMOS clock -w3 强制把系统时间写入CMOS hwclock作用与clock相…