martes, 30 de diciembre de 2008

inicialización y manejo del procesador

Cada vez que se activa el pin #RESET, cada procesador conectado al bus del sistema proporciona una inicialización del hardware del procesador (conocido como reset de hardware) y una built-in self-test (BIST) opcional. Un reset de hardware pone los registros de cada procesador en un estado conocido y establece el procesador en modo real-address. También invalida las caches internas, los buffers lookaside de traducción (TLBs) y el branch target buffer (BTB). En este punto, la acción que se toma depende de la familia del procesador:
- Los Pentium 4 y Intel Xeon: Todos los procesadores en el bus del sistema ejecutan el protocolo de inicialización MP. Se selecciona un BSP y se ejecuta el código de inicialización de software en el segmento de código actual empezando en el offset del registro EIP. Los APs se ponen en un estado 'wait for startup IPI' (SIPI) mientras el BSP ejecuta el código de inicialización.
- familia P6: La acción es la misma que en los anteriores.
- procesadores Pentium: en estos sistemas siempre es el mismo procesador el que inicializa, y el segundo procesador se para.
- Intel486: El procesador primario empieza ejecutando código de inicialización de software en el segmento del código actual en el offset del registro EIP.
El código de inicialización de software proporciona todas las inicializaciones específicas de los sistemas del BSP o del primer procesador y del sistema lógico. Entonces el BSP despierta a los APs para que cada uno pueda ejecutar su código de configuración. Cuando todos los procesadores están inicializados, configurados, y sincronizados, el BSP empieza a ejecutar un sistema operativo inicial o una tarea.
El código de inicialización de software puede determinar si un procesador contiene una FPU x87 usando la CPUID. El código debe inicializar la FPU x87 y activar las banderas en el registro de control CR0 para reflejar el estado del entorno del FPU x87.
Los procesadores IA-32 y Intel 64 contienen instrucciones internas y caches de datos. Estos caches se activan borrando las banderas CD y NW del registro de control CR0. Como todas las lineas internas de la cache no son válidas después de la inicialización con el reset, no es necesario invalidar la cache antes de activar el caching. Todas las caches externas pueden requerir inicialización y invalidación usando una inicialización específica del sistema y una secuencia de código de invalidación. Dependiendo del hardware y del sistema operativo, se pueden proporcionar facilidades adicionales para la configuración de las caches.
La mayoría de los procesadores IA-32 y Intel 64 contienen registros de modelos específicos (MSRs). Un MSR dado puede no estar soportado por todas las familias y modelos de la IA-32 o de la Intel 64. Algunos MSRs están diseñados según la arquitectura para simplificar la programación del software. Los MSRs que proporcionan control para unas características de relación entre el software y el hardware incluyen:
- Contadores de monitoreo del rendimiento.
- Extensiones de depuración.
- Capacidad de excepciones de comprobaciones de máquina y de su arquitectura.
- MTRR.
- Administración térmica y de energía.
- Soporte de instrucciones específicas.
- Soporte para las características del procesador.
Los MSRs se pueden leer y escribir usando las instrucciones RDMSR y WRMSR, respectivamente.
Los registros de rango de tipo de memoria (MTRRs) permiten a los tipos de caching (o no caching) ser específicos en un sistema de memoria para un rango de direcciones físicas seleccionado. Permiten el acceso a memoria para optimizarlo a varios tipos de memoria como RAM, ROM... En general la inicializacion de los MTRRs se maneja por el código de inicialización de software o BIOS (basic input/output system), que no es un sistema operativo.
Para inicializar las extensiones SSE/SSE2/SSE3/SSSE3 se siguen los siguientes pasos:
- Se comprueba su presencia mediante CPUID
- Se activa la bandera OSFXSR (bit 9 en el registro CR4)
- Se activa la bandera OSXMMEXCPT (bit 10 en el registro CR4)
- Establecer los bits máscara y banderas en el registro MXCSR de acuerdo con el modo de operación que se quiera para las instrucciones SSE/SSE2/SSE3 SIMD en punto flotante.
Al resetear el procesador, se pone en modo real-address. Para inicial el modo protegido, se deben cargar algunas estructuras básicas de datos y módulos de código en la memoria física para soportar inicializaciones posteriores del procesador. Antes de que el procesador cambie al modo protegido, se debe cargar estas estructuras: un IDT, un GDT, un TSS, opcionalmente un LDT, si se usa paginamiento como mínimo un directorio de páginas y una tabla de páginas, un segmento de código con código a ejecutar cuando el procesador cambie, y uno o más módulos de código con administradores de interrupciones y de excepciones. El código de inicialización debe también inicializar estos registros: el GDTR, opcionalmente el IDTR, el CR1 a través del CR4, y los que tengan MTRR los MTRR. Con estas estructuras, módulos, etc cargados, el procesador puede cambiar al modo protegido cargando el registro CR0 con un valor que establece la bandera PE (bit 0).
Una vez el procesador entra en modo protegido después de un reset, el software generalmente no necesita volver al modo real-address, pero si se necesitara ejecutar software escrito para su ejecución en el modo real-address, generalmente es mejor ejecutarlo en el modo virtual-8086 antes que tener que volver a cambiar de modo. Para cambiar al modo protegido es recomendable seguir estos pasos:
- Desactivar las interrupciones.
- Ejecutar la instrucción LGDT para cargar el registro GDTR con la dirección base del GDT.
- Ejecutar la instrucción 'MOV CR0' que activa la bandera PE en el registro CR0.
- Inmediatamente después, ejecutar un JMP largo o un CALL largo.
- El JMP o el CALL justo después del MOV, cambia el flujo de la ejecución y serializa el procesador.
- Si está activada la paginación, el código del MOV, y del CALL o el JMP deben proceder de una página cuya identidad esté mapeada (o sea, que la dirección lineal antes del salto es la misma que la dirección física después de que la paginación y el modo protegido se activen).
- Si se usará una tabla de descriptores local, se ejecuta la instrucción LLDT para cargar el selector de segmento para el LDT en el registro LDTR.
- Ejecutar la instrucción LTR para cargar el registro de tareas con un selector de segmento a la tarea que inicia el modo protegido o a un area que se pueda escribir de la memoria que puede ser usada para guardar la información TSS en un cambio de tarea.
- Actualizar algunos registros de segmentos.
- Ejecutar la instrucción LIDT para cargar al registro IDTR con la dirección y con el límite del IDT de modo protegido.
- Ejecutar la instrucción STI para activar las interrupciones hardware enmascarables y ejecutar las operaciones hardware necesarias para activar las interrupciones NMI.
Si se ejecutan instrucciones entre los pasos 3 y 4 pueden ocurrir errores aleatorios.
Los Pentium 4, Intel Xeon, y los procesadores de la familia P6 tiene la capacidad de corregir erratas cargando un bloque de datos suministrados por Intel en el procesador. Este bloque de datos se llama actualización del microcódigo. Este tipo de actualizaciones sirven para corregir erratas en el procesador. La BIOS, que tiene el lanzador de la actualización, es la responsable de cargarla en el procesador durante la inicialización del sistema. Hay dos pasos en este proceso: el primero es incorporar los bloques de datos de la actualización necesarios en la BIOS, y el segundo es cargarlos en el procesador. La actualización consiste en un binario proporcionado por Intel que contiene un cabezal descriptivo de 48 bytes y de 2000 bytes de datos encriptados. No contiene código ejecutable. Cada microcódigo de actualización está soportado por una lista específica de procesadores. A veces, cuando los datos encriptados sólo soportan un procesador determinado se le añade una tabla de firmas extendida al final de los datos, pero siempre estará presente cuando los datos encriptados soporten múltiples modelos de procesadores. La tabla es una estructura extendida de 20 bytes que contiene un contador extendido de firmas, un checksum, y 12 bytes reservados. Cada estructura de forma de procesador consiste en la firma de procesador, las banderas del procesador, y un checksum. El contador de firmas extendido indica el número de estructuras de firmas de procesador que existe en la tabla de firmas extendida. La actualización comprueba si es compatible con el procesador mediante una invocación a CPUID. Para identificar la plataforma se lee el registro IA32_PLATFORM_ID (MSR 17H) con la instrucción RDMSR.

viernes, 26 de diciembre de 2008

Administración de sistemas con multiprocesamiento

