それが(部分的に)BIOSの役割です。
コンピューターの基本入出力システムは、実際のコンピューター間のこのような違いにもかかわらず、オペレーティングシステムに共通のインターフェイスを提供する役割を果たします。
とはいえ、特にグラフィックスについては、画面に描画するさまざまな方法があります。BIOSに送信できるTTYコマンドがありますが、それはリアルモードのみです。プロテクトモードで何かを描画する場合は、VGAを使用して描画する必要があります。OSDevよりもうまく説明できないので、ここで詳細を探してください。しかし、基本的には、アドレス0xB8000
に始まるメモリに書き込み(ビデオメモリはメモリマップ)して、画面に描画することができます。
VGAよりも高い解像度が必要な場合は、VESA BIOS拡張機能を使用する必要があります。私はそれに詳しくはありませんが、詳細についてはGRUBソースコードを見てみてください。
便利なリファレンス:
あなたがたまたまDに精通しているなら-私はしばらく前に小さなブートローダーを書いたが、それは画面に書き込むことができた(テキストのみ)。興味のある方は、次のコードをご覧ください。
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);
}