new: 引入vmarea

This commit is contained in:
fslongjin
2022-08-12 18:27:34 +08:00
parent aa1046afae
commit 642fa1def8
5 changed files with 235 additions and 130 deletions

View File

@ -78,7 +78,7 @@ int mm_map_proc_page_table(ul proc_page_table_addr, bool is_phys, ul virt_addr_s
uint64_t length_mapped = 0;
// 对user标志位进行校正
if (flags & PAGE_U_S)
if ((flags & PAGE_U_S) != 0)
user = true;
else
user = false;
@ -108,14 +108,12 @@ int mm_map_proc_page_table(ul proc_page_table_addr, bool is_phys, ul virt_addr_s
uint64_t pdpte_id = (((virt_addr_start + length_mapped) >> PAGE_1G_SHIFT) & 0x1ff);
uint64_t *pdpt_ptr = (uint64_t *)phys_2_virt(*pml4e_ptr & (~0xfffUL));
// kdebug("pdpt_ptr=%#018lx", pdpt_ptr);
// 循环填写二级页表
for (; (pgt_num.num_PDPTE > 0) && pdpte_id < 512; ++pdpte_id)
{
--pgt_num.num_PDPTE;
uint64_t *pdpte_ptr = (pdpt_ptr + pdpte_id);
// kdebug("pgt_num.num_PDPTE=%ld pdpte_ptr=%#018lx", pgt_num.num_PDPTE, pdpte_ptr);
// 创建新的三级页表
if (*pdpte_ptr == 0)
@ -123,12 +121,10 @@ int mm_map_proc_page_table(ul proc_page_table_addr, bool is_phys, ul virt_addr_s
ul *virt_addr = kmalloc(PAGE_4K_SIZE, 0);
memset(virt_addr, 0, PAGE_4K_SIZE);
set_pdpt(pdpte_ptr, mk_pdpt(virt_2_phys(virt_addr), (user ? PAGE_USER_DIR : PAGE_KERNEL_DIR)));
// kdebug("created new pdt, *pdpte_ptr=%#018lx, virt_addr=%#018lx", *pdpte_ptr, virt_addr);
}
uint64_t pde_id = (((virt_addr_start + length_mapped) >> PAGE_2M_SHIFT) & 0x1ff);
uint64_t *pd_ptr = (uint64_t *)phys_2_virt(*pdpte_ptr & (~0xfffUL));
// kdebug("pd_ptr=%#018lx, *pd_ptr=%#018lx", pd_ptr, *pd_ptr);
// 循环填写三级页表初始化2M物理页
for (; (pgt_num.num_PDE > 0) && pde_id < 512; ++pde_id)
@ -136,7 +132,6 @@ int mm_map_proc_page_table(ul proc_page_table_addr, bool is_phys, ul virt_addr_s
--pgt_num.num_PDE;
// 计算当前2M物理页对应的pdt的页表项的物理地址
ul *pde_ptr = pd_ptr + pde_id;
// ====== 使用4k页 =======
if (unlikely(use4k))
{
@ -144,7 +139,6 @@ int mm_map_proc_page_table(ul proc_page_table_addr, bool is_phys, ul virt_addr_s
if (*pde_ptr == 0)
{
// 创建四级页表
// kdebug("create PT");
uint64_t *vaddr = kmalloc(PAGE_4K_SIZE, 0);
memset(vaddr, 0, PAGE_4K_SIZE);
set_pdt(pde_ptr, mk_pdt(virt_2_phys(vaddr), (user ? PAGE_USER_PDE : PAGE_KERNEL_PDE)));
@ -156,27 +150,25 @@ int mm_map_proc_page_table(ul proc_page_table_addr, bool is_phys, ul virt_addr_s
}
uint64_t pte_id = (((virt_addr_start + length_mapped) >> PAGE_4K_SHIFT) & 0x1ff);
uint64_t *pt_ptr = (uint64_t *)phys_2_virt(*pde_ptr & (~0x1fffUL));
uint64_t *pt_ptr = (uint64_t *)phys_2_virt(*pde_ptr & (~0xfffUL));
// 循环填写4级页表初始化4K页
for (; pgt_num.num_PTE > 0 && pte_id < 512; ++pte_id)
for (; (pgt_num.num_PTE > 0) && pte_id < 512; ++pte_id)
{
--pgt_num.num_PTE;
uint64_t *pte_ptr = pt_ptr + pte_id;
if (unlikely(*pte_ptr != 0))
{
kwarn("pte already exists.");
length_mapped += PAGE_4K_SIZE;
}
set_pt(pte_ptr, mk_pt((ul)phys_addr_start + length_mapped, flags | (user ? PAGE_USER_4K_PAGE : PAGE_KERNEL_4K_PAGE)));
else
set_pt(pte_ptr, mk_pt((ul)phys_addr_start + length_mapped, flags | (user ? PAGE_USER_4K_PAGE : PAGE_KERNEL_4K_PAGE)));
length_mapped += PAGE_4K_SIZE;
}
}
// ======= 使用2M页 ========
else
{
if (unlikely(*pde_ptr != 0 && user))
if (unlikely((*pde_ptr != 0) && user == true))
{
// 如果是用户态可访问的页,则释放当前新获取的物理页
if (likely((((ul)phys_addr_start + length_mapped) >> PAGE_2M_SHIFT) < mm_total_2M_pages)) // 校验是否为内存中的物理页
@ -213,7 +205,6 @@ void mm_unmap_proc_table(ul proc_page_table_addr, bool is_phys, ul virt_addr_sta
// 计算线性地址对应的pml4页表项的地址
mm_pgt_entry_num_t pgt_num;
mm_calculate_entry_num(length, &pgt_num);
// kdebug("ent1=%d ent2=%d ent3=%d, ent4=%d", pgt_num.num_PML4E, pgt_num.num_PDPTE, pgt_num.num_PDE, pgt_num.num_PTE);
// 已取消映射的内存大小
uint64_t length_unmapped = 0;
@ -272,21 +263,22 @@ void mm_unmap_proc_table(ul proc_page_table_addr, bool is_phys, ul virt_addr_sta
{
// 存在4K页
uint64_t pte_id = (((virt_addr_start + length_unmapped) >> PAGE_4K_SHIFT) & 0x1ff);
uint64_t *pt_ptr = (uint64_t *)phys_2_virt(*pde_ptr & (~0x1fffUL));
uint64_t *pte_ptr = pt_ptr + pte_id;
uint64_t *pt_ptr = (uint64_t *)phys_2_virt(*pde_ptr & (~0xfffUL));
// 循环处理4K页表
for (; pgt_num.num_PTE > 0 && pte_id < 512; ++pte_id, ++pte_ptr)
for (; pgt_num.num_PTE > 0 && pte_id < 512; ++pte_id)
{
uint64_t *pte_ptr = pt_ptr + pte_id;
--pgt_num.num_PTE;
// todo: 当支持使用slab分配4K内存作为进程的4K页之后在这里需要释放这些4K对象
*pte_ptr = 0;
length_unmapped += PAGE_4K_SIZE;
}
// 4级页表已经空了释放页表
if (unlikely(mm_check_page_table(pt_ptr)) == 0)
{
*pde_ptr = 0;
kfree(pt_ptr);
}
}
else
{
@ -298,11 +290,17 @@ void mm_unmap_proc_table(ul proc_page_table_addr, bool is_phys, ul virt_addr_sta
// 3级页表已经空了释放页表
if (unlikely(mm_check_page_table(pd_ptr)) == 0)
{
*pdpte_ptr = 0;
kfree(pd_ptr);
}
}
// 2级页表已经空了释放页表
if (unlikely(mm_check_page_table(pdpt_ptr)) == 0)
{
*pml4e_ptr = 0;
kfree(pdpt_ptr);
}
}
flush_tlb();
}
@ -330,10 +328,15 @@ int mm_map_vma(struct mm_struct *mm, uint64_t vaddr, uint64_t length, uint64_t p
vma->vm_end = vaddr + length;
// 将VMA加入链表
__vma_link_list(mm, vma, mm->vmas);
retval = vma_insert(mm, vma);
if (retval == -EEXIST) // 之前已经存在了相同的vma直接返回
{
kfree(vma);
return -EEXIST;
}
uint64_t len_4k = length % PAGE_2M_SIZE;
uint64_t len_2m = length - len_4k;
// kdebug("len_2m=%ld", len_2m);
// ==== 将地址映射到页表
/*
todo: 限制页面的读写权限
@ -371,6 +374,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);
return retval;