我参考以下两个链接在我的 linux 驱动程序中使用大页面:
在内核驱动程序http://nuncaalaprimera.com/2014/using-hugepage-backed-buffers-in-linux-kernel-driver中顺序访问大页面
下面是我的代码:
#define PAGE_SHIFT_2M 21
pages = vmalloc(nr_pages * sizeof(struct page*));
down_read(¤t->mm->mmap_sem);
get_nr_pages = get_user_pages(current, current->mm, buffer_start, nr_pages,
1 /* Write enable */, 0 /* Force */, pages, NULL);
up_read(¤t->mm->mmap_sem);
nid = page_to_nid(pages[0]); // Remap on the same NUMA node.
remapped_addr = vm_map_ram(pages, nr_pages, nid, PAGE_KERNEL);
printf("page pfn [0]=%lX, [1]=0x%lX, [2]=0x%lX\n",
page_to_pfn(pages[0]),
page_to_pfn(pages[1]),
page_to_pfn(pages[2]));
printf("page physical [0]=%lX, [1]=0x%lX, [2]=0x%lX\n",
page_to_pfn(pages[0])<<PAGE_SHIFT_2M,
page_to_pfn(pages[1])<<PAGE_SHIFT_2M,
page_to_pfn(pages[2])<<PAGE_SHIFT_2M);
printf("page logical addr [0]=%p, [1]=%p, [2]=%p\n",
__va(page_to_pfn(pages[0])<<PAGE_SHIFT_2M),
__va(page_to_pfn(pages[1])<<PAGE_SHIFT_2M),
__va(page_to_pfn(pages[2])<<PAGE_SHIFT_2M));
printf("page_address [0]=%p, [1]=%p, [2]=%p\n",
page_address(pages[0]),
page_address(pages[1]),
page_address(pages[2]));
日志打印:
页 pfn [0]=154A00, [1]=0x154A01, [2]=0x154A02
页物理 [0]=2A940000000, [1]=0x2A940200000, [2]=0x2A940400000
页逻辑地址 [0]=ffff8aa940000000, [1] =ffff8aa940200000, [2]=ffff8aa940400000
page_address [0]=ffff880154a00000, [1]=ffff880154a01000, [2]=ffff880154a02000
我有几个问题:
1)我想知道 vm_map_ram() 是否可以处理大页面。从内核源代码中,我可以看到 vm_map_ram() 使用 PAGE_SIZE 和 PAGE_SHIFT,它的值应该是默认的 4KB 页面大小。就我而言,在写入从 vm_map_ram() 返回的虚拟地址后,我遇到了“BUG:无法在 XXXX 处处理内核分页请求”问题。
2) 两个页面的 page_address 返回值为 0x1000(4KB) 间隙,而不是 2MB 间隙。这是为什么?
3) 我是否正确使用了 "__va(page_to_pfn(pages[0])<
提前致谢!