hmp: gpa2hva and gpa2hpa hostaddr command

These commands are useful when testing machine-check passthrough.
gpa2hva is useful to inject a MADV_HWPOISON madvise from gdb, while
gpa2hpa is useful to inject an error with the mce-inject kernel
module.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: <1490021158-4469-1-git-send-email-pbonzini@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: <20170420133058.12911-1-pbonzini@redhat.com>
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
This commit is contained in:
Paolo Bonzini 2017-04-20 15:30:58 +02:00 committed by Dr. David Alan Gilbert
parent dcaed66cbe
commit e9628441df
2 changed files with 133 additions and 0 deletions

View File

@ -523,6 +523,38 @@ Dump 80 16 bit values at the start of the video memory.
0x000b8090: 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720
@end smallexample
@end itemize
ETEXI
{
.name = "gpa2hva",
.args_type = "addr:l",
.params = "addr",
.help = "print the host virtual address corresponding to a guest physical address",
.cmd = hmp_gpa2hva,
},
STEXI
@item gpa2hva @var{addr}
@findex gpa2hva
Print the host virtual address at which the guest's physical address @var{addr}
is mapped.
ETEXI
#ifdef CONFIG_LINUX
{
.name = "gpa2hpa",
.args_type = "addr:l",
.params = "addr",
.help = "print the host physical address corresponding to a guest physical address",
.cmd = hmp_gpa2hpa,
},
#endif
STEXI
@item gpa2hpa @var{addr}
@findex gpa2hpa
Print the host physical address at which the guest's physical address @var{addr}
is mapped.
ETEXI
{

101
monitor.c
View File

@ -1421,6 +1421,107 @@ static void hmp_physical_memory_dump(Monitor *mon, const QDict *qdict)
memory_dump(mon, count, format, size, addr, 1);
}
static void *gpa2hva(MemoryRegion **p_mr, hwaddr addr, Error **errp)
{
MemoryRegionSection mrs = memory_region_find(get_system_memory(),
addr, 1);
if (!mrs.mr) {
error_setg(errp, "No memory is mapped at address 0x%" HWADDR_PRIx, addr);
return NULL;
}
if (!memory_region_is_ram(mrs.mr) && !memory_region_is_romd(mrs.mr)) {
error_setg(errp, "Memory at address 0x%" HWADDR_PRIx "is not RAM", addr);
memory_region_unref(mrs.mr);
return NULL;
}
*p_mr = mrs.mr;
return qemu_map_ram_ptr(mrs.mr->ram_block, mrs.offset_within_region);
}
static void hmp_gpa2hva(Monitor *mon, const QDict *qdict)
{
hwaddr addr = qdict_get_int(qdict, "addr");
Error *local_err = NULL;
MemoryRegion *mr = NULL;
void *ptr;
ptr = gpa2hva(&mr, addr, &local_err);
if (local_err) {
error_report_err(local_err);
return;
}
monitor_printf(mon, "Host virtual address for 0x%" HWADDR_PRIx
" (%s) is %p\n",
addr, mr->name, ptr);
memory_region_unref(mr);
}
#ifdef CONFIG_LINUX
static uint64_t vtop(void *ptr, Error **errp)
{
uint64_t pinfo;
uint64_t ret = -1;
uintptr_t addr = (uintptr_t) ptr;
uintptr_t pagesize = getpagesize();
off_t offset = addr / pagesize * sizeof(pinfo);
int fd;
fd = open("/proc/self/pagemap", O_RDONLY);
if (fd == -1) {
error_setg_errno(errp, errno, "Cannot open /proc/self/pagemap");
return -1;
}
/* Force copy-on-write if necessary. */
atomic_add((uint8_t *)ptr, 0);
if (pread(fd, &pinfo, sizeof(pinfo), offset) != sizeof(pinfo)) {
error_setg_errno(errp, errno, "Cannot read pagemap");
goto out;
}
if ((pinfo & (1ull << 63)) == 0) {
error_setg(errp, "Page not present");
goto out;
}
ret = ((pinfo & 0x007fffffffffffffull) * pagesize) | (addr & (pagesize - 1));
out:
close(fd);
return ret;
}
static void hmp_gpa2hpa(Monitor *mon, const QDict *qdict)
{
hwaddr addr = qdict_get_int(qdict, "addr");
Error *local_err = NULL;
MemoryRegion *mr = NULL;
void *ptr;
uint64_t physaddr;
ptr = gpa2hva(&mr, addr, &local_err);
if (local_err) {
error_report_err(local_err);
return;
}
physaddr = vtop(ptr, &local_err);
if (local_err) {
error_report_err(local_err);
} else {
monitor_printf(mon, "Host physical address for 0x%" HWADDR_PRIx
" (%s) is 0x%" PRIx64 "\n",
addr, mr->name, (uint64_t) physaddr);
}
memory_region_unref(mr);
}
#endif
static void do_print(Monitor *mon, const QDict *qdict)
{
int format = qdict_get_int(qdict, "format");