下面是你在使用 Buildroot + QEMU 构建和运行嵌入式 Linux 系统时的 完整安装和使用流程(含命令) ,适用于在 WSL(Ubuntu)环境下进行开发。
一、Buildroot 安装与构建流程
1. 获取 Buildroot 源码
bash
wget https://buildroot.org/downloads/buildroot-2025.05-rc1.tar.gz
tar -xzf buildroot-2025.05-rc1.tar.gz
mv buildroot-2025.05-rc1 buildroot-master
cd buildroot-master
2. 配置 Buildroot(可选)
你可以用默认配置开始:
bash
make qemu_arm_versatile_defconfig
或者进入图形界面定制:
bash
make menuconfig
推荐配置调整(在 menuconfig 中):
Target options
→ Architecture:ARM (little endian)
Toolchain
→Build cross toolchain
:Yes
System configuration
→Root password
:空Target packages
→ 勾选常用工具(如nano
,htop
,busybox
,dropbear
等)Filesystem images
→ Enableext2/3/4 root filesystem
3. 编译 Buildroot 系统
bash
make -j$(nproc)
这个过程特别慢会下载很多第三方库
出现 make clean 之后再make
构建完成后,输出文件在:
output/images/
├── rootfs.ext2 # 根文件系统
├── zImage # 内核镜像
├── vexpress-v2p-ca9.dtb # (如果你配置的是 vexpress 板子)
二、QEMU 安装
1. 安装 QEMU for ARM(如果未安装):
bash
sudo apt update
sudo apt install qemu-system-arm
三、使用 QEMU 启动模拟器
直接运行下面的start-qemu.sh 脚本就行

四、挂载/编辑 rootfs.ext2(可选)
你可以在宿主机编辑 rootfs.ext2 的内容,比如添加文件:
bash
sudo mount -o loop output/images/rootfs.ext2 /mnt
sudo cp hello /mnt/root/
sudo umount /mnt
五、交叉编译你自己的程序
假设你有 hello.c
:
c
#include <stdio.h>
int main() {
printf("Hello from ARM!\n");
return 0;
}
使用 Buildroot 提供的交叉编译器:
bash
output/host/bin/arm-*-gcc hello.c -o hello
然后复制到 rootfs 中,如上所述。
常见问题排查
问题 | 解决方案 |
---|---|
cannot use stdio by multiple character devices |
改用 -serial mon:stdio 替代 -serial stdio |
QEMU 启动后无输出 | 检查 console= 参数,是否和板子匹配 (ttyAMA0 for ARM) |
rootfs 无法挂载 | 确保用 root=/dev/mmcblk0 rw rootwait (SD卡模拟) |
无法编译 | 执行 make clean && make ,确保 host 系统有完整工具链(如 build-essential , libncurses-dev 等) |
如果你有特定的需求,比如:
- 添加 SSH 支持
- 使用 initramfs 而非 rootfs.ext2
- 支持网络功能、NFS、USB、I2C 等
可以继续告诉我,我可以帮你扩展配置。






cpp
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
// PL061 GPIO 寄存器地址(基于 Versatile Express,vexpress-a9)
// 参考:ARM Versatile Express 技术参考手册
#define GPIO_BASE 0x10013000 // GPIO 控制器基地址
#define GPIO_DIR 0x400 // 方向寄存器偏移(0x400)
#define GPIO_SET 0x01C // 数据寄存器偏移(设置高电平)
#define GPIO_CLEAR 0x028 // 数据寄存器偏移(清除低电平)
#define GPIO_PIN (1 << 0) // 使用 GPIO0(可根据需要修改)
int main() {
int fd;
void *gpio_base;
volatile unsigned int *gpio_dir;
volatile unsigned int *gpio_set;
volatile unsigned int *gpio_clear;
// 打开 /dev/mem 以访问物理内存
fd = open("/dev/mem", O_RDWR | O_SYNC);
if (fd < 0) {
perror("无法打开 /dev/mem");
return 1;
}
// 映射 GPIO 寄存器
gpio_base = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, GPIO_BASE);
if (gpio_base == MAP_FAILED) {
perror("mmap 失败");
close(fd);
return 1;
}
// 设置寄存器指针
gpio_dir = (unsigned int *)(gpio_base + GPIO_DIR);
gpio_set = (unsigned int *)(gpio_base + GPIO_SET);
gpio_clear = (unsigned int *)(gpio_base + GPIO_CLEAR);
// 设置 GPIO0 为输出
*gpio_dir |= GPIO_PIN;
printf("LED 点灯程序开始运行...\n");
fflush(stdout);
// 循环点亮和熄灭 LED
while (1) {
// 点亮 LED(设置 GPIO0 高电平)
*gpio_set = GPIO_PIN;
printf("LED 点亮\n");
fflush(stdout);
sleep(1);
// 熄灭 LED(设置 GPIO0 低电平)
*gpio_clear = GPIO_PIN;
printf("LED 熄灭\n");
fflush(stdout);
sleep(1);
}
// 清理(实际上不会到达这里)
munmap(gpio_base, 4096);
close(fd);
return 0;
}
