歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> Linux物理內存管理區初始化

Linux物理內存管理區初始化

日期:2017/2/28 16:00:22   编辑:Linux教程

Linux物理內存管理區在start_kernel函數中進行初始化,此時啟動分配器已經建立,所以可以從bootmem中分配需要的內存。

一、全局變量初始化

max_pfn:最大物理頁面幀號

start_kernel()->setup_arch()->e820_end_of_ram_pfn()找出最大可用內存頁面幀號。

  1. void __init setup_arch(char **cmdline_p)
  2. {
  3. ……
  4. /*
  5. * partially used pages are not usable - thus
  6. * we are rounding upwards:
  7. */
  8. /*遍歷e820.map,找到系統中得最大內存數,
  9. 這個內存數需小於4G*/
  10. max_pfn = e820_end_of_ram_pfn();
  11. ……
  1. unsigned long __init e820_end_of_ram_pfn(void)
  2. {
  3. /*MAX_ARCH_PFN為4G空間*/
  4. return e820_end_pfn(MAX_ARCH_PFN, E820_RAM);
  5. }
  1. /*
  2. * Find the highest page frame number we have available
  3. */
  4. static unsigned long __init e820_end_pfn(unsigned long limit_pfn, unsigned type)
  5. {
  6. int i;
  7. unsigned long last_pfn = 0;
  8. unsigned long max_arch_pfn = MAX_ARCH_PFN;/*4G地址空間對應的頁面數*/
  9. /*對e820中所有的內存塊,其中e820為從bios中探測到的頁面數存放處*/
  10. for (i = 0; i < e820.nr_map; i++) {
  11. struct e820entry *ei = &e820.map[i];/*第i個物理頁面塊*/
  12. unsigned long start_pfn;
  13. unsigned long end_pfn;
  14. if (ei->type != type)/*與找的類型不匹配*/
  15. continue;
  16. /*起始地址對應的頁面幀號*/
  17. start_pfn = ei->addr >> PAGE_SHIFT;
  18. /*結束物理地址對應的頁面幀號*/
  19. end_pfn = (ei->addr + ei->size) >> PAGE_SHIFT;
  20. if (start_pfn >= limit_pfn)
  21. continue;
  22. if (end_pfn > limit_pfn) {
  23. last_pfn = limit_pfn;/*找到的結束頁面幀號大於限制大小時*/
  24. break;
  25. }
  26. if (end_pfn > last_pfn)
  27. last_pfn = end_pfn;/*保存更新last_pfn*/
  28. }
  29. if (last_pfn > max_arch_pfn)/*大於4G空間時*/
  30. last_pfn = max_arch_pfn;
  31. /*打印輸出信息*/
  32. printk(KERN_INFO "last_pfn = %#lx max_arch_pfn = %#lx\n",
  33. last_pfn, max_arch_pfn);
  34. /*返回最後一個頁面幀號*/
  35. return last_pfn;
  36. }

max_low_pfn:低端內存最大頁面數

start_kernel()->setup_arch()->find_low_pfn_range()

  1. /*
  2. * Determine low and high memory ranges:
  3. */
  4. /*找到低端內存的做大內存頁面數,初始化兩個變量*/
  5. void __init find_low_pfn_range(void)
  6. {
  7. /* it could update max_pfn */
  8. /*當內存的大小本來就小於低端內存的做大頁框數時;
  9. 直接沒有高端地址映射*/
  10. if (max_pfn <= MAXMEM_PFN)
  11. lowmem_pfn_init();
  12. else/*這是一般PC機的運行流程,存在高端映射*/
  13. highmem_pfn_init();
  14. }

我們直接看具有高端地址空間的部分。

  1. /*
  2. * We have more RAM than fits into lowmem - we try to put it into
  3. * highmem, also taking the highmem=x boot parameter into account:
  4. */
  5. /*高端地址空間的頁面數可以在啟動中進行配置;
  6. 如果不配置,在這裡進行設置大小*/
  7. void __init highmem_pfn_init(void)
  8. {
  9. /*MAXMEM_PFN為最大物理地址-(4M+4M+8K+128M);
  10. 所以低端內存的大小其實比我們說的896M低一些*/
  11. max_low_pfn = MAXMEM_PFN;
  12. if (highmem_pages == -1)/*高端內存頁面數如果在開機沒有設置*/
  13. highmem_pages = max_pfn - MAXMEM_PFN;/*總頁面數減去低端頁面數*/
  14. /*如果highmem_pages變量在啟動項設置了,那麼在這裡就要進行這樣的判斷,因為可能出現不一致的情況*/
  15. if (highmem_pages + MAXMEM_PFN < max_pfn)
  16. max_pfn = MAXMEM_PFN + highmem_pages;
  17. if (highmem_pages + MAXMEM_PFN > max_pfn) {
  18. printk(KERN_WARNING MSG_HIGHMEM_TOO_SMALL,
  19. pages_to_mb(max_pfn - MAXMEM_PFN),
  20. pages_to_mb(highmem_pages));
  21. highmem_pages = 0;
  22. }
  23. #ifndef CONFIG_HIGHMEM
  24. /* Maximum memory usable is what is directly addressable */
  25. printk(KERN_WARNING "Warning only %ldMB will be used.\n", MAXMEM>>20);
  26. if (max_pfn > MAX_NONPAE_PFN)
  27. printk(KERN_WARNING "Use a HIGHMEM64G enabled kernel.\n");
  28. else
  29. printk(KERN_WARNING "Use a HIGHMEM enabled kernel.\n");
  30. max_pfn = MAXMEM_PFN;
  31. #else /* !CONFIG_HIGHMEM *//*存在高端地址情況*/
  32. #ifndef CONFIG_HIGHMEM64G
  33. /*在沒有配置64G的情況下,內存的大小不能超過4G*/
  34. if (max_pfn > MAX_NONPAE_PFN) {
  35. max_pfn = MAX_NONPAE_PFN;
  36. printk(KERN_WARNING MSG_HIGHMEM_TRIMMED);
  37. }
  38. #endif /* !CONFIG_HIGHMEM64G */
  39. #endif /* !CONFIG_HIGHMEM */
  40. }
Copyright © Linux教程網 All Rights Reserved