En las arquitecturas antiguas, se accedía a los periféricos a través de un mecanismo separado para acceder a la memoria con instrucciones especiales de E/S. En x86, había (¡y todavía hay!) Instrucciones de "entrada" y "salida" para transferir bytes entre la CPU y un periférico. Los periféricos recibieron direcciones, por ejemplo 0x80 para el teclado. Simplificar mucho, haciendo "en 0x80" leería un byte desde el controlador del teclado al registro de la CPU "AL".
En las arquitecturas modernas, se accede a los periféricos de forma similar a la memoria: a través de direcciones de memoria asignadas en un bus. No debe pensar en un autobús como una forma de acceder a la memoria. Es más una forma de abordar periféricos individuales, de los cuales la memoria (RAM/DDR) es solo un tipo. Por ejemplo, puede tener 2 GB de RAM en las direcciones 0x00000000..0x7fffffff. Después de eso, es posible que tenga una tarjeta gráfica en 0x80000000..0x80001fff. El controlador de bus (PCIe o lo que sea) sabe qué rangos de direcciones van a qué periféricos.
La memoria es generalmente especial ya que se puede almacenar en caché, por lo que las lecturas/escrituras individuales en la memoria tienden a no traducirse directamente a lecturas/escrituras individuales en los chips de RAM. Los periféricos están marcados como especiales: los accesos a la CPU deben ir al periférico exactamente como está escrito en su programa.
El idioma con el que hablas con los periféricos es bastante ad hoc según el dispositivo. El tema general es que el periférico se mapea en algún lugar de la memoria (por ejemplo, 0x80000000 para unas pocas KB como arriba), con un bit de estado y acciones individuales controladas por palabras diferentes (por lo general, 32 o 64 bits). Un ejemplo de un mítico puerto serie en 0x80000000:
- escribir 32 bit de la palabra 'A' a 0x80000000, haciendo cola carácter 'A' en su salida FIFO.
- Escriba la palabra de 32 bits 0x1 a 0x80000004, que le indica al puerto serie que envíe su cola.
Una vez más, totalmente inventado solo por poner un ejemplo, pero un puerto serie real (uart) no es tan diferente.
El problema es que en realidad no va a ver cualquiera de la disposición de memoria anterior en un sistema operativo moderno, debido a la memoria virtual. Las direcciones anteriores se denominarán "direcciones de memoria física" (o direcciones de bus): las direcciones reales que salen al bus. En cambio, la CPU ve direcciones de memoria virtual. Los periféricos individuales deberán asignarse al espacio de direcciones virtuales. Esto es algo complicado de explicar y probablemente sea mejor en otra Pregunta, pero el punto es que es poco probable que accedas a un periférico por su dirección física real en un sistema operativo moderno.
Esta es una excelente respuesta. ¿Qué tipo de libros crees que podrían ser un poco más amplios y/o más profundos sobre este tema? – Lavya
@JohnRipley Sí, estoy de acuerdo con Lavya. Por favor, recomiéndenos algunas buenas fuentes en las que ha aprendido estos señor. – Utku
Muchas gracias. No estoy trabajando en el nivel kernel en este momento, pero estoy interesado en una cosa. Si hablamos de la arquitectura i386 más popular. No recuerdo nada especial en la información de segmentos de formato de GDTR, LDTR, que se relaciona con cosas como "mapear este segmento o páginas en la memoria de este dispositivo" ... Parece que debería configurarse hablando con un controlador de memoria con comandos especiales para configurarlo? – bruziuz