首页 > 代码库 > Multiboot规范

Multiboot规范

一个启动载入器/OS映像接口主要是三个方面:

1          由启动载入器看到的一个OS映像的格式。

2          当启动载入器启动一个操作系统时,机器的状态。

3          由启动载入器传递给操作系统的信息的格式。

3.1.      OS映像的格式

一个OS映像可能是一个,对于这个特定的操作系统而言,标准格式的普通32位可执行文件,除了它可能被链到一个非缺省的载入地址,以避免载入到PCI/O区域的顶部或其它的保留区域,同样它不应该使用共享库或其它花哨的特性。

一个OS映像,除了该OS映像所使用文件格式的头部外,必须包含一个称为Multiboot头的额外的头部。Multiboot头部必须被完整包含 在OS映像的前8192字节内,而必须与长字(32位)对齐。一般而言,它应该尽早出现,并可能嵌入在可执行文件头部后,代码段的开头。

3.1.1.        Multiboot头的布局

Multiboot头的布局必须如下:

偏移 类型              域名                     注意

0            u32              magic                  要求

4            u32              lags                     要求

8            u32              checksum            要求

12          u32              header_addr               如果设置了flags[16]

16          u32              load_addr            如果设置了flags[16]

20          u32              load_end_addr           如果设置了flags[16]

24          u32              bss_end_addr             如果设置了flags[16]

28          u32              entry_addr          如果设置了flags[16]

32          u32              mode_type          如果设置了flags[2]

36          u32              width                   如果设置了flags[2]

40          u32              height                  如果设置了flags[2]

44          u32              depth                   如果设置了flags[2]

域‘magic’,‘flags’及‘checksum’定义在3.1.2节【头部魔数域】,4页,域 ‘header_addr’,‘load_addr’,‘load_end_addr’,‘bss_end_addr’及‘entry_addr’定义在 3.1.3节【头部地址域】,5页,而域‘mode_type’,‘width’,‘height’及 ‘depth’定义在3.1.4节【头部图形化域】,5页。

3.1.2.        Multiboot头部的魔数域

magic’ 域‘magic’是标识这个头的魔数,它必须是十六进制数0x1BADB002

flags   域‘flags’指定OS映像所要求的特性,或对启动载入器的要求。0-15位显示要求;如果启动载入器看到这些比特中有比特被设置,但不能理解这个标 志,或出于某些原因不能满足其代表的要求,它必须通知用户,并且这个OS映像载入失败。16-31位显示可选的特性;如果这个区域内有比特被设置,但启动 载入器不能理解,它可能只是忽略它们,并如常处理。理所当然,所有‘flags’中尚未定义的比特,必须在OS映像中设置为0。这样,‘flags’域, 除了选择简单特性外,还可用于版本控制。

如果‘flags’字中的第0位被设置,那么所有与操作系统一起载入的启动模块必须在页(4KB)边界上对齐。某些操作系统在启动期间,能够直接把包含启动模块的页面映射到一个页对齐的地址,因此要求启动模块页对齐。

如果‘flags’字中的第1位被设置,那么可用内存的信息,至少是Multiboot 消息结构(参考3.3节【启动信息格式】,7页)的 ‘mem_*’ 域,被包括。 如果启动载入器能够传递一个内存映射图(‘mmap_*’域),而且这样的域存在,它也可能被包括。

如果‘flags’字中的第2位被设置,关于视频模式表(参考3.3节【启动信息格式】,7页)的信息必须对内核可用。如果‘flags’字中的第 6位被设置,那么在Multiboot头偏移为12-28处的域有效,启动载入器应该使用它们,而不是在实际可执行头中的域,来计算何处载入OS映像。如 果内核映像是elf格式,这个信息不需要提供,但如果内核是a.out格式或其它格式,则必须提供。兼容的启动载入器必须能载入elf格式的映像,或在 Multiboot头中嵌入载入地址信息的映像;它们可能也直接支持其它可执行格式,比如特定的a.out变体,不过这不要求。

checksum

域‘checksum’是一个32位无符号值,当加上其它魔数域(即,‘magic’及‘flags’)时,其和必须是无符号32位数0

