手把手教你安装 Ubuntu 20.04和运行部署 QEMU:纯小白无需基础的虚拟化初体验(图文详解)

一、认识 QEMU

1.1 🔍 QEMU是什么?虚拟开发板的神奇工具

QEMU是一款完全开源免费的仿真软件,就像是程序员手中的"魔法棒"!它不仅能像VMware那样虚拟出一台完整的电脑,更厉害的是可以模拟各种嵌入式开发板(ARM、MIPS、RISC-V等架构通吃),而且还能模拟串口、网卡、USB等各种外设。

在这里插入图片描述

想象一下:不用花一分钱买开发板,就能在自己的电脑上搭建一个完整的嵌入式开发环境,运行U-boot、Linux内核和文件系统,这不是很酷吗?

1.2 💡 为什么新手要用QEMU学嵌入式?

1. 🤯 真实开发板的各种"坑"

  • 买开发板要花钱(好板子不便宜!)
  • 硬件连接各种问题(线接错了?电源不稳?)
  • 环境配置复杂(驱动装不上?工具链不对?)
  • 容易损坏硬件(手抖烧了芯片?)

2. ✨ QEMU带来的学习革命

  • 零成本:完全免费,省下买开发板的钱
  • 零风险:随便折腾,不会烧坏任何硬件
  • 快速上手:几分钟就能搭建好开发环境
  • 功能完整:支持从bootloader到应用层的全流程开发
  • 跨平台:Windows/Mac/Linux都能用

1.3 🎯 QEMU能帮你学习哪些嵌入式技能?

学习内容传统方式QEMU方式
U-boot移植需要开发板完全模拟
Linux内核移植需要开发板完全模拟
驱动开发需要硬件支持模拟常见外设
应用开发需要开发板完全模拟
系统调试需要调试器使用GDB即可

💡 专家说:嵌入式开发80%的知识都可以在QEMU上学习!

1.4 🛠️ 本教程带你玩转什么?

我们将以ARM官方的vexpress开发板为例子,在Ubuntu系统上:

(1)安装配置QEMU

(2)移植U-boot引导程序

(3) 编译运行Linux内核

(4)搭建NFS根文件系统

(5)完成一个完整的嵌入式Linux开发环境

1.5 🌟 QEMU学习嵌入式5大优势

你是否想学嵌入式开发,但苦于没有开发板?

你是否想调试Linux内核,却怕搞坏真机?

QEMU 来拯救你啦!🎉


(1) 🛠️ 硬件仿真,0成本学习

  • 支持 树莓派、i.MX、Vexpress、RISC-V 等上百种开发板!
  • 不用买硬件,直接在电脑上仿真 ARM、MIPS、RISC-V 等 CPU!

(2)⚡ 极速开发,NFS 文件共享

  • 挂载主机的 /home/nfs 作为根文件系统,直接修改代码,实时生效
  • 编译内核、调试驱动,再也不用反复烧录 SD 卡!💾

(3) 🌐 网络配置超简单

  • 支持 TFTP 加载 U-Boot 和内核,NFS 挂载根文件系统,一键启动!
  • 不用折腾复杂的网络配置,开箱即用!🔌

(4)📚 适合各种学习场景

  • 嵌入式入门:仿真开发板,跑通第一个 LED 驱动!💡
  • Linux 内核调试:单步跟踪系统启动,再也不怕 panic!🐞
  • RTOS 开发:跑 FreeRTOS、Zephyr,轻松验证代码!

(5)💻 跨平台支持,Mac/Win/Linux 都能玩

  • 在 Ubuntu 上搭好环境,Windows 和 macOS 也能通过 WSL/Docker 使用!

1.6 📚 适合谁学习?

✔ 嵌入式开发入门新手

✔ 想学习Linux内核的小伙伴

✔ 预算有限的学生党

✔ 想验证想法的工程师

✔ 任何对嵌入式感兴趣的人!


二、Ubuntu虚拟机安装

2.1 安装 VMware Player

VMware Player 是一款虚拟机软件,通过它,用户可以在 Windows 操作系统上运行 Linux 系统。您可以访问 VMware Player 的官方网站进行下载:VMware Player 官方主页

建议您安装版本 15 Pro 或者更新的版本。以下是 VMware Player 16 的下载链接:
VMware Player 16 下载链接

2.2 下载 Ubuntu 20.04 镜像

为了在 VMware 虚拟机中运行 Linux 系统,我们选择使用 Ubuntu 20.04 版本。您可以通过以下链接下载 Ubuntu 20.04 镜像文件:
Ubuntu 20.04 镜像下载地址

请确保选择 Desktop 版本的 64 位镜像进行下载。直接下载地址:Ubuntu 20.04 64-bit Desktop 镜像

在这里插入图片描述

2.3 配置Ubuntu20.04在VMware-Player上的虚拟机环境

1. 点击创建新虚拟机

在这里插入图片描述

2. 自定义虚拟机

在这里插入图片描述

在这里插入图片描述

3. 选择稍后安装操作系统

在这里插入图片描述

客户机操作系统选择Linux,版本选择Ubuntu 64位

在这里插入图片描述

4. 虚拟机向导配置

虚拟机名称自己设一个名称

设置安装位置,推荐尽量安装在硬盘剩余空间较多的分区里

在这里插入图片描述

虚拟磁盘推荐设为存储为单个文件,磁盘大小根据自己需要设置

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
后续有俩个都按推荐即可

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5. 自定义硬件配置

在这里插入图片描述
这里需要把2.2下载的镜像文件使用ISO镜像导入
在这里插入图片描述
在这里插入图片描述

6. 开启虚拟机

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

7.给root用户设置密码:

sudo passwd root

8. 手动安装 VMware Tool

apt-get install open-vm-tools -y

在这里插入图片描述

apt-get install open-vm-tools-desktop -y

在这里插入图片描述

9. 添加网卡

这里我们需要两个网卡,一个用于上网,一个用于虚拟机和开发板桥接,添加两个网卡,都改为NAT连接

在这里插入图片描述
设置完以后,输入Ctrl+Alt+T,输入ping www.baidu.com,如果有反应,证明已经可以连上网络了

ping www.baidu.com

在这里插入图片描述

10. 设置软件源

软件源是存储软件包的集中式仓库,尤其在Linux发行版(如Ubuntu)中,提供方便的方式来管理和安装软件。Ubuntu采用集中式的软件仓库机制,将软件包分类存放在软件仓库中,便于用户管理和访问。这些仓库托管在各种镜像服务器上,当用户使用apt-get install命令安装软件包时,系统会从这些服务器下载所需的软件包。

工作原理如下:首先,用户执行apt update命令,程序分析/etc/apt/sources.list文件,查看列出的软件源地址。然后,系统联网查找这些地址对应的PackagesSourcesRelease列表文件。

/etc/apt/sources.list文件下的软件源地址

在这里可以添加国内软件源地址
在这里插入图片描述
如果有更新,系统会下载并存储在/var/lib/apt/lists/目录下。更改之后首先进行apt update

接着,当用户使用apt install命令安装软件包时,系统从已更新的列表中查找并下载所需的软件包,进行安装。

在这里插入图片描述

以下是经常涉及的几个目录的整理:

/var/lib/dpkg/available:存储软件包的描述信息,包括软件源中所有软件包的信息,涵盖已安装和未安装的软件包。
在这里插入图片描述

/var/cache/apt/archives:APT安装软件包时的临时存放路径,下载的软件包会保存在此处。

在这里插入图片描述

/etc/apt/sources.list:此文件包含软件源站点的信息。在执行apt install时,Ubuntu会从这些站点下载软件包并进行安装。

/var/lib/apt/lists:执行apt update命令时,从/etc/apt/sources.list中下载的软件包列表索引会保存到该目录中。
在这里插入图片描述

这些目录在软件包管理和更新过程中起着重要作用。

为了提高下载速率,这里我们把软件源设置为国内的软件源

点击左下角的九点状按钮(显示所有程序),点击全部,点击软件和更新,点击下载自,选择最佳服务器

在这里插入图片描述
在这里插入图片描述

这种机制使软件管理高效、便捷,确保软件的更新和安全性。通过软件源,用户可以轻松获取、安装和更新各种软件,简化软件管理的复杂性。

更换完毕以后,先更新软件源

#更新软件列表
sudo apt update 
#只针对于vmware-tools安装没有成功的情况,安装成功了就不必执行了
sudo apt install open-vm-tools 
sudo apt install build-essential openssh-server vim net-tools gcc-arm-linux-gnueabi git tree

安装内容:gcc、make、ssh、vim编辑器、网络基本工具(可以查网卡ip地址等)、arm编译器arm-linux-gnueabi-gcc、git、tree

推荐安装一个MobaXterm之类的终端管理器,方便通过ssh访问ubuntu

11. 重启系统

重启一下

reboot

三、在Ubuntu上安装QEMU

3.1 安装qemu

现在我们将正式启动 QEMU 的配置工作。本部分的所有设置都将基于 VExpress 开发板进行,因为 U-Boot 和内核对该开发板提供了全面的板级支持包(BSP),使得使用过程非常简单快捷。

Ubuntu 20.04 对 QEMU 的支持也很出色,我们可以直接通过 APT 包管理器安装。安装命令为:

sudo apt install qemu-system

通过这个命令,我们可以轻松地在 Ubuntu 20.04 系统中获取到 QEMU 的相关组件。

3.2 验证安装是否成功

(1)检查 QEMU 版本

打开终端,输入以下命令查看 QEMU 的版本信息。如果 QEMU 安装成功,您将看到其版本号。

qemu-system-x86_64 --version

请注意,如果您安装的是其他架构的 QEMU(如 ARM),请将 x86_64 替换为相应的架构。

在这里插入图片描述

