Подтвердить что ты не робот

Как перевести адрес виртуальной памяти на физический адрес?

В моей программе на С++ (в Windows) я выделяю блок памяти и могу убедиться, что он остается заблокированным (несвязанным и непрерывным) в физической памяти (т.е. используя VirtualAllocEx(), MapUserPhysicalPages() и т.д.).

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


1. Есть ли способ перевести виртуальный адрес на физический в моей программе в режиме USER?

2. Если нет, я могу узнать это виртуальное физическое отображение только в режиме KERNEL. Думаю, это означает, что я должен написать драйвер, чтобы сделать это...? Знаете ли вы о каком-либо легко доступном драйвере /DLL/API, который я могу использовать, чтобы мое приложение (программа) взаимодействовало с тем, чтобы сделать перевод?

3. В случае, если мне придется самому написать драйвер, как мне сделать этот перевод? какие функции я использую? Это mmGetPhysicalAddress()? Как его использовать?

4. Кроме того, если я правильно понимаю, mmGetPhysicalAddress() возвращает физический адрес виртуального базового адреса, который находится в контексте вызывающего процесса. Но если вызывающий процесс является драйвером, и я использую свое приложение для вызова драйвера для этой функции, я меняю контексты, и я больше не в контексте приложения, когда вызывается процедура mmGetPhysicalAddress... поэтому как перевести виртуальный адрес в пространство приложения (пользовательский режим), а не драйвер?

Любые ответы, советы и выдержки из кода будут очень благодарны!

Спасибо

4b9b3361

Ответ 1

В моей программе на С++ (в Windows) я выделяю блок памяти и могу убедиться, что он остается заблокированным (несвязанным и непрерывным) в физической памяти (т.е. используя VirtualAllocEx(), MapUserPhysicalPages() и т.д.).

Нет, вы не можете гарантировать, что он останется заблокированным. Что делать, если ваш процесс выйдет из строя или выйдет раньше? Что делать, если пользователь убивает его? Эта память будет повторно использована для чего-то еще, и если ваше устройство все еще выполняет DMA, это в конечном итоге приведет к потере/повреждению данных или ошибке (BSOD).

Кроме того, MapUserPhysicalPages является частью Windows AWE (расширения окна адресов), который предназначен для обработки более 4 ГБ ОЗУ на 32-разрядных версиях Windows Server. Я не думаю, что оно предназначалось для взлома пользовательского режима DMA.

1. Есть ли способ перевести виртуальный адрес в физический в моей программе, в режиме USER?

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

2. Если нет, я могу найти это виртуальное физическое отображение только в режиме KERNEL. Я думаю, это означает, что я должен написать драйвер, чтобы сделать это...?

Это рекомендуемый способ решения этой проблемы.

Знаете ли вы о каком-либо легко доступном драйвере /DLL/API, который я могу использовать, с которым будет взаимодействовать мое приложение (программа) для перевода?

Вы можете использовать MDL (Список дескрипторов памяти) для блокировки произвольной памяти, включая буферы памяти, принадлежащие процессу пользовательского режима, и перевести свои виртуальные адреса в физические адреса. Вы также можете заставить Windows временно создать MDL для буфера, переданного в вызов DeviceIoControl, с помощью METHOD_IN_DIRECT или METHOD_OUT_DIRECT.

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

3. В случае, если мне придется самому написать драйвер, как мне сделать этот перевод? какие функции я использую? Это mmGetPhysicalAddress()? Как его использовать?

Там гораздо больше написания драйвера, чем просто вызов нескольких API. Если вы собираетесь написать драйвер, я бы порекомендовал читать как можно больше материалов из MSDN и OSR. Кроме того, посмотрите примеры в Windows Driver Kit.

4. Кроме того, если я правильно понимаю, mmGetPhysicalAddress() возвращает физический адрес виртуального базового адреса, который находится в контексте вызывающего процесса. Но если вызывающий процесс является драйвером, и я использую свое приложение для вызова драйвера для этой функции, я меняю контексты, и я больше не в контексте приложения, когда вызывается процедура mmGetPhysicalAddress... поэтому как перевести виртуальный адрес в пространство приложения (пользовательский режим), а не драйвер?

Драйверы не являются процессами. Драйвер может работать в контексте любого процесса, а также различные повышенные контексты (обработчики прерываний и DPC).

Ответ 2

1) Нет

2) Да, вам нужно написать драйвер. Лучшим будет либо виртуальный драйвер, либо изменить драйвер для специального внешнего устройства.

3) Это очень запутывает здесь. MmGetPhysicalAddress должен быть методом, за который вы блокируете, но я действительно не знаю, как физический адрес сопоставляется с банком/чипом/и т.д. в физической памяти.

4) Вы не можете использовать выгружаемую память, потому что это перемещается. Вы можете заблокировать выгружаемую память с помощью MmProbeAndLockPages на MDL, которую вы можете построить на памяти, переданной из контекста вызова режима пользователя. Но лучше распределять память без записи и передавать ее в ваше приложение в режиме пользователя.