3.1.3.        Multiboot头的地址域

所有被flag16位激活的地址域都是物理地址。每个的含义如下:

header_addr

包含对应于Multiboot头开始的地址——magic值被期望载入的物理内存位置。这个域用于同步OS映像偏移与物理内存地址间的映射。

load_addr

包含代码段开头的物理地址。在OS映像中,开始载入的偏移,由Multiboot头部所在偏移减去(header_addr – load_addr)来定义。Load_addr必须小于等于header_addr

load_end_addr

包含数据段末尾的物理地址。(load_end_addr – load_addr)指出了要载入多少数据。这暗示在OS映像中代码段及数据段必须连续;对于现存的a.out可执行格式,这是成立的。如果这个域是0, 启动载入器就假定代码段与数据段占据了整个OS映像文件。

bss_end_addr

包含bss段末尾的物理地址。启动载入器初始化这个区域为0,并保留它所占据的内存,以避免在这个区域放入启动模块及与操作系统相关的其它数据。如果这个域是0,启动载入器就假定bss段没有出现。

entry_addr

为了开始运行操作系统,启动载入器应该跳转到的物理地址。

3.1.4.        Multiboot头的图形化域

所有的图形化域被flag的第2位所激活。它们指定了首选的图形化模式。注意到这仅是OS映像的一个建议的模式。如果该模式存在,当用户没有显式指定一个模式时,启动载入器应该设置它。否则,如果可能,启动载入器应该进入一个类似的模式。

每个域的含义如下:

mode_type

对于线性图形模式,包含‘0’,或‘1’对于EGA-标准文本模式。余下为未来扩展保留。注意到启动载入器可能设置一个文本模式,即便这个域包含‘0’。

width         包含列的个数。在一个图形化模式中,这以像素为单位,在一个文本模式中,以字符为单位。值0表示OS映像没有偏好。

height         包含行的个数。在一个图形化模式中,这以像素为单位,在一个文本模式中,以字符为单位。值0表示OS映像没有偏好。

depth         包含,在一个图形化模式下,每个像素的比特数;而在一个文本模式中,这为0。值0表示OS映像没有偏好。

 

 

 

 

 

3.2.      机器状态

当启动载入器调用32位操作系统时,机器必须具有如下状态:

EAX   必须包含魔数‘0x2BADB002’;这个值的出现,向操作系统表示,它由一个Multiboot兼容的启动载入器载入(即,相对于可以载入该操作系统的,其它类型启动载入器)。

EBX   必须包含由启动载入器提供的,Multiboot信息结构的32位物理地址(参考3.3节【启动信息格式】,7页)。

CS          必须是一个偏移为‘0’,限长为‘0xFFFFFFFF’的32位读/执行代码段。具体值没有定义。

DS

ES

FS

GS

SS       必须是一个偏移为‘0’,限长为‘0xFFFFFFFF’的32位读/写数据段。具体值没有定义。

A20 gate’必须激活。

CR0    31位(PG)必须被清除。第0位(PE)必须被设置。其它位未定义。

EFLAGS

17位(VM)必须被清除。第9位(IF)必须被清除。其它位未定义。

所有其它处理器寄存器及标记位都未定义。这包括,特别是:

ESP    一旦需要,OS映像必须构建自己的栈。

GDTR    即便段寄存器如上所示那样设置,‘GDTR’可能是无效的,因此OS映像必须不加载任何段寄存器(就算只是重载相同的值!),直到它设立自己的‘GDT’。

IDTR  OS映像必须保持禁止中断,直到它设立自己的IDT

然而,在正常的工作次序中,启动载入器不应该改动其它机器状态,即,如BIOS初始化的那样(或DOS,如果那是启动载入器运行的地方)。换而言 之,操作系统在载入后,应该能够进行诸如BIOS调用的操作,只要在这样做之前,它不改写BIOS数据结构。同样,启动载入器必须不改动以正常 BIOS/DOS值编写的PIC,即便在切换到32位模式过程中,它改变了它们。

3.3.      启动信息格式

