Isso é (parcialmente) o papel do BIOS.
O Basic Input Output System do computador é responsável por fornecer uma interface comum aos sistemas operacionais, apesar dessas diferenças entre computadores reais.
Dito isso, especificamente para gráficos, existem diferentes maneiras de desenhar na tela. Existem comandos TTY que você pode enviar para o BIOS, mas isso é apenas no modo real. Se você quiser desenhar qualquer coisa no modo protegido, você precisará usar o VGA para desenhar coisas. Eu não posso explicar melhor do que o OSDev, então olhe aqui para mais informações - mas, basicamente, você pode escrever na memória (vídeo memória é mapeada na memória) começando no endereço 0xB8000
para desenhar coisas na tela.
Se você precisar de uma resolução maior que a VGA, você precisará usar as extensões de BIOS do VESA; Eu não estou familiarizado com isso, mas tente ver o código-fonte do GRUB para mais informações.
Algumas referências úteis:
-
código-fonte do GRUB :
grub-core/video/i386/pc/vbe.c grub-core/video/i386/pc/vga.c
Se você estiver familiarizado com D - eu escrevi um pequeno gerenciador de inicialização um tempo atrás que foi capaz de escrever na tela (somente texto). Se você estiver interessado, aqui está o código:
align(2) struct Cell { char ch; ubyte flags = 0x07; }
@property Cell[] vram()
{ return (cast(Cell*)0xB8000)[0 .. CONSOLE_WIDTH * CONSOLE_HEIGHT]; }
void putc(char c)
{
if (isBochs) { _outp(0xE9, c); } // Output to the Bochs terminal!
bool isNewline = c == '\n';
while (cursorPos + (isNewline ? 0 : 1) > vram.length)
{
for (short column = CONSOLE_WIDTH - 1; column >= 0; column--)
{
foreach (row; 0 .. CONSOLE_HEIGHT - 1)
{
uint cell = column + cast(uint)row * CONSOLE_WIDTH;
vram[cell] = vram[cell + CONSOLE_WIDTH];
}
vram[column + (CONSOLE_HEIGHT - 1) * CONSOLE_WIDTH].ch = ' ';
}
cursorPos = cast(ushort)(cursorPos - CONSOLE_WIDTH);
}
if (isNewline)
cursorPos = cast(ushort)
((1 + cursorPos / CONSOLE_WIDTH) * CONSOLE_WIDTH);
else vram[cursorPos++].ch = c;
}
void putc(char c, ubyte attrib) { vram[cursorPos] = Cell(c, attrib); }
void memdump(void* pMem, size_t length)
{
foreach (i; 0 .. length)
putc((cast(char*)pMem)[i]);
}
void clear(char clear_to = 'grub-core/video/i386/pc/vbe.c
grub-core/video/i386/pc/vga.c
', ubyte attrib = DEFAULT_ATTRIBUTES)
{
foreach (pos; 0 .. vram.length)
vram[pos] = Cell(clear_to, attrib);
cursorPos = 0;
}
@property ushort cursorPos()
{
ushort result = 0;
_outp(0x3D4, 14);
result += _inp(0x3D5) << 8;
_outp(0x3D4, 15);
result += _inp(0x3D5);
return result;
}
@property void cursorPos(ushort position)
{
_outp(0x3D4, 14);
_outp(0x3D5, (position >> 8) & 0xFF);
_outp(0x3D4, 15);
_outp(0x3D5, position & 0xFF);
}