资讯动态

自研操作系统OS类Unix内核开发环境搭建与问题分析(GRUB, Multiboot, xorriso, clangd)

发布时间:2026/10/19 21:56:29 来源:尧图企业网站定制
0 环境准备windows11宿主机, intel core系列芯片vmplayer 17虚拟机(免费)ubuntu24.04vscodeclangd (vscode插件)xorriso (xorriso和bear都可以通过sudo apt install安装)bear (生成build json文件供clangd代码分析内核开发一般用clangd分析)1 前言1.1. 大学课程里的操作系统课程主要是针对内核而言。和字面意思理解可能不一样真正的内核在计算机的运行框架里更像是千层饼里的一层而不是想象中的一个球体。1.2. 在内核之下有硬件,bios寄存器,grub等为内核提供操作硬件的接口指令(这也是内核需要适配不同架构的原因。不同架构的接口指令不同内核只能分开处理统一逻辑)严格可以说内核代码是不直接操作硬件的。1.3. 在内核之上则是用户态程序。而用户态是内核分级权限指令的一种状态。所以可以称为运行在内核用户态之上的程序。怎么运行的呢内核针对用户态会有专门的syscall_abi接口以提供给用户态程序使用包括文件处理内存处理打印服务网络服务等等。这些都有对应的syscall_abi接口提供给用户程序。内核只需要保证abi接口稳定就可以实现内核和用户程序的更新隔离以及编译隔离。常见的用户程序比如(图形界面终端等)。1.4. 我们常见的OS镜像包比如windows的iso安装包ubuntu的iso安装包这些里面包含的是两部分内核以及常驻用户程序。我们可以把内核比作一栋毛坯房把常驻用户程序比作精装修。我们日常使用的电脑系统就是一个精装修的房子。也就是说一栋毛坯房不同的精装修就是不同的居住体验类似不同的linux系统发行商版本arch, ubuntu等。从这个比喻也可以看出即便只有内核也可以算作一个OS可以运行了。就像毛坯房也可以住人不是就是条件简陋点。而我们的目标就是做毛坯房。一个人喔精装房就不用想了没必要。我们是要学习操作系统的不是要做一个新系统开公司和华为苹果windows竞争喔(狗头)。tips: 为什么华为排第一呢因为俺是中国人(^v^)1.5 可以看出常驻用户程序这一层更侧重留住用户是用户导向功能优先而内核这一层更侧重稳定性能时间安全。当然常驻用户程序肯定也是侧重稳定性能时间安全的。但就像刚才的比喻一样常驻用户程序即便在这四项上不达标或表现不好也就是居住体验不好能忍。但内核如果在这四项上不达标或表现不好那就是危房了怎么会有用户敢住呢。2 具体内核选择2.1. 有两个选择方向一个是看早期版本内核这个时候内核是完整的相对简单的能够帮助理解整个内核架构和全貌。这也够了对于想要深入了解内核的同学。至于比如2026年现在的linux内核那都是好多人经过几十年积累写的呢一个人怎么看的完至于为什么不提windows内核呢因为是闭源的俺不想吃国家饭(狗头)。另外个人也觉得windows内核估计很丑陋光看mfc相关就难受。至于另外一个选择呢自然就是自己手搓了。2.2. 那么我们手搓肯定是推荐参考linux的。那这不就矛盾了吗linux那么大我手搓本来就是为了避免看linux那么大的代码。ok现在是2026年我们有AI大人了。2.3. 从创建内核项目目录开始我们就需要了解从引导程序到内核入口这段路程。这其中涉及到内核层与内核层之下的层级交互。会出现很多的名词。我个人推荐在遇到不熟悉的名词时搜索了解一下这些名词背后的发展历史对于自写内核有很大帮助就会觉得喔原来在几十年的诞生历史里内核是这样随着计算机产生长大的。3. 工具编译相关3.0. 首先我们需要在编译系统禁用c库文件以及若干针对内核的编译项比如CPARAMS -m32 -I. -nostdlib -fno-builtin -fno-exceptions \ -fno-leading-underscore -stdgnu2x \ -ffreestanding -fno-stack-protector \ -fno-pic -fno-pie \ -Wall -Wextra -Wno-address-of-packed-member \ -mno-sse -mno-mmx -mno-sse2 -mno-3dnow -mno-avx \ -O2 -g其中-std传统经典的内核比如linux一般都选择gnu11也就是c11但这里为什么选c23呢。因为理论上c23比c11更有优势一些。那为什么linux不用呢我问AI大人说是历史包袱更换代价大且收益不高。3.1. 之前已经讲过内核只是计算机千层饼的中间一层那么要做一个内核呢cpu架构引导程序引导程序提供给内核的统一接口规范内核打包成可运行iso镜像工具x86grubmultiboot自研内核xorrisoarmubootboom/bootz(arm相比于x86在引导程序有很大不同这里放在一列只是为了好看)自研内核xorriso3.2 首先我们要先明确手搓的各个阶段。既然我们要盖房子那就必须得有地基也就是引导程序。引导程序选择呢根据你的电脑的cpu型号来定。我是大部分人所以选择grub。那么我们写内核时怎么就算选择到grub呢3.2.1. 首先我们需要在内核编译文件里添加grub编译命令:$(JLOS).bin: arch/$(ARCH)/linker.ld $(OBJS)ld $(LDPARAMS) -T $ -o $(JLOS).bin $(OBJS)install: $(JLOS).binsudo cp $ /boot/$(JLOS).bin$(JLOS).iso: $(JLOS).binrm -rf isomkdir -p iso/boot/grubcp $ iso/boot/$(JLOS).binecho set timeout0 iso/boot/grub/grub.cfgecho set default0 iso/boot/grub/grub.cfgecho iso/boot/grub/grub.cfgecho menuentry johnlove operating system { iso/boot/grub/grub.cfgecho multiboot /boot/$(JLOS).bin iso/boot/grub/grub.cfgecho boot iso/boot/grub/grub.cfgecho } iso/boot/grub/grub.cfggrub-mkrescue --output$ isorm -rf iso3.2.2. 我们需要.ld链接脚本来定义内核文件链接规则包括段配置虚拟地址边界输出.bin文件的架构和格式以及引导程序加载内核iso后第一条cpu指令执行地址名称。比如ENTRY(loader)OUTPUT_FORMAT(elf32-i386)OUTPUT_ARCH(i386:i386)这里我们指定了入口地址名是loader链接器输出.bin的格式是32位x86 ELF架构是i386。3.2.3. 然后我们需要一个.s文件来定义loader入口比如.global loader .type loader, function loader: movl $boot_stack_top, %esp cmpl $MULTIBOOT_BOOTLOADER_MAGIC, %eax jne _stop_bad_magic /* 保存 mbinfo 物理地址和 magic 到 .boot 段全局变量 */ movl %ebx, boot_mbinfo_pa movl %eax, boot_magic /* 启动页表: 4MB 大页, 恒等 高半核各映射 64MB */ movl $0x00, %ecx movl $0x83, %eax 1: movl %eax, boot_page_dir(, %ecx, 4) movl %eax, boot_page_dir (768 * 4)(, %ecx, 4) addl $0x00400000, %eax incl %ecx cmpl $16, %ecx jl 1b /* 开分页: CR4.PSE → CR3 → CR0.PG → jmp 序列化 */ /* CR4: PSE(bit4,4MB页) | OSFXSR(bit9,启用FXSAVE/FXRSTOR/SSE) */ movl %cr4, %eax orl $0x210, %eax movl %eax, %cr4 movl $boot_page_dir, %eax movl %eax, %cr3 movl %cr0, %eax andl $~0x4, %eax orl $0x80000022, %eax /* PG(bit 31) | MP(bit 1) | NE(bit 5) */ movl %eax, %cr0 jmp .Lpg_flush .Lpg_flush: lea high_half, %ecx jmp *%ecx _stop_bad_magic: 1: cli hlt jmp 1b .size loader, . - loader /* high_half: 链接在 .text, VMA 0xC01xxxxx */ .section .text .extern john_beauty_main .extern _kernel_end .extern _bss_start .extern _bss_end .type high_half, function high_half: /* 从 .boot 段读取 multiboot 参数 (高半核映射: boot_mbinfo_pa PA → VA PA KERNEL_VIRTUAL_BASE) */ movl boot_mbinfo_pa, %ebx movl boot_magic, %eax /* 切永久内核栈 */ movl $kernel_stack, %esp /* 清零 BSS (不影响 .boot 段的 boot_mbinfo_pa/boot_magic) */ movl $_bss_start, %edi movl $_bss_end, %ecx subl %edi, %ecx xorl %eax, %eax cld rep stosb /* mbinfo 物理地址 → 虚拟地址 */ movl boot_mbinfo_pa, %ebx addl $0xC0000000, %ebx pushl $_kernel_end pushl %ebx call john_beauty_main 1: cli hlt jmp 1b .size high_half, . - high_half在这里我们定义了loader符号也就是cpu会在grub把内核加载到内存完成后从这里开始执行。包括校验内核是否遵照multiboot协议存mb信息建临时栈开分页没问题跳转到high_half继续执行。可以看到在high_half中我们让cpu跳转到了john_beauty_main这个内核入口函数。内核真正的逻辑入口处。3.2.4. 然后生成.bin后我们就需要通过grub-mkrescue来打包.bin。它会调用xorriso来制作grub iso镜像。这样镜像就会被grub识别加载到内存。3.2.5. 综上可以看出我们只需要使用grub来生成grub镜像并在内核可执行文件中定义加载入口地址就算是使用grub了。3.3. 在知道怎么从引导程序加载到内核入口函数后我们就需要编写内核入口函数了比如#include common/multiboot.h #include hal/mmu.h #include hal/context.h #include hal/hal_arch.h #include hal/paging.h #include hal/smp.h #include kernel/multitask.h #include kernel/memory_manager.h #include kernel/page_frame_allocator.h #include kernel/device.h #include kernel/initcall.h #define JLOS_KERNEL_LOG_SUBSYS boot #include kernel/printk.h void john_beauty_main(const multiboot_info_t *multiboot_structure, uint32_t kernel_end) { jlos_hal_arch_init(); jlos_printk_init(); printk_info(princess yihan is safe and happy!\n); jlos_smp_init(); jlos_mmu_init(); jlos_arch_tss_init(); jlos_device_init(multiboot_structure); jlos_pfa_boot_alloc_init(VIRT_TO_PHYS(kernel_end)); jlos_arch_paging_initialize_kernel(jlos_pfa_boot_alloc_page); jlos_page_frame_allocator_init(); printk_info(paging initialized\n); jlos_do_initcalls(); for (;;) { jlos_hal_halt(); } }3.3.1. 从这个入口函数我们就可以看出很多内核子系统初始化包括hal, 打印smp多核mmu, tss, 设备管理pfa, paging分页以及initcall分级初始化。3.3.2. 基本到这里就可以了后续就是内核子系统的实现了那就已经进入内核开发了包括4. 结束4.1. 在计算机分支里学习操作系统可以用到很多计算机知识。但是手搓内核是很耗时耗力的。所以呢大学的时候不是正是有时间琢磨的时候。fighting。最后附上基本几个推荐书籍网站以及个人手搓内核项目(^v^)《c程序设计语言》第2版brian w. kernighan, dennis m. ritchie著徐宝文李志译。经典KR《数据结构与算法分析》c语言描述第2版mark allen weiss著冯舜玺译。https://wiki.osdev.org/Expanded_Main_PageLinux Kernel Teaching — The Linux Kernel documentationjohnbeauty-os:基于 C 的操作系统项目 - AtomGit (俺手搓的实际是基于c没法改链接名称了)

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