Escolar Documentos
Profissional Documentos
Cultura Documentos
Construir Um Boot Loader
Construir Um Boot Loader
Pode parecer fora de moda esse assunto (coisa de velho que, segundo um jovem
arrogante, só servem para atrasar o emprego de tecnologia – ouvi isso
recentemente e confesso que não me desceu a garganta ainda, dada a arrogância
com que esse “postulado” foi anunciado em uma reunião de revisão), mas existem
aplicações, principalmente relacionadas aos cenários de IoT onde é desejável
incorporar um sistema operacional altamente especializado onde ter capacidades
de habilitar uma CPU no acesso e controle de seus periféricos é necessário em
diversas aplicações. A pretensão desse ensaio é justamente abordar com algum
detalhe como possível construir um bootloader. Por defi nição do Wikipedia o
bootloader, ou gerenciador de boot, é um programa simples com a função de
acessar o disco do computador e carregar o sistema operacional na memória para
assumir o controle do equipamento. Ele pode ser apenas um único programa ou
múlti plos encadeados, desde que um deles execute o carregamento do sistema
operacional.
Considerações iniciais
O boot loader ou bootloader, como é referenciado por alguns autores, é um programa situado no
primeiro setor do disco rígido; e é o setor de onde a inicialização começa. A BIOS lê automaticamente
todo o conteúdo do primeiro setor na memória logo após a alimentação ser ligada. O primeiro setor
também é chamado de Master Boot Record. Na verdade, não é obrigatório que o primeiro setor do
disco rígido inicialize alguma coisa. Esse nome foi formado historicamente porque os desenvolvedores
costumavam inicializar seus sistemas operacionais com esse mecanismo.
Neste ensaio, a principal linguagens de desenvolvimento são C ++. Mas conhecimento da linguagem C,
será útil para interpretar os elementos C ++ necessários. Em geral, mesmo o conhecimento C será
suficiente para modificar o código fonte dos exemplos descritos nesse ensaio. Conhecimentos sobre
Java ou C #, infelizmente, não ajudarão na tarefa. O problema é que o código das linguagens Java e C #
que é produzido após a compilação é intermediário (byte code e MSIL respectivamente). Uma máquina
virtual especial é usada para processá-la (Java Virtual Machine para Java e CLR - common language
runtime para .NET para C # ) que transforma o código intermediário em instruções do processador. Após
essa transformação, ele pode ser executado. Essa arquitetura torna impossível o uso de tecnologia de
código misto. Portanto, para desenvolver o bootloader simples, será preciso conhecer C ou C ++ e algo
sobre o Assembler - linguagem na qual todo o código de alto nível é transformado após a compilação.
Para usar a tecnologia de código misto, você precisa de pelo menos dois compiladores: para Assembler e
C / C ++, e também o linker para associar arquivos de objeto (.obj) ao executável. Agora vamos falar
sobre alguns momentos especiais. Existem dois modos de funcionamento do processador: modo real e
modo protegido. O modo real é de 16 bits e possui algumas limitações. O modo protegido é de 32 bits e
é totalmente usado no trabalho do SO. Quando inicia, o processador funciona no modo de 16 bits.
Portanto, para criar o programa e obter o arquivo executável, você precisará do compilador e vinculador
do Assembler para o modo de 16 bits. Para C / C ++, você precisará apenas do compilador que pode criar
arquivos de objeto para o modo de 16 bits. Os compiladores modernos são feitos apenas para
aplicativos de 32 bits, para que não possamos usá-los. Tentei vários compiladores gratuitos e comerciais
no modo de 16 bits e escolhi o produto da Microsoft. O compilador, juntamente com o linker para
Assembler, C, C ++, está incluído no pacote Microsoft Visual Studio 1.52 e também pode ser baixado do
site oficial da empresa. Alguns detalhes sobre os compiladores que precisamos são dados a seguir.
A próxima entidade - BootMain - é um análogo de main que, por sua vez, é a principal função em que
todo o funcionamento do programa está concentrado. As classes CDisplay e CString cuidam da parte
funcional do programa e mostram a mensagem na tela. Como você pode ver na figura 2, A classe
CDisplay usa CStringclass em seu trabalho.
Primeiro, devemos criar o projeto do tipo Makefile Project, onde o trabalho principal será executado.
int [number_of_interrupt];
Consideraremos apenas as interrupções e funções que serão usadas em nosso aplicativo exemplo.
Precisaremos:
int 10h, function 00h – realiza mudança do modo de video e limpa a tela;
int 10h, function 01h – ajusta o tipo do cursor;
int 10h, function 13h – exibe a string na tela;
Codificando
O compilador para C ++ suporta o Assembler embutido, ou seja, ao escrever código em linguagem de
alto nível, você também pode usar linguagem de baixo nível. As instruções do Assembler usadas no
código de alto nível também são chamadas de inserções asm. Eles consistem na palavra-chave __asm e
no bloco das instruções do Assembler entre chaves:
Para demonstrar o código misto, vamos usar o código Assembler mencionado anteriormente que
executou a limpeza da tela e combiná-lo com o código C ++.
void ClearScreen()
{
__asm
{
mov al, 02h ; ajusta o modo gráfico para 80x25(texto)
mov ah, 00h ; Código da função de mudança do modo de vídeo
int 10h ; chama a interrupção
}
}
#ifndef __CSTRING__
#define __CSTRING__
#include "Types.h"
class CString
{
public:
static byte Strlen(
const char far* inStrSource
);
};
#endif // __CSTRING__
// CString.cpp
#include "CString.h"
byte CString::Strlen(
const char far* inStrSource
)
{
byte lenghtOfString = 0;
while(*inStrSource++ != '\0')
{
++lenghtOfString;
}
return lenghtOfString;
}
Implementando o Display
A classe CDisplay foi projetada para o trabalho com a tela. Inclui os seguintes métodos:
#ifndef __CDISPLAY__
#define __CDISPLAY__
//
// cores para a func TextOut
//
#define BLACK 0x0
#define BLUE 0x1
#define GREEN 0x2
#define CYAN 0x3
#define RED 0x4
#define MAGENTA 0x5
#define BROWN 0x6
#define GREY 0x7
#define DARK_GREY 0x8
#define LIGHT_BLUE 0x9
#define LIGHT_GREEN 0xA
#define LIGHT_CYAN 0xB
#define LIGHT_RED 0xC
#define LIGHT_MAGENTA 0xD
#define LIGHT_BROWN 0xE
#define WHITE 0xF
#include "Types.h"
#include "CString.h"
class CDisplay
{
public:
static void ClearScreen();
#endif // __CDISPLAY__
// CDisplay.cpp
#include "CDisplay.h"
void CDisplay::TextOut(
const char far* inStrSource,
byte inX,
byte inY,
byte inBackgroundColor,
byte inTextColor,
bool inUpdateCursor
)
{
byte textAttribute = ((inTextColor) | (inBackgroundColor << 4));
byte lengthOfString = CString::Strlen(inStrSource);
__asm
{
push bp
mov al, inUpdateCursor
xor bh, bh
mov bl, textAttribute
xor cx, cx
mov cl, lengthOfString
mov dh, inY
mov dl, inX
mov es, word ptr[inStrSource + 2]
mov bp, word ptr[inStrSource]
mov ah, 13h
int 10h
pop bp
}
}
void CDisplay::ClearScreen()
{
__asm
{
mov al, 02h
mov ah, 00h
int 10h
}
}
void CDisplay::ShowCursor(
bool inMode
)
{
byte flag = inMode ? 0 : 0x32;
__asm
{
mov ch, flag
mov cl, 0Ah
mov ah, 01h
int 10h
}
}
Types.h é o arquivo de cabeçalho que inclui definições dos tipos de dados e macros.
// Types.h
#ifndef __TYPES__
#define __TYPES__
#endif // __TYPES__
BootMain () é a principal função do programa que é o primeiro ponto de entrada (análogo de main ()).
O processamento principal é realizado aqui.
// BootMain.cpp
#include "CDisplay.h"
CDisplay::TextOut(
HELLO_STR,
0,
0,
BLACK,
WHITE,
false
);
return;
}