Escritos
B. Piropo
Anteriores:
< Trilha Zero >
Volte de onde veio
02/01/1995

<Acessos em 32 bits - >
< Parte IV: O Modo Protegido>


Ainda de ressaca pela virada do ano, entramos em 95 com o pé direito: discutindo a mais importante característica dos microprocessadores de 32 bits: a proteção de memória. Já vimos a diferença entre a memória segmentada do 8088 e a memória plana do 386. O tema não foi propriamente dos mais corriqueiros mas, apelando para alguma simplificação, deu para explicar (e vocês entenderem, espero). Mas acontece que para entender exatamente como a proteção de memória funciona, é preciso ir fundo nas entranhas do microprocessador. E isso não é coisa para uma coluna como a nossa. Portanto vou apenas roçar a superfície, deixando de lado esoterismos como níveis de privilégio, checagens de tipo e coisas que tais. Aos puristas, então, fica o aviso: daqui para a frente, o nível de simplificação vai beirar o sacrilégio. Isto posto, adiante.

A grande vantagem da proteção de memória é dar segurança à multitarefa. Quer dizer: um sistema operacional desenvolvido especialmente para uma CPU que usa um esquema de proteção de memória pode rodar com segurança mais de um programa ao mesmo tempo. E a primeira dúvida que assalta a qualquer um que pense um pouco sobre o assunto é a seguinte: se um programa nada mais é que uma série de instruções executadas seqüencialmente pela CPU e se os micros têm apenas uma CPU, como é possível rodar mais de um programa em um dado momento se a CPU só pode executar uma instrução de cada vez e essa instrução só pode "pertencer" a um único programa?

A resposta é simples e se baseia no conceito de "time slice", ou "fatia de tempo". Quando diversos programas (ou "processos") estão rodando, a CPU e o sistema operacional, como malabaristas que jogam uma porção de objetos para o alto e os aparam nas mãos, lançando-os de volta e os mantendo no ar sem jamais permitir que caiam, administram a coisa de forma que cada programa receba a atenção da CPU por algum tempo (ou seja, fornecem-lhe uma "fatia de tempo") enquanto os outros esperam. Depois, é ele que espera até que todos os demais tenham recebido atenção. Na verdade os programas estão rodando cada um a seu tempo, um após o outro. Mas o tempo dado a cada um para usar a CPU é tão pequeno (milésimos de segundo) e a troca tão rápida, que tem-se a impressão que as coisas ocorrem simultaneamente (lembre-se que uma CPU de 33MHz, que não é das mais rápidas, executa 33 mil ciclos em cada milissegundo - tempo suficiente para rodar um bocado de instruções).

O macete está na forma de controlar o tempo fornecido aos programas. Sob OS/2, por exemplo, quem controla é o sistema operacional, o próprio OS/2. Se o programa terminou ou não o que estava fazendo no momento, não importa: esgotado o tempo, o OS/2 passa a CPU para o próximo da fila e o programa espera sua vez para retomá-la. Esta é a chamada multitarefa preemptiva. Já Windows faz diferente: entrega a CPU para o programa e fica esperando que ele a devolva para passá-la para o próximo. Como isso depende da cooperação do programa, chama-se multitarefa cooperativa. E explica porque, quando um programa está demasiadamente ocupado sob Windows, parece que a máquina travou (sem contar com o fato de que um programa mal feito pode simplesmente apoderar-se da CPU e não dar vez aos demais).

Em princípio, nada impediria que um mecanismo como este fosse implementado em uma CPU com características semelhantes a um 8088. Mas aí teríamos a possibilidade de terríveis desastres. Imagine uma situação comum para quem usa multitarefa: editar um texto enquanto transfere um arquivo de um BBS. Haveria dois programas rodando ao mesmo tempo: o de comunicações recebendo dados pela porta serial e escrevendo-os na memória, e o editor de textos modificando seu texto, também na memória. Cada um recebendo o controle da CPU por alguns milésimos de segundo e desempenhando suas tarefas. Enquanto eles, disciplinadamente, só alterarem os trechos da memória que lhes "pertencem", tudo corre na santa paz. Mas já imaginou se, por um erro qualquer, o programa de comunicações começar a escrever o arquivo que está sendo transferido do BBS no trecho de memória ocupado pelo texto que está sendo editado? Ou, pior, no trecho ocupado pelo código executável do editor de textos ou do sistema operacional? Sabe-se lá que tipo de "instrução" pode resultar de uma desgraça destas? No mínimo, a máquina pendura. No máximo, sei lá... Qualquer coisa pode acontecer.

A solução para este tipo de problema depende da CPU e é, justamente, a proteção da memória. A coisa, de forma muito simplificada, funciona mais ou menos assim: imagine um esquema de gerenciamento de memória semelhante à memória segmentada do 8088. Só que o tamanho de cada segmento não está limitado a 64K (um número que "cabe" em um registrador de 16 bits) mas a 4Gb (um número que "cabe" em um registrador de 32 bits). Quando um programa é carregado, o sistema fornece a ele tanta memória quanto solicite, dentro de um destes "segmentos" de tamanho variável. E anota (mas não "conta" para o programa), o tamanho e o endereço base do segmento, que chama de "seletor". Para o programa, essa memória é toda a que existe, já que ele desconhece a existência dos seletores (para o ele os endereços começam a contar na base de seu segmento e ele "pensa" que não existe nada além da memória que lhe foi fornecida). Ali dentro, ele pode fazer a cangancha que quiser: escrever, ler, bagunçar à vontade. Se fizer algo errado, só prejudica a si mesmo. E, nesse caso, o sistema operacional fornece meios de encerrar o programa mal comportado e liberar a memória que ele ocupava sem interferir no funcionamento dos demais.

A coisa, no fundo, é genialmente simples. Cada processo tem seu seletor e fica encapsulado dentro de seu trecho de memória, jamais interferindo com outro. Tudo o que o sistema operacional tem a fazer quando entrega a CPU a um dado processo é ajustar o ponteiro de endereços para seu seletor e ficar "de olho" para evitar que, apesar de todo o esquema de proteção, o programa tente acessar memória fora do seu segmento. Se isso acontecer, é gerada uma GPF ("falha geral de proteção", um nome que agora faz sentido) e o sistema tenta resolver o impasse. Se não consegue, nem discute: apita e mostra o cartão vermelho, encerrando o programa malfeitor.

Pois bem: esse tipo de gerenciamento de memória só é possível se a CPU fornecer meios para operá-lo. E o 386 faz isso, desde que esteja rodando no "modo protegido". Porque, por questões de compatibilidade com as CPU anteriores da Intel, quando um 386 é ligado, entra em funcionamento no "modo real", no qual simula um mísero 8086 (o "pai" do 8088), com todas as suas limitações. Mas, com uma mera instrução, pode passar imediatamente para o modo protegido e abrir as portas do paraíso da multitarefa. Mais ou menos como o Clark Kent que, quando encontra uma cabina telefônica, vira sem mais nem menos o Super Homem...

Puxa, esse negócio está ficando como a espada de Afonso Henriques: comprido e chato. Mas tenha paciência que, agora, falta pouco. E vamos ao modo 86 virtual...

B. Piropo