|  | @@ -326,7 +326,6 @@ int mm_create_vma(struct mm_struct *mm, uint64_t vaddr, uint64_t length, vm_flag
 | 
	
		
			
				|  |  |      vma->vm_flags = vm_flags;
 | 
	
		
			
				|  |  |      vma->vm_start = vaddr;
 | 
	
		
			
				|  |  |      vma->vm_end = vaddr + length;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |      // 将VMA加入mm的链表
 | 
	
		
			
				|  |  |      retval = vma_insert(mm, vma);
 | 
	
		
			
				|  |  |      if (retval == -EEXIST) // 之前已经存在了相同的vma,直接返回
 | 
	
	
		
			
				|  | @@ -335,7 +334,8 @@ int mm_create_vma(struct mm_struct *mm, uint64_t vaddr, uint64_t length, vm_flag
 | 
	
		
			
				|  |  |          kfree(vma);
 | 
	
		
			
				|  |  |          return -EEXIST;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | -    *res_vma = vma;
 | 
	
		
			
				|  |  | +    if (res_vma != NULL)
 | 
	
		
			
				|  |  | +        *res_vma = vma;
 | 
	
		
			
				|  |  |      return 0;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -350,7 +350,12 @@ int mm_map_vma(struct vm_area_struct *vma, uint64_t paddr)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |      int retval = 0;
 | 
	
		
			
				|  |  |      // 获取物理地址对应的页面
 | 
	
		
			
				|  |  | -    struct Page *pg = Phy_to_2M_Page(paddr);
 | 
	
		
			
				|  |  | +    struct Page *pg;
 | 
	
		
			
				|  |  | +    if (vma->vm_flags & VM_IO) // 对于mmio的内存,创建新的page结构体
 | 
	
		
			
				|  |  | +        pg = __create_mmio_page_struct(paddr);
 | 
	
		
			
				|  |  | +    else
 | 
	
		
			
				|  |  | +        pg = Phy_to_2M_Page(paddr);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      if (unlikely(pg->anon_vma == NULL)) // 若页面不存在anon_vma,则为页面创建anon_vma
 | 
	
		
			
				|  |  |      {
 | 
	
		
			
				|  |  |          spin_lock(&pg->op_lock);
 | 
	
	
		
			
				|  | @@ -400,8 +405,13 @@ int mm_map_vma(struct vm_area_struct *vma, uint64_t paddr)
 | 
	
		
			
				|  |  |          if (unlikely(retval != 0))
 | 
	
		
			
				|  |  |              goto failed;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | -    // 计算当前vma的起始地址在对应的物理页中的偏移量
 | 
	
		
			
				|  |  | -    vma->page_offset = paddr - (paddr & PAGE_2M_MASK);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (vma->vm_flags & VM_IO)
 | 
	
		
			
				|  |  | +        vma->page_offset = 0;
 | 
	
		
			
				|  |  | +    else
 | 
	
		
			
				|  |  | +    { // 计算当前vma的起始地址在对应的物理页中的偏移量
 | 
	
		
			
				|  |  | +        vma->page_offset = paddr - (paddr & PAGE_2M_MASK);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |      flush_tlb();
 | 
	
		
			
				|  |  |      return 0;
 | 
	
		
			
				|  |  |  failed:;
 | 
	
	
		
			
				|  | @@ -409,6 +419,46 @@ failed:;
 | 
	
		
			
				|  |  |      return retval;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * @brief 在页表中映射物理地址到指定的虚拟地址(需要页表中已存在对应的vma)
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * @param mm 内存管理结构体
 | 
	
		
			
				|  |  | + * @param vaddr 虚拟地址
 | 
	
		
			
				|  |  | + * @param length 长度(字节)
 | 
	
		
			
				|  |  | + * @param paddr 物理地址
 | 
	
		
			
				|  |  | + * @return int 返回码
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +int mm_map(struct mm_struct *mm, uint64_t vaddr, uint64_t length, uint64_t paddr)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    int retval = 0;
 | 
	
		
			
				|  |  | +    for (uint64_t mapped = 0; mapped < length;)
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        struct vm_area_struct *vma = vma_find(mm, vaddr + mapped);
 | 
	
		
			
				|  |  | +        if (unlikely(vma == NULL))
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            kerror("Map addr failed: vma not found. At address: %#018lx, pid=%ld", vaddr + mapped, current_pcb->pid);
 | 
	
		
			
				|  |  | +            return -EINVAL;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        if (unlikely(vma->vm_start != (vaddr + mapped)))
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            kerror("Map addr failed: addr_start is not equal to current: %#018lx.", vaddr + mapped);
 | 
	
		
			
				|  |  | +            return -EINVAL;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        retval = mm_map_vma(vma, paddr + mapped);
 | 
	
		
			
				|  |  | +        if (unlikely(retval != 0))
 | 
	
		
			
				|  |  | +            goto failed;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        mapped += vma->vm_end - vma->vm_start;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    return 0;
 | 
	
		
			
				|  |  | +failed:;
 | 
	
		
			
				|  |  | +    kerror("Map addr failed.");
 | 
	
		
			
				|  |  | +    return retval;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  /**
 | 
	
		
			
				|  |  |   * @brief 在页表中取消指定的vma的映射
 | 
	
		
			
				|  |  |   *
 | 
	
	
		
			
				|  | @@ -417,15 +467,70 @@ failed:;
 | 
	
		
			
				|  |  |   * @param paddr 返回的被取消映射的起始物理地址
 | 
	
		
			
				|  |  |   * @return int 返回码
 | 
	
		
			
				|  |  |   */
 | 
	
		
			
				|  |  | -int mm_umap_vma(struct mm_struct *mm, struct vm_area_struct *vma, uint64_t *paddr)
 | 
	
		
			
				|  |  | +int mm_unmap_vma(struct mm_struct *mm, struct vm_area_struct *vma, uint64_t *paddr)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |      // 确保vma对应的mm与指定的mm相一致
 | 
	
		
			
				|  |  |      if (unlikely(vma->vm_mm != mm))
 | 
	
		
			
				|  |  |          return -EINVAL;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | +    struct anon_vma_t *anon = vma->anon_vma;
 | 
	
		
			
				|  |  |      if (paddr != NULL)
 | 
	
		
			
				|  |  |          *paddr = __mm_get_paddr(mm, vma->vm_start);
 | 
	
		
			
				|  |  | +    if (anon == NULL)
 | 
	
		
			
				|  |  | +        kwarn("anon is NULL");
 | 
	
		
			
				|  |  | +    semaphore_down(&anon->sem);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      mm_unmap_proc_table((uint64_t)mm->pgd, true, vma->vm_start, vma->vm_end - vma->vm_start);
 | 
	
		
			
				|  |  | +    __anon_vma_del(vma);
 | 
	
		
			
				|  |  | +    /** todo: 这里应该会存在bug,应修复。
 | 
	
		
			
				|  |  | +     * 若anon_vma的等待队列上有其他的进程,由于anon_vma被释放
 | 
	
		
			
				|  |  | +     * 这些在等待队列上的进程将无法被唤醒。
 | 
	
		
			
				|  |  | +     */
 | 
	
		
			
				|  |  | +    list_init(&vma->anon_vma_list);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    semaphore_up(&anon->sem);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      return 0;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * @brief 解除一段虚拟地址的映射(这些地址必须在vma中存在)
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * @param mm 内存空间结构体
 | 
	
		
			
				|  |  | + * @param vaddr 起始地址
 | 
	
		
			
				|  |  | + * @param length 结束地址
 | 
	
		
			
				|  |  | + * @param destroy 是否释放vma结构体
 | 
	
		
			
				|  |  | + * @return int 错误码
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +int mm_unmap(struct mm_struct *mm, uint64_t vaddr, uint64_t length, bool destroy)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    int retval = 0;
 | 
	
		
			
				|  |  | +    for (uint64_t unmapped = 0; unmapped < length;)
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        struct vm_area_struct *vma = vma_find(mm, vaddr + unmapped);
 | 
	
		
			
				|  |  | +        if (unlikely(vma == NULL))
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            kerror("Unmap addr failed: vma not found. At address: %#018lx, pid=%ld", vaddr + unmapped, current_pcb->pid);
 | 
	
		
			
				|  |  | +            return -EINVAL;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        if (unlikely(vma->vm_start != (vaddr + unmapped)))
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            kerror("Unmap addr failed: addr_start is not equal to current: %#018lx.", vaddr + unmapped);
 | 
	
		
			
				|  |  | +            return -EINVAL;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        if (vma->anon_vma != NULL)
 | 
	
		
			
				|  |  | +            mm_unmap_vma(mm, vma, NULL);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        unmapped += vma->vm_end - vma->vm_start;
 | 
	
		
			
				|  |  | +        // 释放vma结构体
 | 
	
		
			
				|  |  | +        if (destroy)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            vm_area_del(vma);
 | 
	
		
			
				|  |  | +            vm_area_free(vma);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    return 0;
 | 
	
		
			
				|  |  | +failed:;
 | 
	
		
			
				|  |  | +    kerror("Unmap addr failed.");
 | 
	
		
			
				|  |  | +    return retval;
 | 
	
		
			
				|  |  | +}
 |