映射用户进程页表
int remap_pfn_range(struct vm_area_struct *vma, unsigned long addr,unsigned long pfn, unsigned long size, pgprot_t prot)
vma:进程的VMA
addr:用户空间的地址
pfn:指定页帧号
size:需要映射的大小
port:设置一些标志位
remap_pfn_range
int remap_pfn_range(struct vm_area_struct *vma, unsigned long addr,
unsigned long pfn, unsigned long size, pgprot_t prot){
struct mm_struct *mm = vma->vm_mm;
err = track_pfn_remap(vma, &prot, remap_pfn, addr, PAGE_ALIGN(size));
if (err)
return -EINVAL;
vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP;
pfn -= addr >> PAGE_SHIFT;
pgd = pgd_offset(mm, addr);
do {
next = pgd_addr_end(addr, end);
err = remap_p4d_range(mm, pgd, addr, next,
pfn + (addr >> PAGE_SHIFT), prot);
if (err)
break;
} while (pgd++, addr = next, addr != end);
}
比那里P4D页表
static inline int remap_p4d_range(struct mm_struct *mm, pgd_t *pgd,
unsigned long addr, unsigned long end,
unsigned long pfn, pgprot_t prot)
{
p4d_t *p4d;
unsigned long next;
int err;
pfn -= addr >> PAGE_SHIFT;
p4d = p4d_alloc(mm, pgd, addr);
if (!p4d)
return -ENOMEM;
do {
next = p4d_addr_end(addr, end);
err = remap_pud_range(mm, p4d, addr, next,
pfn + (addr >> PAGE_SHIFT), prot);
if (err)
return err;
} while (p4d++, addr = next, addr != end);
return 0;
}
遍历PUD页表:
static inline int remap_pud_range(struct mm_struct *mm, p4d_t *p4d,
unsigned long addr, unsigned long end,
unsigned long pfn, pgprot_t prot)
{
pud_t *pud;
unsigned long next;
int err;
pfn -= addr >> PAGE_SHIFT;
pud = pud_alloc(mm, p4d, addr);
if (!pud)
return -ENOMEM;
do {
next = pud_addr_end(addr, end);
err = remap_pmd_range(mm, pud, addr, next,
pfn + (addr >> PAGE_SHIFT), prot);
if (err)
return err;
} while (pud++, addr = next, addr != end);
return 0;
}
remap_p4d_range
p4d = p4d_alloc(mm, pgd, addr);
err = remap_pud_range(mm, p4d, addr, next,pfn + (addr >> PAGE_SHIFT), prot);
pud = pud_alloc(mm, p4d, addr);
err = remap_pmd_range(mm, pud, addr, next,pfn + (addr >> PAGE_SHIFT), prot);
pmd = pmd_alloc(mm, pud, addr);
err = remap_pte_range(mm, pmd, addr, next,pfn + (addr >> PAGE_SHIFT), prot);
pte = pte_alloc_map_lock(mm, pmd, addr, &ptl);
set_pte_at(mm, addr, pte, pte_mkspecial(pfn_pte(pfn, prot)));