advance/QEMUVGA
の編集
http://hrb.osask.jp/wiki/?advance/QEMUVGA
[
リロード
|
差分
|
単語検索
|
一覧
] [
編集
|
バックアップ
|
添付
]
-- 雛形とするページ --
A
Akkie
Athlon64X2
Clover
DAsoran
Falcon
FormatRule
FrontPage
Genesis
Help
I
InterWikiName
InterWikiSandBox
InterWikiテクニカル
Jormungand
K
Kebo
Kor_Lee_Hee_Rak
Leaf
Linux
Linux/wako_memo
MOIZ99
MW
MenuBar
OSC
PG_MANA
ReadersOS
RecentDeleted
SKYDASH
SandBox
Sero
Sigle
Source
Triangle_Ld.
Zxcvbnm
advance
advance/CPU
advance/FDC
advance/FPU
advance/NotHariMain
advance/QEMUVGA
advance/RTC
advance/blike
advance/cpu_reset
advance/driver
advance/driver/01
advance/driver/02
advance/families
advance/filesystem
advance/fwrite
advance/hddboot
advance/he86
advance/hints
advance/ipl
advance/kernel
advance/keycode
advance/osselect
advance/smaller1
advance/startup
advnace/smaller2
anzy
aotatsu
banbi-
bluedwarf
bo
bugs
challengers
cybozulabsyouth11
deskmanta
esb02b
faq
faq/advance
faq/asm
faq/c00-03
faq/c04-07
faq/c08-15
faq/c16-23
faq/c24-31
faq/make
faq/others
faq/qemu
guide
guide03
guide05
guide07
hikarupsp
imp_log/0000
imp_log/0001
imp_log/0002
imp_log/0003
impressions
index
k
killer_elf
kota
lea
lea/10_memory
lea/4_color
lea/idea
lea/terms
links
logs
logs/osa_hrb/comments0000
logs/osa_hrb/rumors0000
masa
members
message
mistakes
moge32
moppoi5168
notice
osdevjp
populars
prog_index
projects
q_and_a
q_and_a_2
qa_log/0000
qa_log/0001
qa_log/0002
qa_log/0003
qa_log/0004
qa_log/0005
qa_log/0006
qa_log/0007
qa_log/0008
qa_log/0009
quark
rankings
rule
sakamoto
sasaki
spc09
spcc_30min_os
tatsu
tools
tools/bim2hrb
tools/bin2obj
tools/cc1
tools/edimg
tools/gas2nask
tools/makefont
tools/nask
tools/obj2bim
tools/sjisconv
uchan
uho
updates
violations
wako
white
win64-bit
x
ytakano
ヘルプ
リックス
質問します
整形ルール
本は買ったぞ!持ってるぞ!
練習用ページ
* BIOSを使わないで画面モードを変更するぞ!(主にQEMU用) -(by [[K]], 2008.08.29) -発展課題のページ(全部読む前にここを読むのは混乱するのでおすすめじゃないです) *** まえがき -「はりぼてOS」では起動時に32bitモードになる前にBIOSを使って画面モードを設定していますが、これは本来は一般的な方法ではありません(個人が作るOSでは定番の方法ですが)。Windowsなどのビデオドライバは、IN命令やOUT命令を使って画面モードを切り替えています。 -そういうのって具体的にどうやっているの?と思うことがあるでしょう。それを説明しようと思います。ただこれはビデオチップ・ビデオカードごとにやり方が違うので、みんなが共通に実験できる例として、QEMUがエミュレーションしているビデオチップを題材にしようと思います。 --これは結局、BIOSが中でどんなことをやっているかを知ることにもなる。 -この方法で画面モードを切り替えるのなら、32bitモードのままでできるので、起動後でも何度でも好きなときに画面モードを変えられます(変えたいと思うかどうかは分からないけど)。 *** QEMUでの画面モード切替方法0(-stdvga編) -実はQEMUではエミュレーションするビデオカードを起動時に選ぶことができます。起動時に-stdvgaというオプションをつけると、QEMUより古いBochsというエミュレータと互換性のある(実在しない)ビデオカードをエミュレーションします。 --歴史的背景を説明すると、初期のQEMUとBochsではこのビデオカードしかサポートされていなかった。しかし、これだと既存のOSをエミュレーションするときに、Bochsのビデオカード用のデバイスドライバを用意しなければいけないため、エミュレーション可能なOSを一気に増やせなかった。そこで、QEMUの開発者(もしかしたらBochsの開発者かもしれない)はそこそこメジャーで実在する複雑なビデオカード(Cirrus Logic GD5446)もエミュレーションできるようして、既存のOSのエミュレーションをしたいときは、既存のデバイスドライバを選ぶだけでいいようにした(未確認だけど、最新のBochsにもCirrus Logic GD5446のエミュレーションモードがあるかも)。 --ちなみにBIOSから利用する限りにおいては、ビデオカードの仕様の複雑さはほとんど関係ない。画面モード設定の方法がややこしくても、それはBIOSが苦労するだけなので。 --新しいQEMUでは-std-vgaと書くようです。 -このカードは非常に単純で理解しやすいので、まずはこれを例に説明しようと思います。 -ただし一度でもこの方法で画面モードを設定してしまうと、BIOS内部が覚えている状態との食い違いが生じてしまうため、BIOSを通じての画面モード切替や文字表示などがうまくいかなくなることがあります(エミュレータを再起動すれば直ります)。 ---- -使用するI/Oポートは0x01ceと0x01cfだけです。0x01ceにレジスタ番号を入れて、0x01cfにデータを入れると、QEMUのビデオカードのレジスタにデータをセットできます。どちらのポートも16bitアクセスしなければいけないので、io_out16()関数を使います。 --レジスタ0x0001 : xの解像度(320, 640, 800, 1024 のどれか) --レジスタ0x0002 : yの解像度(200, 240, 400, 480, 600, 768 のどれか) ---レジスタ0x0001との組み合わせで適切なものを設定すること ---(でも変な組み合わせでも長細い画面でちゃんと設定どおりに動いちゃうんだけどね) --レジスタ0x0003 : 色のビット数(4, 8, 15, 16, 24, 32 のどれか) ---レジスタ0x0001〜0x0002との組み合わせで適切なものを設定すること --レジスタ0x0004 : 詳細設定 ---bit0 : 設定は有効 ---bit6 : リニアアクセスモード選択 ---bit7 : 画面モード切替時にVRAMをクリアしない(クリアしないメリット:切り替えが早く終わる) ---その他のビットの意味は不明。必ず0にしておくこと。 --レジスタ0x0005 : 用途がよく分からないが、0x0000を設定しておくようだ。・・・用途判明!バンクレジスタだった(後述) --レジスタ0x0006 : 以下では使っていないが、表示域よりも広い仮想画面をVRAM内に設定するときのためのxのピクセル数 --レジスタ0x0007 : 上記のyのピクセル数 --レジスタ0x0008 : 仮想画面を使っているときに、表示位置のx座標 --レジスタ0x0009 : 仮想画面を使っているときに、表示位置のy座標 ---- -例としてはできるだけ単純なほうがいいと思うので、4日目の最後から改造することにしましょう。つまりベースとなるのはharib02iです。まず、asmhead.nasの画面モード設定をコメントアウトしてしまいましょう。こんなものにはもう頼りませんよ。 ;; 画面モードを設定 ; ; MOV AL,0x13 ; VGAグラフィックス、320x200x8bitカラー ; MOV AH,0x00 ; INT 0x10 ; MOV BYTE [VMODE],8 ; 画面モードをメモする(C言語が参照する) ; MOV WORD [SCRNX],320 ; MOV WORD [SCRNY],200 ; MOV DWORD [VRAM],0x000a0000 -そしてbootpack.cに以下の記述を書き加えます。init_qemuvga0()での手順が、画面モード切り替えの設定方法です。 void io_out16(int port, int data); void set_qemuvga0reg(int reg, int dat) { io_out16(0x01ce, reg); io_out16(0x01cf, dat); return; } void init_qemuvga0(struct BOOTINFO *binfo, int x, int y, int c, int flag) { set_qemuvga0reg(0x0004, 0x0000); set_qemuvga0reg(0x0001, x); set_qemuvga0reg(0x0002, y); set_qemuvga0reg(0x0003, c); /* 4, 8, 15, 16, 24, 32 */ set_qemuvga0reg(0x0005, 0x0000); set_qemuvga0reg(0x0004, flag); /* リニアアクセスモードでVRAMの初期化をするなら0x41 */ /* bit7 : VRAM初期化抑制, bit6 : リニアアクセスモード, bit0 : 設定有効 */ binfo->scrnx = x; binfo->scrny = y; binfo->vmode = c; if ((flag & 0x40) == 0) { binfo->vram = (char *) 0x000a0000; } else { binfo->vram = (char *) 0xe0000000; } return; } -そんでもって、HariMain()のinit_screen8()の前に、1行書き足します。ここでは800x600の8bitカラーにしてみます。どうせこの直後に全画面描き換えるのでVRAMのクリアはしないことにしました。 void HariMain(void) { (中略) init_gdtidt(); init_palette(); init_qemuvga0(binfo, 800, 600, 8, 0xc1); /* ココ! */ init_screen8(binfo->vram, binfo->scrnx, binfo->scrny); (中略) } -これでできあがりです。さて実験・・・よしうまくいったぁ〜。 -本当にこれだけでうまくいくの?という人は是非自分でもやってみましょう。 ---- -とりあえず上記だけでたいていのことはできると思いますが、32bitモードに切り替えるのが面倒な場合(もしくは切り替えられない特別な事情がある場合)は、なんと1MBまでの番地内だけでも高解像度が使えます。この方法を使うことは多分ないと思いますが、筆者がせっかく調べたので一応まとめておきます。 -まず、画面モード切替だけならOUT命令だけでできるので、16bitモードのままで問題無しです。しかし上記のサンプルと同じ手順では少し問題があるので、以下の点を変えてください。画面モード設定の際に、「レジスタ0x0004 : 詳細設定」の「bit6 : リニアアクセスモード選択」をゼロにします。 -こうすることで、0xe0000000からの64KBの内容がそのまま0xa0000からの64KBで読み書きできるようになります。で、これだともちろん不十分です。だって256色の800x600とかに設定した場合はVRAMは全体で468KBを超えるわけで、そのうちの先頭の64KBしか使えないというのはいかにも困るわけです。 -ということで、他の部分を読み書きしたいときは、上記の「レジスタ0x0005 : バンクレジスタ」を使います。ここに1を書き込むと、0xa0000からの64KBの内容は、0xe0010000からの内容に瞬時に入れ替わります。2を書き込めば0xe0020000になります。こんな感じで、結局0xa0000〜0xaffffへ読み書きするだけで、VRAM全体を読み書きできるというわけです。 *** QEMUでもQEMU以外でも使える切替方法1(古いモード編) -本の中でよく使っている320x240x8bitのモードは、BIOSを使わずに設定することが可能です。VBEを使わなくても設定できる画面モードのうちメジャーなものは、実はほとんどのカードで設定方法が同じになっています。したがってこのセクションの方法は、QEMU以外のエミュレータでもうまくいくのはもちろんのこと、実機でもうまくいきます。QEMUでいえば、-stdvgaであってもなくてもうまくいきます。ただVBE以前のモードばかりなので高解像度や多色に対応できず、ややイマイチな感じではあります。 --ただし一度でもこの方法で画面モードを設定してしまうと、BIOS内部が覚えている状態との食い違いが生じてしまうため、BIOSを通じての画面モード切替や文字表示などがうまくいかなくなることがあります(もちろん再起動すれば直ります)。 - -stdvga以外のビデオカードの設定がどれほど面倒そうなのかの感じをつかんでほしくてこのセクションを作りました。 -すごく長くなりそうなので、別ページに作ります。 -(つづく) *** QEMUでの画面モード切替方法2(Cirrus Logic GD5446編) -(つづく:調査中) * こめんと欄 -もしかすると、この方法だとXen上で動くかもですね -- [[あっきぃ>Akkie]] SIZE(10){2008-09-12 (金) 02:16:21} -ほんとう?XenってQEMUの-std-vgaの互換モードってあるのかな?あったらビンゴだね! -- [[K]] SIZE(10){2008-12-17 (水) 22:14:58} #comment
タイムスタンプを変更しない
* BIOSを使わないで画面モードを変更するぞ!(主にQEMU用) -(by [[K]], 2008.08.29) -発展課題のページ(全部読む前にここを読むのは混乱するのでおすすめじゃないです) *** まえがき -「はりぼてOS」では起動時に32bitモードになる前にBIOSを使って画面モードを設定していますが、これは本来は一般的な方法ではありません(個人が作るOSでは定番の方法ですが)。Windowsなどのビデオドライバは、IN命令やOUT命令を使って画面モードを切り替えています。 -そういうのって具体的にどうやっているの?と思うことがあるでしょう。それを説明しようと思います。ただこれはビデオチップ・ビデオカードごとにやり方が違うので、みんなが共通に実験できる例として、QEMUがエミュレーションしているビデオチップを題材にしようと思います。 --これは結局、BIOSが中でどんなことをやっているかを知ることにもなる。 -この方法で画面モードを切り替えるのなら、32bitモードのままでできるので、起動後でも何度でも好きなときに画面モードを変えられます(変えたいと思うかどうかは分からないけど)。 *** QEMUでの画面モード切替方法0(-stdvga編) -実はQEMUではエミュレーションするビデオカードを起動時に選ぶことができます。起動時に-stdvgaというオプションをつけると、QEMUより古いBochsというエミュレータと互換性のある(実在しない)ビデオカードをエミュレーションします。 --歴史的背景を説明すると、初期のQEMUとBochsではこのビデオカードしかサポートされていなかった。しかし、これだと既存のOSをエミュレーションするときに、Bochsのビデオカード用のデバイスドライバを用意しなければいけないため、エミュレーション可能なOSを一気に増やせなかった。そこで、QEMUの開発者(もしかしたらBochsの開発者かもしれない)はそこそこメジャーで実在する複雑なビデオカード(Cirrus Logic GD5446)もエミュレーションできるようして、既存のOSのエミュレーションをしたいときは、既存のデバイスドライバを選ぶだけでいいようにした(未確認だけど、最新のBochsにもCirrus Logic GD5446のエミュレーションモードがあるかも)。 --ちなみにBIOSから利用する限りにおいては、ビデオカードの仕様の複雑さはほとんど関係ない。画面モード設定の方法がややこしくても、それはBIOSが苦労するだけなので。 --新しいQEMUでは-std-vgaと書くようです。 -このカードは非常に単純で理解しやすいので、まずはこれを例に説明しようと思います。 -ただし一度でもこの方法で画面モードを設定してしまうと、BIOS内部が覚えている状態との食い違いが生じてしまうため、BIOSを通じての画面モード切替や文字表示などがうまくいかなくなることがあります(エミュレータを再起動すれば直ります)。 ---- -使用するI/Oポートは0x01ceと0x01cfだけです。0x01ceにレジスタ番号を入れて、0x01cfにデータを入れると、QEMUのビデオカードのレジスタにデータをセットできます。どちらのポートも16bitアクセスしなければいけないので、io_out16()関数を使います。 --レジスタ0x0001 : xの解像度(320, 640, 800, 1024 のどれか) --レジスタ0x0002 : yの解像度(200, 240, 400, 480, 600, 768 のどれか) ---レジスタ0x0001との組み合わせで適切なものを設定すること ---(でも変な組み合わせでも長細い画面でちゃんと設定どおりに動いちゃうんだけどね) --レジスタ0x0003 : 色のビット数(4, 8, 15, 16, 24, 32 のどれか) ---レジスタ0x0001〜0x0002との組み合わせで適切なものを設定すること --レジスタ0x0004 : 詳細設定 ---bit0 : 設定は有効 ---bit6 : リニアアクセスモード選択 ---bit7 : 画面モード切替時にVRAMをクリアしない(クリアしないメリット:切り替えが早く終わる) ---その他のビットの意味は不明。必ず0にしておくこと。 --レジスタ0x0005 : 用途がよく分からないが、0x0000を設定しておくようだ。・・・用途判明!バンクレジスタだった(後述) --レジスタ0x0006 : 以下では使っていないが、表示域よりも広い仮想画面をVRAM内に設定するときのためのxのピクセル数 --レジスタ0x0007 : 上記のyのピクセル数 --レジスタ0x0008 : 仮想画面を使っているときに、表示位置のx座標 --レジスタ0x0009 : 仮想画面を使っているときに、表示位置のy座標 ---- -例としてはできるだけ単純なほうがいいと思うので、4日目の最後から改造することにしましょう。つまりベースとなるのはharib02iです。まず、asmhead.nasの画面モード設定をコメントアウトしてしまいましょう。こんなものにはもう頼りませんよ。 ;; 画面モードを設定 ; ; MOV AL,0x13 ; VGAグラフィックス、320x200x8bitカラー ; MOV AH,0x00 ; INT 0x10 ; MOV BYTE [VMODE],8 ; 画面モードをメモする(C言語が参照する) ; MOV WORD [SCRNX],320 ; MOV WORD [SCRNY],200 ; MOV DWORD [VRAM],0x000a0000 -そしてbootpack.cに以下の記述を書き加えます。init_qemuvga0()での手順が、画面モード切り替えの設定方法です。 void io_out16(int port, int data); void set_qemuvga0reg(int reg, int dat) { io_out16(0x01ce, reg); io_out16(0x01cf, dat); return; } void init_qemuvga0(struct BOOTINFO *binfo, int x, int y, int c, int flag) { set_qemuvga0reg(0x0004, 0x0000); set_qemuvga0reg(0x0001, x); set_qemuvga0reg(0x0002, y); set_qemuvga0reg(0x0003, c); /* 4, 8, 15, 16, 24, 32 */ set_qemuvga0reg(0x0005, 0x0000); set_qemuvga0reg(0x0004, flag); /* リニアアクセスモードでVRAMの初期化をするなら0x41 */ /* bit7 : VRAM初期化抑制, bit6 : リニアアクセスモード, bit0 : 設定有効 */ binfo->scrnx = x; binfo->scrny = y; binfo->vmode = c; if ((flag & 0x40) == 0) { binfo->vram = (char *) 0x000a0000; } else { binfo->vram = (char *) 0xe0000000; } return; } -そんでもって、HariMain()のinit_screen8()の前に、1行書き足します。ここでは800x600の8bitカラーにしてみます。どうせこの直後に全画面描き換えるのでVRAMのクリアはしないことにしました。 void HariMain(void) { (中略) init_gdtidt(); init_palette(); init_qemuvga0(binfo, 800, 600, 8, 0xc1); /* ココ! */ init_screen8(binfo->vram, binfo->scrnx, binfo->scrny); (中略) } -これでできあがりです。さて実験・・・よしうまくいったぁ〜。 -本当にこれだけでうまくいくの?という人は是非自分でもやってみましょう。 ---- -とりあえず上記だけでたいていのことはできると思いますが、32bitモードに切り替えるのが面倒な場合(もしくは切り替えられない特別な事情がある場合)は、なんと1MBまでの番地内だけでも高解像度が使えます。この方法を使うことは多分ないと思いますが、筆者がせっかく調べたので一応まとめておきます。 -まず、画面モード切替だけならOUT命令だけでできるので、16bitモードのままで問題無しです。しかし上記のサンプルと同じ手順では少し問題があるので、以下の点を変えてください。画面モード設定の際に、「レジスタ0x0004 : 詳細設定」の「bit6 : リニアアクセスモード選択」をゼロにします。 -こうすることで、0xe0000000からの64KBの内容がそのまま0xa0000からの64KBで読み書きできるようになります。で、これだともちろん不十分です。だって256色の800x600とかに設定した場合はVRAMは全体で468KBを超えるわけで、そのうちの先頭の64KBしか使えないというのはいかにも困るわけです。 -ということで、他の部分を読み書きしたいときは、上記の「レジスタ0x0005 : バンクレジスタ」を使います。ここに1を書き込むと、0xa0000からの64KBの内容は、0xe0010000からの内容に瞬時に入れ替わります。2を書き込めば0xe0020000になります。こんな感じで、結局0xa0000〜0xaffffへ読み書きするだけで、VRAM全体を読み書きできるというわけです。 *** QEMUでもQEMU以外でも使える切替方法1(古いモード編) -本の中でよく使っている320x240x8bitのモードは、BIOSを使わずに設定することが可能です。VBEを使わなくても設定できる画面モードのうちメジャーなものは、実はほとんどのカードで設定方法が同じになっています。したがってこのセクションの方法は、QEMU以外のエミュレータでもうまくいくのはもちろんのこと、実機でもうまくいきます。QEMUでいえば、-stdvgaであってもなくてもうまくいきます。ただVBE以前のモードばかりなので高解像度や多色に対応できず、ややイマイチな感じではあります。 --ただし一度でもこの方法で画面モードを設定してしまうと、BIOS内部が覚えている状態との食い違いが生じてしまうため、BIOSを通じての画面モード切替や文字表示などがうまくいかなくなることがあります(もちろん再起動すれば直ります)。 - -stdvga以外のビデオカードの設定がどれほど面倒そうなのかの感じをつかんでほしくてこのセクションを作りました。 -すごく長くなりそうなので、別ページに作ります。 -(つづく) *** QEMUでの画面モード切替方法2(Cirrus Logic GD5446編) -(つづく:調査中) * こめんと欄 -もしかすると、この方法だとXen上で動くかもですね -- [[あっきぃ>Akkie]] SIZE(10){2008-09-12 (金) 02:16:21} -ほんとう?XenってQEMUの-std-vgaの互換モードってあるのかな?あったらビンゴだね! -- [[K]] SIZE(10){2008-12-17 (水) 22:14:58} #comment
テキスト整形のルールを表示する