(2) 查看已安装的包
使用以下命令查看系统中已安装的 QEMU 相关包:

dpkg -l | grep qemu

如果您看到与 QEMU 相关的包列表,说明安装成功。
在这里插入图片描述

(3) 运行 QEMU

可以尝试运行一个简单的 QEMU 命令,例如启动虚拟机。可以使用以下命令创建一个虚拟机:

qemu-system-x86_64 -m 512 -nographic

这将启动一个虚拟机,分配 512MB 的内存,并且不使用图形界面。如果您能够看到 QEMU 的启动界面或命令行,说明安装成功。

在这里插入图片描述

(4)检查帮助文档

输入以下命令查看 QEMU 的帮助文档。如果能够正常显示,说明程序运行正常:

qemu-system-x86_64 --help

在这里插入图片描述
查看支持的开发板

qemu-system-arm -M help

在这里插入图片描述

通过上述方法,可以确认 QEMU 是否已成功安装并能够正常运行。

在这里插入图片描述

四、编译Linux内核镜像

4.1 下载Linux内核源码

Linux 内核源码可以通过以下两种方式下载:

1. 官方网站下载

  • 您可以访问 Linux 内核的官方网站 www.kernel.org 下载最新的内核源码。

2. 国内镜像服务器下载

  • 为了获得更快的下载速度,您可以使用国内的镜像服务器。推荐的下载地址是: 清华大学镜像站

在这里插入图片描述
通过以上链接,您可以方便地获取到所需的 Linux 内核源码。

4.2 Linux 内核的编译和安装

1. 构建内核与配置编译选项

执行以下命令可以完成 Linux 内核的编译和安装工作:

# 进入主目录
mkdir -p /home/wangbeiy/Desktop/linux-cache

##(这里建议在非/home下重新建个文件夹)
cd /home/wangbeiy/Desktop/linux-cache


# 创建 tftpboot 目录
sudo mkdir tftpboot

# 修改权限
sudo chmod 777 tftpboot

# 进入 tftpboot 目录
cd tftpboot

# 创建 kernel 目录
mkdir kernel

# 进入 kernel 目录
cd kernel

# 下载指定版本的 Linux 内核源码
wget https://mirrors.tuna.tsinghua.edu.cn/kernel/v5.x/linux-5.10.99.tar.xz

# 解压下载的内核源码包
tar -xvf linux-5.10.99.tar.xz

# 进入解压后的内核源码目录
cd linux-5.10.99

# 使用文本编辑器打开 Makefile 文件,定位到第 371 行
gedit Makefile

Makefile 的第 371 行,您需要进行以下修改。

这是arm架构:

ARCH ?= arm
CROSS_COMPILE = arm-linux-gnueabi-

在这里插入图片描述
这是arm64架构:

ARCH		?= arm64
CROSS_COMPILE = aarch64-linux-gnu-

在这里插入图片描述

完成以上修改后,可以继续执行内核编译的后续步骤。这通常包括:

(1)构建 Linux 内核

make vexpress_defconfig 是用于构建 Linux 内核的一条命令,通常用于设置特定硬件平台(如 ARM 的 Versatile Express 平台)的默认内核配置。

vexpress_defconfig 是一个预定义的配置文件,包含了为 Versatile Express 开发板(VExpress)优化的内核选项。运行这条命令会将这些默认配置选项加载到 .config 文件中。

使用 defconfig 可以大大简化内核配置的过程,因为它为特定硬件提供了一个基本的、经过验证的配置,用户可以在这个基础上进行进一步的修改。

使用方法

进入内核源代码目录: 在终端中,导航到 Linux 内核的源代码目录。

运行命令:

make vexpress_defconfig

配置结果:

该命令会生成一个 .config 文件,里面包含了为 VExpress 平台优化的内核配置。可以使用 make menuconfigmake xconfig 进一步修改这些选项。
在这里插入图片描述
可能出现的问题:

这两个错误是由于没有安装 flexbison 工具引起的。安装这两个工具后,问题就会得到解决。
在这里插入图片描述

(2)配置编译选项

make menuconfig 是 Linux 内核和其他软件项目中用于配置编译选项的命令。它提供一个基于文本的用户界面,使用户能够方便地选择和修改编译选项,从而生成自定义的配置文件。

图形化界面: make menuconfig 提供了一个菜单驱动的界面,用户可以通过键盘导航,选择和修改各种配置选项,而不需要手动编辑 .config 文件。

模块选择: 用户可以选择要编译到内核中的模块,启用或禁用特定功能,对应的选项会自动更新到 .config 文件中。

依赖处理: 在选择某个选项时,make menuconfig 会自动处理依赖关系,确保所需的其他选项也被正确配置。

保存配置: 配置完成后,你可以保存所做的更改,生成或更新 .config 文件,以用于后续的编译过程。

使用方法

进入内核源代码目录: 在终端中,导航到 Linux 内核的源代码目录。

运行命令:

make menuconfig

进行配置: 使用方向键导航菜单,按 Enter 进入子菜单,使用空格键选择或取消选择选项

保存并退出: 配置完成后,选择“Save”选项以保存配置,然后退出界面。

在这里插入图片描述
在这里插入图片描述

出现这个界面表明内核配置已经完成,可以放心进行编译了。

安装依赖

在某些系统中,使用 make menuconfig 前需要确保安装了必要的依赖项,如 libncurses-dev。你可以通过以下命令安装这个包(以 Ubuntu/Debian 为例):

sudo apt-get install libncurses5-dev libncursesw5-dev

不安装依赖出现的报错:
在这里插入图片描述
在这里插入图片描述

2. 生成不同的内核映像和模块

在 Linux 内核的编译过程中,使用以下命令来生成不同的内核映像和模块。

(1)make zImage -j 6

  • 功能:这条命令用于编译内核的 zImage,它是一个压缩的内核映像,适用于嵌入式系统和一些特定的硬件平台。

  • 参数解释

    • -j 6:表示使用六个并行工作线程进行编译,可以加速编译过程。如果系统有更多的 CPU 核心,可以将数字增加到更高的值,例如 -j 4-j 8

(2)make modules -j 6

  • 功能:这条命令用于编译内核模块。这些模块是可加载的组件,提供额外的功能,可以在运行时动态加载,而不是将它们直接编译到内核中。

  • 参数解释

    • -j 6:同样表示使用六个并行线程进行编译。

(3)make dtbs -j 6

  • 功能:这条命令用于生成设备树二进制文件(Device Tree Blobs,简称 DTB)。设备树是一种数据结构,用于描述硬件设备的配置信息,以便内核在启动时能够正确识别和配置硬件。

  • 参数解释

    • -j 6:同样表示使用六个并行线程。

(4)make LOADADDR=0x60003000 uImage -j 6

  • 功能:这条命令用于生成 uImage,这是一个用于启动的内核映像,通常用于 U-Boot 引导加载程序。uImage 包含了额外的信息,例如加载地址和校验和,以便引导程序能够正确加载和验证内核。

  • 参数解释

    • LOADADDR=0x60003000:指定内核将被加载到内存的地址。这个地址通常需要根据目标硬件的要求进行设置。
    • -j 2:同样表示使用两个并行线程进行编译。

zImage 是通用的内核映像文件,modules 是未直接集成到内核中的模块(通常是驱动程序,设置为 (M) 的内容),dtbs 是编译生成的设备树文件,而 uImage 是专门为 U-Boot 引导程序准备的内核映像。在当前情况下我们可能不需要 uImage,但我们还是先进行编译,以便将来可能用到。在编译过程中可能会遇到一些错误。

在这里插入图片描述

装一个u-boot-tools即可解决

这些命令是编译 Linux 内核和相关组件的重要步骤。通过使用并行编译选项(-j),可以显著缩短编译所需的时间。这些命令的成功执行将生成可用于启动和运行的内核映像、模块和设备树文件。

sudo apt install u-boot-tools

在这里插入图片描述
在这里插入图片描述

3. Linux内核源码文件介绍

在这里插入图片描述
在 Linux 内核源代码中,arch 目录包含与特定体系结构(architecture)相关的代码和文件。这是一个非常重要的目录,因为它实现了不同硬件平台的核心支持。

(1) arch 目录的主要内容

子目录

  • arch 目录下通常会有多个子目录,每个子目录对应一个特定的硬件架构。这些架构可能包括:
    • arm:包含 ARM 架构的支持代码。
    • x86:包含 x86 和 x86-64 架构的支持代码。
    • mips:包含 MIPS 架构的支持代码。
    • powerpc(或 ppc):包含 PowerPC 架构的支持代码。
    • riscv:包含 RISC-V 架构的支持代码。
    • s390:包含 IBM Z 系列(S/390)架构的支持代码。
    • shia64 等:可能还有其他架构的支持代码。

主要功能

  • 体系结构特定的代码:每个架构的实现会包含与该架构特有的硬件特性相关的代码,例如上下文切换、处理器启动、系统调用、异常处理等。
  • 内存管理单元(MMU)支持:实现该架构的内存管理机制。
  • 中断和异常处理:处理与硬件中断和异常相关的代码。
  • 汇编代码:一些低级别的汇编语言代码,直接与硬件交互。
  • 架构特定的驱动程序:与特定硬件组件(如CPU、总线等)相关的驱动程序。

在这里插入图片描述

(2) 关键文件和目录
  • CREDITS:包含了对 Linux 内核开发者的致谢和贡献者名单。

  • LICENSES:包含了与 Linux 内核相关的许可证文件,说明了代码的使用和分发条款。

  • Makefile:构建系统的核心文件,定义了如何编译内核以及如何组织源代码。

  • README:提供了关于内核源码树的基本信息和如何编译及使用内核的指导。

  • COPYING:包含了 GNU 通用公共许可证(GPL),这通常是 Linux 内核的许可证。

  • System.map:内核符号的映射文件,包含了内核中的所有符号及其地址,常用于调试。

  • vmlinux:最终生成的可执行内核映像文件,包含了所有内核代码。

  • vmlinux.o:通常是编译过程中生成的中间目标文件,包含内核代码。

