Skip to main content
 首页 » 编程设计

linux-kernel之如何从 Linux 内核中的任何地址获取结构页面

2024年11月24日18oomusou

我现有的代码需要一个列表 struct page *并建立一个描述符表与设备共享内存。该代码的上层当前期望分配有 vmalloc 的缓冲区。或来自用户空间,并使用 vmalloc_to_page 获取对应的struct page * .

现在上层需要处理各种内存,不仅仅是通过vmalloc获得的内存.这可能是使用 kmalloc 获得的缓冲区,内核线程堆栈内的指针,或我不知道的其他情况。我唯一的保证是这个上层的调用者必须确保有问题的内存缓冲区在那一点被映射到内核空间中(即在这一点上访问 buffer[i] 对所有 0<=i<size 都是有效的)。 我如何获得 struct page*对应于任意指针?

把它放在伪代码中,我有这个:

lower_layer(struct page*); 
upper_layer(void *buffer, size_t size) { 
    for (addr = buffer & PAGE_MASK; addr <= buffer + size; addr += PAGE_SIZE) { 
        struct page *pg = vmalloc_to_page(addr); 
        lower_layer(pg); 
    } 
} 

我现在需要改变 upper_layer处理任何有效的缓冲区(不改变 lower_layer )。

我找到了 virt_to_page , 其中 Linux Device Drivers表示对“逻辑地址,[不是]来自 vmalloc 的内存进行操作”或高内存”。此外, is_vmalloc_addr 测试地址是否来自 vmalloc , 和 virt_addr_valid 测试地址是否是有效的虚拟地址( virt_to_page 的素材;这包括 kmalloc(GFP_KERNEL) 和内核堆栈)。其他情况如何:全局缓冲区、高内存(总有一天会到来,但我现在可以忽略它),可能还有我不知道的其他类型?所以我可以将我的问题重新表述为:
  • 内核中有哪些类型的内存区域?
  • 我如何区分它们?
  • 如何获取每个页面的映射信息?

  • 如果重要,代码运行在 ARM(带有 MMU)上,内核版本至少为 2.6.26。

    请您参考如下方法:

    我想您想要的是页表遍历,例如(警告,不是实际代码,锁定丢失等):

    struct mm_struct *mm = current->mm; 
    pgd = pgd_offset(mm, address); 
    pmd = pmd_offset(pgd, address);   
    pte = *pte_offset_map(pmd, address);   
    page = pte_page(pte); 
    

    但是你应该非常非常小心。例如,您获得的 kmalloc 地址很可能不是页面对齐的。这对我来说听起来像是一个非常危险的 API。