enunciados

Anuncio
Diseño de sistemas operativos
Ingeniería Superior de Informática
PRACTICA #1
OBJETIVOS:
Aprender a programar una interrupción software empleando C y/o
Ensamblador.
Aprender a manipular dispositivos externos (8253, 8255) desde C y/o
ensamblador.
PROCEDIMIENTO: Vamos a programar una rutina que produzca un pitido (beep) a través del
altavoz del PC y vamos a instalarla en la interrupción 7FHex, para invocarla como si se tratara
de una llamada al sistema.
Los pasos a realizar son los siguientes:
a) Programar la subrutina como una función C.
a.0) Guardar el contenido actual de los registros a utilizar en la pila, si es necesario (si no
se identifica la función como rutina de servicio a una interrupción, suponiendo que sea
posible).
a.1) Configurar el contador #2 del 8253/8253-5/8254 para trabajar en modo 3.
a.2) Cargar el valor inicial de cuenta, primero el byte menos significativo. Este valor
determina la frecuencia del pitido:
Frecuencia = 1.193.180 / (valor inicial de cuenta)
Frecuencia máxima = 1.193.180 / 1 = 1,193 MHz
Frecuencia mínima = 1.193.180 / 65535 = 18,2 Hz
a.3) Activar temporizador y altavoz: poner a 1 los bits #0 y #1 del puerto B del 8255.
a.4) Controlar la duración del pitido: bucle de retardo.
a.5) Desactivar el temporizador y el altavoz: poner a 0 los bits #0 y #1 del puerto B del
8255.
a.6) Restaurar registros modificados y retornar de interrupción, si es necesario (si no lo
hace el compilador).
b) Disponer la dirección completa de la subrutina en la entrada correspondiente de la tabla de
interrupciones del 80x86.
c) Invocar la interrupción desde el programa C.
Alberto Ortiz
Diseño de sistemas operativos
Ingeniería Superior de Informática
PRACTICA #2
OBJETIVOS:
Aprender a programar funciones C en ensamblador, paso de parámetros
incluido.
PROCEDIMIENTO: Vamos a programar la función de la práctica #1 íntegramente a base de
ensamblador en línea (directiva asm), y a pasarle dos parámetros: el periodo y la duración del
pitido. El periodo será un valor de 16 bits comprendido entre 1 y 65535 ciclos del reloj básico
(1.193.180 Hz). La duración será un valor de 32 bits correspondiente al número de iteraciones
del bucle de retardo. Así pues, a nuestra función le corresponderá una cabecera tal como:
void beep (p : unsigned; d : unsigned long)
Los pasos a seguir son:
a*) Apuntar el registro BP hacia el registro de activación de la función:
Push BP
Mov BP, SP
En este momento, el stack, si la función ha sido declarada tipo FAR, está de la siguiente forma:
SS:SP, SS:BP ->
d (high)
d (low)
p
CS
IP
BP
[BP + 10]
[BP + 8]
[BP + 6]
[BP + 4]
[BP + 2]
Si la función es tipo NEAR, el CS no está (los parámetros empezarán en BP + 4).
b) Codificar la función, capturando los parámetros de la siguiente forma:
Mov rr, word ptr [BP + d]
c*) Retornar, restaurando el registro BP a su valor original:
Mov SP, BP
Pop BP
Ret
d) Invocar la función Beep, pasándole distintos parámetros de periodo y duración.
*
El compilador ya genera este código de forma automática, por lo que, de hecho, hemos de prescindir de él. Si lo
introducimos, duplicamos código, y en particular introducimos el BP dos veces en la pila, por lo que los parámetros
ya no se encontrarán en las posiciones previstas.
Alberto Ortiz
Diseño de sistemas operativos
Ingeniería Superior de Informática
PRACTICA #3
OBJETIVOS:
Aprender a gestionar las interrupciones generadas por el temporizador del
sistema.
PROCEDIMIENTO: Vamos a programar una especie de "spooler" de impresora, pero sobre la
pantalla. El programa ha de "imprimir" (visualizar) el contenido de un cierto fichero de texto,
cuyo nombre se ha de pasar como parámetro al mismo programa. La idea consiste en instalar
una rutina de servicio a la interrupción generada por el temporizador (08h ó 1Ch — mejor esta
última) que, en cada invocación, visualice un carácter del fichero de texto, hasta terminar
(momento en el cual deberá modificar cierto flag para que el programa principal desinstale
nuestra rutina).
Para facilitar la programación, antes de visualizar nada, el programa leerá todo el fichero de
texto y lo almacenará en un buffer (un string de C), convenientemente dimensionado. El tamaño
de dicho buffer puede ser definido de forma dinámica, para lo cual habrá que determinar
previamente el tamaño del fichero; o bien de forma estática, por lo que el tamaño del fichero no
podrá superar cierto límite preestablecido (p.ej. 64 Kb).
El puntero a dicho buffer será el único parámetro que necesitará la rutina de interrupción. Esta
información, pero, no puede ser pasada a través de la pila, sino que ha de ser una variable global
del programa, así como las variables cuyo contenido sea necesario conservar de una invocación
a la siguiente.
Los pasos a seguir serán:
a) Definir el buffer y leer el fichero de texto. Si no se ha determinado el tamaño del mismo,
dentro del buffer, el final del texto se señalizará con un carácter especial ('\0', $, etc.)
b) Inicializar las variables que ha de emplear la rutina de "impresión" (visualización). Entre
otras:
- dirección del siguiente carácter a "imprimir" (visualizar)
- contador de caracteres (en caso necesario)
c) Instalar la rutina de interrupción en el vector 08h ó 1Ch (mejor esta última si queremos que se
siga ejecutando la rutina de servicio instalada por MS-DOS en respuesta al temporizador)
NOTA: En relación a la rutina de "impresión" (visualización), se puede emplear printf, aunque
hay que tener en cuenta que es una función C que consume mucha CPU dada su complejidad. La
ventaja que tiene es que realiza el SCROLL de la pantalla.
Alternativamente al uso de printf, se puede utilizar la función 02h de la interrupción 21h
instalada por el DOS. El único parámetro que necesita esta función es el código ASCII del
carácter a "visualizar" (imprimir), que se pasa a través de DL. Recordad que para invocar una
función de la interrupción 21h hay que introducir el número de la función en el registro AH,
antes de ejecutar INT 21h. Esta función también realiza el SCROLL de la pantalla.
También se puede visualizar un carácter accediendo a la BIOS, a través de la interrupción 10h,
función 0Eh. El número de función también se pasa via AH. En AL se pasa el código ASCII del
carácter. También realiza el SCROLL de la pantalla.
Alberto Ortiz
Diseño de sistemas operativos
Ingeniería Superior de Informática
Aparte de otras funciones de la BIOS y el DOS que realizan funciones similares a las anteriores,
otra posibilidad consiste en acceder directamente al buffer de video, aunque de esta manera la
función de SCROLL la hemos de implementar nosotros. El buffer de video, en el caso de tarjetas
en color y en el modo 80 × 25, comienza en la dirección de memoria B800:0000 y ocupa 80 × 25
× 2 bytes. En este buffer, las diferentes posiciones de pantalla están asociadas a palabras (16 bits)
consecutivas, donde el byte alto corresponde al atributo del carácter (color y parpadeo —0Fh
para blanco sobre negro, sin parpadeo) y el byte bajo corresponde al código ASCII del mismo
carácter.
Alberto Ortiz
Diseño de sistemas operativos
Ingeniería Superior de Informática
PRACTICA #4
OBJETIVOS:
Aprender a programar una subrutina en ensamblador que pueda ser invocada
como una función C.
PROCEDIMIENTO: Esta práctica consiste en programar dos subrutinas en ensamblador para
visualización de cadenas de caracteres. Los prototipos de estas dos subrutinas serán:
void write (unsigned char atr, unsigned char x, unsigned char y, char *s)
función : visualizar un texto en pantalla
atr : atributo de color, fondo y parpadeo
x, y : posición de la pantalla
s : puntero al texto a imprimir
void cls (unsigned char atr)
función : borrar la pantalla con un cierto color de fondo
atr : atributo de color, fondo y parpadeo
El programa ensamblador correspondiente deberá presentar la siguiente estructura:
<code> SEGMENT BYTE PUBLIC 'CODE'
ASSUME CS : <code>
_write PROC {FAR | NEAR}
<código función write>
_write ENDP
_cls PROC {FAR | NEAR}
<código función cls>
_cls ENDP
<code> ENDS
END
Dependiendo del modelo de memoria escogido, <code> será o bien _TEXT (tiny, small y
compact) o bien <nombre_fichero>_TEXT (medium, large y huge).
Dentro de ambas funciones, el procedimiento de paso de parámetros es el ya discutido
anteriormente. Para poder utilizar estas funciones desde otro programa C hay que informar
apropiadamente al ensamblador y al compilador de C. En primer lugar, hay que indicar al
ensamblador que estas funciones van a ser accedidas desde el exterior. Para ello hay que insertar
la directiva PUBLIC _write, _cls a continuación de la directiva ASSUME.
En segundo lugar, en el programa C desde el que se utilicen estas funciones hay que declarar los
prototipos de la siguiente forma:
void extern write (unsigned char atr, unsigned char x, unsigned char y, char *s);
void extern cls (unsigned char atr);
Alberto Ortiz
Diseño de sistemas operativos
Ingeniería Superior de Informática
En cuanto a su implementación, las funciones write y cls deberán acceder directamente al buffer
de video. En el caso de tarjetas en color y en el modo 80 × 25, el buffer de video comienza en la
dirección de memoria B800:0000 y ocupa 80 × 25 × 2 bytes. En este buffer, las diferentes
posiciones de pantalla están asociadas a palabras (16 bits) consecutivas, donde el byte alto
corresponde al atributo del carácter (color y parpadeo —0Fh para blanco sobre negro, sin
parpadeo) y el byte bajo corresponde al código ASCII del mismo carácter.
NOTA: Codificar estas funciones de forma reentrante; esto es, todas las variables han de ser
locales y definidas sobre la pila. Para obtener el .OBJ correspondiente a las funciones hay que
utilizar el ensamblador, no el compilador de C. Luego, desde el compilador se enlazan los
disintos módulos que componen el programa.
Alberto Ortiz
Diseño de sistemas operativos
Ingeniería Superior de Informática
PRACTICA #5
OBJETIVOS:
Aprender a instalar un programa residente (TSR).
PROCEDIMIENTO: La práctica a realizar consiste en programar una función que, cada vez que
se pulse la combinación de teclas Alt-C, visualice la hora mantenida por MS-DOS a través del
temporizador del sistema. Para ello, necesitamos:
a) saber cómo y dónde guarda MS-DOS la información horaria, y
b) dejar instalada en memoria una rutina que en respuesta a la pulsación de teclas Alt-C
visualice la hora en pantalla.
En cuanto al punto a), la rutina de interrupción que responde al contador #0 del 8253 incrementa
en cada invocación una doble palabra situada en las posiciones 40:6Ch (palabra baja) y 40:6Eh
(palabra alta). Cuando el PC se pone en marcha, esta palabra es inicializada de acuerdo con la
hora mantenida por el reloj de tiempo real del PC. El contenido de esa palabra se incrementa a
una frecuencia de f = 1,193,180/65,535 ≈ 18.206760 veces por segundo, f × 60 ≈ 1092 veces por
minuto y f × 3600 ≈ 65544 = 32772 × 2 veces por hora. Por tanto, dividiendo esta doble palabra
entre 65544 obtenemos la hora. Dividiendo a continuación el resto entre 1092 obtenemos los
minutos. Dividiendo por 18 de nuevo se obtienen los segundos.
En cuanto al apartado b) la interrupción 27h de MS-DOS permite dejar residente una parte del
programa actualmente en ejecución una vez ésta ha concluido. Habitualmente, un programa con
estas características consta de dos partes: una primera parte, situada al principio del programa,
que contiene el código a dejar residente; y una segunda parte de instalación de es código. Antes
de invocar la interrupción 27h, en DX se introduce la dirección de inicio de esta segunda parte
respecto del principio del segmento (esto es, el desplazamiento dentro del segmento de código).
El último aspecto pendiente consiste en determinar cuándo se ha pulsado la combinación de
teclas Alt-C. Para ello, vamos a instalar la rutina de visualización de la hora en la interrupción
que responde al teclado.
Alberto Ortiz
Descargar