(3) 目录
  • block:与块设备的驱动程序和相关代码有关,处理硬盘等设备的输入输出。

  • crypto:包含加密算法和加密相关的功能代码。

  • certs:与内核证书相关的目录,通常用于安全功能。

  • Documentation:包含内核的文档,提供了对于内核各部分的详细说明和使用指南。

  • drivers:包含各种硬件设备驱动程序的代码。

  • fs:文件系统相关的代码,包括不同类型的文件系统实现。

  • include:包含内核头文件,这些头文件定义了数据结构和函数原型,供其他内核代码使用。

  • init:内核初始化代码,负责在引导时设置系统。

  • kernel:核心内核代码,负责调度、进程管理等基本功能。

  • lib:内核的公用库代码,包含一些常用函数和工具。

  • mm:内存管理相关的代码,包括内存分配和管理的实现。

  • net:网络协议栈和网络设备处理代码。

  • security:安全模块和权限管理的相关代码。

  • sound:音频驱动和音频子系统的实现。

  • samples:示例代码,展示如何使用内核提供的功能。

  • scripts:包含用于构建和管理内核的各种脚本。

  • tools:与内核相关的用户空间工具,通常是用于调试或管理内核的工具。

  • virt:虚拟化相关的代码,处理虚拟机和虚拟设备。

(4)模块相关文件
  • modules.builtin:一个列表,展示了内核构建中包含的内置模块。

  • modules.builtin.modinfo:内置模块的元信息。

  • modules.order:记录模块的加载顺序。

  • Module.symvers:包含模块符号的版本信息,用于模块之间的依赖解析。

  • modules-only.symvers:仅包含模块符号的版本信息,通常在模块化内核构建中使用。

(5) Kbuild和Kconfig文件
  • Kbuild:定义了如何构建特定目录下的文件的规则。

  • Kconfig:用于配置内核的选项和模块,提供用户可选的内核配置。

(6)虚拟内存和地址映射
  • vmlinux.symvers:提供了内核符号的版本信息,帮助模块开发者确保符号的一致性。

这些文件和目录共同组成了 Linux 内核的源代码树,提供了开发、编译、调试和使用 Linux 内核所需的所有资源。它们涵盖了内核的各个方面,从驱动程序到文件系统,从文档到构建系统,使得开发者能够高效地进行内核开发和维护。

4.3 复杂相关文件

编译好以后,再把镜像文件和设备树文件复制到工程目录里

在编译完成 Linux 内核及其相关组件后,可以通过以下命令将镜像文件和设备树文件复制到指定的工程目录中(在此示例中为 ~/Desktop/linux-cache/tftpboot)。

1. 复制 zImage 文件

cp arch/arm/boot/zImage ~/Desktop/linux-cache/tftpboot/
  • 功能:将编译好的 zImage 文件复制到 ~/Desktop/linux-cache/tftpboot/ 目录下。
  • zImage:这是一个压缩的内核映像,适用于嵌入式系统。
  • 目标目录~/Desktop/linux-cache/tftpboot 是通常用于 TFTP(Trivial File Transfer Protocol)服务器的目录,方便通过网络启动设备。

2. 复制 uImage 文件

cp arch/arm/boot/uImage ~/Desktop/linux-cache/tftpboot/
  • 功能:将编译好的 uImage 文件复制到 ~/Desktop/linux-cache/tftpboot 目录下。
  • uImage:这是一个为 U-Boot 引导程序准备的内核映像,包含额外的元数据(如加载地址和校验和),用于启动过程。

3. 复制设备树文件

cp arch/arm/boot/dts/vexpress-v2p-ca9.dtb ~/Desktop/linux-cache/tftpboot/
  • 功能:将编译好的设备树二进制文件(DTB)复制到 ~/Desktop/linux-cache/tftpboot/ 目录下。
  • 设备树文件vexpress-v2p-ca9.dtb 描述了硬件的布局,确保 Linux 内核在启动时能够正确识别和配置所有硬件组件。

执行这些命令后,您将会将编译生成的内核映像和设备树文件复制到指定的工程目录中,方便后续通过网络引导或其他方式加载。

4.4 确认生成的内核镜像和设备树文件,并创建启动脚本

1. 确认生成的文件

检查编译后的镜像文件 zImage 和设备树文件 vexpress-v2p-ca9.dtb 是否存在,并记录下它们的路径。

# 确认文件存在
ls ~/Desktop/linux-cache/tftpboot/zImage
ls ~/Desktop/linux-cache/tftpboot/vexpress-v2p-ca9.dtb

(请替换 ~/Desktop/linux-cache/tftpboot 为实际的内核源代码路径)

2. 创建启动脚本

~/Desktop/linux-cache/tftpboot 目录下创建一个脚本 start.sh

# 进入目标目录
cd ~/Desktop/linux-cache/tftpboot

# 创建脚本文件
touch start.sh

# 修改文件权限
chmod 777 start.sh

# 使用文本编辑器编辑脚本内容
gedit start.sh

3. 编辑 start.sh 文件

start.sh 文件中输入以下内容:

qemu-system-arm \
        -M vexpress-a9 \
        -m 512M \
        -kernel zImage \
        -dtb vexpress-v2p-ca9.dtb \
        -nographic \
        -append "console=ttyAMA0"

4. 以 root 用户登录并启动脚本

使用 su 命令切换到 root 用户,然后执行脚本:

# 切换到 root 用户
su root

# 启动脚本
./start.sh

5. 启动结果

如果启动显示正常,说明内核已经成功挂载。但如果出现 “end Kernel panic” 的提示,通常是因为系统没有根文件系统。这意味着内核无法找到可以用作根文件系统的设备。

在这里插入图片描述

6. 解决 Kernel Panic 问题

有以上显示,证明内核挂载成功。最后提示end Kernel panic是因为没有根文件系统,完成下面的部分就可以解决这个问题。

五、制作根文件系统

5.1 什么是BusyBox 根文件系统?

1. 文件系统概述

文件系统是对存储设备上数据进行组织的机制,使数据能够高效地存储、检索和管理。它提供了一种结构化的方法来处理文件和目录,使用户和应用程序能够轻松访问和管理数据。

2. 为什么要使用文件系统

使用文件系统的原因包括:

  • 组织数据:文件系统帮助用户将数据分类存储,使其易于查找和管理。
  • 数据保护:通过权限和访问控制,文件系统可以保护数据不被未授权访问。
  • 持久性:文件系统确保数据在设备重启或断电后仍然可用。
  • 高效存储:文件系统优化了存储空间的使用,提高了读取和写入速度。

3. Linux的哲学:一切皆文件

在Linux操作系统中,"一切皆文件"的哲学意味着几乎所有的系统资源(例如设备、目录和进程)都可以通过文件系统进行访问。这种统一的视图简化了用户和程序与操作系统之间的交互。

4. 用户与操作系统的交互

用户与操作系统之间的主要交互工具是文件系统调用。这些调用允许程序访问和操作文件、目录以及其他存储资源,提供了高层次的接口来与底层存储设备进行沟通。

5. 根文件系统

根文件系统是Linux内核启动后第一个挂载的文件系统。它是整个文件系统结构的基础,包含了系统启动和运行所需的基本文件和目录。

  • 组成:根文件系统主要由基本的shell命令、各种库、字符设备、配置脚本等组成,提供了根目录(/),并在此基础上可以挂载其他文件系统。

6. 存储介质

根文件系统(RFS)可以放置在多种存储介质上,包括:

  • NOR/NAND Flash
  • SD卡
  • 硬盘
  • 网络存储空间

这种灵活性使得Linux能够在各种设备上运行,从嵌入式系统到服务器和个人计算机。

文件系统在Linux中扮演着核心角色,它不仅组织和管理数据,还体现了Linux系统的基本哲学。通过提供一致的接口和可扩展性,文件系统使用户和开发者能够高效地与系统进行交互。

7. BusyBox 概述

BusyBox是一个集成了100多个Linux常用命令和工具的软件,旨在为嵌入式系统提供一个小型而功能强大的环境。它被称为“Linux的瑞士军刀”,因为它将多个命令和实用程序整合到一个单一的可执行文件中,极大地节省了存储空间和资源。

(1) 集成命令和工具

  • BusyBox包含了许多常用的Linux命令,如lscpmvrmcatecho等,同时也包括一些网络工具和系统管理工具。这些命令都共享一个基本的框架,使得BusyBox的体积非常小。

(2)适用于嵌入式系统

  • BusyBox特别适合嵌入式文件系统的构建。由于许多嵌入式设备的存储和资源有限,BusyBox提供的精简和高效的命令集使得它成为嵌入式Linux系统的理想选择。

(3)可配置性

  • 在编译时,BusyBox允许用户根据需要选择启用或禁用某些功能,从而进一步减小最终生成的可执行文件的大小。这种灵活性使其能够满足不同嵌入式项目的需求。

(5)轻量级

  • BusyBox的设计目标是将多种工具合并到一个小型的二进制文件中,通常只有几百KB,因此非常适合存储受限的环境。

应用场景

  • 嵌入式设备:如路由器、智能家居设备、工业控制系统等,BusyBox为这些设备提供了一个基本的命令行接口和实用工具。
  • 恢复环境:在系统故障或恢复时,BusyBox可以提供一个轻量级的操作环境,便于故障排除和系统恢复。
  • Linux发行版:一些轻量级的Linux发行版(例如Alpine Linux)也利用BusyBox来减少系统的总体大小。

