目录名 | 所属文件 |
boot | 核心引导代码 |
fs | 文件系统 |
include | 头文件 |
init | Init 进程,系统中执行的第一个进程 |
kernel | 系统调用 |
lib | 库代码 |
mm | 内存管理 |
tools | 内核引导文件的制作工具 |
boot 目录
文件 | 描述 |
boot.s | BIOS 启动的时候加载并执行的代码 |
head.s | 32 bit 的引导代码,调用 init_main() |
boot.s 文件说明
加电自检结束后,boot.s 的代码被加载到 0x7C00 处,然后 boot.s 将自身移动到物理地址的 0x90000 处,接着跳转到该处执行。
boot.s 使用 BIOS 中断在屏幕上打印 “/nLoading system.../n/n”接着读取核心镜像文件到 0x100000 处,然后关闭引导设备,保存光标位置,关闭所有中断,再将系统核心从 0x100000 复制到 0x0000 处。接着载入中断描述符表和全局描述符表。
head.s 文件说明
该文件包含了 32 位系统的初始化代码。初始化代码的物理地址为:0x00000000 ,这个地址也是系统分页目录存放的地址。因此,系统初始化完成后,系统初始化代码将被分页目录的数据替代。
head.s 的具体工作说明:
setup_idt:建立一个 256 个入口的中断向量表,并正确设置中断向量。设置完中断向量后,打开中断。
setup_gdt:建立一个新的 GDT,并正确设置表项。在新的 GDT 中,只有两个表项被装载,这两个表项是在 init.s 中建立的。
setup_paging:通过 cr0 标志位设置为 0 来建立一个页表。建立的页表可以映射机器的前 8M 物理内存。
head.s 由 boot.s 调用执行,当 head.s 执行时,系统运行在 32 位保护模式下。当 head.s 执行时,中断向量表与全局描述符表都已经被正确设置,并且合适的值被装入到 CPU 的帧、栈、堆栈指针寄存器中,然后检查有没有浮点数处理单元,如果没有,就在中断向量表中设置一个软件异常处理程序,便于模式浮点数运算。因为物理地址 0x00000000 实际上是页表数据的存放地址,因此在系统启动的最后阶段,所有的启动代码都被页表数据覆盖,启动代码将执行一个 jmp 指令,跳转到页表后的第一个地址,这个地址就是 _main() 函数的入口地址,这时,系统就执行 init/main.c 中。
fs 目录
fs 包含了文件系统的所有功能:
文件名 文件包含的函数 bitmap.c new_block(),free_block(),new_inode(),free_inode() block_dev.c block_write(),block_read(),ll_rw_block() buffer.c get_hash_table(),get_blk(),sys_sync(),brelse(),bread(),buffer_init() char_dev.c rw_char() exec.c read_head(),read_ind(),read_area(),do_execve() fcntl.c sys_dup2(),sys_dup(),sys_fcntl() file_dev.c file_read(),file_write() file_table.c file_table[] inode.c sync_inodes(),bmap(),create_block(),iput(),get_empty_inode(),get_pipe_inode() ioctl.c sys_ioctl() namei.c namei(),open_namei(),sys_mkdir(),sys_rmdir(),sys_unlink(),sys_link() pipe.c read_pipe(), write_pipe(), sys_pipe() read_write.c sys_lseek(),sys_read(),sys_write() stat.c sys_stat(),sys_fstat() super.c superblock[],do_mount(),mount_root() truncate.c truncate() ttyioctl.c tty_ioctl() open.c sys_utime(),sys_access(),sys_chdir(),sys_chroot(),sys_chmod(),sys_chown(),sys_open(),sys_create(),sys_close()
include 目录
该目录中包含了内核头文件也包含了 libc 中的内联函数
文件名 功能 a.out.h 定义可执行文件方面的信息 cons.h 定义内核使用的一系列函数 ctype.h 定义标准 C 的类型 errno.h 定义系统错误代码 fcntl.h 定义文件控制的常量与函数 signal.h 定义信号量与信号量处理函数 stdarg.h 定义 var_start(),va_rounded_size(),va_end() stddef.h 定义 size_t,NULL,offsetof 3个宏 string.h 定义标准 C 的字符串处理函数 termios.h 定义 tty 使用的常量与函数 time.h 定义时间函数与常量 unistd.h 定义标准 Unix 函数与宏 utime.h 定义 utime 时间函数
init 目录
在 init 目录下只有一个文件,main.c 。main.c 实现了系统的初始化功能,代码使用 ANSI C 写的,由 boot.s 调用。 main.c 根据机器 CMOS 的值来初始化系统时钟,然后启动 tty 设备,启动系统陷阱,启动进程调度器,启动文件系统,启动硬盘中断处理程序。接下来,内核开启中断,切换到用户模式下执行,最后,调用 init() 函数,进入进程调度循环。init() 函数会调用 setuup() 函数,setup() 函数会检查硬盘分区表,并装载磁盘分区。接下来,init() 函数 fork() 另外一个进程建立一个会话,然后使用 execve() 建立一个登录 shell 进程,这个 shell 进程的 HOME 被设置为 /usr/root 。在 main 不能执行函数调用,直到 调用 fork() 为止。
main() 实现的功能
函数名 功能 time_init() 读取 CMOS 数据,初始化系统时钟 tty_init() 初始化 tty 子系统 trap_init() 初始化出错处理陷阱,如:除零 sched_init() 初始化进程调度器 buffer_init() 初始化系统块设备缓冲区 hd_init() 初始化硬盘中断处理程序 main() 后续部分 开中断 切换到用户模式 fork() 一个子进程进行 init() 进入进程调度循环
init() 函数是 main.c 中的一个静态函数,在 main() 的最后被调用,init() 函数的功能如下:
函数名 功能 setup() 读取硬盘参数表 init() 的后续部分 fork 一个子进程进行 update;为终端创建常用的 stdin 、stdout、stderr 文件句柄 显示一条信息指示缓冲区的总量和可用缓冲区的数量 fork 一个子进程执行文件 /bin/sh,执行参数为 argv[0]=”-”,HOME=/home/root,等待子进程退出,然后打印退出代码 sync(),同步 I/O 操作 _exit(0) 退出系统
kernel 目录
kernel 目录包含了内核的重要功能,如:fork()、控制台处理等等。kernel 下文件与功能列表:
文件名 文件功能 asm.s 硬件中断处理的汇编程序,如:缺页异常中断 console.c 简单虚拟终端输出函数 exit.c exit 与 waitpid 系统功能 fork.c fork 系统功能 hd.c 硬盘中断处理程序,完成硬盘 I/O keyboard.c 键盘中断处理程序 mktime.c 在核心中使用简单版本的 mktime 功能 panic.c 简单的核心 panic 功能,处理核心出错情况,一般打印出错信息 printk.c 在核心中使用 printf 功能,用于使用时保护 FS 寄存器 rs_io.c RS-232 中断处理程序 sys.c 实现一些系统调用 system_call.c 系统调用接口 traps.c 陷阱处理程序:打印进程的信息,然后结束进程 tty_io.c 串口和终端 I/O 的 tty 接口 vsprintf.c 核心版本的 vsprintf
lib 目录
lib 目录包含了系统提供的调用接口:
文件名 文件功能 _exit.c _exit(),调用系统功能 sys_exit() 的接口 close.c close(),调用系统 sys_close() 的接口 ctype.c _ctype[] 数组, 中函数使用的查询表 dup.c dup(),调用系统 sys_dup() 的接口 errno.c errno 变量 execve.c execve(),调用系统 sys_execve() 的接口 open.c open(),调用系统 sys_open() 的接口 setsid.c setsid(),调用系统 sys_setsid() 的接口 string.c l实现 声明的函数 wait.c wait() ,调用系统 sys_waitpid() 的接口 write.c write() ,调用系统interface to sys_write() 的接口
mm 目录
mm 目录中包含了系统内存管理的实现文件:
文件名 文件功能 page.s 缺页异常的处理函数 memory.c 分页存储管理功能的函数,包括:get_free_page(),free_page(),free_page_tables(),copy_page_tables(),put_page(),un_wp_page(),do_wp_page(),write_verify(),do_no_page(),calc_mem()
tools 目录
tools 目录只包含一个文件:build.c 。这个文件主要用于将链接器生成的三个独立核心组成部分拼接成一个完整的可引导的核心镜像文件。
关于 tty:
tty 是 Teletype 的缩写
终端是一种字符型设备,它有多种类型,通常使用tty来简称各种类型的终端设备。tty 是Teletype 的缩写。Teletype 是最早出现的一种终端设备,很象电传打字机(或者说就是),是由 Teletype 公司生产的。设备名放在特殊文件目录 /dev/ 下,终端特殊设备文件一般有以下几种:
1.串行端口终端(/dev/ttySn)
串行端口终端(Serial Port Terminal)是使用计算机串行端口连接的终端设备。计算机把每个串行端口都看作是一个字符设备。有段时间这些串行端口设备通常被称为终端设备,因为那时它的最大用途就是用来连接终端。这些串行端口所对应的设备名称是/dev/tts/0(或/dev/ttyS0)、/dev/tts/1(或/dev/ttyS1)等,设备号分别是(4,0)、(4,1)等,分别对应于DOS系统下的COM1、COM2等。若要向一个端口发送数据,可以在命令行上把标准输出重定向到这些特殊文件名上即可。例如,在命令行提示符下键入:echo test > /dev/ttyS1会把单词”test”发送到连接在ttyS1(COM2)端口的设备上。
当然,这不是固定的。标识设备最为重要的是主设备号和次设备号组成的二元组,然后是基于此的设备驱动程序。EP9301的这块开发板采用了/dev/ttyAM0来代替/dev/ttyS0,/dev/ttyAM1来代替/dev/ttyS1。我还没有学习开发驱动程序,下个学期要熟悉一下,以加深理解。
2.伪终端(/dev/pty/)
伪终端(Pseudo Terminal)是成对的逻辑终端设备,例如/dev/ptyp3和/dev/ttyp3(或着在设备文件系统中分别是/dev/pty/m3和/dev/pty/s3)。它们与实际物理设备并不直接相关。如果一个程序把ttyp3看作是一个串行端口设备,则它对该端口的读/写操作会反映在该逻辑终端设备对的另一个上面(ttyp3)。而ttyp3则是另一个程序用于读写操作的逻辑设备。这样,两个程序就可以通过这种逻辑设备进行互相交流,而其中一个使用ttyp3的程序则认为自己正在与一个串行端口进行通信。这很象是逻辑设备对之间的管道操作。
对于ttyp3(s3),任何设计成使用一个串行端口设备的程序都可以使用该逻辑设备。但对于使用ptyp3的程序,则需要专门设计来使用ptyp3(m3)逻辑设备。例如,如果某人在网上使用telnet程序连接到你的计算机上,则telnet程序就可能会开始连接到设备ptyp2(m2)上(一个伪终端端口上)。此时一个getty程序就应该运行在对应的ttyp2(s2)端口上。当telnet从远端获取了一个字符时,该字符就会通过m2、s2传递给getty程序,而getty程序就会通过s2、m2和telnet程序往网络上返回”login:”字符串信息。这样,登录程序与telnet程序就通过“伪终端”进行通信。通过使用适当的软件,就可以把两个甚至多个伪终端设备连接到同一个物理串行端口上。
在使用设备文件系统(device filesystem)之前,为了得到大量的伪终端设备特殊文件,HP-UX、AIX等使用了比较复杂的文件名命名方式。
关于伪终端的编程也是很复杂的一块,要掌握不是一朝一夕就能办到的。先大体了解一下就是了。
3.控制终端(/dev/tty)
如果当前进程有控制终端(Controlling Terminal)的话,那么/dev/tty就是当前进程的控制终端的设备特殊文件。可以使用命令”ps –ax”来查看进程与哪个控制终端相连。对于你登录的shell,/dev/tty就是你使用的终端,设备号是(5,0)。使用命令”tty”可以查看它具体对应哪个实际终端设备。/dev/tty有些类似于到实际所使用终端设备的一个联接。
4.控制台终端(/dev/ttyn, /dev/console)
在UNIX系统中,计算机显示器通常被称为控制台终端(Console)。它仿真了类型为Linux的一种终端(TERM=Linux),并且有一些设备特殊文件与之相关联:tty0、tty1、tty2等。当你在控制台上登录时,使用的是tty1。使用Alt+[F1—F6]组合键时,我们就可以切换到tty2、tty3等上面去。tty1 –tty6等称为虚拟终端,而tty0则是当前所使用虚拟终端的一个别名,系统所产生的信息会发送到该终端上。因此不管当前正在使用哪个虚拟终端,系统信息都会发送到控制台终端上。
可以登录到不同的虚拟终端上去,因而可以让系统同时有几个不同的会话期存在。只有系统或超级用户root可以向/dev/tty0进行写操作。
5.其它类型
还针对很多不同的字符设备存在有很多其它种类的终端设备特殊文件。例如针对ISDN设备的/dev/ttyIn终端设备等。这里不再赘述。