这(部分)是BIOS的角色。
尽管实际计算机之间存在差异,但计算机的基本输入输出系统仍负责为操作系统提供通用接口。
也就是说,特别是对于图形,有多种绘制屏幕的方法。您可以发送一些TTY命令到BIOS,但这只是在实模式下。如果要在保护模式下绘制任何内容,则需要使用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);
}