una tratamiento software sistemas servicio rutina que procesamiento operativos interrupción interrupciones excepción ejemplos contexto concepto cambio assembly operating-system x86 interrupt osdev

assembly - tratamiento - ¿Tengo que mostrar el código de error que se apila para apilar ciertas excepciones antes de volver desde el manejador de interrupciones?



rutina de servicio de interrupción (4)

Hace un tiempo escribí un pequeño sistema operativo x86 . Eche un vistazo al archivo isr.asm en el repositorio cvs.

Observe cómo configuramos los manejadores, la mayoría empuja un dummy dword en la pila para dar cuenta de los pocos manejadores que automáticamente obtienen un código de error. Luego, cuando volvemos a través de un iret siempre podemos asumir 2 dwords en la pila independientemente de la interrupción y realizar un add esp, 8 antes del iret para limpiar bien las cosas.

Eso debería responder tu primera pregunta.

En cuanto a su segunda pregunta: Un doble error cuando habilita interrupciones, ... hmmm podría ser un problema con paginación si no lo ha configurado correctamente. Podría ser un millón de otra cosa también :)

He cargado una tabla idt con 256 entradas, todas apuntando a controladores similares:

  • para las excepciones 8 y 10-14, inserte el número de excepción (estas excepciones envían un código de error automáticamente)
  • para los demás, inserte un código de error "ficticio" y el número de excepción;
  • luego salta a un manejador común

Entonces, cuando ingresa el controlador común, la pila se alinea correctamente y contiene el número de excepción / interrupción, el código de error (que puede ser simplemente un maniquí), eflags, cs y eip.

Mi pregunta se refiere a regresar del controlador de interrupción. Uso iret para regresar después de sacar el número de excepción y el código de error de la pila, pero esto no funciona para la excepción n º 8; si dejo el código de error en la pila, ¡vuelve bien!

Preguntas:

  • ¿Debo dejar el código de error en la pila para las excepciones que ponen allí el código de error? Si es así, ¿cómo determina iret si tiene que iret un código de error o no?
  • tan pronto como habilito las interrupciones siempre obtengo la excepción 8 (doble culpa), pero luego todo funciona bien (estoy desarrollando un sistema operativo hobby). ¿Es este comportamiento normal o tengo un error en alguna parte?

Si la CPU inserta un código de error automáticamente, el controlador debe iret antes del iret . La instrucción iret no sabe de dónde vienes, si es un error, una trampa o una interrupción externa. Siempre hace lo mismo, y asume que no hay código de error en la pila.

Citando del SDM (Manual del desarrollador de software), Volumen 3, Capítulo 5, sección 5.13 titulado Código de error:

El código de error se inserta en la pila como una palabra doble o palabra (según la interrupción predeterminada, la captura o el tamaño de la puerta de tareas). Para mantener la pila alineada para empujes de doble palabra, la mitad superior del código de error está reservada. Tenga en cuenta que el código de error no aparece cuando la instrucción IRET se ejecuta para regresar desde un manejador de excepciones, por lo que el manejador debe eliminar el código de error antes de ejecutar una devolución.

Puede encontrar el Manual del desarrollador de software IA-32 aquí : http://www.intel.com/products/processor/manuals/

El volumen 3 parte 1, capítulo 5, describe el manejo de excepciones e interrupciones. Volumen 2 parte 1 tiene la especificación para la instrucción iret .


Tuve un problema similar con "fallas dobles" tan pronto como habilité las interrupciones. Bueno, parecían dobles fallas, ¡pero realmente eran interrupciones de temporizador!

Las fallas dobles son la interrupción número 8 .

Desafortunadamente, una configuración de PIC predeterminada señala las interrupciones del temporizador como número de interrupción (DEFAULT_PIC_BASE + TIMER_OFFSET) = (8 + 0) = 8 .

Enmascarando todas mis interrupciones de PIC (hasta que estuve listo para configurar correctamente el PIC) silenciamos estas interrupciones de temporizador de doble falla.

(Los PIC requieren que la CPU reconozca las interrupciones antes de que produzcan la siguiente. Como su código no reconocía la interrupción inicial del temporizador, ¡el PIC nunca le dio más! Es por eso que solo obtuvo uno, en lugar del trillón que uno podría haber esperado .)


¿Debo dejar el código de error en la pila para las excepciones que ponen allí el código de error?

Como otros mencionaron, debes hacer lo siguiente:

pop %eax /* Do something with %eax */ iret

O si quiere ignorar el código de error:

add $4, %esp iret

Si no lo hace, iret interpretará el código de error como el nuevo CS, y es probable que obtenga un error de protección general como se menciona en: ¿Por qué iret de un controlador de fallas de página genera interrupción 13 (falla de protección general) y código de error 0x18?

Mínimo Trabajando con este controlador de página que he creado para ilustrar esto. Intenta comentar el pop y verlo explotar.

Compare lo anterior con una excepción de error de División que no hace saltar la pila.

Tenga en cuenta que si lo hace simplemente int $14 , no se empuja ningún byte adicional: esto solo ocurre en la excepción real.

Manual de programación del sistema Intel Volume 3 - 325384-056ES Septiembre de 2015 Tabla 6-1. La columna "Código de error" de "Excepciones e interrupciones de modo protegido" contiene la lista de interrupciones que activan o no el código de error.

38.9.2.2 "Códigos de error de falla de página" explica qué significa el error.

Una buena manera de lidiar con esto es insertar un código de error ficticio 0 en la pila para las interrupciones que no hacen esto para uniformizar las cosas. El tutorial de James Molloy hace exactamente eso .

El núcleo de Linux 4.2 parece hacer algo similar. Bajo arch / x86 / entry / entry64.S modela interrupciones con has_error_code :

trace_idtentry page_fault do_page_fault has_error_code=1

y luego lo usa en el mismo archivo como:

.ifeq /has_error_code pushq $-1 /* ORIG_RAX: no syscall to restart */ .endif

que hace el empuje cuando has_error_code=0 .