xvmware って何だよ

ここ

あとは過去記事の ここ とか ここ を参照の事、過去記事のリンク切れはいつ直るかって?まず俺に直す気があるのかを疑ってみよう。

スクリーンショット

だから何だよ!

ここ最近いじってる vmt(4) はあくまで In-kernel VMware Tools なので X Window System の領域である

  • ホストとゲスト間のシームレスなマウス移動
  • 〃カットアンドペースト
  • 〃ドラッグアンドドロップ

はナン オブ マイ ビジネスである。

なもんで O では vmt(4) のマニュアルvmwh という ツールを併用することをお勧めしている。

ただこいつはクリップボード周りって自ら実装することなく丸投げで xclip という別アプリへのプロキシとして動作するのであった。

しかも当時 xclip は Compound Text Encoding(XA_COMPOUND_TEXT) 対応しておらず Latin1(XA_STRING) 以外の文字が使えないという東アジアとかいうどこかも知らん地の果てに棲む人より猿にみえるドワーフだけがキーキーわめく以外は誰も困らない平和な致命的問題が存在したのだ。

最新のコード読んだら UTF-8(UTF8_STRING) にも対応するようになってるから Xutf8* に何らかのトラウマ持ってない限り今では日常生活で困らんと思う。

一方俺は XA_COMPOUND_TEXT と iconv(3) を正しく使う Code Set Independent(CSI) による国際化 (I18N) アプリケーションの実例として xvmware をすでに作ってたのだよな。

まぁ最大でも世界で 3 人も使ってなかっただろうし、CSI が死んだ今コードの参考にもされることはないけどな!

CSI とは何かについてはもう令和の世に知る必要もない単語なので説明しない。 海外ドラマの科学捜査班で埋もれる検索エンジンと格闘する必要もない。 そっとしておけ。

というか存在しない過去記事読んだら俺も最初の実装は Xutf8* 使ってた ので笑った、この記事を典拠に俺も 16 年前から Unicode 派だったって歴史改竄すれば勝ち馬でもバンドワゴンでも乗って札束風呂でウェーイできませんかね?

せっかくなので xvmware を現代に生き返らせる

ノーメンテで 11 年経過してるけど特に問題なく動くはずなので死んでねえよ! いや生まれた瞬間から世界に忘れられた子だけど!

ぱっと思いつく課題としては

  • xf86-video-vmware でカーソルのシームレス移動は HWcursor のお仕事になったから機能を削除する
  • 元々 -noautogrub ってオプションがその予定だったけど GUI の設定トグルしてるだけで実装間違ってね?
  • つーか s/grub/grab/ だろ、英語もダメ人間かよ
  • 一度に 4byte づつしか転送できないコマンドは非推奨になったので、より効率的な RPC への移行
  • ESXi for ARM が爆誕し VMware Tools 側でも aarch64 対応が必要になった
  • X.org による XFree86 バラバラ殺人事件により、長年のあいだ標準ビルドツールであった imake(1) および xmkmf(1) がインストールされない環境がほとんどになったので、いまさら GNU Autotools 化

あたりで改善の余地はあるんだよね。

でも xf86-video-vmware ドライバのシームレス移動って動作変じゃね?

前述の通り HWcursor が実装されたことで VMware Tools 側でいちいちゲストとホストのカーソル位置を同期させる必要が無くなった。

ところが使ってると以下の条件

  • ゲストの画面をホストに合わせて最大化していない
  • ホストの画面解像度よりもゲストの画面解像度が上(そろそろ ThinkPad X は FullHD くらいにはなりましたか?)

だと画面下と左にスクロールバーが表示されるんだけど、その場合スクロールバーのある側からシームレス移動しようとするとカーソルが跳ね返される現象が起きるんだよね。

たしか昔の VMware Tools にはスクロールバー側のエッジにカーソルある時自動スクロールするって機能あった記憶もあるがそれに失敗してるんだろうか。

あと時々勝手にカーソルが変な方向に動こうとするんだよね、感覚としては ThinkPad のトラックポイントが死にかかった時みたいな。

これは自分の持ってる Workstation Pro のライセンス 12.5 で止まってんので最新版では改善してるかもしれない。 ただ開発マシンが C2D T7500 なので Workstation Player で試すにしても 13 以降足切りくらってるから試せないんだよな。

なので xorg.conf に

