svn commit: r353703 - stable/12/usr.sbin/bhyve

John Baldwin jhb at FreeBSD.org
Thu Oct 17 23:17:58 UTC 2019


Author: jhb
Date: Thu Oct 17 23:17:56 2019
New Revision: 353703
URL: https://svnweb.freebsd.org/changeset/base/353703

Log:
  MFC 348212,348712: Add support for writing to guest memory in the debug server.
  
  348212:
  Add support for writing to guest memory in the debug server.
  
  - Add a write_mem counterpart to read_mem to handle writes to MMIO.
  - Add support for the GDB 'M' packet to write bytes to the guest's
    memory.  For MMIO writes, attempt to batch writes up into words.
    This is imprecise, but if you write a single 2 or 4-byte aligned
    word, it should be treated as a single MMIO write operation.
  - While here, tidy up the parsing of the 'm' command used for reading
    memory to match 'M'.
  
  348712:
  Use parse_integer to avoid sign extension.
  
  Coverity warned about gdb_write_mem sign extending the result of
  parse_byte shifted left by 24 bits when generating a 32-bit memory
  write value for MMIO.  Simplify the code by using parse_integer
  instead of unrolled parse_byte calls.

Modified:
  stable/12/usr.sbin/bhyve/gdb.c
  stable/12/usr.sbin/bhyve/mem.c
  stable/12/usr.sbin/bhyve/mem.h
Directory Properties:
  stable/12/   (props changed)

Modified: stable/12/usr.sbin/bhyve/gdb.c
==============================================================================
--- stable/12/usr.sbin/bhyve/gdb.c	Thu Oct 17 22:37:25 2019	(r353702)
+++ stable/12/usr.sbin/bhyve/gdb.c	Thu Oct 17 23:17:56 2019	(r353703)
@@ -33,6 +33,7 @@ __FBSDID("$FreeBSD$");
 #ifndef WITHOUT_CAPSICUM
 #include <sys/capsicum.h>
 #endif
+#include <sys/endian.h>
 #include <sys/ioctl.h>
 #include <sys/mman.h>
 #include <sys/socket.h>
@@ -768,15 +769,24 @@ gdb_read_mem(const uint8_t *data, size_t len)
 	bool started;
 	int error;
 
+	/* Skip 'm' */
+	data += 1;
+	len -= 1;
+
+	/* Parse and consume address. */
 	cp = memchr(data, ',', len);
