new: vma反向映射

This commit is contained in:
fslongjin
2022-08-15 01:42:34 +08:00
parent f3cd2b7777
commit 1dd9195d69
20 changed files with 486 additions and 245 deletions

View File

@ -4,26 +4,61 @@
/**
* @brief 将vma结构体插入mm_struct的链表之中
*
*
* @param mm 内存空间分布结构体
* @param vma 待插入的VMA结构体
* @param prev 链表的前一个结点
*/
void __vma_link_list(struct mm_struct * mm, struct vm_area_struct * vma, struct vm_area_struct * prev);
void __vma_link_list(struct mm_struct *mm, struct vm_area_struct *vma, struct vm_area_struct *prev);
/**
* @brief 将vma给定结构体从vma链表的结点之中删除
*
*
* @param mm 内存空间分布结构体
* @param vma 待插入的VMA结构体
*/
void __vma_unlink_list(struct mm_struct * mm, struct vm_area_struct * vma);
void __vma_unlink_list(struct mm_struct *mm, struct vm_area_struct *vma);
/**
* @brief 获取指定虚拟地址处映射的物理地址
*
*
* @param mm 内存空间分布结构体
* @param vaddr 虚拟地址
* @return uint64_t 已映射的物理地址
*/
uint64_t __mm_get_paddr(struct mm_struct * mm, uint64_t vaddr);
uint64_t __mm_get_paddr(struct mm_struct *mm, uint64_t vaddr);
/**
* @brief 创建anon_vma并将其与页面结构体进行绑定
* 若提供的页面结构体指针为NULL则只创建不绑定
*
* @param page 页面结构体的指针
* @param lock_page 是否将页面结构体加锁
* @return struct anon_vma_t* 创建好的anon_vma
*/
struct anon_vma_t *__anon_vma_create_alloc(struct Page *page, bool lock_page);
/**
* @brief 释放anon vma结构体
*
* @param anon_vma 待释放的anon_vma结构体
* @return int 返回码
*/
int __anon_vma_free(struct anon_vma_t *anon_vma);
/**
* @brief 将指定的vma加入到anon_vma的管理范围之中
*
* @param anon_vma 页面的anon_vma
* @param vma 待加入的vma
* @return int 返回码
*/
int __anon_vma_add(struct anon_vma_t *anon_vma, struct vm_area_struct *vma);
/**
* @brief 从anon_vma的管理范围中删除指定的vma
* (在进入这个函数之前,应该要加锁)
* @param vma 将要取消对应的anon_vma管理的vma结构体
* @return int 返回码
*/
int __anon_vma_del(struct vm_area_struct *vma);

View File

@ -1,6 +1,7 @@
#pragma once
#include <common/glib.h>
#include <common/semaphore.h>
#include <common/spinlock.h>
#include <common/atomic.h>
struct mm_struct;
@ -163,10 +164,18 @@ struct mm_struct
*/
struct anon_vma_t
{
// anon vma的操作信号量
semaphore_t sem;
/**
* 记录当前有多少个vma与该anon_vma关联当vma被释放时
* 应当检查这个值。当该值为0时应当释放anon_vma结构体
*/
atomic_t ref_count;
// todo: 把下面的循环链表更换成红黑树
// 与当前anon_vma相关的vma的列表
struct List vma_list;
// 当前anon vma对应的page
struct Page* page;
};

View File