BusyBox通过将多个命令和工具整合到一个可执行文件中,提供了一个高效、便捷的解决方案,适合在资源有限的嵌入式环境中使用。它的灵活性和轻量级特性使其成为众多嵌入式Linux应用的理想选择。

5.2 编译和安装 BusyBox 根文件系统

1. 进入工作目录

cd ~/Desktop/linux-cache/tftpboot

2. 创建文件系统目录

mkdir filesys
cd filesys

3. 下载 BusyBox 源代码

wget https://busybox.net/downloads/busybox-1.35.0.tar.bz2

4. 解压下载的文件

tar -xvf busybox-1.35.0.tar.bz2
cd busybox-1.35.0

5. 创建目标根文件系统目录

sudo mkdir -p /home/wangbeiy/Desktop/linux-cache/nfs

6. 更改目录权限

sudo chmod 777 /home/wangbeiy/Desktop/linux-cache/nfs

5.3 编译 BusyBox

1. 配置 BusyBox的Makefile

在编译 BusyBox 或其他类似项目时,配置 Makefile 是确保编译正确的关键步骤。下面是如何配置 Makefile 以支持 ARM 架构的详细说明,包括 ARCHCROSS_COMPILE 变量。

(1) 打开 Makefile

使用文本编辑器(如 gedit 或任何您喜欢的编辑器)打开 Makefile。这里我们使用 gedit 并定位到文件的第191行:

gedit Makefile +191

(2)设置 ARCH 和 CROSS_COMPILE

Makefile 中,找到以下行并进行修改(如果这些行不存在,可以添加):

ARCH ?= arm
CROSS_COMPILE ?= arm-linux-gnueabi-

在这里插入图片描述

解释

  • ARCH:指定目标架构为 ARM。
  • CROSS_COMPILE:指定用于交叉编译的工具链前缀。在此示例中,arm-linux-gnueabi- 是一个常见的 ARM 交叉编译器前缀。

(3) 保存并退出

确保保存对 Makefile 的修改,然后关闭编辑器。

2. 配置 BusyBox

(1)进入配置菜单

在 BusyBox 源代码目录中,使用以下命令进入配置菜单:

make menuconfig

(2)设置编辑器环境

  • 在配置菜单中,选择 Settings 选项。
    在这里插入图片描述

  • 找到 [ ] vi-style line editing commands 选项并勾选(标记为 [*])。这将使您在编辑配置时能够使用 vi 风格的命令,更方便地操作。
    在这里插入图片描述

(3)设置安装路径

  • Settings 下,找到 Destination path for ‘make install’ 选项。
    在这里插入图片描述

  • 输入您的根文件系统路径,例如 ./_install/home/wangbeiy/Desktop/linux-cache/nfs 。确保该路径是您之前创建的用于存放 BusyBox 根文件系统的路径。

在这里插入图片描述

3. 编译与安装

编译和安装

使用以下命令进行安装:

make install -j 6
  • -j 6 表示使用六个并行作业,这样可以加快编译速度。BusyBox 会在安装之前自动进行编译,无需单独运行 make 命令。

在这里插入图片描述

此时安装成功!

在这里插入图片描述
在这里插入图片描述
生成各种命令和软连接,shell命令已经全部生成。

4. 安装 BusyBox 说明

(1)编译与安装

  • 在执行 make install 时,如果未手动编译,系统会自动先编译再进行安装。因此,无需单独输入编译命令。这简化了安装过程,用户只需关注安装目录的设置。

(2) 用户权限注意事项

  • 不要以 root 用户或使用 sudo 进行编译和安装

    • 强烈建议在普通用户下执行 make install,以避免将 BusyBox 安装到系统根目录(/),从而保护您的 Ubuntu 系统不受破坏。

    • 如果以 root 用户身份执行,可能会错误地将文件安装到系统根目录,导致系统功能异常或崩溃。

(3)设置正确的安装路径

  • 确保将安装路径设置为用户可写的目录
    • 通常,可以将安装路径设置为 /home/wangbeiy/Desktop/linux-cache,因为这个目录通常已经设置了最高权限,确保可以顺利安装。
    • 如果安装路径设置错误(例如设置为 /),可能会因为权限不足而导致安装失败,从而避免潜在的系统崩溃。

在这里插入图片描述
(4)安装过程中的权限问题

  • 如果您误将安装目录设置为根目录,系统会因为权限不足而无法完成安装,错误信息将指明安装未成功。这样,您能及时发现错误,从而避免系统受到影响。

5.4 完成完整的根文件系统的构建

在成功建立基本系统功能后,接下来需要进行以下几个步骤,以确保系统能够正常运行并具备所需的功能

1. 安装动态链接库

确保系统中包含必要的动态链接库,以支持应用程序和工具的正常运行。这些库为系统提供了基本的运行时支持。

在使用 APT 安装 ARM 编译器的过程中,动态链接库通常位于 /usr/arm-linux-gnueabi/lib 目录下。为了确保这些库能够在根文件系统中正常使用,您需要将它们复制到相应的目录。

(1)复制动态链接库

创建目标目录

首先,进入您设置的 NFS 文件系统目录并创建 lib 目录:

cd /home/wangbeiy/Desktop/linux-cache/nfs
mkdir lib

复制动态链接库

然后,进入 ARM 编译器的库目录并复制所有共享库文件到 NFS 文件系统的 lib 目录下:

cp bash~/Desktop/linux-cache/filesys/busybox-1.35.0/_install ./
cd /usr/arm-linux-gnueabi/lib
cp *.so* /home/wangbeiy/Desktop/linux-cache/nfs/lib -d

在这里插入图片描述

在这里插入图片描述

(2)解决运行时问题

如果在运行 linuxrc 时遇到失败,可能是由于动态库版本不兼容导致的。为了解决这个问题,可以选择在编译 BusyBox 时配置为静态编译:

配置静态编译

在 BusyBox 的配置菜单中,选择以下选项:

[*] Build static binary (no shared libs)

在这里插入图片描述

这样配置后,BusyBox 将生成一个静态二进制文件,运行时不再依赖于动态库。

通过以上步骤,可以将动态链接库复制到根文件系统中,并通过静态编译 BusyBox 来避免因动态库不兼容而导致的运行问题。这将确保 linuxrc 在启动时能够顺利运行,增强系统的稳定性和兼容性。

2. 创建设备节点

设置必要的设备节点,如 /dev/console/dev/null 等,以便系统能够正确识别和使用硬件设备。

(1)进入目标目录

cd /home/wangbeiy/Desktop/linux-cache/nfs
mkdir dev
cd dev

(2) 创建设备节点

使用 mknod 命令创建所需的设备节点,具体步骤如下:

# 创建虚拟终端设备节点
sudo mknod -m 666 tty1 c 4 1
sudo mknod -m 666 tty2 c 4 2
sudo mknod -m 666 tty3 c 4 3
sudo mknod -m 666 tty4 c 4 4

# 创建控制台设备节点
sudo mknod -m 666 console c 5 1

# 创建空设备节点
sudo mknod -m 666 null c 1 3
(1)设备节点说明
  • tty1, tty2, tty3, tty4:这些是虚拟终端设备节点,分别对应于系统的四个终端。
  • console:控制台设备节点,通常用于系统的输出和输入。
  • null:一个特殊的设备节点,所有写入该节点的数据都会被丢弃,读取时返回 EOF。
(2)权限设置
  • 使用 -m 666 选项设置设备节点的权限,允许所有用户进行读写操作。这在某些情况下可以方便测试和调试,但在生产环境中应根据需要设置更严格的权限。

在这里插入图片描述

3. 配置初始化进程

配置系统的初始化进程,确保在系统启动时能够正确加载和执行 BusyBox,从而管理系统的启动过程。

设置初始化进程 /etc/rcS

进入目标目录

首先,导航到 NFS 根文件系统的路径:

cd ~/Desktop/linux-cache/nfs

创建必要的目录

创建 etc/init.d 目录,如果该目录已经存在,可以跳过这一步:

mkdir -p etc/init.d

创建 rcS 脚本文件

进入 etc/init.d 目录并创建 rcS 文件:

cd etc/init.d
touch rcS

设置文件权限

设置 rcS 文件的权限,以便可以读写和执行:

chmod 777 rcS

编辑 rcS 文件

使用文本编辑器(如 gedit)打开 rcS 文件并添加初始化命令。示例内容如下:

gedit rcS

在编辑器中,可以添加以下内容:

#!/bin/sh
PATH=/bin:/sbin:/usr/bin:/usr/sbin 
export LD_LIBRARY_PATH=/lib:/usr/lib
/bin/mount -n -t ramfs ramfs /var
/bin/mount -n -t ramfs ramfs /tmp
/bin/mount -n -t sysfs none /sys
/bin/mount -n -t ramfs none /dev
/bin/mkdir /var/tmp
/bin/mkdir /var/modules
/bin/mkdir /var/run
/bin/mkdir /var/log
/bin/mkdir -p /dev/pts
/bin/mkdir -p /dev/shm
/sbin/mdev -s
/bin/mount -a
echo "-----------------------------------"
echo "*****welcome to vexpress board*****"
echo "-----------------------------------"

以下是对这段Shell脚本的逐行详细注释:

#!/bin/sh
  • #!/bin/sh:这是一个shebang行,指示系统使用/bin/sh作为脚本的解释器。这是一个标准的Unix shell,通常用于执行脚本。
PATH=/bin:/sbin:/usr/bin:/usr/sbin 
  • PATH=/bin:/sbin:/usr/bin:/usr/sbin:设置环境变量PATH,指定可执行文件的搜索路径。它包含了常见命令的目录,确保在执行命令时能够找到它们。
