Interrompe dispositivos externos em um sistema x86. Parte 1. A evolução dos controladores de interrupção

Neste artigo, gostaria de considerar os mecanismos de entrega de interrupção de dispositivos externos no sistema x86 e tentar responder às perguntas:

  • O que é o PIC e para que serve?
  • O que é o APIC e para que serve? Para que servem o LAPIC e o I / O APIC?
  • Quais são as diferenças entre APIC, xAPIC e x2APIC?
  • O que é MSI? Quais são as diferenças entre MSI e MSI-X?
  • Como as tabelas $ PIR, MPtable, ACPI estão relacionadas a isso?

Se você estiver interessado em receber uma resposta para qualquer uma dessas perguntas ou se quiser apenas se familiarizar com a evolução dos controladores de interrupção no sistema x86, seja bem-vindo ao gato.

1. Introdução


Todos sabemos o que é interrupção. Para quem não é, cite a wikipedia:

Interrupção (interrupção em inglês) - um sinal de software ou hardware que informa o processador sobre a ocorrência de qualquer evento que exija atenção imediata. A interrupção notifica o processador sobre a ocorrência de um evento de alta prioridade que requer interrupção do código atual executado pelo processador. O processador responde suspendendo sua atividade atual, salvando seu estado e executando uma função chamada manipulador de interrupções (ou manipulador de interrupções) que responde ao evento e os presta serviços de manutenção, após o que retorna o controle ao código interrompido.

Dependendo da fonte do sinal de interrupção, eles são divididos em:

  • assíncrono ou externo (hardware) - eventos originados de dispositivos de hardware externos (como dispositivos periféricos) e podem ocorrer em qualquer momento arbitrário: um sinal de um timer, placa de rede ou unidade de disco, pressionamentos de teclas, movimento do mouse. O fato de tal interrupção ocorrer no sistema é interpretado como uma solicitação de interrupção (IRQ) - os dispositivos relatam que precisam de atenção do sistema operacional;
  • eventos síncronos ou internos no próprio processador como resultado da violação de determinadas condições ao executar o código da máquina: divisão por zero ou excesso de pilha, acesso a endereços de memória inválidos ou código de operação inválido;
Neste artigo, eu gostaria de discutir interrupções externas no IRQ.

Por que eles são necessários? Suponha que desejemos executar alguma ação com um pacote de entrada para uma placa de rede quando ela chegar. Para não perguntar constantemente à placa de rede "você tem um novo pacote?" e não desperdice recursos do processador nisso, você pode usar a interrupção do IRQ. A linha de interrupção do dispositivo está conectada à linha INTR do processador e, quando um pacote é recebido, a placa de rede "puxa" essa linha. O processador entende que há informações e lê o pacote.

Mas e se houver muitos dispositivos? Você não pode obter o suficiente de todos os dispositivos externos das pernas do processador.



Para resolver esse problema, eles criaram um chip - um controlador de interrupção.

Pic


( wiki / osdev )

O primeiro foi um chip Intel 8259 PIC . 8 linhas de entrada (IRQ0-7) e uma saída conectando o controlador à linha INTR do processador. Quando ocorre uma interrupção de um dispositivo, 8259 puxa a linha INTR, o processador entende que algum dispositivo sinaliza uma interrupção e consulta o PIC para entender qual perna do IRQx causou a interrupção. Há um atraso adicional para esta pesquisa, mas o número de linhas de interrupção aumenta para 8.



No entanto, 8 linhas rapidamente se mostraram pequenas e, para aumentar seu número, foram utilizados 2 8259 controladores (mestre e escravo) conectados em cascata (Dual PIC).

Os IRQs de 0 a 7 são processados ​​pelo primeiro Intel 8259 PIC (mestre) e os IRQs de 8 a 15 são processados ​​pelo segundo 8259 PIC (escravo). Somente um mestre sinaliza a ocorrência de uma interrupção. Se ocorrer uma interrupção nas linhas 8 a 15, o segundo PIC (escravo) sinaliza uma interrupção ao mestre via IRQ 2, e o mestre, por sua vez, sinaliza a CPU. Essa interrupção em cascata leva uma das 16 linhas, mas no final fornece 15 interrupções disponíveis para os dispositivos.



