使用Buildroot + QEMU构建和运行Linux

2023-05-16

使用Buildroot + QEMU构建和运行Linux

xunknown@2022.04.06

  1. 概述

Buildroot是一个用于为嵌入式系统构建完整的Linux系统(包括Bootloader,Linux kernel以及shell和各种应用软件)的交叉编译工具。

QEMU是一个通用的开源机器模拟器和虚拟器。QEMU可以以多种不同的方式使用。最常见的是“系统仿真”,它提供整个机器(CPU、内存和仿真设备)的虚拟模型来运行客户操作系统(guest OS)。

本文介绍如何使用Buildroot工具构建不同体系架构的嵌入式系统的完整Linux系统,并使用QEMU运行该系统,并且可以通过ssh登录。

  1. 使用Buildroot构建riscv64 Linux系统
    1. 下载Buildroot工具包并解压

wget https://buildroot.org/downloads/buildroot-2022.02.tar.xz

tar Jxf buildroot-2022.02.tar.xz

后续构建过程中,如果有报软件包找不到的错误,可先参考Buildroot文件检查一下依赖的软件包是否已经安装,把缺少的软件包装上。

    1. 创建并进入构建输出目录

这里使用out-of-tree的方式构建,使用这种方式可以同时构建多个系统。

mkdir buildroot-riscv64

cd buildroot-riscv64

    1. 构建选项概述

提示:

Buildroot工具源码目录下的configs目录有预定义的配置,可以使用这些配置。如果自定义配置导致编译失败或者QEMU启动失败,可能是由于架构,编译选项,交叉工具链,内核配置等错误导致,可以使用Buildroot自带配置先编译一个版本(有些架构下还会自动生成一个qemu启动脚本),再增加自己需要的软件包。

make O=$PWD -C ../buildroot-2022.02/ menuconfig

第一次执行make命令需要使用O选项指定输出目录,使用-C选项指定Buildroot工具路径,后续在输出目录下执行make命令可以不需要这两个选项。

将menuconfig改为configs目录下的文件名,即可使用Buildroot自带的配置生成.config文件,例如:

make O=$PWD -C ../buildroot-2022.02/ qemu_riscv64_virt_defconfig

注:使用make menuconfig配置选项时,如果退格键无法删除内容,可以加按Ctrl键,即使用Ctrl+backspace组合键。

主要有以下选项需要配置:

  1. Target options:目标体系架构,例如riscv,arm,x86等。
  2. Build options:构建选项,例如make过程中使用的命令,源码下载目录,并行构建选项等。
  3. Toolchain:交叉编译工具链选项,例如使用的C库类型。跟体系架构相关。
  4. System configuration:系统配置,例如根文件系统框架,目标系统hostname,bash,root密码等。
  5. Kernel:(可选的)Linux kernel编译选项。
  6. Target packages:安装到目标系统的软件包,例如dhcp,ssh等。
  7. Filesystem images:根文件系统镜像格式,例如ext4镜像根文件系统。根文件系统镜像是Buildroot最主要的输出件。
  8. Bootloaders:(可选的)系统启动引导程序/Bootloader,例如u-boot,grub等。跟体系架构相关。

编译不同架构的Linux系统通常只需要修改目标架构和交叉编译工具相关的选项,其他的可以保持一致。

      1. Target options

配置目标架构,选择RISCV,64位,并配置扩展指令集。

这部分与体系架构强相关,切换体系架构后,这部分需要重新配置。

修改体系架构也会影响到后面的交叉编译工具选项。

      1. Build options

配置构建选项,一般可以使用默认配置。

这部分与体系架构不强相关的,切换体系架构不影响这些配置(保持默认值就好)。

如果需要修改构建过程中执行的命令,例如给wget加上--no-check-certificate选项,可以通过→ Build options → Commands选项配置:

在使用代理服务器的情况下,可能需要修改这些配置,避免各种下载错误。

如果使用Buildroot提供的默认配置进行配置的话,为了保存默认配置时(make savedefconfig)不修改Buildroot提供的配置,需要修改($(CONFIG_DIR)/defconfig) Location to save buildroot config选项,通常可修改为$(CONFIG_DIR)/defconfig。

下载目录(Download dir)保持默认值$(TOPDIR)/dl(Buildroot工具目录下的dl目录),这样编译其他体系架构的Linux系统时,可以重用已下载的代码。

在→ Build options → Advanced选项下面,选择Use per-package directories (experimental),可以使用make -j<N>指定并行构建的线程,加快构建过程。

可以通过libraries选项配置使用动态链接(默认)还是静态链接方式编译目标程序,例如busybox(还需要通过make busybox-menuconfig,修改为静态链接方式)。

需要注意的是,修改libraries选项,可能会导致使用个C库变化。

      1. Toolchain

配置交叉编译工具,大部分选择可以保持默认值。如果没有特别要求,建议使用Buildroot默认的工具链配置。

不同体系架构,Buildroot能够提供交叉编译工具也不相同,切换体系架构后,这部分需要重新配置(主要是工具来源和版本)。

交叉编译工具链的配置会影响到一些软件包的编译(例如openssh),如果编译失败,可以考虑修改交叉编译工具配置,或者使用Buildroot默认选项先编译。

关键选项:

Toolchain type (Buildroot toolchain):交叉编译工具类型(使用Buildroot自带的还是外部工具链)。

