本文档的翻译是基于linux内核版本2.6.11.1的,本人英语超难,但是由于学习linux内核代码也硬着头皮看英文文档,看的过程中感觉能够学到许多东西所以决定发点时间把这篇翻译下来了,里面很很多的不准确希望大家纠正和指导。希望共同探讨和学习,这也是自己学习linux源代码的一部分内容,接下来会有更多关于这方面的知识和大家分享,包括详细的内核运行原理和超详细的内核代码注释,期待和大家分享学习过程中的点点滴滴。每天成长一点点嘛!这篇文章虽然不长,但也发了我一天的时间,主要还是因为我英文太差的缘故吧。文章中翻译不当之处或错误还请大家提出来以便我尽快改正和学习。
写在前面的一点知识:
ramdisk一个作用就是用来解决boot过程中mount根文件系统的“先有鸡还是先有蛋”的问题的。
一般来说,根文件系统在形形色色的存储设备上,不同的设备又要不同的硬件厂商的驱动,比如intel的南桥自然需要intel的ide/sata驱动,VIA的南桥需要VIA的ide/sata驱动,根文件系统也有不同的文件系统的可能,比如ubuntu发行版可能一般用ext3,suse可能就不是了,不同的文件系统也需要不同的文件系统模块;假如把所有驱动/模块都编译进内核,那自然没问题,但是这样就违背了“内核”的精神或本质,所以一般来说驱动/模块都驻留在根文件系统本身上/lib/modules/xxx,那么“鸡蛋”问题就来了,现在要mount根文件系统却需要根文件系统上的模块文件,怎么办?于是,就想出ramdisk,内核总是能安装ramdisk的,然后把所有可能需要的驱动/模块都放在ramdisk上,首先,让内核将ramdisk当作根文件系统来安装,然后再用这个根文件系统上的驱动来安装真正的根文件系统,就将这个矛盾问题解决了.
ramdisk还举出一个作用,现在的发行版在boot时一般都是图形界面的,那么,ramdisk就可以放framebuffer驱动和一些图片来做这种简单的动画。
说明:文章中的“命令行”都应该是“命令行参数”更好吧。从下面开始是英文和我翻译中文的对照。
THELINUX/I386BOOTPROTOCOL(Linux/I386启动协议)
----------------------------
H.PeterAnvin<hpa@zytor.com>(作者邮箱)
Lastupdate2002-01-01(最后更新时间2002-01-01)
Onthei386platform,theLinuxkernelusesarathercomplicatedbootconvention.Thishasevolvedpartiallyduetohistoricalaspects,aswellasthedesireintheearlydaystohavethekernelitselfbeabootableimage,thecomplicatedPCmemorymodelandduetochangedexpectationsinthePCindustrycausedbytheeffectivedemiseofreal-modeDOSasamainstreamoperatingsystem.
在i386平台,linux内核使用了一个相当复杂的启动协议。这个特别的演变是由于历史各个方面,在早期的愿望是内核本身是可引导的镜像,复杂的PC机内存模型和由于期望改变在个人计算机产业中有效的终止实模式DOS而作为主流的操作系统。
Currently,fourversionsoftheLinux/i386bootprotocolexist.
当前,四种版本的Linux/i386启动协议存在。
Oldkernels: zImage/Imagesupportonly.Someveryearlykernelsmaynotevensupportacommandline.
老的内核:zImage/Image格式仅仅被支持。一些非常早的内核甚至可能不支持命令行。
Protocol2.00: (Kernel1.3.73)AddedbzImageandinitrdsupport,aswellasaformalizedwaytocommunicatebetweenthebootloaderandthekernel.setup.Smaderelocatable,althoughthetraditionalsetupareastillassumedwritable.
协议2.00:(Kernel1.3.73)增加了bzImage和initrd支持,以及引导加载程序和内核之间的通信的正式方式。setup.S作出可重定位,尽管传统setup区域仍假定可写。
Protocol2.01: (Kernel1.3.76)Addedaheapoverrunwarning.
协议2.01:(Kernel1.3.76)添加堆溢出警告
Protocol2.02: (Kernel2.4.0-test3-pre3)Newcommandlineprotocol.Lowertheconventionalmemoryceiling. Nooverwriteofthetraditionalsetuparea,thusmakingbootingsafeforsystemswhichusetheEBDAfromSMMor32-bitBIOSentrypoints.zImagedeprecatedbutstillsupported.
协议2.02:(Kernel2.4.0-test3-pre3)新的命令行协议。降低常规的内存上限。传统setup区域不能重写,从而使安全的启动系统,使用从SMM(SystemManagementMode系统管理模式)或32位BIOS入口点EBDA(ExtendedBIOSDataArea可扩展的BIOS数据区域)。zImage不赞成但是仍然支持。
Protocol2.03: (Kernel2.4.18-pre1)Explicitlymakesthehighestpossibleinitrdaddressavailabletothebootloader.
协议2.03:(Kernel2.4.18-pre1)明白地安排最高initrd地址可用引导装入过程
****MEMORYLAYOUT(内存布局)
Thetraditionalmemorymapforthekernelloader,usedforImageor
zImagekernels,typicallylookslike:
传统的内核装载内存映射,使用ImageorzImage内核,典型地看起来像:
| |
0A0000 +------------------------+
|ReservedforBIOS | Donotuse.ReservedforBIOSEBDA.(不使用。为BIOSEBDA保留)
09A000 +------------------------+
|Stack/heap/cmdline | Forusebythekernelreal-modecode.(实模式内核代码使用)
098000 +------------------------+
|Kernelsetup | Thekernelreal-modecode.(实模式内核代码)
090200 +------------------------+
|Kernelbootsector | Thekernellegacybootsector.(内核启动扇区)
090000 +------------------------+
|Protected-modekernel| Thebulkofthekernelimage.(保护模式,大的内核映像)
010000 +------------------------+
|Bootloader | <-Bootsectorentrypoint0000:7C00(启动装载进入点0000:7c00)
001000 +------------------------+
|ReservedforMBR/BIOS|(为MBR(masterbootrecord主引导记录)BIOS保留)
000800 +------------------------+
|TypicallyusedbyMBR|(典型被MBR使用)
000600 +------------------------+
|BIOSuseonly |(仅仅被BIOS使用)
000000 +------------------------+
WhenusingbzImage,theprotected-modekernelwasrelocatedto0x100000("highmemory"),andthekernelreal-modeblock(bootsector,setup,andstack/heap)wasmaderelocatabletoanyaddressbetween0x10000andendoflowmemory.
当使用bzImage,保护模式内核是移动到0x100000(“高内存”),实模式模块(bootsector,setup,andstack/heap)被装载到地址0x10000到最低内存的结尾的任何地方。
Unfortunately,inprotocols2.00and2.01thecommandlineisstillrequiredtoliveinthe0x9XXXXmemoryrange,andthatmemoryrangeisstilloverwrittenbytheearlykernel.The2.02protocolresolvesthatproblem.
幸运地,在协议2.00和2.01中命令行仍然被要求存在0x9XXXXX内存区域,那段内存区域仍然被早期内核重写。2.02协议解决了那个问题。
Itisdesirabletokeepthe"memoryceiling"--thehighestpointinlowmemorytouchedbythebootloader--aslowaspossible,sincesomenewerBIOSeshavebeguntoallocatesomeratherlargeamountsofmemory,calledtheExtendedBIOSDataArea,nearthetopoflowmemory. Thebootloadershouldusethe"INT12h"BIOScalltoverifyhowmuchlowmemoryisavailable.
期望保持内存上限--在低内存的最高点被引导加载程序接触--尽可能的低,因为一些新的BIOSes已经开始分配一些相当大的内存数量,叫做可扩展BIOS的数据区域,在低内存的顶端附近。引导加载程序应该使用"INT12h"BIOS中断调用确定有多大的低内存是可利用的。
Unfortunately,ifINT12hreportsthattheamountofmemoryistoolow,thereisusuallynothingthebootloadercandobuttoreportanerrortotheuser.Thebootloadershouldthereforebedesignedtotakeupaslittlespaceinlowmemoryasitreasonablycan.ForzImageoroldbzImagekernels,whichneeddatawrittenintothe
0x90000segment,thebootloadershouldmakesurenottousememoryabovethe0x9A000point;toomanyBIOSeswillbreakabovethatpoint.
幸运地,如果INT12h中断调用报告内存总量太少,则通常没有引导加载程序能启动并且报告一个错误给用户。因此引导加载程序应该被设计在低内存占用尽量少量的空间。因为zImage或老的bzImage内核,需要数据被写在0x90000段处,引导加载程序应该确保不使用高于0x9A000点的内存;太多的BIOSes将破坏那个点以上的内存。
****THEREAL-MODEKERNELHEADER(实模式内核开头)
Inthefollowingtext,andanywhereinthekernelbootsequence,"asector"refersto512bytes.Itisindependentoftheactualsectorsizeoftheunderlyingmedium.
在下面的文本中,在内核启动顺序的任何地方,“一个扇区”是指512字节。它是下面媒介的实际扇区大小的独立(意思不依赖具体的存储介质,一个扇区都是指512字节)。
ThefirststepinloadingaLinuxkernelshouldbetoloadthereal-modecode(bootsectorandsetupcode)andthenexaminethefollowingheaderatoffset0x01f1.Thereal-modecodecantotalupto32K,althoughthebootloadermaychoosetoloadonlythefirsttwosectors(1K)andthenexaminethebootupsectorsize.
第一步在装载一个linux内核应该被装载实模式代码(bootsector和setup代码)然后检查接下来在偏移0x01f1处的header代码。实模式代码能达到32K,但是引导加载程序可能选择装载仅仅开始的两个扇区(1K)然后检查启动扇区的大小。
Theheaderlookslike:
Header看起来像:
Offset(偏移量)Proto(协议)Name(名字)Meaning(意思)
/Size(大小)
01F1/1 ALL setup_sects Thesizeofthesetupinsectors
(所有)(setup设置扇区的大小)
01F2/2 ALL root_flags Ifset,therootismountedreadonly
如果被设置,root被只读挂载
01F4/2 ALL syssize DONOTUSE-forbootsect.Suseonly
不使用-仅仅被bootsect.S使用
01F6/2 ALL swap_dev DONOTUSE-obsolete
(不使用-已不用的)
01F8/2 ALL ram_size DONOTUSE-forbootsect.Suseonly
不使用-仅仅被bootsect.S使用
01FA/2 ALL vid_mode Videomodecontrol
视频模式控制
01FC/2 ALL root_dev Defaultrootdevicenumber
默认的根设备号
01FE/2 ALL boot_flag 0xAA55magicnumber
0xAA55魔法数字
0200/2 2.00+ jump Jumpinstruction
2.00以上 跳转指令
0202/4 2.00+ header Magicsignature"HdrS"
魔法信号"HdrS"
0206/2 2.00+ version Bootprotocolversionsupported
协议版本 启动协议版本支持
0208/4 2.00+ realmode_swtch Bootloaderhook(seebelow)
实模式转换 引导装载程序钩子(看下面)
020C/2 2.00+ start_sys Theload-lowsegment(0x1000)(obsolete)
开始系统段 低装载段0x1000(已过时)
020E/2 2.00+ kernel_version Pointertokernelversionstring
内核版本 指向内核版本字符串
0210/1 2.00+ type_of_loader Bootloaderidentifier
装载类型 引导装载程序标志
0211/1 2.00+ loadflags Bootprotocoloptionflags
装载标志 引导协议可选标志
0212/2 2.00+ setup_move_size Movetohighmemorysize(usedwithhooks)
Setup移动大小 移动到高内存大小(使用钩子)
0214/4 2.00+ code32_start Bootloaderhook(seebelow)
32位代码启动 引导装载程序钩子(看下面)
0218/4 2.00+ ramdisk_image initrdloadaddress(setbybootloader)
Ramdisk镜像 initrd(初始化跟设备)装载地址(被引导装载程序设置)
021C/4 2.00+ ramdisk_size initrdsize(setbybootloader)
Ramdisk大小 initrd大小(被引导装载程序设置)
0220/4 2.00+ bootsect_kludge DONOTUSE-forbootsect.Suseonly
不使用-仅仅被bootsect.S使用
0224/2 2.01+ heap_end_ptr Freememoryaftersetupend
2.01以上 堆结束指针 setup结束以后是自由内存
0226/2 N/A pad1 Unused
0228/4 2.02+ cmd_line_ptr 32-bitpointertothekernelcommandline
2.02以上 命令行参数指针 32位指向内核命令行参数
022C/4 2.03+ initrd_addr_max Highestlegalinitrdaddress
2.03以上 initrd最大地址 最高合法的initrd地址
Forbackwardscompatibility,ifthesetup_sectsfieldcontains0,therealvalueis4.
为了后面的兼容性,如果setup_sects区域包含0,真实的值是4。
Ifthe"HdrS"(0x53726448)magicnumberisnotfoundatoffset0x202,thebootprotocolversionis"old".Loadinganoldkernel,thefollowingparametersshouldbeassumed:
如果"HdrS"(0x53726448)魔法数字没有在偏移0x202处被找到,启动协议版本是“老的”。装载一个老的内核,下面的参数应该被假设:
Imagetype=zImage 映像内核=zImage
initrdnotsupportedinitrd不被支持
Real-modekernelmustbelocatedat0x90000.实模式内核必须位于0x90000
Otherwise,the"version"fieldcontainstheprotocolversion,e.g.protocolversion2.01willcontain0x0201inthisfield.Whensettingfieldsintheheader,youmustmakesureonlytosetfieldssupportedbytheprotocolversioninuse.
否则,“version”区域包含协议版本,例如协议本版2.01将包含0x0201在这个区域。当设置区域在header中时,你必须确保仅仅设置区域被使用的协议版本所支持。
The"kernel_version"field,ifsettoanonzerovalue,containsapointertoanull-terminatedhuman-readablekernelversionnumberstring,less0x200.Thiscanbeusedtodisplaythekernelversiontotheuser.Thisvalueshouldbelessthan(0x200*setup_sects).Forexample,ifthisvalueissetto0x1c00,thekernelversionnumberstringcanbefoundatoffset0x1e00inthekernelfile.Thisisavalidvalueifandonlyifthe"setup_sects"fieldcontainsthevalue14orhigher.
"kernel_version"字段,如果被设置为一个非零值,包含一个指向(NULL)空结束的人可读的内核版本数字字符串,小于0x200。这个能够被使用显示内核版本给用户看。这个值应该小于(0x200*setup的扇区数)。例如,如果这个值被设置为0x1c00,内核版本数字字符串能够被找到在内核文件偏移0x1e00处。如果并且仅仅如果"setup_sects"字段包含值14或更高这是一个有效值
Mostbootloaderswillsimplyloadthekernelatitstargetaddressdirectly.Suchbootloadersdonotneedtoworryaboutfillinginmostofthefieldsintheheader.Thefollowingfieldsshouldbefilledout,however:
大多数引导装载程序将简单直接的装载内核到它的目的地址。这样引导装载程序不需要担心在header填充很多的字段。然而,下面的字段应该被填充:
vid_mode:PleaseseethesectiononSPECIALCOMMANDLINEOPTIONS.
视频模式:请看特殊的命令行可选部分
type_of_loader:装载类型
Ifyourbootloaderhasanassignedid(seetablebelow),enter0xTVhere,whereTisanidentifierforthebootloaderandVisaversionnumber.Otherwise,enter0xFFhere.
如果你的引导装载程序有一个被指派的id(看下面的表格),进入0xTV这儿,T是一个引导装载程序的标志符,V是一个版本数字。否则,进入0xFF这儿。
Assignedbootloaderids:指派的引导装载程序(以下9种)
0LILO
1Loadlin
2bootsect-loader
3SYSLINUX
4EtherBoot
5ELILO
7GRuB
8U-BOOT
Pleasecontact<hpa@zytor.com>ifyouneedabootloaderIDvalueassigned.
请联系<hpa@zytor.com>如果你需要一个引导装载程序被指派的ID值
loadflags,heap_end_ptr:装载标志,堆结束指针
Iftheprotocolversionis2.01orhigher,entertheoffsetlimitofthesetupheapintoheap_end_ptrandsetthe0x80bit(CAN_USE_HEAP)ofloadflags.heap_end_ptrappearstoberelativetothestartofsetup(offset0x0200).
如果协议版本是2.01或更高,设置setup堆栈的限制到heap_end_ptr(堆结束指针)处和设置0x80位(能够使用堆栈)标志。heap_end_ptr(堆结束指针)显示相对setup的开始(偏移0x0200)。
setup_move_size:setup移动的大小
Whenusingprotocol2.00or2.01,iftherealmodekernelisnotloadedat0x90000,itgetsmovedtherelaterintheloadingsequence.Fillinthisfieldifyouwantadditionaldata(suchasthekernelcommandline)movedinadditiontothereal-modekernelitself.
当使用协议2.00或2.01,如果实模式内核是不装载在0x90000,它在加载序号以后被移动那里。如果你需要额外的数据(例如内核命令行)被移动,那么填充这个字段增加到实模式内核自身。
ramdisk_image,ramdisk_size:内存盘映像,内存盘大小
Ifyourbootloaderhasloadedaninitialramdisk(initrd),setramdisk_imagetothe32-bitpointertotheramdiskdataandtheramdisk_sizetothesizeoftheramdiskdata.
如果你的引导装载程序已经装载一个初始化的内存盘(initrd),设置内存盘映像(ramdisk_image)为一个32位指针指向内存盘数据和设置内存盘大小(ramdisk_size)为内存盘数据的大小。
Theinitrdshouldtypicallybelocatedashighinmemoryaspossible,asitmayotherwisegetoverwrittenbytheearlykernelinitializationsequence. However,itmustneverbelocatedabovetheaddressspecifiedintheinitrd_addr_maxfield. Theinitrdshouldbeatleast4Kpagealigned.
初始化的内存盘(initrd)应该典型地位于尽可能的高的内存,因为它可能被早的内核初始化序列覆盖写。然而,它必须从来不位于在专门化的initrd_addr_max字段以上的地址。初始化的内存盘(initrd)应该被设置至少4K页对齐。
cmd_line_ptr:命令行指针
Iftheprotocolversionis2.02orhigher,thisisa32-bitpointertothekernelcommandline.Thekernelcommandlinecanbelocatedanywherebetweentheendofsetupand0xA0000.Fillinthisfieldevenifyourbootloaderdoesnotsupportacommandline,inwhichcaseyoucanpointthistoanemptystring(orbetteryet,tothestring"auto".)Ifthisfieldisleftatzero,thekernelwillassumethatyourbootloaderdoesnotsupportthe2.02+protocol.
如果协议是2.02或更高,这是一个32位指针指向内核命令行。内核命令行能位于setup结束至0xA0000的任何地方。填充这个字段虽然你的引导装载程序不支持一个命令行,它能使你这个字段指向一个空字符串(或更好,是一个“auto”字符串)如果这个字段被留下在零,内核将假设你的引导装载程序不支持2.02以上的协议。
ramdisk_max:内存盘最大
Themaximumaddressthatmaybeoccupiedbytheinitrdcontents.Forbootprotocols2.02orearlier,thisfieldisnotpresent,andthemaximumaddressis0x37FFFFFF.(Thisaddressisdefinedastheaddressofthehighestsafebyte,soifyourramdiskisexactly131071310722byteslongandthisfieldis0x37FFFFFF,youcanstartyourramdiskat0x37FE0000.)
可能被初始化内存盘内容占用的最大地址。对于引导协议2.02或更早,这个字段是不存在的,并且最大地址是0x37FFFFFF。(这个地址被定义为最高的安全字节,因此如果你的内存盘确切的131072字节长并且这个区域是0x37FFFFFF,你能开始你的内存盘在0x37FE0000)。
****THEKERNELCOMMANDLINE内核命令行
Thekernelcommandlinehasbecomeanimportantwayforthebootloadertocommunicatewiththekernel.Someofitsoptionsarealsorelevanttothebootloaderitself,see"specialcommandlineoptions"below.
内核命令行已近是改变引导装载程序和内核通信的一种重要方式。一些它的可选项也是有关于引导装载程序自身的,看下面的“特殊的命令行可选项”。
Thekernelcommandlineisanull-terminatedstringupto255characterslong,plusthefinalnull.
内核命令行是一个NULL(空)终止的加上最后的null到达255个字符长度的字符串。
Ifthebootprotocolversionis2.02orlater,theaddressofthekernelcommandlineisgivenbytheheaderfieldcmd_line_ptr(seeabove.)
如果引导协议版本是2.02或更晚,内核的命令行地址被header字段cmd_line_ptr给出(看上面)。
Iftheprotocolversionis*not*2.02orhigher,thekernelcommandlineisenteredusingthefollowingprotocol:
如果协议版本不是2.02或更高,内核命令行被输入使用下面的协议:
Atoffset0x0020(word),"cmd_line_magic",enterthemagicnumber0xA33F.
在偏移0x0020(字),“cmd_line_magic”,输入魔法数字0xA33F。
Atoffset0x0022(word),"cmd_line_offset",entertheoffsetofthekernelcommandline(relativetothestartofthereal-modekernel).
在偏移0x0022(字),"cmd_line_offset",输入内核命令行的偏移量(与实模式内核开始有关)
Thekernelcommandline*must*bewithinthememoryregioncoveredbysetup_move_size,soyoumayneedtoadjustthisfield.
内核命令行必须在被setup_move_size内存区域大小覆盖以内,因此你可能需要调整这个字段。
****SAMPLEBOOTCONFIGURATION引导程序配置样例
Asasampleconfiguration,assumethefollowinglayoutoftherealmodesegment:
作为一个样例配置,假设实模式段有下面的布局:
0x0000-0x7FFF Realmodekernel实模式内核
0x8000-0x8FFF Stackandheap栈和堆
0x9000-0x90FF Kernelcommandline内核命令行
Suchabootloadershouldenterthefollowingfieldsintheheader:
如此一个引导装载程序应该进入下面字段,在header中。
unsignedlongbase_ptr; /*baseaddressforreal-modesegment*/实模式的段地址
if(setup_sects==0){
setup_sects=4;
}
if(protocol>=0x0200){
type_of_loader=<typecode>;
if(loading_initrd){
ramdisk_image=<initrd_address>;
ramdisk_size=<initrd_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{
/*Veryoldkernel*/
cmd_line_magic =0xA33F;
cmd_line_offset=0x9000;
/*AveryoldkernelMUSThaveitsreal-modecode
loadedat0x90000*/一个老的内核必须有它的实模式代码装载在0x90000
if(base_ptr!=0x90000){
/*Copythereal-modekernel*/复制实模式内核
memcpy(0x90000,base_ptr,(setup_sects+1)*512);
/*Copythecommandline*/复制命令行
memcpy(0x99000,base_ptr+0x9000,256);
base_ptr=0x90000; /*Relocated*/重映射
}
/*Itisrecommendedtoclearmemoryuptothe32Kmark*/它要求清除内存到32K标志
memset(0x90000+(setup_sects+1)*512,0,
(64-(setup_sects+1))*512);
}
****LOADINGTHERESTOFTHEKERNEL(装载剩余的内核部分)
Thenon-real-modekernelstartsatoffset(setup_sects+1)*512inthekernelfile(again,ifsetup_sects==0therealvalueis4.)Itshouldbeloadedataddress0x10000forImage/zImagekernelsand0x100000forbzImagekernels.
非实模式内核开始在内核文件偏移(setup_sects+1)*512处(重复一下,如果setup_sects==0真实值是4)。作为Image/zImage它应该被装载在地址0x10000,作为bzImage它应该被装载在地址0x100000
ThekernelisabzImagekerneliftheprotocol>=2.00andthe0x01bit(LOAD_HIGH)intheloadflagsfieldisset:
如果协议大于等于2.00并且在装载标志(loadflags)字段的0x01位(高装载)被设置,则内核是一个bzImage(大模式内核)。
is_bzImage=(protocol>=0x0200)&&(loadflags&0x01);//伪代码表示
load_address=is_bzImage?0x100000:0x10000;//伪代码表示
NotethatImage/zImagekernelscanbeupto512Kinsize,andthususetheentire0x10000-0x90000rangeofmemory.Thismeansitisprettymucharequirementforthesekernelstoloadthereal-modepartat
0x90000.bzImagekernelsallowmuchmoreflexibility.
注意thatImage/zImage(小模式内核)能够到达512K大小,因此使用整个0x10000-0x90000内存区域。这意味着对这些内核它是相当多的要求来装载实模式部分在0x90000。bzImage内核允许更多的灵活性。
****SPECIALCOMMANDLINEOPTIONS(特殊的命令行可选项)
Ifthecommandlineprovidedbythebootloaderisenteredbytheuser,theusermayexpectthefollowingcommandlineoptionstowork.Theyshouldnormallynotbedeletedfromthekernelcommandlineeven
thoughnotallofthemareactuallymeaningfultothekernel.BootloaderauthorswhoneedadditionalcommandlineoptionsforthebootloaderitselfshouldgetthemregisteredinDocumentation/kernel-parameters.txttomakesuretheywillnotconflictwithactualkerneloptionsnoworinthefuture.
如果被引导装载程序提供的命令行被用户输入,用户可能期望根据下面的命令行的可选项来运行。通常不应该从内核命令行删除他们,即使不是所有的他们对内核来说都有实际上的意义。针对引导装载程序自身的需要额外的命令行可选项的引导装载程序作者应该从注册在Documentation/kernel-parameters.txt这个文件中得到他们,来确保他们将不会和现在或将来的实际的内核可选项产生冲突。
vga=<mode>VGA=《模式》(也就是显卡模式配置)
<mode>hereiseitheraninteger(inCnotation,eitherdecimal,octal,orhexadecimal)oroneofthestrings
"normal"(meaning0xFFFF),"ext"(meaning0xFFFE)or"ask"(meaning0xFFFD).Thisvalueshouldbeenteredintothevid_modefield,asitisusedbythekernelbeforethecommandlineisparsed.
<模式>这儿不是一个整数(在C语言中的记号,不是十进制,八进制,就是十六进制)就是一个字符串“正常”(0xFFFF代表的意义),“ext”(0xFFFE代表的意义),“ask”(0xFFFD代表的意义)。这个值应该被输入视频模式(vid_mode)字段,在命令行被解析以前被内核使用。
mem=<size>
<size>isanintegerinCnotationoptionallyfollowedbyK,MorG(meaning<<10,<<20or<<30).Thisspecifiestheendofmemorytothekernel.Thisaffectsthepossibleplacementofaninitrd,sinceaninitrdshouldbeplacednearendofmemory.Notethatthisisanoptionto*both*thekernelandthebootloader!
在C语言的表示<size>是随意地跟着K,M或G的一个整数(意思左移10,20,30位),这指定内核的内存末端。这可能影响的地方是一个初始化的内存盘(initrd),因为初始化的内存盘(initrd)应该被放置在内存末端的附近。注意在内核(kernel)和引导装载程序(bootloader)都是一个可选项。
initrd=<file>
Aninitrdshouldbeloaded.Themeaningof<file>isobviouslybootloader-dependent,andsomebootloaders(e.g.LILO)donothavesuchacommand.
这个初始化的内存盘应该被装载。<file>的意思明显是依赖于引导装载程序(bootloader),并且一些引导装载程序(bootloader)(像LILO)没有如此的一个命令。
Inaddition,somebootloadersaddthefollowingoptionstotheuser-specifiedcommandline:
另外,一些启动装载程序增加以下选择项到用户指定的命令行:
BOOT_IMAGE=<file>
Thebootimagewhichwasloaded.Again,themeaningof<file>isobviouslybootloader-dependent.
被装载的引导镜像。再一次,<file>的意思明显是依赖于引导装载程序(bootloader)。
Auto(自动)
Thekernelwasbootedwithoutexplicituserintervention.
内核被引导没有明显的用户交互。
Iftheseoptionsareaddedbythebootloader,itishighlyrecommendedthattheyarelocated*first*,beforetheuser-specifiedorconfiguration-specifiedcommandline.Otherwise,"init=/bin/sh"getsconfusedbythe"auto"option.
如果这些选择项由启动装载程序增加,在用户指定或配置指定的命令行之前我们极力推荐他们是被第一个被找出的。否则,“init=/bin/sh”由“自动”选项拒绝。
****RUNNINGTHEKERNEL运行内核
Thekernelisstartedbyjumpingtothekernelentrypoint,whichislocatedat*segment*offset0x20fromthestartoftherealmodekernel.Thismeansthatifyouloadedyourreal-modekernelcodeat0x90000,thekernelentrypointis9020:0000.
内核跳转到位于的内核入口点被启动的,从实模式内核开始的地址处段偏移0x20。这意味着如果您加载您的实时模式内核代码在0x90000,内核入口点是9020:0000。
Atentry,ds=es=ssshouldpointtothestartofthereal-modekernelcode(0x9000ifthecodeisloadedat0x90000),spshouldbesetupproperly,normallypointingtothetopoftheheap,andinterruptsshouldbedisabled.Furthermore,toguardagainstbugsinthekernel,itisrecommendedthatthebootloadersetsfs=gs=ds=es=ss.
在入口,ds=es=ss应该指向实模式内核代码开始的地方(如果代码被装载在ox90000处就是0x9000),SP(堆栈指针)的开始应该适当地设定,通常指向堆的顶端,并且所有的中断应该被禁止。此外,为了在内核控制产生错误(bugs),建议启动装载程序设置fs=gs=ds=es=ss。
Inourexamplefromabove,wewoulddo:
在来至上面我们的例程,我们应该做:
/*Note:inthecaseofthe"old"kernelprotocol,base_ptrmustbe==0x90000atthispoint;seetheprevioussamplecode*/
注意:在老内核协议的情况下,在base_ptr这一点必须是在0x90000,看以前样例代码
seg=base_ptr>>4;
cli(); /*Enterwithinterruptsdisabled!*/禁止中断
/*Setupthereal-modekernelstack*/建立实模式内核堆栈
_SS=seg;
_SP=0x9000; /*LoadSPimmediatelyafterloadingSS!*/在装载了SS(堆栈段)以后立即装载堆栈指针(SP)
_DS=_ES=_FS=_GS=seg;
jmp_far(seg+0x20,0); /*Runthekernel*/运行内核
Ifyourbootsectoraccessesafloppydrive,itisrecommendedtoswitchoffthefloppymotorbeforerunningthekernel,sincethekernelbootleavesinterruptsoffandthusthemotorwillnotbeswitchedoff,especiallyiftheloadedkernelhasthefloppydriverasademand-loadedmodule!
如果您的引导扇区访问(软盘)磁盘驱动器,推荐在运行内核之前关闭马达。因为内核引导停止中断,因此电机将不会关闭,特别是如果在加载的内核有软盘驱动程序作为需求加载的模块!
****ADVANCEDBOOTTIMEHOOKS先进的启动时间挂钩
Ifthebootloaderrunsinaparticularlyhostileenvironment(suchasLOADLIN,whichrunsunderDOS)itmaybeimpossibletofollowthestandardmemorylocationrequirements.Suchabootloadermayusethefollowinghooksthat,ifset,areinvokedbythekernelattheappropriatetime.Theuseofthesehooksshouldprobablybe
consideredanabsolutelylastresort!
如果你的引导装载程序运行在一个特别的不稳定的环境中(例如LOADIN,运行在DOS之下)它可能不能按照标准内存位置的要求。因为一个引导装载程序可能使用下面那样的钩子,如果设置,被内核在合适的时间调用。使用这些钩子可能应考虑一个绝对最后的手段。
IMPORTANT:Allthehooksarerequiredtopreserve%esp,%ebp,%esiand%ediacrossinvocation.
重要:所有在调用的钩子要求保护esp寄存器,ebp寄存器,esi寄存器和edi寄存器
realmode_swtch:实模式切换
A16-bitrealmodefarsubroutineinvokedimmediatelybeforeenteringprotectedmode.ThedefaultroutinedisablesNMI,soyourroutineshouldprobablydoso,too.
在进入保护模式以前16位实模式远子程序立即调用。默认例程禁止NMI(不可屏蔽中断),因此你的例程也应该可能这样做。
code32_start:32位代码开始
A32-bitflat-moderoutine*jumped*toimmediatelyafterthetransitiontoprotectedmode,butbeforethekernelisuncompressed.Nosegments,exceptCS,aresetup;youshouldsetthemuptoKERNEL_DS(0x18)yourself.
在过渡到保护模式以后立即跳转到一个32位的线性平板模式运行路线,但是在内核被解压之前。除了CS代码段是没有段被建立;你应该建立你自己的内核数据段(KERNEL_DS)(0x18)。
Aftercompletingyourhook,youshouldjumptotheaddressthatwasinthisfieldbeforeyourbootloaderoverwroteit.
在完成您的勾子以后,您应该跳到在这个字段的地址,在您的启动装载程序重写它之前。