O circuito se estabeleceu, e é isso que eles querem dizer quando falam sobre o PIC (Programm Interrupt Controller) agora. Posteriormente, os controladores 8259 receberam algumas melhorias e ficaram conhecidos como 8259A, e esse circuito foi incluído no chipset. No momento em que o barramento principal para conectar dispositivos externos era o barramento ISA, esse sistema como um todo era suficiente. Era necessário apenas garantir que dispositivos diferentes não se conectassem à mesma linha de IRQ para evitar conflitos, pois as interrupções do ISA não são compartilhadas.

Geralmente, o layout das interrupções para dispositivos era mais ou menos padrão

Exemplo (retirado daqui ):
IRQ 0 - temporizador do sistema
IRQ 1 - controlador de teclado
IRQ 2 - cascata (interrupção do controlador escravo)
IRQ 3 - porta serial COM2
IRQ 4 - porta serial COM1
IRQ 5 - porta paralela 2 e 3 ou placa de som
IRQ 6 - controlador de disquete
IRQ 7 - porta paralela 1
IRQ 8 - Temporizador RTC
IRQ 9 - ACPI
IRQ 10 - aberto / SCSI / NIC
IRQ 11 - aberto / SCSI / NIC
IRQ 12 - controlador de mouse
IRQ 13 - co-processador matemático
IRQ 14 - canal ATA 1
IRQ 15 - canal ATA 2

A configuração e o trabalho com microcircuitos 8259 são realizados através das portas de E / S:
ChipRegistre-sePorta de E / S
Foto principalComando0x0020
Foto principalDados0x0021
EscravoComando0x00A0
EscravoDados0x00A1

→ A documentação para o 8259A pode ser encontrada aqui.

O barramento ISA foi substituído pelo barramento PCI. E o número de dispositivos claramente começou a exceder o número 15, além disso, diferentemente do barramento ISA estático, nesse caso, os dispositivos podem ser adicionados ao sistema dinamicamente. Felizmente, neste barramento, as interrupções podem ser compartilhadas (ou seja, vários dispositivos podem ser conectados à mesma linha de IRQ). Como resultado, para resolver o problema da falta de linhas IRQ, eles decidiram agrupar interrupções de todos os dispositivos PCI em linhas PIRQ (solicitação de interrupção programável).

Digamos que temos 4 linhas de interrupção livremente no controlador PIC e 20 dispositivos PCI. Combinamos as interrupções de 5 dispositivos por linha PIRQx e conectamos as linhas PIRQx ao controlador. Se ocorrer uma interrupção na linha PIRQx, o processador precisará interrogar todos os dispositivos conectados a esta linha para entender de quem veio a interrupção, mas, em geral, isso resolve o problema. Um dispositivo que vincula linhas de interrupção PCI em uma linha PIRQ é geralmente chamado de roteador PIR.

Nesse método, você precisa garantir que as linhas PIRQx não estejam conectadas às linhas IRQx nas quais as interrupções ISA já foram iniciadas (pois isso causará conflitos) e que as linhas PIRQx estejam equilibradas (afinal, quanto mais dispositivos conectamos à mesma linha PIRQ, mais dispositivos você precisará interrogará o processador para entender qual desses dispositivos causou a interrupção).



Nota : o dispositivo PCI -> mapeamento PIR é mostrado abstratamente na figura, porque na verdade é um pouco mais complicado. Na realidade, cada dispositivo PCI possui 4 linhas de interrupção (INTA, INTB, INTC, INTD). Cada dispositivo PCI pode ter até 8 funções e agora cada função possui uma interrupção INTx. O INTx que cada função do dispositivo puxará é determinado pela configuração do chipset.