export LD_LIBRARY_PATH=/lib:/usr/lib
  • export LD_LIBRARY_PATH=/lib:/usr/lib:设置并导出环境变量LD_LIBRARY_PATH,指示动态链接器在/lib/usr/lib目录中查找共享库。这对于程序运行时动态链接到正确的库是必要的。
/bin/mount -n -t ramfs ramfs /var
  • /bin/mount -n -t ramfs ramfs /var:将ramfs类型的内存文件系统挂载到/var目录。-n选项表示不在/etc/mtab中记录此挂载点,ramfs是一种基于内存的文件系统,通常用于临时数据存储。
/bin/mount -n -t ramfs ramfs /tmp
  • /bin/mount -n -t ramfs ramfs /tmp:将另一个ramfs类型的内存文件系统挂载到/tmp目录。/tmp目录通常用于存储临时文件。
/bin/mount -n -t sysfs none /sys
  • /bin/mount -n -t sysfs none /sys:将sysfs文件系统挂载到/sys目录。sysfs提供了对内核对象和设备的访问,通常用于设备管理。
/bin/mount -n -t ramfs none /dev
  • /bin/mount -n -t ramfs none /dev:将ramfs类型的内存文件系统挂载到/dev目录,创建一个临时的设备文件系统,通常用于存放设备节点。
/bin/mkdir /var/tmp
  • /bin/mkdir /var/tmp:在/var目录下创建一个tmp子目录,通常用于存放临时文件。
/bin/mkdir /var/modules
  • /bin/mkdir /var/modules:在/var目录下创建一个modules子目录,用于存放内核模块。
/bin/mkdir /var/run
  • /bin/mkdir /var/run:在/var目录下创建一个run子目录,通常用于存放运行时文件和进程信息。
/bin/mkdir /var/log
  • /bin/mkdir /var/log:在/var目录下创建一个log子目录,用于存放日志文件。
/bin/mkdir -p /dev/pts
  • /bin/mkdir -p /dev/pts:在/dev目录下创建pts子目录,-p选项表示如果上级目录不存在则同时创建。/dev/pts用于支持伪终端(PTY),这是多用户环境下的终端支持。
/bin/mkdir -p /dev/shm
  • /bin/mkdir -p /dev/shm:在/dev目录下创建shm子目录,用于共享内存(shared memory)区域,允许不同进程之间进行高效的内存共享。
/sbin/mdev -s
  • /sbin/mdev -s:运行mdev命令以初始化设备节点。mdev是一个轻量级的设备管理器,用于创建和删除设备文件。
/bin/mount -a
  • /bin/mount -a:挂载在/etc/fstab文件中列出的所有文件系统。这一步骤确保系统启动时所需的所有文件系统都被正确挂载。
echo "-----------------------------------"
  • echo "-----------------------------------":打印一行分隔符,用于在终端上格式化输出。
echo "*****welcome to vexpress board*****"
  • echo "*****welcome to vexpress board*****":打印欢迎信息,提示用户已经成功进入vexpress开发板环境。
echo "-----------------------------------"
  • echo "-----------------------------------":再次打印一行分隔符,结束欢迎信息的输出。

该脚本主要用于在vexpress开发板上初始化系统环境,包括挂载必要的文件系统、创建必要的目录并设置设备管理器。通过这些步骤,脚本为系统的后续操作提供了一个良好的基础环境。

保存并退出编辑器

保存您所做的更改并退出编辑器。

4. 设置文件系统/etc/fstab

确保文件系统的目录结构合理,以便于后续的操作和管理,确保各个组件能够正常访问。

(1) 进入目标目录

首先,导航到 NFS 根文件系统的 etc 目录:

cd ~/Desktop/linux-cache/nfs/etc
(2) 创建 fstab 文件

创建 fstab 文件:

touch fstab
(3) 编辑 fstab 文件

使用文本编辑器(如 gedit)打开 fstab 文件:

gedit fstab
(4) 输入内容

fstab 文件中输入以下内容,这将定义需要挂载的文件系统:

proc    /proc           proc    defaults        0       0
none    /dev/pts        devpts  mode=0622       0       0
mdev    /dev            ramfs   defaults        0       0
sysfs   /sys            sysfs   defaults        0       0
tmpfs   /dev/shm        tmpfs   defaults        0       0
tmpfs   /dev            tmpfs   defaults        0       0
tmpfs   /mnt            tmpfs   defaults        0       0
var     /dev            tmpfs   defaults        0       0
ramfs   /dev            ramfs   defaults        0       0

在这里插入图片描述

(5) 保存并退出编辑器

保存您所做的更改并退出编辑器。

(6) 说明
  • 每一行的格式如下:

    <文件系统> <挂载点> <类型> <选项> <转储> <自检>
    
  • 解释各列

    • proc:挂载点为 /proc,使用 proc 文件系统。
    • none /dev/pts:挂载点为 /dev/pts,使用 devpts 文件系统,设置模式为 0622
    • mdev:挂载点为 /dev,使用 ramfs 文件系统,这是用于临时设备节点的。
    • sysfs:挂载点为 /sys,使用 sysfs 文件系统。
    • tmpfs:挂载点为 /dev/shm/dev/mnt,这些使用 tmpfs 文件系统,以提供临时存储。
    • var /dev:这里的 var 行似乎有点重复,可能需要根据您的具体需求考虑是否需要保留。

设置好 /etc/fstab 文件后,系统在启动时将自动挂载这些文件系统,确保系统的正常运行。

5. 设置初始化脚本/etc/inittab

设置初始化脚本 /etc/inittab 以确保系统在启动时能够正确配置运行级别和初始化进程。

(1)设置初始化脚本 /etc/inittab

进入目标目录

首先,导航到 NFS 根文件系统的 etc 目录:

cd ~/Desktop/linux-cache/nfs/etc

创建 inittab 文件

创建 inittab 文件:

touch inittab

编辑 inittab 文件
使用文本编辑器(如 gedit)打开 inittab 文件:

gedit inittab

输入内容
inittab 文件中输入以下内容:

::sysinit:/etc/init.d/rcS
::askfirst:-/bin/sh
::ctrlaltdel:/bin/umount -a -r

保存并退出编辑器
保存您所做的更改并退出编辑器。

(2)说明
  • 解释各行
    • ::sysinit:/etc/init.d/rcS

      • 这行表示在系统初始化时执行 /etc/init.d/rcS 脚本。这个脚本负责执行系统启动所需的操作,比如挂载文件系统、启动服务等。
    • ::askfirst:-/bin/sh

      • 这行表示在启动后进入一个交互式的 shell。如果用户在启动时按下回车,系统将提供一个 shell 提示符,允许用户进行手动操作。
      • askfirst 选项告诉 init 进程在进入这个 shell 前先询问用户。
    • ::ctrlaltdel:/bin/umount -a -r

      • 这行表示当用户按下 Ctrl+Alt+Del 组合键时,系统将执行 /bin/umount -a -r 命令。这条命令会卸载所有文件系统并重新启动系统。

6. 设置环境变量 /etc/profile

(1)进入目标目录

首先,导航到 NFS 根文件系统的 etc 目录:

cd ~/Desktop/linux-cache/nfs/etc
(2)创建 profile 文件

创建 profile 文件:

touch profile
(3) 编辑 profile 文件

使用文本编辑器(如 gedit)打开 profile 文件:

gedit profile
(4)输入内容

profile 文件中输入以下内容:

USER="root"
LOGNAME=$USER
export HOSTNAME=`cat /etc/sysconfig/HOSTNAME`
export USER=root
export HOME=/root
export PS1="[$USER@$HOSTNAME \W]\# "
PATH=/bin:/sbin:/usr/bin:/usr/sbin
LD_LIBRARY_PATH=/lib:/usr/lib:$LD_LIBRARY_PATH
export PATH LD_LIBRARY_PATH
(5)保存并退出编辑器

保存您所做的更改并退出编辑器。

(6)说明
  • 解释各行
    • USER="root":设置 USER 环境变量为 root,表示当前用户。
    • LOGNAME=$USER:将 LOGNAME 环境变量设置为与 USER 相同的值。
    • export HOSTNAME=\cat /etc/sysconfig/HOSTNAME`:从 /etc/sysconfig/HOSTNAME文件中读取主机名并将其导出为环境变量HOSTNAME`。这要求该文件存在且包含有效的主机名。
    • export USER=root:明确导出 USER 环境变量。
    • export HOME=/root:设置 HOME 环境变量为 /root,表示 root 用户的主目录。
    • export PS1="[$USER@$HOSTNAME \W]\# ":设置命令提示符格式,显示当前用户、主机名和当前工作目录。
    • PATH=/bin:/sbin:/usr/bin:/usr/sbin:设置可执行文件的搜索路径。
    • LD_LIBRARY_PATH=/lib:/usr/lib:$LD_LIBRARY_PATH:设置动态链接库的搜索路径,确保系统能够找到所需的库文件。
    • export PATH LD_LIBRARY_PATH:导出 PATHLD_LIBRARY_PATH 变量,以便子进程也能访问这些环境变量。

以下是在 /etc/sysconfig/HOSTNAME 文件中设置主机名的步骤:

7. 设置主机名 /etc/sysconfig/HOSTNAME

(1) 进入目标目录

首先,导航到 NFS 根文件系统的 etc 目录:

cd ~/Desktop/linux-cache/nfs/etc
(2)创建 sysconfig 目录

创建 sysconfig 目录(如果尚未存在):

mkdir sysconfig
(3) 进入 sysconfig 目录

进入刚创建的 sysconfig 目录:

cd sysconfig
(4)创建 HOSTNAME 文件

创建 HOSTNAME 文件:

touch HOSTNAME
(5) 编辑 HOSTNAME 文件

使用文本编辑器(如 gedit)打开 HOSTNAME 文件:

