Devo far apparire il codice di errore inserito nello stack da determinate eccezioni prima di tornare dal gestore degli interrupt?

StackOverflow https://stackoverflow.com/questions/491613

Domanda

Ho caricato una tabella idt con 256 voci, tutte indicanti gestori simili:

  • per le eccezioni 8 e 10-14, invia il numero di eccezione (queste eccezioni inviano automaticamente un codice di errore)
  • per gli altri, premi un " dummy " codice di errore e numero di eccezione;
  • quindi passa a un gestore comune

Quindi, quando il gestore comune entra, lo stack è correttamente allineato e contiene il numero di eccezione / interruzione, il codice di errore (che potrebbe essere solo un manichino), eflags, cs ed eip.

La mia domanda riguarda il ritorno dal gestore degli interrupt. Uso iret per tornare dopo aver estratto il numero di eccezione e il codice di errore dallo stack, ma questo non funziona per l'eccezione n. 8; se lascio il codice di errore nello stack, allora ritorna bene!

Domande:

  • devo lasciare il codice di errore nello stack per le eccezioni che inseriscono il codice di errore? In tal caso, in che modo <=> determina se deve essere visualizzato un codice di errore o meno?
  • non appena abilito gli interrupt ottengo sempre l'eccezione 8 (doppio errore), ma poi tutto funziona correttamente (sto sviluppando un sistema operativo hobby). È un comportamento normale o ho un bug da qualche parte?
È stato utile?

Soluzione

Se la CPU ha inviato automaticamente un codice di errore, il gestore deve farlo comparire prima di iret. L'istruzione <=> non sa da dove vieni, se si tratta di un errore, una trap o un interrupt esterno. Fa sempre lo stesso e presuppone che non ci sia codice di errore nello stack.

Citazione da SDM (Manuale per gli sviluppatori di software), Volume 3, Capitolo 5, sezione 5.13 intitolata Error Code:

  

Il codice di errore viene inserito nello stack   come doppia parola o parola (a seconda di   l'interrupt, trap o task predefinito   dimensione del cancello). Per mantenere allineato lo stack   per i push doppia parola, la metà superiore   del codice di errore è riservato. Nota   che il codice di errore non viene visualizzato quando   l'istruzione IRET viene eseguita su   ritorno da un gestore di eccezioni, quindi   il gestore deve rimuovere il codice di errore   prima di eseguire un ritorno.

Puoi trovare il Manuale dello sviluppatore del software IA-32 qui : http://www.intel.com/products/processor/manuals/

Il volume 3, parte 1, capitolo 5, descrive la gestione delle eccezioni e degli interrupt. Il volume 2, parte 1, contiene le specifiche per l'istruzione <=>.

Altri suggerimenti

Ho scritto un piccolo sistema operativo x86 qualche tempo fa. Dai un'occhiata al file isr. asm nel repository cvs.

Nota come configuriamo i gestori, la maggior parte inserisce una dummy dummy nello stack per tenere conto dei pochi gestori che ricevono automaticamente un codice di errore. Quindi quando torniamo tramite un iret possiamo sempre assumere 2 parole nello stack indipendentemente dall'interruzione ed eseguire un esp esp, 8 prima dell'iret per ripulire bene le cose.

Questo dovrebbe rispondere alla tua prima domanda.

Per quanto riguarda la seconda domanda: un doppio errore quando si abilitano gli interrupt, ... hmmm potrebbe essere un problema con il paging se non è stato impostato correttamente. Potrebbe essere anche un milione di altre cose :)

Ho avuto un problema simile con " doppi guasti " non appena abilito gli interrupt. Bene, sembravano come doppi difetti, ma erano davvero interruzioni del timer!

I doppi guasti sono il numero di interruzione 8.

Sfortunatamente, una configurazione PIC predefinita segnala che il timer si interrompe come numero di interruzione (DEFAULT_PIC_BASE + TIMER_OFFSET) = (8 + 0) = <=>.

Il mascheramento di tutti i miei interrupt PIC (fino a quando non ero pronto a configurare correttamente il PIC) ha messo a tacere questi interrupt timer a doppio errore.

(p potrebbe essersi aspettato.)

  

Devo lasciare il codice di errore nello stack per eccezioni che inseriscono il codice di errore lì?

Come altri hanno già detto, devi fare:

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

O se si desidera ignorare il codice di errore:

add $4, %esp
iret

In caso contrario, iret interpreterà il codice di errore come il nuovo CS e è probabile che si verifichi un errore di protezione generale come indicato in: Perché iret da un gestore di errori di pagina genera l'interrupt 13 (errore di protezione generale) e il codice di errore 0x18 ?

Minimal Lavorando questa pagina che ho creato per illustrare questo. Prova a commentare pop e vederlo esplodere.

Confronta quanto sopra con un Manuale di programmazione del sistema Intel Volume 3 - 325384-056US settembre 2015 Tabella 6-1. " Eccezioni e interruzioni in modalità protetta " colonna " Codice errore " contiene l'elenco degli interrupt che inviano o meno il codice di errore.

38.9.2.2 " Codici errore errore di pagina " spiega cosa significa l'errore.

Un modo accurato per risolvere questo problema è quello di inserire un codice di errore fittizio 0 nello stack per gli interrupt che non lo fanno per rendere le cose uniformi. Tutorial di James Molloy a>.

Il kernel 4.2 di Linux sembra fare qualcosa di simile. Sotto arch / x86 / entry / entry64 .S modella gli interrupt con has_error_code:

trace_idtentry page_fault do_page_fault has_error_code=1

e quindi lo utilizza sullo stesso file di:

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

che fa il push quando has_error_code=0.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top