1. 程式人生 > >Linux 虛擬地址與實體地址的對映關係分析

Linux 虛擬地址與實體地址的對映關係分析

Ordeder原創文章,原文連結: http://blog.csdn.net/ordeder/article/details/41630945

原始碼版本 2.4.0

1. 虛擬空間

0-3G 使用者空間  0x00000000  ~ 0xbfffffff

3-4G 核心空間     0xc0000000 ~ 0xffffffff

每個使用者程序都有獨立的使用者空間(虛擬地址0-3),而核心空間是唯一的(相當於共享)

每個程序的使用者空間用mm_struct描述,即task_struct.mm。

2.程序虛擬地址的組織

2.1 虛擬空間、使用者空間

struct mm_struct {
	struct vm_area_struct * mmap;	/* list of VMAs */
	...
	pgd_t * pgd;				//用於地址對映
	atomic_t mm_users;			/* How many users with user space? */
	atomic_t mm_count;			/* How many references to "struct mm_struct" (users count as 1) */
	int map_count;				/* number of VMAs */
	...
	//描述使用者空間的段分佈:資料段,程式碼段,堆疊段
	unsigned long start_code, end_code, start_data, end_data;
	unsigned long start_brk, brk, start_stack;
	unsigned long arg_start, arg_end, env_start, env_end;
	unsigned long rss, total_vm, locked_vm;
	...
};
以上結構描述了程序的使用者空間的結構,其中
pgd_t    是該程序使用者空間地址對映到實體地址時使用
vm_area_struct 是程序使用者空間已對映到物理空間的虛擬地址區間,mmap是該空間區塊組成的連結串列。

虛擬空間的空洞:虛擬空間還未被對映的區塊(即沒有被使用),那麼就沒有vm_area_struct結構

2.2 記憶體區間

/*
 * This struct defines a memory VMM memory area. There is one of these
 * per VM-area/task.  A VM area is any part of the process virtual memory
 * space that has a special rule for the page-fault handlers (ie a shared
 * library, the executable area etc).
 */
struct vm_area_struct {
	struct mm_struct * vm_mm;	/* VM area parameters */
	unsigned long vm_start;		//虛擬空間起始地址
	unsigned long vm_end;		//終止地址

	/* linked list of VM areas per task, sorted by address */
	struct vm_area_struct *vm_next;
	
	//該區間的許可權及標誌
	pgprot_t vm_page_prot;
	unsigned long vm_flags;
	
	//一些vm_area 的連結
	...
	struct vm_operations_struct * vm_ops;
	unsigned long vm_pgoff;		/* offset in PAGE_SIZE units, *not* PAGE_CACHE_SIZE */
	struct file * vm_file;		//用於將磁碟檔案對映至使用者空間
	...
};

虛擬空間區間的描述中:
vm_start/vm_end    為該區塊的起始和結束地址
vm_file    是在檔案對映中使用到,即常用的mmap(fd,...)函式,簡單說即將虛擬空間對映至檔案在核心的緩衝區,那麼這時候訪問該虛擬空間將有別於pgd的對映。
vm_operations_struct 為本虛擬區間的操作,其中的nopage函式指標是處理記憶體缺頁而使用的。對於通用的記憶體對映,該缺頁處理函式為do_no_page()將虛擬地址對映到實體地址(匿名對映):分配物理頁& 設定pgd & pte。
而對於mmap操作相關的虛擬地址,其缺頁處理函式將和檔案系統的缺頁函式相關,filemap_nopage(),通過檔案系統的缺頁從磁碟將相關檔案塊載入如核心緩衝區.
struct vm_operations_struct {
	void (*open)(struct vm_area_struct * area);
	void (*close)(struct vm_area_struct * area);
	struct page * (*nopage)(struct vm_area_struct * area, unsigned long address, int write_access); 	//缺頁操作
};


3.系統實體地址的組織

核心將實體地址按頁來組織,struct page描述系統的物理頁的資訊,但是頁的資料內容是不在該結構中的。系統有全域性資料 struct page mem_map[],用於記錄每個物理頁。
頁面大小為4kb,在原始碼中用體現為(PAGE_SHIFT = 12)

