c++ - sistemas - paginacion de memoria ejemplos
¿Cómo traducir una dirección de memoria virtual a una dirección física? (6)
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.).
En el contexto de mi proceso, puedo obtener la dirección de memoria VIRTUAL de ese bloque, pero necesito averiguar su dirección de memoria FÍSICA para pasarla a algún dispositivo externo.
1. ¿Hay alguna forma de que pueda traducir la dirección virtual a la física dentro de mi programa, en modo USUARIO?
2. De lo contrario, puedo encontrar este mapeo virtual a físico 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 se encuentra 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
1) No
2) Sí, tienes 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 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 del 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
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.).
No, realmente no puedes asegurarte 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 forma de que pueda traducir la dirección virtual a la física dentro de mi programa, en modo USUARIO?
Hay controladores que le permiten hacer esto, pero no puede programar DMA desde el 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. De lo contrario, puedo encontrar este mapeo virtual a físico solo en el modo KERNEL. Supongo que significa que tengo que escribir un controlador para hacerlo ...
Esa es la forma recomendada de abordar este problema.
¿Conoces algún controlador / DLL / API disponible que pueda usar, con el que mi aplicación (programa) interactuará para hacer la traducción?
Puede usar MDL (Lista de descriptores de memoria) 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 a 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 tenga que escribir el controlador yo mismo, ¿cómo hago esta traducción? ¿Qué funciones uso? ¿Es mmGetPhysicalAddress ()? ¿Como lo uso?
Hay mucho más para escribir un controlador que simplemente llamar a algunas 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 Kit de controladores de Windows .
4. Además, si entiendo correctamente, mmGetPhysicalAddress () devuelve la dirección física de una dirección base virtual que se encuentra 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 controladores 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).
Realmente no deberías estar haciendo cosas como esta en el 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 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
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, de nuevo, escriba un controlador adecuado . 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)
EDITAR: Solo pensé en tirar algunas referencias de libros para ayudarte, definitivamente (incluso si no sigues escribiendo el controlador) lee 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 )
Espera, hay más. Por el privilegio de ejecutar en Vista 64 bit de su cliente, usted obtiene gastar más tiempo y dinero para que su controlador de modo kernal renuncie a mi Microsoft,
Usted 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 (a través de 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 del búfer en un controlador para su dispositivo, puede bloquearlo para que el búfer permanezca en la memoria durante todo el período en que su dispositivo pueda actuar sobre él. Busque MmProbeAndLockPages en MSDN.
Su dispositivo puede o no ser capaz de 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.
La API de DMA que use dependerá 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.
Por lo general, te interesarán GetScatterGatherList y PutScatterGatherList. Usted proporciona una función (ExecutionRoutine) que realmente programa su hardware para realizar la transferencia.
Hay muchos detalles involucrados. Buena suerte.
No puede acceder a las tablas de páginas desde el espacio de usuario, están mapeadas en el kernel.
Si está 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.
Esta serie de blogs tiene una maravillosa explicación de cómo hacer esto. No necesita ninguna facilidad / API de sistema operativo para resolver direcciones físicas <-> virtuales.
Dirección virtual: f9a10054
1: kd> .formats 0xf9a10054 Binary: 11111001 10100001 00000000 01010100 Page Directory Pointer Index(PDPI) 11 Index into
1ra tabla (Tabla del puntero del directorio de la página) Índice del directorio de la página (PDI)
111001 101 Índice en la 2da tabla (Tabla de directorio de página) Índice de tabla de página (PTI)
00001 0000 Índice en la 3ª 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.