GSoC 2012 week6:INT命令をハンドルしてみる

まずブートセクタをゲスト空間に読み込めるようにする。

bhyvebiosload.c

	disk_fd = open(disk_image, O_RDONLY);
	if (read(disk_fd, &membase[0x7c00], 512) != 512) {
		perror("read ");
		return (1);
	}

これに合わせて、ゲストのRIPは0x7c00から開始するように設定しておいた。(コード省略)

次に、リアルモードの割込みハンドラだが、こんな風にしてみた。

bhyvebiosload.c

	addr = 0x400;
	for (i = 0x0; i < 0x400; i += 0x4) {
		uint16_t *p = (uint16_t *)&membase[i];
		membase[addr + 0] = 0x0f;	/* vmcall(3byte) */
		membase[addr + 1] = 0x01;
		membase[addr + 2] = 0xc1;
		membase[addr + 3] = 0xcf;	/* iret */
		*p = addr;
		p = (uint16_t *)&membase[i + 0x2];
		*p = 0x0;
		addr += 4;
	}

マジックナンバーじみてて分かりにくいコードだが、割り込み番号0x0〜0xffの割り込みハンドラを0x400から0x4刻みで一対一に用意していて、ハンドラの中身はvmcall; iret;となっている。

ゲスト内の割り込みハンドラで実行されたvmcallで生じるVMExitをハンドルするコードに、レジスタダンプとRIPから計算出来る割り込み番号の表示を入れてみる。
fbsdrun.c

	error = vm_get_register(ctx, *pvcpu, VM_REG_GUEST_RSP, &rsp);
	if (!error)
		error = vm_get_register(ctx, *pvcpu, VM_REG_GUEST_RIP, &rip);
	if (!error)
		error = vm_get_register(ctx, *pvcpu, VM_REG_GUEST_RAX, &rax);
	if (!error)
		error = vm_get_register(ctx, *pvcpu, VM_REG_GUEST_RBX, &rbx);
	if (!error)
		error = vm_get_register(ctx, *pvcpu, VM_REG_GUEST_RCX, &rcx);
	if (!error)
		error = vm_get_register(ctx, *pvcpu, VM_REG_GUEST_RDX, &rdx);

	if (error) {
		printf("errno = %d\n", errno);
		return (VMEXIT_ABORT);
	}

	printf("VMCALL handled\n");
	printf("rsp=%"PRIx64" rip=%"PRIx64" rax=%"PRIx64" rbx=%"PRIx64" rcx=%"PRIx64" rdx=%"PRIx64"\n",
		rsp, rip, rax, rbx, rcx, rdx);
	intr = (rip - 0x400) / 0x4;
	printf("intr=%"PRIu64"\n", intr);

	return (VMEXIT_ABORT);

こんな感じ。今のところ、割り込みから復帰させずに実行を中断している。

では試しに、こんなブートセクタプログラムをロードして、正しい値が得られるか試してみる。
testbootsect.S

.code16
	mov $0x1, %ax
	mov $0x2, %bx
	mov $0x3, %cx
	mov $0x4, %dx
	int $0x13
	int $0x14

以下が実行結果。

$ sudo bhyvebiosload -d ~/testbootsect/testbootsect.bin -m 128 -M 256 vm0
$ sudo bhyve -b -m 128 -M 256 vm0
VMCALL handled
rsp=7ff8 rip=44c rax=1 rbx=2 rcx=3 rdx=4
intr=19

レジスタ値と割り込み番号が正しく取れている事が分かる(※0x13 == 19)。

今週は全くカーネル弄ってない。
というか、実の所、ここからの作業はほぼ100%ユーザランドなのだ。

詳しくは

svn diff -r238305:238881 https://socsvn.freebsd.org/socsvn/soc2012/syuu/bhyve-bios