Das ist (teilweise) die Rolle des BIOS.
Das Basic Input Output System des Computers ist dafür verantwortlich, trotz solcher Unterschiede zwischen den tatsächlichen Computern eine gemeinsame Schnittstelle zu Betriebssystemen bereitzustellen.
Das heißt, für Grafiken gibt es verschiedene Möglichkeiten, auf dem Bildschirm zu zeichnen. Es gibt TTY-Befehle, die Sie an das BIOS senden können, aber das ist nur im Real-Modus. Wenn Sie etwas im geschützten Modus zeichnen möchten, müssen Sie VGA zum Zeichnen verwenden. Ich kann es nicht besser erklären als OSDev, also schau hier nach mehr Informationen - aber grundsätzlich kannst du in den Speicher schreiben (der Videospeicher ist speicherabgebildet), beginnend mit der Adresse, 0xB8000
um Dinge auf dem Bildschirm zu zeichnen.
Wenn Sie eine höhere Auflösung als VGA benötigen, müssen Sie die VESA-BIOS-Erweiterungen verwenden. Ich bin damit nicht vertraut, aber versuche, im GRUB-Quellcode weitere Informationen zu finden.
Einige nützliche Hinweise:
Wenn Sie mit D vertraut sind, habe ich vor einiger Zeit einen kleinen Bootloader geschrieben, der in der Lage war, auf den Bildschirm zu schreiben (nur Text). Wenn Sie interessiert sind, ist hier der 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);
}