Este artículo trata sobre el proceso de entrega de interrupciones desde dispositivos externos en el sistema x86. Intenta responder preguntas como:
- ¿Qué es pic y para qué sirve?
- ¿Qué es APIC y para qué sirve? ¿Cuál es el propósito de LAPIC y I / O APIC?
- ¿Cuáles son las diferencias entre APIC, xAPIC y x2APIC?
- ¿Qué es el MSI? ¿Cuáles son las diferencias entre MSI y MSI-X?
- ¿Cuál es el papel de las tablas $ PIR, MPtable y ACPI?
Si desea conocer la respuesta a una de estas preguntas, o si simplemente desea saber sobre la evolución del controlador de interrupción, por favor, bienvenido.
Introduccion
Para aquellos que no saben qué es una interrupción, aquí hay una cita de Wikipedia:
En la programación del sistema, una interrupción es una señal al procesador emitida por hardware o software que indica un evento que requiere atención inmediata. Una interrupción alerta al procesador sobre una condición de alta prioridad que requiere la interrupción del código actual que el procesador está ejecutando. El procesador responde suspendiendo sus actividades actuales, guardando su estado y ejecutando una función llamada controlador de interrupción (o una rutina de servicio de interrupción, ISR) para tratar el evento. Esta interrupción es temporal y, una vez que finaliza el controlador de interrupciones, el procesador reanuda las actividades normales.
Hay dos tipos de interrupciones: interrupciones de hardware e interrupciones de software (softirqs):
- Los dispositivos utilizan las interrupciones de hardware para comunicar que requieren atención del sistema operativo. Internamente, las interrupciones de hardware se implementan utilizando señales de alerta electrónicas que se envían al procesador desde un dispositivo externo, que es parte de la computadora, como un controlador de disco o un periférico externo. Por ejemplo, al presionar una tecla en el teclado o al mover el mouse se activan interrupciones de hardware que hacen que el procesador lea la pulsación de tecla o la posición del mouse. El acto de iniciar una interrupción de hardware se denomina solicitud de interrupción (IRQ).
- Una interrupción de software es causada por una condición excepcional en el procesador o por una instrucción especial en el conjunto de instrucciones que causa una interrupción cuando se ejecuta. El primero a menudo se llama trampa o excepción y se usa para errores o eventos que ocurren durante la ejecución del programa que son lo suficientemente excepcionales como para que no puedan manejarse dentro del programa mismo. Por ejemplo, se generará una excepción de división por cero si se ordena a la unidad lógica aritmética del procesador que divida un número por cero, ya que esta instrucción es un error e imposible.
Este artículo trata sobre hardware / interrupciones externas IRQ.
¿Cuál es el propósito de las interrupciones? Por ejemplo, queremos realizar una acción con un paquete entrante de la tarjeta de red tan pronto como llegue el paquete. Si no desea preguntar continuamente a la tarjeta de red "¿Ha llegado mi paquete?" y perder el tiempo de su procesador, puede utilizar IRQ de interrupción de hardware externo. La línea de interrupción de un dispositivo debe conectarse a la línea INTR de la CPU, y después de recibir cada paquete, la tarjeta de red emitirá una señal a través de esta línea. La CPU detectará esta señal y sabrá que la tarjeta de red tiene información para ella. Solo después de eso, la CPU leerá el paquete entrante.
Pero, ¿qué debemos hacer si hay muchos dispositivos externos? Sería muy improductivo hacer un montón de pines INTR en la CPU para todos ellos.

Para resolver este problema, se inventó un chip especial: un controlador de interrupción.
Pic
(
wiki /
osdev )
El primer chip controlador de interrupción fue el
PIC Intel 8259 . Tenía 8 líneas de entrada (IRQ0-7) y 1 línea de salida (que conecta el controlador de interrupción con la línea INTR de la CPU). Cuando hay una interrupción de uno de los dispositivos en sus líneas de entrada, el 8259 emitirá una señal sobre la línea INTR. Después de eso, la CPU sabrá que algún dispositivo requiere su atención inmediata, y el procesador le preguntará al PIC cuál de las 8 líneas de entrada (IRQx) fue la fuente de esta interrupción. Hay algo de sobrecarga en este sondeo, pero ahora tenemos 8 líneas de interrupción en lugar de 1.