PVOID p = ExAllocatePoolWithTag( NonPagedPool, POOL_TAG );
PHYSICAL_ADDRESS realAddr = MmGetPhysicalAddress( p );

// use realAddr

Ответ 3

Вы действительно не должны делать подобные вещи в usermode; как говорит Кристофер, вам нужно заблокировать страницы, чтобы mm не решал вывести вашу резервную память во время использования устройства, что в итоге повредило бы случайные страницы памяти.

Но если вызывающий процесс является драйвером, и я использую свое приложение для вызова драйвера для этой функции, я меняю контексты, и я больше не в контексте приложения, когда вызывается процедура mmGetPhysicalAddress

У драйверов нет такого контекста, как приложения в режиме пользователя; если вы звоните в драйвер через IOCTL или что-то такое, вы обычно (но не гарантированы!) должны быть в контексте пользовательского потока вызовов. Но на самом деле это не имеет значения для того, что вы просите, потому что память в режиме ядра (что-то выше 0x80000000) - это одно и то же отображение независимо от того, где вы находитесь, и вы в конечном итоге выделяете память на стороне ядра. Но опять же, напишите правильный драйвер. Используйте WDF (http://www.microsoft.com/whdc/driver/wdf/default.mspx), и это сделает запись правильного драйвера намного проще (хотя все еще довольно сложно, запись драйверов Windows непростая )

EDIT: Просто подумал, что я выброшу несколько ссылок на книги, чтобы помочь вам, вы должны определенно (даже если вы не будете продолжать писать драйвер) читайте "Внутренние документы Windows" Руссиновичем и Соломоном (http://www.amazon.com/Microsoft-Windows-Internals-4th-Server/dp/0735619174/ref=pd_bbs_sr_2?ie=UTF8&s=books&qid=1229284688& ср = 8-2); Программирование модели драйверов Microsoft Windows тоже хорошо (http://www.amazon.com/Programming-Microsoft-Windows-Driver-Second/dp/0735618038/исх = sr_1_1 т.е. = UTF-8 &? s = книги & QID = 1229284726 & ср = 1-1)

Ответ 4

В вашем приложении имеется виртуальный буфер. Этот диапазон виртуальной памяти, как вы отметили, доступен только в контексте вашего приложения, и некоторые из них могут быть выгружены в любое время. Таким образом, для доступа к памяти с устройства (то есть DMA) вам необходимо как заблокировать его, так и получить описание, которое может быть передано устройству.

Вы можете получить описание буфера, называемого MDL, или списка дескрипторов памяти, отправив IOCTL (через функцию DeviceControl) вашему драйверу, используя METHOD_IN_DIRECT или METHOD_OUT_DIRECT. См. Следующую страницу для обсуждения определения IOCTL.

http://msdn.microsoft.com/en-us/library/ms795909.aspx

Теперь, когда у вас есть описание буфера в драйвере для вашего устройства, вы можете заблокировать его, чтобы буфер оставался в памяти в течение всего периода, в течение которого ваше устройство может воздействовать на него. Посмотрите MmProbeAndLockPages на MSDN.

Возможно, ваше устройство может читать или записывать всю память в буфере. Устройство может поддерживать только 32-разрядную DMA, и устройство может иметь более 4 ГБ ОЗУ. Или вы можете иметь дело с машиной, в которой есть IOMMU, GART или другая технология преобразования адресов. Чтобы разместить это, используйте различные API DMA для получения набора логических адресов, которые подходят для использования вашим устройством. Во многих случаях эти логические адреса будут эквивалентны физическим адресам, о которых ваш вопрос задает вопрос, но не всегда.

Какой DMA API вы используете, зависит от того, может ли ваше устройство обрабатывать списки рассылки/сбора и т.д. Ваш драйвер в своем установочном коде вызовет IoGetDmaAdapter и воспользуется некоторыми функциями, возвращаемыми им.

Как правило, вас будет интересовать GetScatterGatherList и PutScatterGatherList. Вы предоставляете функцию (ExecutionRoutine), которая на самом деле программирует ваше оборудование для передачи.

Там много деталей. Удачи.

Ответ 5

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

Если вы находитесь в ядре, вы можете просто проверить значение CR3, чтобы найти адрес таблицы базовой страницы, а затем начать свое разрешение.

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

Виртуальный адрес: f9a10054

1: kd> .formats 0xf9a10054
Binary:  11111001 10100001 00000000 01010100

Page Directory Pointer Index(PDPI)       11                        Index into

1-я таблица (указатель каталога страницы Таблица) Индекс каталога страниц (PDI)
111001 101 Индекс на 2-й таблица (Таблица каталога страниц) Индекс таблицы (PTI)
00001 0000 Индекс на 3-й таблица (Таблица страниц) Байт-указатель
0000 01010100 0x054, смещение на страницу физической памяти

В его примере они используют windbg,! dq - это физическая память.

enter image description here

Ответ 6

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