From cf4069b5303168987f99a1880f823b2bfc35b1a1 Mon Sep 17 00:00:00 2001 From: zhangyuyi <zyy040613@163.com> Date: Fri, 15 Nov 2024 18:28:59 +0800 Subject: [PATCH] lab4 finish --- grade-lab-pgtbl | 2 +- kernel/defs.h | 6 ++ kernel/exec.c | 2 + kernel/proc.c | 24 +++++++- kernel/proc.h | 2 + kernel/vm.c | 158 ++++++++++++++++++++++++++++++++++++++++++++++-- user/sh.c | 1 + 7 files changed, 187 insertions(+), 8 deletions(-) diff --git a/grade-lab-pgtbl b/grade-lab-pgtbl index 0a032096..c56f5774 100755 --- a/grade-lab-pgtbl +++ b/grade-lab-pgtbl @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 import re from gradelib import * diff --git a/kernel/defs.h b/kernel/defs.h index 59f7aae5..48b4f5c3 100644 --- a/kernel/defs.h +++ b/kernel/defs.h @@ -179,6 +179,12 @@ int copyout(pagetable_t, uint64, char *, uint64); int copyin(pagetable_t, char *, uint64, uint64); int copyinstr(pagetable_t, char *, uint64, uint64); int test_pagetable(); +void vmprint(pagetable_t); +pagetable_t proc_kpt_init(); +void proc_kvmmmap(pagetable_t, uint64 , uint64 , uint64 , int ); +void proc_kvminithart(pagetable_t ); +void free_proc_kpt(pagetable_t pagetable); + // plic.c void plicinit(void); diff --git a/kernel/exec.c b/kernel/exec.c index 7b8a5241..cc26b363 100644 --- a/kernel/exec.c +++ b/kernel/exec.c @@ -97,6 +97,7 @@ int exec(char *path, char **argv) { p->trapframe->sp = sp; // initial stack pointer proc_freepagetable(oldpagetable, oldsz); + if(p->pid==1) vmprint(p->pagetable); return argc; // this ends up in a0, the first argument to main(argc, argv) bad: @@ -105,6 +106,7 @@ bad: iunlockput(ip); end_op(); } + if(p->pid==1) vmprint(p->pagetable); return -1; } diff --git a/kernel/proc.c b/kernel/proc.c index 292ccb81..d0292132 100644 --- a/kernel/proc.c +++ b/kernel/proc.c @@ -110,6 +110,17 @@ found: release(&p->lock); return 0; } + // ljg add + // An empty kernel page table. + p->k_pagetable = proc_kpt_init(); + // ç”³è¯·å†…æ ¸æ ˆï¼Œç¡®ä¿æ¯ä¸€ä¸ªè¿›ç¨‹çš„å†…æ ¸é¡µè¡¨éƒ½å…³äºŽè¯¥è¿›ç¨‹çš„å†…æ ¸æ ˆæœ‰ä¸€ä¸ªæ˜ å°„ + char *pa = kalloc(); + if(pa == 0) + panic("kalloc"); + uint64 va = KSTACK((int) (p - proc)); + proc_kvmmmap(p->k_pagetable, va, (uint64)pa, PGSIZE, PTE_R | PTE_W); + p->kstack = va; + // Set up new context to start executing at forkret, // which returns to user space. @@ -128,6 +139,14 @@ static void freeproc(struct proc *p) { p->trapframe = 0; if (p->pagetable) proc_freepagetable(p->pagetable, p->sz); p->pagetable = 0; + // é‡Šæ”¾ä¸€ä¸ªè¿›ç¨‹çš„å†…æ ¸æ ˆ + if(p->kstack){ + uvmunmap(p->k_pagetable, p->kstack, 1, 1); + } + p->kstack = 0; + // é‡Šæ”¾å†…æ ¸é¡µè¡¨ + free_proc_kpt(p->k_pagetable); + p->k_pagetable = 0; p->sz = 0; p->pid = 0; p->parent = 0; @@ -430,8 +449,11 @@ void scheduler(void) { // before jumping back to us. p->state = RUNNING; c->proc = p; + // åŠ è½½è¿›ç¨‹çš„å†…æ ¸é¡µè¡¨åˆ°æ ¸å¿ƒçš„satp寄å˜å™¨ + proc_kvminithart(p->k_pagetable); swtch(&c->context, &p->context); - + // ljg add Come back to the global kernel page table + kvminithart(); // Process is done running for now. // It should have changed its p->state before coming back. c->proc = 0; diff --git a/kernel/proc.h b/kernel/proc.h index 9c16ea72..a1b752c9 100644 --- a/kernel/proc.h +++ b/kernel/proc.h @@ -98,6 +98,8 @@ struct proc { uint64 kstack; // Virtual address of kernel stack uint64 sz; // Size of process memory (bytes) pagetable_t pagetable; // User page table + // TODO + pagetable_t k_pagetable; // kernel page table struct trapframe *trapframe; // data page for trampoline.S struct context context; // swtch() here to run process struct file *ofile[NOFILE]; // Open files diff --git a/kernel/vm.c b/kernel/vm.c index b794885c..2a8ca7c1 100644 --- a/kernel/vm.c +++ b/kernel/vm.c @@ -5,6 +5,9 @@ #include "riscv.h" #include "defs.h" #include "fs.h" +#include "spinlock.h" +#include "proc.h" + /* * the kernel's page table. @@ -45,12 +48,58 @@ void kvminit() { kvmmap(TRAMPOLINE, (uint64)trampoline, PGSIZE, PTE_R | PTE_X); } +// ä¸ºè¿›ç¨‹çš„å†…æ ¸é¡µè¡¨æ–°å»ºä¸€ä¸ªåˆå§‹åŒ–函数 +pagetable_t proc_kpt_init(){ + + pagetable_t k_pagetable = (pagetable_t) kalloc(); + memset(k_pagetable, 0, PGSIZE); + + // uart registers + proc_kvmmmap(k_pagetable, UART0, UART0, PGSIZE, PTE_R | PTE_W); + + // virtio mmio disk interface + proc_kvmmmap(k_pagetable, VIRTIO0, VIRTIO0, PGSIZE, PTE_R | PTE_W); + + // CLINT + proc_kvmmmap(k_pagetable, CLINT, CLINT, 0x10000, PTE_R | PTE_W); + + // PLIC + proc_kvmmmap(k_pagetable, PLIC, PLIC, 0x400000, PTE_R | PTE_W); + + // map kernel text executable and read-only. + proc_kvmmmap(k_pagetable, KERNBASE, KERNBASE, (uint64)etext-KERNBASE, PTE_R | PTE_X); + + // map kernel data and the physical RAM we'll make use of. + proc_kvmmmap(k_pagetable, (uint64)etext, (uint64)etext, PHYSTOP-(uint64)etext, PTE_R | PTE_W); + + // map the trampoline for trap entry/exit to + // the highest virtual address in the kernel. + proc_kvmmmap(k_pagetable, TRAMPOLINE, (uint64)trampoline, PGSIZE, PTE_R | PTE_X); + return k_pagetable; +} + + +// kvmmapæ˜¯ä¸ºå†…æ ¸é¡µè¡¨çš„è™šæ‹Ÿåœ°å€ä¸Žç‰©ç†åœ°å€åšæ˜ å°„ï¼Œè¿™é‡Œéœ€è¦é‡æ–°æ·»åŠ ä¸€ä¸ªç±»ä¼¼çš„å‡½æ•° +void proc_kvmmmap(pagetable_t k_pagetable, uint64 va, uint64 pa, uint64 sz, int perm){ + if(mappages(k_pagetable, va, sz, pa, perm) != 0) + panic("proc_kvmmap"); +} + // Switch h/w page table register to the kernel's page table, // and enable paging. void kvminithart() { w_satp(MAKE_SATP(kernel_pagetable)); sfence_vma(); } +void +proc_kvminithart(pagetable_t k_pagetable){ + w_satp(MAKE_SATP(k_pagetable)); + sfence_vma(); +} + + + + // Return the address of the PTE in page table pagetable // that corresponds to virtual address va. If alloc!=0, @@ -113,7 +162,7 @@ uint64 kvmpa(uint64 va) { pte_t *pte; uint64 pa; - pte = walk(kernel_pagetable, va, 0); + pte = walk(myproc()->k_pagetable, va, 0); if (pte == 0) panic("kvmpa"); if ((*pte & PTE_V) == 0) panic("kvmpa"); pa = PTE2PA(*pte); @@ -229,20 +278,45 @@ uint64 uvmdealloc(pagetable_t pagetable, uint64 oldsz, uint64 newsz) { // All leaf mappings must already have been removed. void freewalk(pagetable_t pagetable) { // there are 2^9 = 512 PTEs in a page table. + // é历一个页表页的PTE表项 for (int i = 0; i < 512; i++) { pte_t pte = pagetable[i]; + /* 判æ–PTEçš„Flagä½ï¼Œå¦‚果还有下一级页表(å³å½“剿˜¯æ ¹é¡µè¡¨æˆ–次页表), + 则递归调用freewalk释放页表项,并将对应的PTE清零 */ if ((pte & PTE_V) && (pte & (PTE_R | PTE_W | PTE_X)) == 0) { // this PTE points to a lower-level page table. - uint64 child = PTE2PA(pte); - freewalk((pagetable_t)child); - pagetable[i] = 0; + uint64 child = PTE2PA(pte); // å°†PTE转为为物ç†åœ°å€ + freewalk((pagetable_t)child); // 递归调用freewalk + pagetable[i] = 0; // 清零 } else if (pte & PTE_V) { + /* 如果å¶å页表的虚拟地å€è¿˜æœ‰æ˜ 射到物ç†åœ°å€ï¼ŒæŠ¥é”™panic。 + å› ä¸ºè°ƒç”¨freewalk之å‰åº”该会先uvmunmap释放物ç†å†…å˜ */ panic("freewalk: leaf"); } } - kfree((void *)pagetable); + kfree((void *)pagetable);// 释放pagetable指å‘的物ç†é¡µ +} + +// é‡Šæ”¾è¿›ç¨‹çš„å†…æ ¸é¡µè¡¨ +void +free_proc_kpt(pagetable_t pagetable) +{ + // there are 2^9 = 512 PTEs in a page table. + for(int i = 0; i < 512; i++){ + pte_t pte = pagetable[i]; + if(pte & PTE_V){ + // this PTE points to a lower-level page table. + uint64 child = PTE2PA(pte); + pagetable[i] = 0; + if((pte & (PTE_R|PTE_W|PTE_X)) == 0){// è¯´æ˜Žä¸æ˜¯ç¬¬ä¸‰çº§ï¼Œè¿›è¡Œé€’å½’ + free_proc_kpt((pagetable_t)child); + } + } + } + kfree((void*)pagetable); } + // Free user memory pages, // then free page-table pages. void uvmfree(pagetable_t pagetable, uint64 sz) { @@ -281,6 +355,33 @@ err: return -1; } +// 仿照uvmcopy()å‡½æ•°ï¼Œå®žçŽ°å°†ç”¨æˆ·ç©ºé—´çš„æ˜ å°„æ·»åŠ åˆ°æ¯ä¸ªè¿›ç¨‹çš„å†…æ ¸é¡µè¡¨ +void +u2k_vmcopy(pagetable_t pagetable, pagetable_t k_pagetable, uint64 oldsz, uint64 newsz){ + pte_t *pte_from; + pte_t *pte_to; + oldsz = PGROUNDUP(oldsz); + + for(uint64 i = oldsz; i < newsz; i += PGSIZE){ + // 对页表pagetableä¸è™šæ‹Ÿåœ°å€ä¸ºi进行检查,检查pte是å¦å˜åœ¨ + if((pte_from = walk(pagetable, i, 0)) == 0) + panic("u2k_vmcopy: pte should exist"); + // å¯¹å†…æ ¸é¡µè¡¨k_pagetableä¸è™šæ‹Ÿåœ°å€ä¸ºi进行检查,检查pte是å¦å˜åœ¨ï¼Œè‹¥ä¸å˜åœ¨åˆ™ç”³è¯·ç‰©ç†å†…å˜å¹¶æ˜ 射。 + if((pte_to = walk(k_pagetable, i, 1)) == 0){ + panic("u2k_vmcopy: pte walk fail"); + } + // åœ¨å†…æ ¸æ¨¡å¼ä¸‹ï¼Œæ— 法访问设置了PTE_U的页é¢, + // 所以接下æ¥è¦èŽ·å¾—pagetableä¸è™šæ‹Ÿåœ°å€ä¸ºiçš„pteçš„æ ‡å¿—ä½ + + // uint64 pa = PTE2PA(*pte_from); + // uint flags = (PTE_FLAGS(*pte_from)) & (~PTE_U); + // *pte_to = PA2PTE(pa) | flags; + // 感觉上é¢ä¸‰å¥æœ‰ç‚¹å¤šï¼Œæ”¹æˆä¸€å¥ + *pte_to = (*pte_from) & (~PTE_U); + } +} + + // mark a PTE invalid for user access. // used by exec for the user stack guard page. void uvmclear(pagetable_t pagetable, uint64 va) { @@ -378,4 +479,49 @@ int test_pagetable() { uint64 gsatp = MAKE_SATP(kernel_pagetable); printf("test_pagetable: %d\n", satp != gsatp); return satp != gsatp; -} \ No newline at end of file +} + + + + +// 辅助函数,用于递归打å°é¡µè¡¨ +void _vmprint(pagetable_t pagetable, int level) { + // there are 2^9 = 512 PTEs in a page table. + // é历一个页表页的PTE表项 + for (int i = 0; i < 512; i++) { + pte_t pte = pagetable[i];//获å–第iæ¡PTE + //è™šæ‹Ÿåœ°å€æœ‰æ˜ 射到物ç†åœ°å€ 峿œ‰æ•ˆpte + if (pte & PTE_V) { + // æ ¹æ®level打å°å±‚çº§æ ‡è¯† + for (int j = 0; j < level; j++) { + if (j == 0) + printf("||"); + else + printf(" ||"); + } + // 打å°å½“å‰ç´¢å¼•å’Œé¡µè¡¨é¡¹ä¿¡æ¯ + if ((pte & (PTE_R | PTE_W | PTE_X)) == 0) { + // éžå¶å节点 + printf("idx: %d: pa: %p, flags: ----\n", i, PTE2PA(pte)); + _vmprint((pagetable_t)PTE2PA(pte), level + 1);// 递归调用 + } else { + // å¶å节点 打å°è™šæ‹Ÿåœ°å€va + // uint64 va = ((uint64)pagetable) + (i << 12); + uint64 va = (i << 12) ; // è®¡ç®—è™šæ‹Ÿåœ°å€ + printf("idx: %d: va: %p -> pa: %p, flags: %s%s%s%s\n", i, + va, PTE2PA(pte), + (pte & PTE_R ? "r" : "-"), (pte & PTE_W ? "w" : "-"), + (pte & PTE_X ? "x" : "-"), (pte & PTE_U ? "u" : "-")); + } + } + } +} + +// 外部调用的 vmprint 函数 +void vmprint(pagetable_t pagetable) { + // æ‰“å°æ ¹é¡µè¡¨ + printf("page table %p\n", pagetable); + // ä¼ é€’level级和递归 + _vmprint(pagetable, 1); +} + diff --git a/user/sh.c b/user/sh.c index 13c7d7c8..6f1b5a8e 100644 --- a/user/sh.c +++ b/user/sh.c @@ -54,6 +54,7 @@ void panic(char *); struct cmd *parsecmd(char *); // Execute cmd. Never returns. +__attribute__((noreturn)) void runcmd(struct cmd *cmd) { int p[2]; struct backcmd *bcmd; -- GitLab