EXTENSOR DE MEMORIA DPMI.

degradado.jpg (2539 bytes) Entorno

Crear ZEUS 98 OS en modo protegido, era una de las principales premisas impuestas por el grupo de desarrollo cuando se propuso la modificación del ZEUS OS.

Programar en modo protegido, provocó un cambio de mentalidad en el grupo de desarrollo, ya que la inexperiencia era generalizada, salvo en casos puntuales. Para entrar en el modo protegido hace falta un extensor de memoria, que haga el cambio de modo real (el del 80x86), al ya nombrado modo protegido (a partir del 80x386). El cambio no fue fortuito, ya que no se provocó al cambio de programación por aumentar el nivel de conocimientos (que siempre viene bien) sino porque a partir del m P i80386, se ven modificados los registros para poder llevar a cabo una multitarea vía hardware. La multitarea soportada por ZEUS OS, era totalmente virtual, controlada por software, sin embargo la implementada por ZEUS 98 OS, intenta hacer uso por completo de los recursos y servicios implementados físicamente, con lo que el aumento de rendimiento es increíble. Además se entra también a utilizar los registros extendidos de 32 bits, en vez de los de 16 bits soportados por el modo real del i8086, con lo que los rangos de direccionamiento de memoria dejan de ser restringidos, por lo menos a nivel humano, y la cantidad de memoria direccionable se dispara hasta los 4 Gb por segmento, cantidad que hasta ahora no es normal de utilizar ni de poseer. Esto provoca una acceso a memoria de manera plana, ya que eliminamos la segmentación, típica de 64 Kb en el modo real.

Hasta aquí todo son ventajas. Pero a cambio de tener un más cómodo acceso a memoria, se tienen que implementar una serie de nuevos mecanismos, que dividan la memoria en páginas, para proporcionarlas a los procesos, y protegerlas para que las utilicen ellos. Esto se transforma en una serie de selectores que apuntan a tablas de descriptores globales y locales, y otra serie de mecanismos que no nos concierne explicar. Para más información ver anexos.

Si bien es cierto que existen versiones comerciales (DOS4GW...) y de libre distribución (PMODEW...) de extensores de memoria, se optó por crear uno propio de ZEUS 98 OS. Para llevarlo a cabo hace falta un gran conocimiento del sistema a nivel físico y de todos los medios que nos poporciona. Si no es óptimo el funcionamento del extensor, el rendimiento va a ser penoso, y si no está bien implementado no va a funcionar, por lo tanto el extensor es crítico.

Además al arrancar en un sistema no conocido, no se puden utilizar los sistemas creador por otros sistemas operativos (la útil int 21h del DOS por ejemplo). Es por ello que hay que crear toda una serie de servicios que luego se implementarán como comandos para poder realizar la programación tanto del sistema como de sus aplicaciones.

El extensor está implementado en ensamblador. Utiliza una serie de macros y valores predefinidos que se pueden encontrar en EXTENSOR.INC, TSS.ASM y SEG.ASM. La implementación real del extensor se lleva a cabo en CODIGO32.ASM. El fichero de cabecera que se debe de incluir dentro de los fuentes en C/C++ es EXTENSOR.H, y da soporte a gran parte de las funciones básicas definidas como estándar en lenguaje C, así como las extendidas de paginación y control de tareas, tanto a nivel de creación como de ejecución.

 

degradado.jpg (2539 bytes) Secuencia de arranque del extensor

El extensor sigue unos ciertos pasos que se han de dar antes de entrar en el modo protegiso. Vamos a ver de una manera escueta dentro del pseudocódigo cuales son los pasos, pues, a grandes rasgos.

  1. inicio
  2. activar_linea_A20_del procesador;
  3. iniciar_el_timer;
  4. poner_tabla_de_teclado;
  5. revectorizar_CTRL_AL_DEL;
  6. poner_tarea_padre;
  7. poner_procedimiento;
  8. permitir_IRQ_0_y_1;
  9. contador_del_timer_a_0;
  10. activar_LEDS;
  11. espera_del_teclado;
  12. inicia_teclado;
  13. inicia_disco;
  14. hacer_puntero_a_memoria_de_video;
  15. hacer_puntero_a_buffer_de_tareas;
  16. ejecutar_main;
  17. volver_al_modo_real;
  18. habilitar_linea_A20;
  19. preparar_excepciones;
  20. tratar_errores;
  21. fin.

 

Tipos predefinidos

Estructura stGDT.

La estructura stGDT, implementa el registro necesario para crear, acceder y operar en la Tabla Globales de Descriptores. El formato es impuesto por la arquitectura del m P i80386.

Para obtener más información remitimos a los anexos.

Estructura stIDT.

