LINUX I386引导协议.doc_第1页
LINUX I386引导协议.doc_第2页
LINUX I386引导协议.doc_第3页
LINUX I386引导协议.doc_第4页
LINUX I386引导协议.doc_第5页
已阅读5页,还剩7页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

LINUX/I386引导协议 - H. 彼得安文 最后更新于2002-01-01在i386平台上,Linux内核使用一个相当复杂的引导协定。演变至此,这一方面是由于历史方面的原因,另一方面是由于早期要求将内核本身做成可引导镜像、复杂的PC内存模型,以及因实模式的DOS作为主流操作系统的实际消亡而引发的对PC工业的预期发生的转变。 现在,存在四个版本的Linux/i386引导协议。旧内核:只支持zImage和Image。有些很早期的内核甚至不支持命令行。2.00协议:(1.3.73内核) 添加了对bzImage和initrd的支持,以及引导加载程序和内核之间通信的规范方法。尽管传统的setup区域仍然假定是可写的,但是Setup.S做成了可重定位的了。(译者注:setup区域会被旧内核的实模式代码重写,比如0x9XXXX处的命令行参数。)2.01协议:(1.3.76内核)添加了堆超出警告。2.02协议:(2.4.0-test3-pre3内核)新加的命令行协议。降低了传统的内存顶端地址。禁止重写传统的setup区域,这使得从系统管理模式(SMM)或从32位BIOS调用的入口地址那里使用扩展BIOS数据区(EBDA)的系统安全引导。zImage不建议使用,但依然支持。2.03协议:(2.4.18-pre1内核) 显式地给引导加载程序给出initrd的最高可能地址。* 内存布局 传统的Image或zImage使用的内核加载器的典型内存布局如下:| |0A0000+-+| BIOS保留 |不要使用。保留给BIOS EBDA。09A000+-+| 堆栈/堆/命令行 |内核实模式代码使用。098000+-+| 内核setup |内核实模式代码。090200+-+| 内核引导扇区 |内核遗留引导扇区。090000+-+| 保护模式内核 |内核镜像块。010000+-+| 引导加载程序 |-引导扇区入口点0000:7C00001000+-+| MBR/BIOS保留 |000800+-+| 一般由MBR使用 |000600+-+ | 仅BIOS使用 |000000+-+ 当使用zImage时,保护模式的内核要被迁移到0x100000(“高端内存”)处,内核实模式块(引导扇区、setup以及堆栈和堆)被做成可以迁移到从地址0x10000到低端内存地址末尾之间的任何位置。然而,在2.00协议和2.01协议里,命令行依然必须放在0x9XXXX的地址范围,那段范围的内存依然会被早期的内核重写。2.02协议解决了那个问题。 最好保持“内存顶端”,即低端内存中被引导加载程序触摸到的最高点,越低越好。因为一些较新的BIOS已经开始在低端内存顶部附近分配一些相当多数量的内存了,称作扩展BIOS数据区(EBDA)。引导加载程序应该用“INT 12h”BIOS调用检查有多少低端内存可以用。 但是,如果INT 21h报告说内存数量不足,那引导加载程序除了给用户报错外什么也干不了了。因此,引导加载程序要设计得当,尽量少占用低端内存空间。zImage或老的bzImage内核需要在0x90000段内写数据,引导加载程序要确保不要使用0x9A000地址以上的内存,有太多的BIOS会闯入那个地址以上。* 实模式内核头下文以及内核引导系列的任何地方,一个“扇区”指512字节。和底层媒体的实际扇区大小无关。加载Linux内核的第一步是加载实模式代码(引导扇区和setup代码)然后检测下面的内核头的偏移量0x01f1处。实模式代码最大总共可以有32K,但引导加载程序却可能只选择开始的两个扇区(1K)加载,然后检测启动扇区大小。内核头如下:偏移协议字段名释义/大小01F1/1所有setup_sectssetup以扇区计的大小01F2/2所有root_flags如果设置,表示根文件系统只读挂载01F4/2所有syssize不要使用 仅bootsect.S使用01F6/2所有swap_dev不要使用 已过时01F8/2所有ram_size不要使用 仅bootsect.S使用01FA/2所有vid_mode视频模式控制01FC/2所有root_dev默认根设备号01FE/2所有boot_flag0xAA55 幻数0200/22.00+jump跳转指令0202/42.00+header魔法签名HdrS0206/22.00+version支持的引导协议版本0208/42.00+realmode_swtch引导加载程序钩子(见下面)020C/22.00+start_sys低端加载段(0x1000) (已过时)020E/22.00+kernel_version指向内核版本字符串0210/12.00+type_of_loader引导加载程序识别号0211/12.00+loadflags引导协议选项标志0212/22.00+setup_move_size移到高端内存的大小(和钩子一块使用)0214/42.00+code32_start引导加载程序钩子(见下面)0218/42.00+ramdisk_imageinitrd加载地址(由引导加载程序设置)021C/42.00+ramdisk_sizeinitrd大小(由引导加载程序设置)0220/42.00+bootsect_kludge不要使用 仅bootsect.S使用0224/22.01+heap_end_ptr紧跟setup结尾的空闲内存大小0226/2N/A用1填充未使用0228/42.02+cmd_line_ptr32位指针指向内核命令行022C/42.03+initrd_addr_maxinitrd的最高合法地址为了向后兼容,如果setup_sects字段是0,实际值是4。如果在偏移0x202处没有找到HdrS (0x53726448) 魔法签名,引导协议版本是“旧版本”。加载老内核时,要假定以下参数:Image type = zImage不支持initrd实模式内核必须加载到0x90000。 否则,若“version”字段包含协议版本,例如:2.01版协议的该字段包含0x0201。当设置内核头的字段时,你必须确保只设置在用的协议版本所支持的字段。 “kernel_version”字段,如果设置成非零值,包含一个指向以零结尾的人们可读取的内核版本号的字符串的指针,再减去0x200。这个可以用来给用户显示内核版本。该值应该小于(0x200*setup_sects)。例如:如果这个值设置成0x1c00,内核版本号字符串可以在内核文件偏移0x1e00的地方找到,当且仅当“setup_sects”字段包含的值大于等于14时该值才有效。 大部分引导加载程序简单的直接加载内核到它的目标地址。这样的引导加载程序不需要考虑填写内核头里的大部分字段,但下面的字段应当填写。 vid_mode:请看特殊命令行选项一节。 type_of_loader:如果你的引导加载程序分配了id(见下表),在这里输入0xTV,其中T是引导加载程序识别号,V是版本号。否则,在这里输入0xFF.已分配的引导加载程序id:0 LILO1 Loadlin2 bootsect-loader3 SYSLINUX4 EtherBoot5 ELILO7 GRuB8 U-BOOT如果你需要分配一个新的引导加载程序ID值,请联系 loadflags, heap_end_ptr:如果协议版本是2.01或以上,在heap_end_ptr里输入setup堆的偏移量界限并在loadflags里设置0x80位(CAN_USE_HEAP),heap_end_ptr 从相对于setup开始处(0x0200)看的。 setup_move_size: 当使用协议2.00 or 2.01,如果实模式内核没有加载到0x90000,它在后面的加载步骤里将被移到那里。如果除了实模式内核本身外你想要移动额外的数据(像内核命令行),填写这个字段。 ramdisk_image, ramdisk_size:如果引导加载程序已经加载了初始RAM盘(initrd),设置指向ramdisk数据的32位指针到ramdisk_image,设置ramdisk数据的大小到ramdisk_size。 Initrd通常要加载到尽量高的内存里,要不然,它将被早期内核初始化过程重写。但是,它不能加载到大于由initrd_addr_max字段指出的地址,initrd要至少以4K字节的页对齐。 cmd_line_ptr: 如果协议版本是2.02或以上,这是一个指向内核命令行的32位指针。内核命令行可以放在setup结尾到0xA0000之间的任何地方。即使你的引导加载程序不支持命令行也要填写这个字段,这时,你可以把它指向空字符串(或者指向字符串“自动”将更好)。如果保留该字段在0值,内核将认为你的引导加载程序是不支持2.02以上的协议。 ramdisk_max: (译者注:即initrd_addr_max字段) initrd的内容能占用的最大地址。2.02或更早的引导协议里没有这个字段,因此,最大地址是0x37FFFFFF。(这个地址定义为最高的安全字节的地址,因此,如果你的ramdisk恰好是131072字节长并且这个字段的值是0x37FFFFFF,你可以从0x37FE0000开始你的ramdisk。)* 内核命令行 内核命令行已成为引导加载程序和内核通信的重要手段。它的一些选项也与引导加载程序本身相关,见下面的“特殊命令行选项” 内核命令行是一个零结尾的字符串,加上最后的零字节长度不超过255字节。 如果引导协议时2.02或以上,内核命令行地址由内核头cmd_line_ptr字段给出(见前面)。如果内核版本不是2.02或以上,命令行由以下协议输入: 在偏移0x0020处,“cmd_line_magic”字段(字),输入幻数0xA33F。 在偏移0x0022处,“cmd_line_offset”字段(字),输入内核命令行偏移量(相对于实模式内核开始处)。 内核命令行必须在setup_move_size覆盖的内存区以内,所以你可能需要调整这个字段。译者注:命令行的内容有些是针对引导加载程序的,有些是针对内核的,用户输入后,引导加载程序分析,如果是给自己的,就解析使用,如果是给内核的就传递。引导加载程序也可以给内核加入命令行参数* 引导配置举例作为配置举例,假定如下实模式段的布局:0x0000-0x7FFF实模式内核0x8000-0x8FFF堆栈和堆0x9000-0x90FF内核命令行这样的引导加载程序要在内核头里输入下面的字段。unsigned long base_ptr;/* 实模式段基址 */if ( setup_sects = 0 ) setup_sects = 4;if ( protocol = 0x0200 ) type_of_loader = ;if ( loading_initrd ) ramdisk_image = ;ramdisk_size = ;if ( protocol = 0x0201 ) heap_end_ptr = 0x9000 - 0x200;loadflags |= 0x80; /* CAN_USE_HEAP */if ( protocol = 0x0202 ) cmd_line_ptr = base_ptr + 0x9000; else cmd_line_magic= 0xA33F;cmd_line_offset = 0x9000;setup_move_size = 0x9100; else /* Very old kernel */cmd_line_magic= 0xA33F;cmd_line_offset = 0x9000;/* 很老的内核必须将它的实模式代码加载到0x90000 */if ( base_ptr != 0x90000 ) /* 复制实模式内核 */memcpy(0x90000, base_ptr, (setup_sects+1)*512);/* 复制命令行 */memcpy(0x99000, base_ptr+0x9000, 256);base_ptr = 0x90000; /* Relocated */* 建议清零32K以内的内存 */memset(0x90000 + (setup_sects+1)*512, 0, (64-(setup_sects+1)*512);* 加载剩下的内核 非实模式内核从内核文件偏移(setup_sects+1)*512处开始(再次,如果setup_setcs=0,真实值是4)。如果是Image/zImage,它应被加载到地址0x10000处,如果是bzImage,加载到0x100000处。 如果协议=2.00并且loadflags字段的0x01位(LOAD_HIGH)置位,内核是bzImage的内核:is_bzImage = (protocol = 0x0200) & (loadflags & 0x01);load_address = is_bzImage ? 0x100000 : 0x10000; 注意:Image/zImage内核最大可以有512K大小,因此可以使用0x100000x90000范围的整个内存。这表示内核实模式部分加载到0x90000绝对必需。bzImage内核则允许更多灵活处理。* 特殊命令行选项 如果引导加载程序提供的命令行是由用户输入的,用户可能希望下面的命令行选项有效。正常情况下,即使它们实际上不全对内核有意义,也不能将它们从命令行删除。如果需要给引导加载程序本身添加额外的命令行选项,引导加载程序的作者要在Documentation/kernel-parameters.txt里注册它们,以确保它们没有和当前现行的以及将来的内核选项相冲突。 vga= 这里的是整数(用C表示法,十进制、八进制或十六进制)或“normal”(表示0xFFFF)、“ext”(表示0xFFFE)、“ask”(表示0xFFFD)字符串的一种。当命令行被解析之前被内核使用时,该值应当输入vid_mode字段。 mem= 是以C语法表示的整数,后面可选跟K、M或G(表示10,20,30)。它给内核定义内存的末端。这将影响initrd的安置,因为initrd应被放到内存末端附近。注意这个选项既是针对内核的也是针对引导加载程序的。 initrd= 表示要加载initrd,的含义显然和引导加载程序无关,一些引导加载程序(比如LILO)没有这个命令。 另外,一些引导加载程序给用户定义的命令行添加了如下选项: BOOT_IMAGE= 要加载的引导镜像,再次,的含义显然和引导加载程序无关。 Auto 内核加载不需要显式的用户干预。 如果引导加载程序添加了这些选项,强烈建议将它们放在前面,放在用户定义或配置定义的命令行之前。要不然,“init=/bin/sh”会混淆“auto”选项。译者注:这些选项是引导加载程序要解析使用的选项,命令行有给内核和/或给引导加载程序的差别。* 运行内核内核是通过跳转到位于从实模式内核开始,段偏移量0x20处的内核入口点开始运行的。这表示如果你加载你的实模式内核代码到0x90000,内核入口点是0x9020:0000。 在入口点,ds=es=ss应指向实模式内核代码开始处(0x9000如果代码加载到0x90000),sp要设置正确,正常应指向堆顶,中断应该关闭。还有,为了

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论