系统与基础设施arjunsreedharan.org编辑精选
内核入门——让我们写一个内核
Kernel 101 – Let’s write a Kernel
2014 — 2017,它一次次回到首页
黑点是上首页(≥ 50 分)的那次投稿,空心点是没冲上去的投稿,点越大分数越高。
导读
这是一篇入门教程,手把手教你在 x86 上写出并引导一个最小的“内核”:从 GRUB/Multiboot 引导、进入保护模式,到用 C 代码直接写显存 0xb8000 在屏幕上打印字符串。代码极简,适合作为裸机编程的第一步。
为什么经久不衰:它把“写操作系统”从神秘门槛变成一个下午就能跑起来的实验,多年后仍是初学者进入内核/裸机开发最平易近人的入口之一。
HN 评论精选
指出教程未按 Multiboot 规范设置栈指针,并给出修复方法
教程有个小问题:它假设引导程序会把 ESP(栈指针)设置到合适的栈位置,但 Multiboot 标准规定 ESP 是未定义的,操作系统需要自己尽早建立栈。解决办法是在汇编文件的 .bss 段预留一些字节作为栈,然后在用到栈之前(比如 cli 和 call kmain 之间)设置好栈指针。
grahamedgecombe查看英文原文
There's a slight problem in this tutorial in that it assumes ESP (the stack pointer) will be defined by the boot loader to point to an appropriate location for the stack. However, the Multiboot standard states that ESP is undefined [1], and that the OS should set up its own stack as soon as it needs one (here the CALL instruction uses the stack, and the compiled C code may well too). An easy way to solve this is to reserve some bytes in the .bss section of the executable for the stack by adding a new section in the assembly file: [section .bss align=16] resb 8192 stack_end: Then before you make use of the stack (between `cli` and `call kmain` would be appropriate in this case), you need to set the stack pointer: mov esp, stack_end [1]: https://www.gnu.org/software/grub/manual/multiboot/multiboot.html#Machine-state
教程能跑通靠运气:缺栈空间设置和 BSS 清零,换编译选项就可能失败
这是个不错的起点,但要注意它并不能保证正确工作。问题在于控制权交给 C 代码时没有设置栈空间,它能跑起来纯属运气——编译器恰好把所有变量都放在寄存器里,换个编译选项就可能以有趣的方式失败。另外还缺少在进入 C 代码前清零 .bss 段的步骤。我在自己的 Ring-0 项目里就为栈空间和未初始化 BSS 调试了很久。
exDM69查看英文原文
This seems like a good start but it's worth noting that it isn't guaranteed to work correctly. The problem is that the control is passed to C code with no stack space set up. It works out of pure luck because the compiler has decided to keep all variables in registers and changing your C compiler flags might make this fail in interesting ways. Another thing that is missing is clearing the .BSS section before passing control to the C code. It's not used at the moment, though. I am pointing these things out because in my own Ring—0 programming projects I spent a lot of time debugging some failures related to stack space and an un-initialized BSS section.
建议加 volatile、用交叉编译器而非系统 gcc,并配好目标平台调试器
裸机项目是很有趣的爱好,分享一些我吃过的亏。char *vidptr = (char*)0xb8000 需要 volatile 限定符,否则开优化后对显存的写入会被丢弃——内存映射 I/O 正是 C 里少数必须用 volatile 的场景。另外裸机项目应该构建交叉编译器,用系统自带的 gcc 长远看不行,它可能带有针对宿主系统的补丁或配置,最糟的是可能看起来能用一段时间然后突然出问题。应为 i686-pc-elf 目标构建 binutils 和 GCC,再配上目标平台的 gdb,调试会容易得多。
exDM69查看英文原文
Bare metal projects are always a fun hobby. I've done some projects like this in the past [0], let me share some things I learned the hard way. If the author is reading, here are a few corrections. > char * vidptr = (char * )0xb8000; This needs "volatile" qualifier or all the writes to video memory will be dropped when optimization is enabled. Memory mapped I/O like this is one of the few use cases where you need "volatile" in C. > gcc -m32 -c kernel.c -o kc.o You need to build a cross-compiler for bare metal projects. Using the system gcc will not work in the long run. The compiler packaged with your operating system is intended for building binaries for use with your operating system. It may have downstream patches or configured to a target in a way that will cause problems. The worst part is that it may seem to work for a while, until it doesn't. I ran into some hard-to-debug issues with my past projects and learned this the hard way. If I recall correctly, the issues were related to redzones and ABI conventions. You need to build GNU binutils and GCC for the "i686-pc-elf" target. I documented this process for someone else's bare metal project here [1]. It really pays off to do this right from the start. Once you have a cross-compiler and a build system that can produce debuggable elf images (you also need to build gdb for the target), things get much easier. Using the built-in debuggers in QEMU or Bochs can only get you so far. Having a proper debugger with symbols and source view will make working much easier. For a build system, plain old Makefiles work best, CMake and other high level build systems are a pain in the ass with bare metal projects that require linker scripts, etc. [0] https://github.com/rikusalminen/danjeros [1] https://github.com/Overv/MineAssemble/blob/master/README.md
认为这更像裸机应用而非内核,希望教程补充内核架构设计概念
这算不上一个内核,更像一个自包含的裸机应用程序。内核的主要目标是向应用程序提供服务。虽然马上动手写代码、得到可见结果很有成就感,但一篇“Kernel 101”最好还是提到内核设计的核心概念:如何选择宏内核/微内核/纳米内核架构?主要目标和用例是什么?HAL 应该抽象哪些硬件?如何设计用户态-内核及驱动-内核的 API/ABI?需要多少隔离、用什么方式提供?
magnat查看英文原文
It's not much of a kernel. More like a self-contained bare-metal application. Main goal of a kernel is to provide services to applications. Although starting coding right away and getting tangible results is somewhat rewarding, it would be nice to see core concepts of designing a kernel mentioned in a "Kernel 101" article: * How to choose between monolithic/micro/nano architecture? * What are primary goals and use cases? * What hardware should it abstract away in HAL? * How to design userland-kernel and drivers-kernel API/ABI? * How much isolation is needed and what are ways to provide it?
历次讨论
同类还值得读
TTY 揭秘(2008)
The TTY demystified (2008)
经典文章深入剖析了 Unix/Linux 中 TTY 子系统的工作原理,包括线路规程、终端驱动、信号与控制字符等机制。
系统与基础设施上首页 11 次 · 2009–2025linusakesson.net编辑精选为什么 GNU grep 这么快
Why GNU grep is Fast
FreeBSD 邮件列表上一篇广为流传的帖子,解释 GNU grep 为什么快:核心在于 Boyer-Moore 字符串搜索算法配合精心优化的内部循环和 I/O,让程序在搜索时“…
系统与基础设施上首页 9 次 · 2010–2022lists.freebsd.orgXplain:为普通人讲解 X11
Xplain – Explaining X11 for the rest of us
《Xplain》是作者(HN 用户 Jasper_)写的一系列 X11 长文,用他在浏览器中重建的 X11 绘图模型做交互演示,讲解 X11 的绘图模型与窗口系统设计。
系统与基础设施上首页 6 次 · 2013–2020magcius.github.io编辑精选旋风教程:为 Linux 创建极小 ELF 可执行文件(1999)
A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux (1999)
breadbox 写于 1999 年的经典教程,主题是如何为 Linux 手工构造并裁剪出体积极小的 ELF 可执行文件。
系统与基础设施上首页 6 次 · 2007–2025muppetlabs.comPostgreSQL 内部原理
The internals of PostgreSQL
《The Internals of PostgreSQL》是一本免费在线书籍,系统讲解 PostgreSQL 的内部实现,包括查询处理、并发控制、WAL、缓冲区管理等核心机制。
系统与基础设施上首页 5 次 · 2017–2025interdb.jp编辑精选