La IA-32 y la Intel 64 proporcionan mecanismos para administrar y mejorar el rendimiento de múltiples procesadores conectados al mismo bus del sistema. Esto incluyen buses de cierre y/o administración de coherencia de caches para realizar operaciones atómicas en el sistema de memoria, instrucciones de serialización, un controlador avanzado de interrupciones programable, un cache de segundo nivel, un cache de tercer nivel, y la tecnología Hyper-Threading de Intel. Estos mecanismos son particularmente útiles en sistemas de multiprocesamiento simétrico (SMP). Sin embargo, también se pueden usar cuando un procesador Intel 64 o IA-32 y un procesador de propósito especial, comparten el bus del sistema. Los mecanismos de multiprocesamiento tienen las siguientes caracteristicas: guardan la coherencia de memoria del sistema, guardan la consistencia de la cache, permiten mantener un orden predecible de las escrituras a memoria, distribuyen la administración de interrupciones a lo largo de un grupo de procesadores, e incrementan el rendimiento del sistema explotando la naturaleza de multiprocesado y de multi-thread de los sistemas operativos y aplicaciones actuales.
Los procesadores de la IA-32 de 32 bits soportan operaciones atómicas que están en localizaciones en la memoria del sistema. Esas operaciones se usan típicamente para manejar estructuras de datos compartidas en las cuales dos o más procesadores pueden intentar modificar el mismo campo o la misma bandera a la vez. El procesador usa tres mecanismos independientes para llevar a cabo operaciones atómicas encerradas en memoria: Garantiza operaciones atómicas, encierra el bus, y utiliza protocolos de coherencia de cache para asegurar que las operaciones atómicas se pueden llevar a cabo en estructuras de datos en caches. Estos tres mecanismos son interdependientes.
El acto de que un procesador escriba datos en el segmento de código ejecutable actual con la intención de ejecutar esos datos como si fuera código se llama código automodificable. Los procesadores IA-32 muestran un comportamiento diferente dependiendo del modelo específico cuando ejecutan código de este tipo. El acto de que un procesador escriba datos en un segmento de código ejecutable de un segundo procesador con la intención de que los ejecute como si fuera código, se llama código modificable cruzado. Al igual que antes, el comportamiento de los IA-32 depende del modelo específico.
El término de ordenación de memoria se refiere al orden en el cual el procesador lee y escribe a través del bus del sistemaa la memoria del sistema. La IA-32 y la Intel 64 soportan múltiples modelos de ordenación de memoria dependiendo de la implementación de la arquitectura. Para optimizar el rendimiento de las ejecuciones de instrucciones, la IA-32 proporciona departamentos desde un modelo de ordenación sólido llamado ordenación de procesador en el Pentium 4, Intel Xeon, y la familia P6. Estas variantes permiten aumentar el rendimiento de operaciones. El objetivo de cualquiera de estas variantes es aumentar la velocidad de ejecución de instrucciones, manteniendo la coherencia de la memoria a pesar de sistemas com multiprocesamiento. Los procesadores Intel Core 2 Duo, Intel Core, Pentium 4, y la familia P6 modifican las operaciones del procesador durante las operaciones de reserva de strings para maximizar el rendimiento. La IA-32 y la Intel 64 proporcionan mecanismos para fortalecer o para activar el modelo de ordenación de la memoria para administrar situaciones especiales de programación. Estos mecanismos incluyen:
- Las instrucciones de E/S, las de encerramiento, los prefijos LOCK, y las instrucciones de serialización fuerzan un ordenamiento más fuerte en el procesador.
- La instrucción SFENCE, LFENCE y MFENCE proporcionan ordenación de memoria y capacidades de serialización para tipos específicos de operaciones en memoria.
- El rango de registros de tipos de memoria (MTRRs) se puede usar para fortalecer o para activar la ordenación de memoria para un área específica de memoria física. Sólo para Pentium 4, Intel Xeon y la familia P6.
- La tabla de atributos de páginas (PAT) se puede usar también para fortalecer la ordenación en memoria ordenando una página específica o un grupo de ellas.
En un sistema multiprocesador, cuando uno de los procesadores cambia una tabla de páginas o una entrada del directorio de páginas, los cambios tienen que ser propagados a todos los otros procesadores. A esto se le llama 'TLB shootdown'. La propagación de cambios a una tabla o a una entrada se puede hacer usando semáforos basados en memoria y/o interrupciones entre los procesadores (IPI). El sistema operativo está preparado para ocuparse si los procesadores usan el mapeado pasado durante el proceso de actualización.
La IA-32 y la Intel 64 definen instrucciones de serialización. Estas fuerzan al procesador a completar todas las modificaciones en las banderas, en los registros, y en la memoria por las instrucciones previas y para vaciar todas las escrituras a memoria de todos los bufferes antes de que la siguiente instrucción se ejecute. El concepto de instrucción de serialización se introdujo en el IA-32 con el Pentium para soportar ejecución de instrucciones en paralelo. Este tipo de instrucciones no tienen ningún significado para procesadores que no ejecuten instrucciones en paralelo. Cuando el procesador serializa la ejecución de instrucciones, se asegura de que todas las transacciones de memoria pendientes se completan (incluídas las que usan el buffer) antes de que se ejecute la siguiente instrucción.
Comenzando con la familia P6, la IA-32 define el protocolo de inicialización del multiprocesamiento (a partir de ahora multiprocesamiento = MP) como "Especificaciones para multiprocesadores versión 1.4", que define el protocolo de inicialización para sistemas multiprocesador con arquitectura IA-32. Este protocolo tiene las siguientes características:
- Soporta inicialización controlada de múltiples procesadores sin requerir hardware dedicado.
- Proporciona hardware para inicializar la carga del sistema sin la necesidad de una señal dedicada o una carga predefinida del procesador.
- Proporciona la misma manera de carga para todos los procesadores IA-32.
- También se aplica a sistemas Intel 64.
Los mecanismos para llevar a cabo el protocolo de inicialización de multiprocesamiento difieren dependiendo de la familia dentro de la IA-32. El protocolo define dos clases de procesadores: los procesadores autosuficientes (BSP) y los procesadores de aplicación (AP). Después del encendido o del reseteado de un sistema MP, el sistema hardware selecciona dinámicamente uno de lo procesadores en el bus del sistema (este es el BSP). Los AP son el resto de procesadores. Para los procesadores con soporte para Intel Hyper-Threading Technology, el protocolo de inicialización MP trata cada uno de los procesadores lógicos en el bus del sistema o al dominio coherente de links como un procesador separado. Durante la carga, se selecciona uno de los procesadores lógicos que actúa como BSD y los demás como APs. Después de que la BIOS haya completado el protocolo de inicialización MP, cada procesador lógico puede ser identificado por si APIC ID local. El software puede acceder a esas APIC IDs de cualquiera de estas formas: leyendo APIC ID para una APIC local, leyendo un ACPI o una tabla de MP, leyendo un APIC ID inicial, o leyendo un APIC ID de 32 bits desde el CPUID.
La tecnología Intel Hyper-Threading y la Intel multi-core son extensiones para la IA-32 y la Intel 64 que permiten a un procesador físico único, ejecutar una o más flujos de código (llamados threads) a la vez. En la primera tecnología, un sólo núcleo de procesador proporciona dos procesadores lógicos que comparten recursos de ejecución. En la tecnología multi-core, un procesador físico contiene dos o más núcleos de procesador. Ambas configuraciones requieren chipset y BIOS que soporten estas tecnologías. El software no necesita contar con el nombre del procesador para determinar si soporta alguna de ellas; usa CPUID.
Las siguientes características son parte del estado de la arquitectura de los procesadores lógicos dentro de los IA-32 y los Intel 64 que soporten la tecnología Intel Hyper-Threading. Se pueden subdividir en tres grupos: Duplicado de cada procesador lógico, compartir entre procesadores lógicos un procesador físico, y compartir o duplicar dependiendo de la implementación. Cuando un procesador que soporta la tecnología Intel Hyper-Threading se inicializa, a cada procesador lógico se le asigna una APIC ID local. La APIC ID sirve como un ID para el procesador lógico y se guarda en el registro APIC ID del procesador lógico. El software se comunica con el procesador lógico usando la facilidad de mensajería de interrupciones entre los APICs de los procesadores. Se implementan facilidades específicas en los IA-21 que soportan la tecnología Intel Hyper-Threading como caches, translation lookaside buffers (TLBs) y facilidades de monitoreo térmico.
En general cada núcleo de procesador tiene unas características de su microarquitectura idénticas a una implementación en un procesador único de una microarquitectura subyacente sin capacidad de hardware multi-threading. Cada procesador lógico en un procesador con doble núcleo tiene sus propias funcionalidades APIC , PAT, comprobaciones de arquitectura de máquina, depuración de registros y extensiones. Cada procesador lógico administra instrucciones de serialización o código automodificable por sí mismo. El orden de memoria está mantenido de la misma forma que en la tecnología Intel Hyper-Threading. Los registros de rangos de tipos de memoria (MTRR) se comparten entre dos procesadores lógicos compartiendo un núcleo de procesador si el procesador físico soporta tecnología Intel Hyper-Threading. Los MTRR no se comparten entre procesadores lógicos localizados en diferentes núcleos. La IA-32 y la Intel 64 requieren que todos los procesadores lógicos en un sistema MP usen un mapa de memoria MTRR idéntico. Esto le da al software una vista consistente de la memoria, independientemente del procesador. Los contadores de rendimiento y los MSRs de control se comparten entre dos procesadores lógicos compartiendo un núcleo de procesador si el núcleo soporta la tecnología Intel Hyper-Threading y está basado en la microarquitectura Intel NetBurst. No se comparten entre procesadores lógicos en núcleos diferentes. Como resultado, el software tiene que administrar el uso de estos recursos basados en la topología de los recursos de monitoreo del rendimiento. Algunos campos en el MSR IA32_MISC_ENABLE se pueden compartir entre dos procesadores lógicos que comparten el mismo núcleo, o también entre núcleos diferentes de un procesador físico. Las facilidades de actualización del microcódigo se comparten entre dos procesadores lógicos que comparten un núcleo si el sistema soporta Intel Hyper-Threading. No se comparte entre procesadores lógicos si están en diferentes núcleos o en diferentes unidades físicas. Cada procesador lógico con acceso a las facilidades de actualización de microcódigo puede iniciar una actualizacióno.
En un entorno de multi-threading, puede haber ciertos recursos hardware que son físicamente compartidos en algún nivel de la topología de hardware. En sistemas MP, los buses típicos y la memoria de los subsistemas son compartidas físicamente entre múltiples sockets. Dentro de los procesadores con hardware que soporte multi-threading, se proporcionan ciertos recursos para cada núcleo, mientras otros recursos se proporcionan a cada procesador lógico.
Para detectar el número de unidades físicas, núcleos de procesador, y otras relaciones topológicas en un sistema MP, se recomiendan estos procedimientos:
- Extraer los identificadores de tercer nivel del APIC ID de cada procesador lógico permitido por el software del sistema.
- Montar los identificadores de tercer nivel de SMT_ID, CORE_ID, PACKAGE_ID en arrays para cada procesador lógico permitido.
- Para detectar el número de unidades físicas: usar PACKAGE_ID para identificar los procesadores lógicos que residen en la misma unidad física.
- Para detectar el número de núcleos: usar CORE_ID para identificar los procesadores lógicos que residen en el mismo núcleo.
Cuando un procesador lógico en un sistema MP está inactivo (sin tareas que hacer) o bloqueado, la administración adicional de los recursos de ejecución de núcleos puede ser lograda usando las instrucciones HLT, PAUSE, o MONITOR/MWAIT.
La instrucción HLT para la ejecución del procesador lógico que la ejecuta y lo establece en estado inactivo hasta nuevas noticias. Cuando un procesador lógico se para, los procesadores lógicos activos continúan teniendo acceso total a los recursos compartidos en la unidad física. Entonces los recursos compartidos usados por el procesador lógico inactivo se ponen disponibles para los procesadores lógicos activos, permitiéndoles ejecutarlos con una mayor eficiencia. Cuando el procesador lógico inactivo retoma la ejecución, los recursos compartidos se vuelven a compartir entre todos los procesadores lógicos. La instrucción PAUSE puede aumentar el rendimiento de procesadores que soportan la tecnología Intel Hyper-Threading cuando ejecutan bucles 'spin-wait' y otras rutinas donde un flujo accede a un bloqueo compartido o semáforo en un bucle limitado. Cuando se ejecuta un bucle 'spin-wait', el procesador puede sufrir una penalización grave de rendimiento cuando sale del bucle porque detecta un posible fallo en el orden de la memoria y vuelca el pipeline del núcleo del procesador. La instrucción PAUSE proporciona una pista al procesador que la secuencia del código es un bucle 'spin-wait'. El procesador usa esto para esquivar el fallo de orden de memoria y previene el vuelco del pipeline.

