前面两篇文章已经分别讲了OS的实验环境配置及x86汇编的指令,本文则着重于讲解操作系统的初始化。
8086可以访问1MB的内存空间,地址从0x00000
到0xFFFFF
,顶端一部分用于访问ROM和外围板卡,其他大部分则用来访问内存DRAM。
因为8086加电或者复位时,CS=0xFFFF
,IP=0x0000
,所以,它取的第一条指令位于物理地址0xFFFF0
(也即FFFF:0000
),正好位于 ROM中,那里固化了开机时需要执行的指令。
这块ROM芯片中的内容包括很多部分,主要是进行硬件的诊断、检测和初始化。 所谓初始化,就是让硬件处于一个正常的、默认的工作状态。 最后,它还负责提供一套软件例程,让人们在不必了解硬件细节的情况下从外围设备(比如键盘)获取输入数据,或者向外围设备(比如显示器)输出数据。 设备当然是很多的,所以这块 ROM 芯片只针对那些最基本的、对于使用计算机而言最重要的设备,而它所提供的软件例程,也只包含最基本、最常规的功能。 正因为如此,这块芯片又叫基本输入输出系统(Base Input & Output System, BIOS) ROM
ROM-BIOS的容量是有限的,当它完成自己的使命后,最后所要做的,就是从辅助存储设备读取指令数据,然后转到那里开始执行。 绝大多数时候,对于 ROM-BIOS 来说,硬盘都是首选的外存储设备。 硬盘的第一个扇区是0面0道1扇区,或者说是0头0柱1扇区(512B),这个扇区称为主引导扇区bootsector。
整个加载操作系统的过程如下
0x55aa
才为有效的引导盘
(注意这里在汇编程序中体现为org 7c00h
。非常重要!否则无法正确读取代码段/数据段!)0000:7C00
的地方(也就是物理地址 0x07C00,自举bootstrap),BIOS跳转到7C00
继续执行注:C中直接访问绝对地址
int *var = (int*)0x40001000;
*var = 4;
显存,即显示存储器(Video RAM, VRAM)。 要显示的内容都需要先写入显存,显存同样是按字节访问的存储期间。
两种基本工作模式
由于历史的原因,所有在个人计算机上使用的显卡,在加电自检之后都会把自己初始化到80*25 的文本模式。在这种模式下,屏幕上可以显示25行,每行80个字符,每屏总共2000个字符。
所以,0xB8000-0xBFFFF
这段物理地址空间,是留给显卡的,由显卡来提供,用来显示文本。
除非显卡出了毛病,否则这段空间总是可以访问的。
如果显卡出了毛病,计算机一定不会通过加电自检过程,这就是传说中的严重错误,计算机是无法启动的,更不要说加载并执行主引导扇区的内容了。
因此要访问显存,段寄存器要先指向0xB800
,然后设置好偏移量,将对应的字符和显示属性放入该内存地址中。
屏幕上的每个字符都对应着显存中连续两个字节,前一字节是字符的ASCII码,后一字节是字符的显示属性。
字符的显示属性分为两部分,低4位定义的是前景色,高4位定义的是背景色。K=0时不闪烁,K=1时闪烁。
R | G | B | 背景色 | 前景色(I=0) | 前景色(I=1) |
---|---|---|---|---|---|
0 | 0 | 0 | 黑 | 黑 | 灰 |
0 | 0 | 1 | 蓝 | 蓝 | 浅蓝 |
0 | 1 | 0 | 绿 | 绿 | 浅绿 |
0 | 1 | 1 | 青 | 青 | 浅青 |
1 | 0 | 0 | 红 | 红 | 浅红 |
1 | 0 | 1 | 品红 | 品红 | 浅品红 |
1 | 1 | 0 | 棕 | 棕 | 黄 |
1 | 1 | 1 | 白 | 白 | 亮白 |
即连续两个字节为(ASCII)(KRGB)(IRGB),如0000 0000 0000 0101
代表黑底(背景)品红字(前景)ASCII码为0x00
的字符。
通常一个扇区尺寸是512B,可以看成是一个数据块(block)。 1440KB=1474560B,1B=8b等同于两个hex位。 1.44M的软盘一共包含2880个扇区。
采用磁头、磁道和扇区这种模式来访问硬盘的方法称为CHS模式,但不是很方便。 后来引入了逻辑块地址(Logical Block Address, LBA)的概念。 现在市场上销售的硬盘,无论是哪个厂家生产的,都支持LBA模式。
LBA模式是由硬盘控制器在硬件一级上提供支持,所以效率很高,兼容性很好。 LBA模式不考虑扇区的物理位置(磁头号、磁道号),而是把它们全部组织起来统一编号。 在这种编址方式下,原先的物理扇区被组织成逻辑扇区,且都有唯一的逻辑扇区号。
软盘有2个磁头(head)/面(side),有80个柱面(cylinder),每一个道(track)18个扇区(sector)。 柱面和磁头从0开始计数,扇区从1开始计数。
#define FLOPPY_144_SECTORS_PER_TRACK 18
void lba_2_chs(uint32_t lba, uint16_t* cyl, uint16_t* head, uint16_t* sector)
{
*cyl = lba / (2 * FLOPPY_144_SECTORS_PER_TRACK);
*head = ((lba % (2 * FLOPPY_144_SECTORS_PER_TRACK)) / FLOPPY_144_SECTORS_PER_TRACK);
*sector = ((lba % (2 * FLOPPY_144_SECTORS_PER_TRACK)) % FLOPPY_144_SECTORS_PER_TRACK + 1);
}
磁盘操作系统(Disk Operating System, DOS)主要有五部分组成