Eu tenho que colocar o código de erro empurrado para a pilha por certas exceções antes de retornar do manipulador de interrupção?

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

Pergunta

Eu tenho carregado uma tabela IDT com 256 entradas, todos apontando para manipuladores semelhantes:

  • para exceções 8 e 10-14, empurrar o número de exceção (essas exceções empurrar um código de erro automaticamente)
  • para os outros, empurrar um código de erro "fictício" eo número de exceção;
  • em seguida, saltar para um manipulador comum

Assim, quando o manipulador comum entra, a pilha está alinhada corretamente e contém a exceção / número de interrupção, o código de erro (que pode ser apenas um simulado), eflags, cs e EIP.

A minha pergunta diz respeito retornar do manipulador de interrupção. Eu uso iret para retornar depois de tomar o número de exceção eo código de erro da pilha, mas isso não funciona para exceção nr 8; se eu deixar o código de erro na pilha, em seguida, ele retorna bem!

Perguntas:

  • que eu tenho que deixar o código de erro na pilha para exceções que colocam o código de erro lá? Se assim for, como é que iret determinar se tem a pop um código de erro ou não?
  • assim que eu permitir que as interrupções Eu sempre obter exceção 8 (falha dupla), mas, em seguida, tudo corre bem (Eu estou desenvolvendo um sistema operacional hobby). É este o comportamento normal ou eu tenho um lugar bug?
Foi útil?

Solução

Se a CPU empurrou um código de erro automaticamente, o manipulador deve pop-lo antes do iret. A instrução iret não sabe onde você está vindo, se é uma falha, uma armadilha ou uma interrupção externa. Ele sempre faz o mesmo, e ele assume que não há nenhum código de erro na pilha.

Citando o SDM (Software Manual do desenvolvedor), Volume 3, Capítulo 5, seção 5,13 intitulado Código de erro:

O código de erro é empurrado na pilha como um doubleword ou palavra (dependendo a interrupção padrão, armadilha, ou tarefa tamanho da janela). Para manter a pilha alinhada para empurrões doubleword, a metade superior do código de erro é reservado. Nota que o código de erro não é estalou quando a instrução IRET é executado para retornar de um manipulador de exceção, assim o manipulador deve remover o código de erro antes de executar um retorno.

Você pode encontrar Manual IA-32 Software do desenvolvedor aqui : http://www.intel.com/products/processor/manuals/

Volume 3 parte 1, capítulo 5, descreve exceção e manipulação de interrupção. Volume 2 Parte 1 tem a especificação para a instrução iret.

Outras dicas

Eu escrevi um pequena OS x86 um tempo atrás. Dê uma olhada no arquivo ISR. asm no repositório cvs.

Observe como montamos os manipuladores, a maioria empurrar um dword manequim para a pilha para a conta para os poucos manipuladores que recebem automaticamente um código de erro empurrado. Então, quando nós retornamos através de um IRET sempre podemos assumir 2 dwords na pilha, independentemente da interrupção e executar um add esp, 8 antes do iret a coisas limpas-se muito bem.

Isso deve responder a sua primeira pergunta.

Quanto à sua segunda pergunta: A dupla falta quando você habilita interrupções, ... hmmm poderia ser um problema com a paginação se você não configurá-lo corretamente. Poderia ser uma outra coisa milhões também:)

Eu tive um problema semelhante com "duplas faltas" assim que permitiu interrupções. Bem, eles olhou como duplas faltas, mas eles realmente eram interrupções do timer!

duplas faltas são número de interrupção 8.

Infelizmente, interrompe uma configuração sinais PIC padrão temporizador como número de interrupção (DEFAULT_PIC_BASE + TIMER_OFFSET) = (8 + 0) = 8.

Masking todas as minhas interrupções PIC (até que eu estava pronto para configurar corretamente o PIC) silenciados estas interrupções do timer-fault-lookalike dupla.

(PICs exigem a CPU para reconhecer interrupções antes de produzir a próxima. Desde seu código não estava reconhecendo a interrupção inicial do timer, o PIC nunca lhe dei qualquer mais! É por isso que você só tem um, em vez de um zilhão poderia ter esperado.)

Eu tenho que deixar o código de erro na pilha para exceções que colocam o código de erro lá?

Como os outros mencionados, você tem que fazer qualquer um:

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

Ou se você deseja ignorar o código de erro:

add $4, %esp
iret

Se você não fizer isso, iret irá interpretar o código de erro como o novo CS, e que são susceptíveis de obter uma falha de proteção geral, como mencionado em: Por que iret a partir de uma falha de página manipulador de gerar interrupção 13 (falha de proteção geral) eo código de erro 0x18

Minimal Trabalho desta página manipulador que eu criei para ilustrar isso. Tente comentar o pop e vê-lo explodir.

Compare o acima com um erro Divisão excepção, que não a pop a pilha.

Note que se você simplesmente int $14, nenhum byte extra é empurrado:. Isso só acontece na exceção real

manual Intel Volume 3 Guia de programação do Sistema - 325384-056US setembro 2015 Tabela 6-1. "Exceções de modo protegido e interrupções" coluna "Código de erro" contém a lista de interrupções que empurram o código de erro ou não.

38.9.2.2 "Códigos de erro Erro de página" explica o que os meios de erro.

Uma maneira elegante de lidar com isso é para empurrar um código 0 erro manequim na pilha para as interrupções que não fazem isso para fazer coisas uniforme. James Molloy tutorial faz exatamente isso .

O kernel Linux 4.2 parece estar a fazer algo semelhante. Sob arch / x86 / entry / entry64 .S ele modela interrupções com has_error_code:

trace_idtentry page_fault do_page_fault has_error_code=1

e, em seguida, usa-lo no mesmo arquivo como:

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

que faz o impulso quando has_error_code=0.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top