C library (glibc):使用哪个C库。

Kernel Header Options:编译出来的C库使用的Linux头文件版本(影响使用C库编译的APP,并且跟运行App的目标系统的Linux内核版本有关)。

GCC Options:配置gcc版本。

交叉编译工具选择外部工具链Toolchain type (External toolchain) ,来源选择预安装类型Toolchain origin (Pre-installed toolchain),可以节省交叉编译工具链的编译时间,但需要给出预编译好的交叉工具下载地址。

      1. System configuration

系统配置,大部分也是使用默认配置。

这部分与体系架构不强相关,切换体系架构后,这部分配置可以保持不变。

重点选项:

(mascot.zone) System hostname:配置目标系统的hostname,可以改为自己喜欢的名字。

(Welcome to mascot.zone) System banner:在登录界面显示的欢迎信息,可以改为自己喜欢的字符串。

Init system (BusyBox) :目标系统的init进程,没有特别需求则保留默认,否则可能需要根据这个配置增加其他的定制操作(脚本等)。

Enable root login with password:默认选择,允许root用户登录。

Root password:root用户密码,默认为空,构建用于本地测试的Linux建议留空,省事。这个配置很关键,影响到后续ssh登录。

/bin/sh (bash):默认shell,可以保留默认,可修改为bash等。这个主要是根据不同shell的特点选择。选择bash支持的功能更全面些。默认bash不可选,需要在Target packages选择Show packages that are also provided by busybox之后才能回到这里选择bash。

Run a getty (login prompt) after boot:系统启动后给出登录提示,要求输入用户名和密码(登录后进入 /root目录)。这里默认选择,后续可以通过/etc/inittab脚本关闭登录提示,直接进入系统(这种情况进入系统后当前目录是根目录/)。

需要注意,Run a getty (login prompt) after boot的TTY port配置跟kernel启动参数console有关,console参数不同架构不一样,要与TTY port保持一致。(qemu启动时console参数通过-append参数配置,例如-append "console=ttyS0")。---实际上,console参数取决于内核,例如arm使用ttyAMA0,ppc和mips使用hvc0,RISC-V和x86_64使用ttyS0等。

(eth0) Network interface to configure through DHCP:配置通过DHCP自动配置IP的网口,这里可以填eth0。这个配置很关键,影响到后续ssh登录。在这里配置DHCP自动配置网口IP,可以让后续ssh登录省事很多。

Install timezone info,(Asia/Shanghai) default local time:配置时区,主机的时区名称可以通过timedatectl命令查询。如果不配置时区,默认是UTC。

($(BASE_DIR)/rootfs_overlay) Root filesystem overlay directories:在生成目标文件系统时,该目录下的文件会覆盖目标文件系统下对应的文件,可以用于简单的定制。这里配置为$(BASE_DIR)/rootfs_overlay,其中$(BASE_DIR)表示构建输出目录(即make的O选项指定的目录),rootfs_overlay是目标文件系统根目录对应的目录。配置了这个选项,需要在输出目录下先创建一个对应的目录,目录可以为空(相当于不覆盖任何目标文件系统的文件)。为了简化ssh登录,后续会在该目录下增加文件,这一点后面再补充说明。

如果需要其他复杂的定制,还可以通过执行脚本的方式来实现。

      1. Kernel

配置内核源码和内核镜像编译选项。这个是可选的。如果不在这里编译内核镜像,则需要在其他地方单独编译内核镜像,或者使用已经编译好的内核镜像来启动Linux系统。为了方便第一次测试,这里选择编译内核镜像。

这部分跟体系架构不强相关,切换体系架构不影响这些配置。

 主要选项:

Kernel version (Custom tarball):指定内核源码版本,可以使用默认选项。这里选择使用内核源码tar包并给出下载路径。

Kernel configuration (Use the architecture default configuration):内核编译的配置选项,这里选择体系架构默认配置。

Kernel binary format (Image):内核镜像,使用默认的就好,会根据体系架构自动调整。

Kernel compression format (xz compression):内核镜像压缩方式,默认是gzip,这里改成了xz。

另外,还可以在→ Kernel → Linux Kernel Tools选择编译一些内核工具,例如perf。

内核镜像的编译配置,会影响QEMU启动linux内核。如果QEMU启动失败,可以检查一下kernel的配置。

有些架构,如果要通过QEMU启动kernel,需要选择合适的内核配置选项,具体可以参考QMEU文档。

可以使用make linux-menuconfig命令单独配置内核选项。

      1. Target packages

配置安装到目标文件系统的软件包。

这部分跟体系架构不强相关,切换体系架构后,可以保持原来的配置,这样各个体系架构下都是使用相同的软件包。

关键选项和软件包:

Show packages that are also provided by busybox:选中这个选项,显示Busybox以及支持的软件包,这样可以选择专用的软件包替换busybox提供的软件包,功能比busybox提供的更完整一些。如果默认shell选择bash,要选择这个选项才能看到bash软件包选项。如果没有特殊要求,则可以取消这个选项,这样相同的工具,可以使用busybox提供的工具即可。

Individual binaries:对于Busybox提供的软件,如果不选这个选项,则每个命令都是指向busybox的软连接,如果选择这个选项,则每个命令都是busybox的一个副本重命名。coreutils提供的命令也类似。通常没有必要选择这个选项。

