2008-12-14 34 views
18

En mi programa C++ (en Windows), estoy asignando un bloque de memoria y puedo asegurarme de que permanezca bloqueado (sin enrutar y contiguo) en la memoria física (es decir, utilizando VirtualAllocEx(), MapUserPhysicalPages(), etc.).¿Cómo traducir una dirección de memoria virtual a una dirección física?

En el contexto de mi proceso, puede obtener la dirección de memoria virtual de ese bloque, pero necesito averiguar la dirección de memoria física de la misma el fin de pasar a algún dispositivo externo.


1. ¿Hay alguna manera de que pueda traducir la dirección virtual a la física dentro de mi programa, en modo de usuario?

2. Si no, puedo encontrar esta asignación virtual a física solo en el modo KERNEL. Supongo que significa que tengo que escribir un controlador para hacerlo ... ¿Conoce algún controlador/DLL/API disponible que pueda usar, con el que mi aplicación (programa) interactuará para hacer la traducción?

3. En caso de que tenga que escribir el controlador yo mismo, ¿cómo hago esta traducción? ¿Qué funciones uso? ¿Es mmGetPhysicalAddress()? ¿Como lo uso?

4. Además, si entiendo correctamente, mmGetPhysicalAddress() devuelve la dirección física de una dirección base virtual que está en el contexto del proceso de llamada. Pero si el proceso de llamada es el controlador y estoy usando mi aplicación para llamar al controlador para esa función, estoy cambiando los contextos y ya no estoy en el contexto de la aplicación cuando se llama a la rutina mmGetPhysicalAddress ... entonces ¿Cómo traduzco la dirección virtual en el espacio de memoria de la aplicación (modo de usuario), no el controlador?

¡Cualquier respuesta, sugerencia y fragmento de código será muy apreciado!

Gracias

+0

Tengo curiosidad, ¿qué podía hacer un dispositivo externo con una dirección de memoria física? – jyoung

+0

Sin entrar en detalles, es un dispositivo incorporado que tiene acceso directo a la RAM de la máquina, pero no tiene conocimiento de las asignaciones de OS (razón por la cual una dirección virtual o el uso de un objeto de memoria compartida no funcionará). –

Respuesta

4

1) No se

2) Sí, usted tiene que escribir un controlador. Lo mejor sería un controlador virtual o cambiar el controlador del dispositivo externo especial.

3) Esto se vuelve muy confuso aquí. MmGetPhysicalAddress debe ser el método para el que está bloqueando, pero realmente no sé cómo se mapea la dirección física en el banco/chip/etc. en la memoria física.

4) No puede usar la memoria paginada, porque eso se reubica. Puede bloquear la memoria paginada con MmProbeAndLockPages en un MDL que puede compilar en la memoria transferida desde el contexto de llamada en modo de usuario. Pero es mejor asignar memoria no paginada y entregarla a su aplicación de modo de usuario.

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

// use realAddr 
12

En mi programa en C++ (en Windows), estoy asignar un bloque de memoria y puede asegurarse de que permanece bloqueado (a canje y contigua) en la memoria física (es decir, utilizando VirtualAllocEx(), MapUserPhysicalPages() etc.)

No, realmente no puede asegurarse de que permanezca bloqueado. ¿Qué pasa si su proceso se bloquea o sale antes de tiempo? ¿Qué pasa si el usuario lo mata? Esa memoria se reutilizará para otra cosa, y si su dispositivo todavía está haciendo DMA, eso eventualmente dará como resultado la pérdida/corrupción de datos o una comprobación de errores (BSOD).

Además, MapUserPhysicalPages es parte de Windows AWE (Address Windowing Extensions), que es para manejar más de 4 GB de RAM en versiones de 32 bits de Windows Server. No creo que estuviera destinado a ser usado para hackear DMA en modo usuario.

1. ¿Hay alguna manera de que pueda traducir la dirección virtual a la física dentro de mi programa, en modo USUARIO?

