diff options
author | Stefan Kempf <stefan@cvs.openbsd.org> | 2016-01-16 08:55:41 +0000 |
---|---|---|
committer | Stefan Kempf <stefan@cvs.openbsd.org> | 2016-01-16 08:55:41 +0000 |
commit | 14bb73e7a860c71461c6ca641ece152b7bc71b46 (patch) | |
tree | b23d4d1171e6a8d62558116862a01ad0c6c647d4 | |
parent | 2b02d7d35660661bd94a10f72953957ce918f9b7 (diff) |
vmd(8) sometimes attempts page-crossing data copies between the host
and guest. The readpage/writepage ioctls of vmm(4) do not support this
and they return EINVAL on such attempts since recently.
Avoid page-crossing guest memory accesses by changing read_page() and
write_page() into read_mem() and write_mem() that can copy arbitrary
lengths of data between host<->guest without page-crossing accesses.
This also allows us to remove page-wise copy-loops in a few places.
ok mlarkin@
-rw-r--r-- | usr.sbin/vmd/loadfile_elf.c | 26 | ||||
-rw-r--r-- | usr.sbin/vmd/virtio.c | 169 | ||||
-rw-r--r-- | usr.sbin/vmd/vmd.h | 6 | ||||
-rw-r--r-- | usr.sbin/vmd/vmm.c | 80 |
4 files changed, 133 insertions, 148 deletions
diff --git a/usr.sbin/vmd/loadfile_elf.c b/usr.sbin/vmd/loadfile_elf.c index cd5771aeae8..6f93d50bed4 100644 --- a/usr.sbin/vmd/loadfile_elf.c +++ b/usr.sbin/vmd/loadfile_elf.c @@ -1,5 +1,5 @@ /* $NetBSD: loadfile.c,v 1.10 2000/12/03 02:53:04 tsutsui Exp $ */ -/* $OpenBSD: loadfile_elf.c,v 1.8 2016/01/05 06:55:28 mlarkin Exp $ */ +/* $OpenBSD: loadfile_elf.c,v 1.9 2016/01/16 08:55:40 stefan Exp $ */ /*- * Copyright (c) 1997 The NetBSD Foundation, Inc. @@ -191,7 +191,7 @@ push_gdt(void) setsegment(&sd[1], 0, 0xffffffff, SDT_MEMERA, SEL_KPL, 1, 1); setsegment(&sd[2], 0, 0xffffffff, SDT_MEMRWA, SEL_KPL, 1, 1); - write_page(GDT_PAGE, gdtpage, PAGE_SIZE, 1); + write_mem(GDT_PAGE, gdtpage, PAGE_SIZE, 1); } /* @@ -302,7 +302,7 @@ push_bootargs(int mem_sz) ba[sz + 2] = (int)sizeof(bios_consdev_t) + 3 * sizeof(int); memcpy(&ba[sz + 3], &consdev, sizeof(bios_consdev_t)); - write_page(BOOTARGS_PAGE, ba, PAGE_SIZE, 1); + write_mem(BOOTARGS_PAGE, ba, PAGE_SIZE, 1); } /* @@ -350,7 +350,7 @@ push_stack(int mem_sz, uint32_t end) stack[--loc] = 0x0; stack[--loc] = 0x0; - write_page(STACK_PAGE, &stack, PAGE_SIZE, 1); + write_mem(STACK_PAGE, &stack, PAGE_SIZE, 1); return (1024 - (loc - 1)) * sizeof(uint32_t); } @@ -379,7 +379,7 @@ mread(int fd, uint32_t addr, size_t sz) /* * break up the 'sz' bytes into PAGE_SIZE chunks for use with - * write_page + * write_mem */ ct = 0; rd = 0; @@ -397,7 +397,7 @@ mread(int fd, uint32_t addr, size_t sz) } rd += ct; - if (write_page(addr, buf, ct, 1)) + if (write_mem(addr, buf, ct, 1)) return (0); addr += ct; @@ -421,7 +421,7 @@ mread(int fd, uint32_t addr, size_t sz) } rd += ct; - if (write_page(addr, buf, ct, 1)) + if (write_mem(addr, buf, ct, 1)) return (0); } @@ -449,7 +449,7 @@ marc4random_buf(uint32_t addr, int sz) /* * break up the 'sz' bytes into PAGE_SIZE chunks for use with - * write_page + * write_mem */ ct = 0; if (addr % PAGE_SIZE != 0) { @@ -458,7 +458,7 @@ marc4random_buf(uint32_t addr, int sz) arc4random_buf(buf, ct); - if (write_page(addr, buf, ct, 1)) + if (write_mem(addr, buf, ct, 1)) return; addr += ct; @@ -473,7 +473,7 @@ marc4random_buf(uint32_t addr, int sz) arc4random_buf(buf, ct); - if (write_page(addr, buf, ct, 1)) + if (write_mem(addr, buf, ct, 1)) return; } } @@ -499,14 +499,14 @@ mbzero(uint32_t addr, int sz) /* * break up the 'sz' bytes into PAGE_SIZE chunks for use with - * write_page + * write_mem */ ct = 0; memset(buf, 0, sizeof(buf)); if (addr % PAGE_SIZE != 0) { ct = PAGE_SIZE - (addr % PAGE_SIZE); - if (write_page(addr, buf, ct, 1)) + if (write_mem(addr, buf, ct, 1)) return; addr += ct; @@ -518,7 +518,7 @@ mbzero(uint32_t addr, int sz) else ct = PAGE_SIZE; - if (write_page(addr, buf, ct, 1)) + if (write_mem(addr, buf, ct, 1)) return; } } diff --git a/usr.sbin/vmd/virtio.c b/usr.sbin/vmd/virtio.c index 68e685654b5..afb59c8a846 100644 --- a/usr.sbin/vmd/virtio.c +++ b/usr.sbin/vmd/virtio.c @@ -1,4 +1,4 @@ -/* $OpenBSD: virtio.c,v 1.7 2016/01/14 02:46:40 mlarkin Exp $ */ +/* $OpenBSD: virtio.c,v 1.8 2016/01/16 08:55:40 stefan Exp $ */ /* * Copyright (c) 2015 Mike Larkin <mlarkin@openbsd.org> @@ -143,25 +143,11 @@ viornd_update_qa(void) viornd.vq[viornd.cfg.queue_select].qa = viornd.cfg.queue_address; } -static int -push_virtio_ring(char *buf, uint32_t gpa, uint32_t vr_sz) -{ - uint32_t i; - - for (i = 0; i < vr_sz; i += VIRTIO_PAGE_SIZE) { - if (write_page((uint32_t)gpa + i, buf + i, PAGE_SIZE, 0)) { - return (1); - } - } - - return (0); -} - int viornd_notifyq(void) { uint64_t q_gpa; - uint32_t vr_sz, i; + uint32_t vr_sz; int ret; char *buf, *rnd_data; struct vring_desc *desc; @@ -186,11 +172,9 @@ viornd_notifyq(void) memset(buf, 0, vr_sz); - for (i = 0; i < vr_sz; i += VIRTIO_PAGE_SIZE) { - if (read_page((uint32_t)q_gpa + i, buf + i, PAGE_SIZE, 0)) { - free(buf); - return (0); - } + if (read_mem((uint32_t)q_gpa, buf, vr_sz, 0)) { + free(buf); + return (0); } desc = (struct vring_desc *)(buf); @@ -204,7 +188,7 @@ viornd_notifyq(void) if (rnd_data != NULL) { arc4random_buf(rnd_data, desc[avail->ring[avail->idx]].len); - if (write_page((uint32_t)(desc[avail->ring[avail->idx]].addr), + if (write_mem((uint32_t)(desc[avail->ring[avail->idx]].addr), rnd_data, desc[avail->ring[avail->idx]].len, 0)) { log_warnx("viornd: can't write random data @ " "0x%llx", @@ -219,7 +203,7 @@ viornd_notifyq(void) desc[avail->ring[avail->idx]].len; used->idx++; - if (push_virtio_ring(buf, q_gpa, vr_sz)) { + if (write_mem(q_gpa, buf, vr_sz, 0)) { log_warnx("viornd: error writing vio ring"); } } @@ -372,7 +356,7 @@ int vioblk_notifyq(struct vioblk_dev *dev) { uint64_t q_gpa; - uint32_t vr_sz, i, j, len; //, osz; + uint32_t vr_sz; //, osz; uint16_t idx, cmd_desc_idx, secdata_desc_idx, ds_desc_idx; //, dxx; uint8_t ds; int ret; @@ -401,13 +385,10 @@ vioblk_notifyq(struct vioblk_dev *dev) memset(vr, 0, vr_sz); - for (i = 0; i < vr_sz; i += VIRTIO_PAGE_SIZE) { - if (read_page((uint32_t)q_gpa + i, vr + i, PAGE_SIZE, 0)) { - log_warnx("error reading gpa 0x%x", - (uint32_t)q_gpa + i); - free(vr); - return (0); - } + if (read_mem((uint32_t)q_gpa, vr, vr_sz, 0)) { + log_warnx("error reading gpa 0x%x", (uint32_t)q_gpa); + free(vr); + return (0); } /* Compute offsets in ring of descriptors, avail ring, and used ring */ @@ -437,8 +418,8 @@ vioblk_notifyq(struct vioblk_dev *dev) } /* Read command from descriptor ring */ - if (read_page((uint32_t)cmd_desc->addr, &cmd, cmd_desc->len, 0)) { - log_warnx("vioblk: command read_page error @ 0x%llx", + if (read_mem((uint32_t)cmd_desc->addr, &cmd, cmd_desc->len, 0)) { + log_warnx("vioblk: command read_mem error @ 0x%llx", cmd_desc->addr); free(vr); return (0); @@ -473,26 +454,15 @@ vioblk_notifyq(struct vioblk_dev *dev) return (0); } - j = 0; - while (j < secdata_desc->len) { - if (secdata_desc->len - j >= PAGE_SIZE) - len = PAGE_SIZE; - else - len = secdata_desc->len - j; - - if (write_page((uint32_t)secdata_desc->addr + j, - secdata + j, len, 0)) { - log_warnx("can't write sector " - "data to gpa @ 0x%llx", - secdata_desc->addr); - dump_descriptor_chain(desc, - cmd_desc_idx); - free(vr); - free(secdata); - return (0); - } - - j += PAGE_SIZE; + if (write_mem((uint32_t)secdata_desc->addr, secdata, + secdata_desc->len, 0)) { + log_warnx("can't write sector " + "data to gpa @ 0x%llx", + secdata_desc->addr); + dump_descriptor_chain(desc, cmd_desc_idx); + free(vr); + free(secdata); + return (0); } free(secdata); @@ -507,7 +477,7 @@ vioblk_notifyq(struct vioblk_dev *dev) ds_desc = secdata_desc; ds = VIRTIO_BLK_S_OK; - if (write_page((uint32_t)ds_desc->addr, + if (write_mem((uint32_t)ds_desc->addr, &ds, ds_desc->len, 0)) { log_warnx("can't write device status data @ " "0x%llx", ds_desc->addr); @@ -526,7 +496,7 @@ vioblk_notifyq(struct vioblk_dev *dev) dev->vq[dev->cfg.queue_notify].last_avail = avail->idx & VIOBLK_QUEUE_MASK; - if (push_virtio_ring(vr, q_gpa, vr_sz)) { + if (write_mem(q_gpa, vr, vr_sz, 0)) { log_warnx("vioblk: error writing vio ring"); } break; @@ -551,25 +521,15 @@ vioblk_notifyq(struct vioblk_dev *dev) secbias = 0; do { - j = 0; - while (j < secdata_desc->len) { - if (secdata_desc->len - j >= PAGE_SIZE) - len = PAGE_SIZE; - else - len = secdata_desc->len - j; - if (read_page((uint32_t)secdata_desc->addr + j, - secdata + j, len, 0)) { - log_warnx("wr vioblk: can't read " - "sector data @ 0x%llx", - secdata_desc->addr); - dump_descriptor_chain(desc, - cmd_desc_idx); - free(vr); - free(secdata); - return (0); - } - - j += PAGE_SIZE; + if (read_mem((uint32_t)secdata_desc->addr, secdata, + secdata_desc->len, 0)) { + log_warnx("wr vioblk: can't read " + "sector data @ 0x%llx", + secdata_desc->addr); + dump_descriptor_chain(desc, cmd_desc_idx); + free(vr); + free(secdata); + return (0); } if (vioblk_do_write(dev, cmd.sector + secbias, @@ -593,7 +553,7 @@ vioblk_notifyq(struct vioblk_dev *dev) ds_desc = secdata_desc; ds = VIRTIO_BLK_S_OK; - if (write_page((uint32_t)ds_desc->addr, + if (write_mem((uint32_t)ds_desc->addr, &ds, ds_desc->len, 0)) { log_warnx("wr vioblk: can't write device status " "data @ 0x%llx", ds_desc->addr); @@ -610,7 +570,7 @@ vioblk_notifyq(struct vioblk_dev *dev) dev->vq[dev->cfg.queue_notify].last_avail = avail->idx & VIOBLK_QUEUE_MASK; - if (push_virtio_ring(vr, q_gpa, vr_sz)) + if (write_mem(q_gpa, vr, vr_sz, 0)) log_warnx("wr vioblk: error writing vio ring"); break; case VIRTIO_BLK_T_FLUSH: @@ -619,7 +579,7 @@ vioblk_notifyq(struct vioblk_dev *dev) ds_desc = &desc[ds_desc_idx]; ds = VIRTIO_BLK_S_OK; - if (write_page((uint32_t)ds_desc->addr, + if (write_mem((uint32_t)ds_desc->addr, &ds, ds_desc->len, 0)) { log_warnx("fl vioblk: can't write device status " "data @ 0x%llx", ds_desc->addr); @@ -636,7 +596,7 @@ vioblk_notifyq(struct vioblk_dev *dev) dev->vq[dev->cfg.queue_notify].last_avail = avail->idx & VIOBLK_QUEUE_MASK; - if (push_virtio_ring(vr, q_gpa, vr_sz)) { + if (write_mem(q_gpa, vr, vr_sz, 0)) { log_warnx("fl vioblk: error writing vio ring"); } break; @@ -826,7 +786,7 @@ int vionet_enq_rx(struct vionet_dev *dev, char *pkt, ssize_t sz, int *spc) { uint64_t q_gpa; - uint32_t vr_sz, i; + uint32_t vr_sz; uint16_t idx, pkt_desc_idx, hdr_desc_idx; int ret; char *vr; @@ -848,13 +808,10 @@ vionet_enq_rx(struct vionet_dev *dev, char *pkt, ssize_t sz, int *spc) memset(vr, 0, vr_sz); - for (i = 0; i < vr_sz; i += VIRTIO_PAGE_SIZE) { - if (read_page((uint32_t)q_gpa + i, vr + i, PAGE_SIZE, 0)) { - log_warnx("rx enq: error reading gpa 0x%x", - (uint32_t)q_gpa + i); - free(vr); - return (0); - } + if (read_mem((uint32_t)q_gpa, vr, vr_sz, 0)) { + log_warnx("rx enq: error reading gpa 0x%x", (uint32_t)q_gpa); + free(vr); + return (0); } /* Compute offsets in ring of descriptors, avail ring, and used ring */ @@ -887,8 +844,8 @@ vionet_enq_rx(struct vionet_dev *dev, char *pkt, ssize_t sz, int *spc) } /* Write packet to descriptor ring */ - if (write_page((uint32_t)pkt_desc->addr, pkt, sz, 0)) { - log_warnx("vionet: rx enq packet write_page error @ " + if (write_mem((uint32_t)pkt_desc->addr, pkt, sz, 0)) { + log_warnx("vionet: rx enq packet write_mem error @ " "0x%llx", pkt_desc->addr); free(vr); return (0); @@ -901,7 +858,7 @@ vionet_enq_rx(struct vionet_dev *dev, char *pkt, ssize_t sz, int *spc) used->idx++; dev->vq[0].last_avail = (dev->vq[0].last_avail + 1); *spc = avail->idx - dev->vq[0].last_avail; - if (push_virtio_ring(vr, q_gpa, vr_sz)) { + if (write_mem(q_gpa, vr, vr_sz, 0)) { log_warnx("vionet: error writing vio ring"); } @@ -958,7 +915,7 @@ void vionet_notify_rx(struct vionet_dev *dev) { uint64_t q_gpa; - uint32_t vr_sz, i; + uint32_t vr_sz; uint16_t idx, pkt_desc_idx; char *vr; struct vring_desc *desc, *pkt_desc; @@ -977,13 +934,10 @@ vionet_notify_rx(struct vionet_dev *dev) memset(vr, 0, vr_sz); - for (i = 0; i < vr_sz; i += VIRTIO_PAGE_SIZE) { - if (read_page((uint32_t)q_gpa + i, vr + i, PAGE_SIZE, 0)) { - log_warnx("error reading gpa 0x%x", - (uint32_t)q_gpa + i); - free(vr); - return; - } + if (read_mem((uint32_t)q_gpa, vr, vr_sz, 0)) { + log_warnx("error reading gpa 0x%x", (uint32_t)q_gpa); + free(vr); + return; } /* Compute offsets in ring of descriptors, avail ring, and used ring */ @@ -1011,7 +965,7 @@ int vionet_notifyq(struct vionet_dev *dev) { uint64_t q_gpa; - uint32_t vr_sz, i; + uint32_t vr_sz; uint16_t idx, pkt_desc_idx, hdr_desc_idx, dxx; size_t pktsz; int ret, num_enq, ofs; @@ -1041,12 +995,9 @@ vionet_notifyq(struct vionet_dev *dev) memset(vr, 0, vr_sz); - for (i = 0; i < vr_sz; i += VIRTIO_PAGE_SIZE) { - if (read_page((uint32_t)q_gpa + i, vr + i, PAGE_SIZE, 0)) { - log_warnx("error reading gpa 0x%x", - (uint32_t)q_gpa + i); - goto out; - } + if (read_mem((uint32_t)q_gpa, vr, vr_sz, 0)) { + log_warnx("error reading gpa 0x%x", (uint32_t)q_gpa); + goto out; } /* Compute offsets in ring of descriptors, avail ring, and used ring */ @@ -1105,9 +1056,9 @@ vionet_notifyq(struct vionet_dev *dev) } /* Read packet from descriptor ring */ - if (read_page((uint32_t)pkt_desc->addr, pkt + ofs, + if (read_mem((uint32_t)pkt_desc->addr, pkt + ofs, pkt_desc->len, 0)) { - log_warnx("vionet: packet read_page error " + log_warnx("vionet: packet read_mem error " "@ 0x%llx", pkt_desc->addr); goto out; } @@ -1125,9 +1076,9 @@ vionet_notifyq(struct vionet_dev *dev) } /* Read packet from descriptor ring */ - if (read_page((uint32_t)pkt_desc->addr, pkt + ofs, + if (read_mem((uint32_t)pkt_desc->addr, pkt + ofs, pkt_desc->len, 0)) { - log_warnx("vionet: packet read_page error @ " + log_warnx("vionet: packet read_mem error @ " "0x%llx", pkt_desc->addr); goto out; } @@ -1153,7 +1104,7 @@ vionet_notifyq(struct vionet_dev *dev) VIONET_QUEUE_MASK; } - if (push_virtio_ring(vr, q_gpa, vr_sz)) { + if (write_mem(q_gpa, vr, vr_sz, 0)) { log_warnx("vionet: tx error writing vio ring"); } diff --git a/usr.sbin/vmd/vmd.h b/usr.sbin/vmd/vmd.h index 0df024978ba..97a2ebdbba1 100644 --- a/usr.sbin/vmd/vmd.h +++ b/usr.sbin/vmd/vmd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: vmd.h,v 1.17 2016/01/02 15:05:21 benno Exp $ */ +/* $OpenBSD: vmd.h,v 1.18 2016/01/16 08:55:40 stefan Exp $ */ /* * Copyright (c) 2015 Mike Larkin <mlarkin@openbsd.org> @@ -114,8 +114,8 @@ char *get_string(uint8_t *, size_t); /* vmm.c */ pid_t vmm(struct privsep *, struct privsep_proc *); -int write_page(uint32_t dst, void *buf, uint32_t, int); -int read_page(uint32_t dst, void *buf, uint32_t, int); +int write_mem(uint32_t dst, void *buf, uint32_t, int); +int read_mem(uint32_t dst, void *buf, uint32_t, int); int opentap(void); /* control.c */ diff --git a/usr.sbin/vmd/vmm.c b/usr.sbin/vmd/vmm.c index 5acbdfadf3a..119e0ac37e0 100644 --- a/usr.sbin/vmd/vmm.c +++ b/usr.sbin/vmd/vmm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vmm.c,v 1.19 2016/01/13 12:55:18 reyk Exp $ */ +/* $OpenBSD: vmm.c,v 1.20 2016/01/16 08:55:40 stefan Exp $ */ /* * Copyright (c) 2015 Mike Larkin <mlarkin@openbsd.org> @@ -1477,17 +1477,16 @@ vcpu_exit(struct vm_run_params *vrp) } /* - * write_page + * write_mem * - * Pushes a page of data from 'buf' into the guest VM's memory - * at paddr 'dst'. + * Pushes data from 'buf' into the guest VM's memory at paddr 'dst'. * * Parameters: * dst: the destination paddr_t in the guest VM to push into. * If there is no guest paddr mapping at 'dst', a new page will be * faulted in by the VMM (provided 'dst' represents a valid paddr * in the guest's address space) - * buf: page of data to push + * buf: data to push * len: size of 'buf' * do_mask: 1 to mask the destination address (for kernel load), 0 to * leave 'dst' unmasked @@ -1499,8 +1498,10 @@ vcpu_exit(struct vm_run_params *vrp) * Note - this function only handles GPAs < 4GB. */ int -write_page(uint32_t dst, void *buf, uint32_t len, int do_mask) +write_mem(uint32_t dst, void *buf, uint32_t len, int do_mask) { + char *p = buf; + uint32_t gpa, n, left; struct vm_writepage_params vwp; /* @@ -1510,21 +1511,36 @@ write_page(uint32_t dst, void *buf, uint32_t len, int do_mask) if (do_mask) dst &= 0xFFFFFFF; - vwp.vwp_paddr = (paddr_t)dst; - vwp.vwp_data = buf; - vwp.vwp_vm_id = vm_id; - vwp.vwp_len = len; - if (ioctl(env->vmd_fd, VMM_IOC_WRITEPAGE, &vwp) < 0) { - log_warn("writepage ioctl failed"); - return (errno); + left = len; + for (gpa = dst; gpa < dst + len; + gpa = (gpa & ~PAGE_MASK) + PAGE_SIZE) { + n = left; + if (n > PAGE_SIZE) + n = PAGE_SIZE; + if (n > (PAGE_SIZE - (gpa & PAGE_MASK))) + n = PAGE_SIZE - (gpa & PAGE_MASK); + + vwp.vwp_paddr = (paddr_t)gpa; + vwp.vwp_data = p; + vwp.vwp_vm_id = vm_id; + vwp.vwp_len = n; + if (ioctl(env->vmd_fd, VMM_IOC_WRITEPAGE, &vwp) < 0) { + log_warn("writepage ioctl failed @ 0x%x: " + "dst = 0x%x, len = 0x%x", gpa, dst, len); + return (errno); + } + + left -= n; + p += n; } + return (0); } /* - * read_page + * read_mem * - * Reads a page of memory at guest paddr 'src' into 'buf'. + * Reads memory at guest paddr 'src' into 'buf'. * * Parameters: * src: the source paddr_t in the guest VM to read from. @@ -1540,10 +1556,13 @@ write_page(uint32_t dst, void *buf, uint32_t len, int do_mask) * Note - this function only handles GPAs < 4GB. */ int -read_page(uint32_t src, void *buf, uint32_t len, int do_mask) +read_mem(uint32_t src, void *buf, uint32_t len, int do_mask) { + char *p = buf; + uint32_t gpa, n, left; struct vm_readpage_params vrp; + /* * Mask kernel load addresses to avoid uint32_t -> uint64_t cast * errors @@ -1551,13 +1570,28 @@ read_page(uint32_t src, void *buf, uint32_t len, int do_mask) if (do_mask) src &= 0xFFFFFFF; - vrp.vrp_paddr = (paddr_t)src; - vrp.vrp_data = buf; - vrp.vrp_vm_id = vm_id; - vrp.vrp_len = len; - if (ioctl(env->vmd_fd, VMM_IOC_READPAGE, &vrp) < 0) { - log_warn("readpage ioctl failed"); - return (errno); + left = len; + for (gpa = src; gpa < src + len; + gpa = (gpa & ~PAGE_MASK) + PAGE_SIZE) { + n = left; + if (n > PAGE_SIZE) + n = PAGE_SIZE; + if (n > (PAGE_SIZE - (gpa & PAGE_MASK))) + n = PAGE_SIZE - (gpa & PAGE_MASK); + + vrp.vrp_paddr = (paddr_t)gpa; + vrp.vrp_data = p; + vrp.vrp_vm_id = vm_id; + vrp.vrp_len = n; + if (ioctl(env->vmd_fd, VMM_IOC_READPAGE, &vrp) < 0) { + log_warn("readpage ioctl failed @ 0x%x: " + "src = 0x%x, len = 0x%x", gpa, src, len); + return (errno); + } + + left -= n; + p += n; } + return (0); } |