martes, 23 de diciembre de 2008

Administración de tareas

Lo primero; las facilidades de administración de tareas de la arquitectura IA-32 sólo están disponibles cuando el procesador está en modo protegido.
Una tarea es una unidad de trabajo que un procesador puede enviar, ejecutar, o suspender. Puede ser usada para ejecutar un programa, una tarea o proceso, un utilidad de servicio del sistema operativo, un administrador de interrupciones o de excepciones, o una utilidad ejecutable o del núcleo. La IA-32 proporciona mecanismos para guardar el estado de la tarea, para enviar tareas a ejecución, y para cambiar de una tarea a otra. Cuando se opera en modo protegido, todas las ejecuciones del procesador ocurren desde una tarea. Cada sistema simple debe definir como mínimo una tarea, pero los sistemas más complejos pueden usar las facilidades de administración de tareas del procesador para soportar aplicaciones multitarea.
Una tarea se compone de dos partes: un espacio de ejecución y un segmento de estado de tarea (TSS). El espacio de ejecución de tareas consiste en un segmento de código, un segmento de pila, y uno o más segmentos de datos. Si un sistema operativo o un programa usa el mecanismo de protección de niveles de privilegios del procesador, el espacio de ejecución de tareas proporciona también una pila aparte para cada nivel de privilegios. El TSS especifica el segmento que compone al espacio de ejecución de la tarea y proporciona un lugar de almacenamiento para la información de estado de la tarea. En sistemas multitarea, la TSS proporciona también un mecanismo para linkar las tareas. Una tarea se define por el selector de segmento para su TSS. Cuando se carga la tarea en el procesador para su ejecución, el selector de segmento, la base de direcciones, el límite, y los atributos del descriptor de segmento del TSS se cargan en el registro de tarea (TR). Si está activada la paginación para la tarea, la dirección base del directorio de páginas usado por la tarea se carga en el registro de control CR3.
El software del procesador puede invocar una tarea para ejecutarla de 5 formas:
+ Haciendo una llamada explícita a una tarea con una instrucción CALL.
+ Haciendo un salto explícito a una tarea con una instrucción JMP.
+ Haciendo una llamada implícita (por el procesador) a una tarea de administración de interrupciones.
+ Haciendo una llamada implícita a una tarea de administración de excepciones.
+ Haciendo un retorno (iniciada con una instrucción IRET) cuando la bandera NT del registro EFLAGS se activa.
En la arquitectura IA-32, las tareas no son recursivas; una tarea no se puede llamar a sí misma.
El procesador define cinco estructuras de datos para las actividades de administración relacionadas con las tareas:
- Segmento de estado de tarea (TSS): La información de estado del procesador necesita restaurar una tarea guardada en un segmento del sistema (TSS). Los campos del TSS están divididos en campos dinámicos y campos estáticos.
- Descriptor de puerta de tarea: Proporciona una referencia indirecta y protegida a una tarea. Se puede guardar en la GDT, en una LDT o en la IDT. El campo de selector de segmento de TSS en un descriptor de puertas de tarea apunta a un descriptor TSS en el GDT. El RPL en ese segmento no se usa.
- Descriptor de TSS: Sólo se puede guardar en el GDT (no se puede guardar en el LDT ni en el IDT). Cualquier programa o procedimiento con acceso al descriptor TSS puede ejecutar la tarea con un CALL o con un JMP. En el modo de 64 bits el cambio de tarea no está soportado, pero los descriptores TSS siguen existiendo (expandidos a 16 bytes).
- Registro de tarea: Contiene el selector de segmento de 16 bits y el descriptor de segmento completo para el TSS de la tarea en ejecución. Esta información se copia desde el descriptor TSS en el GDT a la tarea en ejecución. El registro de tarea tiene una parte 'visible' (se puede leer y cambiar por software) y una parte 'invisible' (mantenida por el procesador e inaccesible por software, hace operaciones que aumentan la eficiencia).
- Bandera NT en el registro EFLAGS.
Cuando se opera en modo protegido, el TSS y el descriptor TSS tiene que crearse antes que la tarea, y el selector de segmento para el TSS se tiene que cargar en el registro de tareas usando la instrucción LTR.
El procesador transfiere ejecuciones a otras tareas en uno de cuatro casos:
+ Cuando el programa en ejecución, tarea, o procedimiento ejecuta un JMP o un CALL a un descriptor TSS en el GDT.
+ Cuando el programa en ejecución, tarea, o procedimiento ejecuta un JMP o un CALL a un descriptor de puerta de tarea en el GDT o en la LDT actual.
+ Un vector de interrupción o de excepción apunta a un descriptor de puertas de tareas en el IDT.
+ La tarea actual ejecuta un IRET cuando la bandera NT en el registro EFLAGS se activa.
El campo previo de linkar tareas del TSS y la bandera NT del EFLAGS se usan para retornar la ejecución a la tarea anterior. EFLAGS.NT=1 indica que la tarea en ejecución está anidada en otra tarea. Cuando un CALL, una interrupción, o una excepción causa un cambio de tarea, el procesador copia el selector de segmento del TSS actual al campo previo de linkar tareas del TSS para la nueva tarea (entonces pone EFLAGS.NT=1). Si el software usa una instrucción IRET para suspender la nueva tarea, el procesador comprueba que EFLAGS.NT=1; entonces usa el valor del campo previo de linkar tareas para volver a la tarea previa. Cuando se usa JMP para un cambio de tarea, la nueva tarea no está anidada. Es recomendable usar JMP cuando no se requiere anidamiento.
El espacio de direcciones para una tarea consiste en los segmentos a los que la tarea puede acceder. Incluye código, datos, pilas, y segmentos del sistema referenciados en el TSS y cualquier otro segmento accesible por el código de la tarea. Los segmentos se mapean en el espacio de direcciones lineales del procesador. El campo de segmentos LDT en el TSS se puede usar para a las tareas su propio LDT. Esto permite aislarla de otras tareas guardando los descriptores de segmento para todos los segmentos asociados a la tarea, en el LDT de la tarea. Aunque también es posible que múltiples tareas utilicen la misma LDT. Esto aumenta la eficiencia de la memoria cuando se permite especificar tareas para comunicarse o controlar a otras tareas, sin romper las barreras de protección del sistema. Las tareas se pueden mapear al espacio de direcciones lineales y al espacio de direcciones físicas en una de las dos maneras:
- Compartiendo entre todas las tareas un espacio de mapeo de direcciones lineales a físicas.
- Cada tarea tiene su propio espacio de direcciones lineales que está mapeado al espacio de direcciones físicas.
Para permitir la compartición de datos entre tareas, se usan las siguientes técnicas para crear un espacio mapeado de direcciones lógicas a físicas compartido por los segmentos de datos:
+ A través de los descriptores de segmentos en la GDT.
+ A través de los LDT compartidos.
+ A través de descriptores de segmentos en distintas LDTs que están mapeadas a direcciones comunes en el espacio de direcciones lineales.
En el modo de 64 bits, la estructura de las tareas y el estado de las tareas es similar a lo anterior en modo protegido. Sin embargo, el mecanismo de cambio de tarea disponible en modo protegido no está soportado en el modo de 64 bits. La administración de tareas y de sus cambios se tiene que controlar por software.

