libkvm: support access to vmm guest memory, allow writes to fwmem and vmm

This change consists of two parts:
- allow libkvm to recognize /dev/vmm/* character devices as devices that
  provide access to the physical memory of a system (similarly to /dev/fwmem*)
- allow libkvm to recognize that /dev/vmm/* and /dev/fwmem* devices provide
  access to the physical memory of live remote systems and, thus, the memory
  is writable

As a result, it should be possible to run commands like
$ kgdb -w /path/to/kernel /dev/fwmem0.0
$ kgdb /path/to/kernel /dev/vmm/guest

Reviewed by:	kib, jhb
MFC after:	2 weeks
Relnotes:	yes
Sponsored by:	Panzura
Differential Revision: https://reviews.freebsd.org/D8679
This commit is contained in:
Andriy Gapon 2016-12-27 10:17:56 +00:00
parent 44fcad033f
commit 7502cc401b
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=310630
3 changed files with 49 additions and 7 deletions

View File

@ -99,6 +99,7 @@
#define _PATH_VARDB "/var/db/"
#define _PATH_VARRUN "/var/run/"
#define _PATH_VARTMP "/var/tmp/"
#define _PATH_DEVVMM "/dev/vmm/"
#define _PATH_YP "/var/yp/"
#define _PATH_UUCPLOCK "/var/spool/lock/"

View File

@ -167,8 +167,10 @@ _kvm_open(kvm_t *kd, const char *uf, const char *mf, int flag, char *errout)
return (kd);
}
}
/*
* This is a crash dump.
* This is either a crash dump or a remote live system with its physical
* memory fully accessible via a special device.
* Open the namelist fd and determine the architecture.
*/
if ((kd->nlfd = open(uf, O_RDONLY | O_CLOEXEC, 0)) < 0) {
@ -177,8 +179,11 @@ _kvm_open(kvm_t *kd, const char *uf, const char *mf, int flag, char *errout)
}
if (_kvm_read_kernel_ehdr(kd) < 0)
goto failed;
if (strncmp(mf, _PATH_FWMEM, strlen(_PATH_FWMEM)) == 0)
if (strncmp(mf, _PATH_FWMEM, strlen(_PATH_FWMEM)) == 0 ||
strncmp(mf, _PATH_DEVVMM, strlen(_PATH_DEVVMM)) == 0) {
kd->rawdump = 1;
kd->writable = 1;
}
SET_FOREACH(parch, kvm_arch) {
if ((*parch)->ka_probe(kd)) {
kd->arch = *parch;
@ -405,6 +410,15 @@ ssize_t
kvm_write(kvm_t *kd, u_long kva, const void *buf, size_t len)
{
int cc;
ssize_t cw;
off_t pa;
const char *cp;
if (!ISALIVE(kd) && !kd->writable) {
_kvm_err(kd, kd->program,
"kvm_write not implemented for dead kernels");
return (-1);
}
if (ISALIVE(kd)) {
/*
@ -422,12 +436,38 @@ kvm_write(kvm_t *kd, u_long kva, const void *buf, size_t len)
} else if ((size_t)cc < len)
_kvm_err(kd, kd->program, "short write");
return (cc);
} else {
_kvm_err(kd, kd->program,
"kvm_write not implemented for dead kernels");
return (-1);
}
/* NOTREACHED */
cp = buf;
while (len > 0) {
cc = kd->arch->ka_kvatop(kd, kva, &pa);
if (cc == 0)
return (-1);
if (cc > (ssize_t)len)
cc = len;
errno = 0;
if (lseek(kd->pmfd, pa, 0) == -1 && errno != 0) {
_kvm_syserr(kd, 0, _PATH_MEM);
break;
}
cw = write(kd->pmfd, cp, cc);
if (cw < 0) {
_kvm_syserr(kd, kd->program, "kvm_write");
break;
}
/*
* If ka_kvatop returns a bogus value or our core file is
* truncated, we might wind up seeking beyond the end of the
* core file in which case the read will return 0 (EOF).
*/
if (cw == 0)
break;
cp += cw;
kva += cw;
len -= cw;
}
return (cp - (char *)buf);
}
int

View File

@ -78,6 +78,7 @@ struct __kvm {
*/
struct vmstate *vmst;
int rawdump; /* raw dump format */
int writable; /* physical memory is writable */
int vnet_initialized; /* vnet fields set up */
kvaddr_t vnet_start; /* start of kernel's vnet region */