进入到操作系统,EBX寄存器包含Multiboot信息数据结构的物理地址,通过它,启动载入器向操作系统传递重要信息。操作系统可以使用或忽略,所选择的该结构体的任意部分;由启动载入器传入的所有信息仅供参考。

Multiboot信息结构体及其相关的子结构体,可能被启动载入器放在内存的任一处(当然,为内核及启动模块所保留的内存是例外)。避免改写这个内存,直到它没有使用价值,这是操作系统的责任。

Multiboot信息结构(就目前的定义)的格式如下:

            +----------------------+

0           | flags                      | (要求)

            +----------------------+

4           | mem_lower           | (如果设置了flags[0],出现)

8           | mem_upper           | (如果设置了flags[0],出现)

            +----------------------+

12         | boot_device          |(如果设置了flags[1],出现)

            +----------------------+

16         | cmdline                 | (如果设置了flags[2],出现)

            +----------------------+

20         | mods_count          |(如果设置了flags[3],出现)

24         | mods_addr            | (如果设置了flags[3],出现)

            +----------------------+

28 - 40 | syms                      | (如果设置了flags[4]flags[5],出现)

            +----------------------+

44         | mmap_length       |(如果设置了flags[6],出现)

48         | mmap_addr          |(如果设置了flags[6],出现)

            +----------------------+

52         | drives_length        |(如果设置了flags[7],出现)

56         | drives_addr           |(如果设置了flags[7],出现)

            +----------------------+

60         | config_table          |(如果设置了flags[8],出现)

            +----------------------+

64         | boot_loader_name|(如果设置了flags[9],出现)

            +----------------------+

68         | apm_table             |(如果设置了flags[10],出现)

            +----------------------+

72         | vbe_control_info  |(如果设置了flags[11],出现)

76         | vbe_mode_info     |

80         | vbe_mode             |

82         | vbe_interface_seg |

84         | vbe_interface_off |

86         | vbe_interface_len |

      +----------------------+

第一个长字显示在Multiboot信息结构体中其它域存在及有效性。所有尚未定义的比特位必须由启动载入器设为0。操作系统不能理解的任意比特组应该被忽略。这样,域‘flags’还起到版本指示器的作用,允许Multiboot信息结构体在将来进行无损害的扩展。

如果在‘flags’中设置了第0位,那么域‘mem_*’是有效的。‘mem_lower’及‘mem_upper’分别表示低位内存和高位内存 的数量,以KBkilobyte)为单位。低位内存从地址0开始,而高位内存从地址1M开始。低位内存最大的可能值是640KB。为高位内存所返回的值 最大是第一个高位内存空洞的地址减去1M。但不保证就是这个值。

如果在‘flags’中设置了第1位,那么域‘boot_device’是有效的,并显示从哪个BIOS硬盘设备上启动载入器载入OS映像。如果 OS映像不从一个BIOS硬盘上载入,那么这个域必须不出现(第3位必须被清除)。操作系统可能使用这个域作为确定其自己根设备的一个暗示,但它不要求这 样做。域‘boot_device’在41字节子域中布置如下:

+-------+-------+-------+-------+

 | part3  | part2 | part1  | drive |

+-------+-------+-------+-------+

第一个字节包含BIOS设备号,它可被BIOSINT 0x13底层接口所理解:即,0x00对应软盘,0x80对应第一个硬盘。

余下3个字节指定了启动分区。‘part1’指定最上层的分区号,‘part2’指出在最上层分区的一个子分区等。分区号总是从0开始。没有设置的 分区字节必须被设置为0xFF。例如,如果硬盘使用单层DOS分区规划,那么‘part1’包含DOS分区号,而‘part2’及 ‘part3’都是0xFF。另一个例子,如果一个硬盘首先划分为DOS分区,然后其中一个DOS分区被进一步使用BSD硬盘标签(disklabel) 策略划分为几个BSD分区,那么‘part1’包含这个DOS分区号,‘part2’包含在这个DOS分区中的BSD子分区,而‘part3’是 0xFF