Section "Device"
	Driver "vmware"
	Option "NoHWcursor"
	...
EndSection

を入れて HWcursor 無効にして xvmware のシームレス有効にした方が安定してる感あるんだよな。 そもそも xf86-video-vesa ドライバ使う事もあるだろうし、機能の削除はせずにデフォルト無効にするかな。

あと VESA で思い出したゾ、ドライバ関係無しにホストからゲストに通知されるカーソル位置いつのまにか仕様変更になってるっぽい。

以前は

  • 境界判定はホストのカーソル位置 X/Y がゲストのスクリーンサイズ H/W の範囲内外かで行う
  • ゲストのカーソル位置をホストに通知すると同期される

という仕様だったはずなんだが

  • 境界判定はホストのカーソル位置が X/Y が 65435(=0xffff-100) なら外、それ以外は内
  • ゲストのカーソル位置をホストに通知しても値の同期はされない(通知そのものは必要)

と変わってるんだよなこれ、まぁソースの互換性壊れない変更だからいいけど。

バックドアの実装を vmt(4) 由来のコードに置換する

バックドアの実装って当初は vmware-nisetool が使ってた WIDE Project コピーライトのものだったんだが x86_64 対応のタイミングで xf86-input-vmmouse のコードに切換えたのだ。

そして 10 年越しに今度は

  • ESXi for ARM 対応のため
  • クリップボードを RPC 化するため

に vmt(4) 由来のコードに切換えんとす、ちょうど vmt(4) のコード弄ってたしね。

まずオレオレ N6 側で vmtcmd.[ch] と vmtrpc.[ch] としてそれぞれ切り出しは終わっている。

xvmware 側のコードも RPC 化はまだだけどコマンド使ってるとこはすべて 対応した

問題その1 - 移植性がまだちょっと足りない

まず C 標準ではない register_t はそもそも userland では N でさえバージョン間で互換性がない。 どうせ i386/amd64/aarch64 の3つしかないので 素直に

diff --git a/sys/dev/vmt/vmtcmd.h b/sys/dev/vmt/vmtcmd.h
index f97618ae7..bd1cd8e15 100644
--- a/sys/dev/vmt/vmtcmd.h
+++ b/sys/dev/vmt/vmtcmd.h
@@ -19,17 +19,13 @@
 #ifndef _DEV_VMT_VMTCMD_H_
 #define _DEV_VMT_VMTCMD_H_
 
-/* A register frame. */
-/* XXX 'volatile' as a workaround because BACKDOOR_OP is likely broken */
-struct vm_backdoor {
-	volatile register_t eax;
-	volatile register_t ebx;
-	volatile register_t ecx;
-	volatile register_t edx;
-	volatile register_t esi;
-	volatile register_t edi;
-	volatile register_t ebp;
-};
+#if defined(__i386__)
+typedef uint32_t vm_register_t;
+#define PRIxVMREG	PRIx32
+#elif defined(__amd64__) || defined(__aarch64__)
+typedef uint64_t vm_register_t;
+#define PRIxVMREG	PRIx64
+#endif
 
 #define VM_REG_LOW_MASK		__BITS(15,0)
 #define VM_REG_HIGH_MASK	__BITS(31,16)