La estructura stIDT, implementa el registro necesario para crear, acceder y operar en la Tabla de Descriptores Locales. El formato es impuesto por la arquitectura del m P i80386.

Para obtener más información remitimos a los anexos.

Estructura stTSS

La estructura stTSS, implementa el registro necesario para crear, acceder y operar en los registro de la máquina virtuales de cada tarea. El formato es impuesto por la arquitectura del m P i80386. Los campos reservados tienen cometido de guardar alineamiento.

Para obtener más información remitimos a los anexos.

Los campos RCOUNTDOWN y RBITS, se han introducido nuevos, ya que esta técnica se permite.

Estructura stTASK

La estructura stTask, implementa el registro necesario para crear, acceder y operar en los procesos através de las tablas de descriptores. El formato es impuesto por la arquitectura del m P i80386.

Para obtener más información remitimos a los anexos.

 

Funciones

Vamos a tomar las cabeceras de las variables globales y funciones definidas en EXETENSOR.H, ya que van a ser las que se utilicen para llevar a cabo el trabajo en alto nivel. Vamos pues a describirlas:

Variables globales para memoria

Estructura Ext_MemoriaDPMI.

limit: unsigned int, longitud de memoria DPMI.

base: unsigned int, dirección real paginada.

handle: unsigned int, manejador necesario para realizar otras operaciones, lo proporciona la máquina.

Cometido: Trabajar con memoria a nivel físico. Impuesto por la arquitectura.

Estructura Ext_LDT

limit: unsigned short, longitud del descriptor.

base_low: unsigned short, 16 bits bajos de la dirección base real.

base_med: unsigned char, 8 bits medios de la dirección base real.

access: unsigned char, contenido des descriptor.

e386: unsigned char, reservado.

base_high: unsigned char, 8 bits alstos de la dirección base real.

Cometido: Designar descriptores tanto de GDT como de LDT. Impuesto por la arquitectura.

Ext_DSP_DS.

Tipo: extern unsigned short.

Cometido: Indica el segmento del DSP del programa

Ext_DSP.

Tipo: extern unsigned short.

Cometido: Parrafos que ocupa el programa.

Ext_MEM.

Tipo: extern unsigned int.

Cometido: Memoria total del sistema incluyendo las n referencias que pueden hacer n páginas a una misma dirección física.

Ext_MemoriaVideo.

Tipo: extern void far*.

Cometido: Puntero a 0xA0000, que es la memoria física de vídeo.

 

Funciones de librería para memoria.

Ext_CopiarMemoria.

p1 Ext_CopiarMemoria(p2,p3,p4);

Parámetros:

p1: void far, puntero a zona copiada.

p2: void far *, puntero de destino.

p3: void far *, puntero de origen.

p4: unsigned int, tamaño de la memoria a copiar.

Cometido: Copia desde la zona p3 a la p2, p4 bytes.

Pseudocódigo:

  1. inicio
  2. operaciones_de_pila;
  3. mover_registros;
  4. operaciones_de_pila;
  5. fin.

 

Ext_BorrarMemoria.

p1 Ext_BorrarMemoria(p2,p3);

Parámetros:

p1: void far, puntero a zona borrada.

p2: void far *, puntero a zona que se quiere borrar.

p3 unsigned int, longitud de la zona a borrar.

Cometido: Rellena de ceros memoria far.

Pseudocódigo:

  1. inicio
  2. operaciones_de_pila;
  3. mover_registros;
  4. operaciones_de_pila;
  5. fin.

 

Ext_RellenarMemoria.

p1 Ext_RellenarMemoria(p2,p3,p4);

Parámetros:

p1: void far, puntero a zona rellena.

p2: void far *, zona de destino a rellenar.

p2: unsigned int, longitud de la zona a rellenar.

p3: unsigned char, carácter para rellenar.

Cometido: Rellena de un byte memoria far.

Pseudocódigo:

  1. inicio
  2. operaciones_de_pila;
  3. mover_registros;
  4. operaciones_de_pila;
  5. fin.

 

Ext_LongitudCadena.

p1 Ext_LongitudCadena(p2);

Parámetros:

p1: size_t, devuelve la longitud de la cadena.

p2: char far *, cadena que se quiere saber la longitud.

Cometido:Indica la longitud de la cadena p2 en memoria far

Pseudocódigo:

  1. inicio
  2. operaciones_de_pila;
  3. mover_registros;
  4. operaciones_de_pila;
  5. fin.

 

Ext_CrearAcceso.

p1 Ext_CrearAcceso(p2,p3,p4,p5);

Parámetros:

p1: unsigned short far, puntero a acceso.

p2: unsigned int, tipo que apunta el descriptor.

p3: unsigned int, nivel de privilegio.

p4: unsigned int, se crea un acceso por defecto,

p5: unsigned int, granuralidad de la memoria.

