免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1366 | 回复: 0
打印 上一主题 下一主题

LINUX内核 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2004-12-09 16:28 |只看该作者 |倒序浏览
一,系统初启

  首先很惭愧的坦白大部分是抄袭他人(XIAOMAN)的因为系统的初起一直是一个麻烦而头疼的问题,不同的体系结构会有较大的不同。X86从硬件启动,读入引导扇区,执行引导程序从实模式开始再转换到保护模式这个复杂的过程其实与操作系统本身的运行机制关系并不大,但忽略过去又无法给LINUX内核一个完整的 过程,所以我大动剪刀浆糊,但会把精力主要集中在LINUX内核本身,希望得到大家的谅解。
(以核心2.0.36为主)
1,系统引导:
 涉及的文件
 ./arch/$ARCH/boot/bootsect.s
 ./arch/$ARCH/boot/setup.s
1) bootsect.S
  这个程序是linux kernel的第一个程序,包括了linux自己的bootstrap程序,但是在说明这个程序前,必须先说明一般IBM PC开机时的动作(此处的开机是指"打开PC的电源":
  一般PC在电源一开时,是由内存中地址FFFF:0000开始执行(这个地址一定在ROM BIOS中,ROM BIOS一般是在FEOOOh到FFFFFh中),而此处的内容则是一个jump指令,jump到另一个位於ROM BIOS中的位置,开始执行一系列的动作,包括了检查RAM,keyboard,显示器,软硬磁盘等等,这些动作是由系统测试代码 (system test code)来执行的,随着制作BIOS厂商的不同而会有些许差异,但都是大同小异,读者可自行观察自家机器开机时,萤幕上所显示的检查讯息。
  紧接着系统测试码之后,控制权会转移给ROM中的启动程序(ROM bootstrap routine),这个程序会将磁盘上的第零轨第零扇区读入内存中(这就是一般所谓的boot sector,如果你曾接触过电脑病毒,就大概听过它的大名),至於被读到内存的哪里呢? --绝对位置07C0:0000(即07C00h处),这是IBM系列PC的特性。而位在linux开机磁盘的boot sector上的正是linux的bootsect程序,也就是说,bootsect是第一个被读入内存中并执行的程序。现在,我们可以开始来看看到底bootsect做了什么。
    第一步
  首先,bootsect将它"自己"从被ROM BIOS载入的绝对地址0x7C00处搬到0x90000处,然后利用一个jmpi(jump indirectly)的指令,跳到新位置的jmpi的下一行去执行,
    第二步
  接着,将其他segment registers包括DS,ES,SS都指向0x9000这个位置,与CS看齐。另外将SP及DX指向一任意位移地址( offset ),这个地址等一下会用来存放磁盘参数表(disk para- meter table )   

  第三步
  接着利用BIOS中断服务int 13h的第0号功能,重置磁盘控制器,使得刚才的设定发挥功能。                                
  第四步
  完成重置磁盘控制器之后,bootsect就从磁盘上读入紧邻着bootsect的setup程序,也就是setup.S,此读入动作是利用BIOS中断服务int 13h的第2号功能。setup的image将会读入至程序所指定的内存绝对地址0x90200处,也就是在内存中紧邻着bootsect 所在的位置。待setup的image读入内存后,利用BIOS中断服务int 13h的第8号功能读取目前磁盘的参数。
    第五步
  再来,就要读入真正linux的kernel了,也就是你可以在linux的根目录下看到的"vmlinuz" 。在读入前,将会先呼叫BIOS中断服务int 10h 的第3号功能,读取游标位置,之后再呼叫BIOS 中断服务int 10h的第13h号功能,在萤幕上输出字串"Loading",这个字串在boot linux时都会首先被看到,相信大家应该觉得很眼熟吧。
  第六步
  接下来做的事是检查root device,之后就仿照一开始的方法,利用indirect jump 跳至刚刚已读入的setup部份
    第七步
        setup.S完成在实模式下版本检查,并将硬盘,鼠标,内存参数写入到 INITSEG 中,并负责进入保护模式。
    第八步
  是我们详细讨论的开始,即操作系统的初始化。
一点补充:
我们主要讨论的文件是 arch/i386/kernel/head.S
  首先我们要保证这个程序的的确确是内核的开始,因为setup.S最后的 为一条转跳指令,跳到内核第一条指令并开始执行。指令中指向的是 内存中的绝对地址,我们无法依此判断转跳到了head.S。 但是我们可以通过Makefile简单的确定head.S位于内核的前端。 在arch/i386 的 Makefile 中定义了
HEAD := arch/i386/kernel/head.o
   而在linux总的Makefile中由这样的语句
include arch/$(ARCH)/Makefile
说明HEAD定义在该文件中有效
然后由如下语句:
vmlinux: $(CONFIGURATION) init/main.o init/version.o linuxsubdirs
$(LD) $(LINKFLAGS) $(HEAD) init/main.o init/version.o \
$(ARCHIVES) \
$(FILESYSTEMS) \
$(DRIVERS) \
$(LIBS) -o vmlinux
$(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( a \)' | sort >; System.map
从这个依赖关系我们可以获得大量的信息
1>;$(HEAD)即head.o的确第一个被连接到核心中
2>;所有内核中支持的文件系统全部编译到$(FILESYSTEMS)即fs/filesystems.a中
所有内核中支持的网络协议全部编译到net.a中
所有内核中支持的SCSI驱动全部编译到scsi.a中
原来内核也不过是一堆库文件和目标文件的集合罢了,有兴趣对内核减肥的同仁,
可以好好比较一下看究竟是那个部分占用了空间。
3>;System.map中包含了所有的内核输出的函数,我们在编写内核模块的时候
可以调用的系统函数大概就这些了。
好了,消除了心中的疑问,我们可以仔细分析head.s了。


内核开始的地方(二)

Head.S分析

1, 首先将ds,es,fs,gs指向系统数据段KERNEL_DS
    KERNEL_DS 在asm/segment.h中定义,表示全局描述符表中中的第三项。注意:该此时生效的全局描述符表并不是在head.s中定义的而仍然是在setup.S中定义的。
2 数据段全部清空。
3 setup_idt为一段子程序,将中断向量表全部指向ignore_int函数 ,该函数打印出:unknown interrupt 当然这样的中断处理函数什么也干不了。
4 察看数据线A20是否有效,否则循环等待。地址线A20是x86的历史遗留问题,决定是否能访问1M以上内存。
5 拷贝启动参数到0x5000页的前半页,而将setup.s取出的bios参数放到后半页。
6 检查CPU类型
7 初始化页表,只初始化最初几页。
1>;将swapper_pg_dir(0x2000)和pg0(0x3000)清空swapper_pg_dir作为整个系统的页目录
2>;将pg0作为第一个页表,将其地址赋到swapper_pg_dir的第一个32 位字中。
3>;同时将该页表项也赋给swapper_pg_dir的第3072个入口,表示虚拟地址0xc0000000也指向pg0。
4>;将pg0这个页表填满指向内存前4M
5>;进入分页方式
注意:以前虽然在在保护模式但没有启用分页。

--------------------
| swapper_pg_dir | -----------
| |-------| pg0 |----------内存前4M
| | -----------
| |
--------------------
8 装入新的gdt和ldt表。
9 刷新段寄存器ds,es,fs,gs
10 使用系统堆栈,即预留的0x6000页面
11 执行start_kernel函数,这个函数是第一个C编制的函数,内核又有了一个新的开始。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP