|
@@ -195,30 +195,47 @@ vu_panic(VuDev *dev, const char *msg, ...)
|
|
*/
|
|
*/
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/* Search for a memory region that covers this guest physical address. */
|
|
|
|
+static VuDevRegion *
|
|
|
|
+vu_gpa_to_mem_region(VuDev *dev, uint64_t guest_addr)
|
|
|
|
+{
|
|
|
|
+ unsigned int i;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Memory regions cannot overlap in guest physical address space. Each
|
|
|
|
+ * GPA belongs to exactly one memory region, so there can only be one
|
|
|
|
+ * match.
|
|
|
|
+ */
|
|
|
|
+ for (i = 0; i < dev->nregions; i++) {
|
|
|
|
+ VuDevRegion *cur = &dev->regions[i];
|
|
|
|
+
|
|
|
|
+ if (guest_addr >= cur->gpa && guest_addr < cur->gpa + cur->size) {
|
|
|
|
+ return cur;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return NULL;
|
|
|
|
+}
|
|
|
|
+
|
|
/* Translate guest physical address to our virtual address. */
|
|
/* Translate guest physical address to our virtual address. */
|
|
void *
|
|
void *
|
|
vu_gpa_to_va(VuDev *dev, uint64_t *plen, uint64_t guest_addr)
|
|
vu_gpa_to_va(VuDev *dev, uint64_t *plen, uint64_t guest_addr)
|
|
{
|
|
{
|
|
- unsigned int i;
|
|
|
|
|
|
+ VuDevRegion *r;
|
|
|
|
|
|
if (*plen == 0) {
|
|
if (*plen == 0) {
|
|
return NULL;
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
- /* Find matching memory region. */
|
|
|
|
- for (i = 0; i < dev->nregions; i++) {
|
|
|
|
- VuDevRegion *r = &dev->regions[i];
|
|
|
|
-
|
|
|
|
- if ((guest_addr >= r->gpa) && (guest_addr < (r->gpa + r->size))) {
|
|
|
|
- if ((guest_addr + *plen) > (r->gpa + r->size)) {
|
|
|
|
- *plen = r->gpa + r->size - guest_addr;
|
|
|
|
- }
|
|
|
|
- return (void *)(uintptr_t)
|
|
|
|
- guest_addr - r->gpa + r->mmap_addr + r->mmap_offset;
|
|
|
|
- }
|
|
|
|
|
|
+ r = vu_gpa_to_mem_region(dev, guest_addr);
|
|
|
|
+ if (!r) {
|
|
|
|
+ return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
- return NULL;
|
|
|
|
|
|
+ if ((guest_addr + *plen) > (r->gpa + r->size)) {
|
|
|
|
+ *plen = r->gpa + r->size - guest_addr;
|
|
|
|
+ }
|
|
|
|
+ return (void *)(uintptr_t)guest_addr - r->gpa + r->mmap_addr +
|
|
|
|
+ r->mmap_offset;
|
|
}
|
|
}
|
|
|
|
|
|
/* Translate qemu virtual address to our virtual address. */
|
|
/* Translate qemu virtual address to our virtual address. */
|
|
@@ -854,8 +871,8 @@ static inline bool reg_equal(VuDevRegion *vudev_reg,
|
|
static bool
|
|
static bool
|
|
vu_rem_mem_reg(VuDev *dev, VhostUserMsg *vmsg) {
|
|
vu_rem_mem_reg(VuDev *dev, VhostUserMsg *vmsg) {
|
|
VhostUserMemoryRegion m = vmsg->payload.memreg.region, *msg_region = &m;
|
|
VhostUserMemoryRegion m = vmsg->payload.memreg.region, *msg_region = &m;
|
|
- unsigned int i;
|
|
|
|
- bool found = false;
|
|
|
|
|
|
+ unsigned int idx;
|
|
|
|
+ VuDevRegion *r;
|
|
|
|
|
|
if (vmsg->fd_num > 1) {
|
|
if (vmsg->fd_num > 1) {
|
|
vmsg_close_fds(vmsg);
|
|
vmsg_close_fds(vmsg);
|
|
@@ -882,28 +899,22 @@ vu_rem_mem_reg(VuDev *dev, VhostUserMsg *vmsg) {
|
|
DPRINT(" mmap_offset 0x%016"PRIx64"\n",
|
|
DPRINT(" mmap_offset 0x%016"PRIx64"\n",
|
|
msg_region->mmap_offset);
|
|
msg_region->mmap_offset);
|
|
|
|
|
|
- for (i = 0; i < dev->nregions; i++) {
|
|
|
|
- if (reg_equal(&dev->regions[i], msg_region)) {
|
|
|
|
- VuDevRegion *r = &dev->regions[i];
|
|
|
|
-
|
|
|
|
- munmap((void *)(uintptr_t)r->mmap_addr, r->size + r->mmap_offset);
|
|
|
|
-
|
|
|
|
- /* Shift all affected entries by 1 to close the hole at index. */
|
|
|
|
- memmove(dev->regions + i, dev->regions + i + 1,
|
|
|
|
- sizeof(VuDevRegion) * (dev->nregions - i - 1));
|
|
|
|
- DPRINT("Successfully removed a region\n");
|
|
|
|
- dev->nregions--;
|
|
|
|
- i--;
|
|
|
|
-
|
|
|
|
- found = true;
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (!found) {
|
|
|
|
|
|
+ r = vu_gpa_to_mem_region(dev, msg_region->guest_phys_addr);
|
|
|
|
+ if (!r || !reg_equal(r, msg_region)) {
|
|
|
|
+ vmsg_close_fds(vmsg);
|
|
vu_panic(dev, "Specified region not found\n");
|
|
vu_panic(dev, "Specified region not found\n");
|
|
|
|
+ return false;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ munmap((void *)(uintptr_t)r->mmap_addr, r->size + r->mmap_offset);
|
|
|
|
+
|
|
|
|
+ idx = r - dev->regions;
|
|
|
|
+ assert(idx < dev->nregions);
|
|
|
|
+ /* Shift all affected entries by 1 to close the hole. */
|
|
|
|
+ memmove(r, r + 1, sizeof(VuDevRegion) * (dev->nregions - idx - 1));
|
|
|
|
+ DPRINT("Successfully removed a region\n");
|
|
|
|
+ dev->nregions--;
|
|
|
|
+
|
|
vmsg_close_fds(vmsg);
|
|
vmsg_close_fds(vmsg);
|
|
|
|
|
|
return false;
|
|
return false;
|