Pronto 8 líneas no fueron suficientes. Para aumentar el número total de líneas de interrupción, se conectaron dos controladores 8259 (maestro y esclavo) en cascada (Dual PIC).
Las IRQ de 0 a 7 se procesan con el primer Intel 8259 PIC (maestro), y las IRQ de 8 a 15 se procesan con el segundo Intel 8259 PIC (maestro). Solo el maestro está conectado a la CPU y puede señalar las interrupciones entrantes. Si hay una interrupción en las líneas 8-15, el segundo PIC (esclavo) se lo indicará al maestro en la línea IRQ2, y después de eso, el maestro señalará a la CPU. Esta interrupción en cascada elimina 1 de las 16 líneas, pero hace un total de 15 interrupciones para todos los dispositivos externos.

Este esquema fue adoptado por la comunidad, y ahora cuando alguien habla de PIC (Controlador de interrupción de programa) se refieren a este sistema Dual PIC. Después de algún tiempo, los controladores 8259 se mejoraron y obtuvieron un nuevo nombre: 8259A. Con estos controladores, el sistema DUAL PIC se incluyó en el conjunto de chips. En un momento en que el bus principal para la conexión del dispositivo externo era el ISA, este sistema era suficiente. Solo era necesario que diferentes dispositivos no se conectaran a la misma línea IRQ, ya que las interrupciones ISA no son compartibles.
El mapeo de interrupción del dispositivo era bastante estándar:
Ejemplo (desde
aquí ):
IRQ 0 - temporizador del sistema
IRQ 1 - controlador de teclado
IRQ 2 - cascada (interrupción del controlador esclavo)
IRQ 3 - puerto serie COM2
IRQ 4 - puerto serie COM1
IRQ 5 - puerto paralelo 2 y 3 o tarjeta de sonido
IRQ 6 - controlador de disquete
IRQ 7 - puerto paralelo 1
IRQ 8 - Temporizador RTC
IRQ 9 - ACPI
IRQ 10 - abierto / SCSI / NIC
IRQ 11 - abierto / SCSI / NIC
IRQ 12 - controlador de mouse
IRQ 13 - coprocesador matemático
IRQ 14 - ATA canal 1
IRQ 15 - ATA canal 2
La configuración y el trabajo con chips 8259 se realiza con puertos de E / S:
La documentación completa del 8259A se puede encontrar
aquí .
El bus PCI luego reemplazó al bus ISA. Desafortunadamente, el número de dispositivos comenzó a exceder el número 15. Además, en lugar del bus ISA estático, los dispositivos en el bus PCI se pueden agregar al sistema dinámicamente, lo que podría generar aún más problemas. Pero afortunadamente, las interrupciones en el bus PCI se pueden compartir, por lo que es posible conectar muchos dispositivos a una línea de interrupción IRQ. Al final, para resolver el problema de la falta de líneas de interrupción, se decidió agrupar las interrupciones de todos los dispositivos PCI a las líneas PIRQ (solicitud de interrupción programable).
Por ejemplo, supongamos que tenemos 4 líneas de interrupción libres en el controlador PIC y 20 dispositivos PCI. Podemos combinar interrupciones de 5 dispositivos en una línea PIRQx y conectar estas líneas PIRQx al controlador PIC. En este caso, si hay una interrupción en una de las líneas PIRQx, el procesador tendrá que preguntar a todos los dispositivos conectados a esta línea sobre la interrupción para saber quién es el responsable, pero al final resuelve el problema. El dispositivo que conecta las líneas de interrupción PCI a las líneas PIRQ a menudo se denomina enrutador PIR.
Con este método es necesario asegurarse de que las líneas PIRQx no se conectan a líneas con interrupciones ISA (ya que esto producirá conflictos) y que las líneas PIRQx están equilibradas (cuantos más dispositivos conectemos a una línea, más dispositivos necesitará la CPU para sondear cuando necesita verificar qué dispositivo es responsable de la interrupción).
Nota : en la imagen, el mapeo del dispositivo PCI -> PIR se ilustra de forma abstracta, ya que en el caso real es un poco más complicado. En el mundo real, cada dispositivo PCI tiene 4 líneas de interrupción (INTA, INTB, INTC, INTD) y hasta 8 funciones, donde cada función puede tener solo una de estas interrupciones INTx. La configuración del conjunto de chips determina qué línea INTx será utilizada por cada función.
Por su naturaleza, las funciones son bloques lógicos separados. Por ejemplo, un dispositivo PCI puede tener una función de controlador Smbus, una función de controlador SATA y una función de puente LPC. Desde el punto de vista de un sistema operativo (SO), cada función es como un dispositivo separado con su propio espacio de configuración (configuración PCI).
La información sobre el enrutamiento de interrupción del controlador PIC es enviada al SO por el BIOS, con la ayuda de la tabla $ PIR y a través de los registros 3Ch (INT_LN Interrupt Line (R / W)) y 3Dh (INT_PN Interrupt Pin (RO)) de El espacio de configuración PCI para cada función.
Recientemente se encontró una especificación para la tabla $ PIR
en el sitio web de Microsoft , pero actualmente no está disponible. Es posible comprender el contenido de la tabla a partir de la
especificación PCI BIOS [4.2.2. Obtener opciones de enrutamiento de interrupción PCI] o desde
aquí (el último enlace está en ruso, pero puede intentar buscar en Google "Especificación de tabla de enrutamiento PCI IRQ")
Apic
(
wiki ,
osdev )
El último método funcionó hasta que llegaron los sistemas multiprocesador. Por naturaleza, el PIC solo puede enviar interrupciones a una CPU, y en un sistema multiprocesador se desea cargar las CPU de forma equilibrada. La solución a este problema fue la nueva interfaz APIC (Advanced PIC).
Se agregó un controlador especial llamado LAPIC (APIC local) para cada procesador, así como el controlador
APIC de E / S para enrutar interrupciones desde dispositivos externos. Todos estos controladores se combinan en un bus común con el nombre APIC (tenga en cuenta que los sistemas modernos usan un bus de sistema estándar en lugar de un bus APIC separado para esta tarea).
Cuando llega una interrupción externa a la entrada I / O APIC, el controlador enviará un mensaje de interrupción al LAPIC de una de las CPU del sistema. De esta forma, el controlador I / O APIC ayuda a equilibrar la carga de interrupción entre procesadores.
El primer chip APIC fue el
82489DX , que era un chip separado que tenía un LAPIC conectado y un APIC de E / S dentro de sí mismo. Para un sistema de procesador dual se necesitaban tres chips de este tipo: dos para LAPIC y uno para I / O APIC. La funcionalidad LAPIC posterior se incluyó directamente en los procesadores, y la parte I / O APIC se separó al chip 82093AA.
El I / O APIC
82093AA tenía 24 entradas, y la arquitectura APIC podía soportar hasta 16 CPU. Las interrupciones 0-15 se dejaron para las antiguas interrupciones ISA por compatibilidad con sistemas más antiguos, y las interrupciones 16-23 estaban destinadas a todos los dispositivos PCI. Con esta delimitación, todos los conflictos entre las interrupciones ISA y PCI podrían evitarse fácilmente. Con el mayor número de líneas de interrupción libre, también fue posible aumentar el número de líneas PIRQx.

