购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

2.1.2 获取硬件信息

在实模式下,使用BIOS中断可以获取很多硬件信息。本节将会使用BIOS中断查看硬件信息,然后将结果存储在内存的特定位置。这样一来,操作系统内核就可以直接使用这些参数,从而简化编程。获取硬件信息的具体实现如代码清单2-4所示。

代码清单2-4 获取硬件信息

1 _start_setup:

2    ...

3    movw $INITSEG,%ax

4    movw %ax,%ds

5    movb $0x03,%ah

6    xor%bh,%bh

7    int $0x10

8    movw %dx,(0)

9    movb $0x88,%ah

10   int $0x15

11   movw %ax,(2)

12

13   movb $0x0f,%ah

14   int $0x10

15   movw %bx,(4)

16   movw %ax,(6)

17   movb $0x12,%ah

18   movb $0x10,%bl

19   int $0x10

20   movw %ax,(8)

21   movw %bx,(10)

22   movw %cx,(12)

23

24   movw $0x0000,%ax

25   movw %ax,%ds

26   ldsw(4 *0x41),%si

27   movw $INITSEG,%ax

28   movw %ax,%es

29   movw $0x0080,%di

30   movw $0x10,%cx

31   rep

32   movsb

33

34   /* 获取hd1数据 */

35   movw $0x0000,%ax

36   movw %ax,%ds

37   ldsw(4 *0x46),%si

38   movw $INITSEG,%ax

39   movw %ax,%es

40   movw $0x0090,%di

41   movw $0x10,%cx

42   rep

43   movsb

44

45   movw $0x1500,%ax

46   movb $0x81,%dl

47   int $0x13

48   jcno_disk1

49   cmpb$3,%ah

50   jeis_disk1

51 no_disk1:

52   movw $INITSEG,%ax

53   movw %ax,%es

54   movw $0x0090,%di

55   movw $0x10,%cx

56   movw $0x00,%ax

57   rep

58   stosb

59 is_disk1:

60   ...

上述代码首先将INITSEG(0x9000)保存在ds寄存器中,然后通过0x10号中断获取了光标信息,其输入功能号是0x03(第5~7行)。光标位置结果作为中断的输出,会被存放在dx寄存器中。第8行代码将dx寄存器中的值放到内存里,其内存地址以ds为段基址,位置的偏移为0,也就是0x9000<<4+0,或者直接写成0x90000。

这个位置存放着bootsect的代码,但是当CPU执行到setup的时候,bootsect就肯定不会再被执行了,所以这部分内存是可以被复用的。操作系统选择将硬件参数保存在这里。

第9~10行,利用中断号0x15的子功能号0x88来获取扩展内存的大小,获取内存大小的结果会保存在ax寄存器中,然后第11行将扩展内存保存在0x90002处。注意,这条指令是利用了段寻址方式,这与第8行的写法是一致的,所以扩展内存的大小就保存在0x90002处。

1.获取显卡相关信息

接下来就是获取显卡的显示模式相关信息,依然参见代码清单2-4。

第14行使用了中断号0x10,这也是一个和显示器相关的中断。ah寄存器赋值为0x0f,对应的子功能号为获取显示器的显示模式,将返回结果放入ax和bx两个寄存器中。其中ah(ax的高8位),存放屏幕字符的列数,al(ax的低8位)存放显示器的显示模式,bh(bx的高8位)存放显示器页数。第15和16行分别把获取到的显示模式信息放到0x90004和0x90006的位置。

在获取显示器的显示模式信息之后,紧接着还要获取显示器的其他信息。第19行,再次调用BIOS 0x10号中断,这仍然是与显示器相关的中断,第17行中的ah表示中断的功能号为0x12,第18行的bl表示中断子功能号为0x10。这个中断的作用是获取显卡的相关信息,返回结果分别存入ax、bx、cx三个寄存器中。

其中,ax作为返回寄存器的作用已经被废弃。bh存放视频状态,0x00h表示彩色模式,0x01h表示单色模式。bl存放已经安装的显存大小(00h=64KB,01h=128KB,02h=192KB,03h=256KB)。ch存放特性连接器位信息。cl存放的是显卡的一些开关设置。在之后的20~22行,将返回结果存入内存0x90008~0x90012的位置。

内核在初始化控制台的时候就会使用这些信息,这里先不详细解释这些数据的意义,等到实现控制台打印功能时再来仔细研究。更多有关显示卡编程的知识可以查看附录。

2.获取磁盘相关信息

显卡的基本信息获取之后,接下来就是获取硬盘相关的信息。

与磁盘和内存不同,磁盘的信息是在BIOS引导阶段就被保存在了内存里,其中第一块硬盘的参数被存放在4 *0x41的位置,如果系统中还有第二块硬盘,那它的参数就被存放在4 *0x46的位置。

这两个位置本来是BIOS存放中断向量的地方,所以你有时会读到某些材料上说硬盘参数存储在0x41号中断处。这种说法是不准确的,因为BIOS占用了这一段内存,它已经不再是中断向量了。

第24和25行的作用是将ds寄存器初始化为0x0。也就是数据段基址此时被设置成了0。然后第26行使用ldsw指令将地址送入si寄存器,“(4 *0x41)”和前面提到的“0”是一样的,它的地址就是4 *0x41,所以这条指令最终的作用就是把值4 *0x41送入si寄存器。你也可以使用mov指令达成同样的效果,但ldsw指令更加清楚地指明了si寄存器里存放的是一个地址。

接下来,将es寄存器赋值为0x9000,即setup.S开头定义的INITSEG。之后将目的寄存器di赋值为0x80,并将计数寄存器cx赋值为0x10,然后开始进行复制操作。通过rep和movsb两条指令完成从(0x0000:0x41 *4)到(0x9000:0x80)的复制工作,重复16次,完成16个字节的复制工作。

紧接着继续复制第二块硬盘hd1的参数,hd1的参数位于4 *0x46处,它和前面复制hd0参数的代码几乎完全一样,差别仅仅是源地址和目标地址有所不同(第34~43行)。

一台机器可能有多块硬盘,所以接下来还要再通过中断来进行判断。第47行中断类型是0x13,表示磁盘相关的服务,第45行将0x1500赋值给ax,实际上是将功能号0x15赋值给ah(ax的高8位)。第46行dl表示的是驱动器编号,0x80表示第一块硬盘,0x81表示第二块硬盘。中断的返回值存放在ah寄存器中,当ah寄存器的值为0时,代表没有目标驱动器,同时CF会被置位。值为1或者2时代表软盘,值为3时代表硬盘。所以第49行进一步判断:如果ah=3,则表示存在第二块硬盘。

如果没有第二块硬盘,则会执行no_disk1这个lable的代码。首先还是将es寄存器初始化为INITSEG,然后将di寄存器赋值为0x90,这个目标地址是前面初始化hd1时的目标地址。寄存器ax的值是0,所以no_disk1的这段代码的作用就是将硬盘参数表的第二个表清零。

至此,在实模式下的工作就全部完成了,我们可以向保护模式“进发”了。 yYNdAB21zNtwe48uMU3pLVL0j3yjYw5g6qvc+X0ViWgRMH/1A7716coV1sJgPU7V

点击中间区域
呼出菜单
上一章
目录
下一章
×