Arquitetura Plug and Play
Por Alexandre Mendonça e Ricardo Zelenovsky*

O mercado de computadores pessoais vem gradativamente mudando o seu perfil. Primeiramente, o que se observava, no início da década de 80, era que grande parte dos compradores de PCs ou possuíam algum conhecimento técnico ou não se preocupavam com instalações futuras de recursos após o computador ser adquirido. Ou seja, não se tinha o costume de abrir uma máquina e conectar placas, drives ou outros periféricos. Mesmo quando havia uma necessidade de instalação de qualquer componente, exigia-se um mínimo de conceitos técnicos. Ora, era comum, e ainda não deixa de ser, que as configurações de endereços de I/O ou memória, interrupções e canais de DMA fossem determinadas por jumpers e chaves do tipo dip-switch. Daí, no mínimo, era imprescindível saber interpretar alguma literatura técnica, como um manual de placa. E mais, saber mapear endereços ou interrupções, de forma a garantir que não houvesse conflitos elétricos no barramento. Um outro tipo de problema também era freqüente: o usuário comprava uma placa nova que requeria, em sua instalação, alterar algum parâmetro de configuração de outra placa já conectada e com seu software já inicializado. Certamente, quem não tem tanta intimidade com conceitos de hardware teria certa dificuldade em adequar os device-drivers outrora configurados, tanto nos arquivos "config.sys" e "autoexec.bat", quanto no painel de controle do windows ou outro aplicativo. Contudo, o perfil de mercado passou a ser dominado por um novo tipo de consumidor: aquele totalmente leigo, o que não sabe sequer o que são interrupções, endereços ou jumpers. Com isso, aquele problema de reconfiguração fica agravado. Para evitar as referidas dificuldades de configuração, reconfiguração e atualização, que tanto frustavam os usuários, foram idealizados sistemas confortáveis, denominados plug and play, ou seja, conecte e opere. Então, tecnicamente falando, o objetivo de um sistema plug and play é permitir que a BIOS ou sistema operacional instalem e configurem quaisquer combinações de placas de expansão e dispositivos. Desta forma, aquele método de configuração de jumpers ou chaves passa a ser substituído por um gerenciamento por software. A flexibilidade conseguida com este sistema é tal que permite reconfigurações mesmo em tempo de execução.

A Solução Plug and Play
A solução para o problema plug and play consiste em fazer com que o hardware, firmware, sistema operacional e aplicativos sejam capazes de compartilhar dispositivos através da definição de formatos de identificadores de dispositivos (tipo, de placa, fabricante, versão, etc.) e recursos exigidos (interrupção, canal de DMA e endereços de I/O ou memória), e que são estruturas de dados, padronizadas pela arquitetura plug and play. O primeiro passo para que seja constituído o ambiente plug and play é identificar a configuração da máquina (feito inicialmente pela BIOS e posteriormente gerenciada pelo sistema operacional), ou seja, construindo-se uma árvore de hardware. Tal árvore deve conter os registros necessários para estabelecerem-se a assinatura ou identificação dos dispositivos e a informação necessária para automaticamente localizar e carregar os device-drivers. Após carregar o device-driver, adiciona-se à árvore de hardware, mesmo em tempo de execução, um nó de dispositivo associado ao driver. Vale observar que toda placa-mãe que suporta a arquitetura plug and play possui uma BIOS que busca, durante a inicialização do computador, e armazena os registros de nós de dispositivos, contendo as informações dos recursos exigidos. Isto orienta todas as partições de sistemas operacionais e os device-drivers que possam futuramente ser instalados. Após a instalação, os nós de dispositivos são acrescentados ou modificados segundo às necessidades do sistema operacional. É importante ressaltar que quaisquer tipos de conecções elétricas fazem parte da árvore de hardware, inclusive todas as ligações hierárquicas entre os barramentos (ex: ponte barramento local - barramento ISA ou PCI). A Figura 1 ilustra um exemplo de configuração envolvida numa árvore de hardware. Um problema surge ao distribuir os recursos pelos nós da árvore de hardware, de solução não trivial, que é o de identificar os dispositivos estáticos, como placas ISA que não têm a flexibilidade de alterar dinamicamente os recursos exigidos de interrupção, DMA e endereços de I/O ou memória. Por tal falta de flexibilidade, duas são as opções para tais dispositivos: mapeá-los de forma prioritária (ex: se o dispositivo exigir a IRQ 5, ele a terá disponível) ou desligá-los (desconectá-los logicamente da configuração da máquina e fisicamente do barramento). A BIOS oferece também um conjunto padronizado de serviços referentes à arquitetura plug and play, como a obtenção dos recursos alocados para cada dispositivo. Tais serviços são acessados, por software, de duas formas: somente em modo real (ex: programas para DOS), através da interrupção por software 1Ah; e tanto em modo real quanto em modo protegido (ex: windows 95 e DOS), através de subrotinas (instrução call).

