¿Cómo puedo reservar un bloque de memoria del kernel de Linux?

25

Tengo un dispositivo que necesita un bloque de memoria reservado exclusivamente para él, sin la intervención del sistema operativo. ¿Hay alguna forma de decirle al BIOS o al sistema operativo que un bloque de memoria está reservado y que no debe usarlo?

Estoy usando este dispositivo en una máquina openSUSE.

Nathan Fellman
fuente

Respuestas:

23

Lo que estás pidiendo se llama DMA. Necesita escribir un controlador para reservar esta memoria.

Sí, me doy cuenta de que dijiste que no querías que el sistema operativo interviniera, y que un controlador se convierte en parte del sistema operativo, pero en ausencia de una reserva del controlador, el núcleo cree que toda la memoria le pertenece. (A menos que le diga al núcleo que ignore el bloque de memoria, según la respuesta de Aaron, eso es).

El Capítulo 15 (PDF) de " Controladores de dispositivos Linux, 3 / e " de Rubini, Corbet y Kroah-Hartmann cubre DMA y temas relacionados.

Si desea una versión HTML de esto, encontré la versión de la segunda edición del capítulo en otra parte en línea. Tenga en cuenta que la segunda edición tiene más de una década, ya que salió cuando el kernel 2.4 era nuevo. Ha habido mucho trabajo en el subsistema de administración de memoria del núcleo desde aquellos días, por lo que puede que ya no se aplique muy bien.

Warren Young
fuente
¿Con DMA puedo elegir qué direcciones físicas usar? ¿El núcleo me dará un bloque contiguo de memoria? ¿Se garantiza que esté siempre disponible?
Nathan Fellman
1
Sus preguntas se responden a partir de la página 442 del PDF que le señalé.
Warren Young,
24

Si desea que el sistema operativo lo ignore por completo , debe hacer un agujero de memoria con " memmap." Ver esta referencia . Por ejemplo, si desea 512M en la barrera de 2GB, puede poner "memmap=512M$2G " en la línea de comando del núcleo.

Deberá verificar su dmesg para encontrar un agujero contiguo para robar para que no pisotee ningún dispositivo; eso es específico para su placa base + tarjetas.

Esta no es la forma recomendada de hacer las cosas: consulte la respuesta de Warren Young sobre cómo hacerlo correctamente (controladores de kernel + DMA). Estoy respondiendo la pregunta exacta que hiciste. Si planeas hacer esto para los usuarios finales, te odiarán si les haces esto ... confía en mí, esa es la única razón por la que sabía esta respuesta.


Editar: Si está utilizando grub2 w / grubby (por ejemplo, CentOS 7), debe asegurarse de escapar de $ . Debería haber un solo \antes $. Ejemplo:

$ sudo -v
$ sudo grubby --update-kernel=ALL --args=memmap='128M\\$0x57EF0000'
$ sudo grubby --info $(sudo grubby --default-kernel) | grep memmap
args="ro crashkernel=auto ... memmap=128M\$0x57EF0000"
Aaron D. Marasco
fuente
1
Si bien su respuesta responde mi pregunta directamente, la respuesta de Warren parece ser la mejor manera de hacerlo. :-)
Nathan Fellman
1
@WarrenYoung tengo ninguna idea de lo que se supone que ver con ello. Yo diría " uint8_t *ptr = 0x8000000" con mi ejemplo? O eso puede ser por defecto ... Huh, realmente no lo sé. Nuevamente, sabía la respuesta porque era un usuario final de una tarjeta PCI mal diseñada donde tenía que asignar manualmente un búfer debajo de la marca 4G y luego decirle a un conductor dónde estaba ese espacio; Es posible que no sea posible desde el usuario.
Aaron D. Marasco
2
Solo por sonrisas, busqué un poco más en esto, y parece que lo necesitas MMAP_FIXED | MMAP_ANON. Sin un dispositivo DMA personalizado aquí para jugar, no puedo decir si realmente hace lo que el OP quería, pero mi caja CentOS felizmente me dio un bloque de 8 MB a 512 MB cuando dije memmap=8M$512Men GRUB. Ni siquiera requiere acceso de root, como había temido que pudiera. Pero incluso si esto hace lo correcto, sigo pensando que probablemente necesitará un controlador para manejar las interrupciones y demás.
Warren Young
3
@ AaronD.Marasco: No, mmap()las páginas d se ponen a cero antes de que el código de usuario las vea. Se hace por seguridad, para que los datos no se filtren de un proceso a otro. Otra razón para usar un controlador, ya que es posible que deba conservar el contenido del búfer DMA en el momento de la carga del controlador. Ah, y por cierto, la mmap()llamada localizada arbitrariamente tiene éxito incluso sin la memmapopción de arranque del kernel, al menos siempre que nadie esté usando la memoria ubicada donde solicitó. La opción de arranque sin duda aumenta las posibilidades de éxito, pero no es estrictamente necesario.
Warren Young
1
@ AaronD.Marasco hmm, está bien. interesante. gracias por ese enlace, es una buena lectura.
Woodrow Barlow
5

Para reservar un bloque de memoria del kernel en Linux basado en ARM, también puede usar un reserved-memorynodo en el archivo de árbol de su dispositivo (dts). En la documentación del kernel (ver aquí ), hay un ejemplo:

memory {
    reg = <0x40000000 0x40000000>;
};

reserved-memory {
    #address-cells = <1>;
    #size-cells = <1>;
    ranges;

    /* global autoconfigured region for contiguous allocations */
    linux,cma {
        compatible = "shared-dma-pool";
        reusable;
        size = <0x4000000>;
        alignment = <0x2000>;
        linux,cma-default;
    };

    display_reserved: framebuffer@78000000 {
        reg = <0x78000000 0x800000>;
    };

    multimedia_reserved: multimedia@77000000 {
        compatible = "acme,multimedia-memory";
        reg = <0x77000000 0x4000000>;
    };
};
Vladimir S.
fuente
0

Primero ingrese este comando, para verificar su configuración actual:

sysctl vm.min_free_kbytes

Para cambiar el valor establecido, edite /etc/sysctl.conf. Busca la línea:

vm.min_free_kbytes=12888

Si no existe, créelo (junto con su valor deseado). Los siguientes valores son aceptables:

8192
12288
16384
20480

8M es extremadamente conservador; Puede sentarse cómodamente a 16M. Una vez que cambie el valor, ejecute esto y no es necesario reiniciar:

sudo sysctl -p
Michael Mrozek
fuente
2
Por favor no deje en blanco sus publicaciones; bórrelo o márquelo para que un moderador lo elimine por usted.
jasonwryan