@ -213,6 +213,7 @@ void mm_init()
barrier();
tmp_page = memory_management_struct.pages_struct + j;
page_init(tmp_page, PAGE_PGT_MAPPED | PAGE_KERNEL | PAGE_KERNEL_INIT);
barrier();
page_num = tmp_page->addr_phys >> PAGE_2M_SHIFT;
*(memory_management_struct.bmp + (page_num >> 6)) |= (1UL << (page_num % 64));
++tmp_page->zone->count_pages_using;
@ -248,7 +249,7 @@ unsigned long page_init(struct Page *page, ul flags)
++page->zone->total_pages_link;
}
page->anon_vma = NULL;
spin_init(&page->op_lock);
spin_init(&(page->op_lock));
return 0;
}
@ -588,7 +589,9 @@ uint64_t mm_do_brk(uint64_t old_brk_end_addr, int64_t offset)
{
for (uint64_t i = old_brk_end_addr; i < end_addr; i += PAGE_2M_SIZE)
{
mm_map_vma(current_pcb->mm, i, PAGE_2M_SIZE, alloc_pages(ZONE_NORMAL, 1, PAGE_PGT_MAPPED)->addr_phys, VM_USER | VM_ACCESS_FLAGS, NULL);
struct vm_area_struct * vma=NULL;
mm_create_vma(current_pcb->mm, i, PAGE_2M_SIZE, VM_USER | VM_ACCESS_FLAGS, NULL, &vma);
mm_map_vma(vma, alloc_pages(ZONE_NORMAL, 1, PAGE_PGT_MAPPED)->addr_phys);
}
current_pcb->mm->brk_end = end_addr;
}

View File

