summaryrefslogtreecommitdiff
path: root/kernel/vm.c
diff options
context:
space:
mode:
authorMole Shang <[email protected]>2024-02-16 10:20:27 +0800
committerMole Shang <[email protected]>2024-02-16 10:20:27 +0800
commita98c56a811142e5ede3332a7a444cca45f628769 (patch)
treec93ff7090da7b6ef911932be283818c2f6a03784 /kernel/vm.c
parent0d65be5d1d880afafbf08c2adb605cf9f72216e2 (diff)
parent99015f3a985b2fd051606636743a2a2969b216e8 (diff)
downloadxv6-labs-a98c56a811142e5ede3332a7a444cca45f628769.tar.gz
xv6-labs-a98c56a811142e5ede3332a7a444cca45f628769.tar.bz2
xv6-labs-a98c56a811142e5ede3332a7a444cca45f628769.zip
Merge branch 'lock' into thread
Conflicts: .gitignore Makefile conf/lab.mk
Diffstat (limited to 'kernel/vm.c')
-rw-r--r--kernel/vm.c85
1 files changed, 65 insertions, 20 deletions
diff --git a/kernel/vm.c b/kernel/vm.c
index 5c31e87..be7d042 100644
--- a/kernel/vm.c
+++ b/kernel/vm.c
@@ -4,6 +4,8 @@
#include "elf.h"
#include "riscv.h"
#include "defs.h"
+#include "spinlock.h"
+#include "proc.h"
#include "fs.h"
/*
@@ -30,6 +32,14 @@ kvmmake(void)
// virtio mmio disk interface
kvmmap(kpgtbl, VIRTIO0, VIRTIO0, PGSIZE, PTE_R | PTE_W);
+#ifdef LAB_NET
+ // PCI-E ECAM (configuration space), for pci.c
+ kvmmap(kpgtbl, 0x30000000L, 0x30000000L, 0x10000000, PTE_R | PTE_W);
+
+ // pci.c maps the e1000's registers here.
+ kvmmap(kpgtbl, 0x40000000L, 0x40000000L, 0x20000, PTE_R | PTE_W);
+#endif
+
// PLIC
kvmmap(kpgtbl, PLIC, PLIC, 0x400000, PTE_R | PTE_W);
@@ -136,9 +146,8 @@ kvmmap(pagetable_t kpgtbl, uint64 va, uint64 pa, uint64 sz, int perm)
}
// Create PTEs for virtual addresses starting at va that refer to
-// physical addresses starting at pa.
-// va and size MUST be page-aligned.
-// Returns 0 on success, -1 if walk() couldn't
+// physical addresses starting at pa. va and size might not
+// be page-aligned. Returns 0 on success, -1 if walk() couldn't
// allocate a needed page-table page.
int
mappages(pagetable_t pagetable, uint64 va, uint64 size, uint64 pa, int perm)
@@ -146,17 +155,11 @@ mappages(pagetable_t pagetable, uint64 va, uint64 size, uint64 pa, int perm)
uint64 a, last;
pte_t *pte;
- if((va % PGSIZE) != 0)
- panic("mappages: va not aligned");
-
- if((size % PGSIZE) != 0)
- panic("mappages: size not aligned");
-
if(size == 0)
panic("mappages: size");
- a = va;
- last = va + size - PGSIZE;
+ a = PGROUNDDOWN(va);
+ last = PGROUNDDOWN(va + size - 1);
for(;;){
if((pte = walk(pagetable, a, 1)) == 0)
return -1;
@@ -186,8 +189,10 @@ uvmunmap(pagetable_t pagetable, uint64 va, uint64 npages, int do_free)
for(a = va; a < va + npages*PGSIZE; a += PGSIZE){
if((pte = walk(pagetable, a, 0)) == 0)
panic("uvmunmap: walk");
- if((*pte & PTE_V) == 0)
+ if((*pte & PTE_V) == 0) {
+ printf("va=%p pte=%p\n", a, *pte);
panic("uvmunmap: not mapped");
+ }
if(PTE_FLAGS(*pte) == PTE_V)
panic("uvmunmap: not a leaf");
if(do_free){
@@ -315,20 +320,26 @@ uvmcopy(pagetable_t old, pagetable_t new, uint64 sz)
pte_t *pte;
uint64 pa, i;
uint flags;
- char *mem;
+ // char *mem;
for(i = 0; i < sz; i += PGSIZE){
if((pte = walk(old, i, 0)) == 0)
panic("uvmcopy: pte should exist");
if((*pte & PTE_V) == 0)
panic("uvmcopy: page not present");
- pa = PTE2PA(*pte);
- flags = PTE_FLAGS(*pte);
+ // do not do the actual copy, just increase the refcnt and mark pages readonly COW
+ /*
if((mem = kalloc()) == 0)
goto err;
memmove(mem, (char*)pa, PGSIZE);
- if(mappages(new, i, PGSIZE, (uint64)mem, flags) != 0){
- kfree(mem);
+ */
+ *pte &= ~PTE_W;
+ *pte |= PTE_C;
+ pa = PTE2PA(*pte);
+ refcnt_inc(pa);
+ flags = PTE_FLAGS(*pte);
+ if(mappages(new, i, PGSIZE, (uint64)pa, flags) != 0){
+ // kfree(mem);
goto err;
}
}
@@ -359,17 +370,24 @@ int
copyout(pagetable_t pagetable, uint64 dstva, char *src, uint64 len)
{
uint64 n, va0, pa0;
- pte_t *pte;
+ // pte_t *pte;
while(len > 0){
va0 = PGROUNDDOWN(dstva);
- if(va0 >= MAXVA)
+
+ if(cow_handler(pagetable, va0) < 0)
return -1;
+
+ /*
pte = walk(pagetable, va0, 0);
if(pte == 0 || (*pte & PTE_V) == 0 || (*pte & PTE_U) == 0 ||
(*pte & PTE_W) == 0)
return -1;
pa0 = PTE2PA(*pte);
+ */
+ pa0 = walkaddr(pagetable, va0);
+ if(pa0 == 0)
+ return -1;
n = PGSIZE - (dstva - va0);
if(n > len)
n = len;
@@ -389,7 +407,7 @@ int
copyin(pagetable_t pagetable, char *dst, uint64 srcva, uint64 len)
{
uint64 n, va0, pa0;
-
+
while(len > 0){
va0 = PGROUNDDOWN(srcva);
pa0 = walkaddr(pagetable, va0);
@@ -449,3 +467,30 @@ copyinstr(pagetable_t pagetable, char *dst, uint64 srcva, uint64 max)
return -1;
}
}
+
+static void
+walkprint(pagetable_t pgtbl, int level)
+{
+ for(int i = 0; i < 512; i++){
+ pte_t pte = pgtbl[i];
+ if(pte & PTE_V){
+ for(int j = 0; j < level; j++){
+ printf(" ..");
+ }
+ printf("%d: pte %p pa %p\n", i, pte, PTE2PA(pte));
+ if((pte & (PTE_R|PTE_W|PTE_X)) == 0){
+ // this PTE points to a lower-level page table.
+ walkprint((pagetable_t)PTE2PA(pte), level+1);
+ }
+ }
+ }
+}
+
+// Print the contents of a page table
+void
+vmprint(pagetable_t pgtbl)
+{
+ printf("page table %p\n", pgtbl);
+
+ walkprint(pgtbl, 1);
+}