DOS扩展分区由从4开始的分区号表示,而不是作为嵌套子分区,即便扩展分区所立足的硬盘布局本质上是分层的。例如,如果启动载入器从,一个以传统DOS形式分区的硬盘的第二个扩展分区启动,那么‘part1’将是5,而‘part2’及‘part3’都将是0xFF

如果在‘flags’中设置了第2位,域‘cmdline’是有效的,它包含了要传递给内核的命令行的物理地址。这个命令行是一个普通C样式的,以0结尾的字符串。

如果在‘flags’中设置了第3位,那么域‘mods’向内核显示,什么启动模块会伴随内核映像载入,以及可以在何处找到它们。 ‘mods_count’包含了载入模块的个数;‘mods_addr’包含了第一个模块结构的物理地址。‘mods_count’可能是0,表示不载入 启动模块,就是设置了‘flags’的第一位比特。每个模块结构体的格式如下:

    +-------------------+

0   | mod_start          |

4   | mod_end           |

    +-------------------+

8   | string                 |

    +-------------------+

12 | reserved (0)       |

    +-------------------+

头两个域包含了启动模块本身开头与结尾的地址。域‘string’提供了一个任意的字符串来关联这个特定的启动模块;它是一个0结尾的ASCII字 符串,就像内核命令行。域‘string’可能是0,如果没有字符串可关联这个模块。通常,这个字符串可能是一个命令行(比如,如果操作系统把启动模块处 理作可执行程序),或一个路径名(比如,如果操作系统把启动模块处理作在一个文件系统中的文件),不过它确切的使用,取决于操作系统。域 ‘reserved’必须被启动载入器设置为0,并且为操作系统所忽略。

警告:第4与第5比特位是互斥的。

如果在‘flags’中设置了第4位,那么在Multiboot信息结构体中,从第28个字节开始的以下域是有效的:

    +-------------------+

28 | tabsize              |

32 | strsize               |

36 | addr                  |

40 | reserved (0)      |

    +-------------------+

这些域表示何处可以找到,来自一个a.out内核映像的符号表。‘addr’是一个a.out格式的nlist结构体数组大小(4字节无符号长整 形)的物理地址,其后紧跟着这个数组本身,然后是一组以0结尾的ASCII字符串的大小(4字节无符号长整形,并加上sizeof(unsigned long)),最后是这组字符串本身。‘tabsize’是符号表大小的参数(在符号段开头找到),而‘strsize’是随后的符号表所引用的字符串表 大小的参数(在字符串段开头找到)。注意到‘tabsize’可能是0,表示没有符号,即便设置了‘flags’中的第4位。

如果在‘flags’中设置了第5位,那么在Multiboot信息结构体中,从第28个字节开始的以下域是有效的:

   +-------------------+

28 | num                  |

32 | size                   |

36 | addr                  |

40 | shndx                |

    +-------------------+

这些域表示何处是来自一个ELF内核的段头表(section header table),每个项的大小,项的个数,及用作名字索引的字符串表。它们对应于在可执行及可链接格式(ELF)规范的程序头(program header)中的‘shdr_*’项(‘shdr_num’,等)。所有的段被载入,然后ELF段头的物理地址域指向内存中的段(如何读出段头的细节, 参考i386 ELF 文档)。注意到‘shdr_num’可能是0,表示没有符号,即便设置了‘flags’中的第5位。

如果在‘flags’中设置了第5位,那么域‘mmap_*’是有效的,表示包含由BIOS提供的一个机器内存映射的缓存的地址及长度。其 中,‘mmap_addr’是这个地址,而‘mmap_length’是这个缓存的总体大小。这个缓存由以下一个或多个size/structure对组 成(‘size’实际上用于跳到下一对):

   +-------------------+

-4 | size                   |

    +------------------+

0   | base_addr         |

8   | length               |

16 | type                  |

    +-------------------+

其中‘size’是关联结构体的字节大小,它至少是20。‘base_addr’是起始地址。‘length’是该内存区域的字节大小。‘type’是所代表的地址区域的种类,其中值1表示为可用的ram,而当前其它值表示一个保留区域。

