Study Linux Kernel Notes(v 0.11) Shawn.Xie
Shawshie@msn.com
3. Head.s
3.1 Procedure OverView
(1) 初始化ds, es, fs, gs选择子,均指向在setup.s中建立起的数据段描述符。
-----------------------------------------------------------------------------
386全局描述符详解
63 56 55 54 53 52 51 48 47 46 45 44 43 41 40 39 16 15 0
+-------------+--+--+-----+-------+--+-----+--+----+--+------------------+-----------------+
|Seg Base Addr|G |D | 0 0 |Seg Len|P | DPL |S |TYPE| A| Seg Base Addr | Segment Length |
+-------------+--+--+-----+-------+--+-----+--+----+--+------------------+-----------------+
属性字节中各字段的含义如下:
286/386共有部分:
P ------ 该字节最高位(D7),占一位。用以确定此段是否存在于物理存储器中。P=1,表示在物理存储器中;P=0,在虚拟内存
DPL ---- 该字节D6, D5位,占两位。描述符所定义的段的特权级,其值为0 --- 3
S ------ 该字节D4位,占一位。当S=1时,定义的段为代码段或数据段;S=0时,表示该描述符为系统控制描述符。
TYPE---- 该字节D3,D2 ,D1位,占三位。用于规定该段的的类型:是代码段还是数据段,及相应属性。
当D3=1时,为代码段;D3=0时,为数据段。
当D3=1时,表示该段为代码段,这时
D2=0,当CPL>=DPL时,代码段只能执行
D1=0,代码段不能读;D1=1,代码段可读
A ------- 用于判断该段是否被访问过。当A=0时,未被访问过;否则A=1。该标志用于虚拟存储操作系统中,虚拟内存的交换。该位由操行系统进行修改。
386新增部分:
51-48 -- 新增的4位段长
53-52 -- 为与将来的处理器兼容必须设置=0
D ------ D位,缺省操作数的大小(仅在代码段描述符中识别)。D=1表示32位段 ; D=0表示16位段
G ------ G位,表示粒度:G=1表示段长度为页粒度、G=0表示段长度为字节粒度
In setup.s, such as the following:
Text Segment:
.word 0x07FF ! 8Mb - limit=2047 (2048*4096=8Mb)
.word 0x0000 ! base address=0
.word 0x9A00 ! code read/exec
.word 0x00C0 ! granularity=4096, 386
G=1 : 表示段长度为页粒度
D=1 : 表示32位段
P=1 : 表示在物理存储器中
DPL=0 : 段的特权级 0
S=1 : 定义的段为代码段或数据段
TYPE=101b : D3=1时,为代码段;
D2=0,当CPL>=DPL时,代码段只能执行
D1=1,代码段可读
A=0 : 用于虚拟存储操作系统中,虚拟内存的交换,该位由操行系统进行修改
Seg Base Addr: base address=0
Segment Len : 0x7ff
Data Segment: (2048*4096=8Mb)
.word 0x07FF ! 8Mb - limit=2047 (2048*4096=8Mb)
.word 0x0000 ! base address=0
.word 0x9200 ! data read/write
.word 0x00C0 ! granularity=4096, 386
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
386选择子详解
15 3 2 1 0
+------------------+--+---+
| Index |TI|RPL|
+------------------+--+---+
其中:
RPL --------- 构成选择子特权(数0---3),表示所请求的物权层RPL。
TI --------- 表指示器,表示选择子选择的是全局描述符表或是局部描述符表。TI=0,表示选择的是全局描述符表;TI=1,表示选择局部描述符表。
索引--------- 形成描述符表的入口索引,可寻址8K个描述符。(2^13 = 8K)
_pg_dir:
startup_32:
movl $0x10,%eax
mov %ax,%ds
mov %ax,%es
mov %ax,%fs
mov %ax,%gs
Index = 2 对应于数据段描述符
TI = 0 表示选择的是全局描述符表
RPL = 0 表示所请求的物权层RPL 0
-----------------------------------------------------------------------------
(2) 初始化堆栈指针, 指向全局数组变量 long user_stack [ PAGE_SIZE>>2 ],大小为4K
(3) 建立IDT
-------------------------------------------------------------------------
中断门详解:
63 48 47 46 45 44 4341 40 39 32 31 16 15 0
+----------------+--+-----+--+----+--+------+-------------+-----------------+
| Invalid |P | DPL |S |TYPE| A| | Selector | Shift |
+----------------+--+-----+--+----+--+------+-------------+-----------------+
字节0 ------ 字节1 偏移量
字节2 ------ 字节3 2个字节共16位,目标选择子
字节4 ------ 此字段无效,可为任意值
字节5 ------ 段的属性,包含P、DPL、S、TYPE等字段
字节6 ------ 字节7 286未用,保留给386使用
IDT0~255: 0x0000 8E00 0008 &ignore_int
P=1: 表示在物理存储器中
DPL=0:描述符所定义的段的特权级 0
S=0 表示该描述符为系统控制描述符。
TYPE=111b D3=1,为代码段
D2=1,D2=0,当CPL>=DPL时,代码段只能执行。D2=1则不受限制
D1=1,代码段可读
A 用于判断该段是否被访问过
Selector 0x0008
Index = 1 对应于代码段描述符
TI = 0 表示选择的是全局描述符表
RPL = 0 表示所请求的物权层RPL 0
Shift = &ignore_int 表示跳到ignore_int执行
-------------------------------------------------------------------------
(4) 重新建立GDT,数据段和代码段扩大到16Mb
_gdt:
.quad 0x0000000000000000 /* NULL descriptor */
.quad 0x00c09a0000000fff /* 16Mb */
.quad 0x00c0920000000fff /* 16Mb */
.quad 0x0000000000000000 /* TEMPORARY - don't use */
(5) GDT重新建立之后,重新初始化各个段选择子,以及堆栈段。
(6) 验证A20是否使能,否则进入死循环。
(6.1) 验证值=0
(6.2) 验证值+1,往 0x0地址写验证值,再读出0x100000的值,看看是否等于验证值,如果不是,跳出;否则,继续。
(7) 判断协处理器是否存在,不存在的话,模拟协处理器,执行协处理器的指令。存在话直接执行
287的协处理器码0xDBE4。
-------------------------------------------------------------------------
80386中有3个32位的控制寄存器CR0、CR2、CR3,以保存全局性(不是特定的个别任务)
的机器状态(CR1 保留)。
CR0.MP ------ 监控协处理器,第1位。MP位和TS位一起使用以确定在TS=1时,WAIT操作
码是否产生协处理器无效陷阱(异常7)。即当MP=1且TS=1时,WAIT操作码产生陷阱;否则,
WAIT操作码不产生陷阱。
-------------------------------------------------------------------------
协处理器不知道怎么下发指令,先不管它了。
(8) 将0L,0L,0L,&L6,&main压栈
(9) 初始化页表机制
(9.1) 将0x0000 - 0x5000的空间清零。
(9.2) 初始化页目录表
页表目录项 * 4
页表项 * 1024
将16M的内存空间分成 4K 页
(9.3) CR3 = 0 第一个页目录
CR1.PG = 1 使能页表机制
(10) 函数返回,堆栈弹出main,执行main。
~ ~ ~ ~ ~ ~ ~ ~ ~
| |
----- +------------------+ 0x5000 _tmp_floppy_area
| | 0xfff007 |
Page | 0xffe007 |
Table | ... |
| | 0xf00007 | <----- Page Table Entry * 1024
----- +------------------+ 0x4000 pg3 <-----+
| | |
+------------------+ 0x3000 pg2 |
| | ... |
+------------------+ 0x2000 pg1 |
| | |
----- +------------------+ 0x1000 pg0 <--+ |
| | | | |
Page | pg3+7 | --------------|--+
Dir | pg2+7 | <----- Page Directory Entry
| | pg1+7 | ... |
| | pg0+7 | --------------+
----- +------------------+ _pg_dir