Minikernel Material complementario para la asignatura de Sistemas Operativos Preparado por Gabriel Astudillo Muñoz Escuela de Ingeniería Civil Informática Universidad de Valparaíso 1 Resumen Este documento tiene como objetivo describir el entorno de desarrollo que se utilizará para las tareas prácticas de la asignatura de Teoría de Sistemas Operativos, relativas a gestión de procesos. 2 Introducción El software que se utiliza para el tema de Gestión de Procesos, es un kernel, denominado “minikernel”, que es utilizado en el libro “Prácticas de Sistemas Operativos: de la base al Diseño” [1] y que su diseño se basa en una estructura de Hardware Virtual [2]. Desde este punto de vista, consiste en una virtualización a nivel de sistema operativo. Debido a lo anterior, el minikernel está organizado en dos capas: una que implementa el hardware virtual, denominal HAL (Hardware Abstraction Layer)1, y otra que implementa el sistema operativo propiamente tal. 3 Entorno de desarrollo En esta sección, se describen los principales módulos que componen el minikernel. En forma concreta, posee tres componentes principales, cada una de ellas representada por un directorio, cuya descripción está en la Tabla 3.1. Directorio Raíz Directorio boot/ minikernel/ kernel/ usuario/ Descripción Cargador del sistema Entorno relacionado con el kernel Programas que generan los procesos de la capa de usuario Archivos boot HAL.o kernel.c include/ lib/ init.c simple.c excep_arit.c excep_mem.c Descripción Programa cargador del sistema operativo Módulo que representa el Hardware Virtual Sistema Operativo Cabeceras utilizas por el kernel Bibliotecas utilizas por los programas de usuario Proceso inicial del sistema. Procesos de ejemplo Tabla 3.1 Debido a que el objetivo de la utilización de este entorno es poner en práctica los conocimientos de gestión de procesos, no se incluyen los códigos fuentes del cargador (boot) ni de la capa de abstracción de hardware (HAL.o). 3.1 Módulo HAL.o Este módulo implementa mediante software los componentes de hardware que tiene un computador, tales como el procesador, memoria, reloj temporizador, pantalla y teclado. En el caso de los dos últimos, el sistema utliza la pantalla y el teclado del computador real. Además, implementa interrupciones y nivel de interrupciones y ofrece una API que permite acceder a los recursos implementados. 1 La capa HAL es parte del diseño de los sistemas operativos Unix y similares. Actualmente, HAL ha sido reemplazo por la capa udev. 1 3.1.1 3.1.1.1 Implementación de componentes de hardware Procesador El procesador tiene dos modos de operación: modo privilegiado y modo usuario [2]. En el primero, se ejecuta código propio del sistema operativo mientras que en segundo permite la ejecución de los códigos de los procesos de usuario. El cambio de modo de usuario a privilegiado ocurre sólo cuando exite algún tipo de interrupción. Existe un registro de estado del procesador, que almacena el modo de ejecución del mismo. Para pasar de modo privilegerado a modo usuario, el sistema operativo debe modificar ese valor dentro de éste registro. Por último, dispone de seis registros de propósito general de 32 bits. Se utilizan para el paso de parámetros en las llamadas al sistema. La cantidad de registros está definido en la macro NREGS, en el arhivo de cabecera del kernel HAL.h. 3.1.1.2 Dispositivos de I/O El sistema tiene implementado dos dispositivos de I/O basados en interrupciones: el terminal y el reloj. El terminal es el tipo mapeado en memoria y está formado por dos dispositivos independientes: pantalla y teclado. La salida de datos a la pantalla se realiza escribiendo directamente en su memoria de video y no se utilizan interrupciones. La entrada de datos desde el teclado está comandada por interrupciones que se producen cada vez que se pulsa una tecla. El reloj temporizador tiene una frecuencia de interrupción programable. Esto significa que este temporizador interrumpe periódicamente y su período es modificable. 3.1.1.3 Interrupciones El tratamiento de interrupciones se realiza mediante el uso de una tabla de vectores de interrupción. Existen seis vectores disponibles, los que se muestran en la Tabla 3.2. Vector 0 1 2 3 4 5 Descripción Excepción Aritmética Excepción por acceso no válido a memoria Interrupción de reloj Interrupción del terminal Llamada al sistema Interrupción por Software Modo de manejo Con excepciones Valores Nemotécnicos EXC_ARITM EXC_MEM Interrupciones de I/O INT_RELOJ INT_TERMINAL Interrupciones de software LLAM_SIS INT_SW Tabla 3.2 Vectores disponibles. Los valores nemotécnicos están definidos en la cabecera const.h. El procesador tiene múltiples niveles de interrupción, los que tienen asignado un número. Mientras mayor sea, su prioridad es más alta. Los niveles disponibles se muestran en la Tabla 3.3. Nivel Descripción 3 2 1 Interrupción de Reloj Interrupción de terminal Interrupción de software o llamada al sistema Ejecución en modo usuario 0 Valores Nemotécnicos NIVEL_3 NIVEL_2 NIVEL_1 N/A Tabla 3.3 Niveles de interrupción. Los valores nemotécnicos están definidos en la cabecera const.h. En cada momento el procesador ejecuta código en un determinado nivel de interrupción, cuyo valor está almacenado en el registro de estado. Cabe destacar que sólo admite interrupciones de una nivel superior al actual. 2 Inicialmente, el procesador ejecuta código en modo privilegiado y en el nivel de interrupción máximo, por lo que todas las interrupciones están inhibidas. Por otro lado, cuando el procesador ejecuta código en modo usuario, lo hace en un nivel 0, lo que significa que todas las interrupciones están habilitadas. 3.1.2 3.1.2.1 API ofrecidas al sistema operativo. Iniciación de los controladores de dispositivos void iniciar_cont_teclado(); Inicia el controlador del teclado. void iniciar_con_reloj(int ticks_por_segundo); Permite iniciar el controlador de reloj. El parámetro ticks_por_segundo es la frecuencia de interrupción deseada, medido en cantidad de interrupcione por segundo. unsigned long long int leer_reloj_CMOS(); Permite leer la hora almacenada en el reloj del sistema real. 3.1.2.2 Manejo de interrupciones void iniciar_cont_int(); Permite iniciar el controlador de interrupciones. void instal_man_int(int nvector, void (*manej)() ); Permite que la función manjec() sea la que maneje la intrrupción correspondiente a nvector (ver tabla 3.2). int fijar_nivel_int(int nivel) Fija el nivel de interrupción del procesador devolviendo el nivel previo. Los niveles están descritos en la 3.3. void activar_int_SW() Activa las interrupciones por software int viene_de_modo_usuario() Consulta el registro de estado salvado por la interrupción actual y permite conocer si previamente se estaba ejecutando en modo usuario, devolviendo un valor 1 en tal caso. 3.1.2.3 Gestión de la información del contexto de los procesos El contexto de un proceso se representa por una estructura denominada contexto_t, la que almacena una copia de los registros del procesador con los valores correspondientes a la última vez que ejecutó el proceso. La estructura se muestra en la Tabla 3.4. /* Contexto "hardware" de un proceso */ typedef struct { ucontext_t ctxt; long registros[NREGS]; } contexto_t; Tabla 3.4 Estructura que permite almacenar el contexto de un proceso. (Archivo HAL.h) Las funciones que crean el contexto inicial de un proceso nuevo, así como las que permiten realizar un cambio de contexto [2] son: void fijar_contexto_ini(void *memoria, void *inicia_pila, tam_pila, void *pc_inicial, contexto_t *contexto_ini); int Crea el contexto inicial. Establece los valores iniciales del contador de programa (pc_inicial), puntero de la pila (inicia_pila) y su tamaño (tam_pila). Como parámetro de entrada, debe recibir una referencia al mapa de memoria del proceso (memoria), creado con anterioridad. Como salida, retorna un contexto iniciado (contexto_ini) de acuerdo con los valores especificados. 3 void cambio_context(contexto_t *contexto_a_restaurar); *contexto_a_salvar, contexto_t Básicamente, esta función guarda el contexto de un proceso (contexto_a_salvar) y restaura el de otro (contexto_a_restaurar). 3.1.2.4 Gestión de memoria de los procesos void *crear_imagen(char *prog, void **dir_ini); Crea el mapa de memoria a partir del ejecutable especificado por prog. Para esto, debe procesar el archivo ejecutable y crear las regiones de memoria correspondientes. Devuelve un identificador del mapa de memoria creado, así como la dirección de inicio del programa en el parámetro de salida dir. void liberar_imagen(void *mem); Libera una imagen de memoria previamente creada, representada por el parámetro mem. void *crear_pila(int tam); Reserva una zona de memoria para la región de pila (stack). Se especifica el tamaño de la misma (parámetro tam). Devuelve la dirección inicial de la zona reservada. void liberar_pila(void *pila); Reserva una zona de memoria para la región de pila (stack). Se especifica el tamaño de la misma (parámetro tam). Devuelve la dirección inicial de la zona reservada. 3.1.2.5 Funciones varias int leer_registro(int nreg); int escribir_registro(int nreg, int valor); Permiten leer y escribir en los registros de propósito general del prosesador. char leer_puerto(int dir_puerto); Lee y retorna un byte del puerto de I/O especificado por dir_puerto. El sistema posee un solo puerto definido en la macro DIR_TERMINAL, que tiene el valor 1. void halt(); Detiene el procesador hasta que se active una interrupción void escribir_ker(char *buffer, unsigned int longi) Perminete escribir en pantalla los datos especificados en el parámetro buffer y cuyo tamaño es longi. Para ello, copia en la memoria de video del terminal dichos datos. El código es: /* Funcion interna que escribe en la pantalla */ void escribir_ker(char *texto, unsigned int longi) { int nivel_previo; nivel_previo=fijar_nivel_int(NIVEL_3); write(1, texto, longi); fijar_nivel_int(nivel_previo); } Tabla 3.5 int printk(const char *, ...) Función que llama internamente a escribir_ker(). Funciona como la función printf(). void panico(char *mens) Escribe el mensaje especificado por el parámetro mens por pantalla y termina la ejecución del sistema operativo. 4 3.2 Módulo Kernel 3.3 Carga del sistema operativo En el directorio raíz, se debe ejecutar la intrucción: ./boot/boot minikernel/kernel 3.3.1 Inicio del sistema operativo Una vez cargado en memoria el sistema operativo, el programa cargador pasa el control al punto de entrada del kernel, que es la función main(). En este momento, el sistema inicia sus estructuras de datos, dispositivos de hardware e instala los manejadores en la tabla de procesos. Por último crea el proceso inicial, denominado init, y lo activa pasándole el control del sistema. Duranta la fase descrita anteriormente, el procesador ejecuta código en modo privilegiado y las interrupciones están inhibidas (nivel de interrupción 3). Cabe destacar que cuando se activa el proceso init, el procesador pasa a ejecutar código en modo usuario y se habilitan todas las interrupciones (nivel 0). Además, una vez hecho el cambio de contexto (ver línea 22 del código de kernel mostrado en la Tabla 3.6), el kernel no puede volver nunca a su función main(). A partir de este evento, el sistema operativo sólo se ejecutará cuando se produzca una llamda al sistema, una excepción o una interrupción de un dispositivo. 1: int main(){ 2: /* se llega con las interrupciones prohibidas */ 3: iniciar_tabla_proc(); 4: 5: instal_man_int(EXC_ARITM, exc_arit); 6: instal_man_int(EXC_MEM, exc_mem); 7: instal_man_int(INT_RELOJ, int_reloj); 8: instal_man_int(INT_TERMINAL, int_terminal); 9: instal_man_int(LLAM_SIS, tratar_llamsis); 10: instal_man_int(INT_SW, int_sw); 11: 12: iniciar_cont_int(); /* inicia cont. interr. */ 13: iniciar_cont_reloj(TICK); /* fija frec. del reloj */ 14: iniciar_cont_teclado(); /* inicia cont. teclado */ 15: 16: /* crea proceso inicial */ 17: if (crear_tarea((void *)"init")<0 18: panico("no encontrado el proceso inicial"); 19: 20: /* activa proceso inicial */ 21: p_proc_actual=planificador(); 22: cambio_contexto(NULL, &(p_proc_actual->contexto_regs)); 23: panico("S.O. reactivado inesperadamente"); 24: return 0; 25: } Tabla 3.6 Código principal del kernel a utilizar. 3.3.2 Tratamiento de interrupciones En el caso de interrupciones externas, las únicas fuentes son el reloj y el terminal. Las rutinas de atención instaladas, tanto para interrupciones externas y de software, sólo muestran un mensaje por pantalla indicando la ocurrencia del evento. En el caso de la interrupción del teclado, la rutina de atención, además usa la función leer_puerto() para obtener el carácter ingresado. static void int_terminal(){ printk("-> TRATANDO INT. DE TERMINAL %c\n", leer_puerto(DIR_TERMINAL)); return; } static void int_reloj(){ printk("-> TRATANDO INT. DE RELOJ\n"); return; } Tabla 3.7 Ejemplo de rutinas de tratamiento de interrupciones. 5 3.3.3 Tratamiento de excepciones Las dos posibles excepciones presentes en el sistema tienen un tratamiento común que depende del modo que se ejecutaba el procesador antes de producirse la excepción. Si estaba en modo usuario, se termina la ejecución del proceso actual. En caso contrario, se trata de un error del propio sistema operativo, por lo que se invoca a la función panico() para termina su ejecución. 3.3.4 Llamadas al sistema Existe una única rutina de atención para todas las llamadas a sistema, denominada tratar_llamsis()(ver Tabla 3.8). Tanto el código de la llamada como sus parámetros se pasan mediante registros. Por convención, el código se pasa en el registro 0 y los parámetros en los siguientes, considerando hasta cinco parámetros. El resultado de la llamada se devuelve en el registro 0. Esta rutina invoca indirectamente, a través de la estructura tabla_sevicios[](ver Tabla 3.9 y Tabla 3.10), a la función correspondiente. Dicha tabla almacena en cada posición la dirección de la función del sistema operativo que lleva a cabo la llamada al sistema cuyo código corresponde con dicha posición. static void tratar_llamsis(){ int nserv, res; nserv=leer_registro(0); if (nserv<NSERVICIOS) res=(tabla_servicios[nserv].fservicio)(); else res=-1; /* servicio no existente */ escribir_registro(0,res); return; } Tabla 3.8 Función de atención de llamadas a sistema. Archivo kernel.c. /* Numero de llamadas disponibles */ #define NSERVICIOS 3 #define CREAR_PROCESO 0 #define TERMINAR_PROCESO 1 #define ESCRIBIR 2 Tabla 3.9 Macros utlizados por la estructura tabla_servicios[]. Archivo llamsis.h. typedef struct{ int (*fservicio)(); } servicio; servicio tabla_servicios[NSERVICIOS]={ {sis_crear_proceso}, {sis_terminar_proceso}, {sis_escribir} }; Tabla 3.10 Tabla de Servicio. Archivo kernel.h. 6 Por ejemplo, el llamada a sistema CREAR_PROCESO, está relacionada con la función sis_crear_proceso(). Esta función se muestra en la Tabla 3.11. Se debe notar que el nombre del proceso a crear se pasa a través del registro 1 y la función que realmente lo crea es crear_tarea(). Todas las funciones de atención a llamadas de sistemas, están programadas en el archivo kernel.c. int sis_crear_proceso(){ char *prog; int res; } prog=(char *)leer_registro(1); res=crear_tarea(prog); return res; Tabla 3.11 Función sis_crear_proceso(). Archivo kernel.c. 3.4 Programas de usuario En el subdirectorio usuario existe inicialmente un conjunto de programas de ejemplo que usan los servicios del minikernel. El más importante, al igual que los sistemas operativos reales, es el proceso init, que es el primer programa que ejecuta el sistema operativo. Este proceso es el que va a lanzar o ejecutar otros procesos, que básicamente serán muy simples, no como los procesos de los sistemas reales. Los programas tienen acceso a las llamadas del sistema como funciones de bibioteca. Para este fin, existe una biblioteca estática, denominada libserv.a, que contiene las funciones de interfaz (ver Tabla 3.12) para las tres llamadas básicas al sistema, mencionadas en la sección anterior. Esta biblioteca se crea a través de los objetos misc.o y serv.o. El alumno sólo tiene acceso al código de éste último objeto. Se debe tener presente que por convención, los programas de usuario no deben usar llamadas al sistema directamente. Lo deben hacer a través de bibliotecas. int crear_proceso(char *prog){ return llamsis(CREAR_PROCESO, 1, (long)prog); } int terminar_proceso(){ return llamsis(TERMINAR_PROCESO, 0); } int escribir(char *texto, unsigned int longi){ return llamsis(ESCRIBIR, 2, (long)texto, (long)longi); } Tabla 3.12 Interfaces para las llamadas básicas al sistema. Archivo serv.c. La función llamsis() está definido en misc.o y tiene la estructura que se muestra en la Tabla 3.13. Aunque se pueden implementar las funciones de llamadas a sistema directamente, es preferible, en modo usuario, utilizar esta función para realizar dicha tarea. Nótese que los argumentos de las llamadas a sistema se pasan a través de registros internos del procesador. int llamsis(int llamada, int nargs, ... /* args */) { va_list args; int registro; escribir_registro(0, llamada); va_start(args, nargs); for ( registro=1; nargs; nargs--, registro++) { escribir_registro(registro, va_arg(args, long)); } va_end(args); trap(); return leer_registro(0); } Tabla 3.13 Estructura de la función llamsis() para realizar llamadas a sistema en modo usuario. Finalmente, está definida la función start(), que constituye el punto real de inicio del programa. Su estructura se encuentra en la Tabla 3.14. Esta función se encarga de invocar a la función main, que es el punto de inicio del programa para el programador. Este truco permite asegurarse de que el programa siempre invoca la llamada al sistema de finalización, terminar_proceso(), al terminar. Si no lo ha hecho la función main(), lo hará start() al terminar la función main. 7 void start(void (*fini) (void)) { fini(); terminar_proceso(); } Tabla 3.14 Función start. Incluída en misc.o. Todos los programas de usuario utlizan el archivo usuario/include/servicios.h, que contiene los prototipos de las funciones de interfaz a las llamadas al sistema. 8 4 Código fuente de apoyo En la Tabla 4.1 se describe detalladamento los archivos que se utillizarán en las tareas. Directorio Raíz Archivo o Directorio Makefile boot/ boot/boot minikernel/ Makefile kernel HAL.o kernel.c include/ HAL.h const.h llamsis.h minikernel/ kernel.h usuario/ Makefile init.c *.c include/ servicios.h lib/ Makefile libserv.a serv.c misc.o Descripción Makefile general del entorno. Invoca a los archivos Makefile de los subdirectorios. Carga del sistema. Programa de arranque del sistema operativo. Entorno relacionado con el kernel. Permite generar el ejecutable del sistema operativo. Ejecutable del sistema operativo. Archivo que contiene las funciones relativas a la capa de hardware. Archivo que contiene la funciones del sistema operativo. Este archivo debe ser modificado por el alumno para incluir la funcionalidad solicitada en cada tarea. Archivos de cabecera Contiene prototipos de las funciones del módulo HAL. No debe ser modificado. Contiene algunas constantes, como los vectores de interrupción del sistema. Contiene los códigos numéricos asignados a cada llamada del sistema. Este archivo debe ser modificado para incluir nuevas llamadas. Contiene definiciones usadas por el módulo kernel.c, como la tabla de servicios. Este archivo debe ser modificado. Programas de usuario. Permite compilar los programas de usuario. Primer programa que ejecuta el sistema operativo. Se debe modifcar para que invoque a los programas que se consideren oportunos. Programas que son ejecutados por init.c. Archivos de cabecera. Contiene los prototipos de las funciones que sirven de interfaz a las llamadas al sistema. Debe ser modificado para incluir la interfaz para nuevas llamadas. Módulos que permiten generar la biblioteca que utilizan los programas de usuario. Genera la biblioteca de servicios. Biblioteca de servicios. Contiene la interfaz a los servicios del sistema operativo. Debe ser modificado para incluir la interfaz a nuevas llamadas. Contiene otros funciones de bibliotecas auxiliares. Tabla 4.1 Descripción de los archivos utlizados por el entorno minikernel. 9 5 Gestión de procesos La gestión de procesos del sistema corresponde al de un sistema monoprogramado. Esto significa que aunque se puedan crear y cargar en memoria múltiples programas, el proceso en ejecución continúa hasta que termina, ya sea voluntariamento o involutariamente a través de una excepción. Las llamadas al sistema disponibles no pueden causar que el proceso pase a un estado bloqueado. 5.1 Características de la gestión de procesos del minikernel La tabla de procesos (tabla_procs) es un arreglo de tamaño fijo (MAXPROC) de BCP. BCP tabla_procs[MAX_PROC]; El BCP tiene la siguiente estructura (minikernel/include/kernel.h): typedef struct BCP_t { int id; /* ident. del proceso */ int estado; /* TERMINADO|LISTO|EJECUCION|BLOQUEADO*/ contexto_t contexto_regs; /* copia de regs. de UCP */ void * pila; /* dir. inicial de la pila */ BCPptr siguiente; /* puntero a otro BCP */ void *info_mem; /* descriptor del mapa de memoria */ } BCP; El BCP dispone de un puntero (siguiente) que permite que el sistema operativo construya listas de BCP que tengan alguna característica en común. Una lista de este tipo es la de procesos en estado listo (lista_listos). Esta lista incluye al que se está ejecutándose actualmente. El tipo usado para la fila de listos (tipo lista_BCP) permite construir listas con enlace simple, almacenando referencias al primero y al último elemento de la lista. Para facilitar su gestión, se ofrecen funciones que permiten eliminar e insertar BCP en una lista de este tipo. Este tipo puede usarse para otras listas del sistema operativo (por ejemplo, para un semáforo). Este tipo de datos exige que un BCP no pueda estar en dos listas simultáneamente. La variable p_proc_actual apunta al BCP del proceso en ejecución. Este BCP está incluido en la fila de listos. La función que crea procesos (crea_proceso()) realiza los siguiente pasos: • • • • • • Busca una entrada libre. Crea el mapa de memoria a partir del ejecutable. Reserva la pila del proceso. Crea el contexto inicial. Rellena el BCP adecuadamente. Pone el proceso como listo para ejecutar y lo coloca al final de la fila de listos. Cuando un proceso termina, se liberan sus recursos (imagen de memoria, pila y BCP). Luego se invoca al planificador para que elija otro proceso y hacer un cambio de contexto a este nuevo proceso. El planificador está determinado por la funcion planificador(). Debido a que el sistema es monoprogramado, no se llama hasta que el proceso actual termina. Su política es FIFO. En el caso que todos los procesos estén bloqueado (por ejemplo, si se cambia la política), se llamaría a la función espera_int(), de la que no se volvería hasta que se produjese una interrrupción. 5.2 Cambios de contexto El cambio de contexto es la operación que cambia el proceso asignado al procesdor por otro. Existen dos tipos de cambios de contexto. • • Cambio de contexto Voluntario: se produce cuando el proceso en ejecución pasa al estado bloqueado debido a que tiene que esperar por algún tipo de evento. Sólo pueden ocurrir dentro de una llamada a sistema. No pueden darse nunca en una función de interrupción, ya que éste generalmente no está relacionada con el proceso que está actualmente ejecutando. Cambio de contexto Involuntario: se produce cuando el proceso en ejecución tiene que pasar al estado Listo, ya que debe dejar el procesador por algún motivo (por ejemplo, cuando se le acaba su ventana de tiempo de ejecución o por que hay otro proceso con más prioridad que hay que ejecutar). 10 5.3 Cambio de contexto Voluntario En este caso, el programador incluye llamadas a la función cambio_contexto() cuando lo requiera. Por ejemplo: { ... //Bloquear el proceso por que se //necesitan datos bloquear() //Llamada a sistema ... } y la funcion bloquear(), tendría la forma: bloquear(){ proc_anterior = proc_actual; proc_anterior->estado = BLOQUEADO; proc_actual = planificador(); cambio_contexto(proc_anterior, proc_actual); } Nótese que la función bloquear() debería elevar al máximo el nivel de interrupción del procesador, puesto que está modificando la lista de procesos listos y es prácticamente suguro que todas las funciones de interrupción manipulan esta lista. 5.4 Cambio de contexto Involuntario Los cambios de contexto involuntario se producen a través de interrupciones de software. Algunos procesadores proporcionan este mecanismo, que consiste en una instrucción especial, que sólo puede ejecutarse en modo privilegiado, que causa una interrupción de mínima prioridad. Con la interrupción de software, el cambio de contecto involuntario es trivial: cuando dentro del código de una llamada o una interrupción se detecta que hay que realizar, por motivo que sea, un cambio de contexto involuntario, se activa la interrupción de software respectiva. Dado que se trata de una interrupción del nivel mínimo, su rutina de tratamiento no se activará hasta que el nivel de interrupción del procesador sea 0 (esto es, modo usuario). Esta función de tratamiento se encargará de realizar el cambio de contexto involuntario. 6 Modalidad de trabajo Originalmente, el minikernel se entregaba en formato comprimido estándar de unix (.tar.gz). El único requisito es que la persona que desee utilizarlo, lo debe instalar en un sisema operativo Linux. Para esto, la Escuela de Ingeniería Civil Informática posee computadores con Linux instalado. Pero para promover la movilidad y el trabajo en otros lugares que no sean las salas de computadores y que no sea necesario tener Linux instalado en un computador personal, se ha decidido entregar el minikernel junto con una distribución de Linux en formato de Máquina Virtual. Especificamente, se entrega un “appliance”, que básicamente consiste en un archivo que tiene todas las definiciones y archivos para que el usuario final disponga de un computador virtual sin la necesidad de instalarlo. Para esto, sólo es necesario instalar el software de virtualización VirtualBox [3] y luego importar el archivo que constituye el appliance. Es recomendable instalar adicionalmente el software VirtualBox Extension Pack. Ambos se pueden bajar de la página de VirtualBox. 7 Bibliografía [1] Prácticas de Sistemas Operativos, Jesús Carretero Pérez, MC Graw-Hill, 2003. [2] Operating system concepts, Abraham Silberschatz, Peter Baer Galvin, Greg Gagne, 6 ed. [3] Virtual Box. http://www.virtualbox.org 8 Anexo: Utilización de Virtual box. Se asume que el sistema operativo que usted utiliza es alguna versión de windows superior a XP y que el software Virtual Box está instalado en su sistema. Además, usted necesitará el programa WinSCP, el que lo puede bajar de http://portableapps.com/apps/internet/winscp_portable. Finalmente, el archivo appliance se llama INC303.ova, el que estará publicado en un servidor que se dará a conocer a través del Aula Virtual. 11 Paso 1: Importar el appliance en Virtual Box: Menú Archivo->Importar Servicio virtualizado. Luego seleccionar el archivo ramosinc.ova. Inicie la máquina virtual. Si sale un error con respecto a las interfaces de red, sólo coloque configurar las interfaces, acepte los cambios propuesto e inicie la máquina nuevamente. Paso 2: Ejecutar WinSCP, y seleccionar Sesión del tipo SFTP. En la IP del servidor, debe ingresar 192.168.56.10. El puerto de comunicación es 22. El usuario es root y su contraseña es admin. Una vez realizado lo anterior, debe presionar “Conectar”. Luego de conectar, sus archivos locales estarán en el lado izquierdo de la ventana del programa, y los archivos de la máquina virtual, es el lado derecho. Para copiar de un lado a otro, sólo arrastre y suelte. Observaciones: Para compilar, es necesario que usted ingrese directamente a la máquina virtual. Para esto, debe ingresar a ella con el usuario root y su contraseña admin. Usted deberá averiguar comandos básicos de Linux para moverse en los directorios, en modo consola. La distribución entregada es Debian, versión Jessie, con entorno gráfico XFCE. Para acceder a dicho entorno, cuando usted ingrese al sistema, debe ejecutar el comando startxfce4. El software instalado en la máquina virtual, está resumido en el campo “descripción” de la misma. 12