Skip to content

Commit

Permalink
Add support for writing to guest memory in the debug server.
Browse files Browse the repository at this point in the history
- 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'.

Reviewed by:	markj, Scott Phillips <[email protected]>
MFC after:	2 weeks
Differential Revision:	https://reviews.freebsd.org/D20307
  • Loading branch information
bsdjhb committed May 24, 2019
1 parent 1379d32 commit 0429620
Show file tree
Hide file tree
Showing 3 changed files with 153 additions and 14 deletions.
134 changes: 129 additions & 5 deletions usr.sbin/bhyve/gdb.c
Original file line number Diff line number Diff line change
Expand Up @@ -767,15 +767,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) {
Expand Down Expand Up @@ -861,6 +870,119 @@ 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 = parse_byte(data) |
(parse_byte(data + 2) << 8);
} else {
bytes = 4;
val = parse_byte(data) |
(parse_byte(data + 2) << 8) |
(parse_byte(data + 4) << 16) |
(parse_byte(data + 6) << 24);
}
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)
{
Expand Down Expand Up @@ -1000,6 +1122,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;

Expand Down Expand Up @@ -1035,7 +1160,6 @@ handle_command(const uint8_t *data, size_t len)
finish_packet();
break;
case 'G': /* TODO */
case 'M': /* TODO */
case 'v':
/* Handle 'vCont' */
/* 'vCtrlC' */
Expand Down
31 changes: 22 additions & 9 deletions usr.sbin/bhyve/mem.c
Original file line number Diff line number Diff line change
Expand Up @@ -251,30 +251,43 @@ emulate_mem(struct vmctx *ctx, int vcpu, uint64_t paddr, struct vie *vie,
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
Expand Down
2 changes: 2 additions & 0 deletions usr.sbin/bhyve/mem.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,5 +61,7 @@ int read_mem(struct vmctx *ctx, int vcpu, uint64_t gpa, uint64_t *rval,
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_ */

0 comments on commit 0429620

Please sign in to comment.