From 99a4ea32a54269cac99db97e6d2a0c4fdb2288ae Mon Sep 17 00:00:00 2001 From: Bryan Cantrill Date: Sat, 9 Apr 2011 13:52:14 -0700 Subject: HVM-43 add ::kvm_gpa2qva to translate guest physical to QEMU virtual --- kvm_mdb.c | 242 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 242 insertions(+) create mode 100644 kvm_mdb.c (limited to 'kvm_mdb.c') diff --git a/kvm_mdb.c b/kvm_mdb.c new file mode 100644 index 0000000..015a6b8 --- /dev/null +++ b/kvm_mdb.c @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2011, Joyent, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "msr.h" +#include "vmx.h" +#include "irqflags.h" +#include "iodev.h" +#include "kvm_host.h" +#include "kvm_x86host.h" +#include "kvm.h" + +int +kvm_mdb_memory_slot_init(mdb_walk_state_t *wsp) +{ + struct kvm_memslots *memslots; + struct kvm kvm; + uintptr_t addr; + + if (wsp->walk_addr == NULL) { + mdb_warn("kvm_memory_slot does not support global walks"); + return (WALK_ERR); + } + + if (mdb_vread(&kvm, sizeof (kvm), wsp->walk_addr) == -1) { + mdb_warn("couldn't read kvm at %p", wsp->walk_addr); + return (DCMD_ERR); + } + + addr = (uintptr_t)kvm.memslots; + memslots = mdb_alloc(sizeof (struct kvm_memslots), UM_SLEEP | UM_GC); + + if (mdb_vread(memslots, sizeof (struct kvm_memslots), addr) == -1) { + mdb_warn("couldn't read memslots at %p", addr); + return (DCMD_ERR); + } + + wsp->walk_addr = addr + offsetof(struct kvm_memslots, memslots); + wsp->walk_arg = 0; + wsp->walk_data = memslots; + + return (WALK_NEXT); +} + +int +kvm_mdb_memory_slot_step(mdb_walk_state_t *wsp) +{ + struct kvm_memslots *memslots = wsp->walk_data; + uintptr_t ndx = (uintptr_t)wsp->walk_arg; + + if (ndx >= KVM_MEMORY_SLOTS) + return (WALK_DONE); + + wsp->walk_arg = (void *)(ndx + 1); + + return (wsp->walk_callback(wsp->walk_addr + + ndx * sizeof (struct kvm_memory_slot), &memslots->memslots[ndx], + wsp->walk_cbdata)); +} + +int +kvm_mdb_mem_alias_init(mdb_walk_state_t *wsp) +{ + struct kvm_mem_aliases *aliases; + struct kvm kvm; + uintptr_t addr; + + if (wsp->walk_addr == NULL) { + mdb_warn("kvm_mem_alias does not support global walks"); + return (WALK_ERR); + } + + if (mdb_vread(&kvm, sizeof (kvm), wsp->walk_addr) == -1) { + mdb_warn("couldn't read kvm at %p", wsp->walk_addr); + return (DCMD_ERR); + } + + addr = (uintptr_t)kvm.arch.aliases; + aliases = mdb_alloc(sizeof (struct kvm_mem_aliases), UM_SLEEP | UM_GC); + + if (mdb_vread(aliases, sizeof (struct kvm_mem_aliases), addr) == -1) { + mdb_warn("couldn't read aliases at %p", addr); + return (DCMD_ERR); + } + + wsp->walk_addr = addr + offsetof(struct kvm_mem_aliases, aliases); + wsp->walk_arg = 0; + wsp->walk_data = aliases; + + return (WALK_NEXT); +} + +int +kvm_mdb_mem_alias_step(mdb_walk_state_t *wsp) +{ + struct kvm_mem_aliases *aliases = wsp->walk_data; + uintptr_t ndx = (uintptr_t)wsp->walk_arg; + + if (ndx >= aliases->naliases) + return (WALK_DONE); + + wsp->walk_arg = (void *)(ndx + 1); + + return (wsp->walk_callback(wsp->walk_addr + + ndx * sizeof (struct kvm_mem_alias), &aliases->aliases[ndx], + wsp->walk_cbdata)); +} + +static int +kvm_mdb_gpa2qva_walk_alias(uintptr_t addr, + const struct kvm_mem_alias *alias, uintptr_t *gfn) +{ + if (alias->flags & KVM_ALIAS_INVALID) + return (WALK_NEXT); + + if (*gfn < alias->base_gfn || *gfn >= alias->base_gfn + alias->npages) + return (WALK_NEXT); + + *gfn = alias->target_gfn + *gfn - alias->base_gfn; + + return (WALK_DONE); +} + +static int +kvm_mdb_gpa2qva_walk_slot(uintptr_t addr, + const struct kvm_memory_slot *memslot, uintptr_t *gpa) +{ + uintptr_t gfn = *gpa >> PAGESHIFT; + + if (gfn < memslot->base_gfn) + return (WALK_NEXT); + + if (gfn >= memslot->base_gfn + memslot->npages) + return (WALK_NEXT); + + mdb_printf("%p\n", memslot->userspace_addr + + ((gfn - memslot->base_gfn) << PAGESHIFT) + (*gpa & PAGEOFFSET)); + + *gpa = -1; + + return (WALK_DONE); +} + +static int +kvm_mdb_gpa2qva(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) +{ + struct kvm kvm; + uintptr_t gpa = addr, gfn, kaddr; + int i; + + if (!(flags & DCMD_ADDRSPEC) || argc < 1) + return (DCMD_USAGE); + + switch (argv[0].a_type) { + case MDB_TYPE_STRING: + kaddr = mdb_strtoull(argv[0].a_un.a_str); + break; + + case MDB_TYPE_IMMEDIATE: + kaddr = argv[0].a_un.a_val; + break; + + default: + return (DCMD_USAGE); + } + + if (mdb_vread(&kvm, sizeof (kvm), kaddr) == -1) { + mdb_warn("couldn't read kvm at %p", kaddr); + return (DCMD_ERR); + } + + gfn = gpa >> PAGESHIFT; + + /* + * First unalias our guest PFN... + */ + if (mdb_pwalk("kvm_mem_alias", + (mdb_walk_cb_t)kvm_mdb_gpa2qva_walk_alias, &gfn, kaddr) == -1) { + mdb_warn("failed to walk 'kvm_memory_slot' for %p", kaddr); + return (DCMD_ERR); + } + + gpa = (gfn << PAGESHIFT) | (gpa & PAGEOFFSET); + + /* + * Now walk memory slots looking for a match. + */ + if (mdb_pwalk("kvm_memory_slot", + (mdb_walk_cb_t)kvm_mdb_gpa2qva_walk_slot, &gpa, kaddr) == -1) { + mdb_warn("failed to walk 'kvm_memory_slot' for %p", kaddr); + return (DCMD_ERR); + } + + if (gpa != -1) { + mdb_warn("0x%p is unknown for kvm 0x%p", addr, kaddr); + return (DCMD_ERR); + } + + return (DCMD_OK); +} + +static const mdb_dcmd_t dcmds[] = { + { "kvm_gpa2qva", "?[address of kvm]", "translate a guest physical " + "to a QEMU virtual address", kvm_mdb_gpa2qva }, + { NULL } +}; + +static const mdb_walker_t walkers[] = { + { "kvm_memory_slot", "walk kvm_memory_slot structures for a given kvm", + kvm_mdb_memory_slot_init, kvm_mdb_memory_slot_step }, + { "kvm_mem_alias", "walk kvm_mem_alias structures for a given kvm", + kvm_mdb_mem_alias_init, kvm_mdb_mem_alias_step }, + { NULL } +}; + +static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers }; + +const mdb_modinfo_t * +_mdb_init(void) +{ + return (&modinfo); +} -- cgit v1.2.3