Cometido: Crea el acceso de un descriptor.

Pseudocódigo:

  1. inicio
  2. operaciones_de_pila;
  3. mover_registros;
  4. operaciones_de_pila;
  5. fin.

 

Ext_CrearSelector.

p1 Ext_CrearSelector(p2,p3,p4);

Parámetros:

p1: unsigned short far, devuelve selector o error.

p2: unsigned int, dirección base del selector.

p3: unsigned int, tamaño del selector.

p4: unsigned short, tipo de acceso del selector.

Cometido: Crea un selector y devuelve su valor, si el resultado es menor que 0 se hqa producido un error.

Pseudocódigo:

  1. inicio
  2. operaciones_de_pila;
  3. mover_registros;
  4. llamar_int_31h;
  5. mover_registros;
  6. fin.

 

Ext_HacerSelector.

p1 Ext_HacerSelector(p2,p3,p4,p5);

Parámetros:

p1: unsigned short far, selector de vuelto o error.

p2: unsigned int, dirección base.

p3: unsigned short, tamaño del selector.

p4: unsigned short, tipo de acceso del selector.

p5: unsigned short, selector a modificar.

Cometido: Hacer/Rehacer un selector Reservado que ya está creado. Devuelve el valor del selector o menor de 0 si ha habido error.

Pseudocódigo:

  1. incio
  2. operaciones_de_pila;
  3. mover_registros;
  4. llamar_int_31h;
  5. operaciones_de_pila;
  6. mover_registros;
  7. llamar_int_31h;
  8. mover_registros;
  9. tratar_errores;
  10. fin.

 

Ext_DestruirSelector.

p1 Ext_DestruirSelector(p2);

Parámetros:

p1: int far, valor devuelto.

p2: unsigned short, selector a destruir.

Cometido: Libera un descriptor (selector). Devuelve 0 si ha habido éxito.

Pseudocódigo:

  1. inicio
  2. operaciones_de_pila;
  3. mover_registros;
  4. llamar_int_31h;
  5. operaciones_de_pila;
  6. mover_registros;
  7. fin.

 

Ext_ReservarMemoriaDPMI.

p1 Ext_ReservarMemoriaDPMI(p2);

Parámetros:

p1: int far, valor devuelto.

p2: Ext_MemoriaDPMI far*, registro de creación de memoria.

Cometido: Por el limite de variable estruturada. Devuelve -1 si no ha habido éxito.

Pseudocódigo:

  1. inicio
  2. operaciones_de_pila;
  3. mover_registros;
  4. llamar_int_31h;
  5. mover_registros;
  6. operaciones_de_pila;
  7. tratar_errores;
  8. fin.

 

Ext_LiberarMemoriaDPMI

p1 Ext_LiberarMemoriaDPMI(p2);

Parámetros:

p1: int far, valor devuelto.

p2: Ext_MemoriaDPMI far*, registro de memoria a liberar.

Cometido: Libera memoria DPMI a partir del Handle.Devuelve -1 si no ha habido éxito.

Pseudocódigo:

  1. inicio
  2. operaciones_de_pila;
  3. mover_registros;
  4. llamar_int_31h;
  5. mover_registros;
  6. operaciones_de_pila;
  7. tratar_errores;
  8. fin.

 

Ext_HacerPuntero.

p1 Ext_HacerPuntero(p2,p3,p4);

Parámetros:

p1: void far, valor devuelto.

p2: unsigned short, selector.

p3: unsignded int, desplazamiento.

p4: void far* far *, puntero.

Cometido: Crea un puntero dando selector y desplazamiento.

Pseudocódigo:

  1. inicio
  2. operaciones_de_pila;
  3. mover_registros;
  4. movimientos_de_registros;
  5. fin.

 

Ext_Segmento.

p1 Ext_Segmento(p2);

Parámetros:

p1: unsigned short far, develve el selector del puntero.

p2 void far *, puntero del que se quiere el selector.

Cometido: Devuelve el selector de un puntero

Pseudocódigo:

  1. inicio
  2. movimientos_de_registros;
  3. fin.

 

Ext_Desplazamiento

p1 Ext_Desplazamiento(p2);

Parámetros:

p1: unsigned int far, devuelve el desplazamiento.

p2: void far *, puntero del que se quiere saber el desplazamiento.

Cometido: Devuelve el desplazamiento de un puntero.

Pseudocódigo:

  1. inicio
  2. devolver desplazamiento;
  3. fin

 

Ext_DescriptorLDT.

p1 Ext_DescriptorLDT( p2,p3,p4,p5);

Parámetros:

p1: void far, devuelve puntero a descriptor.

p2: unsigned int, posición del selector.

p3: unsigned int, dirección base.

p4: unsigned short, tamaño del descriptor.