/*
 * Try to keep the most commonly accessed fields in single cache lines
 * here (16 bytes or greater).  This ordering should be particularly
 * beneficial on 32-bit processors.
 *
 * The first line is data used in page cache lookup, the second line
 * is used for linear searches (eg. clock algorithm scans). 
 */
typedef struct page {
	struct list_head list;
	struct address_space *mapping;
	unsigned long index;
	struct page *next_hash;
	atomic_t count;
	unsigned long flags;	/* atomic flags, some possibly updated asynchronously */
	struct list_head lru;
	unsigned long age;
	wait_queue_head_t wait;
	struct page **pprev_hash;
	struct buffer_head * buffers;
	void *virtual; /* non-NULL if kmapped */
	struct zone_struct *zone;
} mem_map_t;

struct page是用於描述一個物理頁面,該結構僅僅是作為描述,也就是說該頁面的4kb資料時儲存於某個連續的4kb的物理空間(由MMU決定,具體見下文)。其中:
lru    頁面緩衝的排程策略(最少使用優先)

題外話:
page也可以用於檔案緩衝,相關引數及作用:
buffer_head    是和裝置檔案相關的操作,例如在檔案系統中,file的一個page有4個塊,這些塊就儲存於buffer_head連結串列指定的記憶體中。
index 在檔案系統中是用於file緩衝的頁號。

3.1 使用者空間頁面目錄(對映關係)

程序的虛擬空間描述中,pgd是用於頁式儲存的對映使用。當核心發生程序切換時,將新程序的pgd載入CR3暫存器,CPU中的MMU單元依據CR3暫存器進行頁面對映。

pgd,pmd和pte可以看做是陣列,為程序的地址空間到物理空間實現對映。其中虛擬地址的高位地址決定pgd,中間段地址決定pmd,而低位地址決定pte,pte是“page table entry”。
最終定位的pte中存放的即為對應物理頁面的指標。
typedef struct { unsigned long pte; } pte_t;
typedef struct { unsigned long pmd; } pmd_t;
typedef struct { unsigned long pgd; } pgd_t;
typedef struct { unsigned long pgprot; } pgprot_t;	//操作標誌


3.2使用者空間的對映:

1. 使用者空間的虛擬地址vaddr通過MMU(pgd,pmd,pte)找到對應的頁表項x(即為實體地址)
2. 頁表項x的高20位是物理也好,物理頁號index = x >> PAGE_SHIFT, 同理,index後面補上12個0就是物理頁表的首地址。
3. 通過物理頁號,我們可以再核心中找到該物理頁的描述的指標mem_map[index],當然這個指標是虛擬地址,page結構見上文。


3.3核心空間虛擬地址的對映:

核心空間與實體地址之間有直接的對映關係,而不需要向用戶空間那樣通過mmu(pgd)。系統空間對映(3G開始)到物理空間0G起始:
例如:
系統核心映像載入的虛擬地址為3G+1M的起始地址,那麼對應的實體地址為1M。
緊接著分配在3G+2M開始分配了8M的虛擬地址(實體地址為2-9M)用於PDG
之後預留了16M空間用DMA於儲存。
而全域性的page結構的mem_page[]陣列是在0xc1000000開始的。
所以核心空間虛擬地址到實體地址的轉換為:

PAGE_OFFSET = 3GB
vitr_to_phys(kadd)
  return vadd - PAGE_OFFSET
  
核心空間的虛擬地址vaddr是通過如下方式找到它對應實體地址的page結構:
vitr_to_page(vadd)
	index = virt_to_phys(kadd) >> PAGE_SHIFT
	return mem_map[index]

4. 相關資料結構關係圖

說明:

1. 黑色+紅色 箭頭展示了虛擬地址空間到物理空間的對映關係

2. 藍色箭頭涉涉及到檔案的對映操作mmap(),相比匿名對映,檔案對映多了檔案層的磁碟IO。