Device-Drivers
Basicamente, a diferença entre desenvolver um device-driver comum e um device-driver plug and play é deixá-lo prevenido contra reconfigurações por parte do sistema operacional. Isto pode ser traduzido por alguns procedimentos de software que se resumem aos recursos exigidos pelo device-driver ficarem sob custódia do sistema operacional (isto para que eles possam ser gerenciados dinamicamente). Detalhando um pouco mais tal custódia, o device-driver, no instante de seu registro ou instalação, retorna ao sistema operacional um endereço de uma rotina, contida no device-driver, do tipo call-back (como o procedimento de janela ou de caixa de diálogo). Com isso, fica permitida a troca de mensagens entre o sistema operacional e o device-driver. Inclusive, fica o device-driver obrigado a responder a todas as mensagens de reconfiguração enviadas pelo sistema operacional. A Figura 2 ilustra uma seqüência de comandos que devem estar contidos no código desenvolvido para o device-driver plug and play.

/* variáveis globais do device-driver */
unsigned int interrupção, endereço_base;
/* subrotina que recebe as ordens de reconfiguração */
LRESULT CALLBACK device_driver_reconfig( ... ) {
...
/* identifica mensagem de reconfiguração */
...
/* altera variáveis globais */
interrupção = ...;
endereço_base = ...;
altera_manipulador_vetor_interrupção( ... );
...
}
/* rotinas de acesso ao periférico */
void envia_dado (int dado) {
outp (endreço_base, dado); }
...
Figura 2: Exemplo de uma arquitetura de device-driver, contendo a subrotina que intercepta as ordens de reconfiguração e subrotinas de acesso genérico ao periférico.
Concluindo, o processo de configuração de recursos é realizado em duas situações:
primeira, por parte da BIOS, durante a inicialização do computador, naturalmente, fazendo parte do POST (Power On Self Test) e, segundo, em tempo de execução, sob gerenciamento do sistema operacional.

BIOS Plug and Play
Primeiramente, o mínimo exigido para um sistema ser plug and play é que ele contenha uma BIOS plug and play, ou seja, que disponha ao sistema operacional e aos aplicativos serviços padronizados de gerenciamento de recursos. Para detectar a BIOS plug and play, o sistema operacional ou o aplicativo procura, na memória, o que se chama de "cabeçalho de instalação". O cabeçalho é uma estrutura de 34 bytes que contém os endereços a partir de onde estão residentes as rotinas de serviços oferecidas pela BIOS, tanto para o modo real, quanto para o modo protegido, além de outras informações (assinatura, fabricante, versão, etc.). O cabeçalho de instalação começa com uma assinatura de 4 bytes ("$PNP"), e pode estar localizado a partir do offset 0 do início de qualquer dos segmentos do modo real entre os endereços físicos F0000h e FFFF0h. A rotina a seguir, implementada para o modo real, verifica se o sistema é plug and play, através da busca de um cabeçalho de instalação com a assinatura padronizada.