gedit HOSTNAME
(6)输入主机名

HOSTNAME 文件中输入以下内容:

vexpress
(7) 保存并退出编辑器

保存您所做的更改并退出编辑器。

(8)说明
  • 主机名设置
    • 文件 /etc/sysconfig/HOSTNAME 中的内容是系统主机名,主机名 vexpress 将被用作识别该系统的名称。
    • 该主机名在系统启动时会被读取,并设置为系统的主机名。

以下是创建指定文件夹的步骤,以便在 NFS 根文件系统中构建必要的目录结构。

8. 创建剩下的文件夹

(1)进入目标目录

首先,导航到 NFS 根文件系统的根目录:

cd ~/Desktop/linux-cache/nfs
(2)创建文件夹

使用 mkdir 命令创建所需的文件夹。您可以一次性创建多个文件夹,命令如下:

mkdir mnt proc root sys tmp var
(3)说明
  • 各个目录的用途
    • mnt:用于挂载文件系统的临时挂载点。
    • proc:用于访问内核和进程信息的虚拟文件系统,包含有关系统状态的信息。
    • root:用于指定 root 用户的主目录,通常包含该用户的配置文件和数据。
    • sys:用于访问内核和设备信息的虚拟文件系统,提供有关设备驱动程序和设备的接口。
    • tmp:用于存放临时文件的目录,一般会定期清理。
    • var:用于存放可变数据的目录,如日志文件、邮件和数据库等。

5.5 封装构建好的根文件系统,并挂载

用于封装根文件系统、挂载并创建启动脚本 start.sh

1. 封装根文件系统并挂载

(1)进入 ~/Desktop/linux-cache/nfs/ 目录

cd ~/Desktop/linux-cache/nfs

(2) 创建临时目录

创建一个用于挂载根文件系统的临时目录:

sudo mkdir mnt

(3)制作SD卡文件系统镜像

使用 dd 命令创建一个大小为 32MB 的空文件 rootfs.ext3(可看作SD卡)

sudo dd if=/dev/zero of=rootfs.ext3 bs=1M count=32

(4)格式化磁盘映像为 ext3 文件系统

将文件格式化为 ext3 文件系统:

sudo mkfs.ext3 rootfs.ext3

(5)挂载文件系统到临时目录

将刚创建的文件挂载到临时目录:

sudo mount -t ext3 rootfs.ext3 ~/Desktop/linux-cache/nfs/mnt -o loop

(6)复制 NFS 根文件系统的内容

~/Desktop/linux-cache/nfs 目录下的所有内容复制到挂载的临时目录中:

