Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions ukvm/ukvm_gdb_freebsd_x86_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,71 @@
#include "ukvm_gdb_x86_64.h"
#include "ukvm_gdb.h"

#if 0
#define KVM_GUESTDBG_ENABLE 0x00000001
#define KVM_GUESTDBG_SINGLESTEP 0x00000002

static int ukvm_gdb_update_guest_debug(struct ukvm_hv *hv)
{
struct kvm_guest_debug dbg = {0};
struct breakpoint_t *bp;
const uint8_t type_code[] = {
/* Break on instruction execution only. */
[GDB_BREAKPOINT_HW] = 0x0,
/* Break on data writes only. */
[GDB_WATCHPOINT_WRITE] = 0x1,
/* Break on data reads only. */
[GDB_WATCHPOINT_READ] = 0x2,
/* Break on data reads or writes but not instruction fetches. */
[GDB_WATCHPOINT_ACCESS] = 0x3
};
const uint8_t len_code[] = {
/*
* 00 \xe2\x80\x94 1-byte length.
* 01 \xe2\x80\x94 2-byte length.
* 10 \xe2\x80\x94 8-byte length.
* 11 \xe2\x80\x94 4-byte length.
*/
[1] = 0x0, [2] = 0x1, [4] = 0x3, [8] = 0x2
};
int n = 0;

if (stepping)
dbg.control = KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_SINGLESTEP;

if (!SLIST_EMPTY(&sw_breakpoints))
dbg.control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP;

if (!SLIST_EMPTY(&hw_breakpoints)) {
dbg.control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_HW_BP;

/* Enable global breakpointing (across all threads) on the control
* debug register. */
dbg.arch.debugreg[7] = 1 << 9;
dbg.arch.debugreg[7] |= 1 << 10;
SLIST_FOREACH(bp, &hw_breakpoints, entries) {
assert(bp->type != GDB_BREAKPOINT_SW);
dbg.arch.debugreg[n] = bp->addr;
/* global breakpointing */
dbg.arch.debugreg[7] |= (2 << (n * 2));
/* read/write fields */
dbg.arch.debugreg[7] |= (type_code[bp->type] << (16 + n*4));
/* Length fields */
dbg.arch.debugreg[7] |= ((uint32_t)len_code[bp->len] << (18 + n*4));
n++;
}
}

if (ioctl(hv->b->vcpufd, KVM_SET_GUEST_DEBUG, &dbg) == -1) {
/* The KVM_CAP_SET_GUEST_DEBUG capbility is not available. */
err(1, "KVM_SET_GUEST_DEBUG failed");
return -1;
}

return 0;
}
#endif

