[BitVisor-devel:28] Re: BitVisorのシリアル入出力について

Hideki EIRAKU hdk @ igel.co.jp
2011年 10月 25日 (火) 12:16:25 JST


イーゲル 榮樂です。

From: Shougo Matsushita <shougo @ softlab.cs.tsukuba.ac.jp>
Subject: [BitVisor-devel:27] BitVisorのシリアル入出力について
Date: Fri, 21 Oct 2011 17:57:26 +0900

> 筑波大学 ソフトウェア研究室の松下正吾です。

> BitVisor側はdbgsh経由で実行したBitVisor付属のcore/builtin/bin_serialtest,
> PC側はgtktermで通信をさせて実験をしました。
> BitVisorのシリアル入出力オプション(TTY_SERIAL)はコンパイル時に有効化しています。
> 
> BitVisorからのシリアル出力はちゃんと送れているのですが、BitVisorのシリアル入力がおかしいです。
> どういう挙動をするかというと、bin_serialtest内のc = msgsendint (in, 0))で10秒〜20秒ほど固まることがあります。
> inはシリアル入力ポートです。
> 固まるまではリアルタイムにシリアル入力から受けとった文字がdbgshに出力されます。
> 固まる頻度は、連続して5, 6文字くらい入力すると固まります。
> 固まった後しばらく待ってから、またgtktermで出力すると
> 「固まっている間に表示できていなかった文字+gtktermで入力した文字」が画面に表示されます。
> データが取り零されていることはないようです。

BitVisor のシリアルポート入出力待ちは、割り込みを使わずポーリングで行っ
ています。出力はいいのですが、入力は、データが届くまでの間、ゲスト OS
の動作を止めてしまうので、dbgsh から試すと、固まるように見えることがあ
るかも知れません。

> 	printf ("serial in test\n");
> 	while ((c = msgsendint (in, 0)) != '.')
> 		printf ("%c", c);

ここからたどると core/serial.c の serial_recv() 関数のところにたどり着
きます。serial_recv() 関数は、もともと panic 後のデバッグ用途のみを想定
していたため、ビジーループでデータが届くまで待ちます。dbgsh が動作して
いるのは VM とは違うスレッドではあるものの、BitVisor のスレッドはプリエ
ンプティブではないため、この処理にきたところでかたまります。

少々強引ですが、こんな修正でも回避可能です。

------------------------------------------------------------
diff --git a/core/serial.c b/core/serial.c
--- a/core/serial.c
+++ b/core/serial.c
@@ -79,6 +79,7 @@
 #define INIT_MODEMCTL		0x3 /* RTS | DTR */
 
 static bool initialized;
+static bool schedule_ok = false;
 
 static void
 serial_init (unsigned int port)
@@ -98,9 +99,13 @@ serial_send (unsigned int port, unsigned
 	u8 status;
 
 	asm_outb (port + PORT_DATA, data);
-	do
+	goto x;
+	do {
+		if (schedule_ok)
+			schedule ();
+	x:
 		asm_inb (port + PORT_LINESTATUS, &status);
-	while (!(status & LINESTATUS_TX_BIT));
+	} while (!(status & LINESTATUS_TX_BIT));
 }
 
 static unsigned char
@@ -108,9 +113,13 @@ serial_recv (unsigned int port)
 {
 	u8 status, data;
 
-	do
+	goto x;
+	do {
+		if (schedule_ok)
+			schedule ();
+	x:
 		asm_inb (port + PORT_LINESTATUS, &status);
-	while (!(status & LINESTATUS_RX_BIT));
+	} while (!(status & LINESTATUS_RX_BIT));
 	asm_inb (port + PORT_DATA, &data);
 	return data;
 }
@@ -182,4 +191,11 @@ serial_init_msg (void)
 	msgregister ("serialout", serialout_msghandler);
 }
 
+static void
+serial_init_bsp (void)
+{
+	schedule_ok = true;
+}
+
 INITFUNC ("msg0", serial_init_msg);
+INITFUNC ("bsp0", serial_init_bsp);
------------------------------------------------------------

これは、ビジーループの時に schedule() を呼び出してスレッドを回すように
するものです。単純に schedule() だけ入れると、起動時の文字出力で落ちて
しまいますので、準備ができるまでは schedule() を呼ばないような仕掛けも
いれてあります。

-- 
Hideki EIRAKU <hdk @ igel.co.jp>



BitVisor-devel メーリングリストの案内