C'est (en partie) le rôle du BIOS.
Le système de base des entrées-sorties de l'ordinateur est chargé de fournir une interface commune aux systèmes d'exploitation, malgré les différences existant entre les ordinateurs.
Cela dit, pour les graphiques en particulier, il existe différentes manières de dessiner à l'écran. Il existe des commandes TTY que vous pouvez envoyer au BIOS, mais ce n'est qu'en mode réel. Si vous voulez dessiner quelque chose en mode protégé, vous devez utiliser VGA pour dessiner des choses. Je ne peux pas l'expliquer mieux que OSDev, alors regardez ici pour plus d'informations - mais en gros, vous pouvez écrire dans la mémoire (la mémoire vidéo est mappée en mémoire) en partant de l'adresse 0xB8000
pour dessiner des éléments à l'écran.
Si vous avez besoin d'une résolution supérieure à celle du VGA, vous devez utiliser les extensions du BIOS VESA. Je ne le connais pas bien, mais essayez de regarder le code source de GRUB pour plus d'informations.
Quelques références utiles:
Si vous connaissez bien D - j’ai écrit il ya quelque temps un petit chargeur de démarrage capable d’écrire à l’écran (texte uniquement). Si cela vous intéresse, voici le code:
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 = '\0', 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);
}