From 19e38dc5983008e58a7b355ca79de1c80e45678c Mon Sep 17 00:00:00 2001 From: CGH0S7 <776459475@qq.com> Date: Thu, 29 May 2025 20:01:24 +0800 Subject: [PATCH] task5 finished --- kernel/defs.h | 2 + kernel/kalloc.c | 51 ++++++++- kernel/riscv.h | 2 +- kernel/vm.c | 296 +++++++++++++++++++++++++++++++++--------------- 4 files changed, 256 insertions(+), 95 deletions(-) diff --git a/kernel/defs.h b/kernel/defs.h index d133cd3..6bc6444 100644 --- a/kernel/defs.h +++ b/kernel/defs.h @@ -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 diff --git a/kernel/kalloc.c b/kernel/kalloc.c index 0699e7e..9448ab9 100644 --- a/kernel/kalloc.c +++ b/kernel/kalloc.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 diff --git a/kernel/riscv.h b/kernel/riscv.h index 8bf202c..4c1fd2b 100644 --- a/kernel/riscv.h +++ b/kernel/riscv.h @@ -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) diff --git a/kernel/vm.c b/kernel/vm.c index c2bc210..7623c11 100644 --- a/kernel/vm.c +++ b/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) {