setup.asm 模块文档说明

------------------------------------------------------------------------

      setup.asm 模块文档说明
      By 姜江 <Jiang Jiang>
     E-mail:jznsmail@tom.com
   http://blog.csdn.net/jznsmail

1.模块介绍
==========
    该模块是被boot.asm代码加载到内存0x90200位置的一共24个扇区,该段代码完
成设备信息的采集,建立全局描述符表,开启A20门,并且设置好相应的寄存器然后跳
转到保护模式下执行.

2.模块功能
==========
    1.获取启动设备号码,boot.asm代码将设备号码存储在0x90A00位置
    2.获取当前光标位置
    3.获取扩展内存大小
    4.检查显卡数据
    5.检查EGA/VGA参数
    6.获取硬盘参数表
    7.将系统模块从0x10000位置移动到0x00000位置,这将覆盖BIOS中断向量,意味
      着我们将不能再使用BIOS中断了.
    8.开启A20门
    9.设置CR0寄存器,并且跳转到保护模式下运行

3.相关概念
==========
  1>什么是硬盘参数表
        在PC机中BIOS设定的中断向量表中int 0x41的中断向量位置(4*0x41 =
    0x0000:0x0104)存放的并不是中断程序的地址,而是第一个硬盘的基本参数表
    对于100%兼容的BIOS来说,这里存放着硬盘参数表阵列的首地址0xF000:0E401
    第二个硬盘的基本参数表入口地址存于int 0x46中断向量位置处.每个硬盘参
    数表有16个字节大小.
  2>什么是A20门
        在8086/8088中,只有20根地址总线,所以可以访问的地址是2^20=1M,但由
    于8086/8088是16位地址模式,能够表示的地址范围是0-64K,所以为了在8086/
    8088下能够访问1M内存,Intel采取了分段的模式:16位段基地址:16位偏移.
    其绝对地址计算方法为:16位基地址左移4位+16位偏移=20位地址.
        但这种方式引起了新的问题,通过上述分段模式,能够表示的最大内存为:
    FFFFh:FFFFh=FFFF0h+FFFFh=10FFEFh=1M+64K-16Bytes(1M多余出来的部分被
    称做高端内存区HMA).但8086/8088只有20位地址线,如果访问100000h-
    10FFEFh之间的内存,则必须有第21根地址线.所以当程序员给出超过1M
    (100000H-10FFEFH)的地址时,系统并不认为其访问越界而产生异常,而是自动
    从重新0开始计算,也就是说系统计算实际地址的时候是按照对1M求模的方式
    进行的,这种技术被称为wrap-around.
        到了80286,系统的地址总线发展为24根,这样能够访问的内存可以达到
    2^24=16M.Intel在设计80286时提出的目标是,在实模式下系统所表现的行为
    应该和8086/8088所表现的完全一样,也就是说,在实模式下80286以及后续系
    列,应该和8086/8088完全兼容.但最终,80286芯片却存在一个BUG:如果程序员
    访问100000H-10FFEFH之间的内存,系统将实际访问这块内存,而不是象过去一
    样重新从0开始.
        为了解决上述问题,IBM使用键盘控制器上剩余的一些输出线来管理第21
    根地址线(从0开始数是第20根),被称为A20 Gate.如果A20 Gate被打开,则当
    程序员给出100000H-10FFEFH之间的地址的时候,系统将真正访问这块内存区
    域;如果A20 Gate被禁止,则当程序员给出100000H-10FFEFH之间的地址的时候,
    系统仍然使用8086/8088的方式.绝大多数IBM PC兼容机默认的A20 Gate是被
    禁止的.由于在当时没有更好的方法来解决这个问题,所以IBM使用了键盘控制
    器来操作A20 Gate.在80286以及更高系列的PC中,即使A20 Gate被打开,在实
    模式下所能够访问的内存最大也只能为10FFEFH,尽管它们的地址总线所能够
    访问的能力都大大超过这个限制.为了能够访问10FFEFH以上的内存,则必须进
    入保护模式.
        A20,其实它就是对于20-bit(从0开始数)的特殊处理(也就是对第21根地
    址线的处理).如果A20 Gate被禁止,对于80286来说其地址为24bit,其地址表
    示为EFFFFF;对于80386极其随后的32-bit芯片来说,其地址表示为FFEFFFFF.
    这种表示的意思是如果A20 Gate被禁止,则其第20-bit在CPU做地址访问的时
    候是无效的,永远只能被作为0;如果A20 Gate被打开,则其第20-bit是有效的,
    其值既可以是0,又可以是1.
        所以,在保护模式下,如果A20 Gate被禁止,则可以访问的内存只能是奇数
    1M段,即1M,3M,5M…,也就是00000-FFFFF,200000-2FFFFF,300000-3FFFFF….
    如果A20 Gate被打开,则可以访问的内存则是连续的.
  3>如何开启A20地址线
        多数PC都使用键盘控制器(8042芯片)来处理A20 Gate.从理论上讲,打开
    A20 Gate的方法是通过设置8042芯片输出端口(64h)的2nd-bit,但事实上,当
    你向8042芯片输出端口进行写操作的时候,在键盘缓冲区中,或许还有别的数
    据尚未处理,因此你必须首先处理这些数据.
    处理过程如下:
        1. 禁止中断;
 2. 等待,直到8042 Input buffer为空为止;
 3. 发送禁止键盘操作命令到8042 Input buffer;
 4. 等待,直到8042 Input buffer为空为止;
 5. 发送读取8042 Output Port命令;
 6. 等待,直到8042 Output buffer有数据为止;
 7. 读取8042 Output buffer,并保存得到的字节;
 8. 等待,直到8042 Input buffer为空为止;
 9. 发送Write 8042 Output Port命令到8042 Input buffer;
 10. 等待,直到8042 Input buffer为空为止;
 11. 将从8042 Output Port得到的字节的第2位置1(OR 2),然后写入8042
            Input buffer;
 12. 等待,直到8042 Input buffer为空为止;
 13. 发送允许键盘操作命令到8042 Input buffer;
 14. 打开中断。
  4>如何检测A20地址线是否开启
        我们在之前已经提到,如果A20 Gate被打开了,则在实模式下,程序员可以
    直接访问100000H~10FFEFH之间的内存,如果A20 Gate被禁止,则在实模式下,
    若程序员访问100000H~10FFEFH之间的内存,则会被硬件自动转换为0H~0FFEFH
    之间的内存,所以我们可以利用这个差异来检测A20 Gate是否被打开.
  5>CR0寄存器
        CR0寄存器是处理器4个控制寄存器之一,结构如下
    +----+--------------------------+----+----+----+----+----+
    | PG |         Reserved         | ET | TS | EM | MP | PE |
    +----+--------------------------+----+----+----+----+----+
    31   30                         5    4    3    2    1    0
     BIT 0:PE 如果该位被置位,则运行保护模式,否则运行实模式
 BIT 1:MP 控制wait指令
 BIT 2:EM 表示协处理器功能是否可以被仿真
 BIT 3:TS 用于任务转换
 BIT 4:ET 表示当前协处理器的类型(80287或80387)
 BIT 31:PG表示处理器是否使用分页机制
  6>描述符表
        在保护模式下内存的寻址方式跟实模式下不同,它并不是简单的将段寄存
    器的16位地址左移4位,然后加上偏移量来构成20位地址.在保护模式下,是可
    以寻址4GB空间的,因为有32跟地址线,所以2^32 = 4GB.在该模式下是通过段
    寄存器的索引值在描述符表(全局描述符表GDT或者局部描述符表LDT)内寻找
    到相应的表项,然后通过获取表项里保存的段基地址,段基地址与偏移量相加
    得到线性地址.如果系统没采用分页处理模式,那么线性地址就对应着实际的
    物理地址了.分页处理模式放到内存管理文档里详细说明.
        段寄存器格式:
    +--------------------------------+------+-----+
    |           Index            |  TI | RPL |
    +--------------------------------+------+-----+
   15                           32     1     0
    RPL: 优先级别 0 - 4 LINUX只用了0核心态 3用户态
    TI:  0使用全局描述符表(GDT),1使用局部描述符表(LDT)

        描述符表是保存在gdtr或者ldtr寄存器里的,该寄存器共占用6个字节大
    小.0-15位是表限,16-47位是表的基地址.表限是表示该表的大小,基地址是表
    示描述符表所在的线性地址中的位置.
    全局描述符号表和局部描述符号表的结构是一样的,如下:
    +---------------------------------+----------+
    |            Base address         |   Limit  |
    +---------------------------------+----------+
    47                               1615        0
        描述符表项是存储在描述符表里的内容.Intel公司将表项的第一个项设
    为空,从第2个表项开始使用.描述符表项的结构定义如下:
