2011-08-06 11 views
10

¿Cuál es la forma correcta de asignar en un espacio de usuario un búfer asignado con kmalloc? Quizás aún no entendía el mapeo de la memoria ... Escribí un módulo kernel que asigna este búfer (por ejemplo, 120 bytes) y lo leía y escribía en un proceso de espacio de usuario. Obviamente, creé un dispositivo char e implementé un método mmap en la estructura file_operations. Mi método es:mmap: asignación en el espacio de usuario un búfer de núcleo asignado con kmalloc

static int my_mmap(struct file *filp, struct vm_area_struct *vma) 
{ 
    //printk(KERN_INFO "Allocated virtual memory length = %d", vma->vm_end - vma->vm_start); 

    long unsigned int size = vma->vm_end - vma->vm_start; 

    if (remap_pfn_range(vma, vma->vm_start, 
         __pa(mem_area) >> PAGE_SHIFT, //what about vma->vm_pgoff? 
         size, 
         vma->vm_page_prot) < 0) 
    return -EAGAIN; 

    vma->vm_flags |= VM_LOCKED; 
    vma->vm_ops = &vmops; 
    vma->vm_flags |= VM_RESERVED; 

    my_vm_open(vma); 

    return 0; 
} 

donde mem_area puntos en un área de memoria asignada con kmalloc al inicio del módulo. El área se llena con el mismo valor (por ejemplo 0x10). Todas las obras pero creo que hay algo mal en este código:

  1. kmalloc podría devolver un puntero que no está alineado página y, en ese caso, no creo que es correcto el valor del tercer parámetro de remap_pfn_range, de hecho, en el espacio de usuario, leí el valor incorrecto. En cambio, todo funciona si utilizo __get_free_page (porque la función siempre devuelve un puntero que está alineado con la página) o cuando kmalloc devuelve un puntero alineado con la página. El mapeo de memoria funciona con regiones de memoria que son múltiples de PAGE_SIZE, entonces, ¿debo asignar una página completa en lugar de usar kmalloc?

  2. Cuando my_mmap se denomina, el kernel ha asignado algunas páginas todavía? Pregunto esto porque encontré algunas implementaciones del método personalizado mmap que llama a remap_pfn_range con vma->vm_pgoff como tercer parámetro ... ¿cómo podría ser útil esto? ¿Es este el marco de página de la primera página nueva asignada? Si paso como tercer parámetro un marco de página como lo hago en my_mmap, debería liberar páginas comenzando desde la página en vma->vm_pgoff?

  3. Sin embargo, encontré una implementación del método mmap que mapea un buffer asignado con kmalloc. Para asignar correctamente el búfer, se realiza una operación (que no entiendo por el momento) antes del remap_pfn_range. Supongamos que mem es el puntero devuelto por kmalloc, mem_area se inicializa de esta manera:

    mem_area=(int *)(((unsigned long)mem + PAGE_SIZE - 1) & PAGE_MASK); 
    

Así mem_area contiene el mismo valor de mem sólo si mem está página alineado lo contrario, se debe contener el puntero al principio de la página siguiente. Sin embargo, con esta operación, si paso como tercer parámetro de remap_pfn_range, la asignación de valor __pa(mem_area) >> PAGE_SHIFT funciona bien. ¿Por qué?

¡Gracias a todos!

+0

Tengo una pregunta similar, pero con el uso de parámetro de arranque 'mmap': http://stackoverflow.com/q/12790382/143897? ¿Podría darnos algunos de sus hallazgos? Gracias. –

+0

¿No necesita un manejador de errores de página aquí para vm_operations_struct.fault? –

+0

Ejemplo ejecutable mínimo: https://stackoverflow.com/questions/10760479/how-to-mmap-a-linux-kernel-buffer-to-user-space/45645732#45645732 –

Respuesta

6
  1. Sí, debe asignar un número entero de páginas.

  2. No, el núcleo no se ha asignado ninguna página. vm->vm_pgoff es el desplazamiento solicitado dentro del dispositivo que se está mapeando; es el último parámetro de la llamada al espacio de usuario mmap(), traducido de bytes a páginas. Probablemente está mirando las implementaciones de mem o kmem mmap, en cuyo caso el desplazamiento representa la página física o lineal que el espacio de usuario quiere asignar.

  3. Eso es solo asignar un búfer alineado con la página dentro del búfer asignado kmalloc().Es mejor que utilices __get_free_pages() como ya has conjeturado, eliminando al intermediario.

Debería probar que el tamaño que se está asignando no supera su memoria intermedia.

+0

¡Gracias caf por el producto! Todavía no entiendo el punto número 2 ... no miré las implementaciones 'mem' o' kmem' pero lo encontré en el libro del controlador del dispositivo Linux ... ahora sé que 'vma-> vm_pgoff' es el desplazamiento dentro del dispositivo que se está mapeando, pero si paso a 'remap_pfn_range' como tercer parámetro' vma-> vm_pgoff', ¿qué memoria del dispositivo estoy mapeando? – MirkoBanchi

+0

@caf Tengo una pregunta similar pero con el uso de boot param mmap: stackoverflow.com/q/12790382/143897? ¿Podría darnos algunos de sus hallazgos? Gracias. –

Cuestiones relacionadas