Em essência, funções são blocos lógicos separados. Por exemplo, em um dispositivo PCI, pode haver uma função de controlador Smbus, uma função de controlador SATA, uma função de ponte LPC. No lado do SO, cada função é um dispositivo separado com seu próprio espaço de configuração PCI Config.

O BIOS passou as informações sobre o roteamento de interrupção no PIC para o BIOS usando a tabela $ PIR e preenchendo os registros 3Ch (INT_LN Interrupt Line (R / W)) e 3Dh (INT_PN Interrupt Pin (RO)) do espaço de configuração do PCI para cada função. A especificação para a tabela $ PIR estava anteriormente no site da Microsoft , mas agora não está mais lá. O conteúdo das linhas da tabela $ PIR pode ser entendido na especificação do BIOS BIOS [4.2.2. Obtenha opções de roteamento de interrupção PCI] ou leia aqui

Apic


( wiki , osdev )

O método anterior funcionou até o surgimento dos sistemas multiprocessadores. O fato é que, em seu dispositivo, o PIC pode transmitir interrupções para apenas um processador principal. Mas eu gostaria que a carga nos processadores da manipulação de interrupções fosse equilibrada. A solução para esse problema foi a nova interface APIC (Advanced PIC).

Para cada processador, um controlador LAPIC especial (APIC local) é adicionado e um controlador APIC de E / S é adicionado para rotear interrupções de dispositivos. Todos esses controladores são combinados em um barramento comum chamado APIC (novos sistemas agora são conectados através de um barramento de sistema padrão).

Quando uma interrupção de um dispositivo chega ao pino de E / S APIC, o controlador direciona a interrupção para o LAPIC de um dos processadores. A presença de E / S APIC permite equilibrar a distribuição de interrupções de dispositivos externos entre processadores.

O primeiro chip APIC foi o 82489DX , era um chip separado que combina LAPIC e I / O APIC. Para criar um sistema de 2 processadores, eram necessários 3 microcircuitos. 2 funcionaria como LAPIC e um como E / S APIC. Posteriormente, a funcionalidade LAPIC foi incluída diretamente nos processadores e a funcionalidade I / O APIC foi enquadrada no chip 82093AA.

O I / O APIC 82093AA continha 24 pinos de entrada e a arquitetura APIC podia suportar até 16 CPUs. Para manter a compatibilidade com sistemas mais antigos, de 0 a 15 interrupções foram alocadas para interrupções antigas do ISA. E as interrupções dos dispositivos PCI começaram a ser exibidas na linha IRQ 16-23. Agora era possível não pensar em conflitos de interrupção dos dispositivos ISA e PCI. Além disso, graças ao aumento do número de linhas de interrupção livres, também foi possível aumentar o número de linhas PIRQx.



A programação de E / S APIC e LAPIC é feita através do MMIO. Os registros LAPIC geralmente estão localizados em 0xFEE00000, os registros de E / S APIC em 0xFE00000. Embora, em princípio, todos esses endereços possam ser reconfigurados.

Como no caso do PIC, inicialmente, chips individuais passaram a fazer parte do chipset.

Posteriormente, a arquitetura APIC recebeu modernização e a nova versão foi denominada xAPIC (x - extended). Manteve a compatibilidade com a versão anterior. O número de possíveis CPUs no sistema aumentou para 256.

A próxima rodada de desenvolvimento da arquitetura foi chamada x2APIC . O número de CPUs possíveis no sistema aumentou para 2 ^ 32. Os controladores podem trabalhar no modo de compatibilidade xAPIC ou no novo modo x2APIC, onde a programação LAPIC é realizada não através do MMIO, mas através de registros MSR (que são muito mais rápidos). A julgar por este link, o suporte do IOMMU é necessário para que este modo funcione.

Note-se que o sistema pode ter vários controladores de E / S APIC. Por exemplo, um para 24 interrupções na ponte sul e outro para 32 no norte. No contexto de E / S, as interrupções APIC são freqüentemente chamadas de GSI (Global System Interrupt). Portanto, em um sistema como esse será o GSI 0-55.

