编译qemu-arm公司的系统中没有这个软件设置外部源也下载不了只能自己编译qenu-arm。1. 安装编译依赖sudo dnf install git gcc make ninja-build glib2-devel pixman-devel zlib-devel python32. 克隆并编译仅构建 ARM 目标大幅缩短编译时间gitclone https://gitlab.com/qemu-project/qemu.gitcdqemu# 1. 告诉系统优先去 Conda 环境里找库文件exportPKG_CONFIG_PATH$CONDA_PREFIX/lib/pkgconfig:$PKG_CONFIG_PATH# 2. 回到 QEMU 源码目录彻底清理旧的编译缓存cd~/code/gitlab/qemurm-rfbuildmkdirbuildcdbuild# 3. 强制指定编译器并带上更新后的环境变量重新配置CC$CONDA_PREFIX/bin/gccCXX$CONDA_PREFIX/bin/g../configure --target-listaarch64-softmmu,arm-softmmu --enable-slirpmake-j$(nproc)3. 编译产物位于 build/ 目录无需安装即可直接使用./build/qemu-system-aarch64 --version编译时是gcc版本太低。没有办法无法安装源里的高版本gcc只能再编译一个高版本的gcc—2026-05-24 通过conda安装gcc的问题解决了。conda设置镜像源有坑除了设置镜像源还要修改默认通道。conda里的gcc 包括arm和x86的是15.x下载编译gcc下载 GCC 12.4.0最新 12.x 稳定版清华 TUNA 镜像仅当 GNU FTP 不通时使用wget https://mirrors.tuna.tsinghua.edu.cn/gnu/gcc/gcc-12.4.0/gcc-12.4.0.tar.xztar xf gcc-12.4.0.tar.xzcd gcc-12.4.0【关键】自动下载 gmp, mpfr, mpc 三大数学库依赖该脚本会从 GNU 内部可信源拉取通常不受企业代理限制./contrib/download_prerequisites创建独立构建目录严禁在源码目录内直接 configuremkdir build cd build配置安装到当前 conda 环境仅启用 C/C禁用多架构以加速编译../configure\--prefix$CONDA_PREFIX\--enable-languagesc,c\--disable-multilib\--disable-bootstrap并行编译根据服务器核心数调整 -j 参数make -j$(nproc)安装到 $CONDA_PREFIXmake install$ gcc --versiongcc (GCC) 12.4.0编写一个最简的OS编写一个最简单的 ARM OS 是学习操作系统原理如启动流程、内存管理、异常处理的绝佳途径。对于初学者强烈建议使用 QEMU 模拟 ARM64 (AArch64) 架构而不是直接操作物理开发板。QEMU 提供了完美的调试环境且 AArch64 的文档比老旧的 ARM32 更清晰、更现代化。以下是一个“最小可运行”的 ARM64 OS 学习路线与调试指南。️ 1. 环境准备你需要一套交叉编译工具链和 QEMU 模拟器# Ubuntu/Debiansudoaptinstallgcc-aarch64-linux-gnu binutils-aarch64-linux-gnu qemu-system-arm gdb-multiarchmake--这个armgcc最后通过conda下载的。conda还有演进版 pixi推荐用这个代替conda# macOS (Homebrew)brewinstallaarch64-elf-gcc aarch64-elf-binutils qemu gdb 2. 最小 OS 代码结构一个能跑起来的最小 OS 只需要两个文件一个汇编启动文件和一个 C 语言主函数。boot.S- 引导与初始化OS 启动时 CPU 处于特定状态必须用汇编完成最基础的初始化才能跳转到 C 代码。.section .text.boot .global _start _start: // 1. 检查处理器ID确保只有核心0执行后续代码 mrs x0, mpidr_el1 and x0, x0, #0xFF cbz x0, primary_core // 非核心0进入死循环 b . primary_core: // 2. 设置栈指针 (SP)C语言运行必须有栈 // 假设我们将栈顶设置在内存 0x48000000 处 ldr x0, 0x48000000 mov sp, x0 // 3. 清零 BSS 段未初始化全局变量 ldr x0, __bss_start ldr x1, __bss_end clear_bss: cmp x0, x1 b.ge jump_to_c stp xzr, xzr, [x0], #16 b clear_bss jump_to_c: // 4. 跳转到 C 语言入口 bl kernel_main // 如果 kernel_main 返回进入死循环 b .kernel.c- 内核主逻辑最简单的内核向 UART 串口打印字符证明 OS 已接管硬件。// PL011 UART 基地址 (QEMU virt 机器默认)#defineUART_BASE0x09000000voiduart_putc(charc){volatileunsignedint*uart_dr(unsignedint*)(UART_BASE0x00);*uart_drc;}voiduart_puts(constchar*s){while(*s)uart_putc(*s);}voidkernel_main(void){uart_puts(Hello, ARM64 OS!\n);// 简单的异常测试触发一个未定义指令异常// asm volatile(.word 0x00000000);while(1){// 内核空闲循环asmvolatile(wfi);}}linker.ld- 链接脚本告诉链接器如何将代码和数据放置到正确的内存地址。这是 OS 开发中最容易出错的地方。ENTRY(_start) SECTIONS { /* QEMU virt 机器的 RAM 起始地址 */ . 0x40080000; .text : { *(.text.boot) *(.text*) } .rodata : { *(.rodata*) } .data : { *(.data*) } . ALIGN(16); __bss_start .; .bss : { *(.bss*) *(COMMON) } __bss_end .; }Makefile- 构建与运行# # 交叉编译工具链配置 # CROSS_COMPILE aarch64-linux-gnu- CC $(CROSS_COMPILE)gcc LD $(CROSS_COMPILE)ld OBJCOPY $(CROSS_COMPILE)objcopy # # 编译与链接选项 # CFLAGS -Wall -O2 -ffreestanding -nostdinc -nostdlib -mcpucortex-a72 LDFLAGS -T linker.ld -nostdlib # # 目标文件定义 # TARGET kernel.img SRCS boot.S kernel.c # 自动将 .S 和 .c 后缀替换为 .o OBJS $(SRCS:.S.o) OBJS $(OBJS:.c.o) # # 默认目标执行 make 时默认构建 kernel.img # all: $(TARGET) # # 编译规则将 .S 和 .c 文件编译为 .o 目标文件 # %.o: %.S $(CC) $(CFLAGS) -c $*.S -o $*.o %.o: %.c $(CC) $(CFLAGS) -c $*.c -o $*.o # # 链接规则将所有 .o 目标文件链接成 kernel.bin # kernel.bin: $(OBJS) $(LD) $(LDFLAGS) $(OBJS) -o kernel.bin # # 格式转换将 ELF 格式的 kernel.bin 转为纯二进制 kernel.img # kernel.img: kernel.bin $(OBJCOPY) -O binary kernel.bin kernel.img # # 运行与调试目标 # run: $(TARGET) qemu-system-aarch64 -M virt -cpu cortex-a72 -nographic -kernel kernel.img debug: $(TARGET) qemu-system-aarch64 -M virt -cpu cortex-a72 -nographic -kernel kernel.img -s -S gdb-multiarch -ex target remote localhost:1234 -ex symbol-file kernel.bin # # 辅助目标 # clean: rm -f $(OBJS) kernel.bin $(TARGET) .PHONY: all run debug clean help help: echo 可用的 make 命令 echo make - 编译生成 kernel.img默认 echo make run - 使用 QEMU 运行内核 echo make debug - 启动 QEMU 并进入 GDB 调试模式 echo make clean - 清理所有编译生成的文件 3. 如何高效调试OS 开发没有printf可用在你自己实现之前必须依赖调试器。GDB QEMU 联合调试运行make debug后GDB 会连接到 QEMU 的内置 GDB Server。你可以像调试普通程序一样调试 OSGDB 命令作用OS 调试特殊用途b kernel_main在 C 入口设断点验证汇编跳转是否成功info registers查看所有寄存器检查 SP、ELR_EL1、ESR_EL1x/16xb 0x40080000查看内存十六进制验证代码是否正确加载到指定地址set $sp0x48000000手动修改寄存器修复因栈设置错误导致的崩溃stepi/si单步执行一条汇编跟踪启动阶段每一条指令关键调试技巧永远先调通串口输出在写任何复杂功能前先让uart_putc工作。它是你后续所有调试信息的唯一出口。善用 QEMU 的-d参数当 OS 莫名重启或挂起时使用qemu-system-aarch64 -d int,unimp,guest_errors -D qemu.log ...QEMU 会将中断、未实现指令、客户机错误记录到日志文件中这比 GDB 更能定位底层问题。检查异常级别 (EL)AArch64 有 EL0-EL3 四个特权级。QEMU virt 默认从 EL1 启动。如果你的代码试图访问 EL2/EL3 寄存器会触发异常。用mrs x0, CurrentEL确认当前特权级。 4. 推荐学习路径与资源不要试图从零发明一切站在巨人肩膀上入门教程搜索“Writing an Operating System for Raspberry Pi 3”(GitHub: isometimes/rpi3-os-tutorial)。虽然针对树莓派但前几章完全适用于 QEMU ARM64且讲解极其细致。进阶参考“Operating Systems: From 0 to 1”或 MIT 6.S081 (RISC-V但概念完全相通)。官方文档ARM Architecture Reference Manual (DDI0487)。不需要全读重点看System Registers和Exception Model章节。下一步演进在跑通上述最小 OS 后按此顺序添加功能实现完整的异常向量表 (vbar_el1)实现简单的内存分配器 (buddy system)实现进程/线程上下文切换实现一个简单的 Shell⚠️重要提醒OS 开发中 90% 的 Bug 来自链接脚本地址错误和对齐问题。当你遇到无法解释的崩溃时第一反应应该是检查linker.ld中的地址是否与 QEMU 的内存映射一致以及数据结构是否满足 ARM 的对齐要求。conda修复好了什么意思我们设置了镜像源还要修改默认通道吗● 是的需要理解 conda 的通道机制Conda 通道的工作原理当你设置 channels: 时你只是添加了额外的通道但 defaults 这个特殊通道仍然指向官方源。你的配置channels:- https://mirrors.ustc.edu.cn/anaconda/cloud/conda-forge/- defaults # 这个是特殊的defaults 通道的实际含义defaults 不是一个 URL而是一个别名它默认展开为https://repo.anaconda.com/pkgs/main/https://repo.anaconda.com/pkgs/r/所以即使你设置了镜像源只要 defaults 还在conda 仍会尝试访问 repo.anaconda.com。解决方案有两种方式方案 1完全禁用 defaults推荐channels:- https://mirrors.ustc.edu.cn/anaconda/cloud/conda-forge/只从 conda-forge 安装包。方案 2重写 defaults 指向镜像default_channels:- https://mirrors.ustc.edu.cn/anaconda/pkgs/main/- https://mirrors.ustc.edu.cn/anaconda/pkgs/r/channels:- https://mirrors.ustc.edu.cn/anaconda/cloud/conda-forge/- defaults为什么会这样设计这是 Anaconda 的设计问题。defaults 是硬编码的特殊通道不像其他通道可以直接替换 URL。很多用户都不知道这个坑。简单记忆用国内镜像时要么去掉 defaults要么必须显式重写 default_channels。