mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-12 05:56:48 +00:00
new: 引入vmarea
This commit is contained in:
parent
aa1046afae
commit
642fa1def8
@ -586,8 +586,7 @@ 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)
|
for (uint64_t i = old_brk_end_addr; i < end_addr; i += PAGE_2M_SIZE)
|
||||||
{
|
{
|
||||||
// kdebug("map [%#018lx]", i);
|
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);
|
||||||
mm_map_proc_page_table((uint64_t)current_pcb->mm->pgd, true, i, alloc_pages(ZONE_NORMAL, 1, PAGE_PGT_MAPPED)->addr_phys, PAGE_2M_SIZE, PAGE_USER_PAGE, true, true, false);
|
|
||||||
}
|
}
|
||||||
current_pcb->mm->brk_end = end_addr;
|
current_pcb->mm->brk_end = end_addr;
|
||||||
}
|
}
|
||||||
|
@ -382,6 +382,7 @@ ul set_page_attr(struct Page *page, ul flags);
|
|||||||
#define VM_SOFTDIRTY (1 << 5)
|
#define VM_SOFTDIRTY (1 << 5)
|
||||||
#define VM_MAYSHARE (1 << 6) // 该vma可被共享
|
#define VM_MAYSHARE (1 << 6) // 该vma可被共享
|
||||||
#define VM_USER (1 << 7) // 该vma可被用户态访问
|
#define VM_USER (1 << 7) // 该vma可被用户态访问
|
||||||
|
#define VM_DONTCOPY (1 << 8) // 当fork的时候不拷贝该虚拟内存区域
|
||||||
|
|
||||||
/* VMA basic access permission flags */
|
/* VMA basic access permission flags */
|
||||||
#define VM_ACCESS_FLAGS (VM_READ | VM_WRITE | VM_EXEC)
|
#define VM_ACCESS_FLAGS (VM_READ | VM_WRITE | VM_EXEC)
|
||||||
@ -396,6 +397,7 @@ static inline void vma_init(struct vm_area_struct *vma, struct mm_struct *mm)
|
|||||||
{
|
{
|
||||||
memset(vma, 0, sizeof(struct vm_area_struct));
|
memset(vma, 0, sizeof(struct vm_area_struct));
|
||||||
vma->vm_mm = mm;
|
vma->vm_mm = mm;
|
||||||
|
vma->vm_prev = vma->vm_next = NULL;
|
||||||
vma->vm_ops = NULL;
|
vma->vm_ops = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -435,6 +437,31 @@ struct vm_area_struct *vm_area_alloc(struct mm_struct *mm);
|
|||||||
*/
|
*/
|
||||||
void vm_area_free(struct vm_area_struct *vma);
|
void vm_area_free(struct vm_area_struct *vma);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 从链表中删除指定的vma结构体
|
||||||
|
*
|
||||||
|
* @param vma
|
||||||
|
*/
|
||||||
|
void vm_area_del(struct vm_area_struct *vma);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 查找第一个符合“addr < vm_end”条件的vma
|
||||||
|
*
|
||||||
|
* @param mm 内存空间分布结构体
|
||||||
|
* @param addr 虚拟地址
|
||||||
|
* @return struct vm_area_struct* 符合条件的vma
|
||||||
|
*/
|
||||||
|
struct vm_area_struct *vma_find(struct mm_struct *mm, uint64_t addr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 插入vma
|
||||||
|
*
|
||||||
|
* @param mm
|
||||||
|
* @param vma
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
int vma_insert(struct mm_struct *mm, struct vm_area_struct *vma);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 重新初始化页表的函数
|
* @brief 重新初始化页表的函数
|
||||||
* 将所有物理页映射到线性地址空间
|
* 将所有物理页映射到线性地址空间
|
||||||
@ -509,9 +536,7 @@ int mm_map_vma(struct mm_struct *mm, uint64_t vaddr, uint64_t length, uint64_t p
|
|||||||
* @param paddr 返回的被取消映射的起始物理地址
|
* @param paddr 返回的被取消映射的起始物理地址
|
||||||
* @return int 返回码
|
* @return int 返回码
|
||||||
*/
|
*/
|
||||||
int mm_umap_vma(struct mm_struct *mm, struct vm_area_struct * vma, uint64_t *paddr);
|
int mm_umap_vma(struct mm_struct *mm, struct vm_area_struct *vma, uint64_t *paddr);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 检测是否为有效的2M页(物理内存页)
|
* @brief 检测是否为有效的2M页(物理内存页)
|
||||||
@ -547,3 +572,13 @@ uint64_t mm_do_brk(uint64_t old_brk_end_addr, int64_t offset);
|
|||||||
* @return struct mm_stat_t 内存信息结构体
|
* @return struct mm_stat_t 内存信息结构体
|
||||||
*/
|
*/
|
||||||
struct mm_stat_t mm_stat();
|
struct mm_stat_t mm_stat();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 检测指定地址是否已经被映射
|
||||||
|
*
|
||||||
|
* @param page_table_phys_addr 页表的物理地址
|
||||||
|
* @param virt_addr 要检测的地址
|
||||||
|
* @return true 已经被映射
|
||||||
|
* @return false
|
||||||
|
*/
|
||||||
|
bool mm_check_mapped(ul page_table_phys_addr, uint64_t virt_addr);
|
@ -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;
|
uint64_t length_mapped = 0;
|
||||||
|
|
||||||
// 对user标志位进行校正
|
// 对user标志位进行校正
|
||||||
if (flags & PAGE_U_S)
|
if ((flags & PAGE_U_S) != 0)
|
||||||
user = true;
|
user = true;
|
||||||
else
|
else
|
||||||
user = false;
|
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 pdpte_id = (((virt_addr_start + length_mapped) >> PAGE_1G_SHIFT) & 0x1ff);
|
||||||
uint64_t *pdpt_ptr = (uint64_t *)phys_2_virt(*pml4e_ptr & (~0xfffUL));
|
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)
|
for (; (pgt_num.num_PDPTE > 0) && pdpte_id < 512; ++pdpte_id)
|
||||||
{
|
{
|
||||||
--pgt_num.num_PDPTE;
|
--pgt_num.num_PDPTE;
|
||||||
uint64_t *pdpte_ptr = (pdpt_ptr + pdpte_id);
|
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)
|
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);
|
ul *virt_addr = kmalloc(PAGE_4K_SIZE, 0);
|
||||||
memset(virt_addr, 0, PAGE_4K_SIZE);
|
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)));
|
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 pde_id = (((virt_addr_start + length_mapped) >> PAGE_2M_SHIFT) & 0x1ff);
|
||||||
uint64_t *pd_ptr = (uint64_t *)phys_2_virt(*pdpte_ptr & (~0xfffUL));
|
uint64_t *pd_ptr = (uint64_t *)phys_2_virt(*pdpte_ptr & (~0xfffUL));
|
||||||
// kdebug("pd_ptr=%#018lx, *pd_ptr=%#018lx", pd_ptr, *pd_ptr);
|
|
||||||
|
|
||||||
// 循环填写三级页表,初始化2M物理页
|
// 循环填写三级页表,初始化2M物理页
|
||||||
for (; (pgt_num.num_PDE > 0) && pde_id < 512; ++pde_id)
|
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;
|
--pgt_num.num_PDE;
|
||||||
// 计算当前2M物理页对应的pdt的页表项的物理地址
|
// 计算当前2M物理页对应的pdt的页表项的物理地址
|
||||||
ul *pde_ptr = pd_ptr + pde_id;
|
ul *pde_ptr = pd_ptr + pde_id;
|
||||||
|
|
||||||
// ====== 使用4k页 =======
|
// ====== 使用4k页 =======
|
||||||
if (unlikely(use4k))
|
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)
|
if (*pde_ptr == 0)
|
||||||
{
|
{
|
||||||
// 创建四级页表
|
// 创建四级页表
|
||||||
// kdebug("create PT");
|
|
||||||
uint64_t *vaddr = kmalloc(PAGE_4K_SIZE, 0);
|
uint64_t *vaddr = kmalloc(PAGE_4K_SIZE, 0);
|
||||||
memset(vaddr, 0, PAGE_4K_SIZE);
|
memset(vaddr, 0, PAGE_4K_SIZE);
|
||||||
set_pdt(pde_ptr, mk_pdt(virt_2_phys(vaddr), (user ? PAGE_USER_PDE : PAGE_KERNEL_PDE)));
|
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 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页
|
// 循环填写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;
|
--pgt_num.num_PTE;
|
||||||
uint64_t *pte_ptr = pt_ptr + pte_id;
|
uint64_t *pte_ptr = pt_ptr + pte_id;
|
||||||
|
|
||||||
if (unlikely(*pte_ptr != 0))
|
if (unlikely(*pte_ptr != 0))
|
||||||
{
|
|
||||||
kwarn("pte already exists.");
|
kwarn("pte already exists.");
|
||||||
length_mapped += PAGE_4K_SIZE;
|
else
|
||||||
}
|
|
||||||
|
|
||||||
set_pt(pte_ptr, mk_pt((ul)phys_addr_start + length_mapped, flags | (user ? PAGE_USER_4K_PAGE : PAGE_KERNEL_4K_PAGE)));
|
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页 ========
|
// ======= 使用2M页 ========
|
||||||
else
|
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)) // 校验是否为内存中的物理页
|
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页表项的地址
|
// 计算线性地址对应的pml4页表项的地址
|
||||||
mm_pgt_entry_num_t pgt_num;
|
mm_pgt_entry_num_t pgt_num;
|
||||||
mm_calculate_entry_num(length, &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;
|
uint64_t length_unmapped = 0;
|
||||||
|
|
||||||
@ -272,22 +263,23 @@ void mm_unmap_proc_table(ul proc_page_table_addr, bool is_phys, ul virt_addr_sta
|
|||||||
{
|
{
|
||||||
// 存在4K页
|
// 存在4K页
|
||||||
uint64_t pte_id = (((virt_addr_start + length_unmapped) >> PAGE_4K_SHIFT) & 0x1ff);
|
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 *pt_ptr = (uint64_t *)phys_2_virt(*pde_ptr & (~0xfffUL));
|
||||||
uint64_t *pte_ptr = pt_ptr + pte_id;
|
|
||||||
|
|
||||||
// 循环处理4K页表
|
// 循环处理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;
|
--pgt_num.num_PTE;
|
||||||
// todo: 当支持使用slab分配4K内存作为进程的4K页之后,在这里需要释放这些4K对象
|
|
||||||
*pte_ptr = 0;
|
*pte_ptr = 0;
|
||||||
length_unmapped += PAGE_4K_SIZE;
|
length_unmapped += PAGE_4K_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4级页表已经空了,释放页表
|
// 4级页表已经空了,释放页表
|
||||||
if (unlikely(mm_check_page_table(pt_ptr)) == 0)
|
if (unlikely(mm_check_page_table(pt_ptr)) == 0)
|
||||||
|
{
|
||||||
|
*pde_ptr = 0;
|
||||||
kfree(pt_ptr);
|
kfree(pt_ptr);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
*pde_ptr = 0;
|
*pde_ptr = 0;
|
||||||
@ -298,12 +290,18 @@ void mm_unmap_proc_table(ul proc_page_table_addr, bool is_phys, ul virt_addr_sta
|
|||||||
|
|
||||||
// 3级页表已经空了,释放页表
|
// 3级页表已经空了,释放页表
|
||||||
if (unlikely(mm_check_page_table(pd_ptr)) == 0)
|
if (unlikely(mm_check_page_table(pd_ptr)) == 0)
|
||||||
|
{
|
||||||
|
*pdpte_ptr = 0;
|
||||||
kfree(pd_ptr);
|
kfree(pd_ptr);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// 2级页表已经空了,释放页表
|
// 2级页表已经空了,释放页表
|
||||||
if (unlikely(mm_check_page_table(pdpt_ptr)) == 0)
|
if (unlikely(mm_check_page_table(pdpt_ptr)) == 0)
|
||||||
|
{
|
||||||
|
*pml4e_ptr = 0;
|
||||||
kfree(pdpt_ptr);
|
kfree(pdpt_ptr);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
flush_tlb();
|
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->vm_end = vaddr + length;
|
||||||
|
|
||||||
// 将VMA加入链表
|
// 将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_4k = length % PAGE_2M_SIZE;
|
||||||
uint64_t len_2m = length - len_4k;
|
uint64_t len_2m = length - len_4k;
|
||||||
|
// kdebug("len_2m=%ld", len_2m);
|
||||||
// ==== 将地址映射到页表
|
// ==== 将地址映射到页表
|
||||||
/*
|
/*
|
||||||
todo: 限制页面的读写权限
|
todo: 限制页面的读写权限
|
||||||
@ -371,6 +374,7 @@ int mm_map_vma(struct mm_struct *mm, uint64_t vaddr, uint64_t length, uint64_t p
|
|||||||
flush_tlb();
|
flush_tlb();
|
||||||
return 0;
|
return 0;
|
||||||
failed:;
|
failed:;
|
||||||
|
kdebug("failed.");
|
||||||
__vma_unlink_list(mm, vma);
|
__vma_unlink_list(mm, vma);
|
||||||
vm_area_free(vma);
|
vm_area_free(vma);
|
||||||
return retval;
|
return retval;
|
||||||
|
@ -16,6 +16,18 @@ struct vm_area_struct *vm_area_alloc(struct mm_struct *mm)
|
|||||||
return vma;
|
return vma;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 从链表中删除指定的vma结构体
|
||||||
|
*
|
||||||
|
* @param vma
|
||||||
|
*/
|
||||||
|
void vm_area_del(struct vm_area_struct *vma)
|
||||||
|
{
|
||||||
|
if (vma->vm_mm == NULL)
|
||||||
|
return;
|
||||||
|
__vma_unlink_list(vma->vm_mm, vma);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 释放vma结构体
|
* @brief 释放vma结构体
|
||||||
*
|
*
|
||||||
@ -75,3 +87,70 @@ void __vma_unlink_list(struct mm_struct *mm, struct vm_area_struct *vma)
|
|||||||
if (next)
|
if (next)
|
||||||
next->vm_prev = prev;
|
next->vm_prev = prev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 查找第一个符合“addr < vm_end”条件的vma
|
||||||
|
*
|
||||||
|
* @param mm 内存空间分布结构体
|
||||||
|
* @param addr 虚拟地址
|
||||||
|
* @return struct vm_area_struct* 符合条件的vma
|
||||||
|
*/
|
||||||
|
struct vm_area_struct *vma_find(struct mm_struct *mm, uint64_t addr)
|
||||||
|
{
|
||||||
|
struct vm_area_struct *vma = mm->vmas;
|
||||||
|
struct vm_area_struct *result = NULL;
|
||||||
|
while (vma != NULL)
|
||||||
|
{
|
||||||
|
if (vma->vm_end > addr)
|
||||||
|
{
|
||||||
|
result = vma;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
vma = vma->vm_next;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 插入vma
|
||||||
|
*
|
||||||
|
* @param mm
|
||||||
|
* @param vma
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
int vma_insert(struct mm_struct *mm, struct vm_area_struct *vma)
|
||||||
|
{
|
||||||
|
|
||||||
|
struct vm_area_struct *prev;
|
||||||
|
prev = vma_find(mm, vma->vm_start);
|
||||||
|
if (prev && prev->vm_start == vma->vm_start && prev->vm_end == vma->vm_end)
|
||||||
|
{
|
||||||
|
// 已经存在了相同的vma
|
||||||
|
return -EEXIST;
|
||||||
|
}
|
||||||
|
else if (prev && (prev->vm_start == vma->vm_start || prev->vm_end == vma->vm_end)) // 暂时不支持扩展vma
|
||||||
|
{
|
||||||
|
kwarn("Not support: expand vma");
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
prev = vma_find(mm, vma->vm_end);
|
||||||
|
if (prev)
|
||||||
|
prev = prev->vm_prev;
|
||||||
|
if (prev == NULL) // 要将当前vma插入到链表的尾部
|
||||||
|
{
|
||||||
|
struct vm_area_struct * ptr = mm->vmas;
|
||||||
|
while(ptr)
|
||||||
|
{
|
||||||
|
if(ptr->vm_next)
|
||||||
|
ptr = ptr->vm_next;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
prev = ptr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
__vma_link_list(mm, vma, prev);
|
||||||
|
return 0;
|
||||||
|
}
|
@ -252,18 +252,39 @@ static int process_load_elf_file(struct pt_regs *regs, char *path)
|
|||||||
pos = phdr->p_offset;
|
pos = phdr->p_offset;
|
||||||
|
|
||||||
uint64_t virt_base = phdr->p_vaddr;
|
uint64_t virt_base = phdr->p_vaddr;
|
||||||
// kdebug("virt_base = %#018lx, &memory_management_struct=%#018lx", virt_base, &memory_management_struct);
|
|
||||||
|
|
||||||
while (remain_mem_size > 0)
|
while (remain_mem_size > 0)
|
||||||
{
|
{
|
||||||
|
// kdebug("loading...");
|
||||||
|
int64_t map_size = 0;
|
||||||
|
|
||||||
// todo: 改用slab分配4K大小内存块并映射到4K页
|
if (remain_mem_size > PAGE_2M_SIZE / 2)
|
||||||
if (!mm_check_mapped((uint64_t)current_pcb->mm->pgd, virt_base)) // 未映射,则新增物理页
|
|
||||||
{
|
{
|
||||||
mm_map_proc_page_table((uint64_t)current_pcb->mm->pgd, true, virt_base, alloc_pages(ZONE_NORMAL, 1, PAGE_PGT_MAPPED)->addr_phys, PAGE_2M_SIZE, PAGE_USER_PAGE, true, true, false);
|
|
||||||
|
|
||||||
|
uint64_t pa = alloc_pages(ZONE_NORMAL, 1, PAGE_PGT_MAPPED)->addr_phys;
|
||||||
|
int ret = mm_map_vma(current_pcb->mm, virt_base, PAGE_2M_SIZE, pa, VM_USER | VM_ACCESS_FLAGS, NULL);
|
||||||
|
// 防止内存泄露
|
||||||
|
if (ret == -EEXIST)
|
||||||
|
free_pages(Phy_to_2M_Page(pa), 1);
|
||||||
memset((void *)virt_base, 0, PAGE_2M_SIZE);
|
memset((void *)virt_base, 0, PAGE_2M_SIZE);
|
||||||
|
map_size = PAGE_2M_SIZE;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// todo: 使用4K、8K、32K大小内存块混合进行分配,提高空间利用率(减少了bmp的大小)
|
||||||
|
map_size = ALIGN(remain_mem_size, PAGE_4K_SIZE);
|
||||||
|
// 循环分配4K大小内存块
|
||||||
|
for (uint64_t off = 0; off < map_size; off += PAGE_4K_SIZE)
|
||||||
|
{
|
||||||
|
uint64_t paddr = virt_2_phys((uint64_t)kmalloc(PAGE_4K_SIZE, 0));
|
||||||
|
|
||||||
|
int val = mm_map_vma(current_pcb->mm, virt_base + off, PAGE_4K_SIZE, paddr, VM_USER | VM_ACCESS_FLAGS, NULL);
|
||||||
|
if (val == -EEXIST)
|
||||||
|
kfree(phys_2_virt(paddr));
|
||||||
|
memset((void *)(virt_base + off), 0, PAGE_4K_SIZE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pos = filp->file_ops->lseek(filp, pos, SEEK_SET);
|
pos = filp->file_ops->lseek(filp, pos, SEEK_SET);
|
||||||
int64_t val = 0;
|
int64_t val = 0;
|
||||||
if (remain_file_size != 0)
|
if (remain_file_size != 0)
|
||||||
@ -275,9 +296,9 @@ static int process_load_elf_file(struct pt_regs *regs, char *path)
|
|||||||
if (val < 0)
|
if (val < 0)
|
||||||
goto load_elf_failed;
|
goto load_elf_failed;
|
||||||
|
|
||||||
remain_mem_size -= PAGE_2M_SIZE;
|
remain_mem_size -= map_size;
|
||||||
remain_file_size -= val;
|
remain_file_size -= val;
|
||||||
virt_base += PAGE_2M_SIZE;
|
virt_base += map_size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -285,9 +306,12 @@ static int process_load_elf_file(struct pt_regs *regs, char *path)
|
|||||||
regs->rsp = current_pcb->mm->stack_start;
|
regs->rsp = current_pcb->mm->stack_start;
|
||||||
regs->rbp = current_pcb->mm->stack_start;
|
regs->rbp = current_pcb->mm->stack_start;
|
||||||
|
|
||||||
|
{
|
||||||
uint64_t pa = alloc_pages(ZONE_NORMAL, 1, PAGE_PGT_MAPPED)->addr_phys;
|
uint64_t pa = alloc_pages(ZONE_NORMAL, 1, PAGE_PGT_MAPPED)->addr_phys;
|
||||||
|
int val = mm_map_vma(current_pcb->mm, current_pcb->mm->stack_start - PAGE_2M_SIZE, PAGE_2M_SIZE, pa, VM_USER | VM_ACCESS_FLAGS, NULL);
|
||||||
mm_map_proc_page_table((uint64_t)current_pcb->mm->pgd, true, current_pcb->mm->stack_start - PAGE_2M_SIZE, pa, PAGE_2M_SIZE, PAGE_USER_PAGE, true, true, false);
|
if (val == -EEXIST)
|
||||||
|
free_pages(Phy_to_2M_Page(pa), 1);
|
||||||
|
}
|
||||||
|
|
||||||
// 清空栈空间
|
// 清空栈空间
|
||||||
memset((void *)(current_pcb->mm->stack_start - PAGE_2M_SIZE), 0, PAGE_2M_SIZE);
|
memset((void *)(current_pcb->mm->stack_start - PAGE_2M_SIZE), 0, PAGE_2M_SIZE);
|
||||||
@ -870,7 +894,7 @@ uint64_t process_copy_mm(uint64_t clone_flags, struct process_control_block *pcb
|
|||||||
memset(new_mms, 0, sizeof(struct mm_struct));
|
memset(new_mms, 0, sizeof(struct mm_struct));
|
||||||
|
|
||||||
memcpy(new_mms, current_pcb->mm, sizeof(struct mm_struct));
|
memcpy(new_mms, current_pcb->mm, sizeof(struct mm_struct));
|
||||||
|
new_mms->vmas = NULL;
|
||||||
pcb->mm = new_mms;
|
pcb->mm = new_mms;
|
||||||
|
|
||||||
// 分配顶层页表, 并设置顶层页表的物理地址
|
// 分配顶层页表, 并设置顶层页表的物理地址
|
||||||
@ -884,55 +908,40 @@ uint64_t process_copy_mm(uint64_t clone_flags, struct process_control_block *pcb
|
|||||||
uint64_t *current_pgd = (uint64_t *)phys_2_virt(current_pcb->mm->pgd);
|
uint64_t *current_pgd = (uint64_t *)phys_2_virt(current_pcb->mm->pgd);
|
||||||
|
|
||||||
uint64_t *new_pml4t = (uint64_t *)phys_2_virt(new_mms->pgd);
|
uint64_t *new_pml4t = (uint64_t *)phys_2_virt(new_mms->pgd);
|
||||||
// 迭代地拷贝用户空间
|
|
||||||
for (int i = 0; i <= 255; ++i)
|
// 拷贝用户空间的vma
|
||||||
|
struct vm_area_struct *vma = current_pcb->mm->vmas;
|
||||||
|
while (vma != NULL)
|
||||||
{
|
{
|
||||||
// 当前页表项为空
|
if (vma->vm_end > USER_MAX_LINEAR_ADDR)
|
||||||
if ((*(uint64_t *)(current_pgd + i)) == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// 分配新的二级页表
|
|
||||||
uint64_t *new_pdpt = (uint64_t *)kmalloc(PAGE_4K_SIZE, 0);
|
|
||||||
memset(new_pdpt, 0, PAGE_4K_SIZE);
|
|
||||||
|
|
||||||
// 在新的一级页表中设置新的二级页表表项
|
|
||||||
set_pml4t(new_pml4t + i, mk_pml4t(virt_2_phys(new_pdpt), (*(current_pgd + i)) & 0xfffUL));
|
|
||||||
|
|
||||||
uint64_t *current_pdpt = (uint64_t *)phys_2_virt((*(uint64_t *)(current_pgd + i)) & (~0xfffUL));
|
|
||||||
// kdebug("current_pdpt=%#018lx, current_pid=%d", current_pdpt, current_pcb->pid);
|
|
||||||
for (int j = 0; j < 512; ++j)
|
|
||||||
{
|
{
|
||||||
if (*(current_pdpt + j) == 0)
|
vma = vma->vm_next;
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// 分配新的三级页表
|
int64_t vma_size = vma->vm_end - vma->vm_start;
|
||||||
uint64_t *new_pdt = (uint64_t *)kmalloc(PAGE_4K_SIZE, 0);
|
// kdebug("vma_size=%ld, vm_start=%#018lx", vma_size, vma->vm_start);
|
||||||
memset(new_pdt, 0, PAGE_4K_SIZE);
|
if (vma_size > PAGE_2M_SIZE / 2)
|
||||||
// 在二级页表中填写新的三级页表
|
{
|
||||||
// 在新的二级页表中设置三级页表的表项
|
int page_to_alloc = (PAGE_2M_ALIGN(vma_size)) >> PAGE_2M_SHIFT;
|
||||||
set_pdpt((uint64_t *)(new_pdpt + j), mk_pdpt(virt_2_phys(new_pdt), (*(current_pdpt + j)) & 0xfffUL));
|
for (int i = 0; i < page_to_alloc; ++i)
|
||||||
|
|
||||||
uint64_t *current_pdt = (uint64_t *)phys_2_virt((*(current_pdpt + j)) & (~0xfffUL));
|
|
||||||
// kdebug("current_pdt=%#018lx", current_pdt);
|
|
||||||
|
|
||||||
// 循环拷贝三级页表
|
|
||||||
for (int k = 0; k < 512; ++k)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
if (*(current_pdt + k) == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// 获取新的物理页
|
|
||||||
uint64_t pa = alloc_pages(ZONE_NORMAL, 1, PAGE_PGT_MAPPED)->addr_phys;
|
uint64_t pa = alloc_pages(ZONE_NORMAL, 1, PAGE_PGT_MAPPED)->addr_phys;
|
||||||
|
|
||||||
memset((void *)phys_2_virt(pa), 0, PAGE_2M_SIZE);
|
mm_map_vma(new_mms, vma->vm_start + i * PAGE_2M_SIZE, PAGE_2M_SIZE, pa, vma->vm_flags, vma->vm_ops);
|
||||||
|
// kdebug("phys_2_virt(pa)=%#018lx, vaddr=%#018lx", phys_2_virt(pa), vma->vm_start + i * PAGE_2M_SIZE);
|
||||||
set_pdt((uint64_t *)(new_pdt + k), mk_pdt(pa, *(current_pdt + k) & 0x1ffUL));
|
memcpy((void *)phys_2_virt(pa), (void *)(vma->vm_start + i * PAGE_2M_SIZE), (vma_size >= PAGE_2M_SIZE) ? PAGE_2M_SIZE : vma_size);
|
||||||
|
vma_size -= PAGE_2M_SIZE;
|
||||||
// 拷贝数据
|
|
||||||
memcpy(phys_2_virt(pa), phys_2_virt((*(current_pdt + k)) & (~0x1ffUL)), PAGE_2M_SIZE);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uint64_t map_size = PAGE_4K_ALIGN(vma_size);
|
||||||
|
uint64_t va = (uint64_t)kmalloc(map_size, 0);
|
||||||
|
mm_map_vma(new_mms, vma->vm_start, map_size, virt_2_phys(va), vma->vm_flags, vma->vm_ops);
|
||||||
|
memcpy((void *)va, (void *)vma->vm_start, vma_size);
|
||||||
|
}
|
||||||
|
vma = vma->vm_next;
|
||||||
}
|
}
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
@ -958,64 +967,43 @@ uint64_t process_exit_mm(struct process_control_block *pcb)
|
|||||||
kdebug("pcb->mm->pgd==NULL");
|
kdebug("pcb->mm->pgd==NULL");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// 获取顶层页表
|
|
||||||
|
// // 获取顶层页表
|
||||||
pml4t_t *current_pgd = (pml4t_t *)phys_2_virt(pcb->mm->pgd);
|
pml4t_t *current_pgd = (pml4t_t *)phys_2_virt(pcb->mm->pgd);
|
||||||
|
|
||||||
// 迭代地释放用户空间
|
// 循环释放VMA中的内存
|
||||||
for (int i = 0; i <= 255; ++i)
|
struct vm_area_struct *vma = pcb->mm->vmas;
|
||||||
|
while (vma != NULL)
|
||||||
{
|
{
|
||||||
// 当前页表项为空
|
struct vm_area_struct *cur_vma = vma;
|
||||||
if ((current_pgd + i)->pml4t == 0)
|
vma = cur_vma->vm_next;
|
||||||
continue;
|
|
||||||
|
|
||||||
// 二级页表entry
|
uint64_t pa;
|
||||||
pdpt_t *current_pdpt = (pdpt_t *)phys_2_virt((current_pgd + i)->pml4t & (~0xfffUL));
|
mm_umap_vma(pcb->mm, cur_vma, &pa);
|
||||||
// 遍历二级页表
|
uint64_t size = (cur_vma->vm_end - cur_vma->vm_start);
|
||||||
for (int j = 0; j < 512; ++j)
|
|
||||||
|
// 释放内存
|
||||||
|
switch (size)
|
||||||
{
|
{
|
||||||
if ((current_pdpt + j)->pdpt == 0)
|
case PAGE_2M_SIZE:
|
||||||
continue;
|
free_pages(Phy_to_2M_Page(pa), 1);
|
||||||
|
break;
|
||||||
|
case PAGE_4K_SIZE:
|
||||||
|
kfree(phys_2_virt(pa));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
vm_area_del(cur_vma);
|
||||||
|
kfree(cur_vma);
|
||||||
|
}
|
||||||
|
|
||||||
// 三级页表的entry
|
|
||||||
pdt_t *current_pdt = (pdt_t *)phys_2_virt((current_pdpt + j)->pdpt & (~0xfffUL));
|
|
||||||
|
|
||||||
// 释放三级页表的内存页
|
|
||||||
for (int k = 0; k < 512; ++k)
|
|
||||||
{
|
|
||||||
if ((current_pdt + k)->pdt == 0)
|
|
||||||
continue;
|
|
||||||
// 存在4级页表
|
|
||||||
if (unlikely(((current_pdt + k)->pdt & (1 << 7)) == 0))
|
|
||||||
{
|
|
||||||
// 存在4K页
|
|
||||||
uint64_t *pt_ptr = (uint64_t *)phys_2_virt((current_pdt + k)->pdt & (~0x1fffUL));
|
|
||||||
uint64_t *pte_ptr = pt_ptr;
|
|
||||||
|
|
||||||
// 循环处理4K页表, 直接清空
|
|
||||||
// todo: 当支持使用slab分配4K内存作为进程的4K页之后,在这里需要释放这些4K对象
|
|
||||||
for (int16_t g = 0; g < 512; ++g, ++pte_ptr)
|
|
||||||
*pte_ptr = 0;
|
|
||||||
|
|
||||||
// 4级页表已经空了,释放页表
|
|
||||||
if (unlikely(mm_check_page_table(pt_ptr)) == 0)
|
|
||||||
kfree(pt_ptr);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// 释放内存页
|
|
||||||
if (mm_is_2M_page((current_pdt + k)->pdt & (~0x1fffUL))) // 校验是否为内存中的物理页
|
|
||||||
free_pages(Phy_to_2M_Page((current_pdt + k)->pdt & (~0x1fffUL)), 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 释放三级页表
|
|
||||||
kfree(current_pdt);
|
|
||||||
}
|
|
||||||
// 释放二级页表
|
|
||||||
kfree(current_pdpt);
|
|
||||||
}
|
|
||||||
// 释放顶层页表
|
// 释放顶层页表
|
||||||
kfree(current_pgd);
|
kfree(current_pgd);
|
||||||
|
if (unlikely(pcb->mm->vmas != NULL))
|
||||||
|
{
|
||||||
|
kwarn("pcb.mm.vmas!=NULL");
|
||||||
|
}
|
||||||
// 释放内存空间分布结构体
|
// 释放内存空间分布结构体
|
||||||
kfree(pcb->mm);
|
kfree(pcb->mm);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user