task5 finished

This commit is contained in:
2025-05-29 20:01:24 +08:00
parent b4bdc3e1db
commit 19e38dc598
4 changed files with 256 additions and 95 deletions

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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) {