63     5655 5251    4847  4039    3231         1615      87     0
+---------+----+-------+-----+---------+-------------+-----------------+
|B31 - B24|   |L19-L16|    |B23 - B16|基地址 B15-B0|段上限L15 - L0|
+---------+----+-------+-----+---------+-------------+-----------------+

+------+------+------+------+
|   G  |  D/B |   O  |  AV  |
+------+------+------+------+
55                         52
G:   =1 段长以4K字节为单位 =0 段长以字节为单位
D/B: =1 表示对该段访问为32位指令 =0 表示为16位指令
O:   永远为0
AV:  可由软件使用,CPU忽略该位

+-----+----------+-----+-----+-------+-------+------+
|  P  |    DPL   |  S  |  E  | ED/C  |  R/W  |   A  |
+-----+----------+-----+-----+-------+-------+------+
47                   44   43                         40
A: =1 已经被访问过 =0 还未被访问过
R/W:  ---+        
ED/C: ---|----+---> +---- E = 0 数据段
E:    ---+    |     |
              |     +---- ED = 0 向上伸(数据段) ED = 1 向下伸(堆栈段)
              |     |
              |     +---- W = 0不可写 W = 1 可写
              |
              +---> +---- E = 1代码段
                    |
                    +---- C = 0 忽略特权级 C = 不忽略特权级
                    |
                    +---- R = 0 不能读 R = 1可读