@ -325,6 +325,7 @@ static inline void vma_init(struct vm_area_struct *vma, struct mm_struct *mm)
vma->vm_mm = mm;
vma->vm_prev = vma->vm_next = NULL;
vma->vm_ops = NULL;
list_init(&vma->anon_vma_list);
}
/**
@ -442,17 +443,26 @@ void mm_unmap_proc_table(ul proc_page_table_addr, bool is_phys, ul virt_addr_sta
})
/**
* @brief 创建VMA,并将物理地址映射到指定的虚拟地址处
* @brief 创建VMA
*
* @param mm 要绑定的内存空间分布结构体
* @param vaddr 起始虚拟地址
* @param length 长度(字节)
* @param paddr 起始物理地址
* @param vm_flags vma的标志
* @param vm_ops vma的操作接口
* @param res_vma 返回的vma指针
* @return int 错误码
*/
int mm_map_vma(struct mm_struct *mm, uint64_t vaddr, uint64_t length, uint64_t paddr, vm_flags_t vm_flags, struct vm_operations_t *vm_ops);
int mm_create_vma(struct mm_struct *mm, uint64_t vaddr, uint64_t length, vm_flags_t vm_flags, struct vm_operations_t *vm_ops, struct vm_area_struct **res_vma);
/**
* @brief 将指定的物理地址映射到指定的vma处
*
* @param vma 要进行映射的VMA结构体
* @param paddr 起始物理地址
* @return int 错误码
*/
int mm_map_vma(struct vm_area_struct *vma, uint64_t paddr);
/**
* @brief 在页表中取消指定的vma的映射

View File

@ -306,17 +306,17 @@ void mm_unmap_proc_table(ul proc_page_table_addr, bool is_phys, ul virt_addr_sta
}
/**
* @brief 创建VMA,并将物理地址映射到指定的虚拟地址处
* @brief 创建VMA
*
* @param mm 要绑定的内存空间分布结构体
* @param vaddr 起始虚拟地址
* @param length 长度(字节)
* @param paddr 起始物理地址
* @param vm_flags vma的标志
* @param vm_ops vma的操作接口
* @param res_vma 返回的vma指针
* @return int 错误码
*/
int mm_map_vma(struct mm_struct *mm, uint64_t vaddr, uint64_t length, uint64_t paddr, vm_flags_t vm_flags, struct vm_operations_t *vm_ops)
int mm_create_vma(struct mm_struct *mm, uint64_t vaddr, uint64_t length, vm_flags_t vm_flags, struct vm_operations_t *vm_ops, struct vm_area_struct **res_vma)
{
int retval = 0;
struct vm_area_struct *vma = vm_area_alloc(mm);
@ -327,19 +327,50 @@ int mm_map_vma(struct mm_struct *mm, uint64_t vaddr, uint64_t length, uint64_t p
vma->vm_start = vaddr;
vma->vm_end = vaddr + length;
// 将vma与对应的anon_vma进行绑定
struct Page * pg = Phy_to_2M_Page(paddr);
// 将VMA加入链表
// 将VMA加入mm的链表
retval = vma_insert(mm, vma);
if (retval == -EEXIST) // 之前已经存在了相同的vma直接返回
{
*res_vma = vma_find(mm, vma->vm_start);
kfree(vma);
return -EEXIST;
}
*res_vma = vma;
return 0;
}
/**
* @brief 将指定的物理地址映射到指定的vma处
*
* @param vma 要进行映射的VMA结构体
* @param paddr 起始物理地址
* @return int 错误码
*/
int mm_map_vma(struct vm_area_struct *vma, uint64_t paddr)
{
int retval = 0;
// 获取物理地址对应的页面
struct Page *pg = Phy_to_2M_Page(paddr);
if (unlikely(pg->anon_vma == NULL)) // 若页面不存在anon_vma则为页面创建anon_vma
{
uint64_t rflags;
// todo: 查明为什么在mm_init中spin init之后pg会变为0
spin_init(&pg->op_lock);
spin_lock_irqsave(&pg->op_lock, rflags);
if (unlikely(pg->anon_vma == NULL))
__anon_vma_create_alloc(pg, false);
spin_unlock_irqrestore(&pg->op_lock, rflags);
}
barrier();
// 将anon vma与vma进行绑定
__anon_vma_add(pg->anon_vma, vma);
barrier();
uint64_t length = vma->vm_end - vma->vm_start;
// ==== 将地址映射到页表 ====
uint64_t len_4k = length % PAGE_2M_SIZE;
uint64_t len_2m = length - len_4k;
// ==== 将地址映射到页表
/*
todo: 限制页面的读写权限
*/
@ -348,12 +379,12 @@ int mm_map_vma(struct mm_struct *mm, uint64_t vaddr, uint64_t length, uint64_t p
if (likely(len_2m > 0))
{
uint64_t page_flags = 0;
if (vm_flags & VM_USER)
if (vma->vm_flags & VM_USER)
page_flags = PAGE_USER_PAGE;
else
page_flags = PAGE_KERNEL_PAGE;
// 这里直接设置user标志位为false因为该函数内部会对其进行自动校正
retval = mm_map_proc_page_table((uint64_t)mm->pgd, true, vaddr, paddr, len_2m, page_flags, false, false, false);
retval = mm_map_proc_page_table((uint64_t)vma->vm_mm->pgd, true, vma->vm_start, paddr, len_2m, page_flags, false, false, false);
if (unlikely(retval != 0))
goto failed;
}
@ -363,12 +394,12 @@ int mm_map_vma(struct mm_struct *mm, uint64_t vaddr, uint64_t length, uint64_t p
len_4k = ALIGN(len_4k, PAGE_4K_SIZE);
uint64_t page_flags = 0;
if (vm_flags & VM_USER)
if (vma->vm_flags & VM_USER)
page_flags = PAGE_USER_4K_PAGE;
else
page_flags = PAGE_KERNEL_4K_PAGE;
// 这里直接设置user标志位为false因为该函数内部会对其进行自动校正
retval = mm_map_proc_page_table((uint64_t)mm->pgd, true, vaddr + len_2m, paddr + len_2m, len_4k, page_flags, false, false, true);
retval = mm_map_proc_page_table((uint64_t)vma->vm_mm->pgd, true, vma->vm_start + len_2m, paddr + len_2m, len_4k, page_flags, false, false, true);
if (unlikely(retval != 0))
goto failed;
}
@ -376,9 +407,7 @@ int mm_map_vma(struct mm_struct *mm, uint64_t vaddr, uint64_t length, uint64_t p
flush_tlb();
return 0;
failed:;
kdebug("failed.");
__vma_unlink_list(mm, vma);
vm_area_free(vma);
kdebug("map VMA failed.");
return retval;
}

View File

@ -139,10 +139,10 @@ int vma_insert(struct mm_struct *mm, struct vm_area_struct *vma)
prev = prev->vm_prev;
if (prev == NULL) // 要将当前vma插入到链表的尾部
{
struct vm_area_struct * ptr = mm->vmas;
while(ptr)
struct vm_area_struct *ptr = mm->vmas;
while (ptr)
{
if(ptr->vm_next)
if (ptr->vm_next)
ptr = ptr->vm_next;
else
{
@ -153,4 +153,103 @@ int vma_insert(struct mm_struct *mm, struct vm_area_struct *vma)
}
__vma_link_list(mm, vma, prev);
return 0;
}
}
/**
* @brief 创建anon_vma并将其与页面结构体进行绑定
* 若提供的页面结构体指针为NULL则只创建不绑定
*
* @param page 页面结构体的指针
* @param lock_page 是否将页面结构体加锁
* @return struct anon_vma_t* 创建好的anon_vma
*/
struct anon_vma_t *__anon_vma_create_alloc(struct Page *page, bool lock_page)
{
struct anon_vma_t *anon_vma = (struct anon_vma_t *)kmalloc(sizeof(struct anon_vma_t), 0);
if (unlikely(anon_vma == NULL))
return NULL;
memset(anon_vma, 0, sizeof(struct anon_vma_t));
list_init(&anon_vma->vma_list);
semaphore_init(&anon_vma->sem, 1);
// 需要和page进行绑定
if (page != NULL)
{
if (lock_page == true) // 需要加锁
{
uint64_t rflags;
spin_lock_irqsave(&page->op_lock, rflags);
page->anon_vma = anon_vma;
spin_unlock_irqrestore(&page->op_lock, rflags);
}
else
page->anon_vma = anon_vma;
anon_vma->page = page;
}
return anon_vma;
}
/**
* @brief 将指定的vma加入到anon_vma的管理范围之中
*
* @param anon_vma 页面的anon_vma
* @param vma 待加入的vma
* @return int 返回码
*/
int __anon_vma_add(struct anon_vma_t *anon_vma, struct vm_area_struct *vma)
{
semaphore_down(&anon_vma->sem);
list_add(&anon_vma->vma_list, &vma->anon_vma_list);
vma->anon_vma = anon_vma;
atomic_inc(&anon_vma->ref_count);
semaphore_up(&anon_vma->sem);
return 0;
}
/**
* @brief 释放anon vma结构体
*
* @param anon_vma 待释放的anon_vma结构体
* @return int 返回码
*/
int __anon_vma_free(struct anon_vma_t *anon_vma)
{
if (anon_vma->page != NULL)
{
spin_lock(&anon_vma->page->op_lock);
anon_vma->page->anon_vma = NULL;
spin_unlock(&anon_vma->page->op_lock);
}
kfree(anon_vma);
return 0;
}
/**
* @brief 从anon_vma的管理范围中删除指定的vma
* (在进入这个函数之前,应该要加锁)
* @param vma 将要取消对应的anon_vma管理的vma结构体
* @return int 返回码
*/
int __anon_vma_del(struct vm_area_struct *vma)
{
// 当前vma没有绑定anon_vma
if (vma->anon_vma == NULL)
return -EINVAL;
list_del(&vma->anon_vma_list);
semaphore_down(&vma->anon_vma->sem);
atomic_dec(&vma->anon_vma->ref_count);
if (unlikely(atomic_read(&vma->anon_vma->ref_count) == 0)) // 应当释放该anon_vma
{
__anon_vma_free(vma->anon_vma);
// 释放了anon_vma之后清理当前vma的关联数据
vma->anon_vma = NULL;
list_init(&vma->anon_vma_list);
}
else
semaphore_up(&vma->anon_vma->sem);
}