Eu sei que o BIOS carrega sua primeira instrução de 0xFFFFFFF0, mas por que esse endereço específico? Tenho várias perguntas e espero que você possa me ajudar com algumas delas, pelo menos.
Minhas perguntas:
- Por que a primeira instrução do BIOS está localizada na "parte superior" de uma RAM de 4 GB?
- O que aconteceria se meu computador tivesse apenas 1 GB de RAM?
- E os sistemas com mais de 4 GB de RAM (por exemplo, 8 GB, 16 GB, etc.)?
- Por que a pilha é inicializada com algum valor (nesse caso, um valor localizado em 0xFFFFFFF0)?
Eu li sobre isso esta tarde e ainda não entendi.
Respostas:
0xFFFFFFF0
é onde uma CPU compatível com x86 começa a executar instruções quando é ligada. Esse é um aspecto rígido e imutável (sem hardware extra) da CPU e diferentes tipos de CPUs se comportam de maneira diferente.Ele está localizado na "parte superior" do espaço de endereço de 4 GB - e, na inicialização, o BIOS ou a UEFI ROM está configurado para responder às leituras desses endereços.
Minha teoria sobre por que isso é:
Quase tudo na programação funciona melhor com endereços contíguos. O projetista da CPU não sabe o que um construtor de sistema deseja fazer com a CPU; portanto, é uma má idéia para a CPU exigir que endereços smack no meio do espaço sejam necessários para vários propósitos. É melhor manter isso "fora do caminho" na parte superior ou inferior do espaço de endereço. Obviamente, lembre-se de que essa decisão foi tomada quando o 8086 era novo, que não possuía um MMU .
No 8086, vetores de interrupção existiam no local de memória 0 e acima. Os vetores de interrupção precisam estar em endereços conhecidos e se deseja estar na RAM para flexibilidade - ainda não foi possível ao projetista da CPU saber quanto RAM haveria em um sistema. Portanto, começar do zero e fazer o trabalho fazia sentido para eles (porque nenhum sistema em 1978, quando o 8086 foi inventado, teria 4 Gbytes de RAM - esperar que a RAM estivesse em 0xFFFFFFF0 não era uma boa ideia) e a ROM teria que ser no limite superior.
Obviamente, começando com pelo menos o 80286, os vetores de interrupção podem ser movidos para um local de partida diferente de 0, mas as modernas CPUs x86 de 64 bits ainda são inicializadas no modo 8086, para que tudo ainda funcione da maneira antiga para compatibilidade (tão ridículo quanto como parece em 2015 ainda precisar da sua CPU x86 para poder executar o DOS).
Portanto, como os vetores de interrupção começam de 0 e funcionam para cima, a ROM precisaria começar de cima e trabalhar para baixo.
Uma CPU de 32 bits possui 4.294.967.296 endereços, numerados de 0 (0x00000000) a 4294967295 (0xFFFFFFFF). A ROM pode residir em alguns endereços e a RAM pode residir em outros. Com o MMU da CPU, isso pode ser alternado em tempo real. A RAM não precisa viver em todos os endereços.
Com apenas 1 GB de RAM, alguns endereços não respondem nada quando são lidos ou gravados. Isso pode fazer com que dados inválidos sejam lidos quando esses endereços são acessados ou um bloqueio do sistema.
Mantendo-o um pouco simples: as CPUs de 64 bits têm mais endereços (que é uma das coisas que as tornam em 64 bits - por exemplo, 0x0000000000000000 a 0xFFFFFFFFFFFFFFFFFF), por exemplo, para que a RAM extra "caiba". Supondo que a CPU esteja no modo longo . Até então, a RAM está lá, apenas não endereçável.
Não consigo encontrar imediatamente nada sobre o que o x86 atribui ao ponteiro da pilha na inicialização, mas acabaria tendo que ser reatribuído por uma rotina de inicialização de qualquer maneira, uma vez que essa rotina descubra quanto RAM há no sistema. (@Eric Towers nos comentários abaixo relata que está definido como zero na inicialização.)
fonte
0xFFFFFFF0
não está acessível até que a CPU tenha sido alterada para o modo de 32 bits. A última vez que examinei atentamente o código do BIOS, o ponto de entrada estava em0xFFFF0
.0xFFFF0
, mas, na realidade, ele mapeia0xFFFFFFF0
. Espero que isso tenha sido feito para compatibilidade com o 8086 - tanto ele quanto as CPUs mais modernas parecem usar0xFFFF0
, mas as CPUs de 32 bits realmente acessam0xFFFFFFF0
(mapeadas para a BIOS ROM).Não está localizado na parte superior da RAM; Ele está localizado na ROM, cujo endereço está no topo do espaço de endereço da memória, junto com qualquer memória nas placas de expansão, como os controladores Ethernet. Está lá para que não entre em conflito com a RAM, pelo menos até que você tenha 4 GB instalados. Os sistemas com 4 GB ou mais de RAM podem fazer duas coisas para resolver o conflito. Placas-mãe baratas simplesmente ignoram as partes da RAM que conflitam com a localização da ROM. Os decentes remapearão a RAM para que pareçam ter um endereço acima da marca de 4 GB.
Não tenho certeza do que você está perguntando sobre a pilha. Certamente não foi inicializado para estar em ROM. Quando a CPU é redefinida, ela está inicialmente no "modo real", onde atua exatamente como o 8086 original e usa endereçamento segmentado de 16 bits, permitindo acessar apenas 1 MB de memória. O código do BIOS está localizado na parte superior desse 1 MB. O BIOS escolhe em algum lugar na RAM para configurar a pilha, carregar e executar o primeiro setor da primeira unidade inicializável. Cabe ao sistema operacional alternar para o modo de 32 ou 64 bits, uma vez que assume e configura suas próprias pilhas (uma por tarefa / encadeamento).
fonte
Primeiro, isso não tem nada a ver com RAM, realmente. Estamos falando de espaço de endereço aqui - mesmo se você tiver apenas 16 MiB de memória, ainda terá 32 bits de espaço de endereço em uma CPU de 32 bits.
Isso já responde à sua primeira pergunta, realmente - no momento em que foi projetada, os PCs do mundo real não tinham nem perto dos 4 GiB de memória completos; eles estavam mais na faixa de 1 a 16 MiB de memória. O espaço de endereço era, para todos os efeitos, gratuito.
Agora, por que exatamente 0xFFFFFFF0? A CPU não sabe quanto do BIOS existe. Alguns BIOS podem levar apenas alguns kilobytes, enquanto outros podem ocupar megabytes completos de memória - e eu nem estou entrando nas várias RAMs opcionais. A CPU deve estar conectada a algum endereço para iniciar - não há nada para configurar a CPU. Mas este é apenas um mapeamento do espaço de endereço - o endereço é mapeado diretamente no chip da ROM do BIOS (sim, isso significa que você não terá acesso aos 4 GiB de RAM completos neste momento, se você tiver muitos - mas isso não é nada de especial, muitos dispositivos exigem seu próprio intervalo no espaço de endereço). Em uma CPU de 32 bits, esse endereço fornece 16 bytes completos para a inicialização básica - o que é suficiente para configurar seus segmentos e, se necessário, o modo de endereço (lembre-se,"procedimento" de inicialização real . Neste ponto, você não usa RAM - tudo é apenas ROM mapeada. De fato, a RAM ainda não está pronta para ser usada neste momento - esse é um dos trabalhos do BIOS POST! Agora, você pode estar pensando - como um modo real de 16 bits acessa o endereço 0xFFFFFFF0? Claro, existem segmentos, então você tem espaço de endereço de 20 bits, mas isso ainda não é bom o suficiente. Bem, há um truque: os 12 bits altos do endereço são definidos até você executar seu primeiro salto em distância, fornecendo acesso ao espaço de endereços alto (enquanto rejeita o acesso a algo menor que 0xFFF00000 - até você executar um salto em comprimento) .
Tudo isso é oculto principalmente pelos programadores (para não mencionar os usuários) nos sistemas operacionais modernos. Você geralmente não tem acesso a nada tão baixo nível - algumas coisas já estão além do salvamento (você não pode alternar os modos da CPU à toa ou à toa), outras são tratadas exclusivamente pelo kernel do sistema operacional.
Portanto, uma visão mais agradável vem da codificação da velha escola no MS DOS. Outro exemplo típico de memória do dispositivo sendo mapeada diretamente para o espaço de endereçamento é o acesso direto à memória de vídeo. Por exemplo, se você deseja escrever texto rapidamente no visor, você escreveu diretamente no endereço
B800:0000
(mais deslocamento - no modo de texto 80x25, isso significa que(y * 80 + x) * 2
se minha memória me servir corretamente - dois bytes por caractere, linha por linha). Se você queria desenhar pixel por pixel, utilizava o modo gráfico e o endereço inicial deA000:0000
(normalmente, 320x200 a 8 bits por pixel). Fazer algo de alto desempenho geralmente significava mergulhar nos manuais do dispositivo, para descobrir como acessá-los diretamente.Isso sobrevive até hoje - está apenas oculto. No Windows, você pode ver os endereços de memória mapeados para dispositivos no Gerenciador de dispositivos - basta abrir propriedades de algo como sua placa de rede, vá para a guia Recursos - todos os itens do intervalo de memória são mapeamentos da memória do dispositivo para o seu espaço de endereço principal. E em 32 bits, você verá que a maioria desses dispositivos está mapeada acima da marca 2 GiB (mais tarde 3 GiB) - novamente, para minimizar conflitos com a memória utilizável pelo usuário, embora isso não seja realmente um problema com a memória virtual ( os aplicativos não chegam nem perto do espaço real de endereço de hardware - eles têm seu próprio pedaço de memória virtualizado, que pode ser mapeado para RAM, ROM, dispositivos ou arquivo de paginação, por exemplo).
Quanto à pilha, bem, deve ajudar a entender que, por padrão, a pilha cresce a partir do topo. Portanto, se você fizer um
push
, o novo ponteiro da pilha estará em0xFFFFFEC
- em outras palavras, você não está tentando gravar no endereço de inicialização do BIOS :) O que obviamente significa que as rotinas de inicialização do BIOS podem usar a pilha com segurança antes de remapear novamente em algum lugar mais útil. Na programação da velha escola, antes que a paginação se tornasse o padrão de fato, a pilha geralmente era iniciada no final da RAM e o "estouro de pilha" acontecia quando você começava a substituir a memória do aplicativo. A proteção de memória mudou muito disso, mas, em geral, mantém a compatibilidade com versões anteriores o máximo possível - observe como até a mais moderna CPU x86-64 ainda pode inicializar o MS DOS 5 - ou como o Windows ainda pode executar muitos aplicativos DOS que não têm idéia sobre paginação.fonte
0xFFFFFFEC
seria mapeado). Isso significa não apenas não,push
mas, por exemplo,call
também não . Eles devem esperar até que a RAM esteja pronta.Além de outros pontos mencionados, pode ser útil para entender o que um endereço é . Enquanto arquiteturas mais recentes complicam as coisas, historicamente uma máquina produzia em cada ciclo de memória o endereço desejado em 20 a 32 fios (dependendo da arquitetura, com alguns truques especiais para observar se era necessário um par ou um quarteto de bytes simultaneamente); várias partes do sistema de memória examinavam o estado desses fios e se ativavam quando viam certas combinações de valores altos e baixos.
Se uma máquina com 32 fios de endereço precisar apenas usar 1 MB de RAM e 64 KB de ROM [bastante plausível para alguns controladores incorporados], poderá ativar a RAM para todos os endereços em que o fio de endereço superior estava baixo e a ROM para todos os endereços em que estava. Alto. Os 20 fios inferiores do endereço seriam amarrados à RAM para selecionar um dos 1.048.576 bytes e os 16 inferiores também seriam conectados à ROM, para selecionar um dos 65.536 bytes. Os 11 fios restantes do endereço simplesmente não seriam conectados a nada.
Nessa máquina, os acessos aos endereços 0x00100000-0x001FFFFF seriam equivalentes aos acessos aos endereços RAM 0x00000000-0x000FFFFF. Da mesma forma com os endereços 0x000200000-0x0002FFFFF ou 0x7FF00000-0x7FFFFFFFF. Os endereços acima de 0x80000000 liam ROM, com um padrão de 64K repetindo-se por todo o espaço.
Embora o processador possua um espaço de endereço de 4.294.967.296 bytes, não é necessário que o hardware reconheça muitos endereços distintos. Colocar o vetor de redefinição próximo à parte superior do espaço de endereço é um design que funcionará bem, independentemente da quantidade ou quantidade de RAM e ROM que o sistema possui e evita a necessidade de decodificar completamente o espaço de endereço.
fonte
Minha teoria é que, porque estamos usando lógica negativa, a digital (1) não possui tensão (O volts). Só precisamos colocar tensão nos últimos 4 bits na inicialização para que o contador de programa (ou ponteiro de instrução) atinja 1111 1111 1111 1111 1111 1111 1111 0000. Não precisamos endereçar os 28 bits superiores, já que a maioria dos CPUs (antigos) era de 16 bits e os nibbles inferiores podem ser endereçados por um único chip de endereço nos velhos tempos. Agora, como temos 64 bits com compatibilidade de 32 bits e 32 a 16 bits, o campo de hardware foi aprimorado, mas o método permanece. Além disso, os bioses nem sempre são programados em 64 ou 32 bits. Minha opinião também é que as memórias nem sempre são as mesmas, o BIOS deve estar localizado no mesmo primeiro segmento. A maneira como vemos as biografias endereçadas não é o endereço real o tempo todo. Apenas um ensinou de mim ...
fonte
em RESET, um processador compatível com 8088/8086 executa as instruções em 0FFFF0, 16 bytes abaixo do limite de 1 megabyte. normalmente a ROM neste local (em implementações de PC) seria o BIOS; portanto, no final da ROM do BIOS, há um salto para o início da ROM do BIOS.
mostrado aqui: vetor inicial e assinatura de 'data' por trás dele, data do BIOS do IBM 5150 PC 8KB eprom dump: 19/10/1981
observe que o endereçamento é de uma ROM de 8KB $ 2000, que coloca o endereço inicial (o JMP distante absoluto, em qualquer outro local, nesse caso, dentro da própria ROM de 8KB, embora não seja o endereço mais baixo possível nessa ROM) em $ FFFF: $ 0 segmentado ou $ FFFF0 linear.
quanto à compatibilidade: se algum processador 'futuro' ou atual 'espera' que ele tenha muito mais Fs na frente do endereço, isso não importa. para compatibilidade de cpus mais recentes em sistemas mais antigos, as linhas de endereço adicionais permanecem desconectadas e, portanto, os dados no databus são exatamente os mesmos. desde que os bits menos significativos permaneçam em FFFF0.
(em um sistema com apenas 1 MB de RAM e a ROM posicionada no final desse RAM, e mais nada, ele pensará 'feliz' que está falando com o endereço mais alto e ainda obterá exatamente os mesmos dados, porque essas implementações nunca ouviram falar linhas de endereço maiores que A19)
observe que o mundo não é apenas 'pcs' ... o ibm pc foi um 'acidente', esses processadores nunca foram projetados especificamente para 'pcs' e envolvem muito mais coisas do que apenas pcs (como satélites, sistemas de armas, etc). Os modos protegido de 32 e 64 bits geralmente não são desejados. (o modo 8086 virtual é muito mais interessante, como um motivo para escolher uma versão mais recente (386 ou mais), por exemplo). portanto, há muito mais na 'compatibilidade com versões anteriores' do que apenas 'será executado'.
fonte
A placa-mãe garante que a instrução no vetor de redefinição seja um salto para o local da memória mapeado para o ponto de entrada do BIOS. Esse salto limpa implicitamente o endereço de base oculto presente na inicialização. Todos esses locais de memória têm o conteúdo certo necessário para a CPU, graças ao mapa de memória mantido pelo chipset. Todos eles são mapeados para a memória flash que contém o BIOS, pois, nesse ponto, os módulos de RAM possuem uma porcaria aleatória.
fonte