提案/電源管理/カーネル落ちを調査/secondboot の変更点



 #topicpath
 #contents
 
 * secondbootの改造 [#l5deb5fc]
 
 secondbootを改造してAPM BIOSの返り値を調べてみます。
 
 #ref(secondboot.zip)
 
 - レジスタ破壊など最適化の地雷を踏まないように配慮して修正しました。
 -- 便利なのか、複雑なだけなのか、微妙なコード・・・
 -- ログを表示するようにしただけではないので念のため。
 - 表示で止めているため、このままではカーネルが起動しません。このコードベースでカーネルを起動させるには以下のように変更が必要です。
  diff -ur secondboot.orig/APM.cs secondboot/APM.cs
  --- secondboot.orig/APM.cs	2006-09-22 12:12:00.000000000 +0900
  +++ secondboot/APM.cs	2006-09-22 12:42:31.562500000 +0900
  @@ -99,7 +99,7 @@
   			Memory.Write(0, (ushort)(addr + 24), 0, version);
   			Memory.Write(0, (ushort)(addr + 28), 0, 1);
   
  -			for (;;) new Inline("hlt");
  +			//for (;;) new Inline("hlt");
   
   			return true;
   		}
  diff -ur secondboot.orig/SecondBoot.cs secondboot/SecondBoot.cs
  --- secondboot.orig/SecondBoot.cs	2006-09-22 12:10:00.000000000 +0900
  +++ secondboot/SecondBoot.cs	2006-09-22 12:51:03.312500000 +0900
  @@ -26,8 +26,8 @@
   			ReadServer("MONITOR.BIN");
   			
   			ReadConfig("MONA.CFG");
  -			APM.InterfaceConnect32(APMInfoAddr);
   			SetVesaMode();
  +			APM.InterfaceConnect32(APMInfoAddr);
   			
   			WriteSize(0);
   		}
 
 ** Virtual PC 2004 SP1 [#k6c634d8]
 
  cs32     = 0000F000
  eip      = 0000EF50
  cs16     = 0000F000
  ds       = 00000040
  cs32_len = FFFF
  cs16_len = 0000
  ds_len   = 00000100
  version  = 00000102
 
 - カーネル起動後に値を比較⇒一致
 
 ** qemu-20050121-tap-windows [#l522d60a]
 
  cs32     = 0000F000
  eip      = 000095E3
  cs16     = 0000F000
  ds       = 0000F000
  cs32_len = FFF0
  cs16_len = FFF0
  ds_len   = 0000FFF0
  version  = 00000102
 
 - カーネル起動後に値を比較⇒一致
 
 ** 小技 [#i1fd1b35]
 
 ソースをいじりながらこまめに動かす原始的な技。
 
  $ make install && make -C ../../tool/mkimg/ && (cd ../../../qemu && ./MonaCDBoot.bat)
 
 - ひらすら[↑][Enter]で履歴を出してビルド&起動の繰り返し。
 - 手軽さだけが取り柄。
 - 能率は度外視。
 
 ** 正常動作 [#jfcbf22f]
 
 Cygwin+qemuで正常動作を確認した手順
 
 + secondbootを添付のものに差し替える
 -- secondbootを差し替えないでカーネルの最適化を外しただけでは、qemuでもVPC同様result = 0x00000001とだけ表示されて電源が切れない。
 + 上記のカーネル起動用の修正を施す
 -- 【追記1】APM.InterfaceConnect32()内のRegisters.ES = 0;を消す
 -- 【追記2】APM.InterfaceConnect32()内のConsole.WriteLine()を全部コメントアウトする(無駄なので)
 + GDTUtil.cppのAPM関連のコメントアウトを外す
 + kernel/Makefileで最適化を外す(重複指定すると最初の指定が無視されることを利用)
  .cpp.o:
  	$(CXX) $(CXXFLAGS) -O0 $(INCLUDE) -c $<
 + これでqemuでのshutdown -hの正常動作を確認
 -- VPCではresult = 0x00000001とだけ表示されて電源は切れないが、エラーで落ちるということはなくなった。
 
 *** 開発環境 [#y3791851]
 
  $ uname -srv
  CYGWIN_NT-5.1 1.5.21(0.156/4/2) 2006-07-30 14:21
  $ gcc --version
  gcc (GCC) 3.4.4 (cygming special) (gdc 0.12, using dmd 0.125)
 
 *** qemuで正常動作しているISOイメージ [#qa44c545]
 
 #ref(mona-apm-iso.zip)
 
 ** GDTUtilで-O3の副作用を回避するパッチ [#n3b66602]
 
 コンパイラの問題だと思われるので、適用は推奨しません。
 
  --- GDTUtil.cpp.orig	2006-09-23 10:51:47.078125000 +0900
  +++ GDTUtil.cpp	2006-09-23 10:52:32.609375000 +0900
  @@ -168,7 +168,8 @@
       g_tss->ss0  = KERNEL_SS;
   
       /* load TSS */
  -    ltr(selector);
  +    //ltr(selector);
  +    asm volatile("ltr %0\n": "=m" (selector));
   
       return;
   }
 
 ** Tinoさんの調査後のひげぽんがやった事 [#s02756c9]
 -[[提案/電源管理/カーネル落ちを調査/secondboot]]の正常動作に従い shutdown -h が正常動作することを確認した。
 -「GDTUtilで-O3の副作用を回避するパッチ」を試す。→正常動作した。
 -最適化での誤動作を防げないか調べる
 -- -O3 -O0 でそれぞれ -S で比較してみる
 -- ltrの仕様を忘れたのでIntelのマニュアルを読んでみる
 -- Tinoさんの指摘通り
  /* TSS. Mona has only one TSS */
  setSegDesc(&g_gdt[4], (dword)g_tss, 0x00000067, SEGMENT_PRESENT | SEGMENT_DPL0 | 0x00 | 0x09);
 -- 上で設定した tss のアドレスをCPUは参照していて、同アドレスの内容を ltr 時にselector 経由で参照しているのだけど、コンパイラはそれ知りようもなく最適化してしまう。
  /* prepare dpl0 stack */
  memset(g_tss, 0, sizeof(TSS));
  g_tss->esp0 = 0x90000;
  g_tss->ss0  = KERNEL_SS;
  /* load TSS */
  ltr(selector);
 -- まず g_tssとそのメンバを volatile 指定してみたがダメだった。
 -- setupTSS内が最適化されるのを防ぐにはどうしたら良いか?を考える。gccがそのような構文を用意しているかもしれないので調べてみよう。
 --- info gcc して s で volatile を検索したらたまたま「Declaring Attributes of Functions」という項目をみつけた。
 --- 読み進めたら noinline という attribute があるらしいので試す。
 --- static void ltr(word selector) __attribute__ ( (noinline) ) /* we need this! */
 --- うまくいきました。これで -O3 を保持しつつ該当部の inline 最適化を防げます。
 
 ** Tinoさんの調査後のひげぽんがやった事2 [#s0b85d54]
 secondboot調査。~
 -Memrory.cs(追加)~
 --MemoryへのWrite。特定アドレスに値を書き込む。byte/short。
 --MemoryのRead。特定アドレスに値を読み込む。byte/short
 -Console.cs(変更)~
 --16進出力など追加
 -APM.cs(変更)
 --ここが大きな変更。
 --処理が始まってすぐにレジスタの値をローカル変数に退避。
 ---bool cf = Flags.C;など。
 ---値が意図せず書き換わる前に保持したい?
 --メモリへのwriteをMemory.csを利用するようになった。
 --同じくメイン処理部に関しても
 ---inlineでのmovではなくMemory.writeを使うようになった
 ---レジスタの内容をあらかじめローカル変数に保存するようになった
 -まとめると
 --メモリへの書き込みが汎用手続きを利用するようになった。またes/diなどの退避なども局所的に行うようになった。
 --処理開始時にレジスタの値をローカル変数(スタック)に保持してから行うことで意図せぬレジスタの値変更の影響をうけないようにした。(これが最適化問題?)
 ---Tinoさんんが「及的速やかにレジスタの値をローカル変数に退避させるのが、地雷を踏まないコツ」と書いているのはこのことか。
 ---Tinoさんが「可及的速やかにレジスタの値をローカル変数に退避させるのが、地雷を踏まないコツ」と書いているのはこのことか。
 
 ** コメント [#t6a7fc2f]
 
 #pcomment(,1000,below,reply)

リロード   新規 編集 差分 添付 複製 改名   トップ 一覧 検索 最終更新 バックアップ   ヘルプ   最終更新のRSS

Modified by mona
PukiWiki 1.4.6 Copyright © 2001-2005 PukiWiki Developers Team. License is GPL.
Based on "PukiWiki" 1.3 by yu-ji
Powered by PHP 5.2.17
HTML convert time to 0.018 sec.