hay conductores que le permiten hacer esto, pero no se puede programar DMA de modo de usuario en Windows y aún así tener un sistema estable y seguro. Dejar que un proceso que se ejecuta como una cuenta de usuario limitada leer/escribir en la memoria física permite que ese proceso sea el propietario del sistema. Si se trata de un sistema único o un prototipo, probablemente sea aceptable, pero si espera que otras personas (especialmente los clientes que pagan) usen su software y su dispositivo, debe escribir un controlador.

2. Si no es así, no puedo encontrar a cabo este virtual de modo que la cartografía física única en el kernel. Supongo que significa que tengo que escribir un controlador para hacerlo ...

Esa es la forma recomendada para abordar este problema.

¿Conoce algún controlador/DLL/API disponible que pueda usar, con el que se conectará mi aplicación (programa) para hacer la traducción?

Puede usar un MDL (Memory Descriptor List) para bloquear la memoria arbitraria, incluidos los almacenamientos intermedios de memoria que pertenecen a un proceso en modo de usuario, y traducir sus direcciones virtuales en direcciones físicas. También puede hacer que Windows cree temporalmente una MDL para el búfer pasado a una llamada al DeviceIoControl utilizando METHOD_IN_DIRECT o METHOD_OUT_DIRECT.

Tenga en cuenta que las páginas contiguas en el espacio de direcciones virtuales casi nunca son contiguas en el espacio de direcciones físicas. Es de esperar que su dispositivo esté diseñado para manejar eso.

3. En caso de que voy a tener que escribir el conductor a mí mismo, ¿cómo lo hago esta traducción? ¿Qué funciones uso? ¿Es mmGetPhysicalAddress()? ¿Como lo uso?

Hay mucho más para escribir un controlador que simplemente llamando a unos API. Si va a escribir un controlador, le recomendaría leer todo el material relevante que pueda de MSDN y OSR. Además, mira los ejemplos en el Windows Driver Kit.

4. Además, si entiendo correctamente, mmGetPhysicalAddress() devuelve la dirección física de una dirección base virtual que está en el contexto del proceso de llamada. Pero si el proceso de llamada es el controlador, y estoy usando mi aplicación para llamar al controlador para esa función, estoy cambiando los contextos y ya no estoy en el contexto de la aplicación cuando se llama a la rutina mmGetPhysicalAddress ... entonces ¿Cómo traduzco la dirección virtual en el espacio de memoria de la aplicación (modo de usuario), no el controlador?

Los conductores no son procesos. Un controlador se puede ejecutar en el contexto de cualquier proceso, así como en varios contextos elevados (controladores de interrupción y DPC).

4

Usted realmente no debería estar haciendo cosas como esta en modo de usuario; como dice Christopher, debe bloquear las páginas para que mm no decida sacar la memoria de respaldo mientras el dispositivo está usándola, lo que terminaría corrompiendo páginas de memoria aleatorias.

Pero si el proceso de llamada es el conductor, y estoy usando mi solicitud a llamar al conductor para esa función, estoy cambiando los contextos y ya no estoy en el contexto de la aplicación cuando la rutina mmGetPhysicalAddress se llama