lunes, 22 de diciembre de 2008

Manejo de interrupciones y excepciones

Las interrupciones y las excepciones son eventos que indican que se ha producido una condición en algún lugar del sistema, que requiere la atención del procesador. Típicamente resultan en una transferencia de ejecución forzada desde el programa en ejecución hasta una rutina especial de software llamada administrador de interrupciones o de excepciones. La acción llevada a cabo por el procesador en respuesta a la interrupción o excepción se llama servir o mantener la instrucción o la excepción. Las interrupciones y las excepciones son muy similares: la principal diferencia es que las primeras son asíncronas (no se puede preveer su aparición; normalmente se producen por señales de hardware externo) y las segundas son síncronas (se puede preveer su aparición; ocurren normalmente cuando el procesador detecta algún error, ya sea de seguridad, de división por cero...). Cuando se recibe alguna interrupción o se detecta alguna excepción, el programa en ejecución se suspende mientras el procesador ejecuta el administrador de interrupciones o de excepciones. Cuando la ejecución del administrador se completa, el procesador retoma la ejecución del programa interrumpido. Todo esto ocurre sin perder continuidad en el programa, excepto si no es posible la recuperación desde una excepción o si una interrupción causa que no se pueda terminar la ejecución del programa interrumpido.
Para ayudar en el manejo de instrucciones y excepciones, se definen condiciones de excepciones y de interrupciones que requieren un manejo especial desde el procesador. A cada condición se le asigna un único número de identificación, llamado vector. El procesador usa el vector asignado a la excepción o interrupción como un índice en la tabla de descriptores de interrupciones (IDT). La tabla proporciona un punto de entrada a un administrador de interrupciones o de excepciones. El rango disponible para los vectores es de 0 a 255. Los vectores desde el 0 al 31 está reservados por las arquitecturas Intel 64 y IA-32 para las excepciones y interrupciones definidas por la arquitectura, pero no todos los vectores de ese rango tienen una función definida. Los vectores no asignados en ese rango están reservados igualmente, así que no se pueden usar. El resto de vectores (desde el 32 hasta el 255) se pueden usar, y normalmente las interrupciones se asignan a dispositivos externos de E/S para activarlos y que puedan mandar interrupciones al procesador a través de un mecanismo de interrupción externo por hardware. El procesador puede recibir interrupciones de dos fuentes; externas (generadas por hardware), o internas (generadas por software). Las interrupciones externas se reciben a través de pines del procesador o a través del APIC local.
Cualquier interrupción externa que se entrega al procesador es llamada interrupción por hardware, y no puede ser enmascarada.
La instrucción INT n permite interrupciones generadas desde software interno suplantando un número de vector de interrupción por un operando. Por ejemplo, INT 35 fuerza una llamada implícita al administrador de interrupciones para las interrupción 35. Cualquier vector de interrupción desde el 0 hasta el 255 puede ser usado como parámetro en ella. Si el vector NMI predefinido del procesador se está usando, el procesador producirá una respuesta diferente a cuando la interrupción NMI se genera de forma normal. Si el numero de vector 2 (el vector NMI) se usa para esa instrucción, el administrador de interrupciones NMI se invoca pero el hardware del administrador del NMI del procesador no se activa. Las interrupciones generadas por software con la instrucción INT n no se puede enmascarar por la bandera IF del registro EFLAGS.
El procesador recibe excepciones de tres fuentes: de las detecciones de errores de programas del procesador (el procesador genera una o más excepciones cuando detecta errores durante la ejecución de aplicaciones o del sistema operativo), de las generadas por software (las instrucciones INTO, INT 3 Y BOUND generan excepciones por software; INT 'n' permite emularlas), y de comprobaciones de la máquina (los Pentium y los P6 proporcionan mecanismos internos y externos de comprobación de máquina para comprobar la operación del chip hardware interno y las operaciones del bus).
Las excepciones se clasifican en faltas, trampas y abortos dependiendo de la forma en que son reportados y si la instrucción que la causó puede ser reiniciada sin pérdida de la continuidad del programa. Una falta es una excepción que generalmente se puede corregir y no provoca pérdida de continuidad en el programa. Cuando se reporta una falta, el procesador restaura el estado de la máquina al estado anterior para reiniciar la instrucción que la provocó. Una trampa es una excepción que se reporta inmediatamente después de ejecutar la instrucción que la provocó, y tampoco provoca pérdidas en la continuidad de la ejecución. Un aborto es una excepción que no siempre se reporta a la localización precisa de la instrucción que la provocó, y no permite el reinicio del programa que causó la excepción. Los abortos son usados para reportar errores graves, como errores de hardware o valores inconscientes o ilegales en las tablas del sistema.
Para permitir el reinicio del programa después del mantenimiento de una excepción o de una interrupción, todas las excepciones (excepto los abortos) y todas las interrupciones reportan excepciones o interrupciones en un límite de instrucción. Para las instrucciones de falta de clase, el retorno del puntero de instrucción apunta a la instrucción que provocó la falta. Por lo tanto, cuando un programa se reinicia después del mantenimiento de una falta, la instrucción culpable se reejecuta. Cuando ocurre una excepción de trampa de clase, el retorno del puntero de instrucción apunta a la instrucción siguiente a la culpable. Las excepciones de aborto de clase no soportan reinicios fiables del programa. Los administradores de abortos están diseñados para recolectar información de diagnóstico sobre el estado del procesador cuando la excepción ocurre, y entonces apaga la aplicación y el sistema como puede. Las interrupciones soportan reinicio de los programas interrumpidos sin perder continuidad. El puntero de instrucción de retorno guardado para una interrupción apunta a la siguiente instrucción a ejecutar en el límite de la instrucción donde el procesador atendió a la interrupción. Si la instrucción que se acaba de ejecutar tiene un prefijo repetido, la interrupción se atenderá al final de la iteración en curso con el conjunto de registros para ejecutar la siguiente iteración.
La interrupción que no puede ser enmascarada (NMI) se puede generar de dos formas: mediante un pin NMI externo, o cuando el procesador recibe un mensaje en el bus del sistema con un modo de entrega NMI. Cuando se recibe una NMI desde alguna de estas dos fuentes, el procesador la atiende inmediatamente llamando al administrador NMI apuntado por el vector de interrupciones número 2. El procesador también activa un conjunto de condiciones hardware para asegurar que no haya otras interrupciones, incluyendo interrupciones NMI, hasta que el administrador NMI completa su ejecución.
El procesador inhibe la creación de algunas interrupciones, dependiendo del estado del procesador y de las banderas IF y RF del registro EFLAGS. La bandera IF puede desactivar el servicio de interrupciones enmascaradas por hardware recibidas en el pin INTR del procesador a través del APIC local. Si la bandera está a cero, el procesador inhibe las interrupciones en ese pin. La bandera IF no afecta a las NMIs. La bandera RF en el registro EFLAGS controla la respuesta del procesador a las condiciones de breakpoint de instrucción. Cuando está activo, previene un breakpoint de instrucción generando una excepción de depuración; cuando no esta activo, los breakpoints de instrucción generarán las excepciones de depuración. La principal función de RF es prevenir al procesador de caer en un bucle de excepciones de depuración en un breakpoint de instrucción.
Una tabla de descriptores de interrupciones (IDT) asocia cada vector de excepción o interrupción con un descriptor de puerta para el procedimiento usado para servir a la excepción o interrupción asociada. Como las GDTs o las LDTs, la IDT es un array de descriptores de 8 bytes (en modo protegido). Para formar un índice en el IDT, el procesador escala el vector de excepción o de interrupción por ocho. Como solo hay 256 vectores de interrupción o de excepción, el IDT no necesita contener más de 256 descriptores (puede contener menos). La base de direcciones del IDT debe estar alineada en un límite de 8 bytes para maximizar el rendimiento de llenado de los caches.
La IDT contiene tres tipos de descriptores de puertas: de tareas, de interrupciones, y de trampa. Estos dos últimos son muy similares a las puertas de llamada, excepto en que el procesador administra la bandera IF del registro EFLAGS.
El procesador maneja las llamadas a los administradores de excepciones y a interrupciones de forma similar a las llamadas a procedimientos con CALL. Cuando se responde a una excepción o a una interrupción, el procesador usa el vector de excepción o de interrupción como un índice hacia un descriptor en el IDT. Si el índice apunta a una puerta de interrupción o a una puerta trampa, llama al administrador de interrupciones o de excepciones de manera similar que un CALL a una puerta de llamada. Si el índice apunta a una puerta de tarea, el procesador ejecuta un cambio de tarea al administrador de excepciones o de interrupciones de forma similar al CALL. Una puerta de interrupciones o de trampa referencia a un procedimiento de administración de excepciones o de interrupciones que se ejecuta en el contexto de el programa en ejecución. El selector de segmento de la puerta apunta a un descriptor de segmentos para un segmento de código ejecutable en cualquier GDT o en la LDT actual. El campo offset del descriptor de puerta apunta al principio del procedimiento de administración de excepciones o interrupciones. Cuando se accede a un administrador de excepciones o de interrupciones a través de una puerta de tarea en el IDT, resulta un cambio de tarea. Administrar una excepción o una interrupción en tareas separadas tiene múltiples ventajas: El contexto entero del programa interrumpido se guarda automáticamente, un nuevo TSS permite la administración para usar una nueva pila de privilegios de nivel 0, o que el administrador puede ser aislado de otros programas separándolo en el espacio de direcciones.
Cuando una condición de excepción está relacionada a un segmento específico, el procesador genera un código de error en la pila del administrador de excepciones. El código tiene un formato especial, y se parece a un selector de segmento; sin embargo, a diferencia de una bandera TI y un campo RPL, el código de error contiene 3 banderas (de evento externo, de localización de descriptor, y de GDT/LDT). El formato de este código es distinto para las excepciones de falta de páginas.
El mantenimiento de excepciones e interrupciones en el modo de 64 bits es muy parecido al descrito, excepto en esto: todos los administradores de interrupciones apuntadas por el IDT están en código de 64 bits; el tamaño de los pushes de interrupciones de pila se fijan en 64 bits; el puntero a pila actúa incondicionalmente sobre interrupciones; la nueva SS se pone a cero si hay cambios en el CPL; cambia el comportamiento de IRET; hay un nuevo mecanismo de cambio de pila de interrupciones; el alineamiento de los marcos de la pila de interrupciones es diferente.

