next up previous contents
Next: Manejo de excepciones para Up: El hilo Virtual V86 Previous: Requerimientos para ejecutar programas

Creación del hilo en modo virtual V86

El monitor se encarga de crear e inicializar al proceso V86. En esta inicialización se crea la tarea V86 y se prepara el primer megabyte de su espacio de direcciones para crear la máquina DOS, se carga el programa 8086, y se crea e inicializa el hilo V86 para que ejecute el programa 8086.

Los pasos para crear el hilo virtual V86 son:

1.
Crea la tarea V86, y le asigna su primer megabyte de memoria con permisos de lectura escritura y ejecución para cada una de las páginas que conforman esta área de memoria. Este paso se realiza con ayuda del llamado a Mach task_create, vm_allocate y la primitiva para asociar permisos a las páginas de memoria vm_protect:
   task_t       taskV86;
   vm_address_t *addr; 

   task_create(task_self(), FALSE, &taskV86);
   addr = (vm_address_t) 0x00; 
   vm_allocate(taskV86,  &addr, MEGABYTE, FALSE);
   vm_protect(taskV86,    addr, MEGABYTE, FALSE, 0x07));

Note que el hilo que ejecuta el llamado task_create coloca a la tarea a la que pertenece como la tarea padre de la tarea V86. Al declarar FALSE el segundo argumento de este llamado, la tarea se crea sin memoria. Lo que permite que posteriormente se le asigne el área de memoria para mapear la memoria de la máquina DOS.

2.
Cargar el código del programa 8086. Esto se hace con ayuda de la primitiva de escritura de páginas de memoria vm_write:
    task_t       taskV86; 
    char         *name; 
    vm_address_t addr, dato, addr_i; 
    int          i; 

    vm_allocate(task_self(), &dato, vm_page_size, TRUE); 
    fd=open(name, O_RDONLY); 
    addr_i = (char *) addr; 
    while ( (n=read(fd, dato, vm_page_size)) > 0 ) { 
      for (i=n+1; i<vm_page_size; i++)  dato[i] = '\0'; 
      vm_write(taskV86, addr_i, dato, vm_page_size);
      addr_i += vm_page_size; 
   }
   vm_deallocate(task_self(), dato, vm_page_size);
La lectura del código del programa 8086 se realiza desde el proceso monitor en un apágina de memoria y después se manda a escribir, por página, a la tarea V86.

3.
Crear e inicializar el hilo V86. Para inicializar el hilo V86 se trabaja directamente con la estructura de datos que representa el estado de un hilo para el i386, representado por la estructura i386_thread_state_t:
  typedef struct {
      unsigned int	eax;
      unsigned int	ebx;
      unsigned int	ecx;
      unsigned int	edx;
      unsigned int	edi;
      unsigned int	esi;
      unsigned int	ebp;
      unsigned int	esp;
      unsigned int	ss;
      unsigned int	eflags;
      unsigned int	eip;
      unsigned int	cs;
      unsigned int	ds;
      unsigned int	es;
      unsigned int	fs;
      unsigned int	gs;
  } i386_thread_state_t;
Se puede observar que la estructura de datos contiene los distintos registros del procesador. Entonces, para crear un hilo V86, se debe crear un hilo Mach, y encender la bandera VM del registro eflags. Toda esta operación, se realiza con los llamados a Mach thread_create, para crear el hilo V86; thread_get_state, para obtener el estado inicial del hilo V86 (a través de una estructura i386_thread_state_t); y thread_set_state, para asignarle los valores necesarios para inicializar un hilo en modo virtual 8086. Como se muestra a continuación:
  task_t               taskV86;
  thread_t             threadV86;
  port_t               port_ex;
  i386_thread_state_t  vm_thread_state;
  thread_create(taskV86, &threadV86);
  port_allocate(task_self(), &port_ex);
  thread_get_state(threadV86, i386_THREAD_STATE, 
       (thread_state_t)(&vm_thread_state), &vm_state_count);
  vm_thread_state.eflags = (vm_thread_state.eflags | EFL_VM);
  vm_thread_state.eip = entry_point;
  vm_thread_state.cs  = 0x00;
  vm_thread_state.ds  = 0x60;
  vm_thread_state.ss  = 0x00;
  vm_thread_state.gs  = 0x00;
  vm_thread_state.es  = 0x00;
  vm_thread_state.ebp = 0x00;
  vm_thread_state.eax = 0x00;
  vm_thread_state.ebx = 0x00;
  vm_thread_state.ecx = 0x00;
  vm_thread_state.edx = 0x00;
  vm_thread_state.edi = 0x00;
  vm_thread_state.esi = 0x00;
  vm_thread_state.esp = 0x60;
  thread_set_state(threadV86, i386_THREAD_STATE,
       (thread_state_t)(&vm_thread_state), vm_state_count);
El llamado thread_get_state regresa la estructura del estado del hilo para poder inicializar los registros que se cargarán en el procesador. Una vez que se han obtenidos los valores del hilo, se enciende la bandera VM (Virtual Machine) del registro EFLAGS --para declarar que el hilo V86 efectivamente se ejecutará en modo virtual 8086-- y se le dan valores a los registros SS y SP para asignarle una pila, se le indica la dirección CS:IP del programa 8086 que se ejecutará. Y, finalmente, asignan estos valores al hilo V86.

4.
Crear el puerto que recibirá del núcleo los mensajes de excepción generados por la ejecución del hilo V86. Este puerto se crea en el proceso monitor, ya que este proceso es el encargado de manejar las excepciones, aunque se asocia al hilo V86, que a su vez, se encuentra asociado a la tarea V86, como se aprecia en el listado anterior. Los llamados que se utilizan son port_allocate y thread_set_special_port.
Gracias a las facilidades que ofrece Mach, podemos obtener el estado del hilo V86 en su inicialización, y modificarlo para indicarle que se ejecutará en el modo virtual 8086. Estas facilidades no se encuentran en otras plataformas como UNIX o LINUX. Una vez que el proceso monitor a creado e inicializado la tarea V86 y el hilo V86, pondrá en ejecución al hilo V86, con el llamado thread_resume, y esperará a que éste hilo genere excepciones. El núcleo informará al proceso monitor, a través del puerto de excepción, que el hilo V86 ha ocasionado una excepción y le permitirá manejarla a través de una simulación.


next up previous contents
Next: Manejo de excepciones para Up: El hilo Virtual V86 Previous: Requerimientos para ejecutar programas
Amilcar Meneses
2002-10-03