精华内容
下载资源
问答
  • 要想在安卓手机上获得root权限,通常需要解锁引导加载程序,禁用手机的签名验证,这样的话,我们就可以部署一个修改过的安卓引导映像了。在Qualcomm芯片组上,这是一个标准化的过程,可以使用安卓引导加载程序中的...

    本文是我们在DEF CON
    29大会上的演示视频的配套文章,视频的链接地址为https://www.youtube.com/watch?v=z4gIxdFfJDg。

    要想在安卓手机上获得root权限,通常需要解锁引导加载程序,禁用手机的签名验证,这样的话,我们就可以部署一个修改过的安卓引导映像了。在Qualcomm芯片组上,这是一个标准化的过程,可以使用安卓引导加载程序中的命令来执行解锁。智能手机制造商经常修改引导加载程序以增加特定的限制,但是,这通常要求使用他们自家的工具。

    这些自定义的限制通常包括:强迫创建一个用户账户来请求解锁,并在允许解锁之前强制等待一段时间,等等。

    那么,手机制造商为什么要添加这些限制呢?原因如下所示:

    ◼ 防止没有经验的用户因为受骗而削弱手机的安全性;

    ◼ 防止第三方在售前给设备加载恶意软件(如供应链攻击);

    ◼ 制造商可以跟踪是谁解锁了他们的引导加载程序。

    我购买的手机就有这些限制,要求我等待七天后才能获得设备的root权限。由于这个原因,我决定调查我是否可以绕过同一制造商生产的旧智能手机的等待期。我给自己设定了一个挑战,即在七天等待期结束前绕过引导加载程序的保护。

    在这里插入图片描述

    标准绕过方法

    实际上,现在已经有一些标准方法可以绕过这些限制,然而,它们都具有相应的风险。

    其中,最常用的方法就是进入高通公司紧急下载模式。这是一种低级别的紧急状态启动模式,可以使用诊断工具将具有签名的“加载器”有效载荷上传至芯片,这样,就可以直接修改设备的分区了。虽然这种方法是有效的,但这要求用户先引导进入该模式(并非所有用户都可以直接进入该模式),并且需要访问可能无法用于该设备的已签名加载程序ELF文件。

    第二种常见的方法是在硬件层面上攻击设备。通过拆卸手机,并连接电路板上的EMMC芯片,就能在配置分区中设置“解锁”位,从而获得解锁权限。现在,已经有一些这方面的公开资料,其中说明了应该连接到哪些引脚,但是这通常需要一些硬件知识和动手能力。此外,硬件一旦受到物理损坏,手机就可能永远变砖了。

    因此,我可不想使用这两种方法,相反,我的目标是攻击第二阶段的引导加载程序。这是因为,虽然通过第一阶段的引导加载程序可以进入紧急下载模式,但是在引导过程的下一个阶段,却可以获得额外的诊断和管理工具。

    SDM660安卓手机

    目标设备是2017年发布的一款中档手机,它使用Qualcomm Snapdragon 660作为核心芯片组。

    对制造商实现的自定义解锁功能的分析表明,它会将一个较小的唯一值从手机发送到解锁工具,并在其服务器上生成一个签名。七天后,这个签名将被发送到手机上并进行验证,从而完成解锁。我是借助于Windows主机和USBPCAP USB分析软件对这个过程进行分析的。

    在这里插入图片描述
    我发现,对唯一值的请求、签名的发送以及对引导加载程序解锁的请求,都是通过安卓引导加载程序的Fastboot界面完成的。通过手机上的ADB重新启动到引导加载程序模式,或者在启动时按住音量下降键,就可以访问这个界面。然后,我们可以使用命令行工具“fastboot”,通过USB访问该界面。
    在这里插入图片描述

    Fastboot工具

    这个工具能够简化对标准和定制的功能的访问,包括闪存分区、获得OEM特定的数据,或引导至不同的模式。对这个工具的分析表明,fastboot协议非常简单,可以用基本的C++代码和LibUSB进行实现。
    在这里插入图片描述
    在这里插入图片描述
    分析表明,这个工具的所有的命令都是通过一个USB端点以ASCII文本形式发送的,而对命令的响应则是由另一个端点异步发送的。同时,虽然可以借助于某些程序库来简化对fastboot界面的访问,但是,我还是决定使用LibUSB,因为这样能够更好地控制通信过程。

    ABL引导加载程序

    实际上,fastboot界面是由安卓引导加载程序提供的,它属于第二阶段的引导加载程序,存储在手机的“abl”分区中。这个引导加载程序的作用,就是验证和加载手机的安卓映像和恢复映像,以实现其标准功能,或接收fastboot命令。需要说明的是,这个引导加载程序的高通版本是完全开源的,以便于手机制造商对其进行修改。
    在这里插入图片描述
    由于我想攻击这个引导加载程序,所以,我希望从底层分析其功能。另外,由于手机制造商添加的自定义命令不会出现在源代码中,所以,我决定直接分析编译后的引导加载程序。为此,我们可以下载最新的OTA更新文件,然后解压缩,并访问存储在其中的“abl.img”文件,这样,我们就能够访问手机“abl”分区的内容了。通过对这个映像进行分析发现,虽然这是一个ELF文件,但是其中并没有包含任何可执行代码。

    相反,通过文件分析工具“binwalk”对该文件的分析结果表明,该ELF文件包含一个EFI系统分区。这是一种用于在嵌入式和非嵌入式设备上启动操作系统的标准格式,并且,我们可以使用“uefi-firmware-parser”工具将其提取出来。

    在这里插入图片描述
    实际上,存储在其中的“LinuxLoader”文件是一个PE格式的可执行文件,其内容就是引导加载程序的代码。这种标准的格式可以直接加载到IDA中,并进行反汇编。

    对该引导加载程序的简单分析表明,所有的fastboot命令都存储在一个表中,该表由ASCII命令和该命令的函数回调组成。通过这个表,不仅可以快速分析任何潜在的隐藏命令,同时,还有助于分析具体的功能。我们还发现,该引导加载程序中包含大量的调试字符串,这使得对代码的理解更加容易。
    在这里插入图片描述
    我的主要目标是找到一个内存损坏漏洞,以便通过它绕过解锁限制。为此,我决定把重点放在“flash:”命令上。我之所以选择这个命令,是因为它需要从PC主机接收大型有效载荷,并将其保存到闪存设备分区。

    传统上,当引导加载程序被锁定时,“flash:”命令是不允许对设备上的分区执行写操作的,但是我注意到,制造商已经修改了他们的引导加载程序,以允许在锁定状态下刷写特定的、自定义的分区。由于这些分区对上传的数据进行了额外的解析,因此,这就增加了存在缺陷的可能性。

    在这里插入图片描述
    因为我是从逆向工程的角度来研究fastboot协议的,而不是通过阅读文档来了解它的,因此,我对数据上传的方式做了一些假设。上传的正确顺序如下所示:

    ◼download:< payload size >

    ◼< send full payload >

    ◼flash:< partition >

    但是,我尝试的是以下顺序:

    ◼flash:< partition >

    ◼< send payload >

    除此之外,我在代码中的这个序列后面,故意放入了一个额外的“flash:”命令。因此,当运行这个序列时,将导致引导加载程序在执行第二个“flash:”命令后发生崩溃,从而导致USB接口不再接收任何命令。

    崩溃分析

    将设备从USB端口上拔下来,再插回去,我们发现它就不再通过USB进行枚举了,这意味着它完全无法正常工作了。按住电源和音量减弱按钮10秒钟,导致硬重启,我们发现上述操作并没有对设备产生永久性的损坏。

    为了确认我偶然发现的是一个有效的缓冲区溢出,我决定尝试一个较小的有效载荷大小。我从一个10兆字节的有效载荷开始,并尝试用4千字节的有效载荷进行同样的序列。这个较小的有效载荷并没有使手机崩溃,它继续正常运行。

    在阅读了如何在fastboot中使用“download:”命令上传数据之后,我猜测可能是发生了缓冲区溢出,因为我发送的大量有效载荷被视为fastboot命令,而不是要上传的分区。这意味着崩溃是由于高通引导加载程序的命令处理功能的漏洞所致,而不是由手机制造商实现的任何自定义功能所致。

    为了确认我偶然发现的是一个有效的缓冲区溢出漏洞,我决定尝试一个较小的有效载荷长度。我从一个10兆字节的有效载荷开始,并尝试了长度为4千字节的相同序列的有效载荷。这个较小的有效载荷并没有导致手机崩溃,相反,手机一切正常。

    由于较小的有效载荷不会导致崩溃,所以,我选择进行二分搜索,以确定不会使手机崩溃的最大有效载荷。我把要发送的有效载荷的长度设为最小值和最大值之间的中间值,然后更具手机是否崩溃,来减少有效载荷长度的最大值,或增加有效载荷长度的最小值。这使我找到了不会使设备崩溃的最大有效载荷,其长度为0x11bae0(1161952)字节。

    由于这是一个不寻常的内存大小,这让我相信这肯定是某种类型的缓冲区溢出,然而,由于我无法接触到内部硬件,无法进行调试,对内存的映射情况一无所知,所以,具体是哪种类型的溢出,我还是拿不准。另外我注意到,引导加载程序使用随机值实现了堆栈金丝雀,这意味着如果我溢出堆栈并击中了金丝雀,那么,这种溢出漏洞很可能是无法利用的。
    在这里插入图片描述
    我决定发送一个长度为0x11bae1(1161953)字节的有效载荷,并将最后一个字节的值从0x00递增为0xff。如果手机没有因为其中某个特定的值而崩溃,那就说明并没有碰到堆栈金丝雀,而是找到了序列中的下一个字节。在这个位置,我们发现有效字节的值是0xff。

    通过不断地循环加电,寻找有效的字节值,然后移动到序列中的下一个字节,就可以生成该位置上内存中数据的合理表示。当然,它不一定是准确的数据,但会足够接近,并且不会使引导加载程序崩溃。一旦生成这个序列,就有可能使用它来在引导加载程序中执行代码,但是如果不能自动化的话,这将是一个非常漫长的过程。

    实现自动循环加电

    实际上,加电循环的自动化可以通过拆除手机电池,使用主机PC供电,并使用USB继电器不断切断电源来实现自动化,但这需要拆卸手机并去除外壳周围的胶水。另外,如果我拆解手机,我可以直接进入EMMC,用基于硬件的方法解锁引导加载程序。

    在寻找解决方案的时候,我不断按住手机的电源和音量下降按钮。这导致手机处于引导循环状态:它将重新启动并加载引导加载程序几秒钟,然后再次重新启动。我注意到,在这个过程中,USB接口会工作一段时间,并且这段时间足以让我发送fastboot命令。

    于是,我在导致引导循环的两个按钮上缠了一条发带,并发现这种方法非常管用,所以,这样就实现了这一过程的自动化。

    在这里插入图片描述
    然后,我修改了自己编写的fastboot工具,以便于内存转储。它将等待USB接口出现,尝试这个序列,然后验证引导加载程序是否崩溃,以及是否收到了 “Flashing is not allowed ”响应。我们对这两件事情进行了验证,因为这更有可能获得准确的内存转储。每次尝试都需要10-30秒,这意味着内存转储将需要一段时间。
    在这里插入图片描述
    于是,我让手机连夜尝试这种内存转储方法,并发现了0x34字节不会导致引导加载程序发生崩溃的数据:

    FF 43 02 51 60 02 00 0C 60 02 00 0C 60 02 00 0C 60 02 00 0C E8 00 00 B0 34 00 00 10 01 00 00 0A 08 0D 40 F9 00 00 00 08 C0 00 04 0B 60 02 00 0A D3 9F FF 97

    我注意到其中有许多重复的值,但这些值与默认的堆栈金丝雀值0xC0C0C0C0并不一致,这意味着它们可能是不相关的。另外,这些数据看起来并不像在堆栈中常见的东西,但是我们发现每个32位的字都是一个有效的ARM64操作码。
    在这里插入图片描述
    这些操作码中的大多数虽然有效,但不一定与引导加载程序中的操作码相同,但是所有的堆栈管理和分支操作必须相当准确,这样引导加载程序才不会崩溃。我试图利用IDA在引导加载程序的反汇编代码中搜索“Sub WSP”和“BL”指令,但是,并没可有找到它们。

    当然,导致这种情况的原因有多种。例如,ARM64操作码通常具有相同或类似的功能,即使操作码中的位被翻转,寄存器也可以在32位(Wx)和64位(Xx)模式下被访问,同时,分支指令也可能带有某些条件,而现在蛮力攻击恰好无法满足这些条件。

    由于这些外观上的差异,我决定尝试寻找类似的操作码,选择我已经确定的“BL”指令,因为这依赖于相对寻址,而且地址必须相当相似,才能正确执行分支。我对操作码的32位值进行了文本搜索,但删除了第一个四位组。这样的话,就可以在前面试图刷写到那个分区的解析器中寻找类似的分支,并确定了一条有效的指令。
    在这里插入图片描述
    对其他操作码的进一步检查表明,这些操作也极其相似。这意味着,我的引导加载程序缓冲区的溢出内容正在覆盖缓冲器溢出本身。这也意味着引导加载程序是从EFI文件系统中提取并从RAM中执行的。

    对所用地址的进一步分析表明,引导加载程序代码在0x101000字节之后被覆盖了,并允许使用从PE可执行文件中提取的代码覆盖整个引导加载程序,即用引导加载程序覆盖其自身。这样做的好处是可以防止随后的崩溃,并可以通过修补引导加载程序本身来修改所需的任何功能,包括引导加载程序的解锁代码。
    在这里插入图片描述

    解锁引导加载程序

    找到引导加载程序代码是为了验证解锁工具提供的RSA签名,以便进行解锁。我想跳过这个验证,直接进行解锁。我注意到引导加载程序的解锁功能是通过转移并连接指令(Branch and Link instruction)实现的,它是由编译器为函数调用而生成的,因此,我决定修改最初用于缓冲区溢出的代码,直接跳转到这个指令。我为它生成了正确的相对地址,并使用一个在线ARM64编译器生成了适当的BL指令。然后,我把它添加到引导加载程序中,以实现这个跳转。
    在这里插入图片描述
    虽然很难调试这个过程,但成功解锁是显而易见的:手机会重新启动,擦除用户数据分区,并引导至解锁状态。这说明该方法的确是有效的,因为设备成功解锁了。

    漏洞的影响

    现在,我可以在不借助制造商的工具的情况下,对我的旧手机进行刷机,也不必等待七天。然而,试图对较新的设备进行类似的攻击是无效的。因此,我认为它只适用于基于SDM660的设备。

    当然,如果对引导加载程序进行额外的修补的话,则可以实现更多的功能,例如为调试目的从设备上转储一些有限的RAM,但是由于引导加载程序可以访问的RAM区域是受限的,所以,这无法实现冷启动攻击。

    此外,高通芯片还可以对手机的“userdata”分区进行加密,并且无需用户输入密码或个人识别码(PIN)。所以,这将阻止未签名的Android映像和解锁的引导加载程序直接访问它,这意味着即使执行了此攻击,用户的数据仍将受到保护。此外,在默认情况下,引导加载程序会解锁并擦除此分区。
    在这里插入图片描述

    复现漏洞

    为了证实我的理论,即所有SDM660设备都可能出现这种情况,我购买了一部由不同制造商生产的、但具有相同芯片组的手机。这部手机的发布时间比第一部晚了好几年,并且已经完全禁用了引导器解锁功能。

    制造商通过类似于第一台设备上发现的引导器解锁的签名保护机制来实现这一点,但没有发布相关的工具。

    我使用新设备的OTA映像来提取引导加载程序,具体如前所述。

    我试图重现与以前相同的缓冲区溢出,不幸的是,这次并没有成功。相反,通过发送一个更大的有效载荷,新设备确实崩溃了。通过使用与之前相同的二分搜索方法,可以确定这个引导加载程序的内容是在0x403000字节之后被覆盖的,而第一个引导加载程序被覆盖的内容位于第0x101000字节之后。有了这些信息,就可以迅速地开发出一个解锁的引导加载程序。

    我找到了一条分支指令,如果签名未通过验证,该指令将跳过解锁过程。
    在这里插入图片描述
    通过使用一个NOP操作码,这个分支可以被移除,从而在设备上实现引导加载程序解锁。

    由于该漏洞可能存在于所有基于SDM660的手机上,因此,我们直接向Qualcomm公司报告了该漏洞。

    对于不允许用户进行解锁的情况下,由于无需引导加载程序的访问权限,因此,可以完全禁止针对fastboot的访问,以防止针对它的攻击。然后,可以通过主安卓系统中的工程应用程序重新激活fastboot。实际上,禁止消费者解锁引导器的制造商经常使用这种方法。

    绕过Qualcomm公司的用户数据保护

    如前所述,Qualcomm公司的芯片支持对“userdata”分区进行加密,这样就可以通过使用内部密钥来保护用户数据,而不需要在启动时输入密码。这个特性的好处在于,可以防止攻击者通过chip-off分析,进而通过未签名的安卓映像访问数据。我想试试是否能绕过这种保护,即通过修改引导加载程序的功能来访问用户数据分区。

    我使用Qualcomm公司的源代码来确定如何访问加密密钥和解密分区。我发现,他们是故意不让引导加载程序访问这些密钥的,相反,要想访问密钥,必须使用相应的内部API,而这个API并没有被前面的攻击所修改。实际上,这个API是用来验证引导安卓的映像的,以及验证引导加载程序是否被解锁。
    在这里插入图片描述
    我注意到,这个函数调用并没有引导相应的映像,这意味着验证引导安卓映像的函数与实际启引导系统的函数是相互独立的。

    我决定研究一下fastboot命令“boot”,该命令用于引导并执行从主机上传的Android映像。我注意到,验证映像和开始执行映像的函数,实际上是两个不同的函数。
    在这里插入图片描述
    然后,我决定看看能否可以修改引导加载程序,以便在这两个调用之间交换已签名和未签名的Android映像。如果成功,我将能够执行一个未签名的Android映像,而无需解锁引导加载程序,从而获得对加密的userdata分区的完全访问权。

    修改boot命令

    命令“boot”可以通过fastboot的“download:”命令接收一个完整的Android“boot”映像,然后,在RAM中验证并执行该映像。我决定修改这个工具,使其可以接收多个Android映像。

    我修改了fastboot工具,使它不再发送一个映像,而是发送:

    ◼ 一个四字节的、相对于未签名映像的偏移量;

    ◼ 一个已签名的映像;

    ◼ 一个经过修改的未签名映像。

    完成上述任务之后,我还需要修补引导加载程序,以便使其可以正确使用这个有效载荷。我需要做的第一件事,就是绕过解锁检查。传统上,“boot”命令只在引导加载程序被解锁的情况下,才会引导上传的映像,即使该映像已经签名。我决定在代码中用一个操作码来覆盖这个检查,将新的有效载荷的指针向上移动四个字节——将其指向已签名的Android映像。
    在这里插入图片描述
    这将导致在代码到达“LoaderImageAndAuth”函数时对已签名的映像进行验证。

    在此之后,我需要在这个函数和“bootlinux”函数之间留出足够的空间,以便交换映像。我注意到,在这两者之间调用的函数只是出于内部管理的目的,提供“OK”响应并关闭引导加载程序的某些功能,一旦Android映像启动,这些功能就将被禁用。因此,我决定用交换映像所需的少量操作码来覆盖它们。
    在这里插入图片描述
    为此,我只需要在这些指令的基础之上另外添加四条即可,这意味着有足够的空间来做我需要的事情。具体来说,这四条指令及其作用如下所示:

    ◼ 将指针移回有效载荷的起点位置:sub x19, x19, 4;

    ◼ 读取偏移值:ldr w22, [x19];

    ◼ 将偏移值添加到映像的指针中:add x19, x19, x22;

    ◼ 将新的指针值压入“Info”结构体的“ImageBuffer”指针中:str x19, [x21,#0xa0]。

    这足以让指针从已签名的映像指向未签名的映像,这将有助于从检查时间到使用时间的攻击,并允许在不解锁引导加载程序的情况下运行无签名的映像。

    在这里插入图片描述

    通过锁定的引导器来运行未签名的代码

    在许多情况下,我们都希望能在自己的设备上运行未签名的安卓映像,尤其是希望获得Tethered的root权限的时候。通过使用Magisk引导未签名的映像,人们可以随意访问其设备上的全部数据,包括他们的照片、信息和联系人,而不需要备份、删除和恢复这些数据。此外,这将允许研究人员以root权限对其个人设备进行安全研究,然后,通过重启移除权限,再引导至已签名的映像。这种做法的好处在于,几乎没有证据表明他们获得了访问该设备的特权。

    这不仅对研究而言很有用,同时,攻击者也可以利用这一点来发动攻击。例如,通过这个漏洞和一个自定义的映像,攻击者就可以访问用户的所有文件,或只是禁用锁屏就能访问用户的应用程序。具有物理访问权限的攻击者也可以获得与用户获得的绑定型root访问权限(tethered root access)相同的访问权限。

    最后,安卓允许用户通过开发者选项菜单进一步对手机进行加密。这就增加了一个额外的保护层,要求在引导时输入PIN码或密码,以便解密用户数据分区。这与设备的解锁屏幕不同,后者只在软件层面保护设备。
    在这里插入图片描述
    虽然这这种方法确实能够保护用户数据,但它无法保护核心的安卓引导映像,一个获得临时物理访问某人的手机的攻击者可以很容易地上传一个后门,一旦用户输入了他们的密码,这个后门就会被激活。虽然这不是一种非常可行的攻击,但的确很有趣。
    在这里插入图片描述

    小结

    在引导加载程序中发现的所有漏洞都已披露给Qualcomm公司,并与进行了协调后才给予披露。虽然这些漏洞确实使SDM660面临风险,但在打补丁之前,我没有发现任何其他Qualcomm Snapdragon芯片是易受攻击的。目前,所有使用该芯片的设备都已部署了补丁,因此,该漏洞已不复存在。

    最后,该漏洞被分配的CVE编号为CVE-2021-1931。

    在这里插入图片描述

    最后

    我在网上整理了相关的资料与工具,有需要的可以call me!!!

    资料详细

    展开全文
  • BootLoader——嵌入式系统的引导加载程序一、BootLoader的概念1.1 编译工具链 引导加载程序(BootLoader)是系统上电后运行的第一段代码,在嵌入式系统中,通常没有像PC体系结构的BIOS固态启动程序,因此嵌入式系统...

    • 引导加载程序(BootLoader)是系统上电后运行的第一段代码,在嵌入式系统中,通常没有像PC体系结构的BIOS固态启动程序,因此嵌入式系统的加载启动任务是由BootLoader来完成的。例如,基于ARM core的嵌入式系统中,系统在启动时通常从地址0x00000000处开始执行,在这个地址存放的通常是系统的BootLoader程序。

    一、BootLoader的简介

    • BootLoader是操作系统内核系统运行之前,需要首先运行的一段小程序,通过BootLoader程序,可以初始化硬件设备、建立内存空间的映射图,为调用操作系统内核做好环境准备。
    • 由于嵌入式系统硬件的多样性,且BootLoader与系统硬件具有密不可分的关系,因此,设计一个通用的Bootloader几乎是不可能的。然而,我们却可以归纳出一个通用的BootLoader概念,用以指导用户设计特定的BootLoader。

    1.1 BootLoader在固态存储设备中的位置

    • 系统上电或复位后,所有的CPU通常从CPU预先指定的起始地址上读取指令,嵌入式系统通常将某种类型的固态存储设备(例如ROM、EEPROM、FLASH等)安排在这个起始位置。下图就是一个同时安装了BootLoader、内核启动参数、内核映射和跟文件系统映像的固态存储设备的典型空间分配结构。
      在这里插入图片描述

    1.2 BootLoader的启动过程

    • BootLoader的启动过程分为单阶段(Single Stage)和多阶段(Multi-Stage)两种。通常多阶段的BootLoader能够提供更为复杂的功能与更好的移植性。从固态存储设备上启动BootLoader通常经过两个阶段启动(分为stage1和stage2)。由于启动过程比较复杂,因此这两个步骤的启动过程放到下面进一步展开讨论。

    1.3 BootLoader的操作模式

    • BootLoader通常包括两种操作模式:启动加载(Boot Loading)模式和下载模式(Down Loading)模式。
    • 1、启动加载模式
    • 启动加载模式也成为自主(Autonomous)模式,即BootLoader从目标机上的某个固态存储设备上将操作系统加载到RAM中运行。这种模式是BootLoader的正常工作模式,因此嵌入式产品发布时,BootLoader应该工作该模式下。
    • 2、下载模式
    • 在该模式下,目标机上的BootLoader将通过串口连接或网络连接从主机(Host)上下载文件(通常包括内核映像与跟文件系统映像等)。从主机下载的文件通常首先被BootLoader保存到目标机(Target)的RAM中,最终被BootLoader载入到目标机的FLASH类固态存储设备中。在第一次安装内核、根文件系统时以及更新系统时两种情况下,BootLoader采用下载模式。

    二、BootLoader的启动过程

    2.1 BootLoader启动简介

    • 嵌入式系统的内核映像、根文件系统映像可以运行于RAM、ROM以及FLASH设备上,本文以加载到RAM上为例讨论BootLoader的启动过程。
    • 由于BootLoader的实现依赖于CPU的体系结构,并且通常分为两个阶段。其中,stage1通常对设备的代码进行初始化,并且通常是采用汇编语言实现的;而stage2通常采用C语言实现,以实现复杂功能,并可以使得代码具有很好的可读性与可移植性。BootLoader的stage1通常包括如下步骤:
    硬件初始化
    为加载BootLoader的stage2准备RAM空间
    拷贝BootLoader的stage2到RAM空间中
    设置好堆栈
    跳到stage2的C语言入口点
    • stage2通常包括以下步骤:
    初始化本阶段需要使用的硬件设备
    检测系统内存映射
    将内核映像与根间映像从FLASH载入到RAM中
    为内核设置启动参数
    调用内核

    2.2 BootLoader启动的stage1

    1、基本硬件初始化

    • BootLoader一开始就执行基本硬件初始化,其目的是为stage2执行以及kernel的执行的执行准备好基本的硬件环境。基本硬件初始化包括以下步骤:
    • (1)屏蔽所有中断:BootLoader的执行过程不必响应任何中断,为中断提供服务通常是操作系统驱动程序的责任。中断的屏蔽可以通过写CPU的中断屏蔽寄存器活状态寄存器来完成。
    • (2)设置CPU的速度和时钟频率。
    • (3)RAM初始化:正确地设置系统内存控制器的功能寄存器。
    • (4)初始化LED系统指示灯:通过GPIO来驱动LED系统指示灯,以表明系统的状态是正常的。
    • (5)关闭CPU内部指令/数据cache。
    • 2、为加载stage2准备RAM空间
    • 为了获得更快的执行速度,通常把stage2加载到RAM空间中执行,因此必须为加载BootLoader的stage2准备一段可用的RAM空间范围。为了便于表述,这里将RAM空间范围大小标记为:是stage2_size(字节),并把起始地址与终止地址分别标记为:stage2_start与stage2_end(这两个地址均以4字节边界对齐):
    stage2_end=stage2_start+stage2_end
    
    • 另外,必须确保所安排的地址范围确定是可读写的RAM空间,并且需要对所安排的地址范围进行测试。具体测试方法为:以memory page(4K的倍数)作为测试单位,测试每个memory page开始的两个字是否可读写,为了便于后续的描述,将这种测试算法叫做test_mempage,其具体步骤如下:
    • (1)首先保存memory page开始的两个字的内容。
    • (2)向这两个字中写入任意的数字(比如0x12,0x13)。
    • (3)立刻将这两个字的内容读回,如果读回的内容为0x12,0x13,则说明这个memory page所占据的地址范围是一段有效的RAM空间,否则不是。
    • (4)恢复这两个字的原始内容,测试完毕。
    • 3、拷贝stage2到RAM中
    • 拷贝时需要确定两点:第一,stage2的可执行映像在固态存储设备的起始地址与终止地址;第二,RAM空间的起始地址。
    • 4、设置堆栈指针sp
    • 堆栈指针的设置是为执行C语言代码做好准备。
    • 执行完以上四个步骤后,系统的物理内存布局如下图所示:
      在这里插入图片描述
    • 5、跳转到stage2的C语言入口点
    • 至此,就可以跳转到BootLoader的stage2去执行了,在ARM系统中,通过修改PC寄存器指向合适的地址来实现跳转。

    2.3 BootLoader启动的stage2

    • 在该阶段,与普通C语言应用程序不同,在编译与连接BootLoader程序时,不能使用glibc库的任何支持函数。BootLoader启动过程中的stage2打流程如下所示:
    • 1、初始化本阶段需要使用的硬件设备
    • 首先许需要点亮系统指示LED等,这表明系统已经进入main()函数,并进而初始化至少一个串口,以便和终端用户进行I/O输出信息;还需要初始化计时器等硬件设备。初始化阶段完成后,系统就可以输出一些打印信息、程序名称字符串、版本号等。
    • 2、检测系统的内存映射(memory map)
    • 内存映射就是指在整个4GB物理地址空间中那些地址范围被分配以用作寻址系统的RAM单元。在具体的嵌入式系统中,CPU通常会预留处足够大的地址空间给RAM,而不一定预留全部的RAM地址空间。因此,BootLoader的stage2需要检测整个系统内存映射情况,划分清楚CPU预留的全部RAM地址空间中那些被真正映射到RAM地址单元,那些处于“unused”状态。
    • 3、加载内核映像与根文件系统映像
    • 内存映像与根文件系统映像的加载包括规划内存占用的布局与从FLASH上拷贝两个步骤:
    • (1)规划内存占用的布局
    • 结合系统物理内存分布,规划内存布局的主要内容包括两个方面:第一,内核映像所占用的内存范围;第二,根文件系统所占用的内存范围。在规划内存占用的布局时,主要考虑基地址与映像大小两个方面。
    • 对于内核映像,一般将其拷贝到从MEM_START+0x8000这个基地址开始的1MB的内存范围内(嵌入式Linux的内核一般都小于1MB)。这样就空出了从MEM_START到MEM_START+0x8000这段32KB大小的内存空间,在Linux内核中,这32KB的内存空间通常防止一些全局数据结构,如启动参数与内核页表等。
    • 对于根文件系统映像,通常将其拷贝到MEM_START+0x00100000开始的地方,如果采用的是Ramdisk作为根文件系统映像,解压后的大小通常是1MB。
    • (2)从FLASH上拷贝
    • 对于ARM嵌入式系统,CPU通常在统一的内存地址空间中寻址FLASH固态存储设备,并从FLASH上读取数据。通常,用一个简单的循环就可以完成从FLASH设备上拷贝映像的工作:
    while(count){
    	*dest++ = *src++; /* they are all aligned with word boundary */
    	count -= 4; /*byte number 8/
    };
    

    4、设置内核的启动参数

    • 在将内核映像与根文件系统映像拷贝到RAM空间后,就可以准备启动Linux内核了。但是在启动内核之前,通常需要根据需求,设置Linux内核的启动参数。
    • 在Linux 2.4x版本以后,通常以标记列表(tagged list)形式来传递内核启动参数。启动参数标记列表以标记ATAG_CORE开始,以标记ATAG_NONE结束,每个标识包括内核启动参数的tag_header结构与参数结构,数据结构tag与tag_header定义在Linux内核源码的“include/asm/setup.h”头文件中。其中,BootLoader设置的常用启动参数包括ATAG_CORE、ATAG_MEM、ATAG_CMDLINE、ATAG_RAMDISK、ATAG_INITRD等。
      5、调用内核
    • BootLoader调用Linux内核的方法是直接跳转到内核的第一条处,即直接跳转到MEM_START+0x8000地址处。在跳转时,应该满足以下条件:
    • (1)CPU寄存器的设置:R0=0;R1=机器类型ID;R2=启动参数标记列表在RAM中的起始基地址。
    • (2)CPU模式:必须禁止中断IRQs与FIQs;CPU必须处于SVC模式。
    • (3)cache与MMU的设置:MMU必须关闭;指令cache可以打开也可以关闭;数据cache必须关闭。
    展开全文
  • 嵌入式Linux操作系统引导加载程序BootLoarderBootLoarder是什么Linux操作系统分层BootLoarderBootLoader操作模式BootLoader启动过程 BootLoarder是什么 Linux操作系统分层 一个嵌入式Linux系统从软件的角度看通常...

    BootLoarder是什么

    Linux操作系统分层

    一个嵌入式Linux系统从软件的角度看通常可以分为四个层次:

    1. 引导加载程序。包括固化在固件(firmware)中的boot代码(可选),和BootLoader两大部分。
    2. Linux内核。特定于嵌入式板子的定制内核以及内核的启动参数。
    3. 文件系统。包括根文件系统和建立于Flash内存设备之上文件系统。通常用ramdisk来作为rootfs。
    4. 用户应用程序。特定于用户的应用程序。有时在用户应用程序和内核层之间可能还会包括一个嵌入式图形用户界面。常用的嵌入式GUI有:MicroWindows和MiniGUI等。

    BootLoarder

    BootLoader是嵌入式Linux操作系统的第一个层次,即引导加载程序,是硬件加电之后要运行的第一段程序,也是内核运行的引导程序。

    bootloader是指操作系统的启动加载程序。
    它是在操作系统内核运行之前运行的一段小程序,主要负责初始化硬件空间,初始化内存空间,调整系统的软硬件环境,以便操作系统内核启动。

    Bootloader是嵌入式系统在加电后执行的第一段代码,在它完成CPU和相关硬件的初始化之后,再将操作系统映像或固化的嵌入式应用程序装在到内存中然后跳转到操作系统所在的空间,启动操作系统运行 。

    不同的硬件以及不同的配置bootloader是不一样的。
    不同的CPU也有不同的bootloader,有些也支持多种CPU。

    嵌入式系统通常把固态存储设备地址映射好,bootloader就放在这个地址,这样系统复位之后,就可以首先执行这段程序。
    采用汇编和c语言的结合方式来写程序,完成了它的使命之后,它就不再运行了。

    BootLoader操作模式

    大多数Bootloader都包含两种不同的操作模式:

    1. 启动加载模式
      在这种模式下,Bootloader从目标机的某个固态存储设备上将操作系统加载到RAM中运行,整个过程并没有用户的介入。这种模式是Bootloader的正常工作模式,因此在嵌入式产品发布时,Bootloader必须工作在这种模式下。

    2. 下载模式
      在这种模式下,目标机上的Bootloader将通过串口或网络等通信手段从开发主机(Host)上下载内核映像和根文件系统映像等到RAM中,然后可再被Bootloader写到目标机上的固态存储媒质中,或者直接进行系统的引导。

    启动加载模式通常用于第一次烧写内核与根文件系统到固态存储媒质时或者以后的系统更新时使用;
    下载模式多用于开发人员在前期开发的过程中,工作于这种模式下的Bootloader通常都会向它的终端用户提供一个简单的命令行接口。

    BootLoader启动过程

    Bootloader启动大多数都分为两个阶段。

    1. 第一阶段主要包含依赖于CPU的体系结构硬件初始化的代码,通常都用汇编语言来实现。
      这个阶段的任务有:
    • 基本的硬件设备初始化(屏蔽所有的中断、关闭处理器内部指令/数据Cache等)。
    • 为第二阶段准备RAM空间
    • 如果是从某个固态存储媒质中,则复制Bootloader的第二阶段代码到RAM。
    • 设置堆栈
    • 跳转到第二阶段的C程序入口点

    在第一阶段中为什么要关闭Cache?通常使用Cache以及写缓冲是为了提高系统性能,但由于Cache的使用可能改变访问主存的数量、类型和时间,因此Bootloader通常是不需要的。

    1. 第二阶段通常用C语言完成,以便实现更复杂的功能,也使程序有更好的可读性和可移植性。这个阶段的任务有:
    • 初始化本阶段要使用到的硬件设备
    • 检测系统内存映射
    • 内核映像和根文件系统映像从Flash读到RAM
    • 内核设置启动参数
    • 调用内核

    可以看出,BootLoader的主要工作有两个:

    • 硬件初始化;
    • 将内核加载到RAM中,为内核启动做准备.
    展开全文
  • 用户必须在其应用程序代码中放入引导加载程序检查功能,否则计算机无法将节点置于引导加载程序模式。 节点侦听重置消息的时间长短与传感器节点的低电流需求有关。 例如,如果节点每10分钟仅唤醒一次并发送一次...
  • 设置ASPM工作模式 睡眠自动关闭蓝牙WIFI 预先变量 OC I2C-GPIO补丁 补丁库 仿冒设备 仿冒EC RTC0 仿冒环境光传感器 操作系统补丁 注入设备 注入X86 PNLF注入方法 SBUS(SMBU)补丁 添加缺失的部件 PS2键盘映射及亮度...
  • 引导加载程序

    2015-11-21 11:26:08
    通过本文了解引导加载程序工作原理,认识两个流行的引导加载程序 LILO(LInux LOader)和 GNU GRUB(GRand Unified Boot loader), 并研究两者各自的优点和缺点。 什么是引导加载程序? 最简单地讲,引导...

    在不考虑他们的工作或专业情况下,所有 Linux 用户都会使用的是哪个工具?引导加载程序。通过本文了解引导加载程序的工作原理,认识两个流行的引导加载程序 LILO(LInux LOader)和 GNU GRUB(GRand Unified Boot loader), 并研究两者各自的优点和缺点。

    什么是引导加载程序?

    最简单地讲,引导加载程序(boot loader) 会引导操作系统。当机器引导它的操作系统时,BIOS 会读取引导介质上最前面的 512 字节(即人们所知的 主引导记录(master boot record,MBR))。在单一的 MBR 中只能存储一个操作系统的引导记录,所以当需要多个操作系统时就会出现问题。所以需要更灵活的引导加载程序。

    主引导记录本身要包含两类内容 —— 部分(或全部)引导加载程序以及分区表(其中包含有关于介质其余部分如何划分为分区的信息)。当 BIOS 引导时,它会寻找硬盘驱动器第一个扇区(MBR)中存储的数据;BIOS 使用存储在 MBR 中的数据激活引导加载程序。

    由于 BIOS 只能访问很少量的数据,所以大部分引导加载程序分两个阶段进行引导。在引导的第一个阶段中,BIOS 引导一部分引导加载程序,即 初始程序加载程序(initial program loader,IPL)。IPL 查询分区表,从而能够加载位于不同介质上任意位置的数据。首先通过这步操作 来定位第二阶段引导加载程序(其中包含加载程序的其余部分)。

    第二阶段引导加载程序是引导加载程序的主体;很多人认为这才是引导加载程序的真正部分。它包含有加载程序更需要磁盘空间的部分,比如用户界面和内核引导程序。从简单的命令行到绘声绘色的 GUI,这些用户界面的范围很广泛。

    引导加载程序通常配置为两种方式的其中之一:要么是作为主引导加载程序(primary boot loader),要么是作为二级引导加载程序(secondary boot loader)。主引导程序 是安装在 MBR 上的第一阶段引导加载程序(见先前的描述)。 二级引导加载程序 是安装在可引导分区的第一阶段引导加载程序。必须在 MBR 上安装单独的引导加载程序,并配置它将 控制权转交给二级引导加载程序。

    很多较新的 Linux 引导加载程序特别实用,因为它们提供了不同程度的交互,比如高级的 GUI 和加密的口令,以及通过选择操作系统进行引导的能力。这样,可以在具有多个物理磁盘的同一机器上共存多个操作系统。这种设置越来越常见,因为它帮助很多用户在安装新的 Linux 时,能够保留先前由 Windows® 机器所生成的宝贵数据资料。我个人认为这种设置非常美妙;只使用一台机器就可同时拥有 Linux 和 Windows。

    随着时间的推移,引导加载程序已经得到了增强,为用户引入了大量的功能。各个引导程序的功能和配置存在差异,但基本的目标是相同的。

    现在来看两个较为流行的引导加载程序:LILO 和 GRUB。

    LILO

    LInux LOader(LILO) 已经成为所有 Linux 发行版的标准组成部分。作为一个 较老的/最老的 Linux 引导加载程序,它那不断壮大的 Linux 社区支持使它能够随时间的推移而发展,并始终能够充当一个可用的现代引导加载程序。有一些新的功能,比如增强的用户界面,以及对能够突破原来 1024-柱面限制的新 BIOS 功能的利用。

    虽然 LILO 仍在不断地发展,但 LILO 工作原理的基本概念保持不变。

    使用 LILO 作为引导加载程序

    要使用 LILO 作为引导加载程序,需要做的事情取决于是要进行全新安装还是要让已经安装的 Linux 改为使用 LILO。如果是要进行全新安装,那么直接跳转到 配置 LILO 那一节。如果已经安装了某个 Linux 发行版,那么通常可以选择安装并配置 LILO(并可以将机器引导到新的 Linux 安装)。

    要将现有的 Linux 迁移到 LILO,首先必须获得最新版本的 LILO(见 参考资料)。在做任何其他事情之前,建议您确保在手边拥有一张 Linux 引导盘 —— 如果偶而弄错了某些地方,它可以提供很大的帮助,能够恢复到初始的 Linux 配置!将 LILO 安装到系统中之后,让它接管 MBR 非常简单。以 root 用户身份输入:

    # /sbin/lilo -v -v

    这将使用当前的 LILO 默认值,抹去 MBR 中当前所有内容。不过,请阅读 配置 LILO,以确保能够按预期引导起来。也要注意,如果想要在同一机器上运行 Windows 和 Linux,那么应该先安装 Windows OS,然后再安装 Linux OS,这样,在 Linux 安装中所选择的引导加载程序就不会被 Windows 引导加载程序所覆盖。与 Linux 引导加载程序不同,多数 Window 引导加载程序不支持引导 Linux。如果已经先安装了 Linux,那么只需要自己创建一张 Linux 引导盘,这样就可以在安装完 Windows 之后,回到 Linux 安装中并重写 MBR。

    配置 LILO

    LILO 的配置都是通过位于 /etc/lilo.conf 的一个配置文件来完成的。清单 1 给出了一个示例配置,使用的是我的家用机器,支持 Linux 和 Windows 机器的双重引导。了解我的工作站的基本配置,就可以想像出这些配置是如何与实际机器相关联的:

    • 主 HDD(物理磁盘 1)上安装了 Windows XP(最初机器上只有它)。在 Linux 术语中,这个 HDD 是 /dev/hda(在 GRUB 术语中是 hd0,0)。
    • 从 HDD(物理磁盘 2)上安装了 Red Hat Linux;root 分区位于这个硬盘驱动器的第三个分区,即 /dev/hdb3(在 GRUB 术语中是 hd1,3)。
    清单 1. lilo.conf 示例文件
    boot=/dev/hda
    map=/boot/map
    install=/boot/boot.b
    prompt
    timeout=100
    compact
    default=Linux
    image=/boot/vmlinuz-2.4.18-14
    	label=Linux
    	root=/dev/hdb3
    	read-only
    	password=linux
    other=/dev/hda
    	label=WindowsXP

    清单 1 中的选项:

    • boot= 行告诉 LILO 在哪里安装引导加载程序。在上面的示例中,将把它安装到第一块硬盘的 MBR。也可以选择将 LILO 安装到 /dev/hdb3(示例中的 Linux 分区),这样需要向 /dev/hda 安装另一个引导加载程序,并令其指向 LILO 引导加载程序;然后只需要让 LILO 作为二级引导加载程序。通常,引导加载程序应该位于 /dev/hda。还可以将这个参数指向软盘驱动器(最常见的是 /dev/fd0),来制做 LILO 软盘引导磁盘。
    • map= 指向引导期间 LILO 内部使用的映射文件。当使用 /sbin/lilo 命令安装 LILO 时, 它会自动生成这个文件,其中包含有描述符表(还有其他内容)。建议不要改动这个文件!
    • install= 是 LILO 在引导过程中内部使用的文件之一。它同时包含有引导加载程序的主要部分和二级部分。boot.b 文件的 一个片段被写入到 MBR(引导加载程序的主要部分),它会指向那个映射,接下来指向二级引导加载程序。同样,不要改动它!
    • prompt= 告诉 LILO 使用用户界面(本例中给出了两个选择 —— Linux 和 WindowsXP)。除了使用 prompt/user 界面以外,在适当情况下还可以为 Linux 内核等指定具体的参数。如果不在配置文件中指定此选项,那么 LILO 将引导到 默认的 OS,不发生任何用户交互,也不会等待。(但是请注意,如果在引导时按下了 SHIFT,那么还是可以得到提示,当不想把 引导加载程序暴露给普通用户时,这非常有用)。
    • timeout= 是引导提示在自动引导默认 OS(本例中是 Linux)之前的等待时间(以十分之一秒为单位)。 如果在 lilo.conf 没有指定 prompt,那么这个参数就会被忽略。
    • compact 选项可以大大加速引导过程,它会将连续的读磁盘的请求合并为一个单独的请求。不过,这可能是 一件祸福参半的事情,因为我在论坛上看到过很多贴子提到了关于此选项的问题。当希望从软盘引导时,这个选项尤其有用。
    • default= 选项告诉 LILO 默认使用哪个映像进行引导,比如在等待超时之后。这与 lilo.conf 文件中的某个映像的 标签相关联。如果没有在配置文件中指定此选项,那么它将引导文件中指定的第一个映像。
    • 对于允许用户引导到的每一个 Linux 版本,都应该指定 image= 及以下三个选项。image 选项指定希望 引导到的内核版本。
    • label= 标明了在运行期间希望能够从用户界面引导的不同 OS。另外,这个标签用于指定引导的默认 OS。 (注意:标签名称中避免出现空格;否则,引导那个文件时会出现无法预期的错误。)
    • root= 告诉 LILO OS 文件系统实际所在的位置。在我们的示例中为 /dev/hdb3,即第二块硬盘上的第三个分区。
    • read-only 告诉 LILO 以只读的方式初始引导到文件系统。OS 一旦完全引导起来,就会以读写方式挂载。
    • password= 允许您为将要引导到的特定 OS 设置口令。不幸的是,这个口令是以可读文本的方式保存在 lilo.conf 文件中,所以,所有人都能够读取它。如果需要,还可以对想要引导自的每个操作系统设置口令(在我们的示例中,只为 Linux 的引导 设置了一个口令)。
    • other= 的动作类似于 image 和 root 选项的组合,但是用于除了 Linux 以外的其他操作系统。 在我们的示例中,它告诉 LILO 到哪里去找到 Windows OS(位于第一块硬盘的第一个分区)。如果先安装 Windows,后安装 Linux,通常会是这样。
    • label= 与所有其他 label 选项相同。

    在 lilo.conf 文件中可以使用很多其他参数,不过清单 1 中的参数就足以让机器可用了。要获得关于 lilo.conf 的这些以及其他参数的 进一步资料,请参考手册页(man lilo.conf)。由于在引导时不会读取 lilo.conf,所以,当这个文件有改动时,需要“更新”MBR。 如果不完成此步骤就重新引导,那么对 lilo.conf 的修改不会在启动中反映出来。与先前将 LILO 写入 MBR 类似,需要运行:

    $ /sbin/lilo -v -v

    -v -v 标记会为您给出非常详细的输出。当像我们那样运行 LILO 时,有很多参数可以指定。 参阅手册页以获得更进一步的信息(man lilo)。

    初始引导过程

    当 LILO 初始引导时,它会按次序打印出每个字母 —— L-I-L-O。如果所有字母都显示出来,那么第一阶段引导就成功了。缺少任何内容 都表示出现了问题:

    • L:第一阶段引导加载程序已经被加载。如果 LILO 停止在这里,那么是在引导第二阶段引导加载程序时出现了问题。这通常会伴随有一个错误代码。 在这个阶段的常见问题是介质问题,或者在 lilo.conf 文件中指定了不正确的磁盘参数。
    • LI:第二阶段引导加载程序已经被加载。LILO 在此处停止表示第二阶段引导加载程序不能被执行。同样,这可能是因为出现了与只显示 L 类似的问题: 正在加载,或者因 boot.b 文件被破坏、移动或删除而不能加载。
    • LIL:第二阶段引导加载程序正在被执行。此时,可能会再次出现介质问题,或者映射文件(如 lilo.conf 文件中所指定的)在寻找描述符表时 可能会出现问题。
    • LIL?:加载到与上面相同的阶段。这通常意味着加载第二阶段引导加载程序使用了错误的地址,最常见的原因是 boot.b 所在的位置与 lilo.conf 文件所指定的不同。
    • LIL-:加载到与上面相同的阶段。加载描述符表时出现问题,最常见的原因是描述符表错误。
    • LILO:LILO 成功被加载,没有出现任何错误。

    引导时的附加配置

    LILO 被成功加载后,将看到 LILO 提示符。还是使用前面的示例 lilo.conf 文件,此时将有两个选择,可能对 LILO 新手来说并不直观。首先,可以 让 LILO 超时(10 秒后),这将引导 /dev/hdb3,即 Linux 分区。另外,可以按下 TAB 键,这将列出将要引导的操作系统选项。在我们的示例 lilo.conf 中, 将得到的选项是 “Linux” 和 “Windows”。输入哪一个,就会引导到哪个 OS。指定加载 Linux 选项,会提示输入一个口令,在本例中是 linux。如果输入的口令有误,则会返回 LILO 提示符。

    不幸的是,LILO 不支持引导期间的交互式配置,所以,只能在 lilo.conf 中或者运行 /sbin/lilo 时指定选项。

    关于第一次尝试 LILO 的最后一点建议是:我发现使用软盘引导磁盘比使用硬盘实现 LILO 配置更为安全。为此,必须在 lilo.conf 文件中使用boot=/dev/fd0 替换 boot=/dev/hda。那样,如果弄乱了 lilo.conf 文件 中的任何配置,都可以取出引导磁盘并像先前一样引导到 Linux。当使用软盘进行引导一切正常以后,可以将 lilo.conf 修改回 boot=/dev/hda,然后最后一次运行 /sbin/lilo 来上传修改。

    GNU GRUB

    近来,GRand Unified Boot loader(通常称为 GRUB)似乎要取代 LILO 在引导加载程序方面的统治地位。GNU GRUB 基于原来的 GRUB 程序(最初由 Erich Stefan Boleyn 所创建),正在由自由软件基金会(Free Software Foundation)进行积极开发。

    使用 GRUB 作为引导加载程序

    与使用 LILO 相同,使用 GRUB 作为活动的引导加载程序所需要的步骤,取决于是安装全新的 OS 还是已经安装了 Linux 并计划转移到 GRUB。 如果是进行全新安装,那么可以直接跳转到 配置 GRUB 那一节。如果已经安装了某个 Linux 发行版,那么通常可以选择 安装并配置 GRUB(并可以将机器引导到新的 Linux 安装)。

    计划迁移到 GRUB 的当前 Linux 用户需要去获得最新版本的 GRUB(见 参考资料)。同样, 与 LILO 相同,在做任何其他事情之前,需要在手边准备一张 Linux 引导盘。使用交互模式(后面将描述)则不需要这张磁盘, 不过最好拥有一张以备急需时使用。将 LILO 安装到系统中之后,让它接管 MBR 非常简单。以 root 用户身份输入:

    # /boot/grub/grub

    这样将加载一个类似于 BASH 的命令提示符,可以在这里使用 GRUB 命令:

    grub> install (hd1,3)/boot/grub/stage1 (hd0) (hd1,3)/boot/grub/stage2 p (hd1,3)/boot/grub/menu.conf

    这个命令使用了 GRUB 安装命令,需要为它给出第一阶段映像的位置以及 MBR 的位置(install (hd1,3)/boot/grub/stage1 (hd1))。 也要给出第二阶段映像的位置((hd1,3)/boot/grub/stage2)。最后,可选项 p (hd1,3)/boot/grub/menu.conf 告诉 GRUB GUI 菜单配置文件的位置。

    在前面的示例中,hd1 是我的 Linux Diskhd0 是我的 Windows 磁盘。这样将使用当前 GRUB 默认值,并抹去 MBR 中当前所有内容(请阅读配置 GRUB,以确保能够按预期引导起来)。

    配置 GRUB

    GRUB 的配置都是通过位于 /boot/grub/grub.conf 的一个配置文件来完成的。清单 2 给出了一个示例配置,使用的是我的家用机器,支持 Linux 和 Windows 机器的双重引导:

    清单 2. grub.conf 示例文件
    default=0
    timeout=10
    splashimage=(hd1,3)/grub/splash.xpm.gz
    password --md5 $1$opeVt0$Y.br.18LyAasRsGdSKLYlp1
    title Red Hat Linux
    	password --md5 $1$0peVt0$Y.br.18LyAasRsGdSKLYlp1
    	root (hd1,3)
    	kernel /vmlinuz-2.4.18-14 ro root=LABEL=/
    	initrd /initrd-2.4.18-14.img
    title Windows XP
    	password --md5 $1$0peVt0$Y.br.18LyAasRsGdSKLYlp1
    	rootnoverify (hd0,0)
    	chainloader +1

    清单 2 中的选项:

    • default= 选项通知 GRUB 在超时之后默认使用哪个映像进行引导。这一选项与 grub.conf 文件中的某个映像相关联。 0 表示指定了第一个,1 表示指定了第二个,依次类推。如果没有在配置文件指定此选项,那么它将引导文件中指定的第一个映像。
    • timeout= 是在自动引导默认 OS(在本例中是 Red Hat Linux)之前引导提示会等待多少秒。
    • splashimage= 是用作 GRUB GUI 背景的图片所在的位置。
    • password 选项指定了使用 MD5 加密的口令,用于访问 GRUB 的交互式引导选项。注意,这不会阻止用户选择 引导已经定义的 OS;需要为 每一个 -title 设置它。为了生成一个 md5 口令, 请运行 GRUB 所附带的 grub-md5-crypt 工具(以 root 身份)。它将提示输入一个希望加密的口令。然后输出使用 MD5 加密的口令。将这个口令拷贝到 grub.conf 中 password -md5 之后,但是要在同一行上。通常这个口令可以设置为 root 口令,因为无论如何也只有 root 才可以读取 grub.conf 文件。
    • title 标明了在运行期间能够从用户界面引导的具体 OS。 与 LILO 不同,在这个名称中可以有空格。
    • password 的设置方式与前面的 password 相同。如果计划与其他用户共享此机器,那么不要将这个口令设置为 root 口令。
    • root 告诉 GRUB OS 文件系统的实际位置。可见,GRUB 引用介质的方式与 LILO 不同。在 LILO 示例中, /dev/hdb3 是第二块硬盘中的第三个分区。Grub 将此硬盘引用为(hd1,3),即第二块硬盘的第三个分区(disk 0 是第一块硬盘)。
    • kernel:vmlinuz-X.X.XX-XX 是 root 目录中默认引导映像的名称。
    • initrd:initrd-X.X.XX-XX.img 是 root 目录中默认 initrd 映像的名称。
    • title 与所有其他 title 选项相同。
    • password:见其他口令选项。
    • rootnoverify 告诉 GRUB 不要尝试去改变 OS 的 root。这样,当文件系统不被 GRUB 所支持时,不会出现引导错误。
    • chainloader +1 告诉 GRUB 使用一个链式加载程序来加载这个 OS,加载 Windows 时需要这个选项。

    在 grub.conf 文件中可以使用很多其他参数,不过清单 2 中的参数就足以让机器可用了。 要获得关于 grub.conf 的这些以及其他参数的进一步资料,请参考手册页(man grub.conf)。

    与 LILO 的配置文件不同,grub.conf 会在引导时被读取,当被修改时不必去更新 MBR。

    初始引导过程

    与 LILO 类似,当 GRUB 初始加载时,从 MBR 加载第一阶段程序。加载后,它进入第一阶段和第二阶段引导加载程序之间的中间阶段(为了方便讨论,可称为第 1.5 阶段)。 之所以存在第 1.5 阶段,是为了能够对 /boot/grub 中的 GRUB 配置文件进行常规的文件系统访问,而不是去访问磁盘块。然后进入引导加载程序的第二阶段,GRUB 加载 grub.conf 文件。

    现在应该能够看到 GRUB GUI 了。对于熟悉 Windows 的用户来说,这看起来感觉比 LILO 更友好。不过,不要因为 GRUB 拥有 GUI 就认为它是一个不能 处理数据的引导加载程序。可选项多得惊人。(见 引导时的附加配置 中的提示。)

    如果像我那样配置,那么现在应该能看到屏幕中有两个选项:引导到 Red Hat Linux 或者引导到 Windows XP。默认情况下,它将加载 Linux。选择任意一个的结果不言而喻。

    现在来看一些好东西。

    引导时的附加配置

    在 GRUB GUI 中,按下任何键都会停止超时的计时。然后按下 P 键,可以输入 GRUB 口令,并获得对 GRUB 交互式引导选项的完全访问权限。 按下以下其中一个键,应该能够使用三个选项之中的一个:

    • 要在引导之前编辑命令,请按下 E。这将让您能够为当前选中的 OS 编辑具体的选项。GRUB 只会显示出与那个 OS 的引导相关的选项, 然后您可以恰当地进行编辑。当为 root 文件系统指定了错误的 HDD 时,这尤其有用。如果需要以单用户模式访问机器(不需要指定口令 就能够让您获得 root 访问权限!),那么在 GRUB 主屏幕上选择 Linux OS。然后与前面一样,按下 E,并移到内核那一行( 在我的示例中是kernel /vmlinuz-2.4.18-14 ro root=LABEL=/)。然后在那一行最后添加 single,并按下 B 来使用修改过的 grub.conf 进行引导。在编辑模式下所做的任何修改都不会 保存到 grub.conf 文件中。
    • 要修改内核参数,请按下 A。如果您是一位经验丰富的 Linux 用户,可以根据需要调整内核参数。
    • 要获得类似于 BASH 的命令行界面,请按下 C。这个小型的命令行界面允许您在系统中查找 GRUB 配置文件,加载另外的配置文件, 编辑配置文件中的行,以及直接输入 GRUB 命令。如果配置的变化(比如删除了某个分区)让系统无法引导,那么可能会用到这个界面。 如果需要将系统引导为单用户模式,或者要让运行级别为 3 而不是普通的运行级别,也可能会使用到它。

    这些选项有很多用途,但超出了本文的范围。

    可见,GRUB 真正开放了引导期间的可能性。不过,这可能是一件好坏参半的事情,因为 GRUB 也潜在地允许攻击者在 OS 加载之前访问系统。 会被误用的主要开放领域是:

    • 访问单用户模式。所有加载到单用户模式的人都会得到 root 访问权限,使得 Linux 可被随意滥用。
    • 访问其他操作系统。任何配置为不需要口令的可引导操作系统,比如 DOS,都将是开放的。
    • 访问 GRUB 编辑器。这允许用户获得修改 GRUB 配置的完全访问权限。

    在 GRUB 配置中,设置安全性非常重要;设置口令,并使用 MD5 加密,可以保证整个系统的安全。

    GRUB 的未来

    GRUB 将要被 GRUB2 所取代。原来的 GRUB 将要被重新命名为 GRUB Legacy;除了修复 bug 以外,不会再对它进行积极开发。GRUB2 将是对原来 GRUB 的完全重写。到目前为止,以下特性是变化的核心部分:

    • 通过创建压缩的核心映像取代了第 1.5 阶段
    • 支持核心映像的动态加载
    • 争取让整个 GRUB 框架成为面向对象的
    • 支持国际化,比如 非-ASCII 字符集
    • 支持不同硬件体系结构和不同平台(不同于 Linux 的平台)

    请参考 GRUB Web 站点(见下面的 参考资料 部分)以了解最新的进展。

    GRUB 与 LILO 的比较

    如本文开始处所述,所有引导加载程序都以类似的方式工作,满足共同的目的。不过,LILO 和 GRUB 之间有很多不同之处:

    • LILO 没有交互式命令界面,而 GRUB 拥有。
    • LILO 不支持网络引导,而 GRUB 支持。
    • LILO 将关于可以引导的操作系统位置的信息物理上存储在 MBR 中。如果修改了 LILO 配置文件,必须将 LILO 第一阶段引导加载 程序重写到 MBR。相对于 GRUB,这是一个更为危险的选择,因为错误配置的 MBR 可能会让系统无法引导。使用 GRUB,如果配置文件配置 错误,则只是默认转到 GRUB 命令行界面。

    结束语

    与所有软件相同,对某个用户来说是最好的选择,并不是对所有人来说都是最好的。至于这里所涉及的两个引导加载程序,我个人喜欢的是 GNU GRUB。它是一个非常好的全面的加载程序,组合了灵活的用户界面和大量的功能。但是,还有很多使用过并忠爱 LILO 的人仍然选择 LILO 作为引导加载程序。幸运的是,如果您刚刚开始接触 Linux 引导加载,使用哪个都不会有太大问题。

    关于安全性,任何可以接触到引导磁盘/CD 的人,只需要使用没有设置安全性的 grub.conf 或 lilo.conf,就可以绕过本文中提及的所有安全措施。 特别是使用 GRUB 时,因为能够引导到单用户模式,所以是一个严重的安全漏洞。解决此问题的一个简单方法是在机器的 BIOS 中禁止通过 CD 和软盘进行 引导,并确保为 BIOS 设置了一个口令,使得其他人不能修改这些设置。

    祝您好运!

    展开全文
  • 从普通的桌面用户到 Linux® 系统管理员,大部分 Linux 用户都使用过一种名为引导加载程序的工具。此类工具的不同变种会提供不同层次的支持和功能。在很多情况下,Linux 发行版默认安装的引导加载程序并不总是适合...
  • BIOS的启动原理学习--加载引导程序

    千次阅读 2020-01-27 19:05:08
    在Windows系统以及有图形界面的其他操作系统中要想执行一个程序,必须在窗口中双击它,或者在命令行界面中输入相应的执行命令。从计算机底层机制上讲,这其实是在一个已经运行起来的操作系统的可视化界面或命令行...
  • 什么是引导加载程序 最简单地讲,引导加载程序(Boot Loader)会引导操作系统。当机器引导它的操作系统时,BIOS会读取引导介质上最前面的512字节(即人们所知的主引导记录(Master Boot Record,MBR))。在单一的...
  • 引导加载程序是嵌入式系统中一个特别有趣的组件,引导加载程序经常被嵌入式开发团队忽视并在最后一刻开发,尽管它们通常很难实现并为系统创建关键功能。  什么是安全引导加载程序?  安全引导加载程序不同于标准...
  • 引导加载程序之争: LILO 和 GRUB

    千次阅读 2015-11-21 09:30:12
    通过本文了解引导加载程序工作原理,认识两个流行的引导加载程序 LILO(LInux LOader)和 GNU GRUB(GRand Unified Boot loader), 并研究两者各自的优点和缺点。什么是引导加载程序?最简单地讲,引导加载程序...
  • GRUB是一个多重开机管理工具,它可用来激活Linux、BSD、OS/2、BeOS与Windows95/98/NT等众多操作系统,GRUB是一个独立... 从普通的桌面用户到 Linux® 系统管理员,大部分 Linux 用户都使用过一种名为引导加载程序的工
  • 引导加载程序执行以下功能: 内部模块的最初初始配置; 根据分区表和 ota_data(如果有),选择要引导的应用程序分区; 将此映像加载到 RAM(IRAM 和 DRAM) 并将管理传输到它. 引导加载程序位于 Flash 中的...
  • 上一篇文章学习了以下内容: 用一种不同的分段方法,从另一个不同的的角度理解处理器的分段内存访问机制 ...学习操作系统加载应用程序的过程,演示段的重定位方法,最终彻底理解8086的分段内存管理机...
  • 4-主引导程序

    2019-01-16 17:37:06
    文章目录主引导程序加载位置显卡显卡如何控制显示器显存中的信息如何解释显存映射实验程序代码疑问实战操作关于作者 主引导程序引导程序的用处应该是通过一个中间程序加载操作系统或者直接加载操作系统,但此处只...
  • BIOS 完成工作后,%ds, %es, %ss 的值是未知的,所以在屏蔽中断后,引导加载器的第一个工作就是将 %ax 置零,然后把这个零值拷贝到三个段寄存器中(8415-8418)。 虚拟地址 segment:offset 可能产生21位物理...
  • 文章目录C28x DSP程序加载与运行1 C28x DSP程序加载和运行1.1 程序加载1.1.1 加载地址和运行地址1.1.2 引导加载程序1.2 程序入口地址1.3 Run-Time初始化1.3.1 _c_int00()函数1.3.2 RAM模型与ROM模型1.3.2.1 在运行时...
  • 3.1 引导加载程序都做了些什么 在嵌入式Linux操作系统中,引导加载程序有两个主要工作:基本系统的初始化和内核载入。实际上,前者在一定程度上为后者提供支持,为了更好地加载内核,就必须尽可能多地初始化系统...
  • 其中,重点介绍M29W800AB Flash的使用和编程方法,TMS320VC54X DSP的上电自动引导过程,以及HPI模式和并行模式加载用户代码的方法。 引 言 在TMS320C54X系列DSP系统的开发中,由于DSP片内只有ROM和RAM存储器,...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 63,751
精华内容 25,500
关键字:

引导加载程序的工作模式