对于移植 linux 到其它开发板的人来说,编写 boot loader 是一个不可避免的过程。对于学习linux的人来讲,编写 bootloader 也是一个很有挑战性的工作。本文通过对 linux引导协议进行分析,详细阐述了如何编写一个可以在 i386 机器上引导 2.4.20内核的基本的bootloader
在Linux操作系统的世界里,bootloader扮演着至关重要的角色,它是操作系统加载之前的首个程序,负责初始化硬件、设置内存映射,并将Linux内核加载到内存中。对于那些移植Linux到其他开发板或者深入学习Linux内核的人来说,理解并编写bootloader是一项必备技能。本文将详细介绍如何在i386架构上编写一个能够引导2.4.20内核的基本bootloader。
我们需要了解Linux运行的基础环境。Linux内核通常在保护模式下运行,但计算机启动时处于实模式。因此,bootloader的工作就是在实模式下完成,确保内核能在正确的环境下启动。Linux内核有两种主要格式:zImage和bzImage。zImage由于受制于实模式1MB内存的限制,适用于较小的内核,而bzImage则没有这个限制,更适合大型内核。
接下来,我们将重点讨论bzImage格式。bzImage内核由三部分组成:bootsect(前512字节)、setup(从512字节开始,长度为512*n字节)和保护模式的内核。bootsect是软盘引导时使用的bootloader,setup部分在实模式下运行,主要任务是为保护模式的内核设置环境。setup结束后,会切换到保护模式并跳转至内核执行。
引导流程相对简单:将内核的setup部分拷贝到内存的9020H:0开始的地址,接着将保护模式内核加载到1MB起始的地址。之后,根据Linux Boot Protocol 2.03设定参数区的内容,通常位于9000H:0。使用ljmp指令跳转到setup段,剩下的工作就交给Linux内核自身来处理。
要成功引导Linux,还需要遵循THELINUX/I386BOOTPROTOCOL,该协议详细说明了引导所需的所有信息。这个协议在Documentation/i386/boot.txt文件中能找到。对于其他体系结构的CPU,也有类似协议可供参考。
引导过程中,设置基本参数至关重要。例如,指定root设备(通过root_major和root_minor),定义初始显示模式(vga参数),以及标记bootloader的类型(避免引导过旧内核)。如果环境中没有任何资源,可能需要使用BIOS中断或ATA指令直接从硬盘读取内核。然而,若有DOS系统,可以利用DOS程序简化加载过程,如使用Watcom C编写的程序来读取整个4GB地址空间的内核。
编写bootloader是一个既富有挑战又极其有价值的实践,它要求对底层硬件、操作系统启动流程以及编程技术有深入理解。通过本文的讲解,你应能对如何为i386平台编写一个引导2.4.20内核的bootloader有了清晰的认识。实际操作时,建议参照文档和示例代码,逐步实现每个步骤,以加深理解和提高实践能力。