Estoy bastante confundido sobre cómo Linux administra la memoria compartida de E/S para comunicarse con los dispositivos que la usan.
Si lo entendí correctamente, el kernel de Linux comienza mapeado en 0x100000 (para evitar que los datos de RAM heredados del primer megabyte se almacenen en ubicaciones de memoria contiguas) y luego, después de ingresar al modo protegido:
- en sistemas de 32 bits hay un mapeo como este
ZONE_NORMAL debe estar por debajo de 896 MB, por lo que siempre es posible el mapeo entre el kernel lineal de 1 GB y los 896 MB físicos. Ignoremos ZONE_DMA por ahora (leí que esto es solo para sistemas heredados ya que PCI ahora puede usar transferencias DMA en toda la memoria)
- en sistemas de 64 bits, el espacio de direcciones lineales del kernel debe comenzar desde PAGE_OFFSET= 0xffff810000000000 en adelante
En ambos casos, si una dirección en el espacio del kernel es mayor que PAGE_OFFSET, se debe hacer referencia a un mapeo de ioremap (a resolver mediante paginación), si es menor que PAGE_OFFSET se podría resolver con un simple NEW_ADDRESS = OLD_ADDRESS - PAGE_OFFSET. ¿Es esto correcto?
Pregunta adicional: cuando el kernel está en funcionamiento y se ha realizado la limpieza, ¿todavía reside físicamente desde 0x100000 en adelante (dentro del primer GB)? ¿Incluso en sistemas de 64 bits?
Respuesta1
En las PC, el BIOS asigna rangos de E/S asignados a la memoria de hardware a direcciones de memoria física entre 3 GiB y 4 GiB. Cuando un controlador solicita acceso a la memoria, el kernel lo asigna a algún lugar del espacio de direcciones virtuales del kernel.
Ninguna de sus otras dos preguntas parece tener nada que ver con la memoria compartida, pero:
En ambos casos, si una dirección en el espacio del kernel es mayor que PAGE_OFFSET, se debe hacer referencia a un mapeo de ioremap (a resolver mediante paginación), si es menor que PAGE_OFFSET se podría resolver con un simple NEW_ADDRESS = OLD_ADDRESS - PAGE_OFFSET. ¿Es esto correcto?
Mentalmente sí. El hardware utiliza las tablas de páginas en cualquier caso.
Respuesta2
Piensa que tu pregunta se parece a cómo funciona ioremap.
vaddr = ioremap(paddr_io_mapped_device, tamaño);
vaddr devuelve la dirección virtual en el espacio del kernel. El kernel crea las entradas de la tabla de páginas para el rango de direcciones virtuales (vaddr, tamaño) y las asigna a la dirección física paddr_io_shared_device. Entonces, si accede al rango de direcciones virtuales, será tan bueno como acceder a la dirección física dentro del dispositivo io_mapped.
Es importante destacar que el vaddr devuelto esno almacenable en caché. Cada vez que lea/escriba el rango de direcciones, se leerá/escribirá desde el dispositivo io_mapped y no desde la memoria caché.