jueves, 18 de diciembre de 2008

Protección

En el modo protegido, la IA-32 y Intel 64 proporcionan un mecanismo de protección que opera en el nivel de segmentación y en el de paginamiento. Este mecanismo permite limitar el acceso a ciertos segmentos o páginas basándose en los niveles de privilegios (4 niveles de privilegios para segmentos, 2 para páginas). La protección por segmentación o por paginación puede ser usada en todos los niveles del entorno de desarrollo del software para ayudar en la localización y la detección de problemas de diseño y de errores. También puede ser incorporado en productos finales para ofrecer más robustez a los sistemas operativo, utilidades de software, y aplicaciones de software. Cuando el mecanismo de protección está activo, cada referencia a la memoria es revisada para verificar que satisface varias revisiones de protección. Todas las revisiones se hacen antes de que empiece el ciclo de memoria; ningún error se convierte en excepción. Como las revisiones son ejecutadas en paralelo con la traducción de direcciones, no hay ningún fallo del rendimiento. Los tipos de revisiones son: revisiones de los límites, revisiones de los tipos, revisiones de los niveles de privilegios, restricciones del dominio direccionable, restricciones del procedimiento de entry-points, restricciones del conjunto de instrucciones. Todas los errores de protección resultan en generar una excepción.
Para activar el modo protegido, se debe activar la bandera PE del registro CR0, que activa automáticamente el mecanismo de protección de segmentos. Una vez en modo protegido, no hay bit de control para desactivarlo o activarlo. La parte de mecanismo de protección de segmentos está basado en los niveles de privilegios, y la forma de desactivarlo es dando a todos los selectores y descriptores de segmentos los máximos privilegios (nivel 0). Esto desactiva todas las barreras entre segmentos, pero las otras revisiones de protección (como revisiones de límites, de tipos...) se llevan a cabo igual. La protección del nivel de paginación se activa automáticamente cuando se activa la paginación, y tampoco hay bit de control. Sin embargo, se puede desactivar de dos formas: poniendo a cero la bandera WP del registro de control CR0, o poniendo a uno la bandera de lectura/escritura y la de usar/supervisar para cada entrada del directorio de paginación y de la tabla de paginación. Esto permite que se pueda escribir y usar la página, y por lo tanto acaba con la protección del nivel de paginación.
El campo límite de un descriptor de segmentos previene a los programas o procedimientos de direccionar posiciones de memoria que estén fuera del segmento. El valor efectivo del límite depende de la bandera G (granulación). Para segmentos de datos, el límite depende de las banderas E (dirección de Expansión) y B. Si la bandera G está inactiva, el límite efectivo es el valor del límite del campo de 20 bits en el descriptor de segmento. Aquí, el rango es de 0 a FFFFFH (1 MByte). Si está activada, el procesador escala el valor del límite del campo en un factor de 2^12 (4 KBytes), por lo tanto el rango del límite efectivo es de FFFH (4 KBytes) a FFFFFFFFH (4 GBytes). Cuando se usa este escalado, a los 12 bits más bajos del offset de un segmento no se les aplica la revisión de límites. En el modo de 64 bits, el procesador no realiza las comprobaciones de límites de los segmentos de código o de datos en tiempo de ejecución. Sin embargo, realiza comprobaciones de los límites de las tablas de descriptores.
Los descriptores de segmento contienen información de tipo en dos lugares: en la bandera S, y en el campo de tipo. El procesador usa esta información para detectar errores en la programación que resultan en un intento de usar un segmento o puerta incorrecto o de una forma no prevista. La bandera S indica si el descriptor es un tipo de sistema, o si es un tipo de código o dato. El campo de tipo proporciona 4 bits adicionales para usarlos en definir varios tipos de descriptores de código, datos y sistema. El procesador examina la información de tipo varias veces cuando se opera con selectores y descriptores de segmento.
El mecanismo de protección de segmentos del procesador reconoce 4 niveles de privilegios numerados de 0 a 3 (0 máximos privilegios, 3 mínimos). Normalmente lo único que tiene privilegios 0 es el código crítico, como el núcleo (kernel) de un sistema operativo. El procesador usa este mecanismo para evitar que un programa con privilegios bajos acceda a un segmento que requiere privilegios mayores, excepto en situaciones controladas. Si detecta que se está intentando acceder a un segmento sin los privilegios adecuados, el procesador generará una excepción.
Para acceder a los operandos en un segmento de datos, el selector de segmento de ese segmento tiene que ser cargado en los registros de segmento de dato (DS, ES, FS, o GS) o en el registro de segmento de pila (SS). Antes de cargar un selector de segmento en un registro de segmento, se hace una comprobación de privilegios comparando el nivel de privilegios del programa en ejecución, el RPL del selector de segmento, y el DPL del descriptor de segmento del segmento. El procesador carga el selector en el registro de segmento si el DPL es numéricamente superior o igual al CPL y al RPL. Si no, se genera una falta general de protección y el registro del segmento no se carga.
Para transferir el control del programa de un segmento de código a otro, el selector de segmento del segmento de destino se tiene que cargar en el registro de código de segmento (CS). Como parte del proceso de carga, se examina el descriptor de segmento del segmento de código de destino y hay comprobaciones de privilegios. Si estas comprobaciones son correctas se carga el registro CS, y el control del programa pasa al segmento de código nuevo, y la ejecución del programa comienza en la instrucción indicada por el registro EIP. Para administrar control de acceso a segmentos de código con diferentes niveles de privilegios, el procesador proporciona un conjunto especial de descriptores llamados descriptores de puertas. Hay 4 tipos: de puertas de llamada (facilitan transferencias de control entre distintos niveles de privilegios), de puertas trampa, de puertas de interrupciones, y de puertas de tareas. Para retornar de una llamada a un procedimiento se usa RET. Esta instrucción está prevista para ejecutarse cuando se llama a un procedimiento con la instrucción CALL ya que guarda un puntero en la pila que indica la instrucción de retorno, sin embargo JMP salta pero no guarda ningún puntero de retorno. Las instrucciones SYSENTER y SYSEXIT fueron incluidas en la arquitectura IA-32 en los Pentium II con el propósito de acelerar las llamadas al sistema operativo o a los procedimientos de ejecución. Con SYSENTER se puede acceder al sistema operativo o ejecutar procedimientos en privilegios de nivel 0, teniendo inicialmente los mínimos privilegios (nivel 3). SYSEXIT es una instrucción prevista para usar con privilegios nivel 0, para acelerar el retorno al código de nivel 3 de privilegios. SYSENTER se puede invocar desde los 4 niveles de privilegios, pero SYSEXIT sólo desde el nivel 0. Cuando el procesador está en modo protegido, valida todos los punteros para asegurar la protección entre segmentos y para mantener el aislamiento entre los niveles de privilegios. La validación de los punteros consiste en una serie de comprobaciones: Comprueba los derechos de acceso para determinar si el tipo de segmento es compatible con su uso, comprueba los derechos de lectura/escritura, comprueba si el offset del puntero excede el límite del segmento, comprueba si el proveedor del puntero tiene privilegios para acceder al segmento, y comprueba la alineación del offset. El procesador ejecuta automáticamente las 3 primeras comprobaciones durante la ejecución de las instrucciones. La cuarta se tiene que pedir por software, y la quinta se activa automáticamente cuando en el nivel 3 se activan las comprobaciones de alineación. Esto no afecta al aislamiento entre los niveles de privilegios.
La protección en el nivel de páginas se puede usar sola o aplicada a los segmentos. Cuando se usa esta protección (la de páginas) con modelo de memoria plano (sin segmentación), permite proteger al código supervisor y a sus datos (sistema operativo) del código de usuario y de sus datos (aplicaciones). Cuando se combinan la protección en nivel de páginas con la de nivel de segmentos, la protección de lectura/escritura del nivel de páginas proporciona una mayor granularidad de protección dentro de los segmentos. Con la protección en el nivel de paginación, en cada referencia a memoria se verifica que las comprobaciones de protección sean correctas. Todas estas comprobaciones se hacen antes de que empiece el ciclo de memoria, y cualquier fallo puede provocar que no comience el ciclo, y generar una excepción de fallo de página. La información de protección para páginas está en dos banderas en un directorio de paginación o en una entrada de la tabla de paginación: la bandera de lectura/escritura (bit 1) y la bandera de usuario/supervisor (bit 2). Las comprobaciones de protección se aplican a las tablas de paginación de primer y segundo nivel. El mecanismo de protección proporciona acceso restringido a páginas basado en 2 niveles de privilegios: modo supervisor (máximos privilegios, para el sistema operativo, datos protegidos...), y modo usuario (mínimos privilegios, para aplicaciones y datos). También reconoce dos tipos de páginas: las de acceso para sólo lectura, y las de acceso para lectura/escritura.
Cuando la paginación está activada, el procesador evalúa la protección de segmentación primero y después la de paginación. Si detecta un fallo en cualquiera de las comprobaciones, el acceso a memoria no se lleva a cabo y se genera una excepción. Las protecciones del nivel de páginas no pueden ser usadas para invalidar las de nivel de segmentos.
Además de la protección de nivel de páginas ofrecido por las banderas U/S y R/W, el aumento de las estructuras de paginación PAE proporcionan el bit de execute-disable. Este bit ofrece una protección adicional a las páginas de datos. Un procesador Intel 64 o un IA-32 con la capacidad del bit de desactivación de ejecución puede prevenir páginas de datos de ser usados por software malicioso que ejecuta código. Esta capacidad se ofrece en el modo 32 bits con PAE activado, y en el modo IA-32e. Mientras que la capacidad de ese bit no introduce nuevas instrucciones, requiere sistemas operativos para usar un entorno con PAE activado y para establecer una política de protección granular de páginas en las páginas de la memoria. Si el bit está activado, esa página puede ser usada sólo como datos. Un intento de ejecución de código de una página en memoria con el bit activo causa una excepción de fallo de la página. Sólo las páginas de 4 KBytes y las de 2 MBytes son soportadas por el bit de desactivación de paginación. Existen otros mecanismos de protección de nivel de paginación que se pueden aplicar a páginas en memoria independientemente de ese bit. Para detectar si un procesador tiene la capacidad del bit de desactivación de ejecución, se usa la instrucción CPUID (CPUID.80000001H. EDX[bit 20] = 1 indica que el bit está disponible). Cuando el bit está activado (IA32_EFER.NXE = 1), las condiciones para que ocurra un fallo en una página incluye las mismas condiciones que se aplica a un Intel 64 o a un IA-32 sin el bit activo, y añade una nueva: una instrucción para obtener una dirección lineal que traduzca direcciones físicas en páginas de memoria con el bit de desactivación de ejecución activado.

