1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
| uint64 sys_mmap(void) { struct proc *p = myproc(); uint64 addr; int length, prot, flags, fd, offset;
if(argaddr(0, &addr) < 0) return -1; if(argint(1, &length) < 0 || argint(2, &prot) < 0 || argint(3, &flags) < 0 || argint(4, &fd) < 0 || argint(5, &offset) < 0) return -1; if(addr != 0 || offset != 0) return -1;
if(p->ofile[fd] == 0 || p->ofile[fd]->type != FD_INODE) return -1;
struct file *f = p->ofile[fd]; if((flags & MAP_SHARED) && (prot & PROT_WRITE) && !f->writable) return -1;
struct map_info *map; if((map = map_alloc()) == 0) return -1; map->vend = PGROUNDUP(map->vstart + length); map->length = length; map->prot = prot; map->flags = flags; map->file = f; map->offset = offset; map->used = 1;
filedup(map->file);
return map->vstart; }
uint64 sys_munmap(void) { struct proc *p = myproc(); uint64 addr; int length;
if(argaddr(0, &addr) < 0 || argint(1, &length) < 0) return -1;
if(addr < MMAP_VSTART || addr > MMAP_VEND) return -1; uint64 vpage_base = PGROUNDDOWN(addr); int map_sel = (vpage_base - MMAP_VSTART) / MMAP_SIZE; struct map_info *map = &p->minfo[map_sel];
if(map->used == 0) return -1; static pte_t *pte; uint64 pa; for(uint64 va = vpage_base; va < addr + length; va += PGSIZE) { if((pte = walk(p->pagetable, va, 0)) && (*pte & PTE_V)) { pa = PTE2PA(*pte); if((map->flags & MAP_SHARED) && (*pte & PTE_D)) { uint64 file_start = va - vpage_base; uint64 write_length = PGSIZE; if(write_length > map->length - file_start) write_length = map->length - file_start; struct file *f = map->file;
begin_op(f->ip->dev); ilock(f->ip); writei(f->ip, 0, pa, file_start, write_length); iunlock(f->ip); end_op(f->ip->dev); } uvmunmap(p->pagetable, va, PGSIZE, 0); kderef((void*)pa); } }
if(map->vstart == addr && map->length == length) { fileclose(map->file); map->used = 0; } else { if(map->vstart == addr) map->vstart = addr + length; if(map->vend == addr + length) map->vend = addr; }
return 0; }
void mmap_dup(pagetable_t pagetable, struct map_info *m) { static pte_t *pte; uint64 pa; for (uint64 va = m->vstart; va < m->vend; va += PGSIZE) { if ((pte = walk(pagetable, va, 0)) && (*pte & PTE_V)) { pa = PTE2PA(*pte); kref((void *)pa); } } }
void mmap_dedup(pagetable_t pagetable, struct map_info *m) { static pte_t *pte; uint64 pa; for (uint64 va = m->vstart; va < m->vend; va += PGSIZE) { if ((pte = walk(pagetable, va, 0)) && (*pte & PTE_V)) { pa = PTE2PA(*pte); uvmunmap(pagetable, va, PGSIZE, 0); kderef((void *)pa); } } }
|