ver tengo saber revisar que procesos para memoria mas estado consumo consumen como comando chequear linux memory memory-management embedded linux-kernel

tengo - Acceso directo a memoria en Linux



ver memoria ram linux terminal (5)

¿Has mirado el parámetro kernel ''memmap''? En i386 y X64_64, puede usar el parámetro memmap para definir cómo el núcleo entregará bloques de memoria muy específicos (consulte la documentación de parámetros del kernel de Linux ). En su caso, querría marcar la memoria como ''reservada'' para que Linux no la toque en absoluto. Luego puede escribir su código para usar esa dirección y tamaño absolutos (¡ay de usted si se sale de ese espacio!).

Intento acceder a la memoria física directamente para un proyecto de Linux incorporado, pero no estoy seguro de cómo puedo designar la mejor memoria para mi uso.

Si reinicio mi dispositivo regularmente y accedo a / dev / mem, puedo leer y escribir fácilmente en casi cualquier lugar que desee. Sin embargo, en esto, estoy accediendo a la memoria que se puede asignar fácilmente a cualquier proceso; que no quiero hacer

Mi código para / dev / mem es (se eliminan todas las comprobaciones de errores, etc.):

mem_fd = open("/dev/mem", O_RDWR)); mem_p = malloc(SIZE + (PAGE_SIZE - 1)); if ((unsigned long) mem_p % PAGE_SIZE) { mem_p += PAGE_SIZE - ((unsigned long) mem_p % PAGE_SIZE); } mem_p = (unsigned char *) mmap(mem_p, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, mem_fd, BASE_ADDRESS);

Y esto funciona Sin embargo, me gustaría usar memoria que nadie más tocará. Intenté limitar la cantidad de memoria que ve el kernel arrancando con mem = XXXm, y luego estableciendo BASE_ADDRESS en algo por encima de eso (pero debajo de la memoria física), pero parece que no está accediendo a la misma memoria de manera consistente.

Basado en lo que he visto en línea, sospecho que puedo necesitar un módulo kernel (que está bien) que utiliza ya sea ioremap () o remap_pfn_range () (o ambos ???), pero no tengo ni idea de cómo; ¿Alguien puede ayudar?

EDITAR: Lo que quiero es una forma de acceder siempre a la misma memoria física (por ejemplo, valor de 1,5 MB) y dejar esa memoria a un lado para que el kernel no la asigne a ningún otro proceso.

Estoy tratando de reproducir un sistema que teníamos en otros sistemas operativos (sin administración de memoria) mediante el cual podía asignar un espacio en la memoria a través del enlazador y acceder a él usando algo como

*(unsigned char *)0x12345678

EDIT2: supongo que debería proporcionar más detalles. Este espacio de memoria se usará para un búfer RAM para una solución de registro de alto rendimiento para una aplicación incorporada. En los sistemas que tenemos, no hay nada que borre o codifique la memoria física durante un reinicio suave. Por lo tanto, si escribo un bit en una dirección física X y reinicio el sistema, el mismo bit se establecerá después del reinicio. Esto ha sido probado en el mismo hardware exacto que ejecuta VxWorks (esta lógica también funciona muy bien en Nucleus RTOS y OS20 en diferentes plataformas, FWIW). Mi idea era probar lo mismo en Linux al abordar directamente la memoria física; por lo tanto, es esencial que obtenga las mismas direcciones en cada arranque.

Probablemente debería aclarar que esto es para kernel 2.6.12 y más reciente.

EDIT3: Aquí está mi código, primero para el módulo kernel, luego para la aplicación de espacio de usuario.

Para usarlo, reinicio con mem = 95m, luego insmod foo-module.ko, luego mknod mknod / dev / foo c 32 0, luego ejecuto foo-user, donde muere. Correr bajo gdb muestra que muere en la asignación, aunque dentro de gdb, no puedo desreferenciar la dirección que obtengo de mmap (aunque printf puede)

foo-module.c

