¡Esta es una revisión vieja del documento!
Tabla de Contenidos
How To cambio de tareas en IA-32e
Introducción
En la arquitectura IA-32 (32 bits), el procesador provee un mecanismo de cambio de tareas automático por hardware, haciendo uso de las estructuras TSS y de los descriptores TSS que se cargan en la GDT. El procesador se encarga de hacer un cambio de contexto entre una tarea y la subsiguiente, almacenando la información en la TSS de cada tarea.
Task Register (TR) en IA-32
Los contextos de las diferentes tareas se almacenan en los Task State Segments (TSS), uno por tarea. La parte visible de 16 bits del registro TR incluye en los bits 15-3 el índice del descriptor de TSS de esta tarea dentro de la GDT, por lo que se puede usar ese valor para identificar unívocamente una tarea.
Task Register (TR) en IA-32e
El registro Task Register TR no contiene el identificador de la tarea ya que el sistema usa una sola TSS. Por lo tanto, se debe establecer un identificador unívoco para cada tarea.
Contexto
Una opción es utilizar CR3 ya que este registro contiene la dirección física de cada PML4. Cada tarea debe usar un CR3 propio y diferente para que el sistema de protección funcione. Por lo tanto CR3 identifica unívocamente a cada tarea. Cada tarea debe tener una estructura creada en memoria de kernel para guardar su contexto, tal cual se hacia con las TSS en IA-32. La llamaremos espacio de contexto de la tarea actual. Esa estructura tendrá los siguientes campos:
- RAX, RBX, RCX, RDX, RSI, RDI, RBP (Registros de propósito general extendidos a 64 bits)
- R8, R9, R10, R11, R12, R13, R14, R15 (Registros de propósito general de 64 bits nuevos).
- DS, ES, FS, GS.
- CR3
- RSP0 del TSS. (RSP1, RSP2 no se salvan porque no se usan en td3).
- Registros de SIMD y de coprocesador matemático / MMX.
En general, no todas las tareas usan los registros SIMD y como la imagen en memoria de estos registros ocupa 512 bytes, la idea es salvar los registros de punto flotante sólo si hubo cambios durante el tiempo de corrida de la tarea y restaurar dichos registros del contexto sólo si la tarea usa estos registros.
Manejador de interrupción del scheduler
No hace falta poner los RFLAGS, ni CS ni RIP en la estructura donde se guarda el contexto ya que la interrupción los salva en la pila. Haciendo uso de esta estructura el procedimiento para conmutar tareas en 64 bits es:
- Si se determina que no va a haber cambio de tarea, se debe retornar inmediatamente con IRETQ (verificar de poner en la pila los registros que se usen para esa determinación) ya que lo que se indica a continuación no permite cambiar de una tarea a sí misma.
- Salvar en la pila el registro DS y uno de los registros de uso general y cargar DS con el segmento de datos del kernel. Este par se usará en el paso siguiente, por lo que necesitamos que sus datos no se pierdan.
- A partir de CR3 actual, ubicar la dirección del espacio de contexto de la tarea actual mediante el registro de uso general indicado arriba.
- Salvar en el espacio de contexto de la tarea actual los valores de los registros que conforman el contexto mínimo de la tarea actual.
- Si CR0.TS = 0 entonces se ejecutó el manejador de la excepción 7, por lo que los registros SIMD tendrán un valor diferente a lo que se encuentra en el contexto. De esta manera hay que salvar los nuevos valores de los registros mediante la instrucción FXSAVE pasándole como parámetro el puntero a la imagen de los registros SIMD dentro de ese contexto.
- Retirar los registros ingresados en la pila y ponerlos también en la estructura del contexto.
- Salvar los campos RSP0, RSP1 y RSP2 de la TSS en el espacio de contexto. Generalmente los campos ISTn (1 < = n < = 7) no cambian entre diferentes tareas por lo que no hace falta salvarlos.
- Hallar ⇐n⇐el identificador de la tarea siguiente (nuevo valor de CR3) según la lógica del scheduler.
- Si este valor no coincide con el valor de CR3 actual, poner CR0.TS=1 (Task Switched flag), para que se dispare la excepción de punto flotante cuando se use una instrucción SSE.
- Cargar CR3 con el nuevo valor.
- En base al nuevo valor de CR3 usar un registro de uso general para apuntar a la estructura del nuevo contexto.
- Cambiar RSP a la nueva pila usando ese contexto. El registro SS no hay que cambiarlo ya que corresponde al segmento flat de nivel de privilegio cero.
- Cargar uno de los registros de uso general diferente al usado en los dos pasos anteriores del nuevo contexto y salvarlo en la pila. Luego copiar el puntero a este nuevo registro.
- Cambiar RSP0, RSP1 y RSP2 del TSS con los valores que se encuentran en la estructura del nuevo contexto.
- Cargar todos los registros de uso general (excepto el cargado en el paso 11), y los registros de segmento DS, ES, FS, GS con el nuevo contexto usando el registro cargado en el paso 11 para el direccionamiento indirecto. El último registro cambiado debe ser el DS.
- Restaurar el registro de uso general grabado en el paso 11.
- ejecutar IRETQ
- rezar…
Manejador de la excepción 7
Esta excepción ocurre cuando el procesador ejecuta una instrucción de punto flotante o SIMD y el bit de control Task Switched (CR0.TS) està a '1' y CR0.EM = '0' (valor por defecto de este bit).
Los pasos a seguir son:
- Guardar en la pila todos los registros de uso general que se usen en el manejador.
- Poner a cero el bit CR0.TS para que no se produzca nuevamente esta excepción al restaurar los registros de punto flotante.
- Cargar en un registro de uso general el puntero a la imagen de los registros de punto flotante dentro del contexto de la tarea.
- Mediante la instrucción FXRSTOR usando como parámetro el registro incializado en el paso anterior, sobreescribir los registros SIMD con los valores que corresponden a esta tarea.
- Restaurar de la pila todos los registros de uso general usados en este manejador.
- Ejectuar la instrucción IRETQ.
Para tener en cuenta
Se debe diseñar el sistema de paginación con la precaución de que las estructuras de paginación de todas las tareas apunten a las zonas del kernel cuyo código debe ser accesible desde el contexto de ejecución de las tareas: manejadores de interrupción, servicios del kernel, etc. Obviamente las páginas correspondientes debe tener los permisos con el bit U/S adecuadamente configurados. Luego cada estructura de páginas debe contener descriptores de páginas exclusivas de la tarea en cuestión. De este modo se respeta el principio básico de protección de memoria entre tareas.
Otras consideraciones
Se propone usar el CR3 como identificador de tarea debido a que contiene la dirección física del PML4, que es único para cada tarea.
Task switched y el uso de los registros XMM: al conmutar de tarea en modo protegido, se setea automáticamente el bit CR0.TS denominado Task Switched. Como en IA-32e no se conmuta automáticamente la tarea, sino mediante el procedimiento descripto, hay que tocar este bit a mano. El objeto de esto es que si la nueva tarea usa los registros XMM se genera una excepción #XM, si el bit CR0.EM además está en '0', que es el default cuando arranca el microprocesador.
Se recomienda que un área del kernel sea accesible desde todas las aplicaciones para uso de los servicios.
Las entradas de las tablas que apuntan a la zona no paginada deben estar marcadas con el atributo G (Global) a '1' para que no se recarguen innecesariamente al cambiar el registro CR3.