GSoC 2012 week1:VMCALL命令をtrapする
まぁVM床抜きについては以前にもその手の専門家なgo_vmが詳しく解説されているので、私が色々説明するまでも無いと思う(←説明放棄)。
ってな訳でまぁコード書いてみましょう。
ゲストカーネル
--- /usr/src-bhyve/sys/amd64/amd64/locore.S 2012-01-03 12:27:06.000000000 +0900 +++ /home/syuu/9.0-bhyve/sys/amd64/amd64/locore.S 2012-05-30 09:05:33.000000000 +0900 @@ -77,7 +77,9 @@ xorl %ebp, %ebp call hammer_time /* set up cpu for unix operation */ + + .byte 0xf,0x1,0xc1 + call mi_startup /* autoconfiguration, mountroot etc */ 0: hlt jmp 0b
まず、おもむろにゲストカーネルの起動直後の所へVMCALL命令を突っ込みます。
.byteで書いてるのはgnu asがVMCALL命令を知らなそうな気配を感じたからで、対応してれば普通にvmcallと書けばよさそうな気がします。
ホストカーネル
Index: sys/amd64/include/vmm.h =================================================================== --- sys/amd64/include/vmm.h (revision 236685) +++ sys/amd64/include/vmm.h (working copy) @@ -228,6 +228,7 @@ VM_EXITCODE_MTRAP, VM_EXITCODE_PAUSE, VM_EXITCODE_PAGING, + VM_EXITCODE_VMCALL, VM_EXITCODE_MAX }; Index: sys/amd64/vmm/intel/vmx.c =================================================================== --- sys/amd64/vmm/intel/vmx.c (revision 236685) +++ sys/amd64/vmm/intel/vmx.c (working copy) @@ -1189,6 +1189,9 @@ vmexit->exitcode = VM_EXITCODE_PAGING; vmexit->u.paging.cr3 = vmcs_guest_cr3(); break; + case EXIT_REASON_VMCALL: + vmexit->exitcode = VM_EXITCODE_VMCALL; + break; default: break; }
VMExitの要因(EXIT_REASON)チェックでEXIT_REASON_VMCALLをハンドルします。
ここでは、VM_EXITCODE_VMCALLというexitcodeをユーザランドへ返す事とします。
本当はレジスタの値も一緒に送ってあげたいんですが、とりあえず今日はやめておきます。
ホストユーザランド
Index: usr.sbin/bhyve/fbsdrun.c =================================================================== --- usr.sbin/bhyve/fbsdrun.c (revision 236685) +++ usr.sbin/bhyve/fbsdrun.c (working copy) @@ -429,6 +429,15 @@ return (VMEXIT_CONTINUE); } +static int +vmexit_vmcall(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu) +{ + printf("VMCALL handled\n"); + exit(1); + + return (VMEXIT_RESTART); +} + static void sigalrm(int sig) { @@ -469,7 +478,8 @@ [VM_EXITCODE_RDMSR] = vmexit_rdmsr, [VM_EXITCODE_WRMSR] = vmexit_wrmsr, [VM_EXITCODE_MTRAP] = vmexit_mtrap, - [VM_EXITCODE_PAGING] = vmexit_paging + [VM_EXITCODE_PAGING] = vmexit_paging, + [VM_EXITCODE_VMCALL] = vmexit_vmcall, };
VM_EXITCODE_VMCALLをハンドルする関数を定義します。
今日は、単にprintfしてexitするだけとしておきます。
ここに、おいおいBIOS Emulationのコードを入れていきます。
走らせるとどうなるか
走らせはじめた瞬間に「VMCALL handled」って出てbhyveがexitして終了ー。