#include <linux/module.h> #include <linux/config.h> #include <linux/init.h> #include <linux/fs.h> #include <linux/mm.h> #include <asm/io.h> #define VERSION_STR "1.0.0" #define FOO_BUFFER_SIZE (1u*1024u*1024u) #define FOO_BUFFER_OFFSET (95u*1024u*1024u) #define FOO_MAJOR 32 #define FOO_NAME "foo" static const char *foo_version = "@(#) foo Support version " VERSION_STR " " __DATE__ " " __TIME__; static void *pt = NULL; static int foo_release(struct inode *inode, struct file *file); static int foo_open(struct inode *inode, struct file *file); static int foo_mmap(struct file *filp, struct vm_area_struct *vma); struct file_operations foo_fops = { .owner = THIS_MODULE, .llseek = NULL, .read = NULL, .write = NULL, .readdir = NULL, .poll = NULL, .ioctl = NULL, .mmap = foo_mmap, .open = foo_open, .flush = NULL, .release = foo_release, .fsync = NULL, .fasync = NULL, .lock = NULL, .readv = NULL, .writev = NULL, }; static int __init foo_init(void) { int i; printk(KERN_NOTICE "Loading foo support module/n"); printk(KERN_INFO "Version %s/n", foo_version); printk(KERN_INFO "Preparing device /dev/foo/n"); i = register_chrdev(FOO_MAJOR, FOO_NAME, &foo_fops); if (i != 0) { return -EIO; printk(KERN_ERR "Device couldn''t be registered!"); } printk(KERN_NOTICE "Device ready./n"); printk(KERN_NOTICE "Make sure to run mknod /dev/foo c %d 0/n", FOO_MAJOR); printk(KERN_INFO "Allocating memory/n"); pt = ioremap(FOO_BUFFER_OFFSET, FOO_BUFFER_SIZE); if (pt == NULL) { printk(KERN_ERR "Unable to remap memory/n"); return 1; } printk(KERN_INFO "ioremap returned %p/n", pt); return 0; } static void __exit foo_exit(void) { printk(KERN_NOTICE "Unloading foo support module/n"); unregister_chrdev(FOO_MAJOR, FOO_NAME); if (pt != NULL) { printk(KERN_INFO "Unmapping memory at %p/n", pt); iounmap(pt); } else { printk(KERN_WARNING "No memory to unmap!/n"); } return; } static int foo_open(struct inode *inode, struct file *file) { printk("foo_open/n"); return 0; } static int foo_release(struct inode *inode, struct file *file) { printk("foo_release/n"); return 0; } static int foo_mmap(struct file *filp, struct vm_area_struct *vma) { int ret; if (pt == NULL) { printk(KERN_ERR "Memory not mapped!/n"); return -EAGAIN; } if ((vma->vm_end - vma->vm_start) != FOO_BUFFER_SIZE) { printk(KERN_ERR "Error: sizes don''t match (buffer size = %d, requested size = %lu)/n", FOO_BUFFER_SIZE, vma->vm_end - vma->vm_start); return -EAGAIN; } ret = remap_pfn_range(vma, vma->vm_start, (unsigned long) pt, vma->vm_end - vma->vm_start, PAGE_SHARED); if (ret != 0) { printk(KERN_ERR "Error in calling remap_pfn_range: returned %d/n", ret); return -EAGAIN; } return 0; } module_init(foo_init); module_exit(foo_exit); MODULE_AUTHOR("Mike Miller"); MODULE_LICENSE("NONE"); MODULE_VERSION(VERSION_STR); MODULE_DESCRIPTION("Provides support for foo to access direct memory");

foo-user.c

#include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdio.h> #include <sys/mman.h> int main(void) { int fd; char *mptr; fd = open("/dev/foo", O_RDWR | O_SYNC); if (fd == -1) { printf("open error.../n"); return 1; } mptr = mmap(0, 1 * 1024 * 1024, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd, 4096); printf("On start, mptr points to 0x%lX./n",(unsigned long) mptr); printf("mptr points to 0x%lX. *mptr = 0x%X/n", (unsigned long) mptr, *mptr); mptr[0] = ''a''; mptr[1] = ''b''; printf("mptr points to 0x%lX. *mptr = 0x%X/n", (unsigned long) mptr, *mptr); close(fd); return 0; }


/ dev / mem está bien para registros simples y ataques, pero una vez que se cruza con las interrupciones y el territorio DMA, se debe escribir un controlador kernel-mode. Lo que hizo por sus sistemas operativos anteriores sin administración de memoria simplemente no se adapta bien a un sistema operativo de propósito general como Linux.

Ya ha pensado en el problema de asignación de búfer DMA. Ahora, piense en la interrupción "DMA done" desde su dispositivo. ¿Cómo vas a instalar una rutina de servicio de interrupción?

Además, / dev / mem normalmente está bloqueado para usuarios no root, por lo que no es muy práctico para uso general. Claro, podrías modificarlo, pero luego has abierto un gran agujero de seguridad en el sistema.

Si intenta mantener la base de código de controlador similar entre los sistemas operativos, debería considerar refaccionarla en capas de usuario y kernel independientes con una interfaz similar a IOCTL en el medio. Si escribe la parte de modo de usuario como una biblioteca genérica de código C, debería ser fácil realizar un puerto entre Linux y otros sistemas operativos. La parte específica del sistema operativo es el código kernel-mode. (Utilizamos este tipo de enfoque para nuestros conductores).