-	if (cp == NULL) {
+	if (cp == NULL || cp == data) {
 		send_error(EINVAL);
 		return;
 	}
-	gva = parse_integer(data + 1, cp - (data + 1));
-	resid = parse_integer(cp + 1, len - (cp + 1 - data));
-	started = false;
+	gva = parse_integer(data, cp - data);
+	len -= (cp - data) + 1;
+	data += (cp - data) + 1;
 
+	/* Parse length. */
+	resid = parse_integer(data, len);
+
+	started = false;
 	while (resid > 0) {
 		error = guest_vaddr2paddr(cur_vcpu, gva, &gpa);
 		if (error == -1) {
@@ -862,6 +872,115 @@ gdb_read_mem(const uint8_t *data, size_t len)
 	finish_packet();
 }
 
+static void
+gdb_write_mem(const uint8_t *data, size_t len)
+{
+	uint64_t gpa, gva, val;
+	uint8_t *cp;
+	size_t resid, todo, bytes;
+	int error;
+
+	/* Skip 'M' */
+	data += 1;
+	len -= 1;
+
+	/* Parse and consume address. */
+	cp = memchr(data, ',', len);
+	if (cp == NULL || cp == data) {
+		send_error(EINVAL);
+		return;
+	}
+	gva = parse_integer(data, cp - data);
+	len -= (cp - data) + 1;
+	data += (cp - data) + 1;
+
+	/* Parse and consume length. */
+	cp = memchr(data, ':', len);
+	if (cp == NULL || cp == data) {
+		send_error(EINVAL);
+		return;
+	}
+	resid = parse_integer(data, cp - data);
+	len -= (cp - data) + 1;
+	data += (cp - data) + 1;
+
+	/* Verify the available bytes match the length. */
+	if (len != resid * 2) {
+		send_error(EINVAL);
+		return;
+	}
+
+	while (resid > 0) {
+		error = guest_vaddr2paddr(cur_vcpu, gva, &gpa);
+		if (error == -1) {
+			send_error(errno);
+			return;
+		}
+		if (error == 0) {
+			send_error(EFAULT);
+			return;
+		}
+
+		/* Write bytes to current page. */
+		todo = getpagesize() - gpa % getpagesize();
+		if (todo > resid)
+			todo = resid;
+
+		cp = paddr_guest2host(ctx, gpa, todo);
+		if (cp != NULL) {
+			/*
+			 * If this page is guest RAM, write it a byte
+			 * at a time.
+			 */
+			while (todo > 0) {
+				assert(len >= 2);
+				*cp = parse_byte(data);
+				data += 2;
+				len -= 2;
+				cp++;
+				gpa++;
+				gva++;
+				resid--;
+				todo--;
+			}
+		} else {
+			/*
+			 * If this page isn't guest RAM, try to handle
+			 * it via MMIO.  For MMIO requests, use
+			 * aligned writes of words when possible.
+			 */
+			while (todo > 0) {
+				if (gpa & 1 || todo == 1) {
+					bytes = 1;
+					val = parse_byte(data);
+				} else if (gpa & 2 || todo == 2) {
+					bytes = 2;
+					val = be16toh(parse_integer(data, 4));
+				} else {
+					bytes = 4;
+					val = be32toh(parse_integer(data, 8));
+				}
+				error = write_mem(ctx, cur_vcpu, gpa, val,
+				    bytes);
+				if (error == 0) {
+					gpa += bytes;
+					gva += bytes;
+					resid -= bytes;
+					todo -= bytes;
+					data += 2 * bytes;
+					len -= 2 * bytes;
+				} else {
+					send_error(EFAULT);
+					return;
+				}
+			}
+		}
+		assert(resid == 0 || gpa % getpagesize() == 0);
+	}
+	assert(len == 0);
+	send_ok();
+}
+
 static bool
 command_equals(const uint8_t *data, size_t len, const char *cmd)
 {
@@ -1001,6 +1120,9 @@ handle_command(const uint8_t *data, size_t len)
 	case 'm':
 		gdb_read_mem(data, len);
 		break;
+	case 'M':
+		gdb_write_mem(data, len);
+		break;
 	case 'T': {
 		int tid;
 
@@ -1036,7 +1158,6 @@ handle_command(const uint8_t *data, size_t len)
 		finish_packet();
 		break;
 	case 'G': /* TODO */
-	case 'M': /* TODO */
 	case 'v':
 		/* Handle 'vCont' */
 		/* 'vCtrlC' */

Modified: stable/12/usr.sbin/bhyve/mem.c
==============================================================================
--- stable/12/usr.sbin/bhyve/mem.c	Thu Oct 17 22:37:25 2019	(r353702)
+++ stable/12/usr.sbin/bhyve/mem.c	Thu Oct 17 23:17:56 2019	(r353703)
@@ -251,30 +251,43 @@ emulate_mem(struct vmctx *ctx, int vcpu, uint64_t padd
 	return (access_memory(ctx, vcpu, paddr, emulate_mem_cb, &ema));
 }
 
-struct read_mem_args {
-	uint64_t *rval;
+struct rw_mem_args {
+	uint64_t *val;
 	int size;
+	int operation;
 };
 
 static int
-read_mem_cb(struct vmctx *ctx, int vcpu, uint64_t paddr, struct mem_range *mr,
+rw_mem_cb(struct vmctx *ctx, int vcpu, uint64_t paddr, struct mem_range *mr,
     void *arg)
 {
-	struct read_mem_args *rma;
+	struct rw_mem_args *rma;
 
 	rma = arg;
-	return (mr->handler(ctx, vcpu, MEM_F_READ, paddr, rma->size,
-	    rma->rval, mr->arg1, mr->arg2));
+	return (mr->handler(ctx, vcpu, rma->operation, paddr, rma->size,
+	    rma->val, mr->arg1, mr->arg2));
 }
 
 int
 read_mem(struct vmctx *ctx, int vcpu, uint64_t gpa, uint64_t *rval, int size)
 {
-	struct read_mem_args rma;
+	struct rw_mem_args rma;
 
-	rma.rval = rval;
+	rma.val = rval;
 	rma.size = size;
-	return (access_memory(ctx, vcpu, gpa, read_mem_cb, &rma));
+	rma.operation = MEM_F_READ;
+	return (access_memory(ctx, vcpu, gpa, rw_mem_cb, &rma));
+}
+
+int
+write_mem(struct vmctx *ctx, int vcpu, uint64_t gpa, uint64_t wval, int size)
+{
+	struct rw_mem_args rma;
+
+	rma.val = &wval;
+	rma.size = size;
+	rma.operation = MEM_F_WRITE;
+	return (access_memory(ctx, vcpu, gpa, rw_mem_cb, &rma));
 }
 
 static int

Modified: stable/12/usr.sbin/bhyve/mem.h
==============================================================================
--- stable/12/usr.sbin/bhyve/mem.h	Thu Oct 17 22:37:25 2019	(r353702)
+++ stable/12/usr.sbin/bhyve/mem.h	Thu Oct 17 23:17:56 2019	(r353703)
@@ -61,5 +61,7 @@ int	read_mem(struct vmctx *ctx, int vcpu, uint64_t gpa
 int	register_mem(struct mem_range *memp);
 int	register_mem_fallback(struct mem_range *memp);
 int	unregister_mem(struct mem_range *memp);
+int	write_mem(struct vmctx *ctx, int vcpu, uint64_t gpa, uint64_t wval,
+		  int size);
 
 #endif	/* _MEM_H_ */


More information about the svn-src-all mailing list