#include
...
unsigned int verifica_plug_play(void) {
void far endereço;
unsigned int seletor;
for (seletor=0xF000;seletor!= 0xFFF0; seletor++) {
endereço = MK_FP(seletor,0);
if (strncmp( (char far *) (endereço), "$PNP", 4) == 0 )
return (seletor);
return ( 0 ); }
Obtidos os endereços das rotinas dos serviços (contidos no cabeçalho de instalação), ficam disponíveis os serviços de configuração. As chamadas aos serviços são do tipo int far (função far que retorna um inteiro de 16 bits). Como são vários os serviços, a passagem de parâmetros pela pilha é feita como nos compiladores C, e não como no PASCAL, ou seja, são empilhados os parâmetros da direita para a esquerda. O último parâmetro empilhado é um inteiro que especifica o índice do serviço oferecido. Em C, a declaração destes tipos de função segue ao padrão a seguir:
int far(end_do_conjunto_de_serviços)(int índice_do_serviço,...);
O número de parâmetros passados depende do índice do serviço.
Apenas como ilustração, exemplificam-se alguns serviços como obter as características e recursos de um nó de dispositivo num registro de dados, ou alterar, de acordo com a convenência de gerenciamento, parâmetros do registro outrora obtido.

Hardware Plug and Play Comercial
Dispositivos periféricos conectados diretamente à placa mãe do sistema (temporizadores, RAM CMOS, controladores de interrupção e DMA, interface de teclado e outros) e as placas ISA estáticas (que não são reconfiguráveis) têm seus recursos estrategicamente alocados como num PC AT convencional. Então, apenas os recursos restantes poderão vir a ser compartilhados pelas placas plug and play.
Comercialmente, são mais comuns placas plug and play para 3 tipos de barramentos comerciais: PCI, ISA e PCMCIA. Os dois primeiros casos serão comentados.
Placas que satisfazem à especificação PCI já são, por natureza, plug and play. Tal especificação já reserva, para cada slot PCI lógico, 256 endereços de I/O consecutivos, onde, pelos primeiros 64, são feitas as programações de recursos e oferecidas informações outras, como identificações do fabricante e da versão e a localização da ROM de expansão.
Ao contrário do barramento ISA, podem existir múltiplos barramentos PCI numa configuraçào de máquina (a vantagem disto é descongestionar o fluxo de dados onde está conectada a CPU principal). Tais barramentos são hierarquizados da seguinte forma: existe um barramento raiz e os outros barramentos são interligados eletricamente por pontes PCI-PCI, como mostrado na Figura 3.
Para verificar se a máquina admite a especificação PCI, utilizar o seguinte código, para modo real, em assembler:

mov ax,B101h ;serviço B101h
int 1Ah ;interrupção 1Ah
cmp edx, 50434920h ;se for PCI compatível, retorna a string'PCI 'em edx
Se a flag ZF (zero flag) estiver em 1, o sistema admite o PCI.

Uma placa ISA plug and play é uma variação nova dos adaptadores ISA, com a característica de admitir uma configuração dinâmica de recursos. Vale ressaltar que, para os dois casos, as pinagens dos conectores de encaixe de placas são idênticas. A diferença é que, na tradicional, a configuração é estabelecida por jumpers e chaves, e que, na plug and play, é por software, segundo a padrões bem definidos.
Quanto a custos, as placas ISA tradicionais são de projeto e programação bem mais simples que as ISA plug and play, que, para atender aos padrões de configuração dinâmica, exigem circuitos digitais extras e uma programação bem mais complexa. Isto talvez explica o porquê de ainda projetarem-se bastante placas ISA tradicionais, principalmente no meio acadêmico ou mesmo no profissional em escala reduzida, isto quando a placa tem utilização bastante restrita.
Para permitir-se a reconfiguração em placas ISA plug and play, foram acrescentados, na placa mãe do sistema, 3 registradores extras: o registrador de endereços (279h, só para escrita), o registrador de escrita (A79h, só para escrita) e o registrador de leitura (programável entre 203h e 3FFh, só para leitura). Por estes registradores são feitas algumas trocas de informações entre a BIOS ou sistema operacional e as placas ISA plug and play.
Uma dúvida poderia surgir quanto ao fato de utilizarem-se os endereços 279h e A79h, que são reservados para a LPT2 e LPT3, respectivamente. Contudo, não haverá conflitos elétricos devido a esta multiplexação, pois estes endereços são usados apenas para a leitura pelas portas paralelas.

PCI Plug and Play
Motivado pelas limitações técnicas do barramento ISA (8MHz, 16 bits), a Intel, em 1992, introduziu a especificação de barramento PCI (Peripheral Component Interconnect), que permite a comunicação de palavras de 32 ou 64 bits, a 33MHz. Mais que uma nova especificação de barramentos para PCs, o PCI possui a característica de universalidade, ou seja, pode ser aproveitado por qualquer processador em qualquer arquitetura de máquina. Isto parece ser uma dualidade, pois, apesar de universal, o PCI também tem característica de barramento local.
Outra inovação do barramento PCI é expandir a limitação de alguns carregamentos elétricos através de pontes PCI-PCI. Uma ponte deste tipo cria um barramento secundário isolado eletricamente do barramento raiz, permitindo-se a utilização de mais placas de expansão. Esta característica consagrou o PCI como barramento nas arquiteturas de servidores de grande desempenho, como estudado nas DevMag de fevereiro, março e abril de 97.
Além da ponte PCI-PCI, foi especificada a ponte PCI-ISA, de forma a permitir o aproveitamento de placas ISA na configuração da máquina.

PCI: Interrupções, I/O e DMA
No barramento PCI, a utilização de alguns recursos de hardware requer uma abordagem diferente daquela associada ao barramento ISA. Primeiro, apenas 4 sinais de interrupção estão disponíveis nos slots (INTA#, INTB#, INTC# e INTD#). Com isso, o controlador PCI fica responsável por fazer a ligação elétrica conveniente entre a INT# escolhida pelo projetista da placa e a IRQ que será alocada pelo software de gerenciamento plug and play (BIOS e sistema operacional). Vale observar que as 4 interrupções são roteadas para cada um dos slots lógicos, sem que haja conflitos caso duas placas optem por usar o mesmo sinal. Inclusive, é conveniente que placas que usem apenas 1 sinal de interrupção utilizem a INTA#.
Segundo, as placas PCI admitem uma decodificação de endereços de I/O total, ou seja, de 32 bits (0 a FFFFFFFFh), contra 12 bits do ISA (0 a 3FFh). Isto permite que a BIOS e o sistema operacional tenham a flexibilidade de mapear dispositivos PCI sem que haja qualquer tipo de conflito com placas ISA.
Terceiro, a especificação PCI proíbe que se consuma canal de DMA por placas PCI. Quando alguma placa ISA exigir DMA, estando esta placa conectada a um slot ligado ao PCI por ponte PCI-ISA, é implementado um mecanismo especial para fazer transferências por DMA, que fica transparente para o software.

Mapeamento dos Endereços de I/O
Para cada slot lógico, a especificação PCI reserva 256 endereços de I/O consecutivos, sendo que os 64 primeiros compõem um cabeçalho para a identificação e programação dos recursos exigidos pelo dispositivo. Dependendo do chip-set PCI utlizado na placa mãe do sistema, como será comentado, apenas o cabeçalho poderá ser acessado. O formato deste cabeçalho está ilustrado na Figura 1. Os outros 192 endereços estão disponíveis ao projetista para uso geral.

Campos do Cabeçalho
Os códigos (somente leitura) do vendedor e do dispositivo identificam a empresa e o tipo de controladora da placa.
O registrador de comando (leitura e escrita) é o responsável pela programação de alguns parâmetros de acesso, como a permissão para manusear memória e I/O contidos na placa, a habilitação de alguns ciclos especiais de barramento e outros.
O registrador de estado (leitura e escrita parcial) informa algumas condições de velocidade de comunicação e de detecção de erros.
O identificador de revisão (leitura) informa o número da revisão do adaptador, sendo um código criado pelo fabricante.
O código da classe (leitura) identifica a função básica do dipositivo (ex: multimídia, ponte PCI-outro barramento, placa de rede, base de dados, etc.).
O tamanho do cache (leitura e escrita) (4 para um 486) é o tamnho, em doublewords, da linha de cache para escritas na memória da placa.
O temporizador de latência (leitura e escrita) especifica o tempo mínimo, em clocks de barramento, que o barramento mestre pode manter a posse do barramento. Ele é decrementado pelo barramento mestre a cada clock a partir do início da transferência de um dado.
O tipo de cabeçalho (leitura) define se o dispositivo é um adaptador ou uma ponte PCI-PCI.
O BIST (Built In Self Test - leitura) é um registrador opcional que permite efetuar-se uma seqüência de auto-teste do adaptador.
Os registradores para a programação de endereços bases são necessários quando o dispositivo implementa decodificadores de endereços para mapearem porções de memória e I/O. O bit menos significativo destes registradores é reservado para a leitura e indica o tipo se é a defição de endereços de I/O ou de memória. O mecanismo para tal programação é bastante interessante e será comentado posteriormente.
O registrador do pino de interrupção (leitura) indica por que sinal elétrico do barramento a placa PCI gerará o pedido de interrupção (INT# A, B, C ou D - programa-se 1 a 4 - ou não exige recurso de interrupção - programa-se 0).
O registrador de linha de interrupção (leitura e escrita) é programável pelo software plug and play (BIOS ou sistema operacional) e informa à placa qual das linha IRQ que alimentam o controlador de interrupções do PC está alocado para o adaptador.

3210Offsets
Código do dispositivoCódigo do vendedor00h
registrador de EstadoRegistrador de comando04h
Código de classeid. de revisão08h
BISTTipo cabeçalhoTemp. latênciaTam. cache0ch
primeiro registrador para a programação do endereço base10h
segundo registrador para a programação do endereço base 14h
terceiro registrador para a programação do endereço base18h
quarto registrador para a programação do endereço base1ch
quinto registrador para a programação do endereço base20h
sexto registrador para a programação do endereço base 24h
Reservado28h
ReservadoReservado2ch
Registrador para endereço base da ROM de expansão30h
Reservado34h
Reservado38h
ReservadoReservadoReg. pino int.Reg. linha int.3ch

Figura 1: Mapeamento dos registradores PCI. Os 12 primeiros bytes mais o tipo de cabeçalho são campos obrigatórios.

Programação de Endereços Bases
O mecanismo de programação de endereços bases de regiões de memória e I/O, regiões estas de comprimento mínimo de 16 ou 4 endereços (memória ou I/O, respectivamente), consiste em, primeiramente, escrever 1 em todos os bits do registrador de programação de endereços base. Em seguida, executa-se uma leitura do mesmo registrador. A lógica da placa implementada deve fazer com que seja retornado um número cuja porção menos significativa é, a menos dos primeiros 4 ou 2 bits (memória ou I/O), uma seqüência de zeros, de tamanho igual ao número de bits utilizado pelo decodificador em questão. A porção mais significativa restante deverá ser composta por dígitos 1. Este conjunto de dígitos 1 é que será imediatamente reprogramado, pelo software plug and play, de acordo com a disponibilidade de recursos, de forma a compor o endereço base da região de endereços.
Como exemplo, caso a placa esteja utilizando uma RAM de 4 KB, será retornado, após a escrita de dígitos 1, o valor FFFFF000h (12 bits menos significativos iguais a 0). A lógica da placa deve permitir a programação dos demais 20 bits, que vão habilitar a decodificação. Um exemplo de circuito que implementa os procedimentos detalhados é apresentado na Figura 2.
A BIOS procura por decodificadores implementados nos registradores de programação de endereço base até que encontre um não implementado, quando interrompe a busca.
O registrador de endereço base da ROM de Expansão é utilizado por placas que contêm ROMs que participarão da seqüência de inicialização do computador (POST - Power On Self Test) ou que oferecem serviços de interrupção por software.
A programação deste endereço é feita de forma semelhante à programação do exemplo da RAM de 4KB. Contudo, exige-se também que a ROM tenha a assinatura de uma ROM de expansão tradicional, ou seja, comece por 55h, AAh, tamanho, instrução JMP, etc..

Acesso aos Registradores de Configuração
Primeiramente, vale ressaltar que apenas o software de gerenciamento de recursos (BIOS e sistema operacional plug and play) deve ter acesso aos registradores de configuração (ver Figura 1) de cada dispositivo.
Existem dois mecanismos para acessar o espaço de endereçamento de um slot.
No primeiro mecanismo, programa-se uma palavra de controle de 32 bits (nos endereços de I/O CF8h a CFBh) que contém determinados campos, especificando qual o barramento a ser acessado (0 a 255), qual o número do dispositivo (0 a 39), a função (0 a 3) e o índice do registrador de configuração (0 a 63). O dado a ser lido ou escrito na localização especificada pela palavra de controle é acessado com uma leitura ou escrita no endereço CFCh.
No segundo mecanismo, desprotege-se o espaço de configuração PCI através de uma escrita conveniente no endereço CF8h. Após isto ser feito, o primeiro slot fica mapeado a partir do endereço C000h, o segundo a partir de C100h e assim por diante, sempre saltando 256 endereços por slot. Dets aforma, o registrador de comando do terceiro slot fica mapeado nos endereços C204h e C205h, podendo ser normalmente acessado por instruções IN e OUT.
Na verdade, o mecanismo adotado é automaticamente definido pelo chipset PCI da máquina em questão.
O segundo mecanismo tem a vantagem de ser de programação bastante simples, contudo é impróprio para implementações de máquinas com múltiplos processadores, pois, para a sincronização dos ciclos de barramento, o sistema fica bastante lento e caro.
A BIOS oferece diversos serviços aos aplicativos e sistema operacional, pela INT 1Ah do modo real ou outras funções, de forma que estes possam ter acesso a dados provenientes do resultado da configuração de recursos estabelecida pleo gerenciamento plug and play.

ARQUIVO 048/2001


home.jpg Problemas com o site? contacte o WebMaster