struct vma*
get_vma(struct vma* now, int length){
uint64 max = TRAPFRAME;//起始地址
int target = -1;
for(int i = 0; i < MAX_VMA; i++){
if(target == -1 && now[i].length == 0){
//空闲的vma
target = i;
continue;
}
if(now[i].length == 0)
continue;
if(max > now[i].addr)
max = now[i].addr; //找到最小地址
}
uint64 head_addr = PGROUNDDOWN(max - length);
now[target].addr = head_addr;
now[target].length = length;
now[target].offset = 0;
// printf("length = %d pages\n", length / PGSIZE);
return &now[target];
}
uint64
sys_mmap(void){
// void *addr, int length, int prot, int flags, int fd
uint64 addr;
int length, prot, flags, fd, offset;
struct file* f;
if(argaddr(0, &addr) < 0 ||argint(1, &length) < 0 || argint(2, &prot) < 0 || argint(3, &flags) < 0 || argfd(4, &fd, &f) < 0 || argint(5, &offset) < 0){
return -1;
}
if(addr || offset)
return -1;
//判断权限
if(!f->writable && (prot & PROT_WRITE) && (flags & MAP_SHARED)){
return -1;
}
if(length <= 0)
return -1;
struct proc* p = myproc();
struct vma* now = get_vma(p->vmas, length);
now->f = f;
now->flags = flags;
now->prot = prot;
filedup(f);
return now->addr;
}
uint is_vma(uint64 addr){
struct proc* now = myproc();
struct vma* now_vma = 0;
for(int i = 0; i < MAX_VMA; i++){
if(addr >= now->vmas[i].addr && addr < now->vmas[i].addr + now->vmas[i].length){
now_vma = &now->vmas[i];
break;
}
}
if(now_vma == 0)
return -1;
addr = PGROUNDDOWN(addr);
uint64 pa = (uint64)kalloc();
memset((void *)pa, 0, PGSIZE);
int perm = PTE_U | PTE_V;
if(now_vma->prot & PROT_READ){
perm |= PTE_R;
}
if(now_vma->prot & PROT_WRITE){
perm |= PTE_W;
}
if(now_vma->prot & PROT_EXEC){
perm |= PTE_X;
}
ilock(now_vma->f->ip);
readi(now_vma->f->ip, 0, pa, addr - now_vma->addr, PGSIZE);
iunlock(now_vma->f->ip);
mappages(now->pagetable, addr, PGSIZE, pa, perm);
return 0;
}
if(r_scause() == 15 || r_scause() == 13){
uint64 fault_addr = r_stval();
if (is_vma(fault_addr) == -1){
p->killed = 1;
}
}
uint64
sys_munmap(void){
// munmap(addr, length)
uint64 addr;
int length;
if(argaddr(0, &addr) < 0 ||argint(1, &length) < 0){
return -1;
}
struct proc* p = myproc();
struct vma* now_vma = 0;
//1.找到那个vma
for(int i = 0; i < MAX_VMA; i++){
if(addr >= p->vmas[i].addr && addr < p->vmas[i].addr + p->vmas[i].length){
now_vma = &p->vmas[i];
break;
}
}
// 检查是否找到 VMA
if(!now_vma){
return -1; // addr 不在任何 VMA 的范围内
}
// 检查 length 是否超出 VMA 的范围
if(addr + length > now_vma->addr + now_vma->length){
length = now_vma->addr + now_vma->length - addr;
}
struct file* f = now_vma->f;
//2.判断是否写入
if(now_vma->flags & MAP_SHARED){
begin_op();
ilock(f->ip);
// writei(f->ip, 1, addr, addr - now_vma->addr + now_vma->offset, length);
writei(f->ip, 1, addr, addr - now_vma->addr + now_vma->offset, now_vma->length);
iunlock(f->ip);
end_op();
}
//3.更改vma
now_vma->length -=length;
if(addr == now_vma->addr){
now_vma->offset += length;
now_vma->addr += length;
}
//4.解除映射
// 释放空间
uvmunmap(p->pagetable, addr, length / PGSIZE, 1);
//4.空间完全被释放,关闭文件
if(now_vma->length == 0){
fileclose(f);
now_vma->addr = 0;
now_vma->f = 0;
now_vma->flags = 0;
now_vma->prot = 0;
now_vma->offset = 0;
}
return 0;
}
if((*pte & PTE_V) == 0)
continue;
//fork
for(int i = 0; i < MAX_VMA; i++){
if(p->vmas[i].length != 0){
np->vmas[i] = p->vmas[i];
filedup(p->vmas[i].f);
}
}
//exit
for(int i = 0; i < MAX_VMA; i++){
if(p->vmas[i].addr != 0){
uvmunmap(p->pagetable, p->vmas[i].addr, p->vmas[i].length / PGSIZE, 1);
}
if(p->vmas[i].f){
fileclose(p->vmas[i].f);
}
p->vmas[i].addr = 0;
p->vmas[i].f = 0;
p->vmas[i].flags = 0;
p->vmas[i].prot = 0;
p->vmas[i].offset = 0;
}
// Close all open files.
for(int fd = 0; fd < NOFILE; fd++){
if(p->ofile[fd]){
struct file *f = p->ofile[fd];
fileclose(f);
p->ofile[fd] = 0;
}
}