歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> Linux物理內存探測

Linux物理內存探測

日期:2017/2/28 16:00:21   编辑: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. if (detect_memory_e820() > 0)
  5. err = 0;
  6. if (!detect_memory_e801())
  7. err = 0;
  8. if (!detect_memory_88())
  9. err = 0;
  10. return err;
  11. }
由上面的代碼可知,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. initregs(&ireg);/*初始化ireg中的相關寄存器*/
  21. ireg.ax = 0xe820;
  22. ireg.cx = sizeof buf;/*e820entry數據結構大小*/
  23. ireg.edx = SMAP;/*標識*/
  24. ireg.di = (size_t)&buf;/*int15返回值的存放處*/
  25. /*
  26. * Note: at least one BIOS is known which assumes that the
  27. * buffer pointed to by one e820 call is the same one as
  28. * the previous call, and only changes modified fields. Therefore,
  29. * we use a temporary buffer and copy the results entry by entry.
  30. *
  31. * This routine deliberately does not try to account for
  32. * ACPI 3+ extended attributes. This is because there are
  33. * BIOSes in the field which report zero for the valid bit for
  34. * all ranges, and we don't currently make any use of the
  35. * other attribute bits. Revisit this if we see the extended
  36. * attribute bits deployed in a meaningful way in the future.
  37. */
  38. do {
  39. /*在執行這條內聯匯編語句時輸入的參數有:
  40. eax寄存器=0xe820
  41. dx寄存器=’SMAP’
  42. edi寄存器=desc
  43. ebx寄存器=next
  44. ecx寄存器=size
  45. 返回給c語言代碼的參數有:
  46. id=eax寄存器
  47. rr=edx寄存器
  48. ext=ebx寄存器
  49. size=ecx寄存器
  50. desc指向的內存地址在執行0x15中斷調用時被設置
  51. */
  52. intcall(0x15, &ireg, &oreg);
  53. /*選擇下一個*/
  54. ireg.ebx = oreg.ebx; /* for next iteration... */
  55. /* BIOSes which terminate the chain with CF = 1 as opposed
  56. to %ebx = 0 don't always report the SMAP signature on
  57. the final, failing, probe. */
  58. if (oreg.eflags & X86_EFLAGS_CF)
  59. break;
  60. /* Some BIOSes stop returning SMAP in the middle of
  61. the search loop. We don't know exactly how the BIOS
  62. screwed up the map at that point, we might have a
  63. partial map, the full map, or complete garbage, so
  64. just return failure. */
  65. if (oreg.eax != SMAP) {
  66. count = 0;
  67. break;
  68. }
  69. *desc++ = buf;/*將buf賦值給desc*/
  70. count++;/*探測數加一*/
  71. }
  72. while (ireg.ebx && count < ARRAY_SIZE(boot_params.e820_map));
  73. /*將內存塊數保持到變量中*/
  74. return boot_params.e820_entries = count;
  75. }
Copyright © Linux教程網 All Rights Reserved