La programación I / O APIC y LAPIC se realiza con la ayuda de MMIO. Los registros LAPIC generalmente se colocan en la dirección 0xFEE00000 y los registros APIC de E / S en la dirección 0xFE0000, aunque es posible volver a configurarlos.
Como en el caso de PIC, chips separados al principio se convirtieron en parte del conjunto de chips más tarde.
La arquitectura APIC se modernizó más tarde, y su nueva variante se denominó xAPIC (x - extendida). Con total compatibilidad con versiones anteriores, el número total de CPU posibles en el sistema se incrementó a 256.
El siguiente paso en el desarrollo de la arquitectura se denominó
x2APIC . El número de CPU posibles en el sistema se incrementó a 2 ^ 32. Estos controladores pueden funcionar en un modo de compatibilidad con versiones anteriores con xAPIC, o pueden funcionar en el nuevo modo x2APIC. En este nuevo modo, la programación del controlador no se realiza a través de MMIO, sino a través de registros MSR (que son mucho más rápidos). Según
este enlace , el soporte de IOMMU es necesario para este modo.
Vale la pena señalar que es posible tener varios controladores APIC de E / S en el sistema. Por ejemplo, una para 24 interrupciones en un puente sur y la otra para 32 interrupciones en un puente norte. En el contexto de E / S APIC, las interrupciones generalmente se denominan GSI (Interrupción del sistema global). Entonces, el sistema mencionado tiene GSI 0-55.
¿Cómo podemos determinar si una CPU tiene un LAPIC interno y qué arquitectura APIC admite? Es posible responder a estas preguntas inspeccionando las banderas de bits de CPUID.
Para ayudar al sistema operativo a descubrir LAPIC y I / O APIC, el BIOS debe presentar información sobre ellos a través de una tabla MPtable (método antiguo) o una tabla ACPI (una tabla MADT en este caso). Además de la información común, tanto la MPtable como la ACPI (en este caso, una tabla DSDT) deben contener información sobre el enrutamiento de interrupción. Esto significa información sobre qué dispositivo usa qué línea de interrupción (similar a la tabla $ PIR).
Puede leer sobre MPtable en la
especificación oficial. Anteriormente, la especificación estaba en el sitio web de Intel, pero actualmente solo es posible encontrarla en una versión de archivo. La especificación ACPI se puede encontrar en el sitio web de UEFI (la versión actual es
6.2 ). Vale la pena notar que con ACPI es posible declarar el enrutamiento de interrupción para sistemas sin APIC (en lugar de proporcionar una tabla $ PIR separada).
Msi
(
wiki )
La última variante de APIC fue buena, pero no sin inconvenientes. Todas las líneas de interrupción de los dispositivos complicaron mucho el sistema y, por lo tanto, aumentaron la probabilidad de error. El bus PCI express vino a reemplazar al bus PCI, lo que simplificó completamente todos los sistemas de interrupción. No tiene líneas de interrupción en absoluto. Para la compatibilidad con versiones anteriores, las señales de interrupción (INTx #) se emulan con un tipo separado de mensajes. Con las líneas de interrupción PCI, su conexión se realizó con cables físicos. Con las líneas de interrupción PCI express, una conexión es lógica y se realiza mediante puentes PCI express. Pero este soporte de interrupciones INTx heredadas solo existe para la compatibilidad con el bus PCI. PCI express presenta un método completamente nuevo de entrega de interrupciones: MSI (interrupciones señalizadas por mensaje). En este método, un dispositivo señala la interrupción simplemente escribiendo en un lugar especial en la región MMIO de las CPU LAPIC.

Anteriormente, un solo dispositivo PCI (esto significa todas sus funciones) podía tener solo 4 interrupciones, pero ahora era posible abordar hasta 32 interrupciones.
En el caso de MSI, no se comparten líneas de interrupción: cada interrupción corresponde naturalmente a su dispositivo.
Las interrupciones de MSI también resuelven un problema más. Por ejemplo, imaginemos una situación en la que un dispositivo realiza una transacción de escritura de memoria y quiere indicar que se ha completado a través de la interrupción. Pero una transacción de escritura puede retrasarse en el bus en el proceso de su transmisión (y el dispositivo no podía saberlo). En este caso, la señal sobre la interrupción llegará primero a la CPU, por lo que el procesador leerá datos aún no válidos. Si se usa MSI, la información sobre MSI se transmite de la misma manera que los mensajes de datos, por lo que no puede llegar antes.
Vale la pena notar que las interrupciones de MSI no pueden funcionar sin LAPIC, pero MSI puede reemplazar I / O APIC (una simplificación de diseño más).
Después de algún tiempo, el método MSI se extendió a MSI-X. Ahora cada dispositivo puede tener hasta 2048 interrupciones. Ahora también es posible especificar qué CPU debe procesar qué interrupción. Puede ser muy útil para dispositivos de alta carga, como las tarjetas de red, por ejemplo.
No hay necesidad de una tabla de BIOS separada para el soporte de MSI. Pero el dispositivo debe indicar su soporte MSI a través de una de las capacidades en su espacio de configuración PCI. Además, un controlador de dispositivo debe incluir todo el soporte necesario para trabajar con el MSI.
Conclusión
En este artículo, hemos estudiado información sobre la evolución del controlador de interrupciones y tenemos un conocimiento teórico común sobre la entrega de interrupciones desde dispositivos externos en el sistema x86.
En la siguiente parte, iremos a practicar y veremos cómo involucrar a cada uno de los controladores de interrupción mencionados en Linux.
En la tercera parte, analizaremos el código de arranque de núcleo y veremos qué configuraciones se necesitan en el conjunto de chips para un enrutamiento de interrupción correcto.
Enlaces:
Segmentos reconocidos
Un agradecimiento especial a Jacob Garber de la comunidad
coreboot por ayudarme con la traducción de este artículo.