探索Linux 0.11源码的世界

探索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内核感兴趣,可以参考更多的资料和源码,进一步学习和探索。

操作系统标签