task5 finished
This commit is contained in:
@ -186,6 +186,8 @@ void vmprint(pagetable_t);
|
||||
#endif
|
||||
#ifdef LAB_PGTBL
|
||||
pte_t* pgpte(pagetable_t, uint64);
|
||||
void superfree(void *pa);
|
||||
void* superalloc();
|
||||
#endif
|
||||
|
||||
// plic.c
|
||||
|
||||
@ -23,10 +23,46 @@ struct {
|
||||
struct run *freelist;
|
||||
} kmem;
|
||||
|
||||
struct super_run {
|
||||
struct super_run *next;
|
||||
};
|
||||
|
||||
struct {
|
||||
struct spinlock lock;
|
||||
struct super_run *freelist;
|
||||
} skmem;
|
||||
|
||||
void superfree(void *pa) {
|
||||
struct super_run *r;
|
||||
|
||||
if(((uint64)pa % SUPERPGSIZE) != 0 || (char*)pa < end || (uint64)pa >= PHYSTOP)
|
||||
panic("superfree");
|
||||
|
||||
// Fill with junk to catch dangling refs.
|
||||
memset(pa, 1, SUPERPGSIZE);
|
||||
|
||||
r = (struct super_run *)pa;
|
||||
acquire(&skmem.lock);
|
||||
r->next = skmem.freelist;
|
||||
skmem.freelist = r;
|
||||
release(&skmem.lock);
|
||||
}
|
||||
|
||||
void* superalloc() {
|
||||
struct super_run *r;
|
||||
acquire(&skmem.lock);
|
||||
r = skmem.freelist;
|
||||
if(r) skmem.freelist = r->next;
|
||||
release(&skmem.lock);
|
||||
if(r) memset((void*)r, 0, SUPERPGSIZE);
|
||||
return (void*)r;
|
||||
}
|
||||
|
||||
void
|
||||
kinit()
|
||||
{
|
||||
initlock(&kmem.lock, "kmem");
|
||||
initlock(&skmem.lock, "skmem");
|
||||
freerange(end, (void*)PHYSTOP);
|
||||
}
|
||||
|
||||
@ -35,9 +71,22 @@ freerange(void *pa_start, void *pa_end)
|
||||
{
|
||||
char *p;
|
||||
p = (char*)PGROUNDUP((uint64)pa_start);
|
||||
for(; p + PGSIZE <= (char*)pa_end; p += PGSIZE)
|
||||
for(; p + PGSIZE <= (char*)pa_end - 12 * 1024 * 1024; p += PGSIZE) //留5个巨页
|
||||
kfree(p);
|
||||
|
||||
p = (char*)SUPERPGROUNDUP((uint64)p);
|
||||
for (; p + SUPERPGSIZE <= (char *)pa_end; p += SUPERPGSIZE) {
|
||||
superfree(p);
|
||||
}
|
||||
}
|
||||
// void
|
||||
// freerange(void *pa_start, void *pa_end)
|
||||
// {
|
||||
// char *p;
|
||||
// p = (char*)PGROUNDUP((uint64)pa_start);
|
||||
// for(; p + PGSIZE <= (char*)pa_end; p += PGSIZE)
|
||||
// kfree(p);
|
||||
// }
|
||||
|
||||
// Free the page of physical memory pointed at by pa,
|
||||
// which normally should have been returned by a
|
||||
|
||||
@ -377,7 +377,7 @@ typedef uint64 *pagetable_t; // 512 PTEs
|
||||
#define PTE_U (1L << 4) // user can access
|
||||
#define PTE_A (1L << 6) // Accessed bit
|
||||
#define PTE_D (1L << 7) // Dirty bit
|
||||
#define PTE_PS (1L << 7) // Page Size bit in PTE (for 2MB superpages)
|
||||
#define PTE_PS (1L << 8) // Page Size bit in PTE (for 2MB superpages)
|
||||
|
||||
|
||||
#if defined(LAB_MMAP) || defined(LAB_PGTBL)
|
||||
|
||||
296
kernel/vm.c
296
kernel/vm.c
@ -104,12 +104,9 @@ walk(pagetable_t pagetable, uint64 va, int alloc)
|
||||
for(int level = 2; level > 0; level--) {
|
||||
pte_t *pte = &pagetable[PX(level, va)];
|
||||
if(*pte & PTE_V) {
|
||||
if (*pte & PTE_PS) { // 如果是 Superpage
|
||||
return pte;
|
||||
}
|
||||
pagetable = (pagetable_t)PTE2PA(*pte);
|
||||
#ifdef LAB_PGTBL
|
||||
if(PTE_LEAF(*pte)) {
|
||||
if (*pte & PTE_PS) {
|
||||
return pte;
|
||||
}
|
||||
#endif
|
||||
@ -123,6 +120,25 @@ walk(pagetable_t pagetable, uint64 va, int alloc)
|
||||
return &pagetable[PX(0, va)];
|
||||
}
|
||||
|
||||
pte_t *
|
||||
super_walk(pagetable_t pagetable, uint64 va, int alloc)
|
||||
{
|
||||
if (va > MAXVA)
|
||||
panic("walk");
|
||||
|
||||
pte_t *pte = &(pagetable[PX(2, va)]);
|
||||
if (*pte & PTE_V) {
|
||||
pagetable = (pagetable_t)PTE2PA(*pte);
|
||||
} else {
|
||||
if (!alloc || (pagetable = (pde_t*)kalloc()) == 0)
|
||||
return 0;
|
||||
memset(pagetable, 0, PGSIZE);
|
||||
*pte = PA2PTE(pagetable) | PTE_V;
|
||||
}
|
||||
|
||||
return &pagetable[PX(1, va)];
|
||||
}
|
||||
|
||||
// Look up a virtual address, return the physical address,
|
||||
// or 0 if not mapped.
|
||||
// Can only be used to look up user pages.
|
||||
@ -143,6 +159,13 @@ walkaddr(pagetable_t pagetable, uint64 va)
|
||||
if((*pte & PTE_U) == 0)
|
||||
return 0;
|
||||
pa = PTE2PA(*pte);
|
||||
if(*pte & PTE_PS) {
|
||||
// For superpages, add the offset within the superpage
|
||||
pa += va & (SUPERPGSIZE - 1);
|
||||
} else {
|
||||
// For regular pages, add the offset within the page
|
||||
pa += va & (PGSIZE - 1);
|
||||
}
|
||||
return pa;
|
||||
}
|
||||
|
||||
@ -178,18 +201,35 @@ mappages(pagetable_t pagetable, uint64 va, uint64 size, uint64 pa, int perm)
|
||||
panic("mappages: size");
|
||||
|
||||
a = va;
|
||||
last = va + size - PGSIZE;
|
||||
for(;;){
|
||||
if((pte = walk(pagetable, a, 1)) == 0)
|
||||
return -1;
|
||||
if(*pte & PTE_V)
|
||||
panic("mappages: remap");
|
||||
*pte = PA2PTE(pa) | perm | PTE_V;
|
||||
if(a == last)
|
||||
break;
|
||||
a += PGSIZE;
|
||||
pa += PGSIZE;
|
||||
|
||||
if ((perm & PTE_PS) == 0) { /*不使用巨页*/
|
||||
last = va + size - PGSIZE;
|
||||
for(;;){
|
||||
if((pte = walk(pagetable, a, 1)) == 0)
|
||||
return -1;
|
||||
if(*pte & PTE_V)
|
||||
panic("mappages: remap");
|
||||
*pte = PA2PTE(pa) | perm | PTE_V;
|
||||
if(a == last)
|
||||
break;
|
||||
a += PGSIZE;
|
||||
pa += PGSIZE;
|
||||
}
|
||||
} else { /* 使用巨页 */
|
||||
last = va + size - SUPERPGSIZE;
|
||||
for (;;) {
|
||||
if ((pte = super_walk(pagetable, a, 1)) == 0)
|
||||
return -1;
|
||||
if (*pte & PTE_V)
|
||||
panic("super mappages: remap");
|
||||
*pte = PA2PTE(pa) | perm | PTE_V;
|
||||
if (a == last)
|
||||
break;
|
||||
a += SUPERPGSIZE;
|
||||
pa += SUPERPGSIZE;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -205,7 +245,6 @@ uvmunmap(pagetable_t pagetable, uint64 va, uint64 npages, int do_free)
|
||||
|
||||
if((va % PGSIZE) != 0)
|
||||
panic("uvmunmap: not aligned");
|
||||
|
||||
for(a = va; a < va + npages*PGSIZE; a += sz){
|
||||
sz = PGSIZE;
|
||||
if((pte = walk(pagetable, a, 0)) == 0)
|
||||
@ -216,11 +255,20 @@ uvmunmap(pagetable_t pagetable, uint64 va, uint64 npages, int do_free)
|
||||
}
|
||||
if(PTE_FLAGS(*pte) == PTE_V)
|
||||
panic("uvmunmap: not a leaf");
|
||||
if(do_free){
|
||||
uint64 pa = PTE2PA(*pte);
|
||||
kfree((void*)pa);
|
||||
if ((*pte & PTE_PS)) { /* 释放巨页 */
|
||||
if(do_free){
|
||||
uint64 pa = PTE2PA(*pte);
|
||||
superfree((void*)pa);
|
||||
}
|
||||
*pte = 0;
|
||||
a += SUPERPGSIZE - sz;
|
||||
} else {
|
||||
if(do_free){
|
||||
uint64 pa = PTE2PA(*pte);
|
||||
kfree((void*)pa);
|
||||
}
|
||||
*pte = 0;
|
||||
}
|
||||
*pte = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -261,28 +309,85 @@ uvmalloc(pagetable_t pagetable, uint64 oldsz, uint64 newsz, int xperm)
|
||||
{
|
||||
char *mem;
|
||||
uint64 a;
|
||||
int sz;
|
||||
|
||||
|
||||
if(newsz < oldsz)
|
||||
return oldsz;
|
||||
|
||||
oldsz = PGROUNDUP(oldsz);
|
||||
for(a = oldsz; a < newsz; a += sz){
|
||||
sz = PGSIZE;
|
||||
mem = kalloc();
|
||||
if(mem == 0){
|
||||
uvmdealloc(pagetable, a, oldsz);
|
||||
return 0;
|
||||
|
||||
// Check if the allocation should use superpages
|
||||
// We use superpages if we're allocating at least 2MB AND
|
||||
// the range contains a superpage-aligned 2MB region
|
||||
if (newsz - oldsz >= SUPERPGSIZE) {
|
||||
uint64 super_start = SUPERPGROUNDUP(oldsz);
|
||||
uint64 super_end = newsz & ~(SUPERPGSIZE - 1); // Round down to superpage boundary
|
||||
|
||||
// Allocate regular pages before the first superpage boundary
|
||||
for(a = oldsz; a < super_start; a += PGSIZE){
|
||||
mem = kalloc();
|
||||
if(mem == 0){
|
||||
uvmdealloc(pagetable, a, oldsz);
|
||||
return 0;
|
||||
}
|
||||
#ifndef LAB_SYSCALL
|
||||
memset(mem, 0, PGSIZE);
|
||||
#endif
|
||||
if(mappages(pagetable, a, PGSIZE, (uint64)mem, PTE_R|PTE_U|xperm) != 0){
|
||||
kfree(mem);
|
||||
uvmdealloc(pagetable, a, oldsz);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#ifndef LAB_SYSCALL
|
||||
memset(mem, 0, sz);
|
||||
#endif
|
||||
if(mappages(pagetable, a, sz, (uint64)mem, PTE_R|PTE_U|xperm) != 0){
|
||||
kfree(mem);
|
||||
uvmdealloc(pagetable, a, oldsz);
|
||||
return 0;
|
||||
|
||||
// Allocate superpages for aligned regions
|
||||
for (a = super_start; a < super_end; a += SUPERPGSIZE) {
|
||||
mem = superalloc();
|
||||
if (mem == 0) {
|
||||
uvmdealloc(pagetable, super_start, oldsz);
|
||||
return 0;
|
||||
}
|
||||
if (mappages(pagetable, a, SUPERPGSIZE, (uint64)mem, PTE_R | PTE_U | PTE_PS | xperm) != 0) {
|
||||
superfree(mem);
|
||||
uvmdealloc(pagetable, super_start, oldsz);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate regular pages after the last superpage boundary
|
||||
for(a = super_end; a < newsz; a += PGSIZE){
|
||||
mem = kalloc();
|
||||
if(mem == 0){
|
||||
uvmdealloc(pagetable, a, oldsz);
|
||||
return 0;
|
||||
}
|
||||
#ifndef LAB_SYSCALL
|
||||
memset(mem, 0, PGSIZE);
|
||||
#endif
|
||||
if(mappages(pagetable, a, PGSIZE, (uint64)mem, PTE_R|PTE_U|xperm) != 0){
|
||||
kfree(mem);
|
||||
uvmdealloc(pagetable, a, oldsz);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Allocation is smaller than SUPERPGSIZE, use regular pages
|
||||
for(a = oldsz; a < newsz; a += PGSIZE){
|
||||
mem = kalloc();
|
||||
if(mem == 0){
|
||||
uvmdealloc(pagetable, a, oldsz);
|
||||
return 0;
|
||||
}
|
||||
#ifndef LAB_SYSCALL
|
||||
memset(mem, 0, PGSIZE);
|
||||
#endif
|
||||
if(mappages(pagetable, a, PGSIZE, (uint64)mem, PTE_R|PTE_U|xperm) != 0){
|
||||
kfree(mem);
|
||||
uvmdealloc(pagetable, a, oldsz);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return newsz;
|
||||
}
|
||||
|
||||
@ -350,7 +455,6 @@ uvmcopy(pagetable_t old, pagetable_t new, uint64 sz)
|
||||
int szinc;
|
||||
|
||||
for(i = 0; i < sz; i += szinc){
|
||||
szinc = PGSIZE;
|
||||
szinc = PGSIZE;
|
||||
if((pte = walk(old, i, 0)) == 0)
|
||||
panic("uvmcopy: pte should exist");
|
||||
@ -358,18 +462,44 @@ uvmcopy(pagetable_t old, pagetable_t new, uint64 sz)
|
||||
panic("uvmcopy: page not present");
|
||||
pa = PTE2PA(*pte);
|
||||
flags = PTE_FLAGS(*pte);
|
||||
if((mem = kalloc()) == 0)
|
||||
goto err;
|
||||
memmove(mem, (char*)pa, PGSIZE);
|
||||
if(mappages(new, i, PGSIZE, (uint64)mem, flags) != 0){
|
||||
kfree(mem);
|
||||
goto err;
|
||||
|
||||
if ((flags & PTE_PS) == 0) {
|
||||
if((mem = kalloc()) == 0)
|
||||
goto err;
|
||||
memmove(mem, (char*)pa, PGSIZE);
|
||||
if(mappages(new, i, PGSIZE, (uint64)mem, flags) != 0){
|
||||
kfree(mem);
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
if ((mem = superalloc()) == 0)
|
||||
goto err;
|
||||
if (mappages(new, i, SUPERPGSIZE, (uint64)mem, flags) != 0) {
|
||||
superfree(mem);
|
||||
goto err;
|
||||
}
|
||||
memmove(mem, (char*)pa, SUPERPGSIZE);
|
||||
szinc = SUPERPGSIZE; /* 修正步长 */
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
err:
|
||||
uvmunmap(new, 0, i / PGSIZE, 1);
|
||||
// Clean up properly - need to unmap what we've mapped so far
|
||||
for(uint64 j = 0; j < i; j += PGSIZE) {
|
||||
pte_t *cleanup_pte = walk(new, j, 0);
|
||||
if(cleanup_pte && (*cleanup_pte & PTE_V)) {
|
||||
if(*cleanup_pte & PTE_PS) {
|
||||
// This is a superpage, skip ahead
|
||||
superfree((void*)PTE2PA(*cleanup_pte));
|
||||
*cleanup_pte = 0;
|
||||
j += SUPERPGSIZE - PGSIZE; // Will be incremented by PGSIZE in loop
|
||||
} else {
|
||||
kfree((void*)PTE2PA(*cleanup_pte));
|
||||
*cleanup_pte = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -404,7 +534,6 @@ copyout(pagetable_t pagetable, uint64 dstva, char *src, uint64 len)
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// forbid copyout over read-only user text pages.
|
||||
if((*pte & PTE_W) == 0)
|
||||
return -1;
|
||||
@ -412,14 +541,18 @@ copyout(pagetable_t pagetable, uint64 dstva, char *src, uint64 len)
|
||||
pa0 = walkaddr(pagetable, va0);
|
||||
if(pa0 == 0)
|
||||
return -1;
|
||||
n = PGSIZE - (dstva - va0);
|
||||
|
||||
// Calculate the correct page size and boundary
|
||||
uint64 pgsize = (*pte & PTE_PS) ? SUPERPGSIZE : PGSIZE;
|
||||
uint64 va_base = va0 & ~(pgsize - 1);
|
||||
n = pgsize - (dstva - va_base);
|
||||
if(n > len)
|
||||
n = len;
|
||||
memmove((void *)(pa0 + (dstva - va0)), src, n);
|
||||
memmove((void *)(pa0 + (dstva - va_base)), src, n);
|
||||
|
||||
len -= n;
|
||||
src += n;
|
||||
dstva = va0 + PGSIZE;
|
||||
dstva = va_base + pgsize;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -431,20 +564,28 @@ int
|
||||
copyin(pagetable_t pagetable, char *dst, uint64 srcva, uint64 len)
|
||||
{
|
||||
uint64 n, va0, pa0;
|
||||
pte_t *pte;
|
||||
|
||||
while(len > 0){
|
||||
va0 = PGROUNDDOWN(srcva);
|
||||
if((pte = walk(pagetable, va0, 0)) == 0) {
|
||||
return -1;
|
||||
}
|
||||
pa0 = walkaddr(pagetable, va0);
|
||||
if(pa0 == 0)
|
||||
return -1;
|
||||
n = PGSIZE - (srcva - va0);
|
||||
|
||||
// Calculate the correct page size and boundary
|
||||
uint64 pgsize = (*pte & PTE_PS) ? SUPERPGSIZE : PGSIZE;
|
||||
uint64 va_base = va0 & ~(pgsize - 1);
|
||||
n = pgsize - (srcva - va_base);
|
||||
if(n > len)
|
||||
n = len;
|
||||
memmove(dst, (void *)(pa0 + (srcva - va0)), n);
|
||||
memmove(dst, (void *)(pa0 + (srcva - va_base)), n);
|
||||
|
||||
len -= n;
|
||||
dst += n;
|
||||
srcva = va0 + PGSIZE;
|
||||
srcva = va_base + pgsize;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -458,17 +599,25 @@ copyinstr(pagetable_t pagetable, char *dst, uint64 srcva, uint64 max)
|
||||
{
|
||||
uint64 n, va0, pa0;
|
||||
int got_null = 0;
|
||||
pte_t *pte;
|
||||
|
||||
while(got_null == 0 && max > 0){
|
||||
va0 = PGROUNDDOWN(srcva);
|
||||
if((pte = walk(pagetable, va0, 0)) == 0) {
|
||||
return -1;
|
||||
}
|
||||
pa0 = walkaddr(pagetable, va0);
|
||||
if(pa0 == 0)
|
||||
return -1;
|
||||
n = PGSIZE - (srcva - va0);
|
||||
|
||||
// Calculate the correct page size and boundary
|
||||
uint64 pgsize = (*pte & PTE_PS) ? SUPERPGSIZE : PGSIZE;
|
||||
uint64 va_base = va0 & ~(pgsize - 1);
|
||||
n = pgsize - (srcva - va_base);
|
||||
if(n > max)
|
||||
n = max;
|
||||
|
||||
char *p = (char *) (pa0 + (srcva - va0));
|
||||
char *p = (char *) (pa0 + (srcva - va_base));
|
||||
while(n > 0){
|
||||
if(*p == '\0'){
|
||||
*dst = '\0';
|
||||
@ -483,7 +632,7 @@ copyinstr(pagetable_t pagetable, char *dst, uint64 srcva, uint64 max)
|
||||
dst++;
|
||||
}
|
||||
|
||||
srcva = va0 + PGSIZE;
|
||||
srcva = va_base + pgsize;
|
||||
}
|
||||
if(got_null){
|
||||
return 0;
|
||||
@ -536,46 +685,7 @@ void vmprint(pagetable_t pagetable) {
|
||||
vmprint_recursive(pagetable, 0, 0);
|
||||
}
|
||||
#endif
|
||||
// #ifdef LAB_PGTBL
|
||||
// void
|
||||
// vmprint(pagetable_t page_tbl){
|
||||
// printf("page table %p\n", page_tbl);
|
||||
//
|
||||
// for (int i = 0; i < 512; i++) {
|
||||
// pte_t pte = page_tbl[i];
|
||||
// if ((pte & PTE_V)) {
|
||||
// uint64 pa = PTE2PA(pte);
|
||||
// printf("..%d: pte %lx pa %lx\n", i, (uint64)pte, pa);
|
||||
//
|
||||
// if ((pte & (PTE_R | PTE_W | PTE_X)) == 0) {
|
||||
// // 这是指向下一级页表的项
|
||||
// sub_vmprint((pagetable_t)pa, 1);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// void sub_vmprint(pagetable_t pagetable, int level) {
|
||||
// for (int i = 0; i < 512; i++) {
|
||||
// pte_t pte = pagetable[i];
|
||||
// if (pte & PTE_V) {
|
||||
// uint64 pa = PTE2PA(pte);
|
||||
//
|
||||
// // 打印缩进
|
||||
// for (int j = 0; j < level; j++) {
|
||||
// printf(" ..");
|
||||
// }
|
||||
//
|
||||
// printf("%d: pte %lx pa %lx\n", i, (uint64)pte, pa);
|
||||
//
|
||||
// if ((pte & (PTE_R | PTE_W | PTE_X)) == 0) {
|
||||
// sub_vmprint((pagetable_t)pa, level + 1);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// #endif
|
||||
//
|
||||
|
||||
#ifdef LAB_PGTBL
|
||||
pte_t*
|
||||
pgpte(pagetable_t pagetable, uint64 va) {
|
||||
|
||||
Reference in New Issue
Block a user