Los pasos para crear el hilo virtual V86 son:
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.
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.
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.