jueves, 4 de diciembre de 2008

Administración de memoria en modo protegido

La administración de memoria facilitada por la arquitectura IA-32 está dividida en dos partes: segmentación y paginación. La segmentación proporciona un mecanismo para aislar código, datos, o módulos de pila individuales para que múltiples programas puedan ejecutarse en el mismo procesador sin interferirse entre ellas, dividiendo el espacio de memoria direccionable en espacios de direcciones protegidos más pequeños llamados segmentos. La paginación proporciona un mecanismo para implementar un sistema de memoria virtual convencional paginada donde las secciones del entorno de ejecución del programa sean mapeadas en la memoria física que necesite. La paginación se puede usar también para proporcionar aislamiento entre múltiples tareas. Cuando se opera en modo protegido, siempre se debe usar alguna forma de segmentación, sin embargo la paginación es opcional.
Estos dos mecanismos se pueden configurar para dar soporte a sistemas que ejecuten una única tarea, a sistemas multitarea, o a sistemas multiprocesador que usan memoria compartida.
Todos los segmentos del sistema están en el espacio de direcciones lineales del procesador. Para localizar un byte en un segmento particular, se deben proporcionar una dirección lógica (o puntero), que consiste en un selector de segmento y un offset. El selector de segmento es un identificador único para un segmento, y el offset localiza el byte dentro del segmento.
Los mecanismos de segmentación soportados por la arquitectura IA-32 se pueden implementar en una gran variedad de diseños de sistemas. Desde un sistema que los usa para proteger a los programas, hasta modelos multisegmentados que emplean la segmentación para crear robustos entornos de operación en cuyos múltiples programas y tareas necesitan ejecutarse con seguridad.
En el modo IA-32e de la arquitectura Intel 64, los efectos de la segmentación dependen de si el procesador se esté ejecutando en el modo de compatibilidad o en el modo de 64 bits. En el primero la segmentación actúa como comenté antes, pero en el segundo generalmente no existe segmentación; existe un espacio de direcciones lineales de 64 bits. El procesador trata la base de segmentación de CS, DS, ES y SS como si fueran cero, creando una dirección lineal equivalente a la dirección efectiva. Los segmentos FS y GS son excepciones; estos registros de segmento se pueden usar como una base de registros adicional para cálculos de direcciones lineales. Facilitan el direccionamiento a datos locales y aseguran las estructuras de datos del sistema operativo.
La paginación se puede usar con cualquier modelo de segmentación descrito. Consiste en dividir el espacio de direcciones lineales (en los cuales sus segmentos han sido mapeados) en partes pequeñas, o páginas. Estas páginas del espacio de direcciones lineal se mapea a páginas en el espacio físico de direcciones. Del mismo modo, la memoria es dividida en trozos del mismo tamaño que las páginas llamados marcos de página. Entonces, la cantidad de memoria desperdiciada por un proceso es el final de su última página, lo que minimiza la fragmentación interna y evita la externa. Este mecanismo de paginación ofrece facilidades de protección de niveles a las páginas que se puede usar en conjunto con el sistema de protección que ofrece la segmentación.
En modo protegido, la arquitectura IA-32 ofrece un espacio de direcciones físico normal de 4 GBytes (2^32 bytes). Este espacio no está segmentado, con direcciones contínuas de 0 a FFFFFFFFH. Este espacio puede ser mapeado a memoria de lectura/escritura, de sólo lectura, y memoria mapeada de E/S. Las facilidades para mapear memoria se pueden usar para dividirla en segmentos o páginas.
En el nivel de la arquitectura del sistema en modo protegido, el procesador usa dos modos de traducción de direcciones para conseguir la dirección de la memoria física: la traducción de direcciones lógicas, y la paginación del espacio de direcciones lineales. Incluso con el mínimo uso de la segmentación, a cada byte en el espacio de direcciones del procesador se accede con una dirección lógica, que consiste en un selector de segmento de 16 bits y un offset de 32. El procesador traduce cualquier dirección lógica en una dirección lineal. Una dirección lineal es una dirección de 32 bits en el espacio de direcciones lineales del procesador. Como el espacio de direcciones físicas, el espacio de direcciones lineales no está segmentado, es de 2^32 bytes, y las direcciones están en el rango de 0 a FFFFFFFFH. El espacio de direcciones lineales contiene todos los segmentos y tablas del sistema definidos por él. Si la paginación no está activada, el procesador mapea la dirección lineal directamente a una dirección física. Si está activada, se usa un segundo nivel de traducción de direcciones. En el modo IA-32e de un procesador Intel 64 se usan los mismos métodos de traducción, sin embargo en el modo de 64 bits, el offset y la dirección base del segmento son de 64 bits en vez de 32.
Cuando la bandera S (tipo de descriptor) de un descriptor de segmento está a cero, el descriptor es un descriptor de sistema. El procesador reconoce los siguientes tipos de descriptores de sistema: Descriptores de segmentos de tablas de descriptores locales (LDT, de local descriptor-table), descriptores de segmentos de estado de tarea (TSS, de task-state segment), descriptores de puertas de llamada, descriptores de puertas de interrupción, descriptores de puertas de trampa, y descriptores de puertas de tarea. Una tabla de descriptores de segmento es una selección de descriptores de segmentos, variable en longitud y puede contener hasta 2^13 descriptores de 8 bytes. Hay dos tipos de tablas de descriptores: La tabla de descriptores global (GDT, de global descriptor table), y la tabla de descriptores local (LDT, de local descriptor table). Cada sistema tiene que tener una GDT definida que se usará por todos los programas del sistema, y opcionalmente debe de definir una o más LDTs.
En el modo IA-32e de Intel 64, una tabla de descriptores de segmento puede contener hasta 2^13 descriptores de 8 bytes (como anteriormente), sin embargo los descriptores de sistema se expanden hasta 16 bytes (ocupando el espacio de 2 entradas). El GDTR y el LDTR (los registros del GST y del LDT, respectivamente) también son expandidos para abarcar direcciones base de 64 bits.
Cuando se opera en modo protegido, la IA-32 permite mapear directamente el espacio de direcciones lineales a una memoria física grande (por ejemplo, 4 GBytes de RAM), o indirectamente (usando paginación) a una memoria física más pequeña. Este segundo método de mapear el espacio lineal de direcciones se llama memoria virtual. Cuando se usa la paginación, el procesador divide el espacio de direcciones lineales en páginas de longitud fija (de 4 KBytes, 2 MBytes, o 4 MBytes) que puede ser mapeada en memoria física o almacenada en disco. Cuando un programa referencia una dirección lógica en memoria, el procesador traduce la dirección a una dirección lineal y entonces usa el mecanismo de paginación para traducirla a la correspondiente dirección física.
El mecanismo PAE (physical address extension) de paginamiento soporta direccionamiento físico de 36 bits, y fué introducido en la arquitectura IA-32 del Pentium Pro. La bandera PAE en el registro CR4 activa el mecanismo PAE y extiende las direcciones físicas de 32 bits a 36. El procesador proporciona direcciones de pines de línea adicionales para los bits adicionales. Para usar esta opción deben estar activos la bandera PG del registro CR0 (activa el paginamiento), y la bandera PAE del registro CR4. El procesador sólo soporta dos longitudes de paginamiento: 4 KBytes y 2 MBytes.
El mecanismo de paginamiento PSE-36 proporciona un método alternativo (al PAE) de extensión de direccionamiento de la memoria física a 36 bits. Este mecanismo usa el modo PSE (page size extension) y una tabla de directorios de páginas modificado para mapear páginas de 4 MBytes en un espacio de direcciones físicas de 64 GBytes. El procesador proporciona 4 pines de direccionamiento adicionales para los bits adicionales. Este mecanismo se introdujo en la IA-32 con el Pentium III.
La arquitectura Intel 64 expande las estructuras de paginamiento de la PAE a soportar potencialmente mapeado de una dirección lineal de 64 bits a una dirección física de 52. Cuando está activado IA-32e, la traducción de direcciones lineales a direcciones físicas es diferente que si está activado PAE en modo protegido. En este caso se usa hasta 4 niveles de paginamiento de estructuras de datos. Una nueva tabla de mapeo de páginas, y la tabla de paginamiento de map de nivel 4 (tabla PML4), están añadidas encima de la tabla de punteros de las páginas. La tabla PML4 se usa en la traducción de páginas sólo en el modo IA-32e, no tiene otro uso cuando IA-32e o PAE está desactivado.
Los mecanismos de segmentación y paginamiento proporcionados por la IA-32 soportan un conjunto de enfoques para administración de memoria. Cuando la segmentación y el paginamiento se combinan, los segmentos se pueden mapear a páginas de las dos formas. Para implementar un entorno de direccionamiento no segmentado, por ejemplo, todo el código, datos, y módulos de pila se pueden mapear a uno o más segmentos largos (de más de 4 GBytes) que comparte el mismo rango de direcciones lineales. Aquí los segmentos prácticamente son invisibles para las aplicaciones y para el sistema operativo. Si se usa el paginamiento, el mecanismo puede mapear un solo espacio de direcciones lineales (contenido en su propio segmento) a memoria virtual. O ese programa puede tener su propio espacio de direcciones lineales largo (contenido en su propio segmento), el cual es mapeado en memoria virtual a través de su propio directorio de páginas y de su propio conjunto de tablas de paginamiento.
Los segmentos pueden ser más pequeños que la longitud de la página; si un segmento así está contenido en una página que no está compartida con otro segmento, la memoria extra será desaprovechada. Los segmentos pueden contener el principio y el final de una página, y una página puede contener el principio y el final de un segmento; la arquitectura no fuerza ninguna correspondencia entre ambos, sin embargo es mucho más eficiente y más simple si se fuerza a que haya alguna.
El procesador guarda el directorio de página más reciente y las entradas a la tabla de páginas en caches llamados TLBs (de translation lookaside buffers). La familia P6 y los Pentium tienen TLBs separados para los datos y las caches de instrucción. La mayoría del paginamiento se realiza usando los contenidos de los TLBs, y son inaccesibles a las aplicaciones, programas y tareas. Sólo el sistema operativo o procedimientos ejecutados con privilegios de máximo nivel (nivel 0) pueden acceder a ellos.