p5: insigned short, manejador del descriptor.

Cometido: Completa LDT.

Pseudocódigo:

  1. inicio
  2. operaciones_de_pila;
  3. movimientos_de_registros;
  4. llamada_a_32b;
  5. movimientos_de_registros;
  6. operaciones_de_pila;
  7. fin.

 

Ext_Copy2LDT.

p1 Ext_Copy2LDT( p2,p3,p4,p5);

Parámetros:

p1: void far, devuelve el puntero a selector creado en LDT.

p2: unsigned short, entrada de la GDT que se quiere copiar.

p3: unsigned short, identificador de tarea que se quiere copiar.

p4: unsigned int, Entrada en la LDT.

p5: unsigned int, nivel de privilegio.

Cometido: Copia un selector GDT a LDT

Pseudocódigo:

  1. inicio
  2. operaciones_de_pila;
  3. movimientos_de_registros;
  4. operaciones_de_pila;
  5. fin.

 

Ext_malloc.

p1 Ext_malloc(p2);

Parámetros:

p1: void *, devuelve el puntero a la zona de memoria reservada.

p2: size_t, tamaño de la memoria a reservar.

Cometido: Reserva una porción de memoria near de tamaño p2. Si hay error devuelve NULL.

Pseudocódigo:

  1. inicio
  2. operaciones_de_pila;
  3. movimientos_de_registros;
  4. operaciones_con_registros;
  5. operaciones_de_pila;
  6. tratar_error;
  7. fin.

 

Ext_calloc.

p1 Ext_calloc(p2,p3);

Parámetros:

p1: void *, puntero devuelto a la zona reservada.

p2: size_t, número de elementos a reservar.

p3:size_t, tamaño del elemento.

Cometido: Asigna memoria de tamaño p2*p3 y devuelve el puntero a la zona reservada, si hay error devuelve NULL.

Pseudocódigo:

  1. inicio
  2. operaciones_de_pila;
  3. operaciones_con_registros;
  4. movimientos_de_registros;
  5. llamar_malloc;
  6. operaciones_con_registros;
  7. llamar_a_memset;
  8. operaciones_de_pila;
  9. fin.

 

Ext_free.

Ext_free(p1);

Parámetros:

p1: void *, puntero a la zona de memoria a liberar.

Cometido: Libera una zona de memoria apuntada por un puntero.

Pseudocódigo:

  1. inicio
  2. operaciones_de_pila;
  3. movimientos_de_registros;
  4. operaciones_con_registros;
  5. movimientos_de_registros;
  6. operaciones_de_pila;
  7. fin.

 

Ext_memcpy.

p1 Ext_memcpy(p2,p3,p4);

Parámetros:

p1: void *, puntero a la zona copiada.

p2: void *, puntero al destino de la copia.

p3: void *, puntero al origen de la copia.

p4: size_t, tamaño de memoria a copiar.

Cometido: copia una porción de memoria de p3 a p2 de tamaño p4.

Pseudocódigo:

  1. inicio
  2. operaciones_de_pila;
  3. movimientos_de_registros;
  4. operaciones_con_registros;
  5. operaciones_de_pila;
  6. fin.

 

Ext_memset.

p1 Ext_memset(p2,p3,p4);

Parámetros:

p1: void *, puntero a la zona rellena.

p2: void *, puntero a la zona rellena.

p3: int, carácter con el que se quiere rellenar la zona (atención rellena con 16 bits).

p4: size_t: número de carácteres a poner dentro de la zona.

Cometido: Rellena una zona de memoria apuntada por p2, poniendo el carácter p3, p4 veces, devuelve la zona en p1, si hay error devuelve NULL.

Pseudocódigo:

  1. inicio
  2. operaciones_de_pila;
  3. movimientos_de_registros;
  4. operaciones_con_registros;
  5. operaciones_de_pila;
  6. fin

 

Ext_strlen.

p1 Ext_strlen(p2);

Parámetros:

p1: size_t, devuelve el tamaño de la cadena.

p2: const char *, cadena que se quiere medir.

Cometido: Devuelve la longitud de una cadena p2.

Pseudocódigo:

  1. inicio
  2. operaciones_de_pila;
  3. movimientos_de_registros;
  4. operaciones_con_registros;
  5. operaciones_de_pila;
  6. fin.

 

Ext_strcpy.

p1 Ext_strcpy(p2,p3);

Parámetros:

p1: char *, cadena devuelta, destino.

p2: char *, cadena de destino.

p3: char *, cadena de origen.

Cometido: Copia una cadena p2, en p1. En caso de error devuelve NULL.

Pseudocódigo:

  1. inicio
  2. operaciones_de_pila;
  3. movimientos_de_registros;
  4. operaciones_con_registros;
  5. operaciones_de_pila;
  6. fin.

 

