Nuestro equipo de especialistas pasados varios días de investigación y de recopilar de información, obtuvieron la solución, esperamos que todo este artículo sea de gran utilidad en tu trabajo.
Solución:
Aquí hay una vista de alto nivel del procesamiento de bajo nivel. Estoy describiendo una arquitectura típica simple, las arquitecturas reales pueden ser más complejas o diferir en formas que no importan a este nivel de detalle.
Cuando ocurre una interrupción, el procesador busca si las interrupciones están enmascaradas. Si es así, no pasa nada hasta que se desenmascaran. Cuando las interrupciones se desenmascaran, si hay interrupciones pendientes, el procesador elige una.
Luego, el procesador ejecuta la interrupción ramificándose a una dirección particular en la memoria. El código en esa dirección se llama manejador de interrupciones. Cuando el procesador se bifurca allí, enmascara las interrupciones (por lo que el manejador de interrupciones tiene control exclusivo) y guarda el contenido de algunos registros en algún lugar (típicamente otros registros).
El manejador de interrupciones hace lo que debe hacer, normalmente comunicándose con el periférico que activó la interrupción para enviar o recibir datos. Si el temporizador provocó la interrupción, el controlador podría activar el programador del sistema operativo para cambiar a un subproceso diferente. Cuando el manejador termina de ejecutarse, ejecuta una instrucción especial de retorno de interrupción que restaura los registros guardados y desenmascara las interrupciones.
El manejador de interrupciones debe ejecutarse rápidamente, porque evita que se ejecute cualquier otra interrupción. En el kernel de Linux, el procesamiento de interrupciones se divide en dos partes:
- La “mitad superior” es el controlador de interrupciones. Hace lo mínimo necesario, normalmente se comunica con el hardware y establece una bandera en algún lugar de la memoria del kernel.
- La “mitad inferior” realiza cualquier otro procesamiento necesario, por ejemplo, copiar datos en la memoria del proceso, actualizar las estructuras de datos del kernel, etc. Puede tomar su tiempo e incluso bloquear la espera de alguna otra parte del sistema, ya que se ejecuta con las interrupciones habilitadas.
Como es habitual en este tema, para obtener más información, lea Controladores de dispositivos Linux; el capítulo 10 trata sobre las interrupciones.
Gilles ya describió el caso general de una interrupción, lo siguiente se aplica específicamente a Linux 2.6 en una arquitectura Intel (parte de esto también se basa en las especificaciones de Intel).
Una interrupción es un evento que cambia la secuencia de instrucciones ejecutadas por el procesador.
Hay dos tipos diferentes de interrupciones:
- Interrupción síncrona (excepción) producido por la CPU mientras procesa las instrucciones
- Interrupción asíncrona (interrupción) emitido por otros dispositivos de hardware
Las excepciones se deben a errores de programación (fe Error de división, Fallo de página, Desbordamiento) que debe ser manejado por el kernel. Envía una señal al programa e intenta recuperarse del error.
Se clasifican las siguientes dos excepciones:
- Excepción detectada por el procesador generado por la CPU mientras detecta una condición anómala; dividido en tres grupos: Fallas generalmente se puede corregir, Trampas informar una ejecución, Abortos son errores graves.
- Excepción programada solicitado por el programador, manejado como una trampa.
Las interrupciones pueden ser emitidas por dispositivos de E / S (teclado, adaptador de red, ..), temporizadores de intervalo y (en sistemas multiprocesador) otras CPU. Cuando ocurre una interrupción, la CPU debe detener su instrucción actual y ejecutar la interrupción recién llegada. Necesita guardar el antiguo estado del proceso interrumpido para (probablemente) reanudarlo después de que se maneje la interrupción.
Manejar las interrupciones es una tarea delicada:
- Las interrupciones pueden ocurrir en cualquier momento, el kernel intenta eliminarlo lo antes posible
- Una interrupción puede ser interrumpida por otra interrupción
- Hay regiones en el kernel que no deben interrumpirse en absoluto.
Se definen dos niveles de interrupción diferentes:
- Interrupciones enmascarables emitidos por dispositivos de E / S; puede estar en dos estados, enmascarado o desenmascarado. Solo se procesan las interrupciones no enmascaradas.
- Interrupciones no enmascarables; fallas críticas (falla de hardware fe); siempre procesado por la CPU.
Cada dispositivo de hardware tiene su propia línea de solicitud de interrupción (IRQ). Las IRQ se numeran comenzando desde 0. Todas las líneas de IRQ están conectadas a un controlador de interrupción programable (PIC). El PIC escucha las IRQ y las asigna a la CPU. También es posible deshabilitar una línea IRQ específica.
Los sistemas Linux de multiprocesamiento modernos generalmente incluyen el PIC avanzado más nuevo (APIC), que distribuye las solicitudes de IRQ por igual entre las CPU.
El paso intermedio entre una interrupción o excepción y su manejo es la Tabla de descriptores de interrupciones (IDT). Esta tabla asocia cada vector de interrupción o excepción (un número) con un controlador especificado (fe Error de división es manejado por la función divide_error()
).
A través del IDT, el kernel sabe exactamente cómo manejar la interrupción o excepción ocurrida.
Entonces, ¿qué hace el kernel cuando ocurre una interrupción?
- La CPU comprueba después de cada instrucción si hay una IRQ del (A) PIC
- Si es así, consulte al IDT para mapear el vector recibido a una función
- Comprueba si la interrupción fue emitida por una fuente autorizada
- Guarda los registros del proceso interrumpido
- Llame a la función de acuerdo para manejar la interrupción
- Cargue los registros guardados recientemente del proceso interrumpido e intente reanudarlo
En primer lugar, los participantes involucrados en el manejo de interrupciones son los dispositivos de hardware periféricos, el controlador de interrupciones, la CPU, el núcleo del sistema operativo y los controladores. Los dispositivos de hardware periféricos son responsables de la generación de interrupciones. Afirman líneas de solicitud de interrupción cuando quieren atención del kernel del sistema operativo. Estas señales son multiplexadas por el controlador de interrupciones, que es responsable de la recolección de señales de interrupción. También es responsable de determinar el orden en que las señales de interrupción se pasarán a la CPU. El controlador de interrupciones puede deshabilitar temporalmente una línea de solicitud de interrupción particular (IRQL) y volver a habilitarla (enmascaramiento de IRQL). El controlador de interrupción pasa las solicitudes de interrupción recopiladas a la CPU de forma secuencial. La CPU después de completar la ejecución de cada instrucción, la CPU verifica si hay solicitudes de interrupción en espera del controlador de interrupciones. Si la CPU encuentra que hay una solicitud en espera Y el indicador de habilitación de interrupciones se establece en el registro de control interno de la CPU, la CPU inicia el manejo de interrupciones. Como puede ver, mediante la manipulación del indicador de interrupción en la CPU y la comunicación con el controlador de interrupciones, el kernel de Linux puede controlar la aceptación de interrupciones. Por ejemplo, Linux puede deshabilitar la aceptación de interrupciones del dispositivo en particular o deshabilitar la aceptación de interrupciones en absoluto.
¿Qué sucede cuando el procesador recibe una solicitud de interrupción? En primer lugar, la CPU deshabilita automáticamente las interrupciones restableciendo el indicador de interrupción. Se volverán a habilitar una vez que finalice el manejo de interrupciones. Al mismo tiempo, la CPU realiza una cantidad mínima de trabajo necesaria para cambiar la CPU del modo de usuario al modo de kernel de tal manera que le permita reanudar la ejecución del código interrumpido. La CPU consulta con las estructuras especiales de control de la CPU rellenadas por el kernel de Linux para encontrar una dirección de código a la que se pasará el control. Esta dirección es la dirección de la primera instrucción del controlador de interrupciones, que es parte del kernel de Linux.
Como primer paso del manejo de interrupciones, el kernel identifica el vector de interrupciones recibidas para identificar qué tipo de evento ha ocurrido en el sistema. El vector de interrupción define qué acciones tomará Linux para manejarlo. Como segundo paso, Linux guarda el resto de los registros de la CPU (que la CPU no guardó automáticamente) y que potencialmente pueden ser utilizados por el programa interrumpido. Esta es una acción muy importante, porque permite que Linux maneje las interrupciones de forma transparente con respecto al programa interrumpido. Como tercer paso, Linux logra cambiar al modo kernel configurando el entorno del kernel y configurando el estado de la CPU requerido para ello. Y finalmente, se llama al manejador de interrupciones dependiente del vector. (Puede buscar en BUILD_INTERRUPT3 macro en arch x86 kernel entry_32.S para obtener detalles adicionales para el ejemplo relacionado con la arquitectura x86) En el caso de dispositivos periféricos, esta es una rutina do_IRQ (). (Busque en el archivo arch x86 kernel irq.c)
El manejador de interrupciones dependiente del vector generalmente envuelto por llamadas a irq_enter () e irq_exit (). El área de código encerrada dentro de un par de estas funciones, es atómica con respecto a cualquier otra área y también es atómica con respecto a los pares de cli / sti. Irq_enter () e irq_exit () también capturan algunas estadísticas relacionadas con el manejo de interrupciones. Finalmente, el kernel busca en la tabla vector_irq para encontrar el número irq asignado al vector de la interrupción recibida y llama a handle_irq () (desde arch x86 kernel irq_32.c).
En este punto finaliza la parte común del manejo de interrupciones en Linux, porque el kernel busca la rutina del manejador de interrupciones dependiente del dispositivo instalada por el controlador de dispositivo como parte del descriptor irq y la invoca. Si dicho controlador no ha sido instalado por el controlador, el kernel simplemente reconoce la interrupción en el controlador de interrupciones y sale del controlador de interrupciones general.
Después del final del manejo de interrupciones, el kernel restaura el estado del programa que fue interrumpido previamente y reanuda la ejecución de este programa.
Comentarios y calificaciones del tutorial
Agradecemos que quieras añadir valor a nuestra información participando con tu veteranía en las observaciones.