S = 0表示用于系统管理的系统段 = 1表示一般的代码段或者数据段
DPL: 特权级
P = 1该段在内存中  = 0 不在内存中

4.模块内存映象
==============
0x90090 - 0x9009F HD2硬盘参数表
0x90080 - 0x9008F HD1硬盘参数表
0x9000C 显卡特性参数
0x9000A 显卡内存和显示状态
0x90008 ???
0x90006 显示模式和字符列数
0x90004 显示页面号
0x90002 扩展内存大小
0x90000 光标位置

+--------------+
|              |
|     ....     |
|              |
+--------------+ 0x909FF
|              |
|     setup    |
|              |
|              |
+--------------+ 0x90200
|     ...      |
+--------------+ 0x900A0
|   系统参数   |
+--------------+ 0x90000
|              |
|     ...      |
|              |
+--------------+ 0x13000
|              |
|  bak system  |
|              |
+--------------+ 0x10000
|              |
|     ...      |
|              |
+--------------+ 0x07E00
|     boot     |
+--------------+ 0x07C00
|     ...      |
+--------------+ 0x03000
|              |
|     system   |
|              |
+--------------+ 0x00000

5.模块使用的中断调用
====================
中断号: INT 0x10
        AH = 0x03 读光标功能号
功能: 获取当前光标位置
输入: bh = 页号
返回: ch = 扫描开始线      cl = 扫描结束线
      dh = 行号(0x00是顶端) dl = 列号(0x00是左边)
-----------------------------------------------------------------------
中断号: INT 0x15
        ah = 0x88
功能: 获取扩展内存大小(KB)
返回: ax = 从0x100000(1MB)处开始的扩展内存大小(KB)
错误: FC置位, ax = 出错码
-----------------------------------------------------------------------
中断号: INT 0x10
 ah = 0x0f
功能: 获取显卡当前显示模式
返回: ah = 字符列数 al = 显示模式
      bh = 当前显示页
-----------------------------------------------------------------------
中断号: INT 0x10
 ah = 0x12 bl = 0x10
功能: 检查显示方式(EGA/VGA)
返回: bh = 显示状态
  0x00 - 彩色模式,I/O端口 = 0x3dX
  0x01 - 单色模式,I/O端口 = 0x3bX
      bl = 安装的显示内存
  0x00 - 64k 0x01 - 128k
  0x02 - 192k 0x03 - 256k
-----------------------------------------------------------------------
中断号: INT 0x15
 ah = 0x15
功能: 检查系统是否存在第2个硬盘
输入: dl = 驱动器号(0x8X是硬盘:0x80第一个硬盘,0x81第二个硬盘)
输出: ah = 类型码(00 - 没有这个盘,CF = 1;01 - 软驱,没有change-line支持;
           02 - 软驱(或其他可移动设备),有change-line支持, 03 - 硬盘)
-----------------------------------------------------------------------
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值