Existe um LAPIC embutido na CPU e qual arquitetura pode ser entendida pelos sinalizadores de bit no CPUID.
Para que o sistema detecte LAPIC e I / O APIC, o BIOS deve fornecer informações sobre eles ao sistema através do MPtable (o método antigo) ou da tabela ACPI (MADT neste caso). Além das informações gerais, o MPtable e o ACPI (desta vez na tabela DSDT) devem conter informações sobre roteamento de interrupções, ou seja, informações sobre qual dispositivo fica em qual linha de interrupção (análogo da tabela $ PIR).

A tabela MPTable pode ser encontrada na especificação oficial. Anteriormente, a especificação estava no site da Intel, mas agora só pode ser encontrada no arquivo. A especificação da ACPI agora está localizada no site da UEFI (versão atual 6.2 ). Deve-se observar que, usando o ACPI, você pode especificar o roteamento de interrupção para sistemas sem APIC (em vez de usar a tabela $ PIR).

Msi


( wiki )

A versão anterior do APIC é boa, mas não sem falhas. Todas essas linhas de interrupção do dispositivo complicam o circuito e aumentam a probabilidade de erros. O barramento PCI foi substituído pelo PCI express, no qual as linhas de interrupção foram simplesmente decididas a serem removidas. Para manter a compatibilidade, os sinais de interrupção (INTx #) são emulados por certos tipos de mensagens. Nesse esquema, a adição lógica de linhas de interrupção, que costumava ser feita pela conexão física de fios, caía sobre os ombros das pontes PCI. No entanto, o suporte a interrupções herdadas do INTx é apenas suporte para compatibilidade com versões anteriores com o barramento PCI. De fato, o PCI Express propôs um novo método para entregar mensagens de interrupção - MSI (interrupção sinalizada de mensagens). Nesse método, para sinalizar uma interrupção, o dispositivo simplesmente grava na área MMIO alocada para o LAPIC do processador.



Anteriormente, apenas 4 interrupções eram alocadas para um dispositivo PCI (ou seja, para todas as suas funções), mas agora tornou-se possível tratar até 32 interrupções.

No caso do MSI, não há compartilhamento para as linhas, cada interrupção corresponde ao seu dispositivo.

As interrupções do MSI também resolvem outro problema. Suponha que um dispositivo realize uma transação de gravação na memória e deseje relatar sua conclusão através de uma interrupção. Mas uma transação de gravação pode ser atrasada no barramento durante o processo de transferência (que o dispositivo desconhece) e o sinal de interrupção chegará antes do processador. Assim, a CPU ainda lerá dados inválidos. Se o MSI for usado, as informações sobre o MSI serão transmitidas, assim como os dados, e simplesmente não poderão ser acessadas mais cedo.

Deve-se observar que as interrupções do MSI não podem funcionar sem o LAPIC, mas o uso do MSI pode nos substituir pelo I / O APIC (simplificação de design).

Posteriormente, esse método recebeu a extensão MSI-X. Agora, cada dispositivo pode ter até 2048 interrupções. E tornou-se possível indicar individualmente a cada interrupção em qual processador ele deve ser executado. Isso pode ser muito útil para dispositivos muito carregados, como placas de rede.

Nenhuma tabela BIOS adicional é necessária para o suporte ao MSI. Mas o dispositivo deve relatar o suporte ao MSI em um dos recursos em seu PCI Config e o driver do dispositivo deve oferecer suporte ao trabalho com o MSI.

Conclusão


Neste artigo, examinamos a evolução dos controladores de interrupção e recebemos informações teóricas gerais sobre a entrega de interrupções de dispositivos externos em um sistema x86.

Na próxima parte, veremos como usar no Linux cada um dos controladores descritos na prática.

Referências:


Source: https://habr.com/ru/post/pt430548/


All Articles