1. 初始化硬件信息存放空间
- 先说在前,setup在0x90200位置
- 代码: - start:
- mov ax,#0x9000 ; this is done in bootsect already, but...
- mov ds,ax
- mov ah,#0x03 ; read cursor pos
- xor bh,bh
- int 0x10 ; save it in known place, con_init fetches
- mov [0],dx ; it from 0x90000.
 
- 一开始setup就将ax寄存器放入0x9000地址,这里是之前bootsetc复制过来的位置,此时bootsetc没用了,这块空间将用于存放硬件信息 - 2. 读取硬件信息
- 通过中断操作读取硬件信息,int命令就是中断,中断会读取ah寄存器的数据,数据映射了所有中断操作,0x03就是读取光标的操作 
- 通过诸如此类的方法,读取其他硬件信息: - 获取内存信息。
- ; Get memory size (extended mem, kB)
- mov ah,#0x88
- int 0x15
- mov [2],ax
- 获取显卡显示模式。
- ; Get video-card data:
- mov ah,#0x0f
- int 0x10
- mov [4],bx ; bh = display page
- mov [6],ax ; al = video mode, ah = window width
- 检查显示方式并取参数
- ; check for EGA/VGA and some config parameters
- mov ah,#0x12
- mov bl,#0x10
- int 0x10
- mov [8],ax
- mov [10],bx
- mov [12],cx
- 获取第一块硬盘的信息。
- ; Get hd0 data
- mov ax,#0x0000
- mov ds,ax
- lds si,[4*0x41]
- mov ax,#INITSEG
- mov es,ax
- mov di,#0x0080
- mov cx,#0x10
- rep
- movsb
- 获取第二块硬盘的信息。
- ; Get hd1 data
- mov ax,#0x0000
- mov ds,ax
- lds si,[4*0x46]
- mov ax,#INITSEG
- mov es,ax
- mov di,#0x0090
- mov cx,#0x10
- rep
- movsb
 
- 最终读取结果如下: | 内存地址 | 长度(字节) | 名称 | | —- | —- | —- | | 0x90000 | 2 | 光标位置 | | 0x90002 | 2 - | 扩展内存数 | | 0x90004 | 2 | 显示页面 | | 0x90006 | 1 - | 显示模式 | | 0x90007 | 1 | 字符列数 | | 0x90008 | 2 | 未知 | | 0x9000A | 1 - | 显示内存 | | 0x9000B | 1 - | 显示状态 | | 0x9000C | 2 | 显卡特性参数 | | 0x9000E | 1 - | 屏幕行数 | | 0x9000F | 1 | 屏幕列数 | | 0x90080 | 16 - | 硬盘1参数表 | | 0x90090 | 16 | 硬盘2参数表 | | 0x901FC | 2 - | 根设备号 | 
3. 关闭中断
cli ; no interrupts allowed 表示关闭中断;
- 因为后面我们要把原本是 BIOS 写好的中断向量表给覆盖掉,也就是给破坏掉了,写上我们自己的中断向量表,所以这个时候是不允许中断进来的。
4. 整理内存,完成实模式
- 将system的那块内存复制彻底覆盖掉boots(此时boots还有块BIOS存放的位置)

- 现在只setup和system了
5. 实模式和保护模式物理地址转换
- 实模式是16位的,因为一开始CPU是16位的,现在都是32位或64位CPU了,保护模式就是32位或64位了 - 实模式地址转换
- 先说在前,目前还没进入分页模式,所有地址都是基于段的 
- 之前说过,实模式地址就是段基址(ds寄存器存的地址就是段基址)左移后加上偏移量,很简单
保护模式地址转换

- ds不再直接存段基址,而是段描述符
- 从段描述符表中,ds指向的位置去除段基址
- 段描述符表(gdt)位置,在setup中有一个标签,setup的起始地址(即0x90200) + gdt标签就是gdt的地址
- 
6. 进入保护模式
- setup初始化gdt,把地址存入寄存器,就是开启保护模式第一步 
- 与gdt相同原理,还有个idt,即中断表,是Linux自己定义的中断信号的变量值
- 此时内存是这样:

- 打开A20地址线用于兼容20位地址(传统操作)
- 对可编程中断控制器 8259 芯片进行编程,设置0x00 ~ 0x19的20个保留中断信号(必须设置,兼容传统)中断号是不能冲突的, Intel 把 0 到 0x19 号中断都作为保留中断,比如 0 号中断就规定为除零异常,软件自定义的中断都应该放在这之后,但是 IBM 在原 PC 机中搞砸了,跟保留中断号发生了冲突,以后也没有纠正过来,所以我们得重新对其进行编程,不得不做,却又一点意思也没有。这是 Linus 在上面注释上的原话。 
| PIC 请求号 | 中断号 | 用途 | 
|---|---|---|
| IRQ0 | 0x20 | 时钟中断 | 
| IRQ1 | 0x21 | 键盘中断 | 
| IRQ2 | 0x22 | 接连从芯片 | 
| IRQ3 | 0x23 | 串口2 | 
| IRQ4 | 0x24 | 串口1 | 
| IRQ5 | 0x25 | 并口2 | 
| IRQ6 | 0x26 | 软盘驱动器 | 
| IRQ7 | 0x27 | 并口1 | 
| IRQ8 | 0x28 | 实时钟中断 | 
| IRQ9 | 0x29 | 保留 | 
| IRQ10 | 0x2a | 保留 | 
| IRQ11 | 0x2b | 保留 | 
| IRQ12 | 0x2c | 鼠标中断 | 
| IRQ13 | 0x2d | 数学协处理器 | 
| IRQ14 | 0x2e | 硬盘中断 | 
| IRQ15 | 0x2f | 保留 | 
- 设置cr0寄存器第0位(PE位)的值置1,就代表正式进入了保护模式
7. setup的最后
jmpi命令跳转,根据gdt的定义找到第一项,值是0即跳转到内存0位置,也就是system代码的起始地址
由此,setup结束了,开始了head.s
 
 
 
                         
                                

