versiones update sistema operativo estructura descargar como linux-kernel virtual-memory

linux kernel - update - Cómo obtener una página de estructura desde cualquier dirección en el kernel de Linux



linux y sus versiones (5)

Para arquitecturas de 64 bits, la respuesta de gby debe adaptarse a:

pgd_t * pgd; pmd_t * pmd; pte_t * pte; struct page *page = NULL; pud_t * pud; void * kernel_address; pgd = pgd_offset(mm, address); pud = pud_offset(pgd, address); pmd = pmd_offset(pud, address); pte = pte_offset_map(pmd, address); page = pte_page(*pte); // mapping in kernel memory: kernel_address = kmap(page); // work with kernel_address.... kunmap(page);

Tengo un código existente que toma una lista de la struct page * de struct page * y crea una tabla de descriptores para compartir memoria con un dispositivo. La capa superior de ese código actualmente espera un búfer asignado con vmalloc o desde el espacio de usuario, y usa vmalloc_to_page para obtener la struct page * correspondiente struct page * .

Ahora, la capa superior necesita hacer frente a todo tipo de memoria, no solo a la memoria obtenida a través de vmalloc . Esto podría ser un búfer obtenido con kmalloc , un puntero dentro de la pila de un subproceso de núcleo, u otros casos que no conozco. La única garantía que tengo es que la persona que llama a esta capa superior debe asegurarse de que el búfer de memoria en cuestión se asigne en el espacio del kernel en ese punto (es decir, es válido para acceder al buffer[i] para todos los 0<=i<size en este punto punto). ¿Cómo struct page* una struct page* correspondiente a un puntero arbitrario?

Poniéndolo en pseudocódigo, tengo esto:

lower_layer(struct page*); upper_layer(void *buffer, size_t size) { for (addr = buffer & PAGE_MASK; addr <= buffer + size; addr += PAGE_SIZE) { struct page *pg = vmalloc_to_page(addr); lower_layer(pg); } }

y ahora necesito cambiar upper_layer para hacer frente a cualquier búfer válido (sin cambiar lower_layer ).

He encontrado virt_to_page , que Linux Device Drivers indica que funciona en "una dirección lógica, [no] memoria de vmalloc o memoria alta". Además, is_vmalloc_addr comprueba si una dirección proviene de vmalloc , y virt_addr_valid comprueba si una dirección es una dirección virtual válida (el forraje para virt_to_page ; esto incluye kmalloc(GFP_KERNEL) y pilas de núcleo). ¿Qué pasa con otros casos: búferes globales, memoria alta (llegará un día, aunque puedo ignorarlo por ahora), posiblemente otros tipos que no conozco? Entonces podría reformular mi pregunta como:

  1. ¿Cuáles son todos los tipos de zonas de memoria en el kernel?
  2. ¿Cómo los distingo?
  3. ¿Cómo obtengo información de mapeo de páginas para cada uno de ellos?

Si importa, el código se ejecuta en ARM (con una MMU), y la versión del kernel es al menos 2.6.26.


Para la memoria asignada por el espacio de usuario, desea usar get_user_pages , que le dará la lista de páginas asociadas con la memoria malloc''d, y también incrementará su contador de referencia (deberá llamar a page_cache_release en cada página una vez que haya terminado con ellos .)

Para las páginas vmalloc''d, vmalloc_to_page es tu amigo, y no creo que necesites hacer nada.


Podrías probar virt_to_page . No estoy seguro de que sea lo que quieres, pero al menos es un lugar para comenzar a buscar.


Supongo que lo que quieres es un recorrido de tabla de páginas, algo así como (advertencia, no código real, falta de bloqueo, etc.):

struct mm_struct *mm = current->mm; pgd = pgd_offset(mm, address); pmd = pmd_offset(pgd, address); pte = *pte_offset_map(pmd, address); page = pte_page(pte);

Pero tú debes tener mucho cuidado con esto. La dirección de kmalloc que tienes puede muy bien no estar alineada con la página, por ejemplo. Esto suena como una API muy peligrosa para mí.


Asignación de direcciones a una página de estructura

Hay un requisito para que Linux tenga un método rápido para asignar direcciones virtuales a direcciones físicas y para asignar páginas de estructura a su dirección física. Linux logra esto al saber dónde, en la memoria virtual y física, la matriz global mem_map es porque la matriz global tiene punteros a todas las páginas de estructura que representan la memoria física en el sistema. Todas las arquitecturas logran esto con mecanismos muy similares, pero, con fines ilustrativos, solo examinaremos el x86 con cuidado.

Mapeo Físico a Direcciones del Kernel Virtual

cualquier dirección virtual se puede traducir a la dirección física simplemente restando PAGE_OFFSET, que es esencialmente lo que hace la función virt_to_phys () con la macro __pa ():

/* from <asm-i386/page.h> */ 132 #define __pa(x) ((unsigned long)(x)-PAGE_OFFSET) /* from <asm-i386/io.h> */ 76 static inline unsigned long virt_to_phys(volatile void * address) 77 { 78 return __pa(address); 79 }

Obviamente, la operación inversa implica simplemente agregar PAGE_OFFSET, que se realiza mediante la función phys_to_virt () con la macro __va (). A continuación, veremos cómo esto ayuda a la asignación de páginas de estructura a direcciones físicas.

Hay una excepción en la que virt_to_phys () no se puede usar para convertir direcciones virtuales a direcciones físicas. Específicamente, en las arquitecturas PPC y ARM , virt_to_phys () no se puede usar para convertir direcciones que han sido devueltas por la función coherente_alloc (). Consiste_alloc () se utiliza en arquitecturas PPC y ARM para devolver la memoria desde un dispositivo no almacenado en caché para su uso con DMA.

¿Cuáles son todos los tipos de zonas de memoria en el kernel? <--- ver aquí