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:
parent
dcaed66cbe
commit
e9628441df
@ -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
|
0x000b8090: 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720
|
||||||
@end smallexample
|
@end smallexample
|
||||||
@end itemize
|
@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
|
ETEXI
|
||||||
|
|
||||||
{
|
{
|
||||||
|
101
monitor.c
101
monitor.c
@ -1421,6 +1421,107 @@ static void hmp_physical_memory_dump(Monitor *mon, const QDict *qdict)
|
|||||||
memory_dump(mon, count, format, size, addr, 1);
|
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)
|
static void do_print(Monitor *mon, const QDict *qdict)
|
||||||
{
|
{
|
||||||
int format = qdict_get_int(qdict, "format");
|
int format = qdict_get_int(qdict, "format");
|
||||||
|
Loading…
Reference in New Issue
Block a user