Parece que ya ha llegado a la conclusión de que es hora de escribir un kernel-driver, por lo que está en el camino correcto. El único consejo que puedo agregar es leer estos libros de principio a fin.

Controladores de dispositivos Linux

Comprender el Kernel de Linux

(Tenga en cuenta que estos libros son circa-2005, por lo que la información es un poco anticuada).


Creo que puedes encontrar mucha documentación sobre la parte kmalloc + mmap. Sin embargo, no estoy seguro de que puedas memorizar tanta memoria de forma contigua y tenerla siempre en el mismo lugar. Claro, si todo es siempre igual, entonces es posible que obtenga una dirección constante. Sin embargo, cada vez que cambie el código del núcleo, obtendrá una dirección diferente, por lo que no aceptaría la solución kmalloc.

Creo que deberías reservar algo de memoria en el momento del arranque, es decir, reservar algo de memoria física para que el núcleo no la toque. Luego puede reasignar esta memoria que le dará una dirección virtual del kernel, y luego puede mapearla y escribir un buen controlador de dispositivo.

Esto nos lleva de vuelta a los controladores de dispositivo de Linux en formato PDF. Eche un vistazo al capítulo 15, está describiendo esta técnica en la página 443

Editar: ioremap y mmap. Creo que esto podría ser más fácil de depurar haciendo cosas en dos pasos: primero, obtenga el ioremap correcto y pruébelo con una operación de dispositivo de caracteres, es decir, lectura / escritura. Una vez que sepa que puede tener acceso de forma segura a toda la memoria asignada utilizando lectura / escritura, entonces intente mapear todo el rango ioremapped.

Y si te metes en problemas, puedes publicar otra pregunta sobre mmaping

Editar: remap_pfn_range ioremap devuelve un virtual_adress, que debe convertir a un pfn para remap_pfn_ranges. Ahora, no entiendo exactamente qué es una pfn (Número de fotograma de página), pero creo que puedes obtener una llamada

virt_to_phys(pt) >> PAGE_SHIFT

Probablemente esta no sea la forma correcta (tm) de hacerlo, pero deberías probarlo

También debe verificar que FOO_MEM_OFFSET sea la dirección física de su bloque RAM. Es decir, antes de que ocurra algo con el mmu, su memoria estará disponible en 0 en el mapa de memoria de su procesador.


No soy un experto en estos asuntos, por lo que esta será una pregunta para usted en lugar de una respuesta. ¿Hay alguna razón por la que no puedas hacer una pequeña partición de disco ram y usarla solo para tu aplicación? ¿Eso no le daría acceso garantizado al mismo pedazo de memoria? No estoy seguro de que haya problemas de rendimiento de E / S o gastos generales adicionales asociados con eso. Esto también supone que puede decirle al kernel que particione un rango de direcciones específico en la memoria, sin estar seguro de si eso es posible.

Me disculpo por la nueva pregunta, pero encontré su pregunta interesante, y tengo curiosidad por saber si el disco RAM podría usarse de esa manera.


Perdón por responder, pero no del todo, noté que ya has editado la pregunta. Tenga en cuenta que SO no nos notifica cuando edita la pregunta. Estoy dando una respuesta genérica aquí, cuando actualices la pregunta, por favor deja un comentario, luego editaré mi respuesta.

Sí, vas a necesitar escribir un módulo. Lo que se reduce a esto es el uso de kmalloc() (asignando una región en el espacio del kernel) o vmalloc() (asignando una región en el espacio de usuario).

Exponer lo anterior es fácil, exponer a este último puede ser un dolor en la parte posterior con el tipo de interfaz que está describiendo según sea necesario. Usted notó que 1.5 MB es una estimación aproximada de cuánto necesita reservar realmente, ¿está revestido de hierro? ¿Se siente cómodo sacando eso del espacio del núcleo? ¿Puede tratar adecuadamente con ENOMEM o EIO desde el espacio de usuario (o incluso desde el disco)? IOW, ¿qué entra en esta región?

Además, ¿la concurrencia va a ser un problema con esto? Si es así, ¿vas a utilizar un futex? Si la respuesta a cualquiera es ''sí'' (especialmente la última), es probable que tenga que morder la viñeta e ir con vmalloc() (o arriesgarse a la putrefacción del núcleo desde adentro). Además, si incluso está PENSANDO sobre una interfaz ioctl() para el dispositivo char (especialmente para alguna idea de bloqueo ad-hoc), realmente desea ir con vmalloc() .

Además, ¿has leído this ? Además, ni siquiera estamos hablando de lo que grsec / selinux va a pensar de esto (si está en uso).