在QEMU上运行OpenSBI+Linux+Rootfs

2024-05-07 21:36
文章标签 linux 运行 rootfs qemu opensbi

本文主要是介绍在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》

这篇关于在QEMU上运行OpenSBI+Linux+Rootfs的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/968455

相关文章

防止Linux rm命令误操作的多场景防护方案与实践

《防止Linuxrm命令误操作的多场景防护方案与实践》在Linux系统中,rm命令是删除文件和目录的高效工具,但一旦误操作,如执行rm-rf/或rm-rf/*,极易导致系统数据灾难,本文针对不同场景... 目录引言理解 rm 命令及误操作风险rm 命令基础常见误操作案例防护方案使用 rm编程 别名及安全删除

Linux下MySQL数据库定时备份脚本与Crontab配置教学

《Linux下MySQL数据库定时备份脚本与Crontab配置教学》在生产环境中,数据库是核心资产之一,定期备份数据库可以有效防止意外数据丢失,本文将分享一份MySQL定时备份脚本,并讲解如何通过cr... 目录备份脚本详解脚本功能说明授权与可执行权限使用 Crontab 定时执行编辑 Crontab添加定

使用docker搭建嵌入式Linux开发环境

《使用docker搭建嵌入式Linux开发环境》本文主要介绍了使用docker搭建嵌入式Linux开发环境,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 目录1、前言2、安装docker3、编写容器管理脚本4、创建容器1、前言在日常开发全志、rk等不同

linux系统上安装JDK8全过程

《linux系统上安装JDK8全过程》文章介绍安装JDK的必要性及Linux下JDK8的安装步骤,包括卸载旧版本、下载解压、配置环境变量等,强调开发需JDK,运行可选JRE,现JDK已集成JRE... 目录为什么要安装jdk?1.查看linux系统是否有自带的jdk:2.下载jdk压缩包2.解压3.配置环境

Linux搭建ftp服务器的步骤

《Linux搭建ftp服务器的步骤》本文给大家分享Linux搭建ftp服务器的步骤,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录ftp搭建1:下载vsftpd工具2:下载客户端工具3:进入配置文件目录vsftpd.conf配置文件4:

Linux实现查看某一端口是否开放

《Linux实现查看某一端口是否开放》文章介绍了三种检查端口6379是否开放的方法:通过lsof查看进程占用,用netstat区分TCP/UDP监听状态,以及用telnet测试远程连接可达性... 目录1、使用lsof 命令来查看端口是否开放2、使用netstat 命令来查看端口是否开放3、使用telnet

Linux系统管理与进程任务管理方式

《Linux系统管理与进程任务管理方式》本文系统讲解Linux管理核心技能,涵盖引导流程、服务控制(Systemd与GRUB2)、进程管理(前台/后台运行、工具使用)、计划任务(at/cron)及常用... 目录引言一、linux系统引导过程与服务控制1.1 系统引导的五个关键阶段1.2 GRUB2的进化优

Linux查询服务器 IP 地址的命令详解

《Linux查询服务器IP地址的命令详解》在服务器管理和网络运维中,快速准确地获取服务器的IP地址是一项基本但至关重要的技能,下面我们来看看Linux中查询服务器IP的相关命令使用吧... 目录一、hostname 命令:简单高效的 IP 查询工具命令详解实际应用技巧注意事项二、ip 命令:新一代网络配置全

linux安装、更新、卸载anaconda实践

《linux安装、更新、卸载anaconda实践》Anaconda是基于conda的科学计算环境,集成1400+包及依赖,安装需下载脚本、接受协议、设置路径、配置环境变量,更新与卸载通过conda命令... 目录随意找一个目录下载安装脚本检查许可证协议,ENTER就可以安装完毕之后激活anaconda安装更

Linux查询服务器系统版本号的多种方法

《Linux查询服务器系统版本号的多种方法》在Linux系统管理和维护工作中,了解当前操作系统的版本信息是最基础也是最重要的操作之一,系统版本不仅关系到软件兼容性、安全更新策略,还直接影响到故障排查和... 目录一、引言:系统版本查询的重要性二、基础命令解析:cat /etc/Centos-release详