Ext_strncpy.

p1 Ext_strncpy(p2,p3,p4);

Parámetros:

p1: char *, cadena de destino.

p2: char *, cadena de destino.

p3: char *, cadena de origen.

p4: size_t, número de caractéres.

Cometido: Copia los p4 primeros caractéres de p3 en p2.

Pseudocódigo:

  1. inicio
  2. operaciones_de_pila;
  3. movimientos_de_registros;
  4. operaciones_con_registros;
  5. operaciones_de_pila;
  6. fin

 

Ext_strset.

p1 Ext_strset(p2,p3);

Parámetros:

p1: char *, cadena de destino.

p2: char *, cadena de destino.

p3: int, carácter para rellenar.

Cometido: Rellena una cadena de caractéres p2, con el carácter p3. p3 es un entero de 32 bits.

Pseudocódigo:

  1. inicio
  2. operaciones_de_pila;
  3. movimientos_de_registros;
  4. operaciones_con_registros;
  5. operaciones_de_pila;
  6. fin

 

Ext_strnset.

p1 Ext_strnset(p2,p3,p4);

Parámetros:

p1: char *, cadena a modificar devuelta.

p2: char *, cadena a modificar.

p3: int, carácter para rellenar.

p4: size_t, número de caractéres a escribir.

Cometido: Rellena los p4 primeros caractéres de p2 con el carácter p3. Atención el carácter es de 32 bits.

Pseudocódigo:

  1. inicio
  2. operaciones_de_pila;
  3. movimientos_de_registros;
  4. operaciones_con_registros;
  5. operaciones_de_pila;
  6. fin

 

Ext_strcmp.

p1 Ext_strcmp(p2,p3);

Parámetros:

p1: int, valor devuelto de la comparación.

p2: char *, cadena 1 para la comparación.

p3: char *, cadena 2 para la comparación.

Cometido: Compara las cadena p2 y p3. Puede devolver:

Menor que 0, si p2 es menor que p3

0 si son iguales.

mayor que 0, si p2 es mayor que p3.

Pseudocódigo:

  1. inicio
  2. operaciones_de_pila;
  3. movimientos_de_registros;
  4. operaciones_con_registros;
  5. operaciones_de_pila;
  6. fin

 

Ext_strncmp.

extern int Ext_strncmp( const char *__s1, const char *__s2, size_t __n );

Parámetros:

p1: int, valor devuelto de la comparación.

p2: char *, cadena 1 para la comparación.

p3: char *, cadena 2 para la comparación.

p4: size_t, númreo de caractéres a comparar.

Cometido: Compara los p4 primeros caractéres de las cadena p2 y p3. Puede devolver:

Menor que 0, si p2 es menor que p3

0 si son iguales.

mayor que 0, si p2 es mayor que p3.

Pseudocódigo:

  1. inicio
  2. operaciones_de_pila;
  3. movimientos_de_registros;
  4. operaciones_con_registros;
  5. operaciones_de_pila;
  6. fin

 

Variables globales del timer.

Estructura Ext_TSS.

Corresponde a la esctructura de un estado tarea, corresponde a los registros propios de la tarea, que se restauran cuando va a entrar a ejecutarse durante un quanto de tiempo, y que se guardan cuando termina su tiempo de ejecución.

Está dispuesto en forma de lista, unida por el campo backlink que es el enlace al TSS anterior. De su manejo es totalmente responsable el m P i80386. La estructura está impuesta por la arquitectura, con lo que se remite a anexos.

 

Estructura Ext_Task.

Define la estructura de una tarea a nivel físico. Gracias a la estructura de este registro se pueden hacer referencias a tareas desde las GDT y LDT.

 

Ext_TIMER_COUNT.

Tipo: unsigned int.

Cometido: Cuenta del timer.

Ext_TIMER_OVERFLOW.

Tipo: unsigned int.

Cometido: Overflows de la cuenta del timer.

Ext_TIMER_ACTUAL.

Tipo: unsigned short.

Cometido: Numero de la tarea actual.

Ext_TASK_BUFFER.

Tipo: unsigned short far *.

Cometido: Puntero a buffer de tareas.

Ext_TASK.

Tipo: unsigned short.

Cometido: Identificador de la tarea actual (ID del Ext_TSS).

Ext_END_TASKS.

Tipo: unsigned int.

Cometido: Número de tareas terminadas.

Ext_TIMER_ERROR.

Tipo: void far*, puntero a procedimiento.

Cometido: Contiene el puntero al procedimiento que se ejecutará en caso de error crítico del timer.

 

Funciones de librería de timer.

Ext_settimer.

Ext_settimer(p1);

Parámetros:

p1: unsigned short, velocidad del timer.

