Implantación de DMT (Discrete Multitone Technology)

Anuncio
•
Así se ha implementado DMT
En este capítulo vamos a mostrar los módulos en los que se ha dividido DMT, la función de cada uno de ellos
y cómo se ha implementado. El objetivo principal de este capítulo es que el usuario comprenda perfectamente
como se ha realizado DMT y pueda construirse, si desea, su propio Multitasker.
• El módulo Test16.asm
Este módulo contiene tres funciones, donde dos de ellas se encargan de comprobar el tipo y el estado del
procesador para ver si DMT puede ser ejecutado en esa máquina. Estas funciones se ejecutan estando en el
modo real, antes de entrar en el modo protegido. La tercera de las funciones de este módulo únicamente tiene
como misión la finalización de DMT debido a una condición que no se cumple en la máquina donde va a ser
ejecutado. Estos tres módulos son explicados a continuación:
• Función VerProcesador
Función: VerProcesador.
Descripción: Comprueba si el procesador es un 80386 o superior.
Entrada: Nada
Salida: Si CF = 0 el procesador es un 80386 o superior
Si CF = 1 el procesador es inferior a un 80386
Esta función comprueba si la máquina en la que se está ejecutando DMT es un 80386 o superior. Esta función
es necesaria debido a que se necesita un ordenador que proporcione mecanismos de multitarea y protección
para realizar el Multitasker. El modo protegido del 80386 y superiores nos proporciona estos dos mecanismos.
Aunque el 80286 incluye el modo protegido, este es bastante inferior al del 80386 por las siguientes razones:
• El 80286 posee sólo registros de 16 bits: lo que supone un menor direccionamiento de memoria por parte
del procesador.
• No posee el modo V86: lo que imposibilita la ejecución de programas que fueron creados para el modo real
bajo el modo protegido.
• No posee mecanismo de paginado (directorio y tablas de páginas): no permitiendo la instalación de un
sistema de memoria virtual por páginas.
• Una vez entrado en el modo protegido no se puede volver al modo real, a no ser que se haga un reset del
procesador.
Aunque existen algunas ligeras diferencias más, las más importantes son éstas y sobre todo la segunda
mencionada anteriormente.
Un Multitasker tiene como función ejecutar programas que fueron diseñados para el modo real del MS−DOS,
por tanto necesitamos que el procesador nos permita algún mecanismo de ejecutar estos programas bajo un
telón donde exista la multitarea y la protección entre tareas. Este modo de trabajo nos lo ofrece el 80386 a
través del modo virtual 8086.
1
Para determinar el tipo de procesador, INTEL propone un juego de instrucciones de manipulación del registro
FLAGS que determinarán si el procesador es un 8086, 80286, 80386, 80486, Pentium, etc. Para ver si un
procesador es un 80386, INTEL nos aconseja utilizar el código que se encuentra en la figura 8.1.
Tras ejecutar el código de la figura 8.1, si el contenido del registro AX es igual al contenido del registro BX,
nos es encontramos frente a un 80386 o superior, con lo que podremos seguir chequeando la máquina para ver
si cumple todas las condiciones para ejecutar DMT.
Figura 8.1. Juego de instrucciones propuesto por INTEL
• Función CheqV86
Función: CheqV86.
Descripción: Comprueba si el procesador se está ejecutando en modo V86.
Entrada: Nada.
Salida: Si CF = 1 el procesador se encuentra en modo V86.
Si CF = 0 el procesador está en modo real.
Antes de entrar en el modo protegido debemos de comprobar si el procesador está en modo V86. Si no
realizamos tal comprobación y el procesador está en modo V86, al intentar ejecutar la instrucción que pasa el
procesador a modo protegido, se producirá una excepción por el 80386 y se tomará el control por el programa
que cambió el procesador a modo V86, que seguramente decida eliminar nuestro programa de la memoria de
una forma poco elegante.
Para comprobar si el procesador se encuentra en modo V86, seguramente se piense rápidamente en comprobar
el bit VM del registro EFLAGS se encuentra a 1. Esto es un error, ya que desde el modo V86 no tenemos
acceso a tal bit y cualquier lectura del registro EFLAGS indicará el bit VM a cero. La forma de comprobar si
el procesador se encuentra en modo V86 es leer el contenido del registro CR0 y ver si el bit PE (Protection
Enable) se encuentra a 1.
• Procedimiento Abortar
Procedimiento: Abortar.
Descripción: Termina el programa debido a que no es posible ejecutar DMT en esa máquina.
Entrada: Nada.
Este procedimiento se encarga de mostrar un mensaje por pantalla indicando al usuario que no es posible
ejecutar DMT en su máquina y finalizar el programa realizando una llamada al MS−DOS.
Para finalizar el programa se ha preferido utilizar el servicio 4Ch del DOS, debido a que este es el método que
se aconseja de finalizar un programa en las últimas versiones del DOS, quedando cualquier otro tipo de
finalización de un programa DOS obsoleta.
• El módulo Pantalla.asm
Este módulo consta de dos procedimientos encargados de imprimir un mensaje por pantalla y de borrar la
2
pantalla. Estos procedimientos funcionan sólo cuando la pantalla está en modo texto, debido a que se hace un
acceso directo a pantalla.
• Procedimiento Write
Procedimiento: Write
Descripción: Imprime un mensaje en la posición actual del cursor
Entrada: DS:SI = puntero a la cadena que se desea imprimir
BH = atributos del texto (color, parpadeo, etc.)
La función que se ha querido imitar aquí es el servicio Imprimir cadena del DOS, pero con mayores
prestaciones como puede ser la salida de un texto por pantalla en diferentes colores y mayor velocidad de
impresión.
Para imprimir una cadena que tenemos almacenada en una posición de memoria, debemos de realizar un
acceso directo a la RAM de vídeo si no queremos usar ninguno de los servicios ofrecidos por el sistema
operativo o la BIOS. Como sólo vamos a imprimir cadenas de caracteres en modo texto, solo nos tendremos
que preocupar en cómo se puede imprimir un carácter por pantalla en modo texto.
La RAM de vídeo es un segmento de memoria de donde es leída la información que se va a llevar a pantalla,
por tanto, cualquier acceso a esta zona de memoria producirá un cambio en el contenido de la pantalla. La
RAM de vídeo para los formatos textos comienza en la dirección B800:0000h. A partir de esta dirección de
memoria, cada pareja de bytes componen un carácter en pantalla. El primer byte indica el código ASCII del
carácter que se va a imprimir en pantalla, el segundo byte indica los atributos con los que se desea que
aparezca el carácter (color, parpadeo, etc.).
Para sacar una cadena por pantalla, tan solo deberemos de ir leyendo carácter a carácter de la cadena e ir
insertándolos en la RAM de vídeo acompañados de su byte de atributos.
El procedimiento Write realiza exactamente ese funcionamiento, añadiendo algunas funciones extras:
• Si el carácter que se va a imprimir tiene como código ASCII el valor 13, se realiza un retorno de
carro, es decir, se salta a la línea siguiente.
• Si el carácter que se va a imprimir tiene como código ASCII el valor 36 ó el carácter `$' indicará fin
de la cadena a imprimir, por lo que el procedimiento terminará.
Para realizar múltiples salidas de textos por pantalla, se ha respetado la posición del cursor en pantalla, por lo
que habrá que leer la posición del cursor antes de llevar la cadena a pantalla y posicionarlo al final de la
cadena una vez que esta se haya sacado por pantalla.
• Procedimiento Cls
Procedimiento: CLS.
Descripción: Borra la pantalla en modo texto.
Entrada: Nada.
Este simple procedimiento se encarga de borrar el contenido de la pantalla en modo texto. Para realizar tal
3
función, debemos de rellenar el contenido de la RAM de vídeo desde la dirección B800:0000h hasta la
dirección B800:1000h con espacios en blancos.
• El módulo DMAfunc.asm
Este módulo es encargado de ver si hay instalado en el ordenador un driver virtual de DMA. Un driver virtual
DMA es ofrecido por los servidores VCPI y DPMI y son utilizados para resolver los problemas que ofrece el
DMA en el modo protegido.
El driver virtual DMA (VDMA) posee una especificación (VDS) dada por fabricantes de software y provee de
servicios que usan el DMA para realizar transferencias de datos en el modo protegido con el mecanismo de
paginación activado.
Como se comentó en el capítulo 2, el chip DMA no comprueba si el procesador está trabajando en modo
protegido para realizar las transferencias de datos de un dispositivo a memoria y viceversa. Cuando el
procesador está en modo protegido y activa el mecanismo de paginación, las direcciones lineales son
mapeadas a direcciones físicas diferentes, por lo que el DMA accederá a direcciones físicas de memoria
cuando una tarea le manda una dirección lógica para realizar la transferencia. Un driver VDMA resuelve
todos estos problemas con el DMA a través de diversos servicios y estructuras de memoria que ofrece al
programador.
El único problema es que DMT no funciona bajo servidores VCPI o DPMI, por lo que no se han podido
aprovechar los servicios ofrecidos por la VDS para realizar transferencias con DMA desde el modo protegido.
Las transferencias con DMA han sido posibles en DMT a través del bloqueo del chip DMA y convirtiendo las
direcciones lineales a físicas antes de pasárselas a este chip.
• Función VDMAinst
Función: VDMAinst
Descripción: Comprueba si hay un driver virtual de DMA instalado.
Entrada: Nada.
Salida: Si CF = 0 el driver VDMA está instalado.
Si CF = 1 el dirver VDMA no está instalado.
Esta función realiza una simple llamada a un servicio ofrecido por VCPI y DPMI para comprobar la
existencia de este driver. El por qué se comprueba si hay instalado un driver VDMA si no es posible ejecutar
DMT bajo VCPI o DPMI es debido a que inicialmente se intentó realizar DMT bajo un servidor VCPI y se
hicieron algunas comprobaciones extras para VCPI. Tras cambiar de opinión y abandonar el VCPI, decidí
dejar algunas de estas funciones incluidas en el código de DMT por si algún día decidía incluir el VCPI bajo
DMT.
• El módulo Mensajes.asm
Este módulo contiene dos funciones de las cuales una de ellas se encarga de sacar el Copyright de DMT por
pantalla y la otra imprime por pantalla las características del ordenador.
• Procedimiento Copyright
4
Procedimiento: Copyright
Descripción: Imprime por pantalla un cuadro con el nombre del proyecto y su autor
Entrada: Nada
Este procedimiento utiliza la función definida anteriormente (Cls y Write) para borrar la pantalla y sacar
cadenas de caracteres por pantalla.
• Función Testear
Función: Testear.
Descripción: Comprueba si se puede ejecutar DMT en la máquina actual.
Entrada: Nada.
Salida: Si CF = 1 entonces no es posible ejecutar DMT.
Si CF = 0 entonces es posible ejecutar DMT.
Esta función realiza diversas comprobaciones con respecto al procesador y los drivers que hay instalado en el
ordenador.
Los pasos seguidos por esta función se definen a continuación:
• Comprobar si el procesador es un 80386 o superior: A través de la función definida anteriormente
podemos observar si el procesador es un 80386 o superior. Si el procesador es menor que un 80386,
saldremos del procedimiento indicando a través de la bandera de acarreo que no es posible ejecutar DMT
en la máquina actual.
• Comprobar si hay un servidor VCPI instalado: El resultado de esta comprobación no es tenida en cuenta
por DMT, debido a que no será posible ejecutar DMT bajo este servidor. Dicha comprobación será utilizada
para versiones futuras de DMT.
• Comprobar si el procesador está trabajando en modo V86: Para saber si el procesador se encuentra en
modo V86 utilizamos la función CheqV86 del módulo test16.asm. En caso de que el procesador se
encuentre en modo V86, no será posible ejecutar DMT debido a que no podemos reiniciar el modo
protegido.
• Comprobar si hay un driver virtual DMA instalado: Esta comprobación se realiza para saber si podemos
utilizar los servicios ofrecidos por un driver VDMA bajo configuraciones VCPI o DPMI.
En caso de que todas estas restricciones se hayan cumplido, esta función indicará a través de la bandera de
acarreo que DMT puede ser ejecutado en la máquina actual.
• El módulo DMT.asm
Este es el módulo principal del programa, encargado de conmutar el procesador al modo protegido e
inicializar todas las estructuras necesarias para la ejecución de DMT. Este módulo es bastante complejo y
extenso, por lo que lo iremos explicando a través de una serie de pasos que siguen el flujo secuencial de
instrucciones que componen el módulo.
• Paso 1: Definición de variables para el modo real
5
Antes de entrar al modo protegido, el procesador se encuentra ejecutándose en el modo real, por lo que
deberemos de mantener una serie de variables para: comprobar si es posible ejecutar DMT bajo la máquina
actual, guardar vectores de interrupción que se van a modificar, tipo de configuración, etc. Estas variables se
definirán dentro del segmento de código para mantener todo el código y datos del modo real en un único
segmento y permitir un acceso más fácil a este segmento desde el modo protegido.
• Paso 2: Definición de mensajes utilizados en el modo real
Antes de inicializar el modo protegido necesitamos realizar ciertas comprobaciones acerca de la computadora,
para ver si DMT puede ser ejecutado en ella. En el módulo mensajes.asm se realizan ciertas comprobaciones
que comprueban el estado del procesador. En este módulo se realizan algunas comprobaciones más antes de
entrar al modo protegido.
Todos los mensajes que indican al usuario el estado de la computadora, antes de entrar al modo protegido, son
definidos en este módulo.
• Paso 3: Comprobar si DMT puede ser ejecutado
DMT permite recibir un argumento desde la línea de comando, la opción /d. Esta opción indicará a DMT que
todas las tareas pueden acceder a la vez a la pantalla, de este modo podremos ver como todas las tareas se
ejecutan de forma concurrente.
El paso siguiente es el de mostrar el Copyright por pantalla y luego realizamos el chequeo de la computadora
para ver si DMT puede ser ejecutado. Las condiciones que ha de tener la computadora para que DMT pueda
ejecutarse son las siguientes:
• Tener un procesador igual o superior a un 80386.
• Que el procesador se encuentre trabajando en el modo real.
• Que no haya instalado ningún gestor de memoria.
• Que haya suficiente memoria extendida libre.
• Que se pueda liberar la línea de direcciones A20.
Las dos primeras condiciones se pueden comprobar a través de una llamada a la función realizada
anteriormente (función testear).
Para comprobar que no hay ningún gestor de memoria instalado hay que comprobar que no se encuentra un
driver de XMS en memoria. Tan sólo hay que comprobar que no exista un driver XMS y no un driver EMS,
ya que los gestores de memoria que proporcionan un driver EMS conmutan el procesador a modo V86, lo que
no hubiera superado la condición de tener el procesador en el modo real. Para saber si existe un driver XMS
instalado hay que realizar una llamada al servicio 4300h del multiplexor (interrupción 2fh) y comprobar el
resultado devuelto por tal servicio en el registro AL del procesador. Si el valor devuelto en AL es igual a 80h
entonces existe un driver XMS instalado, lo que supondrá que DMT no pueda ser ejecutado mientras exista
ese driver en memoria.
El siguiente paso es habilitar la línea de direcciones A20 para que podamos acceder más allá del primer Mbyte
de memoria física. Para liberar la línea A20 debemos hacerlo a través del controlador del teclado ya que está
íntimamente ligado a esta línea. En caso de que se haya podido liberar la línea A20, podemos seguir con la
ejecución de DMT.
El último paso referente a las comprobaciones realizadas es ver cuanta memoria extendida se encuentra
disponible a través de la BIOS. Toda la memoria que haya libre será solicitada por DMT para que ninguna de
las tareas ejecutadas bajo él puedan acceder a la memoria extendida a través de la BIOS y pueda machacar las
6
zonas de memoria correspondientes a otras tareas. De este modo será DMT el único que podrá gestionar la
memoria libre que se encuentra en el ordenador.
Una vez que solicitamos toda la memoria extendida libre calculamos cuantas tareas podrán ser ejecutadas bajo
DMT. Como cada tarea ocupa un Mbyte, bastará con dividir la memoria disponible entre un Mbyte y
obtendremos el número de tareas que podrán ser ejecutadas en DMT. El numero de tareas obtenido se utilizará
para mostrarle al usuario por pantalla cuantas tareas puede ejecutar y además será utilizada por DMT para
realizar el barrido de teclas de función. Este barrido de teclas se explicará posteriormente.
• Paso 4: Redireccionar algunos vectores de interrupción
Para crear cada una de las tareas, DMT copiará el contenido del primer Mbyte de memoria física a la zona de
memoria correspondiente a la tarea que se va a crear. Por tanto si ahora modificamos un vector de
interrupción, antes de entrar al modo protegido, conseguiremos que ese vector de interrupción quede
modificado para todas las tareas que vaya a crear DMT.
Los vectores de interrupción que redirecciona DMT, sin incluir los que redirecciona en el modo protegido,
son:
• Interrupción 15h: Servicios del sistema de la BIOS.
• Interrupción 13h: Servicios de disco de la BIOS.
• Interrupción 33h: Servicios del ratón.
La interrupción 15h es redireccionada para manipular el servicio 88h Obtener memoria extendida libre.
Cuando una tarea solicite este servicio para ver de cuanta memoria extendida puede obtener, se le devolverá
un código señalando que no hay memoria extendida libre. En tal caso, la tarea tomará sus propias decisiones
para seguir ejecutándose o no sin memoria extendida.
La interrupción 13h es redireccionada por DMT para indicar cuando se está ejecutando esta interrupción.
Cuando una tarea está realizando una operación de disco y DMT provoca una conmutación de tarea, por haber
finalizado su porción de tiempo, se puede llegar a grandes perdidas de datos en disco. Esto es así porque el
procesador cambia el espacio de direcciones visibles al de la nueva tarea, con lo que el disco leerá o escribirá
datos de una zona de memoria que no se corresponde a la que la primera tarea le indicó. Por tanto debemos de
tener un mecanismo que nos indique cuando se está realizando una operación de disco. Una de las soluciones
es interceptar la interrupción de disco y tener una variable que indique disco activo cada vez que se llama a
esta interrupción. Cuando el servicio de disco ha finalizado se vuelve a poner esta variable a disco inactivo. A
través de este simple mecanismo, DMT puede saber cuando una tarea está realizando una operación de disco
y, por tanto, sabrá que no puede interrumpirla.
La interrupción 33h es redireccionada debido a que se observó un problema cuando dos tareas solicitaban el
servicio de inicialización del ratón al mismo tiempo. Cuando dos tareas inicializaban el ratón al mismo
tiempo, ambas se quedaban bloqueadas indefinidamente, y a veces se deshacía el bloqueo cuando una tercera
tarea inicializaba más tarde el ratón. La razón de porque esto ocurre no he llegado a saberlo aún, aunque si he
encontrado una solución para que este bloqueo no se dé. Para evitar este bloqueo entre tareas he optado por
utilizar el mismo mecanismo que en el mostrado para solucionar el problema del disco. Es decir, tener una
variable que indique ratón ocupado cada vez que se solicita un servicio del ratón, y poner esa misma variable
a ratón libre cuando el servicio haya terminado.
• Paso 5: Rellenar la GDT
La tabla de descriptores global (GDT) de DMT posee los siguientes descriptores para acceder a la memoria
desde el modo protegido:
7
• Descriptor nulo.
• Descriptor GDTcode32.
• Descriptor GDTdata32.
• Descriptor GDTcode16.
• Descriptor GDTdata16.
• Descriptor GDTzero16.
• Descriptor GDTflat32.
• Descriptor GDText.
• Descriptor GDTtask0.
• Descriptor GDTtask1.
• Descriptor GDTtask2.
• .....
• Descriptor GDTtaskN.
En la siguiente tabla puede observarse una tabla resumen con el contenido de la GDT:
Nombre del descriptor
GDTnulo
Descripción del descriptor
Descriptor nulo necesario por el 80386.
Base: 4xxxxxx (4Mbyte = 2ª entrada del directorio de páginas.
GDTcode32
Límite: 0FFFFFh
Atributos: No granular, 32bits, DPL=0, Ejecución, Presente.
Base: 4xxxxxx
GDTdata32
Límite: 0FFFFFh
Atributos: No granular, 32bits, DPL=0, Lectura Escritura, Presente.
Base: Segmento de código de 16 bits (codigo16)
GDTcode16
Límite: 0FFFFh (64 Kbytes)
Atributos: No granular, 16, DPL=0, Ejecución, Presente.
Base: Segmento de código de 16 bits (codigo16)
GDTdata16
Límite: 0FFFFh (64 Kbytes)
Atributos: No granular, 16, DPL=0, Lectura, Escritura.
Base: 4xxxxxxh
GDTzero16
Límite: 0FFFFFh (1 Mbyte)
Atributos: No granular, 16bits, DPL=0, Lectura Escritura, Presente.
Base: 0 (Acceso a la memoria de cada tarea)
GDTflat32
Límite: 0FFFFFh (4 Gbytes, al tener granularidad)
GDText
Atributos: Granular, 32bits, DPL=0, Lectura Escritura, Presente.
Base: xxxxxx (dirección de comienzo de la memoria extendida)
8
Límite: 0FFFFFh
Atributos: Granular, 32bits, DPL=0, Lectura Escritura, Presente.
Base: 4xxxxxx (TSS para DMT)
GDTtask0
Límite: 0FFFFh
Atributos: No granular, DPL=0, Lectura Escritura, Presente.
Base: 4xxxxxx (TSS para las tareas V86)
GDTtaskN
Límite: 0FFFFh
Atributos: No granular, DPL=0, Lectura Escritura.
Cada uno de estos descriptores tiene asociada un área de memoria, que puede ser traslapada con la de otros
descriptores, con funciones específicas. La función de cada uno de estos descriptores se muestra a
continuación.
Descriptor nulo:
Este descriptor no tiene ninguna función bajo DMT. En realidad, todos los programas que se realizan bajo el
modo protegido ha de tener un descriptor nulo y se ha de colocar en la primera entrada de la GDT. El
descriptor nulo se caracteriza por tener todos los valores de su entrada a cero. El 80386 necesita la presencia
de este descriptor para poder manipular la GDT en el modo protegido.
Descriptor GDTcode32:
Este descriptor referencia el segmento de código protegido de DMT. Bajo este segmento de código se
encuentra todo el código en modo protegido encargado de llevar a cabo el funcionamiento de DMT.
La base del segmento, es decir la dirección de comienzo empieza en el cuarto Mbyte de memoria + la
dirección de comienzo dentro del primer Mbyte de memoria. Esto puede parecer un poco complicado, pero se
entenderá fácilmente si decimos que la razón por la que se ha sumado 4 Mbytes a la base del segmento es
debido a que queremos que el segmento de código se mapee a través de la segunda entrada del directorio de
páginas. En el apartado La paginación en DMT se explicará esto más detalladamente.
Continuando con los atributos que posee el segmento del descriptor GDTcode32, hay que señalar que:
• Es de sólo lectura y ejecución: condiciones que ha de cumplir un segmento de código.
• El segmento será del tipo 32 bits: lo que supondrá que todas las instrucciones y operandos serán por
defecto de 32 bits.
• El segmento es del tipo no granular: Al ser no granular, el límite del segmento coincidirá con el
tamaño del atributo Límite del descriptor.
• Nivel de privilegios 0: El segmento de código poseerá el nivel de prioridad supervisor, con lo que
podrá realizar cualquier acción sobre el sistema.
• Segmento presente: Indicamos que el segmento se encuentra en memoria.
• Limite del segmento: 1 Mbyte.
Para referenciar este segmento debemos de usar un selector que se ha definido y tiene como nombre
SelCode32. El selector SelCode32 tiene como valor de selector el número 8h, en binario 1000b (descriptor 1,
tabla GDT (0), nivel de prioridad 00).
9
Descriptor GDTdata32:
Este descriptor es un alias del segmento de código, es decir, mapea exactamente el mismo segmento que el
descriptor GDTcode32. La razón de declarar un alias es debido a que en un segmento de código está
prohibido escribir, por lo que necesitamos declarar otro descriptor que mapee las mismas direcciones que el
segmento de código, pero que tenga el atributo de escritura activado para que podamos escribir sobre él.
Los atributos que definen el segmento del descriptor GDTdata32 son los siguientes:
• Base del segmento: 4 Mbyte + dirección del segmento de código protegido dentro del primer Mbyte.
Se han sumado 4 Mbytes por el motivo anterior. La dirección del segmento de código protegido
dentro del primer Mbyte será rellenada en la GDT mientras la estamos inicializando desde el modo
real.
• Límite: 1 Mbyte.
• No granular: El límite del segmento seguirá siendo de un Mbyte.
• Segmento de 32 bits: Todos los datos que hay en segmento se suponen que tienen una longitud de 32
bits por defecto.
• Nivel de prioridad 0: Indicará que es un segmento que solo puede ser usado por un usuario o
segmento de código que tenga nivel de prioridad cero.
• Segmento presente: Indicamos que el segmento se encuentra cargado en memoria y es posible acceder
a él.
• Segmento de lectura/escritura: Se podrá leer cualquier dato que se encuentra en dicho segmento y se
podrán modificar sus valores.
Para referenciar este segmento lo debemos de hacer a través del selector SelData32, cuyo valor de selector es
el 10h (descriptor 2, tabla GDT, nivel de prioridad del solicitante 0).
Descriptor GDTcode16:
Este descriptor referencia al segmento de código que DMT utiliza antes de entrar al modo protegido. Este
segmento corresponde al código que DMT ejecuta nada mas empezar a ejecutarse (en el modo real). Antes de
entrar a modo protegido de 32 bits, es decir, antes de entrar en el segmento mapeado por GDTcode32,
necesitamos entrar en un segmento de código en modo protegido de 16 bits. Ese segmento de código en modo
protegido de 16 bits estará incluido dentro del segmento que mapea el descriptor GDTcode16.
El segmento mapeado por GDTcode16 posee los siguientes atributos:
• Base: dirección del segmento de código de 16 bits dentro del primer Mbyte de memoria. Es decir, la
dirección base coincide con la dirección en la que el MS−DOS coloca el programa DMT al ejecutarlo.
• Límite: 64 Kbytes, ya que en modo real no puede haber un segmento mayor de 64 Kbytes de
memoria.
• No granular: El límite del segmento seguirá siendo de 64 Kbytes.
• Segmento de 16 bits: Todos los operandos de las instrucciones se supondrán que tienen un tamaño de
16 bits.
• Nivel de prioridad 0: Indicará que es un segmento que solo puede ser usado por un usuario o
segmento de código que tenga nivel de prioridad cero.
• Segmento presente: Indicamos que el segmento se encuentra cargado en memoria y es posible acceder
a él.
• Segmento de lectura y ejecución: Indicará que es un segmento de ejecución.
Para acceder a este segmento necesitamos usar el selector definido en DMT llamado SelCode16, cuyo valor
de selector es 18h (descriptor 3, tabla GDT, nivel de prioridad del solicitante 0).
10
Descriptor GDTdata16:
Este descriptor es utilizado como alias para acceder a los datos que se encuentran dentro del segmento
GDTcode16 y poder realizar modificaciones sobre ellos.
Los atributos que poseen este segmento son:
• Base: dirección del segmento de código de 16 bits dentro del primer Mbyte de memoria. Es decir, la
dirección base coincide con la dirección en la que el MS−DOS coloca el programa DMT al ejecutarlo.
• Límite: 64 Kbytes, ya que en modo real no puede haber un segmento mayor de 64 Kbytes de
memoria.
• No granular: El límite del segmento seguirá siendo de 64 Kbytes.
• Segmento de 16 bits: Todos los datos que hay en segmento se suponen que tienen una longitud de 16
bits.
• Nivel de prioridad 0: Indicará que es un segmento que solo puede ser usado por un usuario o
segmento de código que tenga nivel de prioridad cero.
• Segmento presente: Indicamos que el segmento se encuentra cargado en memoria y es posible acceder
a él.
• Segmento de lectura y escritura: Podremos acceder a cualquier variable que se encuentre dentro de
este segmento y modificar su valor.
Para acceder a este segmento necesitamos usar el selector definido en DMT llamado SelData16, cuyo valor
de selector es 20h (descriptor 4, tabla GDT, nivel de prioridad del solicitante 0).
Descriptor GDTzero16:
Bajo este descriptor se encuentra un segmento de datos el cual mapea el primer Mbyte de memoria física, es
decir, mapea toda la memoria en la que se encuentra cargado el MS−DOS y DMT. La razón por la que hemos
definido un segmento que mapee el primer Mbyte de memoria física, es debido a que necesitamos tener
acceso a este Mbyte para copiarlo a la zona de memoria correspondiente a cada una de las tareas que vaya a
crear DMT.
Las características que posee este segmento son las siguientes:
• Base: 4 Mbyte. A través del cuarto Mbyte podremos acceder a la segunda entrada del directorio de
páginas. Bajo esta segunda entrada se encontrará la dirección de una tabla de páginas que mapea el
primer Mbyte de memoria física, por lo que la dirección lógica 4 Mbyte corresponde a la dirección
física 0.
• Límite: 1 Mbyte, para acceder a todo el primer Mbyte de memoria física.
• No granular: El límite del segmento seguirá siendo de un Mbyte.
• Segmento de 16 bits: Todos los datos que hay en segmento se suponen que tienen una longitud de 16
bits.
• Nivel de prioridad 0: Indicará que es un segmento que solo puede ser usado por un usuario o
segmento de código que tenga nivel de prioridad cero.
• Segmento presente: Indicamos que el segmento se encuentra cargado en memoria y es posible acceder
a él.
• Segmento de lectura y escritura: Podremos acceder a cualquier variable que se encuentre dentro de
este segmento y modificar su valor.
Para acceder a este segmento necesitamos usar el selector definido en DMT llamado SelZero16, cuyo valor
de selector es 28h (descriptor 5, tabla GDT, nivel de prioridad del solicitante 0).
11
Descriptor GDTflat32
Este descriptor se ha creado para acceder a la zona de memoria correspondiente a cada una de las tareas que
DMT ejecuta. Además se utiliza para poder acceder a cualquier dirección dentro del espacio de direcciones
lineales.
Las características que presenta el segmento del descriptor GDTflat32 son las siguientes:
• Base: dirección lineal 0, para acceder a la zona de memoria correspondiente a cada tarea. Las tareas
formarán sus direcciones lineales a partir de la dirección lógica 0. A través del directorio de páginas,
la primera entrada apuntará a una tabla de páginas que será la que mapee las direcciones de cada
tarea. Cada tarea tendrá su propio directorio de páginas, que contendrá en la primera entrada la
dirección de una tabla de páginas que mapea sus direcciones lógicas. La segunda entrada de cada uno
de los directorios de páginas apuntará a una tabla de páginas que contiene el código de DMT (por eso
los segmentos de DMT se mapean a partir de la dirección lógica 4 Mbytes). Como el segmento
GDTflat32 tiene su base en la dirección lógica 0, corresponderá a la dirección 0 de cada una de las
tareas.
• Límite: 4 Gigabytes. Podremos acceder a toda la memoria física disponible en el ordenador a través
de este segmento.
• Granular: Segmento de tipo granular, para poder dar al segmento la longitud de 4 Gbytes.
• Segmento de 32 bits: Todos los datos que hay en segmento se suponen que tienen una longitud de 32
bits.
• Nivel de prioridad 0: Indicará que es un segmento que solo puede ser usado por un usuario o
segmento de código que tenga nivel de prioridad cero.
• Segmento presente: Indicamos que el segmento se encuentra cargado en memoria y es posible acceder
a él.
• Segmento de lectura y escritura: Podremos acceder a cualquier variable que se encuentre dentro de
este segmento y modificar su valor.
Para acceder a este segmento necesitamos usar el selector definido en DMT llamado SelFlat32, cuyo valor de
selector es 30h (descriptor 6, tabla GDT, nivel de prioridad del solicitante 0).
Descriptor GDText
Este descriptor es utilizado para acceder al segmento de memoria donde comienza la memoria extendida.
Aunque podríamos haber utilizado el descriptor GDTflat32 para acceder a la memoria extendida, hemos
preferido crear otro descriptor para realizar un acceso más simple a esta memoria.
Los atributos que definen a este segmento son los siguientes:
• Base: Depende de la dirección donde comienza la memoria extendida libre. Normalmente será la
dirección donde comienza el segundo Mbyte de memoria física.
• Límite: Depende del tamaño de la memoria extendida.
• Granular: Segmento de tipo granular, para que se pueda acceder a cualquier dirección de memoria
extendida, independientemente del tamaño de ésta.
• Segmento de 32 bits: Todos los datos que hay en segmento se suponen que tienen una longitud de 32
bits.
• Nivel de prioridad 0: Indicará que es un segmento que solo puede ser usado por un usuario o
segmento de código que tenga nivel de prioridad cero.
• Segmento presente: Indicamos que el segmento se encuentra cargado en memoria y es posible acceder
a él.
• Segmento de lectura y escritura: Podremos acceder a cualquier variable que se encuentre dentro de
12
este segmento y modificar su valor.
Para acceder a este segmento necesitamos usar el selector definido en DMT llamado SelExt, cuyo valor de
selector es 38h (descriptor 7, tabla GDT, nivel de prioridad del solicitante 0).
Descriptor GDTtask0
Este descriptor referencia al segmento correspondiente al TSS de la tarea cero. La tarea cero corresponde a
aquella que llevó al procesador al modo protegido, en nuestro caso la tarea número cero será DMT.
El segmento TSS de la tarea 0 posee los siguientes atributos:
• Base: 4 Mbyte + dirección donde se encuentra el TSS de la tarea 0. Se vuelve a sumar 4 Mbytes a la
dirección para acceder a la segunda entrada del directorio de páginas, que apuntará a una tabla de
páginas que mapeará el primer Mbyte de memoria física.
• Límite: 64Kb, aunque el TSS ocupa mucho menos damos por defecto 64Kb para cada TSS de cada
una de las tareas.
• No granular: El límite del segmento seguirá siendo de 64 Kbytes.
• Nivel de prioridad 0: Indicará que es un segmento que solo puede ser usado por un usuario o
segmento de código que tenga nivel de prioridad cero. Ninguna tarea con un nivel de privilegios
menor podrá provocar una conmutación de tareas, ya que no tiene acceso a los descriptores de cada
uno de los TSS.
• Segmento presente: Indicamos que el segmento se encuentra cargado en memoria y es posible acceder
a él.
Para llevar a cabo una conmutación de tareas a la tarea 0, debemos de utilizar un selector definido por DMT
cuyo valor de selector es 40h (descriptor 8, tabla GDT, nivel de prioridad del solicitante 0).
Descriptor GDTtaskN
En realidad, el descriptor GDTtaskN no existe, sino que representa a un conjunto de descriptores del TSS de
cada una de las tareas creadas por DMT. Así la tarea número uno utilizará el descriptor GDTtask1, la tarea
número 2 utilizará el descriptor GDTtask2, etc.
Las características de estos segmentos del TSS para cada una de las tareas creadas por DMT son:
• Base: 4 Mbyte + dirección donde se encuentra el TSS de cada tarea.
• Límite: 64Kb.
• No granular: El límite del segmento seguirá siendo de 64 Kbytes.
• Nivel de prioridad 0: Indicará que es un segmento que solo puede ser usado por un usuario o
segmento de código que tenga nivel de prioridad cero. Ninguna tarea con un nivel de privilegios
menor podrá provocar una conmutación de tareas, ya que no tiene acceso a los descriptores de cada
uno de los TSS.
• Segmento presente: Indicamos que el segmento se encuentra cargado en memoria y es posible acceder
a él.
Para provocar una conmutación a cada una de las tareas creadas por DMT, debemos de referenciar el selector
correspondiente al descriptor de cada una de ellas. La tarea 1 tendrá como valor de selector el número 48h, la
tarea 2 tendrá como selector el 50h, la tarea 3 tendrá el selector 58h, la tarea 4 el 60h, etc.
Todos estos descriptores de la GDT han sido rellenados a través del ensamblador, es decir, los hemos
inicializado a través de la definición de variables en ensamblador y asignándole un valor por defecto. La
13
siguiente secuencia en ensamblador muestra como se ha definido la GDT en DMT:
GDT label dword
GDTnulo dq 0
GDTcode32 db 0ffh, 0ffh, 0, 0, 40h, 9ah, 4fh, 0
GDTdata32 db 0ffh, 0ffh, 0, 0, 40h, 92h, 4fh, 0
GDTcode16 db 0ffh, 0ffh, 0, 0, 0, 9ah, 0, 0
GDTdata16 db 0ffh, 0ffh, 0, 0, 0, 92h, 0, 0
GDTzero16 db 0ffh, 0ffh, 0, 0, 40h, 92h, 0cfh, 0
GDTflat32 db 0ffh, 0ffh, 0, 0, 0, 92h, 0cfh, 0
GDText db 0ffh, 0ffh, 0, 0, 80h, 92h, 8fh, 0
GDTtask0 db 0ffh, 0ffh, 0, 0, 40h, 89h, 0, 0
GDTtaskN db NumTareas*8 dup(0)
Algunos valores de la GDT aún no han sido rellenados, estos valores son los que se corresponden con el valor
Base de algunos segmentos como GDTcode32, GDTdata32, GDTcode16 y GDTdata16, que dependen de la
posición de memoria donde el MS−DOS haya colocado DMT. El siguiente paso por tanto es rellenar estos
valores de descriptores para que la GDT pueda ser usada en el modo protegido.
Para encontrar el valor base de los segmentos anteriores debemos de obtener la dirección de comienzo de
DMT en memoria. Como los segmentos de los descriptores GDTcode16 y GDTdata16 se corresponden con el
comienzo del código de arranque de DMT, debemos de coger la dirección del segmento donde comienza este
código de arranque y pasar esta dirección a lineal. Para pasar a lineal una dirección en el modo real tan solo
debemos de multiplicar por 16. Una vez obtenida la dirección lineal debemos de rellenar el atributo Base de
los descriptores GDTcode16 y GDTdata16 con el valor de esa dirección.
Para rellenar el valor Base de los descriptores GDTdata32 y GDTcode32 debemos seguir el proceso anterior,
pero sabiendo que la dirección del segmento de estos descriptores se corresponde con el comienzo del
segmento protegido de 32 bits. En DMT este segmento de 32 bits tiene como nombre codigo32.
• Paso 6: Rellenar la IDT
El 80386 consulta la IDT cada vez que se produce una interrupción. La IDT contiene un conjunto de
descriptores y cada uno de ellos se encarga de tratar a una excepción o interrupción específica. Las primeras
entradas de la IDT están definidas por el 80386 y el programador debe de colocar una rutina de tratamiento
para cada una de ellas, es decir, cada vez que se produce un excepción por falta de página, el 80386 lee el
descriptor número 14 para buscar la dirección del segmento donde comienza la rutina de tratamiento, que el
programador ha elaborado, para tratar el fallo de página. Por tanto, el programador ha de saber qué número de
descriptor corresponde a cada excepción y elaborar una rutina de tratamiento de estas excepciones.
Bajo DMT la IDT está formada por todos los descriptores definidos por el 80386 más un conjunto de
descriptores que son los encargados de gestionar las interrupciones enmascarables que son producidas por las
14
líneas IRQ del procesador.
Las líneas IRQ del procesador le indican a éste cuando se produce una interrupción por alguno de los
componentes del ordenador. Por ejemplo, cuando se pulsa una tecla se activa la línea IRQ1, indicando al
procesador que se ha producido un evento en el teclado. El procesador llamará a una rutina, que ha de tener en
memoria, para gestionar el evento del teclado. Así cada componente hardware tendrá una línea IRQ
disponible para llamar al procesador y que éste le atienda.
El controlador de interrupciones enmascarables (PIC) se encarga de gestionar todas estas interrupciones. El
PIC se puede reprogramar para que las IRQ se correspondan con una interrupción diferente. Por ejemplo, cada
vez que se activa la IRQ0 el PIC avisa al procesador con la interrupción 08h, cuando se activa la línea IRQ1 el
PIC avisa al procesador con la interrupción 09h, cuando se activa la línea IRQ2 el PIC avisa al procesador con
la interrupción 0Ah, etc. Estos valores son tomados tras el arranque normal del ordenador.
Estas interrupciones enmascarables han de tener una rutina en modo protegido para no perder el enlace con
los componentes hardware desde el modo protegido. El problema que surge en el modo protegido es que el
PIC produce interrupciones que están en el rango de 08h hasta 0Fh, lo que significa que cada vez que se pulsa
una tecla, por ejemplo, se produce una interrupción numero 09h que corresponde con la entrada 09 de la IDT
(la entrada 09 de la IDT indica Segmento del coprocesador sobrepasado) lo cual es un grave error. Para
solucionar este problema debemos de reprogramar el PIC para que las interrupciones producidas por los
componentes hardware no hagan referencia a entradas de la IDT que ya están definidas por el 80386.
En DMT se ha reprogramado el PIC para que las interrupciones enmascarables se mapeen a partir de la
entrada 32 de la IDT. Es decir, cada vez que se habilite la línea IRQ0 se producirá la interrupción 32, la línea
IRQ1 provocará una interrupción 33, etc. En la figura 8.2 se puede ver una secuencia en ensamblador, tomada
del extensor de Thomas Tran Pytel, para reprogramar el PIC.
set_PIC proc near
mov al,11h ; ICW4 es necesitado
out 20h,al ; ponemos valor en Command Word 1
out 0a0h,al ; ponemos valor en Command Word 1 (2º)
mov al,bl ; nueva dirección de la IRQ0−7
out 21h,al ; ponemos valor en Command Word 2
mov al,bh ; dirección para IRQ8−15
out 0a1h,al ; ponemos valor en Command Word 2 (2º)
mov al,4h ; IRQ 2 como esclavo
out 21h,al ; Command Word 3
mov al,2h ; respuesta de maestro a esclavo en IRQ 2
out 0a1h,al ; ICW3 para dispositivo esclavo
mov al,1h ; 80x86 Mode
15
out 21h,al ; Command word 4
out 0a1h,al ; Coomand word 4 (2º)
ret ; devolvemos control al invocador
set_PIC endp
figura 8.2
En la tabla siguiente puede observarse el estado final de la IDT en DMT.
Estructura Física de la IDT
Excepción 0: Error de División
Excepción 1: Excepción de depurado
Excepción 2: Interrupción no Enmascarable
Excepción 3: Punto de ruptura
Excepción 4: Desbordamiento (overflow)
Excepción 5: Comprobación de fronteras
Excepción 6: Código de operación invalido
Excepción 7: Coprocesador no disponible
Excepción 8: Fallo doble
Excepción 9: Segmento del copro sobrepasado
Excepción 10: TSS inválido
Excepción 11: Segmento no presente
Excepción 12: Excepción de pila
Excepción 13: Falta de Protección General
Excepción 14: Falta de página
Excepción 15: Reservada
Excepción 16: Error del coprocesador
Excepción 17: Chequeo de interrupción
Excepción 18−31: Reservadas
Excepción 32−48: Interrupciones enmascarables
El siguiente paso en el programa es rellenar cada uno de los descriptores de la IDT para que apunten a la
rutina de tratamiento de excepción correspondiente. A continuación se describen las características
correspondiente a cada uno de los descriptores que forman la IDT de DMT.
Descriptor 0: Error de División
Cada vez que se produce un error de división, como puede ser una división por cero, el 80386 genera esta
excepción.
Los atributos correspondientes a este descriptor son:
• Selector: SelCode32. Cada vez que se produzca esta excepción, el procesador ejecutará el código que
se encuentra en el segmento de código protegido de 32 bits, referenciado por SelCode32. El
desplazamiento específico dentro del segmento de este segmento de código viene dado por el atributo
16
siguiente.
• Desplazamiento: El desplazamiento de esta excepción apunta a una rutina de tratamiento de
excepciones general, donde se produce la finalización de la tarea que generó esta excepción.
• Nivel de privilegios: Cero. Este descriptor sólo puede ser utilizado por un usuario que tenga el nivel
de privilegios cero. En DMT el único usuario que posee el nivel de privilegios cero es la tarea cero.
• Bit presente activado. La rutina de tratamiento de la excepción se encuentra cargada en memoria.
Descriptor 1: Excepción de depurado
Cuando se produce una excepción estando el procesador con el bit TF de EFLAGS a 1 se produce esta
excepción. Esta excepción sólo se da cuando una de las tareas que se ejecuta es un depurador.
Los atributos de este descriptor son los siguientes:
• Selector: SelCode32. Cada vez que se produzca esta excepción, el procesador ejecutará el código que
se encuentra en el segmento de código protegido de 32 bits, referenciado por SelCode32. El
desplazamiento específico dentro del segmento de este segmento de código viene dado por el atributo
siguiente.
• Desplazamiento: El desplazamiento de esta excepción apunta a una rutina que se encarga de preparar
el procesador para que vuelva al modo V86 y ejecute la rutina de tratamiento para esta excepción que
el depurador instaló en memoria. Una vez que esta excepción se haya tratado por el depurador, se
retomará el control por el gestor de la excepción 1 y se volverá a la tarea que provocó esta excepción.
• Nivel de privilegios: Cero. Este descriptor sólo puede ser utilizado por un usuario que tenga el nivel
de privilegios cero. En DMT el único usuario que posee el nivel de privilegios cero es la tarea cero.
• Bit presente activado. La rutina de tratamiento de la excepción se encuentra cargada en memoria.
Descriptor 2: Interrupción no Enmascarable
Este excepción provocará la terminación de la tarea que se está ejecutando de forma inmediata, debido a que
la recuperación de este error es muy difícil de tratar. Esta excepción podría interferir en el resto del sistema y
producir un bloqueo total.
Los atributos de este descriptor son los siguientes:
• Selector: SelCode32. Cada vez que se produzca esta excepción, el procesador ejecutará el código que
se encuentra en el segmento de código protegido de 32 bits, referenciado por SelCode32. El
desplazamiento específico dentro del segmento de este segmento de código viene dado por el atributo
siguiente.
• Desplazamiento: El desplazamiento de esta excepción apunta a una rutina de tratamiento de
excepciones general, donde se produce la finalización de la tarea que generó esta excepción. Sería
recomendable reiniciar el sistema tras producirse esta excepción.
• Nivel de privilegios: Cero. Este descriptor sólo puede ser utilizado por un usuario que tenga el nivel
de privilegios cero. En DMT el único usuario que posee el nivel de privilegios cero es la tarea cero.
• Bit presente activado. La rutina de tratamiento de la excepción se encuentra cargada en memoria.
Descriptor 3: Punto de ruptura
Esta excepción es producida por el procesador cuando se ha establecido un punto de ruptura en el código de
un programa dentro de un depurador. Para trata a esta excepción debemos de llamar a la rutina que el
depurador posee para tratar esta excepción.
Los atributos de este descriptor son los siguientes:
17
• Selector: SelCode32. Cada vez que se produzca esta excepción, el procesador ejecutará el código que
se encuentra en el segmento de código protegido de 32 bits, referenciado por SelCode32. El
desplazamiento específico dentro del segmento de este segmento de código viene dado por el atributo
siguiente.
• Desplazamiento: El desplazamiento de esta excepción apunta a una rutina que se encarga de preparar
el procesador para que vuelva al modo V86 y ejecute la rutina de tratamiento para esta excepción que
el depurador instaló en memoria.
• Nivel de privilegios: Cero. Este descriptor sólo puede ser utilizado por un usuario que tenga el nivel
de privilegios cero. En DMT el único usuario que posee el nivel de privilegios cero es la tarea cero.
• Bit presente activado. La rutina de tratamiento de la excepción se encuentra cargada en memoria.
Descriptor 4: Desbordamiento
Esta excepción es producida por el 80386 cuando el resultado de una operación no se puede almacenar en un
registro. DMT eliminará la tarea que produce esta excepción debido a que seguramente esa tarea tenga errores
de programación.
Los atributos de este descriptor son los siguientes:
• Selector: SelCode32. Cada vez que se produzca esta excepción, el procesador ejecutará el código que
se encuentra en el segmento de código protegido de 32 bits, referenciado por SelCode32. El
desplazamiento específico dentro del segmento de este segmento de código viene dado por el atributo
siguiente.
• Desplazamiento: El desplazamiento de esta excepción apunta a una rutina de tratamiento de
excepciones general, donde se produce la finalización de la tarea que generó esta excepción.
• Nivel de privilegios: Cero. Este descriptor sólo puede ser utilizado por un usuario que tenga el nivel
de privilegios cero. En DMT el único usuario que posee el nivel de privilegios cero es la tarea cero.
• Bit presente activado. La rutina de tratamiento de la excepción se encuentra cargada en memoria.
Descriptor 5: Comprobación de fronteras
Esta excepción se produce cuando se ejecuta una instrucción BOUND y encuentra que el operando excede los
límites impuestos. Cualquier tarea que produzca esta excepción será eliminada de la memoria.
Los atributos de este descriptor son los siguientes:
• Selector: SelCode32. Cada vez que se produzca esta excepción, el procesador ejecutará el código que
se encuentra en el segmento de código protegido de 32 bits, referenciado por SelCode32. El
desplazamiento específico dentro del segmento de este segmento de código viene dado por el atributo
siguiente.
• Desplazamiento: El desplazamiento de esta excepción apunta a una rutina de tratamiento de
excepciones general, donde se produce la finalización de la tarea que generó esta excepción.
• Nivel de privilegios: Cero. Este descriptor sólo puede ser utilizado por un usuario que tenga el nivel
de privilegios cero. En DMT el único usuario que posee el nivel de privilegios cero es la tarea cero.
• Bit presente activado. La rutina de tratamiento de la excepción se encuentra cargada en memoria.
Descriptor 6: Código de Operación Inválido
Esta excepción se produce cuando una tarea ejecuta un código de operación que no está definido por el 80386.
DMT toma el derecho de eliminar cualquier tarea que intente ejecutar una instrucción inválida, ya que podría
interferir en el funcionamiento global del sistema.
18
Los atributos de este descriptor son los siguientes:
• Selector: SelCode32. Cada vez que se produzca esta excepción, el procesador ejecutará el código que
se encuentra en el segmento de código protegido de 32 bits, referenciado por SelCode32. El
desplazamiento específico dentro del segmento de este segmento de código viene dado por el atributo
siguiente.
• Desplazamiento: El desplazamiento de esta excepción apunta a una rutina de tratamiento de
excepciones general, donde se produce la finalización de la tarea que generó esta excepción.
• Nivel de privilegios: Cero. Este descriptor sólo puede ser utilizado por un usuario que tenga el nivel
de privilegios cero. En DMT el único usuario que posee el nivel de privilegios cero es la tarea cero.
• Bit presente activado. La rutina de tratamiento de la excepción se encuentra cargada en memoria.
Descriptor 7: Coprocesador No Disponible
Esta excepción se produce cuando se intenta ejecutar una instrucción correspondiente al coprocesador
matemático y no se dispone de él.
Bajo el modo real, cuando se ejecuta una instrucción correspondiente al coprocesador matemático y no se
dispone de ningún copro en el sistema, el procesador no modifica ninguno de sus registros. El programa que
ejecuta esta instrucción observará que los registros del procesador no son modificados, con lo que supondrá
que el sistema no posee ningún coprocesador matemático. En el modo protegido esto no funciona igual.
Cuando se ejecuta una instrucción correspondiente al coprocesador matemático, se producirá una excepción 7.
Para que el funcionamiento sea igual que en el modo real y no se produzca esta excepción, debemos instalar
una rutina de tratamiento para la excepción 7 que se encargue de saltarse la instrucción correspondiente al
coprocesador matemático. La rutina de tratamiento de la excepción 7 puede verse en el módulo excep07.asm.
Los atributos de este descriptor son los siguientes:
• Selector: SelCode32. Cada vez que se produzca esta excepción, el procesador ejecutará el código que
se encuentra en el segmento de código protegido de 32 bits, referenciado por SelCode32. El
desplazamiento específico dentro del segmento de este segmento de código viene dado por el atributo
siguiente.
• Desplazamiento: El desplazamiento de esta excepción apunta a una rutina que se encargará de saltarse
la instrucción que va dirigida al coprocesador matemático.
• Nivel de privilegios: Cero. Este descriptor sólo puede ser utilizado por un usuario que tenga el nivel
de privilegios cero. En DMT el único usuario que posee el nivel de privilegios cero es la tarea cero.
• Bit presente activado. La rutina de tratamiento de la excepción se encuentra cargada en memoria.
Descriptor 8: Fallo Doble
Esta excepción se produce cuando produce una excepción mientras se estaba tratando a otra. Cualquier tarea
que produzca esta excepción será eliminada de la memoria.
Los atributos de este descriptor son los siguientes:
• Selector: SelCode32. Cada vez que se produzca esta excepción, el procesador ejecutará el código que
se encuentra en el segmento de código protegido de 32 bits, referenciado por SelCode32. El
• desplazamiento específico dentro del segmento de este segmento de código viene dado por el atributo
siguiente.
• Desplazamiento: El desplazamiento de esta excepción apunta a una rutina de tratamiento de
excepciones general, donde se produce la finalización de la tarea que generó esta excepción.
• Nivel de privilegios: Cero. Este descriptor sólo puede ser utilizado por un usuario que tenga el nivel
19
de privilegios cero. En DMT el único usuario que posee el nivel de privilegios cero es la tarea cero.
• Bit presente activado. La rutina de tratamiento de la excepción se encuentra cargada en memoria.
Así se ha implementado DMT 57
54
pushf
pop ax
xor ah,40h
push ax
popf
pushf
pop bx
popf
cmp ax,bx
20
Descargar