090319

|


MCFAJ一戦筑波、エントリーしました。悩んでたんだけど。今日がエントリー締
切。今年からエントリフィーが、筑波29000円、富士32000円(MCFAJの会員じゃ
ない場合)なのだ。

出れるうちに出ておこうということで。
マクガイバーのせいで作業が進んでいません。どれもこれもいい話だ。必要以 上に暴力的な場面が出ないのがいいね。
今日はここまで。フェンダーにフレームよけの穴を開けました。

机は7回塗り終了で、まぁなんとか。塗装は終了でここから仕上げの磨きです。

x86続き。保護モードに移行するのをいろいろ試してみた。

例えば二段階目を0x20000にロード。そのリアルモードのプログラムは
CS,DS,SS=0x2000になるように設定。ここから保護モードに移る。

保護モードのデスクリプタの設定は
struct gdt_config
{
  uint32_t base;
  uint32_t size;
  uint8_t unit;
  uint8_t mode;
  uint8_t type;
} gdt_config [] = {
  { 0x20000,	0x100,	SIZE_UNIT_4KB, CODE_32, CODE_SEGMENT },
  { 0x20000,	0x100,	SIZE_UNIT_4KB, CODE_32, DATA_SEGMENT },
  { 0x40000,	0x100,	SIZE_UNIT_4KB, CODE_32, STACK_SEGMENT },
};
と、0x20000オフセットしたものに。

lgdtに設定するのはリニアアドレスでないといけないので、0x20000の下駄を。

	.section .data
	.balign 4
lgdt_arg:
	.word	0x1f	// 0, Code, Data, Stack.
	.long	_gdt + 0x20000

このように移行。

	lgdt	lgdt_arg

	movl	%cr0,	%eax
	orl	$0x1,	%eax
	movl	%eax,	%cr0
	// Load CS(0x08) with pipeline flush.
//	DATA32	ljmp	$0x08,	$protect_mode_start
	ljmp	$0x08,	$protect_mode_start
protect_mode_start:
	.code32

lgdtは16bitと32bitの二命令がある。それはオペランドの処理の方法で、
16bit命令の場合(このサンプル)、設定したGDTRのベースに0xffffffがANDされ
るかどうかだけ。リアルモードから移行する場合は0xffffffを越えることはあ
りえないので16bit命令でいい。

ljmpは「保護モードのCS」が自動的に更新されているからフェッチできるはず。
オフセットについて。このljmpで先にロードしたGDTの設定(0x08)をCSにロード
して、それに基ずいてアドレスを計算する。設定では0x20000がベースになって
いるので、下駄をはかせる必要はない。
この状態ではまだCSがロードされてないからDビットは16bitモードだ。

DATA32でオペランドサイズプリフィックスをつけた場合、0x66がついてるので
オペランドの解釈を32bitモードだとする。(その変換の寄りどころはCPUによって
自動的に更新されている保護モードのCS)
 1af:	66 ea b7 01 00 00 08 	ljmpl  $0x8,$0x1b7	//DATA32あり
これを32bitとしてオペランドを解釈

つけなかった場合16bitとしてオペランドを解釈。(まだDビットは16bit)
 1af:	ea b4 01 08 00       	ljmp   $0x8,$0x1b4

なので、どっちでも同じはず。

そしてその他のセグメントの設定。
	movw	$0x10,	%ax
	movw	%ax,	%ds
	// Load SS
#if 1
	movw	$0x18,	%ax
	movw	%ax,	%ss
	// Reset stack pointer.
	movl	$0,	%esp
	movl	$0,	%ebp
#else
	movw	%ax,	%ss
	// Reset stack pointer.
	movl	$0xfff0,	%esp
#endif

スタックセグメントの設定は、インテルが想定していた設定はベースにスタッ
クの最大アドレスを設定して、ESPは0からはじまってマイナスに伸張するもの。
(上のコードの#if 1)、これだと同じアドレスでもデータセグメントからと
スタックセグメントからでポインタが異なる。

一般には(#if 0)のようにデータセグメントと同じように設定する。

今回、インテルの想定したような使い方を試してみた。普通にpush,popする分
にはいいのだけれど、varargsがだめ。今の状態ではきっちり追うことはできな
いけれど、スタックをがりがりいじるようなところで予想外のことになってい
るのかな...。スタックポインタ、コピーしてアクセスできないんじゃ、いくら
なんでも地獄過ぎだね。


保護モードに移ったテストはVGAにベタ書き込み。リアルモードの内に320x240 16bppに
しておきます。

	movl	$0x80000,%eax
	movl	$32000,	%ecx
1:	movb	$5, (%eax)
	inc	%eax
	loop	1b

ここで0x80000になっているのはセグメントが0x20000オフセットされているの
で、本来のV-RAM 0xa0000になる。もう既に気が狂いそうだ。