x86 - ¿La diferencia entre Call Gate, Interrupt Gate, Trap Gate?
operating-system cpu (3)
Una puerta de interrupción es especial porque la bandera IF se borra automáticamente. Una puerta de llamada es especial porque no se activa a través de un vector de interrupción. Una puerta de tarea es especial porque guarda automáticamente el estado del procesador. Cuatro comportamientos distintos, tener cuatro nombres para ellos es conveniente.
Estoy estudiando el modo protegido Intel. Descubrí que Call Gate, Interrupt Gate, Trap Gate son casi lo mismo. De hecho, además de que Call Gate tiene los campos para contador de parámetros, y que estas 3 puertas tienen campos de tipos diferentes, son idénticos en todos los demás campos.
En cuanto a sus funciones, todas se usan para transferir control de código a algún procedimiento dentro de algún segmento de código.
Me pregunto, ya que estas 3 puertas contienen la información necesaria para la llamada a través de los límites de los privilegios. ¿Por qué necesitamos 3 tipos de ellos? ¿No es 1 lo suficientemente bueno?
Gracias por su tiempo y respuesta.
Actualización 1
Una pregunta relacionada: ¿ Cuándo usar la puerta de interrupción o la compuerta de trampa?
Actualización 2
Hoy se me ocurrió este pensamiento:
Propósito diferente, puertas diferentes y con diferentes detalles de comportamiento de la CPU llevados a cabo. Tal como manejo de banderas IF.
Una puerta (llamada, interrupción, tarea o trampa) se usa para transferir el control de ejecución a través de segmentos. La verificación del nivel de privilegio se realiza de forma diferente según el tipo de destino y las instrucciones utilizadas.
Una puerta de llamada usa las instrucciones CALL y JMP. Las puertas de llamada transfieren el control desde el código de privilegio inferior al código de privilegio superior. El DPL de puerta se usa para determinar qué niveles de privilegio tienen acceso a la puerta. Las compuertas de llamada son (o han sido, probablemente) abandonadas gradualmente a favor del mecanismo SYSENTER / SYSEXIT, que es más rápido.
Las puertas de tareas se utilizan para el soporte multitarea de hardware. Un conmutador de tareas de hardware puede ocurrir de forma voluntaria (CALL / JMP a un descriptor de puerta de tareas), oa través de una interrupción o un IRET cuando se establece el indicador NT. Funciona de la misma manera con las compuertas de interrupción o trampa. Las compuertas de tareas no se utilizan, a mi leal saber y entender, ya que los kernels generalmente quieren que se haga un trabajo adicional al cambiar las tareas.
Las puertas de interrupción y trampa, junto con las puertas de tarea, se conocen como la tabla de descriptores de interrupción. Funcionan igual que las puertas de llamada, excepto la transferencia de parámetros, de una pila de privilegios a otra. Una diferencia es que las compuertas de interrupción liberan el bit IF en EFLAGS, mientras que las compuertas trampa no. Esto los hace ideales para servir interrupciones de hardware. Las trampas se utilizan ampliamente en la virtualización asistida por hardware.
Para obtener más información, consulte los Manuales de arquitectura Intel en los procesadores que le interesan.
Actualizar
Para responder el comentario:
Hay muchas razones para distinguir las interrupciones de las trampas. Una es la diferencia en el alcance: las puertas de interrupción apuntan al espacio del kernel (después de todo, es el núcleo el que administra el hardware) mientras se llaman las trampas en el espacio de usuario. Los controladores de interrupción se llaman en respuesta a eventos de hardware, mientras que las interrupciones se ejecutan en respuesta a una instrucción de CPU.
Para un ejemplo simple (pero poco práctico) para comprender mejor por qué las puertas de interrupción y trampa tratan EFLAGS de manera diferente, considere qué sucedería en caso de que escribiéramos un controlador de interrupción para eventos de hardware en un sistema uniprocesador y no pudiéramos borrar el bit IF mientras estaban sirviendo uno. Sería posible que llegara una segunda interrupción mientras estábamos ocupados sirviendo al primero. Entonces nuestro procesador de interrupción sería llamado por el procesador en algún punto aleatorio durante nuestra ejecución de IH. Esto podría conducir a la corrupción de datos, a la inmovilización u otra magia mala. Prácticamente, la interrupción de la deshabilitación es uno de los mecanismos para garantizar que una serie de sentencias kernel se trate como una sección crítica.
Sin embargo, el ejemplo anterior está asumiendo interrupciones enmascarables. No querrás ignorar los NMI, de todos modos.
En gran parte es irrelevante hoy también. Hoy prácticamente no hay distinción entre manejadores de interrupción rápidos y lentos (búsqueda de "Manejadores rápidos y lentos"), los manejadores de interrupción pueden ejecutarse de forma anidada, los procesadores SMP hacen obligatorio acoplar la desactivación de interrupción local con bloqueos de giro, y así sucesivamente.
Ahora, las compuertas trampa se usan para dar servicio a interrupciones de software, excepciones, etc. Es probable que una falla de página o una división por cero en su procesador se maneje a través de una compuerta trampa. El ejemplo más simple de uso de compuertas trampa para controlar la ejecución del programa es la instrucción INT 3, que se usa para implementar puntos de interrupción en los depuradores. Al realizar la virtualización, lo que ocurre es que el hipervisor se ejecuta en el anillo 0, y el núcleo invitado usualmente en el anillo 1, donde el código privilegiado fallaría con un error de excepción general. Witchel y Rosenblum desarrollaron la traducción binaria , que básicamente consiste en reescribir las instrucciones para simular sus efectos. Las instrucciones críticas se descubren y reemplazan con trampas. Luego, cuando se ejecuta la captura, el control se cede al VMM / hipervisor, que es responsable de emular las instrucciones críticas en el anillo 0.
Con la virtualización asistida por hardware, la técnica de trampa y emulación ha sido algo limitada en su uso (ya que es bastante costosa, especialmente cuando es dinámica), pero la práctica de la traducción binaria todavía se usa ampliamente .
Para obtener más información, te sugiero que revises:
- Controladores de dispositivo Linux, tercera edición (disponible en línea )
- Para la traducción binaria, QEMU es un excelente comienzo.
- Con respecto a trampa y emulación, verifique una comparación entre las técnicas de software / hardware.
¡Espero que esto ayude!
Desde el punto de vista de la protección, la arquitectura x86 basada en el diseño en capas, según la cual todo el espacio de ejecución entregado por el procesador se divide en cuatro dominios de seguridad protegidos, cada uno de los cuales tiene su propio nivel de privilegios asignados. Este diseño asume que la mayor parte del código de tiempo se ejecutará en el dominio menos privilegiado ya veces se solicitarán servicios del dominio de seguridad más privilegiado y estos servicios adelantarán las actividades menos privilegiadas en la pila y luego lo restaurarán de tal forma que la preferencia completa será invisible para el código menos privilegiado. El diseño de protección en capas indica que el control no se puede pasar arbitrariamente entre diferentes dominios de seguridad. A gates es una característica de la arquitectura x86 para la transferencia de control del segmento de código menos privilegiado al segmento de código más privilegiado, pero no al revés. Además, el punto en el segmento menos privilegiado desde el que se aprobará el control puede ser arbitrario, pero el punto en el segmento más privilegiado donde se pasará el control está estrictamente especificado. El control hacia atrás que pasa al segmento menos privilegiado solo se permite por medio de la instrucción iret. En este sentido, el manual del desarrollador de software Intel afirma:
"Code modules in lower privilege segments can only access modules operating at
higher privilege segments by means of a tightly controlled and protected inter-
face called a gate. Attempts to access higher privilege segments without going
through a protection gate and without having sufficient access rights causes a
general-protection exception (#GP) to be generated."
En otras palabras, gate es el punto de entrada de dominio más privilegiado, con los derechos de acceso requeridos y la dirección de destino especificada. De esta forma, todas las puertas son similares y se utilizan con casi los mismos fines, y todas las descripciones de puertas contienen el campo DPL, que es el que usa el procesador para controlar los derechos de acceso. Pero obsérvese que el procesador verifica el DPL de la puerta solo si el origen de la llamada es un software (se ejecutó la instrucción call, jmp, int) y omite esta comprobación cuando la fuente de la llamada es un hardware. A pesar del hecho de que todas las puertas son similares, tienen algunas diferencias, porque originalmente los ingenieros de Intel pensaron que las diferentes puertas se usarían para diferentes propósitos. Vamos a describir las puertas y sus diferencias:
1) Puerta de tarea. Puede ser almacenado solo en IDT y GDT y llamado por la instrucción int. Es un tipo de puerta muy especial, que difiere significativamente de todos los demás. Inicialmente, los ingenieros de Intel pensaron que revolucionarían la multitarea, al proporcionar una función basada en la CPU para el cambio de tareas. Introdujeron el TSS (segmento de estado de la tarea) que contiene el estado de la tarea de registros y se puede usar para el cambio de tareas de hardware. Hay dos formas de activar la conmutación de tareas de hardware: utilizando TSS y utilizando Task Gate. Para hacer que la tarea de hardware cambie, puede usar las instrucciones call o jmp. Si entiendo correctamente, la razón principal para la introducción de la puerta de tarea fue el deseo de tener la capacidad de activar el interruptor de tarea de hardware en respuesta a la llegada de interrupción, porque el interruptor de tarea de hardware no puede activarse al saltar al selector de TSS. En realidad, nadie lo usa e incluso nadie usa la función de cambio de contexto de hardware en absoluto. En el mundo real, esta característica no es óptima desde el punto de vista del rendimiento y no es adecuada para su uso. Por ejemplo, teniendo en cuenta que TSS solo se puede almacenar en GDT y la longitud de GDT no puede ser más de 8192, no podemos tener más de 8k tareas desde el punto de vista del hardware.
2) Puerta de trampa. Puede ser almacenado solo en IDT y llamado por la instrucción int. Se puede considerar como un tipo básico de puerta. Simplemente pasa el control a la dirección particular especificada en el descriptor de compuerta trampa en el segmento más privado y nada más. Las compuertas trampa se usan activamente para diferentes propósitos, que pueden incluir:
- implementación de llamada al sistema (por ejemplo, uso de Linux int 0x80 y uso de Windows int 0x2E para este propósito)
- implementación de manejo de excepciones (no tenemos ningún motivo para deshabilitar las interrupciones en el caso de una excepción).
- interrumpir la implementación de manejo en máquinas con APIC (podemos controlar mejor la pila de kernel).
3) Puerta de interrupción. Puede ser almacenado solo en IDT y llamado por la instrucción int. Es lo mismo que puerta de trampa, pero además la llamada de puerta de interrupción también prohíbe la futura aceptación de interrupción mediante el borrado automático del indicador IF en el registro EFLAGS. Puertas de interrupción utilizadas activamente para la implementación de manejo de interuptos, especialmente en máquinas basadas en PIC. La razón es un requisito para controlar la profundidad de la pila. PIC no tiene la función de prioridades de fuentes de interrupción. Debido a esto, de forma predeterminada, PIC desactiva solo la interrupción que ya está en el manejo en el procesador. Pero aún pueden llegar otras interrupciones en el medio y adelantarse al manejo de interrupciones. Entonces, puede haber 15 manejadores de interrupciones en la pila del kernel en el mismo momento. Como resultado, los desarrolladores del kernel forzaron o bien a aumentar el tamaño de la pila del kernel de forma significativa, lo que lleva a la penalización de la memoria o a estar preparados para enfrentar un desbordamiento esporádico de la pila del kernel. Interrupt Gate puede garantizar que solo un controlador puede estar en la pila del kernel al mismo tiempo.
4) Puerta de llamada. Se puede almacenar en GDL y LDT y se llama mediante las instrucciones call y jmp. Similar a la puerta de trampa, pero además puede pasar el número de parámetros desde la pila de tareas de modo de usuario a la pila de tareas de modo kernel. El número de parámetros pasados se especifica en el descriptor de puerta de llamada. Las puertas de llamada nunca fueron populares. Hay pocas razones para eso:
- Pueden ser reemplazados por compuertas trampa (Navaja Occam).
- No son portátiles mucho. Otros procesadores no tienen características similares. Eso significa que el soporte de las puertas de llamada para llamadas al sistema significa que durante la transferencia del sistema operativo a otro procesador se debe reescribir más código.
- No son demasiado flexibles, debido a que la cantidad de parámetros que se pueden pasar entre pilas es limitada.
- No son óptimos desde el punto de vista del rendimiento.
Además, a finales de la década de 1990, Intel y AMD introdujeron otras características para la implementación de llamadas al sistema, que a diferencia de las compuertas de llamada proporcionan beneficios de rendimiento suficientemente buenos. Este es un par de instrucciones sysenter / sysexit y syscall / sysret para Intel y AMD, respectivamente. Y a diferencia de las puertas de llamada, estas características se adoptaron ampliamente en los sistemas operativos.
No estoy de acuerdo con Michael Foukarakis. Sory, pero no hay ninguna diferencia entre interrupciones y trampas, excepto que afecta al indicador IF.
1) En teoría, cada tipo de puerta puede servir como interfaz que apunta a un segmento con cualquier nivel de privilegios. En la práctica, en el sistema operativo moderno en uso, solo se utilizan compuertas de interrupción y trampa, que se utilizan en IDT para llamadas al sistema, interrupciones y manejo de excepciones y, debido a esto, todo lo que sirven como punto de entrada del kernel.
2) Cualquier tipo de puerta (incluyendo interrupción, trampa y tarea) puede invocarse en el software utilizando la instrucción int. La única característica que puede prohibir el acceso de código de modo de usuario a una compuerta particular es DPL. Por ejemplo, cuando el sistema operativo construye IDT, independientemente de los tipos de compuertas particulares, el DPL de configuración de kernel de las compuertas que se usarán para el manejo de eventos dewareware a 0 y de acuerdo con este acceso a estas compuertas solo se permitirá desde el espacio del kernel (que se ejecuta en la mayoría de los dominios privilegiados), pero cuando configuró la puerta para la llamada al sistema, estableció DPL en 3 para permitir el acceso a esa puerta desde cualquier código. Como resultado, la tarea del modo de usuario puede realizar una llamada al sistema utilizando la puerta con DPL = 3, pero detectará la falla de protección general al intentar llamar al controlador de interrupción del teclado, por ejemplo.
3) Cualquier tipo de puerta en IDT puede ser invocado por el hardware. Las personas usan compuertas de interrupción para este manejo de eventos de hardware solo en casos en los que desean lograr alguna sincronización. Por ejemplo, para asegurarse de que el desbordamiento de pila de kernel es imposible. Por ejemplo, tengo experiencia exitosa en el uso de puertas trampa para el manejo de interrupciones de hardware en el sistema basado en APIC.
4) De manera similar, la puerta de cualquier tipo en IDT se puede llamar en el software. La razón por la que se utilizan las compuertas trampa para las llamadas al sistema y las excepciones es simple. No hay razones para desactivar las interrupciones. La desactivación de interrupciones es algo malo, porque aumenta la latencia de manejo de interrupciones y aumenta la probabilidad de interrupción perdida. Debido a esto, nadie no los desactivará sin ningún motivo serio en las manos.
5) Manejador de interrupciones usualmente escrito en estilo reentrante estricto. De esta forma, los manejadores de interrupciones generalmente no comparten datos y pueden adelantarse mutuamente. Incluso cuando tenemos que excluir mutuamente el acceso concurrente a los datos en el controlador de interrupciones, podemos proteger solo el acceso a los datos compartidos mediante el uso de instrucciones cli y sti. No hay ninguna razón para considerar un manejador de interrupciones completo como una sección crítica. No hay ninguna razón para usar puertas de interrupción, excepto el deseo de evitar un posible desbordamiento de pila de kernel en los sistemas basados en PIC.
Entonces, en resumen, las compuertas trampa es una solución predeterminada para la interfaz del kernel. Se puede usar la puerta de interrupción en lugar de la puerta de la trampa si hay alguna razón seria para eso.