探索Linux 0.11源码的世界
Linux 0.11是Linus Torvalds于1991年发布的Linux内核的早期版本。这个版本的源代码具有重要的历史意义,并且是理解现代Linux系统的基础。本文将带你深入探索Linux 0.11源码的世界,了解其中的关键部分和设计原理。
1. 引言
在进入源代码的细节之前,让我们先了解一些基本背景。Linux是一个开源的操作系统内核,开发和维护由全球的开源社区共同完成。Linux内核主要由C语言编写,使用了一些汇编语言。Linux 0.11是Linux内核的早期版本,在发布之初只包含了一些基本的功能。
2. 构建过程
了解Linux 0.11的源码之前,我们需要了解如何构建和编译这个版本的内核。在Linux 0.11的根目录下,有一个Makefile文件,该文件描述了整个构建过程。通过运行make命令,可以将源代码编译成可执行的内核文件。让我们来看一下Makefile中的一部分代码:
# 根目录Makefile中的代码片段
# 定义内核编译器
CC=gcc
# 定义编译选项和链接选项
CFLAGS=-Wall -O -fstrength-reduce -fomit-frame-pointer -finline-functions -nostdinc -I../include
ASFLAGS=-D__ASSEMBLY__ -traditional
# 定义链接选项
LDFLAGS=-s -x
# 定义目标文件
OBJS=blk_drv/blk_drv.a chr_drv/chr_drv.a
# 定义目标
all: Image
# 编译目标文件
blk_drv/blk_drv.a:
(cd blk_drv; make)
chr_drv/chr_drv.a:
(cd chr_drv; make)
# 链接目标文件生成Image文件
Image: boot/bootsect boot/setup head.o $(OBJS)
ld $(LDFLAGS) boot/bootsect head.o boot/setup $(OBJS) -o Image
# 清理目标文件和Image文件
clean:
rm -f Image boot/bootsect boot/setup head.o
(cd blk_drv; make clean)
(cd chr_drv; make clean)
在这段代码中,定义了编译选项、链接选项、依赖文件、目标文件和编译/链接规则。我们可以看到,在构建过程中,包含了多个子目录,每个子目录都有自己的Makefile用于描述其构建过程。通过递归调用make命令,可以将每个子目录的源代码编译成目标文件,最终链接生成可执行的内核文件。
3. 内核初始化过程
在Linux 0.11的源码中,有一个非常重要的文件init/main.c,该文件定义了内核的主要入口函数和初始化过程。让我们来看一下其中的一部分代码:
void main(void)
{
...
cli(); // 关闭中断
mem_init(); // 内存初始化
trap_init(); // 中断初始化
sched_init(); // 进程调度初始化
buffer_init(); // 缓冲区初始化
hd_init(); // 硬盘初始化
floppy_init(); // 软盘初始化
sti(); // 开启中断
move_to_user_mode(); // 切换到用户模式
if (!fork()) {
init(); // 初始化用户进程
}
}
在这段代码中,我们可以看到程序的执行流程大致如下:
关闭中断
执行一系列初始化函数,包括内存初始化、中断初始化、进程调度初始化等
开启中断
切换到用户模式
创建一个新的进程,即init进程
这段代码展示了Linux 0.11内核的初始化过程,其中涉及到了多个重要模块的初始化。在程序运行的过程中,还有许多其他模块的初始化和处理工作,这些内容超出了本文的范围。
4. 文件系统
在Linux 0.11的源码中,包含了一个简单的文件系统。文件系统的源码位于fs目录下。让我们来看一下fs目录的结构:
fs/
├── buffer.c
├── exec.c
├── fcntl.c
├── file_dev.c
├── file_table.c
├── inode.c
├── namei.c
├── open.c
├── pipe.c
└── read_write.c
在这些文件中,定义了文件系统的基本操作,包括文件的打开、读取、写入等。其中,最重要的是inode.c文件,该文件定义了inode数据结构和相关函数。让我们来看一下inode.c中的一部分代码:
struct inode inode_table[NR_INODE];
...
struct inode *get_free_inode(void)
{
struct inode * inode;
for (inode = inode_table; inode < inode_table + NR_INODE; inode++)
if (!inode->i_count)
goto found;
return NULL;
found:
...
return inode;
}
这段代码展示了获取空闲inode的过程。在Linux 0.11的文件系统中,inode被用于表示文件和目录。在get_free_inode函数中,通过遍历inode_table数组,找到一个未被使用的inode,并返回其指针。这个过程非常关键,涉及到文件的创建、打开和删除等操作。
5. 设备驱动
Linux 0.11的源码中包含了一些简单的设备驱动程序。这些驱动程序位于drivers目录下,各个驱动程序的代码分别放在不同的子目录中,例如harddisk目录下是硬盘驱动程序的代码,keyboard目录下是键盘驱动程序的代码等。让我们来看一下keyboard目录下的keyboard.c文件:
static void kb_wait(void)
{
u8_t kb_stat;
do {
kb_stat = in_byte(KB_STAT_PORT);
} while (kb_stat & 0x02);
}
static void kb_ack(void)
{
u8_t kb_read;
do {
kb_read = in_byte(KB_DATA_PORT);
} while (kb_read != KB_ACK);
}
void init_keyboard(void)
{
...
kb_wait();
out_byte(KB_CTRL_PORT, KB_CMD_INIT);
kb_ack();
...
}
这段代码展示了键盘驱动程序的初始化过程。通过调用init_keyboard函数,可以初始化键盘,并启动键盘的中断处理程序。其中,kb_wait函数用于等待键盘准备就绪,kb_ack函数用于等待键盘的应答信号,并且init_keyboard函数最终发送了初始化命令给键盘。这些操作是驱动程序与硬件设备进行交互的关键步骤,确保设备正常工作。
6. 结束语
通过对Linux 0.11源码的探索,我们可以深入理解Linux内核的基本结构和设计原理。本文介绍了Linux 0.11的构建过程、内核初始化过程、文件系统和设备驱动等重要部分。但是,由于篇幅和深度的限制,无法详细覆盖所有内容。如果你对Linux内核感兴趣,可以参考更多的资料和源码,进一步学习和探索。