Welcome 微信登录

首页 / 操作系统 / Linux / Linux物理内存探测

linux在被bootloader加载到内存后, cpu最初执行的linux内核代码是/header.S文件中的start_of_setup函数,这个函数在做了一些准备工作后会跳转到boot目下文件main.c的main函数执行,在这个main函数中我们可以第一次看到与内存管理相关的代码,这段代码调用detect_memeory()函数检测系统物理内存在header.S中执行下面汇编代码:
  1. start_of_setup:  
  2.        .....  
  3. # Jump to C code (should not return)   
  4.     calll   main  
  5.        .....  
跳到boot目录下的main.c文件中
  1. void main(void)  
  2. {  
  3.         ......  
  4.     /* Detect memory layout */  
  5.     detect_memory();/*内存探测函数*/  
  6.     ......  
  7. }  

 
  1. int detect_memory(void)  
  2. {  
  3.     int err = -1;  
  4.   
  5.     if (detect_memory_e820() > 0)  
  6.         err = 0;  
  7.   
  8.     if (!detect_memory_e801())  
  9.         err = 0;  
  10.   
  11.     if (!detect_memory_88())  
  12.         err = 0;  
  13.   
  14.     return err;  
  15. }  
由上面的代码可知,linux内核会分别尝试调用detect_memory_e820()、detcct_memory_e801()、detect_memory_88()获得系统物理内存布局,这3个函数内部其实都会以内联汇编的形式调用bios中断以取得内存信息,该中断调用形式为int 0x15,同时调用前分别把AX寄存器设置为0xe820h、0xe801h、0x88h,关于0x15号中断有兴趣的可以去查询相关手册。下面分析detect_memory_e820()的代码,其它代码基本一样。
  1. #define SMAP    0x534d4150  /* ASCII "SMAP" */   
  2. /*由于历史原因,一些i/o设备也会占据一部分内存 
  3. 物理地址空间,因此系统可以使用的物理内存空 
  4. 间是不连续的,系统内存被分成了很多段,每个段 
  5. 的属性也是不一样的。int 0x15 查询物理内存时每次 
  6. 返回一个内存段的信息,因此要想返回系统中所有 
  7. 的物理内存,我们必须以迭代的方式去查询。 
  8. detect_memory_e820()函数把int 0x15放到一个do-while循环里, 
  9. 每次得到的一个内存段放到struct e820entry里,而 
  10. struct e820entry的结构正是e820返回结果的结构!而像 
  11. 其它启动时获得的结果一样,最终都会被放到 
  12. boot_params里,e820被放到了 boot_params.e820_map。 
  13. */  
  14. static int detect_memory_e820(void)  
  15. {  
  16.     int count = 0;/*用于记录已检测到的物理内存数目*/  
  17.     struct biosregs ireg, oreg;  
  18.     struct e820entry *desc = boot_params.e820_map;  
  19.     static struct e820entry buf; /* static so it is zeroed */  
  20.   
  21.     initregs(&ireg);/*初始化ireg中的相关寄存器*/  
  22.     ireg.ax  = 0xe820;  
  23.     ireg.cx  = sizeof buf;/*e820entry数据结构大小*/  
  24.     ireg.edx = SMAP;/*标识*/  
  25.     ireg.di  = (size_t)&buf;/*int15返回值的存放处*/  
  26.   
  27.     /* 
  28.      * Note: at least one BIOS is known which assumes that the 
  29.      * buffer pointed to by one e820 call is the same one as 
  30.      * the previous call, and only changes modified fields.  Therefore, 
  31.      * we use a temporary buffer and copy the results entry by entry. 
  32.      * 
  33.      * This routine deliberately does not try to account for 
  34.      * ACPI 3+ extended attributes.  This is because there are 
  35.      * BIOSes in the field which report zero for the valid bit for 
  36.      * all ranges, and we don"t currently make any use of the 
  37.      * other attribute bits.  Revisit this if we see the extended 
  38.      * attribute bits deployed in a meaningful way in the future. 
  39.      */  
  40.   
  41.     do {  
  42.         /*在执行这条内联汇编语句时输入的参数有: 
  43.         eax寄存器=0xe820 
  44.         dx寄存器=’SMAP’ 
  45.         edi寄存器=desc 
  46.         ebx寄存器=next 
  47.         ecx寄存器=size 
  48.          
  49.         返回给c语言代码的参数有: 
  50.         id=eax寄存器 
  51.         rr=edx寄存器 
  52.         ext=ebx寄存器 
  53.         size=ecx寄存器 
  54.         desc指向的内存地址在执行0x15中断调用时被设置 
  55.         */  
  56.         intcall(0x15, &ireg, &oreg);  
  57.         /*选择下一个*/  
  58.         ireg.ebx = oreg.ebx; /* for next iteration... */  
  59.   
  60.         /* BIOSes which terminate the chain with CF = 1 as opposed 
  61.            to %ebx = 0 don"t always report the SMAP signature on 
  62.            the final, failing, probe. */  
  63.         if (oreg.eflags & X86_EFLAGS_CF)  
  64.             break;  
  65.   
  66.         /* Some BIOSes stop returning SMAP in the middle of 
  67.            the search loop.  We don"t know exactly how the BIOS 
  68.            screwed up the map at that point, we might have a 
  69.            partial map, the full map, or complete garbage, so 
  70.            just return failure. */  
  71.         if (oreg.eax != SMAP) {  
  72.             count = 0;  
  73.             break;  
  74.         }  
  75.   
  76.         *desc++ = buf;/*将buf赋值给desc*/  
  77.         count++;/*探测数加一*/  
  78.     }   
  79.     while (ireg.ebx && count < ARRAY_SIZE(boot_params.e820_map));  
  80.     /*将内存块数保持到变量中*/  
  81.     return boot_params.e820_entries = count;  
  82. }  
  • 1
  • 2
  • 下一页
Linux物理内存描述RedHat Enterprise Linux 5安装Hyper-V的集成驱动(支持网络适配器 )相关资讯      Linux基础教程 
  • Linux基础教程:对文件打包压缩  (03月08日)
  • 基础教程:Linux 新手应该知道的   (09/06/2015 21:17:20)
  • Linux基础教程:find 与 xargs  (04/05/2015 10:20:11)
  • Linux基础教程:tar 命令使用介绍  (12/03/2015 13:19:47)
  • Linux基础教程(1)操作系统基础   (08/15/2015 20:44:01)
  • Linux基础教程:从源码安装软件  (04/05/2015 10:14:45)
本文评论 查看全部评论 (0)
表情: 姓名: 字数