软件包选择建议:

可以先最小选择需要的软件包,后续需要时,再新增选择需要的软件包,重新编译根文件系统。只要没有修改体系架构配置和工具链配置,没有clean编译输出,重新编译只编译新增的软件包,重新生成根文件系统镜像,这个过程比较快。Buildroot编译特点是加法容易减法难,因为可能减不掉,或者减不干净。

为了支持ssh登录,需要选择安装dhcpcd(DHCP自动获取IP地址),以及openssh(或者dropbear)(开启sshd服务)。可以从Networking applications选择这些软件包。

如果需要更丰富的功能,可以选择加入对应的软件包,例如,选择coreutils,iproute2等。

参考软件包:

Audio and video applications  ---> 保持Buildroot默认

Compressors and decompressors  ---> [*] bzip2,[*] gzip,[*] xz-utils

Debugging, profiling and benchmark  ---> [*] lsof,[*] strace

Development tools  ---> [*] diffutils,[*] findutils,[*] gawk,[*] grep,[*] sed,[*] tree

Filesystem and flash utilities  ---> 保持默认或者根据需要选择,如[*] btrfs-progs,[*] cpio

Fonts, cursors, icons, sounds and themes  ---> 保持Buildroot默认

Games  ---> 保持Buildroot默认

Graphic libraries and applications (graphic/text)  ---> 保持Buildroot默认

Hardware handling  ---> 保持Buildroot默认,或者根据需要选择,例如[*] sysstat

Interpreter languages and scripting  ---> [*] python3(其他扩展选项保持默认)

Libraries  ---> 保持Buildroot默认

Mail  ---> 保持Buildroot默认

Miscellaneous  ---> 保持Buildroot默认

Networking applications  ---> [*] dhcpcd(dhcp客户端,动态分配IP地址),[*] ifupdown scripts(默认选择),[*] iproute2(用于网络配置和监控),[*] openssh(及其扩展)(或者用dropbear替代openssh。用于ssh连接guest。openssh支持root用户使用空密码登录,dropbear不支持用户使用空密码登录),[*] tcpdump(及其扩展)

Package managers  ---> 保持Buildroot默认

Real-Time  ---> 保持Buildroot默认

Security  ---> 保持Buildroot默认(默认选择[*] urandom-initscripts)

Shell and utilities  ---> -*- bash (根据系统配置默认shell自动选择),[*] bash completion,[*] file,[*] time(可选),[*] which(可选),(慎选tmux,可能因编码的原因无法运行)

System tools  ---> [*] coreutils(扩展选项保持默认,不选择Individual binaries),[*] procps-ng(top,ps等功能更丰富,top默认界面可能跟ubuntu不同,可通过t,m等命令切换),[*] tar,可以在Target packages → System tools → util-linux进一步选择更多工具,例如[*]scheduling utilities(包含chrt,taskset等)

Text editors and viewers  ---> 保持Buildroot默认(慎选vim,可能不好用,例如可能只能半屏显示)

注:

  1. 选择openssh时,有些架构可能编译失败,例如armeb,或者sshd无法正常启动,例如aarch64,具体原因未明,此时切换交叉编译版本可以解决(可以使用Buildroot提供的config先配置一次再修改配置选项),或者可选择dropbear替代(ssh不支持空密码登录)。
  2. 遇到过单独的vim包没有busybox自带的vi好用的问题,可能是没有配置好的原因。选择vim包时需谨慎。
  3. 运行tmux报错:tmux: need UTF-8 locale (LC_CTYPE) but have ANSI_X3.4-1968

      1. Filesystem images

配置根文件系统的镜像格式。根文件系统镜像是Buildroot最主要的输出。

这部分配置跟体系架构无关,切换体系架构后保持原来的配置即可。

 这里选择输出cpio,ext2/3/4,tar这4个类型的镜像,同时输出对应的压缩镜像(默认都是gzip,可选择xz压缩效果更好)。实际只需要输出ext2/3/4(用于块设备/磁盘文件系统)或者cpio格式(用于RAM文件系统)的镜像即可(不需要压缩镜像)。

ext文件系统镜像大小可以设为256m或者1024m,使用Buildroot提供的默认值可能空间不够大。也可以使用默认配置先编译,等报错时再根据实际大小修改。

以上是RISC-V系统主要的构建配置,其他选项的可以使用默认配置(或者不配置),例如这里不需要编译Bootloaders。

需要注意的是,如果使用Buildroot提供的配置(特别是qemu开头的默认配置),Host utilities会自动选择[ ] host qemu编译qemu(用于在主机上运行),如果本地已经安装了对应版本的qemu,可以取消这个选项,减少编译时间。注意,取消该选项可能不会自动生成start-qemu.sh脚本(使用board/qemu/post-image.sh生成的),这时可以从Buildroot源码目录下board/qemu/<board>/readme.txt文件找到对应的qemu启动命令。

    1. 构建Linux系统

完成配置后,执行make命令开始编译构建:

make -j3 2>&1 | tee log

第一次编译时,Buildroot会下载交叉编译工具的源码或者软件包,下载安装到目标文件系统的软件包,随后执行编译,最后输出根文件系统镜像,保存在images目录下。如果选择编译kernel和bootloader,最后生成的kernel和bootloader的镜像也输出到images目录。

