8.从零开始写LINUX内核——初始化中断控制芯片
Ubuntu 20.04 环境下开发 Linux 0.12 内核全指南
一、开发环境搭建与工具链配置
1. 核心工具链安装
Linux 0.12 内核开发需要特定版本的工具链以确保兼容性,以下是在 Ubuntu 20.04 下的安装命令:
bash
# 安装基础编译工具
sudo apt update && sudo apt install -y \
binutils gcc-multilib g++-multilib \
qemu-system-i386 make xxd \
vim git libncurses5-dev# 验证关键工具版本(Linux 0.12 兼容版本)
as --version | head -n1 # 需显示 2.34 或兼容版本
ld --version | head -n1 # 需显示 2.34 或兼容版本
qemu-system-i386 --version | head -n1 # 4.2 及以上版本
2. 源码获取与目录结构
bash
# 创建工作目录
mkdir -p ~/linux0.12-dev && cd ~/linux0.12-dev# 获取 Linux 0.12 源码(官方归档)
wget https://mirrors.edge.kernel.org/pub/linux/kernel/historic/linux-0.12.tar.gz
tar -zxvf linux-0.12.tar.gz
mv linux-0.12 linux-0.12-src# 目录结构说明
cd linux-0.12-src
ls -l
# boot/:引导相关代码(bootsect.s、setup.s)
# kernel/:内核核心代码
# fs/:文件系统实现
# lib/:库函数
# Makefile:顶层构建文件
二、引导系统开发(boot/ 目录)
1. 引导扇区(bootsect.s)
引导扇区是系统启动的第一个程序,位于磁盘第一个扇区(512 字节):
asm
/* bootsect.s - Linux 0.12 引导扇区* 功能:加载 setup 程序并跳转执行*/
.code16 /* 16位实模式 */
.text
.global _startBOOTSEG = 0x07c0 /* BIOS加载地址 */
INITSEG = 0x9000 /* 重定位目标地址 */
SETUPSEG = 0x9020 /* setup程序加载地址 */
SETUPLEN = 4 /* setup程序占用扇区数 */_start:jmpi $BOOTSEG, $start2 /* 跳转到正确地址 */start2:/* 初始化段寄存器 */movw %cs, %axmovw %ax, %dsmovw %ax, %esmovw %ax, %ssmovw $0xff00, %sp /* 设置栈指针 *//* 清屏操作 */movw $0x0600, %axxorw %bx, %bxmovb $0, %chmovb $0, %clmovb $24, %dhmovb $79, %dlint $0x10/* 显示引导信息 */movw $msg1, %axmovw %ax, %bpmovw $0x1301, %axmovw $0x000c, %bxmovw $25, %cxmovb $0, %dhmovb $0, %dlint $0x10/* 移动自身到0x90000 */movw $BOOTSEG, %axmovw %ax, %dsmovw $INITSEG, %axmovw %ax, %esxorw %si, %sixorw %di, %dimovw $256, %cxrepmovswjmpi $INITSEG, $gogo:/* 加载setup程序 */movw $0x0000, %dxmovw $0x0002, %cxmovw $0x0200, %bxmovb $SETUPLEN, %almovb $0x02, %ahint $0x13jnc ok_load_setup/* 读盘错误处理 */xorw %ax, %axint $0x13jmp gook_load_setup:/* 跳转到setup程序 */jmpi $SETUPSEG, $0msg1:.ascii "Loading Linux 0.12...".org 510.word 0xaa55 /* 引导标志 */
2. 编译引导扇区
bash
# 进入boot目录
cd ~/linux0.12-dev/linux-0.12-src/boot# 汇编生成二进制
as -32 -o bootsect.o bootsect.s
ld -m elf_i386 -Ttext 0x7c00 -s --oformat binary -o bootsect bootsect.o# 验证大小(必须512字节)
ls -l bootsect | awk '{print $5 " bytes (should be 512)"}'
三、Setup 程序开发(setup.s)
Setup 程序负责实模式到保护模式的过渡:
asm
/* setup.s - Linux 0.12 系统设置程序* 功能:收集硬件信息、初始化GDT、切换到保护模式*/
.code16
.text
.global _start_setupINITSEG = 0x9000
SETUPSEG = 0x9020_start_setup:/* 初始化段寄存器 */movw %cs, %axmovw %ax, %dsmovw %ax, %es/* 收集硬件信息 */# 获取光标位置movb $0x03, %ahxor %bh, %bhint $0x10movw %dx, (0)# 获取内存大小movb $0x88, %ahint $0x15movw %ax, (2)# 获取显示模式movb $0x0f, %ahint $0x10movw %bx, (4)movw %ax, (6)/* 显示setup运行信息 */movw $msg, %axmovw %ax, %bpmovw $0x1301, %axmovw $0x000c, %bxmovw $16, %cxmovb $3, %dhmovb $0, %dlint $0x10/* 准备进入保护模式 */cli/* 移动内核到低地址 */movw $0x0000, %axcld
do_move:movw %ax, %esaddw $0x1000, %axcmpw $0x9000, %axjz end_movemovw %ax, %dsxorw %di, %dixorw %si, %simovw $0x8000, %cxrepmovswjmp do_move
end_move:/* 加载GDT */lgdt gdt_48/* 初始化8259A中断控制器 */call empty_8042movb $0xd1, %aloutb %al, $0x64call empty_8042movb $0xdf, %aloutb %al, $0x60call empty_8042/* 切换到保护模式 */movl %cr0, %eaxorl $1, %eaxmovl %eax, %cr0/* 跳转到32位内核 */.byte 0x66, 0xea.long 0x00000000.word 0x0008empty_8042:.word 0x00eb, 0x00ebinb $0x64, %altestb $2, %aljnz empty_8042ret/* GDT定义 */
gdt:.word 0, 0, 0, 0.word 0x07ff, 0x0000, 0x9a00, 0x00c0.word 0x07ff, 0x0000, 0x9200, 0x00c0gdt_48:.word 0x800.word 512 + gdt, 0x9msg:.ascii "setup running".fill 2048 - (.-_start_setup), 1, 0
编译命令:
bash
as -32 -o setup.o setup.s
ld -m elf_i386 -Ttext 0x0 -s --oformat binary -e _start_setup -o setup setup.o
四、内核编译与运行
1. 修改 Makefile(适配 Ubuntu 20.04)
需要调整顶层 Makefile 以确保兼容现代工具链:
bash
# 编辑顶层Makefile
vim ~/linux0.12-dev/linux-0.12-src/Makefile# 修改以下内容:
# CC = gcc → CC = gcc -m32
# LD = ld → LD = ld -m elf_i386
# 增加ASFLAGS = -32
2. 完整编译流程
bash
# 回到源码根目录
cd ~/linux0.12-dev/linux-0.12-src# 清理并编译
make clean
make Image# 生成软盘镜像
dd if=/dev/zero of=linux0.12.img bs=1440k count=1
dd if=boot/bootsect of=linux0.12.img bs=512 count=1 conv=notrunc
dd if=boot/setup of=linux0.12.img bs=512 count=4 seek=1 conv=notrunc
dd if=Image of=linux0.12.img bs=512 count=2875 seek=5 conv=notrunc
3. 使用 QEMU 运行
bash
qemu-system-i386 -fda linux0.12.img -boot a -vga std -no-reboot
成功运行后,QEMU 窗口将显示 Linux 0.12 的启动信息,包括内存检测和进程初始化过程。
五、常见问题解决
汇编错误:invalid instruction suffix for `push'
- 原因:现代 as 默认使用 64 位模式
- 解决:所有汇编命令添加
-32
参数(已在上述命令中包含)
链接错误:cannot generate 32-bit executable
- 原因:缺少 32 位库支持
- 解决:安装
gcc-multilib
和libc6-dev-i386
QEMU 启动后黑屏
- 原因:引导扇区标志错误
- 解决:检查 bootsect.s 末尾是否有
.word 0xaa55
通过以上步骤,你可以在 Ubuntu 20.04 环境下成功构建并运行 Linux 0.12 内核,为进一步学习内核开发打下基础。后续可逐步研究进程管理、内存管理和文件系统等核心模块的实现。