歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux基礎 >> Linux教程

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.     ……  
  12. }  
 
  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.   
  10.     /*對e820中所有的內存塊,其中e820為從bios中探測到的頁面數存放處*/  
  11.     for (i = 0; i < e820.nr_map; i++) {  
  12.         struct e820entry *ei = &e820.map[i];/*第i個物理頁面塊*/  
  13.         unsigned long start_pfn;  
  14.         unsigned long end_pfn;  
  15.   
  16.         if (ei->type != type)/*與找的類型不匹配*/  
  17.             continue;  
  18.         /*起始地址對應的頁面幀號*/  
  19.         start_pfn = ei->addr >> PAGE_SHIFT;  
  20.         /*結束物理地址對應的頁面幀號*/  
  21.         end_pfn = (ei->addr + ei->size) >> PAGE_SHIFT;  
  22.   
  23.         if (start_pfn >= limit_pfn)  
  24.             continue;  
  25.         if (end_pfn > limit_pfn) {  
  26.             last_pfn = limit_pfn;/*找到的結束頁面幀號大於限制大小時*/  
  27.             break;  
  28.         }  
  29.         if (end_pfn > last_pfn)  
  30.             last_pfn = end_pfn;/*保存更新last_pfn*/  
  31.     }  
  32.   
  33.     if (last_pfn > max_arch_pfn)/*大於4G空間時*/  
  34.         last_pfn = max_arch_pfn;  
  35.     /*打印輸出信息*/  
  36.     printk(KERN_INFO "last_pfn = %#lx max_arch_pfn = %#lx\n",  
  37.              last_pfn, max_arch_pfn);  
  38.     /*返回最後一個頁面幀號*/  
  39.     return last_pfn;  
  40. }  

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.   
  13.     if (highmem_pages == -1)/*高端內存頁面數如果在開機沒有設置*/  
  14.         highmem_pages = max_pfn - MAXMEM_PFN;/*總頁面數減去低端頁面數*/  
  15.     /*如果highmem_pages變量在啟動項設置了,那麼在這裡就要進行這樣的判斷,因為可能出現不一致的情況*/  
  16.     if (highmem_pages + MAXMEM_PFN < max_pfn)  
  17.         max_pfn = MAXMEM_PFN + highmem_pages;  
  18.   
  19.     if (highmem_pages + MAXMEM_PFN > max_pfn) {  
  20.         printk(KERN_WARNING MSG_HIGHMEM_TOO_SMALL,  
  21.             pages_to_mb(max_pfn - MAXMEM_PFN),  
  22.             pages_to_mb(highmem_pages));  
  23.         highmem_pages = 0;  
  24.     }  
  25. #ifndef CONFIG_HIGHMEM   
  26.     /* Maximum memory usable is what is directly addressable */  
  27.     printk(KERN_WARNING "Warning only %ldMB will be used.\n", MAXMEM>>20);  
  28.     if (max_pfn > MAX_NONPAE_PFN)  
  29.         printk(KERN_WARNING "Use a HIGHMEM64G enabled kernel.\n");  
  30.     else  
  31.         printk(KERN_WARNING "Use a HIGHMEM enabled kernel.\n");  
  32.     max_pfn = MAXMEM_PFN;  
  33. #else /* !CONFIG_HIGHMEM *//*存在高端地址情況*/   
  34. #ifndef CONFIG_HIGHMEM64G   
  35.     /*在沒有配置64G的情況下,內存的大小不能超過4G*/  
  36.     if (max_pfn > MAX_NONPAE_PFN) {  
  37.         max_pfn = MAX_NONPAE_PFN;  
  38.         printk(KERN_WARNING MSG_HIGHMEM_TRIMMED);  
  39.     }  
  40. #endif /* !CONFIG_HIGHMEM64G */   
  41. #endif /* !CONFIG_HIGHMEM */   
  42. }  
Copyright © Linux教程網 All Rights Reserved