LINUX.ORG.RU

Mmap буфера из пространства ядра в пространство пользователя


1

2

Добрый день/вечер. При написании символьного драйвера для Debian, столкнулся с задачей применения mmap из пространства ядра в пространство пользователя. Прочитал LDD3, но всё равно остался без чёткого понимания реализации этой задачи.

При инициализации модуля, создаётся файл устройства в /dev с помощью демона udev и read/write работающие с этим файлом работают хорошо, но вот только хочеться всё таки избежать лишних операций копирования, если драйвер будет запрашивать n'ое колличество программ(их может быть несколько сотен).

Сам драйвер работает получает данные по SPI. и записывает во внутренний буфер драйвера. именно этот буфер мне и нужно сделать общим(как я понимаю)


Ответ на: комментарий от tailgunner

вопросов несколько в голове, но честно говоря просто хотелось бы увидеть пример кода как в драйвера выглядит подобный ремап, и в пользовательской программе. Потому что сейчас я стою практически на месте и не знаю куда шагать

skjame
() автор топика
Ответ на: комментарий от skjame

просто хотелось бы увидеть пример кода как в драйвера выглядит подобный ремап

drivers/char/mspec.c выглядит неплохо.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Спасибо за исходник. А можешь подсказать что это за numa_node_id() в этой строке? maddr = uncached_alloc_page(numa_node_id(), 1);

skjame
() автор топика
static int mmap_op(struct file *fils, struct vm_area_struct *vma)
{
	int ret;
	ret = remap_pfn_range(
		vma,
		vma->vm_start,
		your_phys_addr >> PAGE_SHIFT,
		PAGE_SIZE*your_buffer_size_in_pages
		vma->vm_page_prot
	);
	if(ret < 0){
		printk("mmap failed\n");
		return -EIO;
	}

	return 0;
}
nanoolinux ★★★★
()
Ответ на: комментарий от tailgunner

static int mspec_mmap(struct file *file, struct vm_area_struct *vma, enum mspec_page_type type)

{ struct vma_data *vdata;

int pages, vdata_size, flags = 0;

if (vma->vm_pgoff != 0) return -EINVAL;

if ((vma->vm_flags & VM_SHARED) == 0) return -EINVAL;

if ((vma->vm_flags & VM_WRITE) == 0) return -EPERM;

pages = vma_pages(vma);

vdata_size = sizeof(struct vma_data) + pages * sizeof(long);

if (vdata_size <= PAGE_SIZE)

vdata = kzalloc(vdata_size, GFP_KERNEL);

else {

vdata = vzalloc(vdata_size); flags = VMD_VMALLOCED;

} if (!vdata) return -ENOMEM;

vdata->vm_start = vma->vm_start;

vdata->vm_end = vma->vm_end;

vdata->flags = flags;

vdata->type = type;

spin_lock_init(&vdata->lock);

atomic_set(&vdata->refcnt, 1);

vma->vm_private_data = vdata;

vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP;

if (vdata->type == MSPEC_FETCHOP || vdata->type == MSPEC_UNCACHED)

vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);

vma->vm_ops = &mspec_vm_ops;

return 0; }

Как я понял, если размер наших данных vdata_size меньше размера страницы, он выделяет память размером vdata_size в моём случае, размер буфера будет около 1кб мааааксимум. т.е. интересует меня именна эта ветка в данном условии, но т.к. у меня есть уже буфер, который kmalloc'ом выделяется при инициализации модуля, мне в этом условии нужно не выделять память, а просто vdata=УКАЗАТЕЛЬ_НА_МОЙ_БУФЕР. так?

skjame
() автор топика
Ответ на: комментарий от skjame

вот только тут vdata это структура struct vma_data { atomic_t refcnt; /* Number of vmas sharing the data. */

spinlock_t lock; /* Serialize access to this structure. */

int count; /* Number of pages allocated. */

enum mspec_page_type type; /* Type of pages allocated. */ int flags; /* See VMD_xxx below. */

unsigned long vm_start; /* Original (unsplit) base. */

unsigned long vm_end; /* Original (unsplit) end. */

unsigned long maddr[0]; /* Array of MSPEC addresses. */

};

и вместо массива maddr должен быть мой указатель?

skjame
() автор топика
Ответ на: комментарий от tailgunner

Василий, может для простоты общения свяжемся в skype? хотя бы в текстовом режиме. мне кажеться это значительно ускорит решение моей проблемы

skjame
() автор топика
Ответ на: комментарий от skjame

размер буфера будет около 1кб мааааксимум

Поверь, тебе не нужен mmap.

так?

Я не помню всех деталей, но просто из кода очевидно, что vdata - это не ТВОЙ_БУФЕР, а служебная структура.

Skype у меня нет, jabber - мойник@jabber.ru, но в моем часовом поясе уже глубокая ночь, так что быстрее не получится.

tailgunner ★★★★★
()
Последнее исправление: tailgunner (всего исправлений: 1)
Ответ на: комментарий от tailgunner

как выяснилось про 1кб я ошибся, и размер до нескольких мегабайт может доходить,так что всё таки придёться с mmap решать.

А на счёт структуры unsigned long maddr[0]; /* Array of MSPEC addresses. */ это как я понимаю адреса страниц которые мы мэпим. значит фактически мой буйфер, при разбитии на страницы являеться этим массивом?

skjame
() автор топика
Ответ на: комментарий от tailgunner

remap_pfn_range не рекомендуется к использованию.

Could you explain? More verbose information.

Dennis7
()

Смотри как в v4l2 делается mmap а пользовательский буфер.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от nanoolinux

kmalloc возвращает логический адрес и если использовать макрос virt_to_page, всё равно компилятор ругается на virt_to_page(rBuf)>>PAGE_SHIFT

skjame
() автор топика

drivers/char/mem.c::mem_fops

ttnl ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.