ImageVerifierCode 换一换
格式:DOCX , 页数:8 ,大小:18.85KB ,
资源ID:10452575      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/10452575.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(探本溯源.docx)为本站会员(b****8)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

探本溯源.docx

1、探本溯源探本溯源 在前文结尾处我们提到内核映像的加载是由专用的bootloader比如LILO或是GRUB来实现的,而在x86架构下Linux内核通常使用其中之一的GRUB,它通过执行initrd文件来识别内核映像所在的文件系统进而执行加载,然而有一个需要注意的问题是,并非所有的物理地址空间对内核而言都是可用的,比如其中的某个物理地址范围可能被映射为I/O设备的共享内存,也可能其中的一个物理页框存放着BIOS数据,综合上述原因,GRUB必须建立一个物理地址映射来将内核加载至可用的物理内存中,而建立映射的这一过程则是根据协议完成的,不仅如此,实模式下的内核代码能够占用的内存空间,以及初始化过程中

2、用来建立堆栈的物理内存大小都需要遵守相关的启动协议,有关LINUX/x86启动协议的详细信息可参考Documentationx86目录下的boot.txt文件,该文件还详细解释了header.S中所定义的全局变量hdr的各个字段的含义,而其重要性单从源文件中各个字段后的注释规模便可见一斑。物理内存布局在深入剖析源代码之前,我们有必要首先明确启动阶段物理内存的分布情况,因为只有明白了执行过程背后所依据的一些基本事实才能对源代码有更为深刻的认识,而其中的一些事实源于软硬件的高速发展,另外一些则是为了满足兼容性的要求。总的来说,内核映像由三部分构成,它们分别是:一个512字节的启动扇区Kernel

3、boot sector,也即在前文中所剖析的Linux内核自带的bootloader,但由于现在使用的bootloader为GRUB,为了避免产生歧义,所以冠以另外一个名称。该boot sector占用操作系统映像所在逻辑分区的第一个扇区,注意从bootsect的偏移0x1f1处开始存放hdr变量。实模式下的内核安装部分Kernel setup,连续占用若干个扇区大小的内存空间,主要用于检测硬件环境并执行一系列的初始化,为保护模式下内核代码的运行完成一些前期的准备工作。保护模式下的内核代码,GRUB将其加载至从地址0x10 0000开始的物理内存中。这里要注意的是实模式下的Kernel boo

4、t sector和Kernel setup虽然从逻辑上被分成两部分,但它们的分布是连续的,并且这两部分都处于第一个1MB的物理内存空间中,而其上所提到的保护模式下的内核代码的初始地址为0x10 0000,表示这部分代码从物理内存的第二个1MB开始安装,因此内核映像的实模式及保护模式这两个部分的分界线即物理地址0x10 0000。这里要特别注意的一点是,GRUB不可能单独在实模式下完成上述加载任务,因为在实模式下CPU只能寻址第一个1MB范围内的物理内存空间(原因请参见处理器体系结构及寻址模式一文)。有意思的是,在GRUB的次引导过程执行时将会临时性地切换到保护模式,完成内核映像的加载后再次回到

5、实模式。因此虽然引导加载过程有两种模式的来回切换操作,但对于内核映像来说却是透明的,当控制权转交给内核后,它仍然首先从实模式下开始运行,但此时并不意味着超出第一个1MB范围的物理内存中没有任何内容,只是这些内容占用的内存空间无法被内核当前执行的指令所寻址,这使得保护模式下的内核代码不会被随意修改,也算是对保护模式中“保护”一词的另类诠释。以下是GRUB将内核映像加载至内存空间后的分布图:图1上图同样位于Documentationx86目录下的boot.txt中。在该文件中还展示了由zImage内核映像所使用的传统内存映射模型,但我们并不过多关注这类历史遗留问题,在后续的代码剖析过程中均以现阶段

6、所使用的一些模型作为基准。在前文结尾处曾提到过BIOS例程将内核放入低地址0x0001 0000(小内核映像zImage)或者从高地址0x00100000(大内核映像bzImage)开始的RAM中,而现阶段所使用的Linux内核均编译为bzImage,因此保护模式下的内核代码被安装在从高地址0x0010 0000开始的RAM中。正如上图所示,我们也可以看到在完成POST以及一系列的初始化工作后,BIOS将bootloader加载至物理地址0000 7c00处。而令人困惑的是,内核的启动扇区bootsect的起始地址并未被严格限制,这其实是由于Linux内核允许使用多种bootloader所导致

7、的,比如前文所提到的LILO以及GRUB,在现实情况中存在更多不同类型的bootloader,不同的bootloader可能将实模式的起始地址加载至不同的位置,然而在x86架构下的GRUB设置的起始地址正是0x90000。另外我们也可以看到实模式下的内核代码以及该代码所创建的堆栈的大小至多为8KB,之所以需要创建堆栈是为了提供C语言的运行环境,因为代码的执行过程需要使用栈来保存局部变量,函数调用则需要借助栈来传递参数以及保存返回地址,其中还有可能涉及到动态内存的分配,以及将内存分配给内核命令行。这样一来,实模式下的内核代码需要使用的内存空间将会达到8KB*2=16KB,而该段的起始地址为0x9

