Page MenuHomeFreeBSD
Paste P146

Masterwork From Distant Lands
ActivePublic

Authored by cem on Oct 10 2017, 9:47 PM.
commit d20373d3bfb8872cae43a8f2804e8a4d7aeb2e73
Author: Conrad Meyer <cem@FreeBSD.org>
Date: Tue Oct 10 13:43:50 2017 -0700
mem: Hack to allow libkvm to read device registers
diff --git a/sys/amd64/amd64/mem.c b/sys/amd64/amd64/mem.c
index 067da04dfc4f..9fb90767688f 100644
--- a/sys/amd64/amd64/mem.c
+++ b/sys/amd64/amd64/mem.c
@@ -73,6 +73,94 @@ __FBSDID("$FreeBSD$");
*/
MALLOC_DEFINE(M_MEMDESC, "memdesc", "memory range descriptors");
+static bool
+is_word_aligned(u_int len, u_long addr)
+{
+ return ((len == 8 && (addr & 7) == 0) || (len == 4 && (addr & 3) == 0)
+ || (len == 2 && (addr & 1) == 0));
+}
+
+static int
+alignmove(void *cp, u_int len, struct uio *uio)
+{
+ struct iovec *iov;
+ size_t cnt;
+ union {
+ uint64_t u64;
+ uint32_t u32;
+ uint16_t u16;
+ } devmem;
+ void *memp;
+ int error;
+
+ switch (len) {
+ case 8:
+ memp = &devmem.u64;
+ break;
+ case 4:
+ memp = &devmem.u32;
+ break;
+ case 2:
+ memp = &devmem.u16;
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ error = 0;
+ iov = uio->uio_iov;
+ cnt = iov->iov_len;
+ if (cnt > len)
+ cnt = len;
+
+ if (uio->uio_rw == UIO_WRITE) {
+ if (uio->uio_segflg == UIO_USERSPACE) {
+ error = copyin(iov->iov_base, memp, cnt);
+ if (error != 0)
+ goto out;
+ } else if (uio->uio_segflg == UIO_SYSSPACE)
+ bcopy(iov->iov_base, memp, cnt);
+
+ switch (len) {
+ case 8:
+ *(volatile uint64_t *)cp = devmem.u64;
+ break;
+ case 4:
+ *(volatile uint32_t *)cp = devmem.u32;
+ break;
+ case 2:
+ *(volatile uint16_t *)cp = devmem.u16;
+ break;
+ }
+ } else {
+ switch (len) {
+ case 8:
+ devmem.u64 = *(volatile uint64_t *)cp;
+ break;
+ case 4:
+ devmem.u32 = *(volatile uint32_t *)cp;
+ break;
+ case 2:
+ devmem.u16 = *(volatile uint16_t *)cp;
+ break;
+ }
+
+ if (uio->uio_segflg == UIO_USERSPACE) {
+ error = copyout(memp, iov->iov_base, cnt);
+ if (error != 0)
+ goto out;
+ } else if (uio->uio_segflg == UIO_SYSSPACE)
+ bcopy(memp, iov->iov_base, cnt);
+ }
+
+ iov->iov_base = (char *)iov->iov_base + cnt;
+ iov->iov_len -= cnt;
+ uio->uio_resid -= cnt;
+ uio->uio_offset += cnt;
+out:
+ return (error);
+}
+
/* ARGSUSED */
int
memrw(struct cdev *dev, struct uio *uio, int flags)
@@ -107,7 +195,10 @@ memrw(struct cdev *dev, struct uio *uio, int flags)
*/
if (v >= DMAP_MIN_ADDRESS &&
v < DMAP_MIN_ADDRESS + dmaplimit) {
- error = uiomove((void *)v, c, uio);
+ if (is_word_aligned(c, v))
+ error = alignmove((void *)v, c, uio);
+ else
+ error = uiomove((void *)v, c, uio);
break;
}
@@ -137,7 +228,10 @@ memrw(struct cdev *dev, struct uio *uio, int flags)
case CDEV_MINOR_MEM:
if (v < dmaplimit) {
vd = PHYS_TO_DMAP(v);
- error = uiomove((void *)vd, c, uio);
+ if (is_word_aligned(c, vd))
+ error = alignmove((void *)vd, c, uio);
+ else
+ error = uiomove((void *)vd, c, uio);
break;
}
if (v > cpu_getmaxphyaddr()) {
@@ -145,7 +239,10 @@ memrw(struct cdev *dev, struct uio *uio, int flags)
break;
}
p = pmap_mapdev(v, PAGE_SIZE);
- error = uiomove(p, c, uio);
+ if (is_word_aligned(c, (u_long)p))
+ error = alignmove(p, c, uio);
+ else
+ error = uiomove(p, c, uio);
pmap_unmapdev((vm_offset_t)p, PAGE_SIZE);
break;
}

Event Timeline

cem edited the content of this paste. (Show Details)Oct 10 2017, 9:47 PM
cem changed the title of this paste from untitled to Masterwork From Distant Lands.
cem updated the paste's language from autodetect to autodetect.