高级操作系统——XV6内存管理
xv6閱讀報告
一:XV6 執行 main.c 時,內存布局是怎樣的(其中已有哪些內容)?
首先經過entry.S,使得
1:內核代碼存在于物理地址低地址的0x100000處具體怎樣實現的不清楚?
2:通過頁表為main.c文件中的entrypgdir數組,使得虛擬地址 [KERNBASE, KERNBASE+4MB) 映射到物理地址[0, 4MB)
其中PTE_P =0x001 PTE_W=0x002 PTE_U=0x004 PDXSHIFT=22(4MB)具體怎樣實現的不清楚?
二: XV6 的動態內存管理是如何完成的? 有一個 kmem(鏈表),用于管理可分配的物理內
存頁。(vend=0x00400000,也就是可分配的內存頁最大為 4Mb)
首先明確動態內存管理是什么?指的是物理地址如何管理的(與虛擬無關)
XV6將物理地址按照頁(4MB)連接成鏈表,當需要申請一個物理頁時,就從freelist中摘下一頁
可以看到主要擁有數據結構struct run *freelist,這個類似于利用鏈表管理頁表當想分配頁表時,利用函數kalloc(void),當想回收頁表時,利用函數kfree(char *v)
那么分配器從哪里獲得內存來存放這些數據結構呢?實際上,分配器將每個空閑頁的 run 結構體保存在該空閑頁本身中,因為空閑頁中沒有其他數據。分配器還用一個 spin lock來保護空閑鏈表。鏈表和這個鎖都封裝在一個結構體中,這樣邏輯就比較明晰:鎖保護了該結構體中的域
那么freelist是如何初始化的呢?
是通過main.cc里的kinit1和kinit2進行初始化
kinit1(end, P2V(410241024))
kinit2(P2V(410241024), P2V(PHYSTOP))
1:從這里我們可以看到,是將end(這里是kernal data=end)到PHYSTOP之間的物理地址初始化給freelist因為0x0到0x01000000分配給I/O,0x01000000-kernal data分配給內核數據和代碼。那至于PHYSTOP到-0xffffffff的數據如何初始化,我也不知道
2:在memlayout.h中有如下定義
可以看到xv6中物理地址轉為虛擬地址直接+KERNBASE,原因在于xv6將
虛擬地址KERNBASE:KERNBASE+PHYSTOP直接映射為物理地址的0:PHYSTOP所以直接加減很方便的實現轉化
為什么要分開成兩部初始化?
我的理解是kinit1使用的是頁表entrypgdir,所以只能初始化4MB,而kinit2使用的是kpgdir ,所可以初始化其他部分。同時由于后期再構建新頁表時也要使用頁表轉換機制來找到實際存放頁表的物理內存空間,這就構成了自舉問題具體怎樣實現的不清楚?
初始化操作解讀:以kinit1為例子
void kinit1(void *vstart, void *vend) {initlock(&kmem.lock, "kmem");kmem.use_lock = 0;freerange(vstart, vend); }可以看到調用freerange,freerange可以理解為初始化vstart到vend的物理頁
void freerange(void *vstart, void *vend) {char *p;p = (char*)PGROUNDUP((uint)vstart);for(; p + PGSIZE <= (char*)vend; p += PGSIZE)kfree(p); }可以看到vstart轉化成p ,根據判斷 p + PGSIZE <= (char*)vend即一次初始化一頁,知道到達vend停止,kfree為初始化一頁
voidkfree(char *v){struct run *r;if((uint)v % PGSIZE || v < end || v2p(v) >= PHYSTOP)panic("kfree");// Fill with junk to catch dangling refs.memset(v, 1, PGSIZE);if(kmem.use_lock)acquire(&kmem.lock);r = (struct run*)v;r->next = kmem.freelist;kmem.freelist = r;if(kmem.use_lock)release(&kmem.lock);}可以看到kfree主要執行
1:判斷是否越界 小于end或者大于PHYSTOP
2:將物理地址對應的值初始化為1
3:將物理頁放在freelist上
三: XV6 的虛擬內存是如何初始化的?畫出 XV6 的虛擬內存布局圖,請說出每一部分對應的
內容是什么。 見 memlayout.h 和 vm.c 的 kmap 上的注釋
首先明白什么是虛擬內存是如何初始化?其實這里應該理解為如何為進程的虛擬空間的內核空間分配物理頁。首先明確幾點
1:進程的虛擬空間分為用戶空間和內核空間,每個進程的用戶空間單獨享有,內核空間共享。用戶空間是在創建進程的時候分配,內核空間實在操作系統初始化后分配
2:因為用戶的內核空間目前還只有虛擬頁,理解為用戶空間的內核空間第i頁有什么呢?內核代碼?沒有,內核數據?沒有,因為此時還沒有對應物理頁,所以我們需要建立虛擬空間到物理空間的映射關系
虛擬內存的初始化是main.c中的kvmalloc()執行
kvmalloc(void) {kpgdir = setupkvm();switchkvm(); }可以看到關鍵是setupkvm,返回一個目錄kpgdir ,這就是用戶的內核空間頁表[PTE]
pde_t* setupkvm(void) {pde_t *pgdir;struct kmap *k;//分配頁表if((pgdir = (pde_t*)kalloc()) == 0)return 0;memset(pgdir, 0, PGSIZE);if (p2v(PHYSTOP) > (void*)DEVSPACE)panic("PHYSTOP too high");for(k = kmap; k < &kmap[NELEM(kmap)]; k++)//kmap[NELEM(kmap)]=kmap[4]if(mappages(pgdir, k->virt, k->phys_end - k->phys_start, (uint)k->phys_start, k->perm) < 0)//return 0;return pgdir; }setupkvm主要完成以下工作:
1:if((pgdir=(pde_t*)kalloc()) == 0) kalloc()為申請一頁物理地址,返回為pgdir。
補充:注意到kalloc()
是從freelist中申請一頁,而這一頁正好是我們kinit1初始化的!
2:完成映射整塊【很多頁】虛擬地址到物理地址的映射工作,相當于此時pgdir就已經是一項項頁表,內含物理地址,虛擬地址,PTE_P,PTE_W,PTE_PS等等
這里我們必須看一下
kmap由四值組成,分別是虛擬地址 ,物理起始地址,物理結束地址,是否可讀
而執行具體的初始化頁表項的操作是由mappages完成
mappages主要完成起始就是從起始地址a到結束地址last,將其中的虛擬地址映射為物理地址。而walkpgdir是將一頁虛擬與物理的映射
static pte_t * walkpgdir(pde_t *pgdir, const void *va, int alloc) {pde_t *pde;pte_t *pgtab;pde = &pgdir[PDX(va)];if(*pde & PTE_P){pgtab = (pte_t*)p2v(PTE_ADDR(*pde));} else {if(!alloc || (pgtab = (pte_t*)kalloc()) == 0)return 0;memset(pgtab, 0, PGSIZE);*pde = v2p(pgtab) | PTE_P | PTE_W | PTE_U;}return &pgtab[PTX(va)]; }可以看到 *pde = v2p(pgtab) | PTE_P | PTE_W | PTE_U;這里可以理解為pde 就含有物理地址,是否存在,是否寫,屬于哪個用戶信息
至此,分配結束
此時我們可以看一下,整個虛擬空間和內核空間的映射如下
僅僅是個人猜測
關于對應關系:
首先說明一些宏定義:
虛擬地址:
#define KERNBASE 0x80000000 // 內核虛擬地址的起始位置
#define EXTMEM 0x100000 // 擴展內存的起始位置
#define KERNLINK (KERNBASE+EXTMEM) //內核的連接地址
#define DEVSPACE 0xFE000000 // 其余設備在高地址空間
物理地址:
#define PHYSTOP 0xE000000 // 224M的物理內存
說明:0xFFFFFFFF不知道書寫是否正確,反正就是到頂
總結
以上是生活随笔為你收集整理的高级操作系统——XV6内存管理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ubuntu搭建xv6环境
- 下一篇: #_1 Win10原版镜像安装教程 +