sudo cp -r nfs/* ~/Desktop/linux-cache/nfs/mnt

(7)卸载临时目录

卸载挂载的文件系统:

sudo umount temp

(8)移动磁盘映像文件

rootfs.ext3 文件移动到 tftpboot 目录:

sudo mv rootfs.ext3 /home/wangbeiy/Desktop/linux-cache/tftpboot

在这里插入图片描述

2. 创建和修改启动脚本 start.sh

(1)进入 tftpboot 目录

cd /home/wangbeiy/Desktop/linux-cache/tftpboot

(2)创建和编辑启动脚本 start.sh

使用文本编辑器创建或编辑启动脚本 start.sh

sudo gedit start.sh

(3) 添加启动命令

start.sh 中输入以下内容,以启动 QEMU 虚拟机:

#!/bin/bash

# 启动 QEMU 虚拟机,要求使用 root 登录
qemu-system-arm \
        -M vexpress-a9 \
        -m 512M \
        -kernel zImage \
        -dtb vexpress-v2p-ca9.dtb \
        -nographic \
        -append "root=/dev/mmcblk0 rw console=ttyAMA0" \
        -sd rootfs.ext3

在这里插入图片描述

qemu-system-arm \
  • qemu-system-arm:这是QEMU虚拟机监控程序的ARM架构仿真器。它允许用户模拟ARM硬件环境并运行ARM架构的操作系统。
-M vexpress-a9 \
  • -M vexpress-a9:指定模拟的机器类型为vexpress-a9,这是一种基于ARM Cortex-A9的开发板,适合用于嵌入式开发和测试。
-m 512M \
  • -m 512M:分配给虚拟机的内存大小为512MB。这决定了运行在虚拟机中的操作系统和应用程序可以使用的内存量。
-kernel zImage \
  • -kernel zImage:指定要使用的内核映像文件,这里使用的是zImagezImage是一种压缩的Linux内核映像格式,适合在内存有限的环境中使用。
-dtb vexpress-v2p-ca9.dtb \
  • -dtb vexpress-v2p-ca9.dtb:指定设备树二进制(Device Tree Blob)文件。设备树描述了硬件的配置和特性,vexpress-v2p-ca9.dtb是与vexpress-a9平台匹配的设备树文件,提供了关于硬件设备的信息。
-nographic \
  • -nographic:禁止使用图形用户界面,所有输入和输出通过控制台(通常是命令行界面)进行。这适用于服务器或嵌入式环境中,不需要图形界面。
-append "root=/dev/mmcblk0 rw console=ttyAMA0" \
  • -append "root=/dev/mmcblk0 rw console=ttyAMA0":向内核传递启动参数。这些参数的意义如下:
    • root=/dev/mmcblk0:指定根文件系统的位置为/dev/mmcblk0,这通常是SD卡或eMMC设备的标识,虚拟机将在此设备上查找根文件系统。
    • rw:表示以读写模式挂载根文件系统。
    • console=ttyAMA0:指定控制台输出设备为ttyAMA0,这是与ARM开发板串行端口相关的设备,允许用户通过串行接口与虚拟机进行交互。
-sd rootfs.ext3
  • -sd rootfs.ext3:指定一个SD卡镜像文件rootfs.ext3,作为虚拟机的存储介质。该文件系统通常包含根文件系统及其内容,QEMU将在此镜像中查找并挂载根文件系统。

这条命令启动了一个基于ARM Cortex-A9的虚拟机,使用了特定的内核映像和设备树文件,配置了内存和存储,并通过命令行接口与虚拟机进行交互。这种设置用于嵌入式开发、测试和调试ARM架构的操作系统和应用程序。

(4)保存并退出编辑器

保存对 start.sh 的更改并退出编辑器。

(5)设置可执行权限

确保脚本具有可执行权限:

sudo chmod +x start.sh

使用 su 命令切换到 root 用户,然后执行脚本:

# 切换到 root 用户
su root

# 启动脚本
./start.sh

在这里插入图片描述

如图,挂载成功,内核版本也是5.10.99版本

在这里插入图片描述
这里就是上面我们制作的根文件系统
在这里插入图片描述

如果您想将 start.sh 脚本修改为支持 LCD 启动,并将控制台输出设置为通过 LCD 显示,而不是串口,需将 console=ttyAMA0 修改为 console=tty0并且删除-nographic

修改后的 start.sh
#!/bin/bash

# 启动 QEMU 虚拟机,使用 LCD 显示
qemu-system-arm \
        -M vexpress-a9 \
        -m 512M \
        -kernel zImage \
        -dtb vexpress-v2p-ca9.dtb \
        -append "root=/dev/mmcblk0 rw console=tty0" \
        -sd rootfs.ext3
更新说明

console=tty0:

  • 这一部分的修改将控制台输出重定向到首个虚拟终端,适用于 LCD 显示。

其他参数:

  • 并且删除-nographic ,保持了其他参数不变,确保虚拟机在启动时能够使用您提供的内核和设备树文件,并正确挂载根文件系统。
保存和设置执行权限

确保您保存了对 start.sh 的更改,并确保脚本具有可执行权限:

sudo chmod +x start.sh

这样,就完成了对 start.sh 的修改,可以通过此脚本启动 QEMU 虚拟机并使用 LCD 显示输出。

在这里插入图片描述

3. 说明

  • 确保在执行这些步骤前,您已经准备好所需的 zImagevexpress-v2p-ca9.dtb 文件,并且它们在正确的位置。
  • 根据需要,您可以在根文件系统内进行额外的配置,以确保系统启动时允许 root 登录。

通过以上可以成功封装根文件系统并创建启动脚本 start.sh,以便使用 QEMU 启动 ARM 虚拟机。

4. 修改网卡信息并设置桥接(Bridge)

确定有以下脚本文件

在这里插入图片描述


(1)查看当前网卡信息
ifconfig
# 或
ip a

找到你要桥接的网卡名称(如 ens33eth0 等)。

在这里插入图片描述


(2)修改 netplan 配置文件

Ubuntu 18.04+ 使用 netplan 管理网络,配置文件通常位于 /etc/netplan/ 目录下,如:

sudo nano /etc/netplan/01-network-manager-all.yaml

(如果文件名不同,请根据实际情况修改)


在这里插入图片描述

修改/etc/netplan/01/01-network-manager-all.yaml的信息配置,输入以下内容:

network:
  version: 2
  renderer: networkd
  ethernets:
      ens33:    #这里设置的是你还需要上网的网卡, ifconfig查看
          dhcp4: no
      ens37:    #这里设置的是br0桥接到的网卡
          dhcp4: yes
  bridges:        
      br0:        #这里设置的是br0网桥
          dhcp4: yes
          interfaces:
              - ens33 #声明br0网桥接入的网卡是ens33

应用配置:

sudo netplan apply
ifconfig  # 检查 br0 是否生效

在这里插入图片描述

当出现以下报错时:
在这里插入图片描述

如果文件存在,检查格式问题:

sudo netplan --debug try

如果提示 Invalid YAML,说明配置文件格式错误,请检查缩进、冒号等。

使用 yaml 在线校验工具(如 YAML Lint)检查语法。

在这里插入图片描述
在这里插入图片描述

(3)修改/etc/qemu-ifdown信息配置

/etc/qemu-ifdown 配置

你可以使用任何文本编辑器(如 nanogedit)来编辑这个文件。

打开 /etc/qemu-ifdown 文件

sudo gedit /etc/qemu-ifdown

复制并粘贴上述内容,保存并关闭文件。

#! /bin/sh
# Script to shut down a network (tap) device for qemu.
# Initially this script is empty, but you can configure,
# for example, accounting info here.
echo sudo brctl delif br0 $1
sudo brctl delif br0 $1
echo sudo tunctl -d $1
sudo tunctl -d $1
echo brctl show
brctl show

在这里插入图片描述


(4)/etc/qemu-ifup 配置
#!/bin/sh
echo sudo tunctl -u $(id -un) -t $1
sudo tunctl -u $(id -un) -t $1
echo sudo ifconfig $1 0.0.0.0 promisc up
sudo ifconfig $1 0.0.0.0 promisc up
echo sudo brctl addif br0 $1
sudo brctl addif br0 $1
echo brctl show
brctl show
sudo ifconfig br0 192.168.214.138 # 这里设置的是网桥br0的地址                                                                                                                                                            

在这里插入图片描述

5. 编写脚本

  • 内核支持:确保虚拟机中的 Linux 内核支持 9p 文件系统。可以通过以下命令检查:

    grep CONFIG_NET_9P /proc/config.gz
    
  • 权限问题:如果在虚拟机中无法访问共享文件夹,可以检查宿主机上的文件权限。

    chmod -R 755 ~/Desktop/linux-cache/tftpboot/shared-dir
    

如果未启用,需要重新编译内核并启用以下选项:

CONFIG_NET_9P
CONFIG_NET_9P_VIRTIO
CONFIG_9P_FS
CONFIG_9P_FS_POSIX_ACL

  • 网络配置:如果虚拟机使用的是用户网络模式(-net user),可能需要调整防火墙设置,以允许 9p 协议的通信。

开启权限

cd ~/linux-kernel-source-code/tftpboot
chmod 777 start.sh
ls -l

在这里插入图片描述

编辑 start.sh

使用 gedit 或任何您喜欢的文本编辑器来编辑 start.sh 文件:

gedit start.sh

整理 start.sh 文件内容

#!/bin/bash
sudo /home/wangbeiy/下载/prefix/bin/qemu-system-aarch64  \
        -M vexpress-a9  \
        -m 1024M \
        -kernel ./zImage  \
        -dtb vexpress-v2p-ca9.dtb \
        -append "root=/dev/mmcblk0 rw console=tty0"  \
        -device virtio-9p-device,fsdev=host_share,mount_tag=host_share \
        -fsdev local,id=host_share,path=/home/wangbeiy/Desktop/linux-cache/tftpboot/shared-dir,security_model=none   \
        -sd rootfs.ext3 

保存并退出

gedit 中,完成编辑后,点击“保存”按钮,然后关闭编辑器。

确认文件权限

确保 start.sh 文件的权限正确:

ls -l start.sh

您应该看到类似于以下内容的输出,表示文件权限为 777:

在这里插入图片描述

在这里插入图片描述


说明

tunctl -u $(id -un) -t $1

  • 创建一个新的 TAP 设备,命名为 $1(通常是 tap0)。
  • $(id -un) 自动获取当前用户的用户名。

ifconfig $1 0.0.0.0 promisc up

  • 将 TAP 设备设置为混杂模式并激活。

brctl addif br0 $1

  • 将创建的 TAP 设备加入到桥接接口 br0,允许它参与网络通信。

brctl show

  • 显示当前网桥的状态,可以查看哪些设备已经加入桥接。

sudo ifconfig br0 192.168.214.138

  • 设置网桥 br0 的 IP 地址为 192.168.214.138

5.6 QEMU 通过网络实现共享文件

1.通过 virtfs 共享文件

在 QEMU 中,virtfs 是一种高效且灵活的文件共享方式,基于 9p 文件系统协议,允许宿主机和虚拟机之间进行高效的文件共享。通过 virtfs,用户可以将宿主机上的目录共享给虚拟机,使得虚拟机能够像访问本地文件一样访问宿主机的文件。

使用 virtfs 的主要步骤包括在宿主机上设置共享目录,将文件放入该目录,然后在启动 QEMU 时使用 -virtfs-fsdev 选项配置共享目录,指定路径、安全模型和挂载标签等参数。

具体而言,-virtfs local 表示使用本地路径作为共享文件夹,path 指定宿主机上的共享目录,mount_tag 用于在虚拟机中识别共享目录,security_model 定义安全模型,常用的有 passthrough,它允许虚拟机直接访问宿主机的文件权限和用户 ID。

可以使用 -fsdev 选项定义共享目录并通过 -device virtio-9p-device virtio-9p-mmio 将其挂载到虚拟机中。在虚拟机中,需要创建挂载点,然后使用 mount 命令将共享目录挂载到指定位置,通常需要指定文件系统类型为 9p,并设置相应的传输协议和版本。

成功挂载后,虚拟机将能够访问宿主机上的共享文件。为了实现自动挂载,可以将挂载命令添加到虚拟机的 /etc/fstab 配置文件中,确保在虚拟机重启后也能自动挂载。此外,需要注意的是,虚拟机的 Linux 内核必须支持 9p 文件系统,并且在宿主机上设置的共享目录的权限需要允许虚拟机访问。

下面是对您提供的关于在 QEMU 中使用 virtfs 进行文件共享及网络配置的详细步骤的整理和补充。


2. 在宿主机上设置共享目录

(1)创建一个共享目录:

  cd ~/Desktop/linux-cache/tftpboot
  mkdir -p shared-dir

(2)将需要共享的文件放入此目录中。

在这里插入图片描述

3 启动 QEMU 配置

使用 -virtfs 选项

-virtfs 选项用于指定共享目录的路径、安全模型以及挂载点等参数。以下是一个完整的命令示例:

sudo /home/wangbeiy/下载/prefix/bin/qemu-system-aarch64  \
        -M vexpress-a9  \
        -m 1024M \
        -kernel ./zImage  \
        -dtb vexpress-v2p-ca9.dtb \
        -nographic \
        -append "root=/dev/mmcblk0 rw console=ttyAMA0"  \
  		-virtfs local,path=/home/wangbeiy/Desktop/linux-cache/tftpboot/shared-dir,id=host_share,security_model=none
  • -virtfs local: 表示使用本地目录作为共享文件夹。
  • /home/wangbeiy/Desktop/linux-cache/tftpboot/shared-dir: 指定宿主机上的共享目录路径。
  • id=host_share: 定义一个挂载标签,用于在虚拟机中识别共享目录。
  • security_model=none: 直接将文件系统的权限和用户 ID 映射到虚拟机中。
使用 -fsdev-device 选项
#!/bin/bash
sudo /home/wangbeiy/下载/prefix/bin/qemu-system-aarch64  \
        -M vexpress-a9  \
        -m 1024M \
        -kernel ./zImage  \
        -dtb vexpress-v2p-ca9.dtb \
        -nographic \
        -append "root=/dev/mmcblk0 rw console=ttyAMA0"  \
        -device virtio-9p-device,fsdev=host_share,mount_tag=host_share \
        -fsdev local,id=host_share,path=/home/wangbeiy/Desktop/linux-cache/tftpboot/shared-dir,security_model=none   \
        -sd rootfs.ext3   

-fsdev local,id=host_share,path=/home/wangbeiy/Desktop/linux-cache/tftpboot/shared-dir,security_model=none

  • -fsdev:这是用于定义文件系统设备的选项。
  • local:这表示使用本地文件系统作为共享目录。
  • id=host_share:为这个文件系统设备指定一个唯一的标识符 host_share,在后续的其他配置中引用。
  • path=/home/wangbeiy/Desktop/linux-cache/tftpboot/shared-dir:指定宿主机上要共享的目录路径。这里是宿主机的一个具体目录 /home/wangbeiy/Desktop/linux-cache/tftpboot/shared-dir
  • security_model=none:表示不施加任何安全限制,虚拟机可以直接以宿主机的权限访问共享目录中的文件。

-device virtio-9p-device,fsdev=host_share,mount_tag=host_share

  • -device:用于添加设备到虚拟机。
  • virtio-9p-device:表示使用 Virtio 9P 设备,这是一种高效的文件系统共享设备,基于 9P 协议。
  • fsdev=host_share:将之前定义的文件系统设备 host_share 连接到这个 Virtio 9P 设备。
  • mount_tag=host_share:为虚拟机中挂载的共享目录指定一个挂载标签 host_share,这样在虚拟机内可以通过这个标签来引用和挂载这个共享目录。

通过这两个选项,可以在虚拟机中设置一个名为 host_share 的共享目录。虚拟机将能够直接访问宿主机

/home/wangbeiy/Desktop/linux-cache/tftpboot/shared-dir 目录中的文件,而不受额外的权限限制。这种配置非常适合开发和测试环境,能够简化文件共享的流程。

注意:如果使用 -device virtio-9p-pci 可能会遇到 “No ‘PCI’ bus found” 错误,此时请使用 -device virtio-9p-mmio 替代。

4 虚拟机中的配置

(1)手动挂载

创建挂载点:

   mkdir -p /mnt/shared

挂载共享文件夹:

mount -t 9p -o trans=virtio,version=9p2000.L host_share /mnt/shared

验证挂载:

ls /mnt/shared

在这里插入图片描述

(2)自动挂载(可选)

为了在虚拟机重启后自动挂载共享文件夹,可以将挂载命令添加到 /etc/fstab 文件中。例如:

echo "host_share /mnt/shared 9p trans=virtio,version=9p2000.L,rw,share,nobootwait,posixacl,msize=104857600 0 0" >> /etc/fstab

然后运行以下命令使配置生效:

mount -a

5.7 网络配置

1. NAT 模式

步骤 1:启动 QEMU 并配置 NAT 网络

启动 QEMU 时,使用 -netdev user-device virtio-net 参数来配置 NAT 网络。以下是一个示例命令:

#!/bin/bash
sudo /home/wangbeiy/下载/prefix/bin/qemu-system-aarch64  \
        -M vexpress-a9 \#!/bin/bash
sudo /home/wangbeiy/下载/prefix/bin/qemu-system-aarch64  \
        -M vexpress-a9  \
        -m 1024M \
        -kernel ./zImage  \
        -dtb vexpress-v2p-ca9.dtb \
        -nographic \
        -netdev user,id=net0,ipv6=off,hostfwd=tcp::8022-:22 \
        -append "root=/dev/mmcblk0 rw console=ttyAMA0"  \
        -device virtio-net-device,netdev=net0   \
        -device virtio-9p-device,fsdev=host_share,mount_tag=host_share \
        -fsdev local,id=host_share,path=/home/wangbeiy/Desktop/linux-cache/tftpboot/shared-dir,security_model=none   \
        -sd rootfs.ext3  
  • -netdev user,id=net0,ipv6=off,hostfwd=tcp::8022-:22:配置 NAT 网络,hostfwd 参数将虚拟机的 22 端口(SSH)映射到宿主机的 8022 端口。
  • -device virtio-net-device,netdev=net0:将虚拟网卡连接到 NAT 网络。
步骤 2:在虚拟机中配置网络

虚拟机启动后,可以使用以下命令检查网络配置:

ip addr show

如果未分配 IP 地址,可以尝试使用 DHCP 获取 IP 地址:

udhcpc

如果 DHCP 无法获取 IP 地址,可以手动配置静态 IP 地址:

# 启动网络接口
ifconfig eth0 up
# 配置 IP 地址
busybox ifconfig eth0 10.0.2.15 netmask 255.255.255.0
# 添加默认路由
busybox route add default gw 10.0.2.2
步骤 3:验证网络连接

在虚拟机中,使用以下命令测试网络连接:

ping 8.8.8.8

在这里插入图片描述

步骤 4:配置 DNS

如果虚拟机可以 ping 通外网,但无法解析域名,可以编辑 /etc/resolv.conf 文件,添加 DNS 服务器地址:

echo "nameserver 8.8.8.8" >> /etc/resolv.conf
echo "nameserver 8.8.4.4" >> /etc/resolv.conf

在这里插入图片描述

2. Tap 模式(网桥模式)

步骤 1:创建 TAP 接口

创建 TAP 接口:

sudo ip tuntap add dev tap0 mode tap
sudo ip link set tap0 up
步骤 2:创建桥接接口

创建桥接接口:

sudo ip link add name br0 type bridge
sudo ip link set br0 up

将物理网络接口添加到桥接接口:

sudo ip link set eth0 master br0

将 TAP 接口添加到桥接接口:

sudo ip link set tap0 master br0
步骤 3:配置 QEMU 启动命令

启动 QEMU 并配置 TAP 接口:

#!/bin/bash
sudo /home/wangbeiy/下载/prefix/bin/qemu-system-aarch64  \
        -M vexpress-a9 \#!/bin/bash
sudo /home/wangbeiy/下载/prefix/bin/qemu-system-aarch64  \
        -M vexpress-a9  \
        -m 1024M \
        -kernel ./zImage  \
        -dtb vexpress-v2p-ca9.dtb \
        -nographic \
        -netdev user,id=net0,ipv6=off,hostfwd=tcp::8022-:22 \
        -append "root=/dev/mmcblk0 rw console=ttyAMA0"  \
  		-netdev tap,id=net0,ifname=tap0,script=no,downscript=no \
  		-device virtio-net-device,netdev=net0  \
        -device virtio-9p-device,fsdev=host_share,mount_tag=host_share \
        -fsdev local,id=host_share,path=/home/wangbeiy/Desktop/linux-cache/tftpboot/shared-dir,security_model=none   \
        -sd rootfs.ext3  

3. 注意事项

  • 权限问题:创建 TAP 接口和配置桥接接口需要管理员权限。
  • 网络配置:确保宿主机的网络配置支持桥接模式,特别是防火墙和网络策略。

3. 命令示例

以下是一些 QEMU 启动命令的示例:

bzImagePath=/home/liuqz/work/linux/linux-6.12.5/arch/x86/boot

image:
        cp ${bzImagePath}/bzImage ./

ramfs:
        cd ./rootfs && find . -print0 | cpio -ov --null --format=newc | gzip -9 > ../initramfs.img

run:
        qemu-system-x86_64 \
                -kernel ${bzImagePath}/bzImage \
                -initrd initramfs.img \
                -m 1G -nographic \
                -virtfs local,path=/mnt/shared,mount_tag=host_share,security_model=none \
                -net user,id=net0,ipv6=off,hostfwd=tcp::8022-:22 \
                -net nic,model=virtio \
                -append "earlyprintk=serial,ttyS0 console=ttyS0 nokaslr"

debug:
        qemu-system-x86_64 \
                -kernel ${bzImagePath}/bzImage \
                -initrd initramfs.img \
                -m 1G -nographic \
                -S -s \
                -append "earlyprintk=serial,ttyS0 console=ttyS0 nokaslr"

run2:
        qemu-system-x86_64 \
                -kernel ${bzImagePath}/bzImage \
                -m 1G -nographic \
                -device qemu-xhci \
                -virtfs local,path=/mnt/shared,mount_tag=host_share,security_model=none \
                -net user,id=net0,ipv6=off,hostfwd=tcp::8022-:22 \
                -net nic,model=virtio \
                -drive file=root0.img,format=raw \
                -append "earlyprintk=serial,ttyS0 console=ttyS0 root=/dev/sda rw"

run3:
        qemu-system-x86_64 \
                -kernel ${bzImagePath}/bzImage \
                -m 1G -nographic \
                -device qemu-xhci \
                -virtfs local,path=/mnt/shared,mount_tag=host_share,security_model=none \
                -net user,id=net0,ipv6=off,hostfwd=tcp::8022-:22 \
                -net nic,model=virtio \
                -drive file=root1.img,format=raw \
                -append "earlyprintk=serial,ttyS0 console=ttyS0 root=/dev/sda rw nokaslr"

以上是通过 QEMU 使用 virtfs 进行文件共享及网络配置的详细整理,涵盖了共享目录的设置、网络配置与示例命令等内容。

六、在开发板上运行应用和内核驱动程序

6.1 编写测试应用程序

在~/Desktop/linux-cache/tftpboot/shared-dir下 gedit 得到text.c

#include <stdio.h>

int main()
{
	printf("hello world!!!\n");
	
	return 0;
}

使用交叉编译工具进行编译代码

在这里插入图片描述

在qemu中则成功运行

在这里插入图片描述

6.2 编写测试内核驱动程序

hello.c测试程序

#include <linux/init.h>
#include <linux/module.h>

MODULE_LICENSE("GPL");

static int hello_init(void) {
    printk(KERN_ALERT "---1\n");
    printk(KERN_ALERT "Hello World!\n");
    printk(KERN_ALERT "Hello vexpress!\n");
    printk(KERN_ALERT "---2\n");
    return 0;
}

static void hello_exit(void) {
    printk(KERN_ALERT "Goodbye, crazy world!\n");
}

module_init(hello_init);
module_exit(hello_exit);

在这里插入图片描述

Makefile 代码:

.PHONY: all clean

ifneq ($(KERNELRELEASE),)
obj-m := hello.o
else
EXTRA_CFLAGS += -DDEBUG
KDIR := ~/Desktop/linux-cache/linux-5.10.99
all:
	make CROSS_COMPILE=arm-linux-gnueabi- ARCH=arm -C $(KDIR) M=$(PWD) modules
clean:
	rm -fr *.ko *.o *.mod.o *.mod.c *.symvers *.order .*.ko .tmp_versions
endif

代码说明

.PHONY 声明

  • PHONY: all clean 表示 allclean 是伪目标。

条件判断

  • ifneq ($(KERNELRELEASE),) 用于判断当前是否在内核构建过程中。
  • 如果在内核构建过程中,设置 obj-m 为目标模块 hello.o

构建设置

  • EXTRA_CFLAGS += -DDEBUG:如果不在内核构建过程中,增加调试选项。
  • KDIR := ~/Desktop/linux-cache/linux-5.10.99:指定内核源代码的路径。

目标 all

  • 使用 make 命令编译模块,指定交叉编译工具链 CROSS_COMPILE 和目标架构 ARCH,使用 -C 选项指定内核源代码目录 $(KDIR)M=$(PWD) 表示当前目录。

目标 clean

  • 删除生成的文件,包括模块文件、对象文件、临时文件等。

在这里插入图片描述
开发板进行测试

#安装驱动
insmod hello.ko
#卸载驱动
rmmod hello.ko
#查看驱动
lsmod

在这里插入图片描述

到此,我们的环境都已搭建完成,诸君!这不仅是一个全新的开始,更是我们追求技术卓越与创新的旅程。每一步的努力和坚持,都将为我们的未来铺就更加广阔的道路。

无论是在编写代码、调试程序,还是在解决问题的过程中,大家都将面临挑战,但请相信,通过我们的合作与坚持,必能克服困难,迎接成功的曙光。

让我们携手并进,共同探索未知的领域,创造出更加美好的明天。未来属于勇敢者,属于不断学习、追求进步的人。无论何时,请牢记我们的初心,保持对技术的热爱与激情!

让我们一起奋勇向前,成就更精彩的明天!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嵌入式设计-妄北y

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值