linux 0.11 bootsect.s中的BIOS部分解读
阅读原文时间:2021年04月20日阅读:1

        电脑启动以后,最先由BIOS自检然后加载磁盘第一扇区数据到内存中,然后把CPU第一条指令设置到这块内存后由CPU执行余下的操作。以下来探索一下,BIOS究竟做了什么,怎么工作的。我参考的资料是维基百科:http://en.wikipedia.org/wiki/BIOS  http://en.wikipedia.org/wiki/BIOS_interrupt_call

After completing the POST, the motherboard BIOS scans for extension ROMs in an area of the "upper memory area" space and runs each ROM found, in order. To discover memory-mapped ISA option ROMs during the boot process, BIOS implementations scan real-mode address space from 0x0C0000 to 0x0F0000 on 2 KiB boundaries, looking for a ROMsignature: 0x55 followed by 0xAA. In a valid expansion ROM, this signature is followed by a single byte indicating the number of 512-byte blocks it occupies in real memory. The next byte contains an offset describing the option ROM's entry point. A checksum of the specified number of 512-byte blocks is calculated, and if the ROM has a valid checksum the BIOS transfers control to the specified entry address. At this point, the expansion ROM code takes over,using BIOS services to register interrupt vectors for use by post-boot applications, to provide a user configuration interface, or to display diagnostic information.       

    自检不是这里说的重点,跳过不说;BIOS自检后,已经收集到从哪一个盘启动的信息;

For a disk drive or a device that logically emulates a disk drive, such as an USB Flash drive or perhaps a tape drive, to perform this check the BIOS attempts to load the first sector (boot sector) from the disk to memory address 0x007C00, and checks for the boot sector signature 0x55 0xAA in the last two bytes of the (512 byte long) sector. If the sector cannot be read (due to a missing or blank disk, or due to a hardware failure), or if the sector does not end with the boot signature, the BIOS considers the disk unbootable and proceeds to check the next device.

BIOS会尝试从第一启动盘的第一个扇区读取数据写到物理内存的0x007c00这个位置;然后检查内存中的0x007dfe和0x007dff上是0x55 0xaa,这个算是启动扇区的签名,如果没有这个标志,就认为这个读取到的数据是不正确的启动数据。如果无法读取指定第一个启动盘的第一个扇区数据或检测启动扇区签名不正确,或者校验和不对,那么就会认为这个启动盘无法启动,转而去检查第二启动盘。

从这里来解析linux0.11里的bootsect.s中的代码段:

SETUPLEN = 4                ! nr of setup-sectors
BOOTSEG  = 0x07c0            ! original address of boot-sector
INITSEG  = 0x9000            ! we move boot here - out of the way
SETUPSEG = 0x9020            ! setup starts here
SYSSEG   = 0x1000            ! system loaded at 0x10000 (65536).
ENDSEG   = SYSSEG + SYSSIZE        ! where to stop loading

! ROOT_DEV:    0x000 - same type of floppy as boot.
!        0x301 - first partition on first drive etc
ROOT_DEV = 0x306

entry start
start:
    mov ax,#BOOTSEG
    mov ds,ax
    mov ax,#INITSEG
    mov es,ax
    mov cx,#256
    sub si,si
    sub di,di
    rep
    movw
    jmpi    go,INITSEG
go:    mov ax,cs
    mov ds,ax
    mov es,ax
! put stack at 0x9ff00.
    mov ss,ax
    mov sp,#0xFF00      ! arbitrary value >>512

BOOTSEG设置为0x07c0是对应的实模式内存地址的段地址;这个值是由于BIOS的规定而设置的。BIOS从第一扇区把bootsect的代码加载到了0x07c0段后,然后从start开始执行;接下来的有一个int 13需要再分析。

! load the setup-sectors directly after the bootblock.
! Note that 'es' is already set up.

load_setup:
    mov dx,#0x0000      ! drive 0, head 0
    mov cx,#0x0002      ! sector 2, track 0
    mov bx,#0x0200      ! address = 512, in INITSEG
    mov ax,#0x0200+SETUPLEN ! service 2, nr of sectors
    int 0x13            ! read it
    jnc ok_load_setup       ! ok - continue
    mov dx,#0x0000
    mov ax,#0x0000      ! reset the diskette
    int 0x13
    j   load_setup

这里使用了BIOS中断INT 0x13将seetup模块从磁盘第2个扇区开始读到0x90200开始处,共读4个扇区。那么,来看一下BIOS的中断机制以及其中的int 0x13是怎么操作运行的。参考 http://en.wikipedia.org/wiki/BIOS_interrupt_call