@@ -146,11 +142,23 @@ struct vm_backdoor {
 #define BACKDOOR_OP_OUT	(X86_IO_W7_WITH | X86_IO_W7_STR)
 #endif
 
+/* A register frame. */
+/* XXX 'volatile' as a workaround because BACKDOOR_OP is likely broken */
+struct vm_backdoor {
+	volatile vm_register_t eax;
+	volatile vm_register_t ebx;
+	volatile vm_register_t ecx;
+	volatile vm_register_t edx;
+	volatile vm_register_t esi;
+	volatile vm_register_t edi;
+	volatile vm_register_t ebp;
+};
+
 void vm_cmd(struct vm_backdoor *);
 bool vm_probe(void);
 
 static inline void
-vm_cmd_send_data(struct vm_backdoor *frame, uint16_t cmd, register_t data)
+vm_cmd_send_data(struct vm_backdoor *frame, uint16_t cmd, vm_register_t data)
 {
 	memset(frame, 0, sizeof(*frame));
 

変更した

その CPU ネイティブのレジスタ幅の型って int_{fast,least}N_t じゃダメ (目的を履き違えれば intptr_t が最も近いのか) だし確かに register_t みたいなの C 標準で欲しい気はしないでもない。

そして 過去回 で説明した BIT(3) を使った二進数表記については 0b プリフィックスに 置換した

diff --git a/sys/dev/vmt/vmtcmd.h b/sys/dev/vmt/vmtcmd.h
index bd1cd8e15..15d05c129 100644
--- a/sys/dev/vmt/vmtcmd.h
+++ b/sys/dev/vmt/vmtcmd.h
@@ -22,14 +22,16 @@
 #if defined(__i386__)
 typedef uint32_t vm_register_t;
 #define PRIxVMREG	PRIx32
+#define VMREG_C(x)	UINT32_C(x)
 #elif defined(__amd64__) || defined(__aarch64__)
 typedef uint64_t vm_register_t;
 #define PRIxVMREG	PRIx64
+#define VMREG_C(x)	UINT64_C(x)
 #endif
 
-#define VM_REG_LOW_MASK		__BITS(15,0)
-#define VM_REG_HIGH_MASK	__BITS(31,16)
-#define VM_REG_WORD_MASK	__BITS(31,0)
+#define VM_REG_LOW_MASK		VMREG_C(0b00000000000000001111111111111111)
+#define VM_REG_HIGH_MASK	VMREG_C(0b11111111111111110000000000000000)
+#define VM_REG_WORD_MASK	VMREG_C(0b11111111111111111111111111111111)
 
 #define VM_REG_IN_LOW(x)	(__SHIFTIN(x, VM_REG_LOW_MASK))
 #define VM_REG_IN_HIGH(x)	(__SHIFTIN(x, VM_REG_HIGH_MASK))
@@ -96,13 +98,13 @@ typedef uint64_t vm_register_t;
 	)
 
 #define X86_IO_MAGIC		0x86	/* magic for upper 32bit of x7 */
-#define X86_IO_W7_SIZE_MASK	__BITS(1, 0)
+#define X86_IO_W7_SIZE_MASK	VMREG_C(0b00000000000000000000000000000011)
 #define X86_IO_W7_SIZE(n)	__SHIFTIN((n), X86_IO_W7_SIZE_MASK)
-#define X86_IO_W7_DIR		__BIT(2)
-#define X86_IO_W7_WITH		__BIT(3)
-#define X86_IO_W7_STR		__BIT(4)
-#define X86_IO_W7_DF		__BIT(5)
-#define X86_IO_W7_IMM_MASK	__BITS(12, 5)
+#define X86_IO_W7_DIR		VMREG_C(0b00000000000000000000000000000100)
+#define X86_IO_W7_WITH		VMREG_C(0b00000000000000000000000000001000)
+#define X86_IO_W7_STR		VMREG_C(0b00000000000000000000000000010000)
+#define X86_IO_W7_DF		VMREG_C(0b00000000000000000000000000100000)
+#define X86_IO_W7_IMM_MASK	VMREG_C(0b00000000000000000001111111100000)
 #define X86_IO_W7_IMM(imm)	__SHIFTIN((imm), X86_IO_W7_IMM_MASK)
 #define BACKDOOR_OP_AARCH64(op, frame)		\
 	__asm__ volatile (			\

あとは __SHIFTIN__SHIFTOUT をどうするかだけど保留、まぁ移植するんだろうな。

問題その2 - 動作確認しようにも手元に aarch64 なんて無いよ

  • ラズパイ?とか種類がおっぱいあってどれがどれだかわけわかんねえし
  • そもそもコロナ渦による半導体払底で売ってねえし在庫あるとこ高けえし
  • オタクじゃないから基板剥き出しだいっきらい感電も火事も怖いし

なので絶対にノゥ、そもそもお金が無いですね。

そういえば数年前にビックとコジマで AIWA KSTB6043 が 980 円で投げ売りしてたの一台買ってはあるけど、 Amlogic S905D で ESXi for ARM 動くんだったらやるかなーってくらい、Linux なら Armbian動作報告 はあるんだけども。

たとえ動くとしても箱から出して設定する気も起きねえや…空気吸うだけでもめんどくさいのに。

次回

おかしいな 10 年後には X Window System なんて Wayland に置きかえられてこんなツール無用になってるはずだったんだ。 おーい Mir … Fresco … みんなどこ行ったんだ…?