需要注意的是,如果选择了(→ Build options → Advanced)Use per-package directories (experimental),make -j指定的并行任务数量太多,可能会导致系统挂死(可能跟系统配置有关,低配的系统可以指定比cpu数量少的任务数)。当然,如果没有选择该选项,make总是单个任务串行执行,这个构建时间会长很多。

第一次编译是全量构建,用时可能比较长,这取决于系统配置。

编译成功后,就可以使用image目录中的镜像来启动Linux系统了。

需要注意一点,构建完成后,如果输出目录改名,可能导致后面再执行make会失败,最后不得不重新全量编译。

常见编译失败问题:

  1. openssh编译失败:常见的错误是通常原因是构建选项配置错误,可以尝试使用Buildroot预定义的配置先配置一次,再按需增加openssh等自己需要的软件包。
  2. 生成根文件系统失败:从错误日志一般能找到原因,例如镜像大小不够,缺少rootfs_overlay目录等。

    1. 定制根文件系统

Buildroot提供了多种方式定制根文件系统,这里以使用overlay方式为例介绍如何修改根文件系统。

      1. 修改根文件系统文件

例1:简化openssh的ssh登录

openssh默认不允许root用户登录,也不允许使用空密码登录。这个约束可以通过修改openssh的配置文件sshd_config取消。

首先从target目录复制该文件到rootfs_overlay目录:

cp --parents etc/ssh/sshd_config ../rootfs_overlay/

cp命令使用--parents选项保持文件路径一致,需要注意的是要进入target目录执行cp命令,否则复制之后路径名称不对。

随后修改rootfs_overlay目录中的文件:

cd ..

vi rootfs_overlay/etc/ssh/sshd_config

1)将PermitRootLogin选项取消注释并改为yes,以允许root用户ssh登录。

2)将PermitEmptyPasswords选项取消注释并改为yes,以允许使用空密码登录。

保存修改之后重新执行make生成新的根文件系统,可以看到target/etc/ssh/sshd_config文件会被替换为rootfs_overlay/etc/ssh/sshd_config文件,image下的根文件系统镜像也更新了(可以根据修改时间简单判断)。

例2:系统启动后直接进入shell,不需要输入用户名

cd target/

cp --parents etc/inittab ../rootfs_overlay/

cd ..

vi rootfs_overlay/etc/inittab

修改rootfs_overlay/etc/inittab文件:

将console::respawn:/sbin/getty -L  console 0 vt100 # GENERIC_SERIAL             

修改为console::respawn:-/bin/sh

保存之后执行make重新生成根文件系统镜像。需要注意的是,这种方式进入shell后,当前目录为根目录/,而不是root用户的home目录/root。

      1. 增删目标软件包

编译完成后,如果后续需要增加其他组件,可以使用make menuconfig配置选择新增的组件,执行make就可以了(如果是某个软件包新增部分组件,则可能要先make <pkg>-dirclean先删除对应软件包的输出),这种情况只需要增量编译。

如果要删除已有的组件,则稍微有点麻烦。尝试过可行的方法:

  1. 使用make menuconfig取消对应的软件包。
  2. 使用make <pkg>-dirclean删除对应软件包的构建输出,其他<pkg>是软件包的名称。
  3. 删除整个target目录。
  4. 重新执行make命令,这里不会触发全量构建,只会重新生成target目录,重新生成根文件系统镜像。

需要注意的是,如果其他被删除的软件包跟其他软件包有依赖关系,可能会有问题,这种情况就要make clean之后再make,全量编译了。