lunes, 1 de diciembre de 2008

Vistazo general sobre la arquitectura del sistema

La arquitectura IA-32 proporciona un amplio soporte para sistemas operativos y desarrollo de software de sistemas. Este soporte ofrece múltiples modos de operación, incluyendo modo real-address(permite un entorno de programación del procesador Intel 8086 con unas pocas extensiones), modo protegido (es el modo nativo de operación del procesador), modo virtual 8086 (permite al procesador ejecutar software 8086 en entorno protegido, y multitarea), y modo de administración de sistemas (es una característica estándar en la arquitectura de todos los procesadores IA-32. Proporciona un sistema operativo o lo ejecuta de manera transparente).
La arquitectura Intel 64 soporta casi todas las facilidades de programación de sistemas disponibles en IA-32 y los amplía a un nuevo modo operativo (modo IA-32e) que soporta un entorno de programación de 64 bits. Este nuevo modo permite al software operar en uno de dos sub-modos: el modo de 64 bits, que soporta sistemas operativos y programas de 64 bits; o el modo compatible que permite ejecutarse a la mayoría del software, coexistiendo con las aplicaciones en un sistema operativo de 64 bits.
El sistema de niveles de IA-32 incluye características útiles en estas operaciones: administración de memoria, protección de módulos de software, multitarea, edición de excepciones e interrupciones, multiprocesamiento, administración de la cache, recursos hardware y administración de energía, y depurar y monitorizar el rendimiento.
Cuando se opera en modo protegido, todos los accesos a memoria pasan o a través de la global descriptor table (GDT) o a través de una local descriptor table (LDT) opcional. Estas tablas contienen entradas llamadas descriptores de segmento. Estos descriptores proporcionan la dirección base de los segmentos además de permisos de acceso, tipos e información útil. Cada descriptor de segmento tiene un selector de segmentos asociado, que proporciona al software que los usa un index en la GDT o LDT, una bandera global/local (depende de si se escogió GDT o LDT), y derechos de acceso a la información. Para acceder a un byte en un segmento, se necesita el selector y un offset. El selector proporciona acceso al descriptor de segmento al segmento; desde el descriptor, el procesador obtiene la dirección base del segmento en el espacio lineal de direcciones, y el offset proporciona la localización del byte relativo a la dirección base. Este mecanismo se puede usar para acceder a cualquier código válido, datos, o segmentos de pila, proporcionado el segmento el cual es accesible desde el nivel de privilegios (CPL, current privilege level) en el que está operando el procesasdor. El CPL se define como el nivel de protección del código del segmento que se está ejecutando.
Además de código, datos, y segmentos de pila que completan el entorno de ejecución de un programa o procedimiento, la arquitectura define 2 segmentos: el segmento task-state (TSS) y el LDT. El GDT no se considera un segmento porque no es accedido por medios de selector de segmento o descriptores de segmento. Los TSSs y LDTs tienen descriptores de segmento definidos para ellos. Esta arquitectura define un conjunto de descriptores especiales llamados puertas (puertas, puertas de interrupciones, puertas trampa, y puertas de tarea), que provocan gateways protegidos a procedimientos del sistema y editores que operan en un nivel de privilegios diferente del de la aplicación. Si el acceso de destino está permitido, el procesador proporciona un selector de segmento para el segmento de destino y un offset en el segmento del código desde la puerta de llamada. Si esto requiere un cambio de privilegios, el procesador los cambia a la pila para conseguir el nivel requerido. El selector de segmentos para la nueva pila se obtiene desde el TSS para la tarea que se está ejecutando. Además las puertas facilitan las transiciones entre segmentos de código de 16 y 32 bits, y entre el modo de 64 bits y el modo compatible.
El TSS (Task-state segments) define el estado del entorno de ejecución para una tarea. Incluye el estado de registros de propósito general, registros de segmentos, registros EFLAGS, el registro EIP, y los selectores de segmentos con punteros a pila para tres segmentos de pila (una pila por cada nivel de privilegios). También incluye el selector de segmentos para el LDT asociado con la tarea y la dirección base de la tabla de paginación. Todo programa ejecutado en modo protegido lleva consigo el contexto de una tarea. El selector de segmento para el TSS para la tarea en ejecución se guarda en el registro de tareas. El método mas simple para cambiar a una tarea es hacer una llamada o saltar a una nueva tarea. Al cambiar a una tarea, el procesador hace lo siguiente:
- guarda el estado de la tarea actual en el TSS actual
- carga el registro de tareas con el selector de segmento para la nueva tarea
- accede al nuevo TSS a travñes del descriptor de segmento en el GDT
- carga el estado de la nueva tarea desde el nuevo TSS en los registros de propósito general, los registros de segmento, el LDTR, el registro de control CR3, el registro EFLAGS, y el registro EIP.
- empieza la ejecución de la nueva tarea
A una tarea también se puede acceder mediante una puerta de tarea. Es similar a una puerta de llamada, excepto en que proporciona más acceso a un TSS que un segmento de código.
Los cambios de tarea hardware no están soportados en el modo IA-32e, sin embargo los TSSs continúan existiendo. La dirección base de un TSS es especificada mediante un descriptor. Un TSS de 64 bits coge la siguiente información importante para operaciones de 64 bits: direcciones de punteros a pila para cada nivel de privilegios, direcciones de punteros para la tabla de interrupciones de pila, y direcciones de offset para el bitmap de permisos de E/S.
Las interrupciones externas, las de software y las excepciones son editadas a través de la interrupt descriptor table (IDT). Esta tabla guarda una colección de puertas descriptor que proporcionan acceso a editores de interrupciones y de excepciones. Como el GDT, el IDT no es un segmento. La dirección de la página para la base de la IDT está en el registro IDT (IDTR). Las puertas descriptor en la IDT pueden ser puertas descriptoras de interrupcion, de trampa, o de tarea. Para acceder al editor de interrupciones o de excepciones, el procesador recibe un vector de interrupción desde el hardware interno, un controlador externo de interrupción, o desde el software. El vector de interrupción provoca un index dentro de la IDT. Si la puerta seleccionada es una puerta de interrupción o una puerta de trampa, el procedimiento del editor asociado se accede de manera similar a llamar a un procedimiento a través de un cambio de tarea.
En el modo IA-32e, los descriptores de interrupciones y el IDTR son expandidos a 16 bytes para soportar direcciones de base 64 bits. Esto es cierto para el modo de 64 bits y el modo compatible. Las puertas de tarea no están soportadas.
La arquitectura soporta o el direccionamiento físico directo de la memoria, o la memoria virtual. Cuando se usa lo primero, se trata una dirección lineal como si fuera una dirección física. La base de direcciones físicas del directorio de páginas está en el registro de control CR3. Una entrada en un directorio de páginas contiene la dirección física de la base de una tabla de páginas, derechos de acceso y información de administración de memoria. Una entrada en la tabla de páginas contiene la dirección física de un marco de páginas, derechos de acceso y información de administración de memoria.
En el modo IA-32e, la memoria física lineal es administrada por un conjunto de estructuras de datos de sistema. En el modo de compatibilidad y de 64 bits, son usados 4 niveles de estructuras de datos de sistema, que incluyen: El map de páginas nivel 4 (PML4), una entrada en una tabla PML4 contiene direcciones físicas de la base de una tabla de punteros a directorios de páginas, derechos de acceso, e información de administración de memoria. La dirección física base del PML4 está en CR3; un conjunto de punteros a directorios de páginas; un conjunto de directorios de páginas; y un conjunto de tablas de páginas.
Para ayudar en la inicialización del procesador y el control de operaciones del sistema, la arquitectura proporciona banderas de sistema en el registro EFLAGS y varios registros de sistema:
- Las banderas del sistema y los campos IOPL en el registro EFLAGS controlan tareas y modos de cambio, editores de interrupciones, tracing de instrucciones, y derechos de acceso.
- Los registros de control (CR0, CR2, CR3 y CR4) contienen una variedad de banderas y campos de datos para controlar operaciones de niveles de sistema.
- Los registros de debug permiten establecer breakpoints para usarlos en la depuración de programas y software del sistema.
- Los registros GDTR, LDTR, y IDTR contienen las direcciones de páginas y los límites para sus respectivas tablas.
- El registro de tareas contiene la dirección de memoria dle TSS para la tarea en curso.
- Registros de modelos específicos (son un grupo de registros disponibles para el sistema operativo o para procedimientos. Controlan extensiones de depuración, la comprobación de la arquitectura de la máquina, etc).
En el modo IA-32e, los 4 registros de tablas de descriptores del sistema (GDTR, IDTR, LDTR y TR (task register)) están expandidas en hardware para que quepan direcciones de 64 bits. Ahora CR8 está disponible, que permite el acceso de lectura/escritura al registro de prioridad de tareas (TPR) de modo que el sistem operativo pueda controlar las clases de prioridad de las interrupciones externas.