该映射保证列出所有可以正常使用的标准ram

如果在‘flags’中设置了第7位,那么域‘drives_*’是有效的,表示第一个drive结构体的物理地址,及drive结构体的大小。 ‘drives_addr’是这个地址,而‘drives_length’是drive结构体的总大小。注意到‘drives_length’可以是0。 每个drive结构体的格式如下:

           +-------------------+

0          | size                    |

           +-------------------+

4          | drive_number    |

           +-------------------+

5          | drive_mode       |

           +-------------------+

6          | drive_cylinders |

8          | drive_heads       |

9          |drive_sectors     |

           +--------------------+

10 - xx | drive_ports        |

           +--------------------+

域‘size’指定这个结构体的大小。这个大小,依赖于端口的数目,是可变的。注意到因为对齐的原因,这个大小可能不等于(10 + 2 * 端口的数目)。

域‘drive_number’包含了BIOS设备号。域‘drive_mode’代表由启动载入器使用的访问模式。当前,以下模式被定义:

0’ CHS 模式(传统的柱面//扇区(cylinder/head/sector)取址模式)。

1’ LBA 模式(逻辑块取址模式(Logical Block Addressing mode))。

drive_cylinders’,‘drive_heads’及‘drive_sectors’这三个域表示由BIOS检测出来的驱动的几何数 据。‘drive_cylinders’包含柱面数目。‘drive_heads’包含柱头个数。‘drive_sectors’包含每个磁道的扇区数。

域‘drive_ports’包含在BIOS代码中使用的I/O端口数组。这个数组由0个或以上的无符号2字节整数构成,以0结尾。注意到这个数组可能包含任意数目的,不与该驱动真正相关的I/O端口 (比如DMA控制器端口)。

如果在‘flags’中设置了第8位,那么域‘config_table’是有效的,它表示由GET CONFIGURATION BIOS调用返回的rom配置表的地址。如果这个BIOS调用失败,这个表的大小必须为0

如果在‘flags’中设置了第9位,域‘boot_loader_name’是有效的,它包含了一个启动该内核的启动载入器名字的地址。这个名字是一个普通C-样式以0结尾的字符串。

如果在‘flags’中设置了第10位,域‘apm_table’是有效的,它包含了一个定义如下的APM表的物理地址:

    +----------------------+

0   | version                 |

2   | cseg                      |

4   | offset                    |

8   | cseg_16                |

10 | dseg                      |

12 | flags                     |

14 | cseg_len               |

16 | cseg_16_len         |

18 | dseg_len               |

    +----------------------+

域 ‘version’,‘cseg’,‘offset’,‘cseg_16’,‘dseg’,‘flags’,‘cseg_len’,‘cseg_16_len’,‘dseg_len’ 分别表示版本号,32位保护模式代码段,入口点的偏移,16位保护模式代码段,16位保护模式数据段,flags32位保护模式代码段的长度,16位保 护模式代码段的长度,16位保护模式数据段的长度。只有域‘offset’是4个字节,其它的都是2个字节。更多信息,参考先进电源管理 (APMBIOS接口规范。 

如果在‘flags’中设置了第11位,表示图形化表可用。如果内核已经在‘Multiboot Header’中表示,它接受一个图形模式,它才能被设置。

域‘vbe_control_info’及‘vbe_mode_info’分别包含了由VBE Function 00h返回的VNE控制信息的物理地址,及由VBE Function 01h返回的VBE模式信息。

域‘vbe_mode’表示在VBE 3.0中所规定格式中的当前视频模式。

余下的域‘vbe_interface_seg’,‘vbe_interface_off’,及‘vbe_interface_len’包含了定义 在VBE 2.0+中的一个保护模式接口表。如果这个信息不可用,这些域包含0。注意VBE 3.0定义了另一个保护模式接口,它与旧的不兼容。如果你希望使用新的保护模式接口,你将不得不自己查找这个表。

用于图形化表的域是为VBE设计的,但Multiboot启动载入器可能在非-VBE模式上模拟 VBE,仿佛它们就是VBE 模式。

 

Multiboot规范