LINUX.ORG.RU

Сделать remap_pfn_range без mmap?


0

1

Доброго времени суток!

Подскажите пожалуйста, можно ли сделать следующее: Есть некоторое устройство и к нему драйвер (модуль ядра). В модуле имеется диспетчер памяти устройства (выделить окно, освободить, дать ID и т.п.).

Необходимо сделать следующее - отобразить такое окно в UserSpace. Можно и спользовать mmap, но тут есть следующее НО: программа в UserSpace должна знать адрес начала региона физической памяти, и теоритически может получить доступ к любой области памяти устройства.

Хотелось бы, чтобы обращение к региону физической памяти проходило по его идентификатору (имени). Другими словами в UserSpace должны происходить, например, следующие вызовы: 1. ObjId = AllocateObj(Size); 2. MapObj(ObjId, Addr); (или Addr = MapObj(ObjId);) 3. memcpy(Addr,...);

По идее должна подойти функция remap_pfn_range, но у меня следующая проблема - как в этом случае правильно определить структуру vm_area_struct.

Возможно ли это, или настолько неудобно, что проще забить и использовать все-таки mmap?

Спасибо!

> программа в UserSpace должна знать адрес начала региона физической памяти, и теоритически может получить доступ к любой области памяти устройства.

То ли мутно сформулировано, то ли просто неверно.

ObjId = AllocateObj(Size);

CamelCaseAteYourBrain

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

Попробую яснее объяснить. Устройство имеет некоторый блок памяти. Предположим, по запросу из UserSpace драйвер считает участок памяти от 0x100 до 0x200 зарезервированным для приложения из userSpace.

Чтобы получить доступ к этому участку, в UserSpace делается вызов mmap(0x100, 0x100) и вроде все хорошо.

А если приложение сделает вызов mmap(0x200, 0x100) то оно все равно получит отображение, если такая ситуация не отслеживается в драйвере.

Я хочу вместо проверки допустимости отображения в драйвере (придется искать соответствующее отображение и проверять его на принадлежность к процессу) лишить приложение из UserSpace возможности сделать некоректный (с точки зрения логики работы) вызов.

Один из путей - UserSpace во write или ioctl передает идентификатор области памяти на устройстве и адрес в своем адресном пространстве, по которому она хотела бы его увидеть (или этот адрес определится драйвером). Соответственно идентификатор при этом был выделен драйвером при «резервировании» участка памяти и передан процессу ранее.

Другой вариант - создавать по спец.файлу на каждый выделенный участок памяти, но не будет ли здесь большого оверхеда?

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

> драйвер считает участок памяти от 0x100 до 0x200 зарезервированным для приложения из userSpace.

Чтобы получить доступ к этому участку, в UserSpace делается вызов mmap(0x100, 0x100) и вроде все хорошо.

На этом можно остановиться. mmap работает со страницами, а тебе нужно что-то меньшее.

проверки допустимости отображения в драйвере (придется искать соответствующее отображение и проверять его на принадлежность к процессу)

?

Другой вариант - создавать по спец.файлу на каждый выделенный участок памяти, но не будет ли здесь большого оверхеда?

Не будет. Но, поскольку у тебя память не выровнена по страницам, the point is moot.

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

Не совсем так, память на устройстве выровнена по страницам, и все операции выделения кратны странице. То есть отображать мне надо страницы.

Примерное количество объектов, одновременно существующих я могу оценить в 1-2 сотни, но размеры у них могуть быть абсолютно разные, от страницы до десятков мегабайт.

Может в этом случае не давать прямой доступ к этим объектам, а все сделать через read/write? Сильная разница в производительности? Как правило операции будут блочные, в том смысле, что что запись не по одному байту, а, как правило весь, блок будет заполняться одним действием. Через ioctl можно будет выбирать активный объект для чтения/записи.

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

> все операции выделения кратны странице. То есть отображать мне надо страницы.

Тогда я бы сделал на нескольких спецфайлах.

Может в этом случае не давать прямой доступ к этим объектам, а все сделать через read/write?

Трудно сказать. Зависит от многих вещей - от природы устройства до предпочтений драйверописателя.

Сильная разница в производительности?

На больших объемах - никакой, на малых - зависит. Правда, в случае использования read/write ты сможешь задействовать DMA (если он у тебя есть) - там ускорение на порядок вполне реально.

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

Устройство - видеоадаптер (Radeon), DMA там вроде имеется. Тогда наверно буду делать на read/write, а спецфайлы или ioctl для выбора объектов - буду думать и сравнивать.

Спасибо за ответы!

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

> Устройство - видеоадаптер (Radeon), DMA там вроде имеется.

Кхм... вообще-то для видеоадаптеров существуют специализированные драйверные интерфейсы, и mmap там используется «в обратную сторону» - мапится пользовательская память, которая потом через DMA отправляется на устройство.

а спецфайлы или ioctl для выбора объектов - буду думать и сравнивать.

Если набор объектов определен заранее, то лучше спецфайлы с операцией чтения (очень удобно иметь возможность обычным od просмотреть состояние регистров); mmap опционален.

tailgunner ★★★★★
()

Вот готовый пример того что вам нужно:
http://rghost.ru/7632381

