Descripción general del modo protegido
El modo protegido corresponde al modo real. Antes de 80286, la CPU solo tenía modo de tiempo real, el bus de direcciones tenía 20 bits y la dirección de memoria era de 16 bits, lo que significa que podía acceder a hasta 2 ^ 20 = 1 M de espacio de memoria. En 80286 y posteriores, la dirección de memoria se cambia a 16 bits o 32 bits y se puede acceder al menos a 2^32=4G de espacio de memoria. Pero para garantizar que las CPU posteriores puedan ejecutar CPU más antiguas, solo pueden mantener la compatibilidad con versiones anteriores. Por lo tanto, las CPU de 80286 y posteriores primero ingresan al modo real y luego ingresan al modo protegido a través del mecanismo de conmutación. Entonces, ¿qué es el modo real? La CPU se inicia en modo real cuando se reinicia o se enciende, y el procesador funciona en modo real. En modo real, el método de direccionamiento de memoria es el mismo que el de 8086. El contenido del registro de segmento de 16 bits se multiplica por 16 (10H) como dirección base del segmento y la dirección de desplazamiento de 16 bits se suma para formar un Dirección física de 20 bits. El espacio máximo de direccionamiento es 1 MB y la segmentación máxima es 64 KB. Se pueden utilizar instrucciones de 32 bits. La CPU x86 de 32 bits utiliza 8086 de alta velocidad. En modo real, todos los segmentos se pueden leer, escribir y ejecutar.
En comparación con el modo real, el modo protegido tiene principalmente dos diferencias: primero, proporciona un mecanismo de protección entre segmentos para evitar problemas causados por el acceso aleatorio de direcciones entre programas; segundo, el espacio de memoria al que se accede aumenta; ver descripción anterior.
En la era 8086/8088, el procesador tenía solo un modo de funcionamiento (Operation Mode). Dado que no había otros modos de funcionamiento en ese momento, este modo no recibió nombre. Desde 80286 a 80386, el procesador ha agregado otros dos modos operativos: modo de protección y modo de administración del sistema SMM (Modo de administración del sistema). Por lo tanto, el modo de 8086/8088 se denomina modo de dirección real RM (Modo de dirección real).
El modo protegido es el modo nativo del procesador. En este modo, el procesador admite todas las instrucciones y todas las características arquitectónicas, proporcionando el mayor rendimiento y compatibilidad. Este modo se recomienda para todas las aplicaciones y sistemas operativos nuevos. Para garantizar la compatibilidad con PM, el procesador permite la ejecución de programas RM en un entorno multitarea protegido. Esta característica se llama Modo Virtual-8086, aunque no es un modo de procesador real. El modo Virtual-8086 es en realidad un atributo PM y cualquier tarea puede usarlo.
RM proporciona un entorno de programación para el procesador Intel 8086, con algunas extensiones (como la capacidad de cambiar a PM o SMM). Cuando el host se enciende o se reinicia, el procesador está en RM.
SMM es una característica arquitectónica estándar unificada para todos los procesadores Intel. Aparece en el chip Intel386 SL. Este modo proporciona un mecanismo transparente para que el sistema operativo implemente funciones específicas de la plataforma (como administración de energía o seguridad del sistema). Cuando se activa el pin de interrupción SMM externo (SMI#) o se recibe un SMI del APIC (Controlador de interrupción de programación avanzada), el procesador ingresará a SMM. En SMM, el procesador cambia a un espacio de direcciones separado al guardar el contexto completo del programa que se está ejecutando actualmente. Entonces el código especificado por SMM se puede ejecutar de forma transparente. Al regresar de SMM, el procesador volverá al estado en el que se encontraba antes de ser interrumpido por la administración del sistema.
Debido a que el procesador está en el estado RM después de encender o reiniciar la máquina, y para Intel 80386 y chips posteriores, solo PM puede desempeñar su función máxima. Entonces nos enfrentamos al problema de cambiar de RM a PM.
Este artículo no trata sobre SMM. El enfoque de esta sección es cómo cambiar de RM a PM durante la etapa de arranque. Los detalles de PM no se discutirán aquí porque el "Volumen del manual del desarrollador de software de arquitectura Intel". 3: Programación del sistema" tiene una introducción muy detallada y precisa. Tabla de descripción global (tabla de descriptores globales GDT): en modo protegido, es una estructura de datos importante y esencial.
¿Por qué existe una GDT? Consideremos primero el modelo de programación en modo de tiempo real:
En modo de tiempo real, nuestro acceso a una dirección de memoria es a través de Segmento: Desplazamiento, donde Segmento es la Dirección base de un segmento, la longitud máxima de un Segmento es de 64 KB, que es la longitud máxima que puede representar un sistema de 16 bits. El desplazamiento es el desplazamiento relativo a esta dirección base de segmento. El desplazamiento de dirección base es una dirección de memoria absoluta. De esto, podemos ver que un segmento tiene dos factores: Dirección base y Límite (la longitud máxima del segmento). Al acceder a una dirección de memoria, es necesario señalar: ¿Qué segmento usar? Y en relación con el desplazamiento de la dirección base de este segmento, este desplazamiento debe ser menor que el límite de este segmento. Por supuesto, para sistemas de 16 bits, no es necesario especificar el límite. El valor predeterminado es la longitud máxima de 64 KB y el desplazamiento de 16 bits nunca puede ser mayor que este límite. Cuando realmente programamos, utilizamos los registros de segmento de 16 bits CS (Segmento de código), DS (Segmento de datos), SS (Segmento de pila) para especificar el segmento. La CPU desplaza el valor en el registro de segmento 4 bits hacia la izquierda. y lo pone. Cuando llega a la línea de dirección de 20 bits, se convierte en la dirección base de 20 bits.
Cuando se trata del modo protegido, el modo de administración de memoria se divide en dos tipos, el modo de segmento y el modo de página. El modo de página también se basa en el modo de segmento. En otras palabras, el modo de administración de memoria del modo protegido es en realidad: modo de segmento puro y modo de página de segmento. Además, el modo de segmento es obligatorio, mientras que el modo de página es opcional; si se utiliza el modo de página, es el modo de página de segmento; de lo contrario, es el modo de segmento puro;
En este caso, no consideraremos el modo página por ahora. Para el modo de segmento, es natural seguir usando Segment:Offset para acceder a una dirección de memoria. Dado que el modo protegido se ejecuta en un sistema de 32 bits, los dos factores del segmento: dirección base y límite también son de 32 bits. IA-32 permite establecer la dirección base de un segmento en cualquier valor que pueda representarse en 32 bits (el límite se puede establecer en cualquier valor que pueda representarse en 32 bits, en múltiplos de 2^12), a diferencia de En modo de tiempo real, la dirección base de un segmento solo puede ser un múltiplo de 16 (porque sus 4 bits inferiores se obtienen mediante la operación de desplazamiento a la izquierda y solo pueden ser 0, por lo que se puede usar un registro de segmento de 16 bits para representan un propósito de dirección base de 20 bits), y el límite de un segmento solo puede ser un valor fijo de 64 KB. Además, el modo protegido, como sugiere el nombre, también proporciona un mecanismo de protección para el modo de segmento, lo que significa que un descriptor de segmento debe especificar sus propios derechos de acceso (Acceso). Por lo tanto, en modo protegido, la descripción de un segmento incluye tres factores: [Dirección base, Límite, Acceso], que se reúnen en una estructura de datos de 64 bits de longitud, denominada descriptor de segmento.
En este caso, si nos referimos a un segmento directamente a través de un descriptor de segmento de 64 bits, debemos usar un registro de segmento de 64 bits de longitud para cargar el descriptor de segmento. Sin embargo, para mantener la compatibilidad con versiones anteriores, Intel aún especifica el registro de segmento como de 16 bits (aunque cada registro de segmento en realidad tiene una parte invisible de 64 bits de largo, pero para los programadores, el registro de segmento es de 16 bits). Es obvio que no podemos hacer referencia directamente al descriptor de segmento de 64 bits a través del registro de segmento de 16 bits de longitud. ¿Qué hacer?
La solución es colocar estos descriptores de segmento de 64 bits en una matriz y usar el valor en el registro de segmento como un índice de subíndice para hacer referencia indirecta (de hecho, el registro de segmento El alto contenido de 13 bits en él se utiliza como índice). Esta matriz global es GDT. De hecho, GDT no solo almacena descriptores de segmento, sino también otros descriptores, todos ellos de 64 bits de longitud, y los analizaremos más adelante.
GDT se puede colocar en cualquier lugar de la memoria, por lo que cuando el programador hace referencia a un descriptor de segmento a través del registro de segmento, la CPU debe conocer la entrada del GDT, es decir, dónde se coloca la dirección base, entonces Intel La puerta del diseñador proporciona un registro GDTR para almacenar la dirección de entrada del GDT. Después de que el programador configura el GDT en una determinada ubicación en la memoria, la dirección de entrada del GDT se puede cargar en este registro a través de la instrucción LGDT. , la CPU El contenido de este registro servirá como entrada a GDT para acceder a GDT.
GDT es una estructura de datos necesaria para el modo protegido, y también es la única: no debe ni puede haber más de una. Además, como su nombre indica (Global Descriptor Table), es visible globalmente para cualquier tarea.
Además de GDT, IA-32 también permite a los programadores construir estructuras de datos similares a GDT. Se denominan LDT (Tabla de descriptores locales), pero a diferencia de GDT, LDT puede ser múltiple y como usted. Se puede decir por el nombre de LDT que los LDT no son visibles globalmente, solo son visibles para las tareas que hacen referencia a ellos y cada tarea puede tener como máximo un LDT. Además, cada LDT existe como un segmento en sí mismo y sus descriptores de segmento se colocan en el GDT.
IA-32 también proporciona un registro LDTR para la dirección de entrada de LDT. Debido a que solo se puede ejecutar una tarea en cualquier momento, solo hay un registro LDT global. Si una tarea tiene su propio LDT, cuando necesita hacer referencia a su propio LDT, necesita cargar el descriptor de segmento de su LDT en este registro a través de LLDT. La diferencia entre la instrucción LLDT y la instrucción LGDT es que el operando de la instrucción LGDT es una dirección de memoria de 32 bits. Esta dirección de memoria almacena una dirección de entrada GDT de 32 bits y un límite de GDT de 16 bits. El operando de la instrucción LLDT es un selector de 16 bits. El contenido principal de este selector es: el valor de índice del descriptor de segmento del LDT cargado en el GDT; esto es lo mismo que la referencia a través del registro de segmento que acabamos de comentar. El patrón de segmento es el mismo. LDT es solo una estructura de datos opcional, no es necesario utilizarla en absoluto. Usarlo puede brindar cierta comodidad, pero también complejidad. Si desea mantener el núcleo de su sistema operativo simple y portátil, es mejor no usarlo.
El segmento descrito por el descriptor de segmento en GDT y LDT se implementa a través de una estructura de datos de 16 bits. Esta estructura de datos se llama Selector de segmentos. Sus 13 bits altos sirven como índice de subíndice del descriptor de segmento referenciado en GDT/LDT. El bit 2 se utiliza para especificar si el descriptor de segmento referenciado se coloca en GDT o LDT. El bit 0 y el bit 1 son RPL: nivel de privilegio de solicitud. que se utiliza con fines de protección y no lo discutiremos en detalle aquí.
El selector de segmento se carga en el registro de segmento como el índice GDT/LDT discutido anteriormente. Cuando es necesario hacer referencia a una dirección de memoria, todavía se usa el modo Segmento: Desplazamiento. La operación específica es: en el. correspondiente El registro de segmento se carga en el Selector de segmento. De acuerdo con este Selector de segmento, el Descriptor de segmento correspondiente se puede encontrar en GDT o LDT. Este Descriptor de segmento registra la Dirección base de este segmento y luego agrega el Desplazamiento para obtener la memoria final. DIRECCIÓN.