1[3h](http://en.wikipedia.org/wiki/INT_13H "INT 13H")

Low Level Disk Services

AH

Description

00h

Reset Disk Drives

01h

Check Drive Status

02h

Read Sectors

03h

Write Sectors

04h

Verify Sectors

05h

Format Track

08h

Get Drive Parameters

09h

Init Fixed Drive Parameters

0Ch

Seek To Specified Track

0Dh

Reset Fixed Disk Controller

15h

Get Drive Type

16h

Get Floppy Drive Media Change Status

17h

Set Disk Type

18h

Set Floppy Drive Media Type

41h

Extended Disk Drive (EDD) Installation Check

42h

Extended Read Sectors

43h

Extended Write Sectors

44h

Extended Verify Sectors

45h

Lock/Unlock Drive

46h

Eject Media

47h

Extended Seek

48h

Extended Get Drive Parameters

49h

Extended Get Media Change Status

4Eh

Extended Set Hardware Configuration

可以看到调用int 0x13时,ah = 0x02; 也就是叫中断处理例程去处理Read Sector功能。其他参数我没有在维基或别的地方找到答案,直接按赵炯的书上说的:

al = 需要读出的扇区数量

ch = 磁道号的低8位; cl =开始扇区(位0-5),磁道号高2位(位6-7);

dh = 磁头号;        dl = 驱动器号(如果是硬盘则位7要置位);

es:bx ->指向数据缓冲区:如果出错则CF标志置位,ah中是出错码。

另外问题来了:中断描述符表在哪里,中断处理例程又在哪里?什么时候放的?

根据赵炯书上说明:bootsect代码为什么不把系统模块直接加载到物理地址0x0000开始处而要在setup程序中再进行移动呢?这是因为在随后执行的setup代码开始部分还需要利用ROM BIOS中的中断调用来获取机器的一些参数(比如int0x13获取setup代码)。当BIOS初始化时会在物理内存开始处放置一个大小为0x400字节的中断向量表,因此需要在使用完BIOS的中断调用后才能将这个区域覆盖掉。

中断处理例程在哪里?没找到依据,有一个网友说在E000:0到F000:0之间。

中断到底是中断CPU还是中断BIOS?根据维基上的BIOS中断表,看起来像是BIOS的中断;但是int 0x13代码bootsect运行时是在CPU执行的。我没找到明确答案。

补充:http://book.51cto.com/art/201106/270092.htm

BIOS程序被固化在计算机主机板上的一块很小的ROM芯片里。通常,不同的主机板所用的BIOS也有所不同,就启动部分而言,各种类型的BIOS的基本原理大致相似。为了便于大家理解,我们选用的BIOS程序只有8KB,所占地址段为0xFE000~0xFFFFF,如图1-1所示。现在CS:IP已经指向了0xFFFF0这个位置,这意味着BIOS开始启动了。随着BIOS程序的执行,屏幕上会显示显卡的信息、内存的信息……说明BIOS程序在检测显卡、内存……这期间,有一项对启动(boot)操作系统至关重要的工作,那就是BIOS在内存中建立中断向量表和中断服务程序。

小贴士

ROM(Read Only Memory):只读存储器,现在通常用闪存芯片做ROM。虽然闪存芯片在特定的条件下是可写的,但在谈到主机板上存储BIOS的闪存芯片时,业内人士把它看作ROM。ROM有一个特性,就是断电之后仍能保存信息,这一点与硬盘类似。

BIOS程序在内存最开始的位置(即:0x00000)用1KB的内存空间(0x00000~ 0x003FF)构建中断向量表,并在紧挨着它的位置用256字节的内存空间构建BIOS数据区(0x00400~0x004FF),在大约56KB以后的位置(0x0E05B)加载了8KB左右的与中断向量表相应的若干中断服务程序,图1-2中精确地标注了这些位置。

小贴士

一个容易计算的方法:0x00100是256个字节,0x00400就是4×256字节=1024字节,即1KB。因为是从0x00000开始计算,所以1KB的高地址端不是0x00400,而是0x00400-1,也就是0x003FF。

 

图1-2 BIOS在内存中加载中断向量表和中断服务程序

中断向量表中有256个中断向量,每个中断向量占4个字节,其中两个字节是CS的值,两个字节是IP的值,每个中断向量都指向一个具体的中断服务程序。

根据研究查证,中断向量在BIOS初始化过程中加载到内存当中的,但是我查阅维基上的POST资料,POST过程没有加载中断向量和中断服务程序到内存的过程。按上面的说法,是在初始化过程加载了,现在就不再考究到底是初始化的哪一步加载了。

中断例程加载在0xE05B位置(根据不同的BIOS估计有不同吧?)。

中断是谁的中断的问题:只有一个级联了两个8295A中断处理器的中断处理构件,BIOS中是没有的。处理BIOS中断的时候,如int 0x13,是由加载到内存的中断例程完成内容填充的。至于从哪里找到硬盘数据,会是在自检的时候?不追究了。

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章