8、0000,因此这段内存空间的结尾处的地址至多将会达到0xA 0000。而这是不允许,因为现代机器中的许多BIOS例程需要使用从起始地址0x9 A000开始的额外内存空间,该内存空间即扩展的BIOS数据区(Extended BIOS Data Area,EBDA)。若内核被GRUB安装至较高的内存空间,那么执行代码将被BIOS修改。事实上实模式下的Linux内核正是基于这一原则所设计的,我们将在后文的源代码剖析过程中看到其具体的实现细节。我们在前文提到过,代码背后所依据的某些事实是为了满足历史遗留问题所提出的兼容性要求,这一点可从上图中物理地址范围0xA 00000x10 0000的内存占用情况

9、得知。追溯至上世纪80年代,当时IBM所推出的第一台PC机可供寻址的物理内存总共为1MB。而这1MB中的低640KB供DOS以及应用程序使用,而高端的384KB则被留作它用,其中低端的640KB被称为常规内存,高端的384KB则被称为保留内存,这两种不同的内存类型通过物理地址0xA0000得以分隔,此后这个分界线便被确定下来并沿用至今。简单总结一下,在x86体系结构中,RAM的第一个1MB内存空间包含如下两个“独特”的地方:物理地址0x00000x1000以及0x9 A0000xA 0000所占内存由BIOS使用,存放加电自检(Power-On Self-Test,POST)期间检查到的系统硬

10、件配置。有些类型的BIOS甚至在系统初始化之后依然将数据写入该内存。从0xA 00000x10 0000范围内的物理内存通常保存BIOS例程,并且映射ISA图形卡上的内部内存。这个区域就是IBM兼容PC上从640KB到1MB之间的著名的洞图1中的I/O memory hole:物理地址存在但被保留,不能由操作系统使用。内核将上述地址范围的物理内存所占页框标记为保留,它们连同内核代码以及已初始化或未初始化的内核数据一起,在整个机器的执行周期中常驻内存,而绝不能被动态分配或由内核调度程序交换到磁盘上。图2上图形象地显示了常驻物理内存中各个区域的使用情况,需要注意的一点是保护模式下的内核代码所占页框

11、的总数依赖于对应的配置方案,因此上图中与之对应的区域只是用符号简单的加以表示。而实模式下的内核代码仅在启动期间执行硬件检测及一系列初始化操作之后便不再被使用,因此当实模式下的内核代码跳转到保护模式之后,这部分内存空间即可由内核代码用于其他用途。实模式下内核的初始化变量安装头(setup header)该安装头为从Kernel boot sector中偏移0x1f1处开始的hdr变量,主要存放初始化期间将会使用到的一些数据。我将把该变量中各个字段的含义集中罗列在这里,在后文中讲到内核执行初始化过程中使用到这些数据时不再单独详细描述。另外要注意的是有些字段的存在同样属于历史遗留性问题,对于这些内容

12、我们直接一带而过。下表是这些字段的概要说明:偏移量/大小字段名含义0x1F1/1setup_sects表示Kernel setup中的代码所占用的物理存储空间0x1F2/2root_flags如果被设置,则根以可读形式挂载0x1F4/4syssize32位代码的大小,该值以16字节的段为单位0x1F8/2ram_size不再使用仅由bootsect.S文件使用(已被废弃)0x1FA/2vid_mode视频模式控制0x1FC/2root_dev默认根设备号0x1FE/2boot_flag魔数,其值为常量0xAA55,标识有效引导记录结尾的标签0x200/2jump跳转指令0x202/4heade

13、r魔数标签,其值为HdrS0x206/2version启动协议版本支持0x208/4realmode_swtch引导加载程序钩子0x20C/2start_sys_seg加载低地址段(已被废弃)0x20E/2kernel_version指向内核版本字符串的指针0x210/1type_of_loader引导加载程序标识符0x211/1loadflags引导协议选项标志0x212/2setup_move_size移动至高位内存所需的大小(已被废弃)0x214/4code32_start引导加载程序钩子0x218/4ramdisk_imageinitrd加载地址0x21C/4ramdisk_sizei

14、nitrd的尺寸0x220/4bootsect_kludge不再使用仅由bootsect.S使用(已被废弃)0x224/2heap_end_ptr在setup尾部之后的空闲内存0x226/1ext_loader_ver扩展的引导加载程序版本0x227/1ext_loader_type扩展的引导加载的ID0x228/4cmd_line_ptr指向内核命令行的32位指针0x22C/4ramdisk_maxinitrd可用的最高地址0x230/4kernel_alignment对内核要求的物理地址对齐0x234/1relocatable_kernel内核是否可重定位0x235/1min_alignment最小对齐,其值要求为2的平方0x236/2pad3不再使用(已被废弃)0x238/4cmdline_size内核命令行的最大尺寸0x23C/4hardware_subarch硬件子架构0x240/8hardware_subarch_data特定子架构的数据0x248/4payload_offset内核负载偏移0x24C/4payload_length内核负载的长度0x250/8setup_data指向存放setup_data结构体的链表的64位物理指针0x258/8pref_address首选的加载地址0x260/4init_size初始化期间的线性地址要求

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1