Mmap: отображение в пользовательском пространстве буфера ядра, выделенного с помощью kmalloc
Каков правильный способ сопоставления в пространстве пользовательского пространства буфера, выделенного с помощью kmalloc? Возможно, я еще не понял карты памяти... Я пишу модуль ядра, который выделяет этот буфер (например, 120 байт), и я буду читать и писать его в процессе пользовательского пространства. Очевидно, я создал устройство char и реализовал метод mmap
в структуре file_operations
. Мой метод:
static int my_mmap(struct file *filp, struct vm_area_struct *vma)
{
//printk(KERN_INFO "Allocated virtual memory length = %d", vma->vm_end - vma->vm_start);
long unsigned int size = vma->vm_end - vma->vm_start;
if (remap_pfn_range(vma, vma->vm_start,
__pa(mem_area) >> PAGE_SHIFT, //what about vma->vm_pgoff?
size,
vma->vm_page_prot) < 0)
return -EAGAIN;
vma->vm_flags |= VM_LOCKED;
vma->vm_ops = &vmops;
vma->vm_flags |= VM_RESERVED;
my_vm_open(vma);
return 0;
}
где mem_area
указывает на область памяти, выделенную kmalloc
в модуле init. Область заполнена тем же значением (например, 0x10). Все работает, но я думаю, что в этом коде есть что-то не так:
-
kmalloc
может возвращать указатель, который не выравнивается по странице, и в этом случае я не считаю правильным значение третьего параметра remap_pfn_range
на самом деле в пользовательском пространстве, я читаю Неверное значение. Вместо этого все работает, если я использую __get_free_page
(потому что функция всегда возвращает указатель, выравниваемый по страницам) или когда kmalloc
возвращает указатель с выравниванием по странице. Картирование памяти работает с областями памяти, которые являются мультиплексированными PAGE_SIZE
, поэтому, если я должен выделить целую страницу вместо использования kmalloc
?
-
Когда вызывается my_mmap
, ядро еще выделило некоторые страницы? Я спрашиваю об этом, потому что я нашел некоторые реализации пользовательского метода mmap
, который вызывает remap_pfn_range
с vma->vm_pgoff
как третий параметр... как это может быть полезно? Является ли это страничным фреймом первой новой выделенной страницы? Если я передаю в качестве третьего параметра кадр страницы, как я делаю в my_mmap
, я должен освобождать страницы, начиная со страницы в vma->vm_pgoff
?
-
Однако я нашел реализацию метода mmap
, который отображает буфер, выделенный с помощью kmalloc
. Чтобы правильно отобразить буфер, перед remap_pfn_range
выполняется операция (которую я не ожидаю). Предположим, что mem
- это указатель, возвращаемый kmalloc
, mem_area
инициализируется следующим образом:
mem_area=(int *)(((unsigned long)mem + PAGE_SIZE - 1) & PAGE_MASK);
Итак, mem_area
содержит одно и то же значение mem
, только если mem
выравнивается по страницам, иначе указатель должен содержать указатель в начале следующей страницы. Однако с этой операцией, если я передаю третий параметр remap_pfn_range
, отображение значения __pa(mem_area) >> PAGE_SHIFT
работает хорошо. Почему?
Спасибо всем!
Ответы
Ответ 1
-
Да, вы должны выделять целые числа страниц.
-
Нет, ядро не выделило ни одной страницы. vm->vm_pgoff
- это запрошенное смещение в отображаемом устройстве - это последний параметр для вызова пользовательского пространства mmap()
, переведенный с байтов на страницы. Вероятно, вы смотрите на реализации mem
или kmem
mmap, и в этом случае смещение представляет физическую или линейную страницу, которую хочет отобразить пользовательское пространство.
-
Это просто распределение буфера с выравниванием по страницам в выделенном буфере kmalloc()
. Вам лучше использовать __get_free_pages()
, как вы уже догадались, вырезая среднего человека.
Вы должны проверить, что отображаемый размер не превышает ваш буфер.