Laboratorio de Sistemas Operativos

Anuncio
Laboratorio de Sistemas Operativos
Primer Parcial
Fecha de entrega: Martes, 13 de octubre de 2009
Planteamiento del problema
Se deberá desarrollar un sector de arranque y un minikernel que permita realizar las
siguientes funciones:




Leer dos cadenas de caracteres X e Y,
Calcular e imprimir la longitud de las dos cadenas en Hexadecimal,
Determinar si las dos cadenas son iguales. En caso que las cadenas no sean
iguales, imprimir la parte restante de la cadena de mayor longitud.
Entrar en un ciclo infinito cuando cualquiera de las dos cadenas (X o Y) sea
‘exit’
Para leer las cadenas se podrá utilizar repetidamente la interrupción de la BIOS 16h
(para leer un carácter), hasta encontrar el carácter de fin de linea (0x0D). Se deberá
adicionar el carácter nulo (0x00) al final de cada cadena leida.
Las operaciones que impliquen la pantalla deberán ser realizadas utilizando
directamente la memoria de video (que se encuentra en la dirección de memoria
0xB8000). Igualmente, el paso de parámetros (para las rutinas de imprimir carácter /
cadena de caracteres) se deberá realizar utilizando la pila.
El sector de arranque (de 512 bytes) y el minikernel (que debe ocupar exactamente
diecisiete (17) sectores de 512 bytes: el primer sector de 512 bytes corresponde al
bootsector, los siguientes 8 sectores corresponden al código del kernel, y los
siguientes 8 sectores corresponden a los datos del kernel.
El sector de arranque deberá contener la lógica necesaria para copiarse a sí mismo a
la dirección de memoria 0x800 (ver anexo : mapa de memoria en modo real) y
continuar su ejecución en esa nueva ubicación. Luego deberá cargar el minikernel de
la imagen de diskette (que se encuentra a partir del sector 2), por medio de
interrupciones de la BIOS (int 13h). Este kernel contendrá las rutinas requeridas. Una
vez que el sector de arranque haya terminado de cargar el kernel (en la dirección
0x1000), le deberá transferir el control (por medio de una instrucción ljmp).
Condiciones de entrega
Se deberá entregar un archivo comprimido (en formato zip) que contenga una carpeta
con nombre login1_login2 (donde login1_login2 son los login de usuario del correo
electronico de los integrantes del grupo). Esta carpeta deberá contener los siguientes
archivos:




README.txt: archivo que contiene el nombre y el código de los integrantes.
También puede incluir aclaraciones, comentarios inconvenientes y soluciones
relacionadas con el problema.
bochsrc.txt: archivo de configuración de bochs para ejecutar la imagen de disco
creada
boot.s: código fuente del sector de arranque
kernel.s: código fuente del kernel

Makefile: archivo de configuración de la utilidad make, que deberá contener
como mínimo las siguientes reglas:
o all: crear la imagen de disco (floppy)
o boot.o: compilar el archivo boot.S
o kernel.o: compilar el archivo kernel.S
o run: ejecutar la imagen de disco
o clean: borrar los archivos de compilación y la imagen de disco
Calificación
La lista de verificación que se usará para calificar el parcial es la siguiente:
LISTA DE VERIFICACIÓN
1. Aspectos generales
CUMPLE
(S/N)
1.1 (10 puntos) El programa se entregó de acuerdo con las condiciones
estipuladas y el la fecha indicada
1.2 (2 puntos) El programa incluye documentación que indica los
autores, la fecha de creación y el problema que soluciona
1.3 (2 puntos) El programa se encuentra estructurado (en rutinas) de
acuerdo con las características del problema
1.4 (2 puntos) Las rutinas se encuentran correctamente documentadas
en términos de parámetros de entrada y descripción general de su
funcionamiento
1.5 (2 puntos) Las secciones críticas del programa se encuentran
documentadas
1.6 (2 punto) El código fuente se encuentra estructurado correctamente
(por ejemplo, permite ver con claridad el inicio y fin de las rutinas y los
ciclos)
2. Funcionamiento del programa
2.1 (30 puntos) El sector de arranque se copia en la posición 0x800 (20
puntos), carga el kernel de disco a la posición 0x1000 y le pasa el
control al kernel (10 puntos)
2.2 (50 puntos) El kernel implementa en forma correcta la funcionalidad
requerida en el planteamiento del problema: Leer dos líneas (5 puntos),
calcular e imprimir la longitud de las lineas en hexadecimal (5 puntos),
determinar si las cadenas son iguales e imprimir la parte restante de la
cadena de mayor longitud (25 puntos), el kernel entra en un ciclo infinito
si X o Y son ‘exit’ (15 puntos)
En caso que alguna de las características no se cumpla completamente, se podrá
asignar una calificación proporcional con su cumplimiento.
Anexo. Documentación básica para la solución del
problema
A continuación se presentan algunos tips básicos que se deben considerar para la
solución del problema. Si se desea mayor profundidad en los temas presentados, se
deberá recurrir a consultas externas.
Proceso general de arranque del computador
Cuando se enciende el computador o se envía la señal RESET a la unidad de control,
el procesador ejecuta la instrucción que se encuentra en el límite de la memoria RAM.
Esta dirección generalmente es mapeada a la BIOS, que a su vez busca el primer
sector del dispositivo configurado como de arranque. Si no lo encuentra en este
dispositivo, continúa con el siguiente dispositivo hasta encontrar un sector de arranque
valido. Si no puede encontrar ningún sector de arranque valido, imprime un mensaje
de error y detiene su ejecución.
El sector de arranque (de 512 bytes) es cargado por la BIOS a la dirección de memoria
0x7C00h (31744 bytes), que es el límite de memoria de 32 K (31744 + 512 = 32256 =
32K). Luego le pasa el control de la ejecución a este sector de arranque.
Además, la BIOS almacena en los 8 bits menos significativos del registro EDX (es
decir, en DL) un valor que indica la unidad desde la cual se cargo el sector de
arranque, el cual puede ser:
1h = floppy
80h = disco duro primario.
Debido al tamaño limitado que tiene un sector de arranque (512 bytes incluyendo la
tabla de particiones), este sólo contiene la funcionalidad necesaria para continuar con
la carga del kernel. De esta forma, cargar un kernel completo generalmente se realiza
por medio de pequeños programas que se cargan y se transfieren el control en forma
secuencial (el primero de ellos es lógicamente el sector de arranque). A este proceso e
le conoce como “arranque por fases”.
Todo sector de arranque tiene un tamaño predeterminado de 512 bytes, y sus últimos
2 bytes (510 y 511) deberán contener la palabra AA55H, que se conoce como la "firma
del sector de arranque", o bootsector signature.
Modo real (Procesadores x86)
Cuando un procesador x86 inicia (luego de PWR o RESET), siempre lo hace en modo
real, en el cual se comporta básicamente como un 8086 con un conjunto de
instrucciones muy limitado, y en el cual sólo son válidas operaciones de 16 bits.
Adicionalmente, en modo real sólo es posible acceder al primer MegaByte de memoria
RAM, debido a que la línea de dirección 20 (conocida como la puerta A20) se
encuentra desactivada. Un esquema de los registros del procesador en modo real se
muestra a continuación:
MODO REAL (16 bits)
15
Registros de
propósito
general
(No se usa en
modo real)
Registros de
segmento
0
15
31
0
%cs
(e)
%ax
%ss
(e)
%bx
%ds
(e)
%cx
%es
(e)
%dx
%fs
(e)
%si
%gs
(e)
%di
Direccionamiento de memoria en modo real
Debido a que en modo real todo procesador se comporta como un 8086 (registros de
16 bits), con estos registros sólo es posible referenciar regiones de memoria de 64 KB
(cuando todos los bits de un registro de 16 bits se encuentran en 1, la máxima
dirección de memoria es 216 = 65536 = 64 KB). Los diseñadores de Intel desarrollaron
una estrategia que permitía acceder hasta 1 MB de memoria, denominada
segmentación.
La segmentación se implementa por medio de dos clases de registros: los registros de
segmento (%cs para el segmento de código, %ss para la pila, %ds para el segmento
de datos, y %es, %fs y %gs como segmentos adicionales de datos) y los registros de
propósito general (%ax, %bx, %cx, %dx, %si y %di). Los valores de estos registros se
combinan de la siguiente forma:
Ejemplo: para la dirección 0x7C00
Reg. de segmento
Reg. de propósito general
* 16
+
%ds
0x7C0
* 16
%si
0x00
+
=
Dirección física (20 bits)
%ds:%si
0x7C00
Por ejemplo, para referenciar la dirección de memoria en la cual se carga el sector de
arranque (0x7C00), haciendo uso del registro de segmento %ds (datos), y del registro
de propósito general %si, %ds deberá contener 0x7C0 y %si deberá contener 0x00. Al
multiplicar %ds por 16 (que en un número hexadecimal implica desplazar un dígito a la
izquierda), se obtiene:
%ds*16 + %si = (0x7C0 * 16) + 0x00 = 0x7C00 + 0x00 = 0x7C00.
De la misma forma, para referenciar la dirección inicial de la memoria de video
(0xB8000), por ejemplo se puede hacer uso de los registros %es y %di de la siguiente
forma:
%es = 0xB800, %di = 0x00, entonces:
%es:%di = %es * 16 + %di = (0xB800 * 16) + 0x00 = 0xB8000.
Se puede ver que la dirección física obtenida contiene 20 bits, con la siguiente gráfica:
Segmento * 16
Desplazamiento
Dirección
física
Es importante resaltar que no es conveniente modificar (asignar un valor) directamente
en un registro de segmento. Generalmente, primero se asigna el valor al registro %ax,
y luego el valor se pasa de %ax al registro de segmento indicado. Por ejemplo, para
mover 0xB800 al registro %es, se deben realizar los siguientes pasos1:
movw $0xB800, %ax
movw %ax, %es
Mapa de memoria en modo real
Cuando el computador arranca y pasa el control a la BIOS, ésta realiza un diagnóstico
inicial del hardware y configura el primer MegaByte de memoria RAM como se
presenta a continuación (las direcciones se presentan en formato hexadecimal).
Inicio
00
Fin
3FF
400
500
4FF
7BFF
1
Tamaño
1 KB
Descripción
Tabla de interrupciones del modo
real
255 bytes
Área de datos de la BIOS
30643 bytes (aprox Memoria convencional (usable). En
59 sectores, 30 KB)
esta región se deberá copiar el
El sufijo “w” en las instrucciones mov indica que se está almacenando un word. Los
sufijos válidos en la sintaxis de GNU Assembler son b para bytes (8 bits), w para word
(2 bytes = 16 bits)y l para long (4 bytes = 32 bits). En modo protegido se puede usar
máximo 16 bits.
7C00
7DFF
512 bytes
7E00
80000
9FC00
A0000
7FFF
9FBFF
9FFFF
FFFFF
480 KB (aprox)
120 KB (aprox)
1 KB
384 KB (aprox)
sector de arranque y el minikernel.
Posición de memoria en la cual la
BIOS carga el sector de arranque
Memoria convencional (usable)
Memoria convencional (usable)
Área de datos de la BIOS extendida
Área de ROM
A su vez, el área de ROM (ubicada de de A0000 a FFFF) se divide de la siguiente
forma:
Inicio
A0000
B0000
Fin
AFFFF
B7FFF
Tamaño
64 KB
32 KB
B8000
BFFFF
32 KB
C0000
C8000
C7000
EFFFF
32 KB
160 KB
F0000
FFFFF
64 KB
Descripción
Framebuffer VGA
Memoria de video en modo texto,
monocromático
Memoria de video en modo texto, a
color
BIOS de Video (ROM)
Hardware mapeado en memoria y
dispositivos varios
BIOS
Memoria de video
La memoria de video en modo texto a color (25 líneas de 80 caracteres cada una)
inicia en la dirección 0xB8000, y ocupa 32 KB de memoria. Cada carácter en que se
muestra en la pantalla ocupa 2 bytes en la memoria de video (un word): un byte
contiene el código ASCII del carácter, y el otro byte contiene los atributos de color de
texto y color de fondo del carácter.
A su vez, el byte para los atributos de texto (color de texto y de fondo) se divide en
fracciones, que representan el color de texto y el color de fondo. Esto quiere decir que
en modo texto a color se tienen 16 combinaciones diferentes (2 4 = 16) para los colores
de texto y de fondo.
Lo anterior se ilustra en el siguiente esquema:
Atributos de texto
Carácter ASCII
0
15
b = blink
b
fondo
texto
De esta forma, para mostrar un carácter en la esquina superior de la pantalla (línea 0,
carácter 0) se deberá escribir un word (2 bytes) en la dirección de memoria 0xB8000.
El primer byte de este word será el código ascii a mostrar, y los siguientes bytes
representarán el color de texto y de fondo del carácter. El siguiente word (ubicado en
la dirección de memoria 0xB8002) corresponde al segundo carácter en la pantalla, y
así sucesivamente.
Los colores válidos se muestran en la siguiente tabla2:
Valor
Color
Valor
Color
0
black
8
dark gray
1
blue
9
bright blue
2
green
10
bright green
3
cyan
11
bright cyan
4
red
12
pink
5
magenta 13
bright magenta
6
brown
14
yellow
7
white
15
bright white
Los colores 0-15 son válidos para el color de texto. Sin embargo para el fondo solo es
posible utilizar los colores del 0 al 7, debido al que el 8 bit se utiliza para el “blink”
(texto que aparece y desaparece).
Por ejemplo, para imprimir el carácter ‘A’, (al cual le corresponde el código ASCII 65,
0x41 en hexadecimal) con color blanco sobre fondo negro en la esquina superior de la
pantalla, se deberá copiar el word 0x0741 en la dirección de memoria 0xB8000.
Se puede observar la posición XY de un carácter en la pantalla se puede obtener de la
siguiente forma:
Pos_XY = 0xB8000 + ((80*Y) + X) *2
En donde 0xB8000 es la dirección base de la memoria de video (esquina superior
izquierda), Y representa la fila, X representa la columna. Se debe multiplicar por 2
debido a que cada carácter en la pantalla en realidad ocupa 2 bytes, uno para el
código ascii y otro para los atributos de color de texto y fondo.
Servicios de la BIOS
La BIOS (Basic Input/Output System) ofrece una serie de servicios que pueden ser
utilizados en modo real. Los servicios necesarios para este parcial se explican en
forma general a continuación3:
Servicio
INT
Leer sectores de un 13h
drive
2
Descripción
Los registros deberán contener los siguientes
valores:
tomada de http://my.execpc.com/~geezer/osd/cons/index.htm
Aquí se utiliza la notación ##h para representar un número hexadecimal. En GNU Assembler,
la instrucción para invocar la interrupción 13h sería: int $0x13
Para
una
lista
completa
de
los
servicios
de
la
BIOS,
consultar
http://en.wikipedia.org/wiki/BIOS_call
3
AH = 02h (Read sectors from drive)
AL = Número de sectores a leer
CH = 8 bits menos significativos del cilindro
CL = (bits 0-5) número del sector, (bits 6-7) 2 bits
más significativos del cilindro
DH = Cabeza
DL = Dispositivo del cual se desean leer los
sectores (0x00 = floppy)
ES:BX deberá apuntar a la posición de memoria en
la cual se desean almacenar los lectores leídos
Este servicio guarda en AL el número de sectores
leídos, y establece el Flag de Acarreo en 0 si la
lectura fue correcta, o 1 si se presentó algún error.
Lee una tecla
16h
AH = 00h (Read Character)
Este servicio guarda el character leído en AX:
AH contiene el scan code
AL contiene el código ASCII del carácter que se
leyó.
Aunque no es un problema para este parcial, es importante resaltar que el servicio de
la BIOS para leer sectores de disco funciona con una geometría de Cilindros, Cabezas
(Heads) y Sectores (C/H/S). Por esta razón tiene algunas limitaciones:
Debido a que el número de la cabeza se almacena en DL (registro de 8 bits), sólo es
posible referenciar de la cabeza 0 a la cabeza 255 (28 = 256 cabezas). Igualmente,
como sólo se cuenta con 10 bits para el cilindro (8 bits en CH y 2 bits en CL), sólo se
puede referenciar del cilindro 0 al 1023 (210 = 1024 cilindros). De la misma forma, solo
se cuenta con 6 bits para el número del sector, por lo cual sólo es posible referenciar
del sector 0 al sector 63 (26 = 64). De esta forma, los servicios de la BIOS sólo
permiten referenciar los primeros 8.5 GB de un disco duro:
(Cilindros * Heads * Sectores) * 512 = 8.5 GB
Como se mencionó anteriormente, cuando se utiliza el servicio de leer sectores de un
drive, la BIOS guarda en AL el número de sectores leídos, y establece el Flag de
Acarreo en 0 si la lectura fue correcta, o 1 si se presentó algún error. Generalmente no
se deberían presentar errores al leer el kernel, pero es aconsejable validar si la lectura
fue correcta.
Descargar