INT 10h AH=0Eh(VGAへの文字出力)のエミュレーション
まずはコンソール出力が無いと始まらないので、INT 10hから手を付ける事にした。
と言っても、結構色々な機能があるので、まずはFreeBSDのMBRで使われているAH=0Ehだけサポートしてみる。
vmexit_hypercall(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu) { int intno = (vmexit->rip - 0x400) / 0x4; if (!bios_mode) { fprintf(stderr, "Failed to handle hypercall at 0x%lx\n", vmexit->rip); return (VMEXIT_ABORT); } if (emulate_bios_call(ctx, *pvcpu, intno) != 0) { fprintf(stderr, "Failed to emulate INT %x at 0x%lx\n", intno, vmexit->rip); return (VMEXIT_ABORT); } return (VMEXIT_CONTINUE); }
int emulate_bios_call(struct vmctx *ctx, int vcpu, int intno) { bios_call_func_t handler; assert(intno < MAX_INTRS); handler = bios_call_handlers[intno].handler; if (handler == default_bios_call) return (-1); return ((*handler)(ctx, vcpu, intno)); }
static int int10_handler(struct vmctx *ctx, int vcpu, int intno) { static int opened; uint64_t rax, rbx; uint8_t al, ah, bl, bh; int error; if (!opened) { ttyopen(); opened = 1; } if ((error = vm_get_register(ctx, vcpu, VM_REG_GUEST_RAX, &rax)) != 0) goto done; if ((error = vm_get_register(ctx, vcpu, VM_REG_GUEST_RBX, &rbx)) != 0) goto done; al = (uint8_t)rax; ah = (uint8_t)(rax >> 8); bl = (uint8_t)rbx; bh = (uint8_t)(rbx >> 8); switch (ah) { case 0x0e: ttywrite(al); break; default: fprintf(stderr, "Not implemented BIOS call int=%x ah=%x\n", intno, ah); } done: return (error); }
詳しくは
svn diff -r238910:238930
https://socsvn.freebsd.org/socsvn/soc2012/syuu/bhyve-bios