xv6の動作検証を行っている最中に、VGAの制御を行っている場所を見付けた。console.cでは、UARTの操作をしているだけだなく、VGAディスプレイに表示する機能もサポートしている。
void consputc(int c) { if(c == BACKSPACE){ uartputc('\b'); uartputc(' '); uartputc('\b'); } else uartputc(c); cgaputc(c); }
consputc()はコンソール(UART)への出力だけでなく、VGAディスプレイへの表示もサポートしている。
static void cgaputc(int c) { int pos; // Cursor position: col + 80*row. outb(CRTPORT, 14); pos = inb(CRTPORT+1) << 8; outb(CRTPORT, 15); pos |= inb(CRTPORT+1); ...
cgaputc()だが、x86のBIOSへアクセスしてCRTポートを制御し、カーソルを移動して文字を出力する、という具合だ。
まず、CRTの制御関連は0x3d4, 0x3d5などにまとめられているらしい。
CRTポートのインデックス14にアクセスすることで現在のカーソルの場所の上位8ビットにあたる場所を取得し、インデックス15にアクセスすることで下位8ビットにあたる場所を探している。
inb(CRTPORT+1,14) << 8 | inb(CRTPORT+1,15)
そしてカーソル位置を一つすすめ、CGAメモリに文字を書き出している。
outb(CRTPORT, 14); outb(CRTPORT+1, pos>>8); outb(CRTPORT, 15); outb(CRTPORT+1, pos); crt[pos] = ' ' | 0x0700;
CGAモジュールのISSへの実装
とりあえず適当にメモリマップを決めて、実装してみた。
const Addr_t crt_start = 0xffffffffffff4000; const Addr_t crt_end = 0xffffffffffff7fff; const Addr_t uart_start = 0xffffffffffff8000; const Addr_t uart_end = 0xffffffffffffffff; const Addr_t ide_start = 0xffffffffffff0000; const Addr_t ide_end = 0xffffffffffff3fff; ... if (addr >= ide_start && addr <= ide_end) { internal_addr = addr - ide_start; result = m_ide->LoadData (internal_addr, size, &w_data); *data = static_cast<Word_t>(w_data); } else if (addr >= crt_start && addr <= crt_end) { internal_addr = addr - crt_start; result = m_crt->LoadData (internal_addr, size, &w_data); *data = static_cast<Word_t>(w_data); } else if (addr >= uart_start && addr <= uart_end) { internal_addr = addr - uart_start; result = m_uart->LoadData (internal_addr, size, &w_data); *data = static_cast<Word_t>(w_data); } else { result = LoadFromBus (addr, size, byte); memcpy (data, byte, 8); }
当該アドレス領域にアクセスすると、CRTモジュールにアクセスすることになる。 一応、実行してみるとログは出るが、ちゃんとしたログにするにはまだ先だな。
<CRT: Load (000003d5) 13559843:M:MBar:[80100474][P80100474] 0007c783 : lbu tp,0x000(tp) tp=>ffff43d5 (00000000000003d5)=>00000000 tp<=00000000 13559844:M:MBar:[80100478][P80100478] fef407a3 : sb tp,0xfef(s6) s6=>8010e0c0 tp=>00000000 (8010e0af)<=00000000 13559845:M:MBar:[8010047c][P8010047c] fef44783 : lbu tp,0xfef(s6) s6=>8010e0c0 (000000008010e0af)=>11700000 tp<=00000000 13559846:M:MBar:[80100480][P80100480] 00078513 : addi s8,tp,0x000 tp=>00000000 s8<=00000000