Cometido: Ajustar la velocidad del timer. El valor de p1 debe de estar entre 0FFFFh y 0h.

Pseudocódigo:

  1. inicio
  2. operaciones_de_pila;
  3. operaciones_con_registros;
  4. operaciones_de_pila;
  5. fin.

 

Ext_readtimer.

p1 Ext_readtimer();

Parámetros:

p1: unsigned short, devuelve la velocidad del timer.

Cometido: Devolver la velocidad actual del timer.

Pseudocódigo:

  1. inicio
  2. operaciones_de_pila;
  3. operaciones_con_registros;
  4. fin.

 

Ext_ExclusionMutua.

Ext_ExclusionMutua(p1);

Parámetros:

p1: int, booleano.

Cometido: Provoca la interrupción de cambios de tarea, si =1, no se producen cambios de tarea, si =0, si que los hay. Se utiliza para proteger zonas críticas, en caso de exclusión mútua.

Pseudocódigo:

  1. inicio
  2. operaciones_con_registros;
  3. fin.

 

Ext_NextTask.

Ext_NextTask(p1);

Parámetros:

p1: int, veces que se ejecuta la interrupción del timer hasta pasar de tarea.

Cometido: Cambiar rápidamente de tarea, a la siguiente de la cola. con valor 1, cambia de tarea al recibir una señal del timer. Atención el valor 0 corresponde al máximo, serían 65535 señales de timer, lo que supondría varias horas.

Pseudocódigo:

  1. inicio
  2. operaciones_de_pila;
  3. operaciones_con_registros;
  4. operaciones_de_pila;
  5. fin;

 

Ext_InicTask.

p1 Ext_InicTask(p2,p3,p4);

Parámetros:

p1: unsigned short far, devuelve la base del selector (ID del Ext_TSS).

p2: unsigned int, tamaño de la pila.

p3: unsigned int, tamaño de la LDT.

p4 unsigned short, nivel de privilegio.

Cometido: Inicia una tarea, devuelve su identificador, si devuelve 0FFFFh es que ha incurrido en un error.

Pseudocódigo:

  1. inicio
  2. operaciones_de_pila;
  3. reserva_memoria;
  4. reservar_4_descriptores;
  5. movimientos_de_registros;
  6. crear_acceso;
  7. movimientos_de_registros;
  8. hacer_selector;
  9. movimientos_de_registros;
  10. crear_acceso;
  11. movimientos_de_registros;
  12. hacer_selector;
  13. movimientos_de_registros;
  14. crear_acceso;
  15. movimientos_de_registros;
  16. hacer_selector;
  17. movimientos_de_registros;
  18. crear_acceso;
  19. movimientos_de_registros;
  20. hacer_selector;
  21. completar_LDT;
  22. tratar_error;
  23. devolver selector;
  24. fin.

 

Ext_FreeTask.

Ext_FreeTask(p1);

Parámetros:

p1: unsigned short, identificador o base del selector.

Cometido: Libera una tarea especificada por p1, esto conlleva eliminar memoria y selectores asociados.

Pseudocódigo:

  1. inicio
  2. operaciones_de_pila;
  3. libera_memoria_DPMI;
  4. libera_descriptores;
  5. operaciones_con_registros;
  6. operaciones_de_pila;
  7. fin.

 

Ext_NewTask.

p1 Ext_NewTask(p2);

Parámetros:

p1: unsigned short, valor del ID devuelto.

p2: Ext_Task far *,

Cometido: Completa básicamente tarea. Devuelve el ID de la tarea o 0 si se ha incurrido en error.

Pseudocódigo:

  1. inicio
  2. operaciones_de_pila;
  3. movimientos_de_registros;
  4. iniciar_tarea;
  5. operaciones_con_registros;
  6. hacer_puntero_TSS;
  7. hacer_puntero_LDT;
  8. operaciones_de_pila;
  9. movimientos_de_registros;
  10. copiar_GDT_a_LDT;
  11. movimientos_de_registros;
  12. actualizar_TSS;
  13. operaciones_de_pila;
  14. tratar_error;
  15. devolver selector;
  16. fin.

 

Variables globales de teclado.

Ext_KEYBOARD_HIT.

Tipo: unsigned char.

Cometido: Corresponde a la última tecla pulsada.

Ext_KEYBOARD_SPEC.

Tipo: unsigned char.

Cometido: Número de teclas pulsadas.

Ext_KEYBOARD_KEY.

Tipo: Array [256] del tipo unsigned char;

Cometido: Array de booleanos de teclas pulsadas.

Ext_KEYBOARD_BUFF.

Tipo: Array [1024] unsigned char.

Cometido: Buffer de teclado.

Ext_KEYBOARD_READ.

Tipo: unsigned short.

Cometido: Puntero del buffer para escritura.