make menuconfig修改配置后,可以使用compare-config工具(https://gitee.com/xunknown/compare-config)检查一下修改了哪些配置选项,确保无误。

./compare-config -p "BR2_" -C

  1. 使用QEMU启动riscv64 Linux系统
    1. qemu启动guest

首先要安装qemu,可以选择apt install安装也可以下载qemu源码编译安装,具体方法可参考qemu文档(也可以通过Buildroot编译qemu,从Host utilities选择[ ] host qemu)。

通常在Buildroot源码目录下board/qemu/<board>/readme.txt文件可以找到对应的qemu启动命令,结合board/qemu/post-image.sh脚本基本可以写出qemu启动命令,在此基础上再增加其他选项。

这里重点介绍(记录)qemu启动命令。

使用RAM文件系统:

qemu-system-riscv64 -M virt -m 256M -nographic \

-kernel images/Image \

-device virtio-rng-pci \

-initrd images/rootfs.cpio \

-device virtio-blk-device,drive=hd0 \

-drive file=images/rootfs.ext4,format=raw,id=hd0 \

-append "root=/dev/ram rw console=ttyS0" \

-device virtio-net-device,netdev=net0 \

-netdev user,id=net0,host=10.0.2.1,hostfwd=tcp::5555-:22

或者使用块设备文件系统:

qemu-system-riscv64 -M virt -m 256M -nographic \

-kernel images/Image \

-device virtio-rng-pci \

-initrd images/rootfs.cpio \

-device virtio-blk-device,drive=hd0 \

-drive file=images/rootfs.ext4,format=raw,id=hd0 \

-append "root=/dev/vda rw console=ttyS0" \

-device virtio-net-device,netdev=net0 \

-netdev user,id=net0,host=10.0.2.1,hostfwd=tcp::5555-:22

以上两个命令只有-append选项中的root参数不同。

riscv64默认打开了9P文件系统(CONFIG_NET_9P等选项默认打开),可以通过9P文件系统实现host和guest共享文件夹。增加以下qemu启动选项:

-fsdev local,id=test_dev,path=./images,security_model=none -device virtio-9p-pci,fsdev=test_dev,mount_tag=dev9p

如果是自己编译的qemu,如果不支持9P文件系统,需要打开--enable-virtfs选项重新编译qemu。

进入guest系统后,通过mount加载9p文件系统,即可直接访问host的文件夹:

mount -t 9p dev9p /mnt

其中:

-kernel:指定Linux内核镜像。

-initrd images/rootfs.cpio:指定根文件系统镜像(无压缩的.cpio或者压缩后.cpio.xz),用于通过RAM文件系统系统启动。这个是可选的,跟-append选项指定的命令行参数root有关,如果root参数为root=/dev/ram,表示使用RAM文件系统,此时要给出-initrd选项。使用RAM文件系统启动,可以确保每次系统启动都使用同样的镜像,因为在系统中做的任何修改在系统退出时都不会被保存。如果要保存系统中的修改,一个方法是可以使用块设备/硬盘镜像启动,另一个方法是可以在系统启动后挂着一个硬盘镜像,将所有修改保存在该硬盘上。

-device/-drive:指定一个块设备/硬盘,该设备对应/dev/vda文件。如果要使用该设备作为根文件系统,可以修改-append选项中的root参数为root=/dev/vda,这种情况下,在系统中的修改会被保存在-drive选项中file指定的镜像文件中。如果该设备不是根文件系统,则可以在进入系统后使用mount命令(例如mount /dev/vad /mnt)加载该文件系统,用于保存系统中的修改。

-device/-netdev:给虚拟机配置一个网卡,对应Buildroot构建时配置的通过DHCP自动分配IP地址的eth0网卡。其中host=10.0.2.1是qemu user类型网络的默认网段10.0.2.0/24的一个地址,分配给host使用,guest通过dhcp获取从该网段获取ip地址。hostfwd=tcp::5555-:22是将host的5555端口的数据都转发到guest的22端口(ssh),host可以通过该端口ssh登录到guest。 

上面的示例使用user类型网卡,只能host连接guest。也可以使用tap类型网卡,使用-device virtio-net-device,netdev=tap0 -netdev tap,id=tap0 或者-net tap -net nic选项(可以使用多次,创建多个网卡),需要注意的是,tap类型网卡需要root权限启动qemu。使用tap类型网卡,在guest和host都会创建tap类型的网卡,guest的tap网卡自动配置了ip地址,host的没有配置,可以给它配置同一个网段的ip,例如sudo ip addr add 169.254.62.132/16 dev tap0,就可以双向互相ping通了。

-append:内核启动参数,可以使用man bootparam了解更多,更准确的,则要看对应内核版本的源码。

-fsdev/-device:指定9P文件系统选项,开启host和guest共享文件夹功能。其中path指定host文件夹路径,mount_tag指定在guest加载9P文件系统时,mount的设备名称,即mount命令的device参数。

注意:

不同架构qemu命令参数和内核参数会有些差别,特别是内核参数,例如console在riscv和x86_64架构下是ttyS0,在arm和aarch64架构下则是ttyAMA0,arm架构还需要指定dtb。复制其他架构的qemu命令来使用时需要注意这点,否则可能看起来像qemu挂死的样子。

    1. ssh登录guest

虚拟机启动后,host可以使用ssh登录guest:

ssh root@localhost -p 5555

也可以使用scp传递文件。

因为root用户密码为空,ssh和scp都不需要输入密码。

  1. 构建和运行其他体系架构的Linux系统

可以复制一份config文件到其他体系架构的输出目录,在此基础上配置,体系架构和交叉编译工具链需要重新配置,而可以省去配置目标软件包,系统配置,根文件系统等选项。

另外,也可以使用Buildroot提供的默认配置生成.config,再修改需要软件包配置,可以解决openssh等软件包编译的问题(需要合适的交叉工具链选项才能编译),或者qemu启动的问题(需要打开一些内核选择才能通过qemu启动)。

在执行make之前,可以使用compare-conig工具检查一下修改了哪些配置选项,确保无误:

./compare-config -p "BR2_" -C

    1. aarch64

qemu-system-aarch64 -M virt -m 256M -nographic -kernel images/Image -device virtio-rng-pci -append "root=/dev/vda rw console=ttyAMA0" -device virtio-net-device,netdev=net0 -netdev user,id=net0,host=10.0.2.1,hostfwd=tcp::5555-:22 -cpu cortex-a57 -drive if=none,file=images/rootfs.ext4,format=raw,id=hd0 -device virtio-blk-device,drive=hd0

问题:qemu启动后无输出,起来像挂死。

原因:内核启动参数console设置错误(-append "root=/dev/vda rw console=ttyS0"),应该使用console=ttyAMA0。

console参数不同架构不同版本不一样,需要根据硬件和内核版本配置。

问题:ssh登录无反应(卡死)

解决:原因未确定,修改了配置(主要的选项是toolchain-external-arm-aarch64),重新编译之后解决。

    1. x86_64

qemu-system-x86_64 -m 256M -nographic \

-kernel images/bzImage \

-device virtio-rng-pci \

-hda data.ext4 \

-initrd images/rootfs.cpio.xz \

-append "root=/dev/ram rw console=ttyS0" \

-device e1000,netdev=net0 \

-netdev user,id=net0,host=10.0.2.10,hostfwd=tcp::5555-:22

    1. arm

qemu-system-arm -cpu cortex-a15 -smp 4 -m 4096 -machine type=vexpress-a15 -drive if=sd,driver=file,filename=images/rootfs.ext4  -kernel images/zImage -initrd images/rootfs.cpio -dtb build/linux-custom/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dtb  -append "console=ttyAMA0 root=/dev/ram ro" -nographic -device virtio-net-device,netdev=net0 -netdev user,id=net0,host=10.0.2.1,hostfwd=tcp::5555-:22

问题:qemu启动后无输出,起来像挂死。

原因:内核启动参数console设置错误(-append "root=/dev/vda rw console=ttyS0"),应该使用console=ttyAMA0。

另外,qemu-system-arm启动需要通过-dtb选项指定dtb。

    1. armeb

qemu启动命令:

qemu-system-arm -cpu cortex-a15 -smp 4 -m 4096 -machine type=vexpress-a15 -drive if=sd,driver=file,filename=images/rootfs.ext4  -kernel images/zImage -initrd images/rootfs.cpio -dtb build/linux-5.15.26/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dtb  -append "console=ttyAMA0 root=/dev/ram ro" -nographic -device virtio-net-device,netdev=net0 -netdev user,id=net0,host=10.0.2.1,hostfwd=tcp::5555-:22

注意,要指定dtb,console使用ttyAMA0,不然会卡死。

问题:交叉编译工具使用toolchain-external-bootlin版本的出现编译失败。

>>> host-file 5.41 Autoreconfiguring

...

checking for ANSI C header files... Cannot execute cross-compiler '/home/alpha/Workspace/buildroot/buildroot-armeb/per-package/toolchain-external-bootlin/host/opt/ext-toolchain/bin/armeb-linux-gcc.br_real'

make[1]: *** [package/pkg-generic.mk:282: /home/alpha/Workspace/buildroot/buildroot-armeb/build/toolchain-external-bootlin-2021.11-1/.stamp_configured] Error 1

make[1]: *** Waiting for unfinished jobs....

...

解决:交叉编译工具改用Buildroot自带的toolchain-external-linaro-armeb版本。

问题:qemu启动后无输出,起来像挂死。

原因:内核启动参数console设置错误(-append "root=/dev/vda rw console=ttyS0"),应该使用console=ttyAMA0。

另外,qemu-system-arm启动需要通过-dtb选项指定dtb。

    1. ppc64

ppc64先使用Buildroot提供的默认配置生成config,再配置软件包比较合适,例如:

make O=$PWD -C ../buildroot-2022.02/ qemu_ppc64_e5500_defconfig

这个默认配置还会自动生成一个qemu启动脚本。

然后使用make menuconfig修改软件包等配置(例如增加openssh)。

qemu启动命令:

qemu-system-ppc64 -M ppce500 -cpu e5500 -m 512 -kernel images/uImage -drive file=images/rootfs.ext4,if=virtio,format=raw -initrd images/rootfs.cpio -append "console=ttyS0 rootwait root=/dev/ram" -serial mon:stdio -nographic -device e1000,netdev=net0 -netdev user,id=net0,host=10.0.2.1,hostfwd=tcp::5555-:22

    1. 样例配置和脚本

参考:https://gitee.com/xunknown/buildroot-samples.git

    1. 一些问题解决

1、qemu要使用什么类型网卡?e1000?virtio-net-device?如果不能启动网卡,可以考虑使用-nic user启动,根据kernel日志判断qemu默认使用的网卡类型,再使用-device配置对应的网卡,进一步可以配置详细参数(例如转发)。例如mips架构通过这个方式可以看到qemu默认使用的是pcnet网卡。  

  1. 参考
  1. Buildroot:https://buildroot.org/downloads/manual/manual.html
  2. QEMU:https://wiki.qemu.org/Documentation
  3. QEMU:Welcome to QEMU’s documentation! — QEMU documentation
  4. QEMU 9P文件系统:https://wiki.qemu.org/Documentation/9psetup
  5. compare-config:https://gitee.com/xunknown/compare-config
  6. 样例配置和脚本:https://gitee.com/xunknown/buildroot-samples.git
  7. 用QEMU实现的网络模式
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用Buildroot + QEMU构建和运行Linux 的相关文章

  • centos7.6远程图形桌面开启和VNC连接

    centos7 6远程图形桌面开启和VNC连接 xff08 一 xff09 安装 yum install tigervnc tigervnc xff1b yum install tigervnc tigervnc server y 搞什么鬼
  • Mac配置sublime text3+python3+brew+boost+cmake+kenlm环境

    1 首先安装python3 xff0c 配置python3环境 下载python3 7 1安装包 xff0c 链接 https pan baidu com s 1JaPaoUCGNeYj60gATpb9eg 密码 0mh6 将python3
  • Centos7安装Python3.7详细教程

    Centos7安装Python3 7详细教程 注 xff1a 如果安装更高的python版本 xff0c 只需修改wget 后面的地址即可 xff0c 然后注意执行命令时候的路径等问题 如 xff1a 安装python3 7 5 则 xff
  • 多用户同时修改同一条数据(并发修改数据)

    如果两个用户同时打开一条记录 xff0c 修改后提交会产生更新冲突 办法有三 xff1a 1 打开同时锁定表的记录 2 用lock对修改方法加锁 2 捕获错误 xff0c 撤消其中一个用户的修改 场景描述如下 xff1a 用户A B同时打开
  • Go 语言入门很简单:Go 实现简易Web应用

    前言 截止到目前为止 xff0c 几乎我们的 Go 入门文章都是在终端运行的 在终端运行的代码或者运用运用程序只适合自己在环境搭好的环境下使用 也就是说 xff0c 如果用户没有安装 Go 语言环境 xff0c 是根本没法运行我们所写的 G
  • 【待解决】使用su或sudo出现Segmentation fault

    一台服务器上 xff0c 使用sudo会出现Segmentation fault xff0c 见下 xff1a 使用root登录后 xff0c 使用su命令 xff0c 一样的会出现Segmentation fault 暂时还未找到答案 相
  • go换源|go更换国内源

    Windows 版本 SETX GO111MODULE on go env w GOPROXY 61 https goproxy cn direct SETX GOPROXY https goproxy cn direct Linux 版本
  • linux安装go环境并配置国内源

    linux安装go环境并配置国内源 第一步 官网下载安装包 https golang google cn go1 4 linux amd64 tar gz 第二步 解压缩 tar C usr local xzf go1 4 linux am
  • python - 获取时间戳(10位和13位)

    在python 开发web程序时 xff0c 需要调用第三方的相关接口 xff0c 在调用时 xff0c 需要对请求进行签名 需要用到unix时间戳 在python里 xff0c 在网上介绍的很多方法 xff0c 得到的时间戳是10位 而j
  • curl命令模拟post请求发送json格式数据

    以下代码可以作为测试接收请求的程序直接复制使用 xff1a from flask import Flask request app 61 Flask name 64 app route 39 service 39 methods 61 39
  • pip换源 -pip更换国内镜像源

    更换pip源到国内镜像 pip国内的一些镜像 阿里云 http mirrors aliyun com pypi simple 中国科技大学 https pypi mirrors ustc edu cn simple 豆瓣 douban ht
  • 使用python的requests 发送multipart/form-data 请求

    发送post请求 1 r 61 requests post 34 http pythontab com postTest 34 data 61 34 key 34 34 value 34 以上得知 xff0c post请求参数是以data关
  • SHELL - shell 脚本获取本机ip并将ip复制给变量待用

    bin bash VAR 61 34 eth0 34 HOST IP 61 ifconfig VAR grep 34 inet addr 34 awk 39 print 2 39 awk F 39 print 2 39 echo HOST
  • shell - sed匹配某一行开头,替换整行内容

    sed i 39 cloud server ip ccloud server ip 61 update skyeye 360safe com 39 name txt
  • caffe安装系列——安装cuda和cudnn

    博客新址 http blog xuezhisd top 邮箱 xff1a xuezhisd 64 126 com 说明 网上关于caffe的安装教程非常多 xff0c 但是关于每一步是否操作成功 xff0c 出现了什么样的错误又该如何处理没
  • caffe安装系列——安装OpenCV

    博客新址 http blog xuezhisd top 邮箱 xff1a xuezhisd 64 126 com 说明 网上关于caffe的安装教程非常多 xff0c 但是关于每一步是否操作成功 xff0c 出现了什么样的错误又该如何处理没
  • 写递归函数的正确思维方法

    什么是递归 简单的定义 当函数直接或者间接调用自己时 xff0c 则发生了递归 说起来简单 但是理解起来复杂 因为递归并不直观 也不符合我们的思维习惯 相对于递归 我们更加容易理解迭代 因为我们日常生活中的思维方式就是一步接一步的 并且能够
  • PCL系列——拼接两个点云

    博客新址 http blog xuezhisd top 邮箱 xff1a xuezhisd 64 126 com PCL系列 PCL系列 读入PCD格式文件操作PCL系列 将点云数据写入PCD格式文件PCL系列 拼接两个点云PCL系列 从深
  • PCL系列——三维重构之移动立方体算法

    博客新址 http blog xuezhisd top 邮箱 xff1a xuezhisd 64 126 com PCL系列 PCL系列 读入PCD格式文件操作PCL系列 将点云数据写入PCD格式文件PCL系列 拼接两个点云PCL系列 从深
  • 字节(Byte)与位(bit)、十进制与二进制的关系

    一 基本常识 数据存储是以 字节 xff08 Byte xff09 为单位 xff0c 数据传输大多是以 位 xff08 bit xff0c 又名 比特 xff09 为单位 xff0c 一个位就代表一个0或1 xff08 即二进制 xff0

随机推荐

  • ubuntu20.04配置TensorFlow-GPU版本+对应版本的cuda&cudnn

    ubuntu20 04配置TensorFlow GPU版本 43 对应版本的cuda amp cudnn 配置说明 操作系统是Ubuntu20 04 xff0c GPU是NVIDIA GeForce RTX 2080 Ti xff0c Py
  • 十四、Rust ORM 框架

    Rust 下的 orm xff0c 之前笔者介绍过 sqlx xff0c 但使用中发现 sqlx 在进行参数绑定时 xff0c 使用的是 宏 xff0c 在当前的 IDE 生态环境下 xff0c 有时不能很好的进行代码提示 xff0c 或代
  • mybatis源码之集成mybatis-plus源码

    本文将结合源码介绍mybatis plus的原理 xff0c 包括 xff1a BaseMapper APIMybatisSqlSessionFactoryBean类BaseMapper API Statement解析Wrapper查询构建
  • Jpa 插入更新如何过滤null值

    使用Jpa时 xff0c 默认的save方法会将entity中null的值也更新到数据库 xff0c 这对与存在默认值或者更新接口将直接导致错误的记录产生 xff0c 那么如何解决这个问题 xff1f Hibernate提供了两个注解 64
  • 一个奇怪的java.lang.IncompatibleClassChangeError异常

    解决方法就是替换jdk版本 xff0c 下面都是废话 最近项目进行了一次小更新 xff0c 添加了一个很小很小的功能 xff0c 结果运行一段时间后莫名出现java lang IncompatibleClassChangeError xff
  • nginx的proxy_pass最后反斜杠/的问题

    如果只是host xff0c 如http host 带 xff1a 用代理的内容替换掉匹配的路径 不带 xff1a 拼接上匹配的路径 2 xff1a 如果是子路径 xff0c 如http host func 带和不带 xff1a 用代理的内
  • gitlab修改克隆地址

    1 修改gitlab yml文件 xff0c 修改gitlab下的host和port vi opt gitlab embedded service gitlab rails config gitlab yml 修改完成后执行gitlab c
  • 结构体成员——数组或指针

    结构体成员是C类型的字符数组 表示字符串时 c语言中没有字符串类型 xff0c 只能使用字符数组表示字符串 当定义结构体时 xff0c 成员是字符数组时 xff0c 在外部给该成员赋值 xff0c 不能使用 结构体把变量名 成员名 61 3
  • C++遍历输出enum枚举类型

    enum DAY MON TUE WED THU FRI SAT SUN 问题 如果使用如下方式来遍历 xff0c 则编译器会报类型转换失败错误 xff0c 因为enum类型没有 43 43 运算符 xff0c 也不支持 43 运算 for
  • Kali Linux

    为什么我输入git clone 43 网址显示无法访问啊
  • Android自定义标题栏异常You cannot combine custom titles with other title features

    我们在使用自定义标题栏时 xff0c 一般的写法基本上是下面几步 requestWindowFeature Window FEATURE CUSTOM TITLE setContentView R layout activity test
  • Kotlin中使用Dagger2 可能导致错误"Dagger does not support injection into private fields"

    Kotlin 生成 java文件时属性默认为 private xff0c 给属性添加 64 JvmField 声明可以转成 public class User var name String 61 null val age Int 61 2
  • [linux]ubuntu22安装mysql5.7.40

    导语 xff1a ubuntu22 04 强制安装mysql5 7 40 安装完安装其他apt依赖的时候 可能会造成mysql出问题 最好还是离线环境用 apt update apt get install zip y cd var rm
  • winxp 远程rdp 连接 Ubuntu10.10-再次远程登陆失败 (二)

    在文章winxp 远程rdp 连接 Ubuntu10 10 一 操作完成 xff0c 并且进行第一成功登陆之后 xff0c 退出 xff08 注销 直接关闭mstsc退出按钮 xff09 远程连接之后 xff0c 重新登录出现 xff0c
  • PostGIS教程七:几何图形(Geometry)

    目录 一 介绍 二 元数据表 三 表示真实世界的对象 3 1 点 xff08 Points xff09 3 2 线串 xff08 Linestring xff09 3 3 多边形 xff08 Polygon xff09 3 4 集合 xff
  • FreeBSD下修改安装源的方法

    FreeBSD默认是从官方的源下载软件包的 xff0c 速度比较慢 xff0c 可以修改配置文件指定国内的镜像源来快速安装软件 说明 xff1a FreeBSD中安装软件一般有两种方式 xff1a xff08 一 xff09 使用pk ad
  • sqlite3_bind

    sqlite3 bind text 中绑定的指针 xff0c 在sqlite3 step 时必须存在 xff0c 不能释放 xff0c 否则会是乱码 sqlite3 bind blob中绑定的指针 xff0c 在sqlite3 step 时
  • Windows10 Clion 无法打开文件cudart.lib

    真是巨坑 xff0c 遇到这个问题 xff0c 且耗费两个小时百度 google xff0c 差点放弃换用Visual Studio xff0c 但真实原因竟然这么简单 在你的CmakeList txt中 xff0c 是不是这样添加cuda
  • cf规则介绍

    codeforces的正确打开方式 1 背景 可能很多人都久闻codeforces网站的大名 xff0c 却苦于各种各样的区域性问题或玄学问题 xff0c 没能真正地体验到cf所带来的极致魅力 而网络上关于这方面的博文太少了 xff08 至
  • 使用Buildroot + QEMU构建和运行Linux

    使用Buildroot 43 QEMU构建和运行Linux xunknown 64 2022 04 06 概述 Buildroot是一个用于为嵌入式系统构建完整的Linux系统 xff08 包括Bootloader xff0c Linux