歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> Linux高端內存管理之非連續內存區(描述)

Linux高端內存管理之非連續內存區(描述)

日期:2017/2/28 15:57:28   编辑:Linux教程

總結了高端內存區的固定內核映射區、臨時內核映射與永久內核映射。但是對於高端內存中各個區間的布置我們任然不是很清楚,首先我們從整體上看看內核對高端內存的劃分情況。

如果內存足夠大(比如用戶:內核線性空間=3:1,內核就只能訪問線性空間的第4GB內容,如果物理內存超過1GB則視為足夠大),內核線性空間無法同時映射所有內存。這就需要將內核線性空間分出一段不直接映射物理內存,而是作為窗口分時映射使用到的未映射的內存。

相關閱讀:

http://www.linuxidc.com/Linux/2012-02/53457.htm

http://www.linuxidc.com/Linux/2012-02/53458.htm

http://www.linuxidc.com/Linux/2012-02/53459.htm

一、非連續內存區布局

Linux內核中對於非連續區間的開始:

[cpp]
  1. #define VMALLOC_START ((unsigned long)high_memory + VMALLOC_OFFSET)
[cpp]
  1. #define VMALLOC_OFFSET (8 * 1024 * 1024)
對於變量high_memory變量:

[cpp]
  1. void __init initmem_init(unsigned long start_pfn,
  2. unsigned long end_pfn)
  3. {
  4. highstart_pfn = highend_pfn = max_pfn;
  5. if (max_pfn > max_low_pfn)
  6. highstart_pfn = max_low_pfn;
  7. ……
  8. num_physpages = highend_pfn;
  9. /*高端內存開始地址物理*/
  10. high_memory = (void *) __va(highstart_pfn * PAGE_SIZE - 1) + 1;
  11. ……
  12. }

其中,變量max_low_pfn在highmem_pfn_init()函數中初始化為下面值

[cpp]
  1. #define MAXMEM (VMALLOC_END - PAGE_OFFSET - __VMALLOC_RESERVE)
[cpp]
  1. <p>unsigned int __VMALLOC_RESERVE = 128 << 20;</p>
對於非連續區間的結束定義:

[cpp]
  1. # define VMALLOC_END (PKMAP_BASE - 2 * PAGE_SIZE)

由上面的內核代碼,畫出內存布局細節圖如下


由上面的布局可知128M+4M+4M+8K,然而直接映射區和連續內存之間空出來了8M的空間不能用,非連續空間和永久內核映射區之間也有8K的空間不可用,另外,內存頂端空出了4K不可用的。這樣,高端內存能用的空間為128M+4M+4M+8K-4K-8M-8K=128M-4K大小的內存。

二、數據結構描述

虛擬內存區描述(對於vmlist鏈表)

[cpp]
  1. struct vm_struct {
  2. struct vm_struct *next;
  3. void *addr;/*內存區的第一個內存單元的線性地址*/
  4. unsigned long size;
  5. unsigned long flags;/*類型*/
  6. struct page **pages;/*指向nr_pages數組的指針,該數組由指向頁描述符的指針組成*/
  7. unsigned int nr_pages;/*內存區填充的頁的個數*/
  8. unsigned long phys_addr;/*該字段設為0,除非內存已被創建來映射一個硬件設備的IO共享內存*/
  9. void *caller;
  10. };

虛擬內存區描述(對於紅黑樹)

[html]
  1. struct vmap_area {
  2. unsigned long va_start;
  3. unsigned long va_end;
  4. unsigned long flags;
  5. struct rb_node rb_node; /* address sorted rbtree */
  6. struct list_head list; /* address sorted list */
  7. struct list_head purge_list; /* "lazy purge" list */
  8. void *private;
  9. struct rcu_head rcu_head;
  10. };

內存區由next字段鏈接到一起,並且為了查找簡單,他們以地址為次序。為了防止溢出,每個區域至少由一個頁面隔離開。

三、非連續內存區初始化 非連續內存區的初始化工作在start_kernel()->mm_init()->vmalloc_init()完成 [cpp]
  1. void __init vmalloc_init(void)
  2. {
  3. struct vmap_area *va;
  4. struct vm_struct *tmp;
  5. int i;
  6. for_each_possible_cpu(i) {
  7. struct vmap_block_queue *vbq;
  8. vbq = &per_cpu(vmap_block_queue, i);
  9. spin_lock_init(&vbq->lock);
  10. INIT_LIST_HEAD(&vbq->free);
  11. INIT_LIST_HEAD(&vbq->dirty);
  12. vbq->nr_dirty = 0;
  13. }
  14. /* Import existing vmlist entries. */
  15. for (tmp = vmlist; tmp; tmp = tmp->next) {/*導入vmlist中已經有的數據到紅黑樹中*/
  16. va = kzalloc(sizeof(struct vmap_area), GFP_NOWAIT);
  17. va->flags = tmp->flags | VM_VM_AREA;
  18. va->va_start = (unsigned long)tmp->addr;
  19. va->va_end = va->va_start + tmp->size;
  20. __insert_vmap_area(va);
  21. }
  22. vmap_area_pcpu_hole = VMALLOC_END;
  23. vmap_initialized = true;/*已經初始化*/
  24. }
Copyright © Linux教程網 All Rights Reserved