Ext_KEYOBARD_WRITE.

Tipo: extern unsigned short.

Cometido: Puntero del buffer para escritura.

Ext_KEYBOARD_LEDS.

Tipo: extern unsigned char.

Cometido: es un booleano, controla el funcionamiento de los LEDS de teclado (NumLock, CapsLock, ScrollLock)

Ext_KEYBOARD_OVERFLOW.

Tipo: extern unsigned char Ext_KEYBOARD_OVERFLOW;

Cometido: Es un booleano que avisa sobre la sobrecarga de buffer de teclado.

Ext_KEYBOARD_CAPS.

Tipo: unsigned char.

Cometido: Booleano que indica el bloqueo de mayúsculas.

Ext_KEYBOARD_NUM.

Tipo: unsigned char.

Cometido: Booleano que indica el bloqueo de teclado numérico.

Ext_KEYBOARD_BLOQ.

Tipo: unsigned char.

Cometido: Booleano que indica el bloqueo de desplazamiento.

Ext_CTRL_ALT_DEL.

Tipo: unsigned char.

Cometido: Booleano que captura el resultado de CTRL+ALT+DEL.

Ext_CTRL_ALT_DEL_PROC.

Tipo: extern void far* Ext_CTRL_ALT_DEL_PROC();

Cometido: Puntero al procedimiento en caso de CTRL+ALT+DEL.

Ext_KEYBOARD_MAP.

Tipo: extern void far *.

Cometido: Puntero hacia el mapa de teclado. Por defecto en español.

KEYBOARD_CERO.

Tipo: extern unsigned char.

Cometido: Booleano que indica si se ha pulsado una combinación de teclas con Shift, Control, Alt, Fxx…

 

Funciones de librería de teclado.

Ext_keyboardleds.

Ext_keyboardleds();

Parámetros: No necesita.

Cometido: Actualizar los LEDS del teclado. Da problemas con procesadores Ciryx, con Intel y AMD funciona correctamente.

Pseudocódigo:

  1. inicio
  2. operaciones_de_pila;
  3. movimientos_de_registros;
  4. entradas_salidas en puertos;
  5. operaciones_de_pila;
  6. fin.

 

Ext_keypressed.

p1 Ext_keypressed();

Parámetros:

p1: unsigned int, indica si se ha pulsado una tecla.

Cometido: Booleano que indica si ha sido pulsada una tecla.

Pseudocódigo:

  1. inicio
  2. operaciones_de_pila;
  3. operaciones_con_registros;
  4. comparaciones_con_valores_de_teclas;
  5. operaciones_de_pila;
  6. fin.

 

Ext_map.

Ext_map(p1);

Parámetros:

p1: void far *, mapa de teclado.

Cometido: Cambiar el mapa de teclado.

Pseudocódigo:

  1. inicio
  2. operaciones_de_pila;
  3. movimientos_de_registros;
  4. operaciones_de_pila;
  5. fin.

 

Ext_getch.

p1 Ext_getch();

Parámetros:

p1: unsigned char, carácter pulsado.

Cometido: Espera a la pulsación de una tecla y devuelve su carácter ASCII.

Pseudocódigo:

  1. inicio
  2. operaciones_de_pila;
  3. movimientos_de_registros;
  4. llamada_a_keypressed;
  5. operaciones_con_registros;
  6. comparaciones_con_caracteres;
  7. operaciones_de_pila;
  8. devolver ascii;
  9. fin.

 

Ext_keyhit.

p1 Ext_keyhit();

Parámetros:

p1: unsigned int, devuelve el código de la tecla pulsada.

Cometido: Boolano que devuelve el código de la tecla pulsada.

Pseudocódigo:

  1. inico
  2. operaciones_de_pila;
  3. movimientos_de_registros;
  4. operaciones_con_registros;
  5. operaciones_de_pila;
  6. fin.

 

Ext_getkey.

p1 Ext_getkey();

Parámetros:

p1: unsigned char, código devuelto de la tecla pulsada.

Cometido: Funciona como Ext_getch, pero devolviendo el código de la tecla pulsada.

Pseudocódigo:

  1. inicio
  2. operaciones_de_pila;
  3. movimientos_de_registros;
  4. llamada_a_keyhit;
  5. operaciones_con_registros;
  6. comparaciones_con_caracteres;
  7. operaciones_de_pila;
  8. devolver ascii;
  9. fin.

 

Tratamiento de excepciones.

 

Cuando ocurre un error a nivel físico, nos vamos a encontrar con una serie de señales que lanza el sistema a nivel de interrupción. Para asegurar la estabilidad del sistema, se deben capturar y ejecutar cierto código para saber lo que ha ocurrido.

Excepciones del sistema.

Revectorización de excepciones.

