1.內存管理部分: kalloc.c vm.c 以及相關其餘文件代碼html
// kalloc.c // Physical memory allocator, intended to allocate // memory for user processes, kernel stacks, page table pages, // and pipe buffers. Allocates 4096-byte pages. void freerange(void *vstart, void *vend); extern char end[]; // first address after kernel loaded from ELF file struct run { struct run *next; }; struct { struct spinlock lock; int use_lock; struct run *freelist; } kmem;
// vm.c …… // Switch h/w page table register to the kernel-only page table, // for when no process is running. void switchkvm(void) { lcr3(v2p(kpgdir)); // switch to the kernel page table } // Switch TSS and h/w page table to correspond to process p. void switchuvm(struct proc *p) { pushcli(); cpu->gdt[SEG_TSS] = SEG16(STS_T32A, &cpu->ts, sizeof(cpu->ts)-1, 0); cpu->gdt[SEG_TSS].s = 0; cpu->ts.ss0 = SEG_KDATA << 3; cpu->ts.esp0 = (uint)proc->kstack + KSTACKSIZE; ltr(SEG_TSS << 3); if(p->pgdir == 0) panic("switchuvm: no pgdir"); lcr3(v2p(p->pgdir)); // switch to new address space popcli(); }
1.XV6初始化以後到執行main.c時,內存佈局是怎樣的(其中已有哪些內容)?node
內核代碼存在於物理地址低地址的0x100000處,頁表爲main.c文件中的entrypgdir數組,其中虛擬地址低4M映射物理地址低4M,虛擬地址 [KERNBASE, KERNBASE+4MB) 映射到 物理地址[0, 4MB);git
最後內存佈局和地址空間以下:內核末尾物理地址到物理地址PHYSTOP的內存空間未使用,虛擬地址空間KERNBASE以上部分映射到物理內存低地址相應位置。github
// kalloc.c // Initialization happens in two phases. // 1. main() calls kinit1() while still using entrypgdir to place just // the pages mapped by entrypgdir on free list. // 2. main() calls kinit2() with the rest of the physical pages // after installing a full page table that maps them on all cores. void kinit1(void *vstart, void *vend) { initlock(&kmem.lock, "kmem"); kmem.use_lock = 0; freerange(vstart, vend); } void kinit2(void *vstart, void *vend) { freerange(vstart, vend); kmem.use_lock = 1; } // kmap.c …… // This table defines the kernel's mappings, which are present in // every process's page table. static struct kmap { void *virt; uint phys_start; uint phys_end; int perm; } kmap[] = { { (void*)KERNBASE, 0, EXTMEM, PTE_W}, // I/O space { (void*)KERNLINK, V2P(KERNLINK), V2P(data), 0}, // kern text+rodata { (void*)data, V2P(data), PHYSTOP, PTE_W}, // kern data+memory { (void*)DEVSPACE, DEVSPACE, 0, PTE_W}, // more devices }; ……
2.XV6 的動態內存管理是如何完成的? 有一個kmem(鏈表),用於管理可分配的物理內存頁。(vend=0x00400000,也就是可分配的內存頁最大爲4Mb)
詳見「Exercise 1 源代碼閱讀」部分,已經做出完整解答。數組
3.XV6的虛擬內存是如何初始化的? 畫出XV6的虛擬內存佈局圖,請說出每一部分對應的內容是什麼。見memlayout.h和vm.c的kmap上的註釋?bash
// memlayout.h // Memory layout #define EXTMEM 0x100000 // Start of extended memory #define PHYSTOP 0xE000000 // Top physical memory #define DEVSPACE 0xFE000000 // Other devices are at high addresses // Key addresses for address space layout (see kmap in vm.c for layout) #define KERNBASE 0x80000000 // First kernel virtual address #define KERNLINK (KERNBASE+EXTMEM) // Address where kernel is linked #ifndef __ASSEMBLER__ static inline uint v2p(void *a) { return ((uint) (a)) - KERNBASE; } static inline void *p2v(uint a) { return (void *) ((a) + KERNBASE); } #endif #define V2P(a) (((uint) (a)) - KERNBASE) #define P2V(a) (((void *) (a)) + KERNBASE) #define V2P_WO(x) ((x) - KERNBASE) // same as V2P, but without casts #define P2V_WO(x) ((x) + KERNBASE) // same as V2P, but without casts
4.關於XV6 的內存頁式管理。發生中斷時,用哪一個頁表? 一個內存頁是多大? 頁目錄有多少項? 頁表有多少項? 最大支持多大的內存? 畫出從虛擬地址到物理地址的轉換圖。在XV6中,是如何將虛擬地址與物理地址映射的(調用了哪些函數實現了哪些功能)?數據結構
// vm.c …… // Create PTEs for virtual addresses starting at va that refer to // physical addresses starting at pa. va and size might not // be page-aligned. static int mappages(pde_t *pgdir, void *va, uint size, uint pa, int perm) { char *a, *last; pte_t *pte; a = (char*)PGROUNDDOWN((uint)va); last = (char*)PGROUNDDOWN(((uint)va) + size - 1); for(;;){ if((pte = walkpgdir(pgdir, a, 1)) == 0) return -1; if(*pte & PTE_P) panic("remap"); *pte = pa | perm | PTE_P; if(a == last) break; a += PGSIZE; pa += PGSIZE; } return 0; } ……
[1] xv6虛擬內存-博客園
[2] xv6 virtual memory-hexo
[3] xv6內存管理-簡書
[4] xv6內存管理-CSDNhexo