лицензия там херовая но анонимус дает добро ;-)
Там из важных параметров
#define HLINA_START_ADDRESS 0x74000000
в memalloc.c - это начальный адрес _физической_ памяти, границы не проверяются - индексирует столько сколько ему нужно, даже несуществующую память. Модуль для gstreamer - для примера как запрашивать память из юзерспейс.

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

Про DMA - дельное замечание, оно там действительно на адаптере. Вроде как есть еще bus-mastering, это я поизучаю, сейчас главное чтобы просто работало, но задел оставлю.

Набор объектов заранее не определен, плюс возникают вопросы с размещением и именованием этих файлов (так, чтобы для разных процессов они не пересекались) и т.п.

Наверно, лучше всего в моем случае применить ioctl, которому я буду передавать указатель на описание объекта в UserSpace (а в описание можно вложить идентификатор, адресс для обмена данными, кол-во байт и т.п.).

read/write мне не нравятся с той точки зрения, что необходимо определять и передавать физические адреса на устройстве в UserSpace, а в обработчике проверять корректность их определения.

Просто переключать с помощью ioctl «активный» объект в памяти я не хочу - нет гарантии, что кто-то не вклинится между ioctl и read/write, и плюс желание минимума блокировок.

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

> read/write мне не нравятся с той точки зрения, что необходимо определять и передавать физические адреса на устройстве в UserSpace, а в обработчике проверять корректность их определения.

Один из нас чего-то серьезно не понимает.

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

Под физическим адресом я имею в виду смещение начала блоков памяти на устройстве, соответствующее конкретному объекту.

Допустим, у меня есть символьное устройство. В клиентском приложении я его открыл, потом хочу записать в объект с идентификатором ID=12 4кб данных. Я могу использовать pwrite, но откуда приложение пользователя узнает необходимое значение параметра offset, соответствующее объекту №12? А с точки зрения модуля ядра нет уверенности, что пользовательское приложение пишет по нужному смещению и нужное количество байт, то есть необходимо определить, какому объекту принадлежит это смещение, и может ли это приложение туда писать. Если проверку не делать, то одно приложение с ошибкой (особенно если это сделано специально) способно испортить данные всем остальным приложениям.

Проблема решается созданием отдельного файла в /proc для каждого выделенного объекта, но тогда придется решать вопрос о именовании этих файлов, поиске их (тем более что некоторые объекты могут быть общими для нескольких приложений) и держать кучу открытых дескрипторов (одно приложение может иметь несколько десятков объектов).

Для обеспечения доступа к устройству это конечно не принципиально, но хотелось бы изолировать приложения друг от друга.

В моем случае один вызов ioctl позволит передать в модуль код операции, ID объекта, кол-во данных и адрес буфера в юзерспейсе и тп (свернутые в структуру, адрес которой подсунут ioctl). Насколько данный подход будет оправдан?

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

>Если проверку не делать, то одно приложение с ошибкой (особенно если это сделано специально) способно испортить данные всем остальным приложениям.

Утопичненько - любое приложение может через /dev/mem смапить себе любые физические адреса и никакой модуль какой-то амдышной карточки этому не помешает.

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

Да, можно и через /dev/mem смапить, если есть на него права (а их как правило нет у обычного пользователя). А на создаваемое символьное устройство - будут, поэтому смысл есть. Иначе проще выкинуть всю безопасность со словами «все равно можно залезть».

Тем более, что в случае ошибки в пользовательской программы она будет не /dev/mem юзать, а вполне конкретный файл.

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

> Под физическим адресом я имею в виду смещение начала блоков памяти на устройстве, соответствующее конкретному объекту.

Значит, ты используешь какие-то свои термины.

Проблема решается созданием отдельного файла

Ну так создавай.

в /proc

Песец.

В моем случае один вызов ioctl позволит передать в модуль код операции, ID объекта, кол-во данных и адрес буфера в юзерспейсе и тп (свернутые в структуру, адрес которой подсунут ioctl).

Я могу сказать только, что это очень корявый подход. Есть ли другой выход, я просто не знаю - документацию по Radeon не читал.

Насколько данный подход будет оправдан?

Повторяю - для видеодрайверов есть свои, специализированные API. А ты изобретаешь велосипед, явно не обладая ни опытом, ни пониманием. Зачем?

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

> Я могу сказать только, что это очень корявый подход. Есть ли другой выход, я просто не знаю - документацию по Radeon не читал.

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

в /proc

Песец.

например по такому пути /proc/card/0/<PID>/<ID-объекта> Вопрос лишь в том, не будет ли это еще корявей, чем использование ioctl?

Повторяю - для видеодрайверов есть свои, специализированные API. А ты изобретаешь велосипед, явно не обладая ни опытом, ни пониманием. Зачем?

Для обретения опыта и понимания. Например зачем столько отдельных модулей и кода для того, чтобы положить несколько блоков данных в видеокарту и взять их оттуда. То что я увидел в исходниках drm-модуля Radeon - ужасает, обертка над оберткой. Ведь должно быть намного проще, простой пример выше: mmap /dev/mem и все данные на устройстве.

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

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

Да все это не нужно - посмотри как в UIO переопределена mmap
drivers/uio/uio.c

тебе достаточно пометить блок памяти как уже используемый в своем аллокаторе и смапить его повторно уже никто не сможет. На кой хрен знать ID процесса смапившего его ?

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