Đó là (một phần) vai trò của BIOS.
Hệ thống đầu ra đầu vào cơ bản của máy tính chịu trách nhiệm cung cấp giao diện chung cho các hệ điều hành, mặc dù có sự khác biệt như vậy giữa các máy tính thực tế.
Điều đó nói rằng, đối với đồ họa cụ thể, có nhiều cách khác nhau để vẽ lên màn hình. Có các lệnh TTY mà bạn có thể gửi tới BIOS, nhưng đó chỉ ở chế độ thực. Nếu bạn muốn vẽ bất cứ thứ gì trong chế độ được bảo vệ, bạn cần sử dụng VGA để vẽ mọi thứ. Tôi không thể giải thích điều đó tốt hơn OSDev, vì vậy hãy xem ở đây để biết thêm thông tin - nhưng về cơ bản, bạn có thể ghi vào bộ nhớ (bộ nhớ video được ánh xạ bộ nhớ) bắt đầu từ địa chỉ 0xB8000
để vẽ mọi thứ trên màn hình.
Nếu bạn cần độ phân giải cao hơn VGA, bạn cần sử dụng các phần mở rộng BIOS VESA; Tôi không quen với nó, nhưng hãy thử xem mã nguồn GRUB để biết thêm thông tin.
Một số tài liệu tham khảo hữu ích:
Nếu bạn tình cờ quen thuộc với D - Tôi đã viết một bộ tải khởi động nhỏ một lúc trước có thể ghi vào màn hình (chỉ văn bản). Nếu bạn quan tâm, đây là mã:
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);
}