#ifdef CONFIG_BLK_DEV_INITRD if (initrd_start && !initrd_below_start_ok && page_to_pfn(virt_to_page((void *)initrd_start)) < min_low_pfn) { printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - " "disabling it.\n", page_to_pfn(virt_to_page((void *)initrd_start)), min_low_pfn); initrd_start = 0; } #endif Linux内核启动流程详解 在Linux操作系统中,内核启动是一个至关重要的过程,它涉及到从引导加载程序(如u-boot)向操作系统内核的平稳过渡。对于基于ARM架构的系统,这个过程通常从加载压缩的内核映像(zImage)开始。在文档中提到的`Linux2.6内核启动流程.doc`中,我们可以看到内核启动的一些关键步骤,特别是针对ARM平台的特定部分。 我们注意到一个关于`CONFIG_BLK_DEV_INITRD`的条件编译块,这部分代码检查初始化根文件系统(initrd)是否被覆盖。initrd是一个临时的文件系统,用于在主根文件系统可用之前提供必要的驱动程序和工具。如果initrd的起始地址低于最小低页帧号(min_low_pfn),那么initrd可能已经被破坏,因此内核会禁用它。 接下来,我们深入探讨Linux内核的启动流程: 1. **启动阶段**: - 在`arch/arm/boot/compressed/start.S`中,启动过程开始。这里使用汇编语言编写,以确保最小的内存占用和最快的执行速度。 - `start.S`中的代码首先进行一些基本的设置,如设置寄存器r0-r6、ip(r12)、sp(栈指针)等。 - 检查处理器模式,确保从u-boot进入内核时,系统处于supervisor模式(SVC32模式)。 2. **加载器信息校验**: - 检查当前运行的代码是否位于预期的地址,这通常是由于内核映像是在加载时被解压缩的,其实际运行地址可能与链接地址不同。 - 如果检测到地址不匹配,代码会进行调整,通过将所有相关寄存器(如r5, r6, r12, r2, r3, sp)加上适当的偏移量来适应新的加载位置。 3. **中断和异常处理**: - 关闭中断,防止在内核初始化期间发生未预期的中断事件。 - 确保处理器状态正确,例如,通过修改cpsr(current program status register)来设置适当的模式和权限。 4. **初始化标签(tags)**: - 在ARM架构下,atags(architecture tags)是一个传递参数给内核的机制,包括内存布局、串口配置等信息。 - r8寄存器保存了atags的指针,这对于内核的早期初始化至关重要。 5. **内存管理**: - 初始化内存管理系统,如页表和物理内存分配器,以便有效地管理系统的RAM资源。 6. **设备初始化**: - 驱动程序的加载和初始化,这通常涉及系统时钟、中断控制器、串口和其他基本硬件接口。 7. **根文件系统加载**: - 如果启用了initrd,内核会尝试挂载并使用它,直到找到永久的根文件系统为止。 8. **调度器和系统调用初始化**: - 初始化调度器,这是多任务操作的基础。 - 设置系统调用表,允许用户空间进程与内核交互。 9. **模块支持**: - 如果配置了模块支持,内核会准备好加载额外的可加载模块。 10. **启动用户空间**: - 内核启动第一个用户进程(通常是init进程),这标志着内核启动阶段的结束,控制权转交给用户空间,开始执行系统服务和应用程序。 整个启动流程非常复杂,涵盖了多个子系统和组件的初始化。不同的硬件平台可能有不同的启动步骤和细节,但基本流程大体一致。理解这个流程对于调试、优化和开发内核扩展至关重要。
剩余12页未读,继续阅读
- 粉丝: 0
- 资源: 2
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助