Para provocar la ejecución de un proceso en el momento en el que se transgriede la integridad del sistema se definen una serie de variables globales con forma de puntero lejano a función, a las que habrá que asignar el puntero al procedimiento deseado. Vamos a ver la forma:

Procedimiento en excepcion X

extern void far* Ext_EXCEPCION_X_PROC();

Se deberá sustituir la X por el número de excepción que queramos revectorizar, p.e. para la excepción 9 será:

  1. #include <extensor.h>
  2. #define ExtERROR
  3. // Función a ejecutar en caso de excepcion
  4. //"coprocesador no disponible".
  5. int revectorizar_excepción_7()
  6. {
  7. puts("¡¡Coprocesador no disponible!!");
  8. Ext_kbhit();
  9. return ExtERROR;
  10. };
  11.  
  12. void main
  13. {
  14. //Revectorizamos a porcedimiento de excepción del sistema.
  15. //Cuando se vaya a utilizar el coprocesador, y no esté
  16. //disponible veremos el mensaje:
  17. // ¡¡Coprocesador no disponible!!
  18. Ext_EXCEPCION_7_PROC=revectorizar_excepcion_7;
  19. };

Recordar que las interrupciones van de la 0 a la 17.

 

Tratamiento de interrupciones.

Con el tratamiento de las interrupciones va a pasar algo parecido a lo de las interrupciones. Mediante el controlador de interrupciones podremos acceder a diferentes dipositivos. De la misma manera podremos revectorizar funciones que nos llevan a ellos.

IRQ’s del sistema.

Por el momento están implementadas las dos primeras interrupciones, la del timer y la del teclado, con ellas es suficiente para hacer funcionar el sistema, pero hay que decir, que se restringe bastante su uso.

TRAP’s del sistema.

En el sistema también nos podemos encontrar con una serie de TRAP’s del sistema. Son las siguientes:

Las disponibles se pueden utilizar a gusto del programador de aplicaciones.

Revectorización de interrupciones.

El tratamiento de revectorización de interrupciones se va a llevar a cabo como las de las excepciones. Crearemos un procedimiento en el que codificaremos lo que creamos conveniente, y este código se lo asignaremos al procedimiento que se ha de ejecutar en el momento en el que se produzca la interrupción.

Cuando se produzca una interrupción no válida se ejecutará EXT_INT_INVALIDA_PROC, que está definido como se indica, en la parte inmediatamente inferior.

extern void far* EXT_INT_INVALIDA_PROC();

Para las demás interrupciones vamos a seguir la misma normativa que para las excepciones:

Para el timer de usuario:

extern void far* Ext_IRQ0_PROC(); // Timer de usuario

Para el teclado de usuario:

extern void far* Ext_IRQ1_PROC(); // Teclado usuario

Para el resto de las interrupciones:

extern void far* Ext_IRQX_PROC();

X debe cambiarse por el número de interrupción, en el rango de 2 a 0Fh (en el caso de numeración hexadecimal sólo pondremos la letra correspondiente p.e.: Ext_IRQE_PROC()).

Revectorización de TRAP’s.

Exactamente lo mismo que en las excepciones y las interrupciones, crearemos un procedimiento y su dirección se lo asignaremos a la variable propia para el TRAP a tratar.

extern void far* Ext_TRAPX_PROC();

Cambiar la X por el número de trapar que se quiere revectorizar p.e. Ext_TRAP3A_PROC.

Las TRAPS llevan una numeración dentro de un rango del 32 al 3Fh, si utilizamos una numeración en hexadecimal, al sustituir por la X, debemos omitir la h.

 

Sobrecarga de operadores para C++.

Durante la codificación del sistema, hubo problemas con la orientación hacia los objetos. Esto era porque al instanciar las clases, se producían una serie de errores, que no venían a cuenta. El problema era que al programar con un compilador propio para DOS, a la hora de crear o destruir las instancias, los operadores new y delete, hacían un acceso a los servicios del DOS, y cuando se ejecutaban los programas bajo el extensor, obviamente producía un fallo.

La solución fué sencilla, se sobrecargaron los operadores, utilizando las funciones de librería de bajo nivel creadas en el extensor de ZEUS 98 OS.

El modo de uso está docuementado en cualquier manual de C/C++. El resultado fué el siguiente.

Operador new.

  1. void * operator new(size_t t)
  2. {
  3. return Ext_malloc(t);
  4. }
  5. void * operator new(size_t t, int n)
  6. {
  7. return Ext_malloc(t*n);
  8. }

Operador delete.

  1. void operator delete(void *q)
  2. {
  3. Ext_free(q);
  4. }


zeusv2@geocities.com

Última actualización de la página: 12/03/99


Esta página está hospedada en   Consigue tu Página Web Gratis