Los controladores no tienen contexto como lo hacen las aplicaciones en modo usuario; si está llamando a un controlador a través de un IOCTL o algo así, por lo general (¡pero no se garantiza!) para estar en el contexto del subproceso de usuario llamante. Pero realmente, esto no tiene importancia para lo que estás preguntando, porque la memoria en modo kernel (cualquier cosa por encima de 0x80000000) es la misma asignación, sin importar dónde estés, y terminarías asignando memoria en el lado del kernel. Pero nuevamente, escribe un controlador apropiado. Use WDF (http://www.microsoft.com/whdc/driver/wdf/default.mspx), y hará que escribir un controlador correcto sea mucho más fácil (aunque sigue siendo bastante complicado, la escritura del controlador de Windows no es fácil)

EDIT: Pensé en tirar algunas referencias de libros para ayudarte , definitivamente debe (incluso si no persigue escribir el controlador) leer Windows Internals por Russinovich y Solomon (http://www.amazon.com/Microsoft-Windows-Internals-4th-Server/dp/0735619174/ref=pd_bbs_sr_2?ie=UTF8&s=books&qid=1229284688&sr=8-2); La programación del modelo de controlador de Microsoft Windows también es buena (http://www.amazon.com/Programming-Microsoft-Windows-Driver-Second/dp/0735618038/ref=sr_1_1?ie=UTF8&s=books&qid=1229284726&sr=1-1)

-2

Espere, hay más. Por el privilegio de ejecutar en Vista 64 bit de su cliente, obtiene gastar más tiempo y dinero para obtener su controlador de modo kernal renunció a mi Microsoft,

4

Tiene un búfer virtualmente extinto en su aplicación. Ese rango de memoria virtual es, como ha notado, solo disponible en el contexto de su aplicación y parte de ella puede ser paginada en cualquier momento. Entonces, para poder acceder a la memoria desde un dispositivo (es decir, hacer DMA), necesita bloquearlo y obtener una descripción que se pueda pasar a un dispositivo.

Puede obtener una descripción del búfer llamada MDL, o Lista de descriptores de memoria, enviando un IOCTL (mediante la función DeviceControl) a su controlador utilizando METHOD_IN_DIRECT o METHOD_OUT_DIRECT. Vea la siguiente página para una discusión sobre la definición de IOCTL.

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

Ahora que tiene una descripción de la memoria intermedia en un controlador para su dispositivo, puede bloquear hacia abajo para que el buffer permanece en la memoria durante todo el período que el dispositivo puede actuar sobre ella. Busque MmProbeAndLockPages en MSDN.

Su dispositivo puede o no puede leer o escribir toda la memoria en el búfer. El dispositivo solo admite DMA de 32 bits y la máquina puede tener más de 4 GB de RAM. O puede tratar con una máquina que tiene una IOMMU, una GART u otra tecnología de traducción de direcciones. Para acomodar esto, use las diversas API de DMA para obtener un conjunto de direcciones lógicas que sean útiles para su dispositivo. En muchos casos, estas direcciones lógicas serán equivalentes a las direcciones físicas sobre las que se preguntó originalmente su pregunta, pero no siempre.

Qué API de DMA utiliza depende de si su dispositivo puede manejar listas de dispersión/recopilación y demás. Su controlador, en su código de instalación, llamará a IoGetDmaAdapter y usará algunas de las funciones que devuelve.

Normalmente, usted estará interesado en GetScatterGatherList y PutScatterGatherList. Usted proporciona una función (ExecutionRoutine) que realmente programa su hardware para realizar la transferencia.

Hay muchos detalles involucrados. Buena suerte.

4

No puede acceder a las tablas de páginas desde el espacio de usuario, están mapeadas en el kernel.

Si se encuentra en el kernel, simplemente puede inspeccionar el valor de CR3 para localizar la dirección de la tabla de la página base y luego comenzar su resolución.

This blog series tiene una maravillosa explicación de cómo hacer esto. No necesita ningún recurso de sistema operativo/API para resolver < virtuales -> direcciones físicas.

virtual Dirección: f9a10054

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

Page Directory Pointer Index(PDPI)  11      Index into 

primera tabla (página Guía puntero Tabla) Página Directorio Índice (PDI)
111001 101 Índice en segundo mesa (Guía tabla) Página tabla de índice (PTI)
00001 0000 Índice en la tercera tabla (Tabla de páginas) Índice de bytes
0000 01010100 0x054, la compensación en la página de memoria física

En su ejemplo, usan windbg,! dq es una lectura de memoria física.

enter image description here

Cuestiones relacionadas