linux启动代码之detect_memory()函数

本文主要讨论了Linux内核在i386平台上的启动过程,特别是detect_memory()函数如何检测系统物理内存。通过调用detect_memory_e820()等函数,利用BIOS中断0x15查询内存信息,并将结果存储在boot_params结构中。文章详细解释了detect_memory_e820()函数的工作原理,包括迭代查询内存段和处理中断返回值的过程。

本篇笔记主要针对平台i386进行讨论,我也是新手,不当之处,敬请指正。以下讨论中“/”代表“/内核源代码根目录/arch/x86/boot/”目录,我用到的内核源代码版本为2.6.26.5

在被bootloader加载到内存后, cpu最初执行的linux内核代码是/header.S文件中的setup函数,这个函数在做了一些准备工作后会跳转到boot目下文件main.cmain函数执行,在这个main函数中我们可以第一次看到与内存管理相关的代码,这段代码调用detect_memeory()函数检测系统物理内存,代码如下图:


/main.c/main()代码片段

detect_memory()函数位于/memory.c中,定义如下图:

detect_memory()函数代码非常简单,由上图可知,linux内核会分别尝试调用detect_memory_e820()detcct_memory_e801()detect_memory_88()获得系统物理内存布局,这3个函数内部其实都会以内联汇编的形式调用bios中断以取得内存信息,该中断调用形式为int 0x15,同时调用前分别把AX寄存器设置为0xe820h0xe801h0x88h,关于0x15号中断的具体作用我这里就不再说明,有兴趣的可以去查询相关手册。下面我仅分析下detect_memory_e820()的代码,其它代码基本一样,源代码如下图所示:

/memory.c/detect_memory_e820(void)代码

该代码中用到的两个结构体定义如下:

detect_memory_e820功能概述:

       由于历史原因,一些i/o设备也会占据一部分内存物理地址空间,因此系统可以使用的物理内存空间是不连续的,系统内存被分成了很多段,每个段的属性也是不一样的。int 0x15 查询物理内存时每次返回一个内存段的信息,因此要想返回系统中所有的物理内存,我们必须以迭代的方式去查询。detect_memory_e820()函数把int 0x15放到一个do-while循环里,每次得到的一个内存段放到struct e820entry里,而struct e820entry的结构正是e820返回结果的结构!而像其它启动时获得的结果一样,最终都会被放到boot_params里,e820被放到了 boot_params.e820_map

 

detect_memory_e820主要注释如下:</

<think>嗯,用户想知道Linux内核5.4.34版本的启动流程源码实现。首先,我需要回忆一下Linux内核启动的大致步骤。通常,内核启动从引导加载程序开始,比如GRUB,然后加载内核映像,解压,进入保护模式,最后初始化各个子系统。 用户提到了版本5.4.34,可能需要具体到该版本的源码结构。我应该检查内核源码中的关键文件,比如arch/x86/boot/header.S,那里可能有实模式下的启动代码。然后是main.c中的start_kernel函数,这是内核初始化的核心入口点。 另外,用户提供的引用内容中有关于SELinux启动模式和内存读取的内容,虽然这些可能和启动流程关系不大,但需要注意是否有相关部分在启动过程中被调用。比如,SELinux可能在启动后期初始化安全模块时才会涉及。 用户可能需要了解从实模式切换到保护模式的过程,以及各个初始化函数的调用顺序。比如,start_kernel函数中会调用setup_arch来初始化架构相关的设置,然后初始化内存管理、进程调度、设备驱动等。 还需要注意内核启动参数的处理,比如引用[1]提到的enforcing=1参数可能在启动时通过命令行传递给内核,影响SELinux的模式。这部分可能在启动流程的参数解析阶段处理,比如在parse_early_param函数中。 此外,内存管理相关的初始化,如页设置、内存分配器初始化,也是启动流程的重要部分。引用[2]提到的rd命令可能涉及内存读取,但具体在内核启动中的哪个阶段使用还需要查证。 需要确保回答的结构清晰,分步骤说明各个阶段的关键文件和函数,并正确引用用户提供的参考资料。如果有相关部分,比如SELinux的初始化,应在适当的位置提及,并标注引用。 最后,生成的相关问题需要围绕内核启动流程,比如不同架构的差异、关键函数的作用或调试方法,确保问题有针对性,帮助用户深入理解。</think>### Linux内核5.4.34启动流程源码分析 #### 1. **引导加载阶段** 内核启动始于引导加载程序(如GRUB)加载`vmlinuz`内核镜像。关键代码位于: - **arch/x86/boot/header.S**:包含实模式下的引导头部(Boot Sector) - **arch/x86/boot/main.c**:初始化控制台、内存检测等操作 ```c // arch/x86/boot/main.c void main(void) { /* 检测内存布局 */ detect_memory(); /* 初始化键盘和显示 */ keyboard_init(); /* 进入保护模式 */ go_to_protected_mode(); } ``` #### 2. **保护模式切换** 实模式到保护模式的转换由以下代码实现: - **arch/x86/boot/pm.c**:启用A20地址线、加载GDT、设置CR0寄存器 ```c // arch/x86/boot/pm.c void go_to_protected_mode(void) { enable_a20(); setup_gdt(); set_cr0(); } ``` #### 3. **内核解压与重定位** 解压程序位于: - **arch/x86/boot/compressed/head_64.S**:初始化长模式环境 - **arch/x86/boot/compressed/misc.c**:解压内核到指定地址 #### 4. **内核初始化入口** 核心初始化函数`start_kernel`位于: - **init/main.c**:初始化调度器、内存管理、中断等子系统 ```c // init/main.c asmlinkage __visible void __init start_kernel(void) { setup_arch(&command_line); // 架构相关初始化[^2] mm_init(); // 内存管理初始化 sched_init(); // 调度器初始化 rest_init(); // 启动第一个用户进程 } ``` #### 5. **安全子系统初始化** 若启用SELinux,其初始化在`security/selinux/hooks.c`中完成。根据引用[^1],可通过`enforcing=`参数控制运行模式: ```c // security/selinux/selinuxfs.c static int selinux_enforcing_set(void *data, u64 val) { selinux_enforcing = val; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值