2011-07-31 11 views
10

Estoy escribiendo un pequeño sistema operativo que ejecutará algún código en modo de usuario (nivel de privilegio 3). Desde ese código de nivel de usuario, quiero llamar una interrupción al sistema operativo que imprime un mensaje. En este momento, realmente no me importa cómo mi manejador de interrupciones toma argumentos o algo así, realmente solo quiero que un manejador de interrupciones me informe (al usuario) que el código se ha ejecutado.Cambiar al modo de usuario usando iret

Mi pregunta es: ¿cómo ejecuto el código en modo de usuario? Tengo una función que configura una tabla de descriptores locales con un segmento de código y un segmento de datos (ambos con privilegios de modo de usuario). Lo que no entiendo es cómo se supone que debo cargar estos segmentos en cs, ss y ds. Cargué con éxito mi LDT, pero no sé cómo usarlo realmente. He escuchado que debería usar iret, pero no entiendo exactamente cómo.

Otra pregunta que tengo es cómo debería funcionar mi controlador de interrupciones. Digamos que instalo un controlador de interrupción para el vector número 0x40, que quiero imprimir "¡Hola, modo de usuario!". Sé cómo configurar un manejador de interrupciones, pero no entiendo exactamente cómo se cambiará el contexto al ingresar un manejador de interrupciones de kernel desde el modo de usuario. Sé que el registro cs debe cambiar, ya que mi rutina se ejecutará desde el segmento de código especificado en mi entrada IDT. También entiendo que el selector de pila probablemente también cambie, pero no puedo estar seguro de esto.

¿Podría alguien explicarme por favor qué cambios de contexto se realizan cuando se llama a una puerta de interrupción?

Respuesta

20

Llegar al timbre 3 se puede hacer usando iret porque la forma en que funciona ha sido documentada. Cuando se recibe una interrupción, el procesador empuja:

  1. El segmento de pila y el puntero (ss: esp), tal como 4 palabras
  2. eflags
  3. El segmento y puntero de instrucción código de retorno (CS: EIP), como 4 palabras
  4. Un código de error, si es necesario.

iret funciona deshaciendo pasos 1-3 (El ISR es responsable de deshacer el paso 4 si es necesario). Podemos usar este hecho para obtener el timbre 3 al empujar la información requerida a la pila y emitir una instrucción iret. Asegúrate de tener la CPL adecuada en tu código y en los segmentos de pila (los dos bits bajos deben establecerse en cada uno). Sin embargo, iret no cambia ninguno de los segmentos de datos, por lo que deberá cambiarlos manualmente. Utiliza la instrucción mov para hacer esto, pero no podrás leer datos fuera de la pila al hacer esto y al cambiar de timbre.

cli 
mov ax, Ring3_DS 
mov ds, eax 
push dword Ring3_SS 
push dword Ring3_ESP 
pushfd 
or dword [esp], 0x200 // Set IF in EFLAGS so that interrupts will be reenabled in user mode 
push dword Ring3_CS 
push dword Ring3_EIP 
iret 

Si quieres un ejemplo completo, trabajando, ver this tutorial.


Cuando se emite una interrupción, el procesador lee el IDT para obtener el segmento de código apropiado y puntero de instrucciones para el ISR. Luego mira tu TSS para encontrar el nuevo segmento de pila y el puntero. Cambia ss y esp de forma adecuada, y luego empuja los valores anteriores a la nueva pila. Sí no cambia cualquiera de los registros del segmento de datos. Debe hacerlo manualmente si necesita acceder a la memoria en su ISR.

+1

Muy bien, usted respondió mi pregunta y ¡MÁS! Lo que ahora entiendo es que necesitaré tener un TSS que contenga mi pila de kernel, etc. Gracias por la ayuda. –

+0

¡Inicié sesión solo para votar esto! ¡Gracias! También para cualquier otra persona, recomiendo osdev y los manuales de Intel ISA también. Realmente aclaran las cosas. – Sid

+0

¿Qué quiere decir con que IRET no cambia el segmento de datos? ¿Estás hablando de valores dentro de los registros de propósito general? –

1

También puede hacer un retf.Un retorno lejano a un segmento de código menos privilegiado provocará que el nuevo ss y sp salgan de la pila con privilegios.

Solo asegúrese de que realiza devoluciones lejanas para llamadas lejanas y ireces por interrupciones. La única diferencia entre ellos es la presencia de banderas en la pila, pero no es bueno mezclarlas.

Además, no olvide que a veces las excepciones envían códigos de error en la pila.

Cuestiones relacionadas