int ukvm_gdb_supported(void)
{
return -1;
Expand All @@ -58,6 +123,7 @@ int ukvm_gdb_write_registers(struct ukvm_hv *hv,

int ukvm_gdb_enable_ss(struct ukvm_hv *hv)
{
VM_REG_GUEST_DR7
return -1;
}

Expand Down
44 changes: 41 additions & 3 deletions ukvm/ukvm_hv_freebsd_x86_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,18 @@ static void vmm_set_desc(int vmfd, int reg, uint64_t base, uint32_t limit,
err(1, "VM_SET_SEGMENT_DESCRIPTOR (%d)", reg);
}

static void vmm_get_reg(int vmfd, int reg, uint64_t *val)
{
struct vm_register vmreg = {
.cpuid = 0, .regnum = reg
};

if (ioctl(vmfd, VM_SET_REGISTER, &vmreg) == -1)
err(1, "VM_SET_REGISTER (%d)", reg);

*val = vmreg.regval;
}

static void vmm_set_reg(int vmfd, int reg, uint64_t val)
{
struct vm_register vmreg = {
Expand Down Expand Up @@ -93,6 +105,10 @@ static void vmm_set_sreg(int vmfd, int reg, const struct x86_sreg *sreg)
vmm_set_reg(vmfd, reg, sreg->selector * 8);
}


#define KVM_GUESTDBG_ENABLE 0x00000001
#define KVM_GUESTDBG_SINGLESTEP 0x00000002

void ukvm_hv_vcpu_init(struct ukvm_hv *hv, ukvm_gpa_t gpa_ep,
ukvm_gpa_t gpa_kend, char **cmdline)
{
Expand All @@ -106,6 +122,8 @@ void ukvm_hv_vcpu_init(struct ukvm_hv *hv, ukvm_gpa_t gpa_ep,
vmm_set_reg(hvb->vmfd, VM_REG_GUEST_CR4, X86_CR4_INIT);
vmm_set_reg(hvb->vmfd, VM_REG_GUEST_EFER, X86_EFER_INIT);

//vmm_set_reg(hvb->vmfd, VM_REG_GUEST_DR7, KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_SINGLESTEP);

vmm_set_sreg(hvb->vmfd, VM_REG_GUEST_CS, &ukvm_x86_sreg_code);
vmm_set_sreg(hvb->vmfd, VM_REG_GUEST_SS, &ukvm_x86_sreg_data);
vmm_set_sreg(hvb->vmfd, VM_REG_GUEST_DS, &ukvm_x86_sreg_data);
Expand Down Expand Up @@ -152,7 +170,7 @@ void ukvm_hv_vcpu_init(struct ukvm_hv *hv, ukvm_gpa_t gpa_ep,
*cmdline = (char *)(hv->mem + X86_CMDLINE_BASE);
}

static void dump_vmx(struct vm_exit *vme)
void dump_vmx(struct vm_exit *vme)
{
warnx("unhandled VMX exit:");
warnx("\trip\t\t0x%016lx", vme->rip);
Expand All @@ -164,19 +182,32 @@ static void dump_vmx(struct vm_exit *vme)
warnx("\tinst_error\t%d", vme->u.vmx.inst_error);
}

void enable_eflag(struct ukvm_hv *hv, int flag)
{
struct ukvm_hvb *hvb = hv->b;
uint64_t flags;

vmm_get_reg(hvb->vmfd, VM_REG_GUEST_RFLAGS, &flags);
flags |= _BITUL(flag);
vmm_set_reg(hvb->vmfd, VM_REG_GUEST_RFLAGS, flags);
}

void ukvm_hv_vcpu_loop(struct ukvm_hv *hv)
{
struct ukvm_hvb *hvb = hv->b;
int ret;

while (1) {
enable_eflag(hv, 8); // ss

ret = ioctl(hv->b->vmfd, VM_RUN, &hvb->vmrun);
if (ret == -1 && errno == EINTR)
continue;
if (ret == -1) {
err(1, "VM_RUN");
}


int handled = 0;
for (ukvm_vmexit_fn_t *fn = ukvm_core_vmexits; *fn && !handled; fn++)
handled = ((*fn)(hv) == 0);
Expand All @@ -185,6 +216,9 @@ void ukvm_hv_vcpu_loop(struct ukvm_hv *hv)

struct vm_exit *vme = &hvb->vmrun.vm_exit;

vmm_set_reg(hvb->vmfd, VM_REG_GUEST_RIP, vme->rip + vme->inst_length);
enable_eflag(hv, 16); // resume

switch (vme->exitcode) {
case VM_EXITCODE_SUSPENDED:
/* Guest has halted the CPU, this is considered as a normal exit. */
Expand Down Expand Up @@ -220,8 +254,12 @@ void ukvm_hv_vcpu_loop(struct ukvm_hv *hv)
}

case VM_EXITCODE_VMX: {
dump_vmx(vme);
exit(1);
if (vme->u.vmx.status != 0) {
dump_vmx(vme);
exit(1);
}
printf("\trip\t\t0x%016lx\n", vme->rip);
break;
}

default: {
Expand Down