#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/proc.h>
#include <sys/systm.h>
#include <sys/uio.h>
#include <vm/vm.h>
#include <vm/vm_page.h>
#include <machine/vmparam.h>
int
uiomove_fromphys(vm_page_t ma[], vm_offset_t offset, int n, struct uio *uio)
{
struct thread *td = curthread;
struct iovec *iov;
void *cp;
vm_offset_t page_offset, vaddr;
size_t cnt;
int error = 0;
int save = 0;
bool mapped;
KASSERT(uio->uio_rw == UIO_READ || uio->uio_rw == UIO_WRITE,
("uiomove_fromphys: mode"));
KASSERT(uio->uio_segflg != UIO_USERSPACE || uio->uio_td == curthread,
("uiomove_fromphys proc"));
KASSERT(uio->uio_resid >= 0,
("%s: uio %p resid underflow", __func__, uio));
save = td->td_pflags & TDP_DEADLKTREAT;
td->td_pflags |= TDP_DEADLKTREAT;
mapped = false;
while (n > 0 && uio->uio_resid) {
KASSERT(uio->uio_iovcnt > 0,
("%s: uio %p iovcnt underflow", __func__, uio));
iov = uio->uio_iov;
cnt = iov->iov_len;
if (cnt == 0) {
uio->uio_iov++;
uio->uio_iovcnt--;
continue;
}
if (cnt > n)
cnt = n;
page_offset = offset & PAGE_MASK;
cnt = min(cnt, PAGE_SIZE - page_offset);
if (uio->uio_segflg != UIO_NOCOPY) {
mapped = pmap_map_io_transient(
&ma[offset >> PAGE_SHIFT], &vaddr, 1, true);
cp = (char *)vaddr + page_offset;
}
switch (uio->uio_segflg) {
case UIO_USERSPACE:
maybe_yield();
switch (uio->uio_rw) {
case UIO_READ:
error = copyout(cp, iov->iov_base, cnt);
break;
case UIO_WRITE:
error = copyin(iov->iov_base, cp, cnt);
break;
}
if (error)
goto out;
break;
case UIO_SYSSPACE:
switch (uio->uio_rw) {
case UIO_READ:
bcopy(cp, iov->iov_base, cnt);
break;
case UIO_WRITE:
bcopy(iov->iov_base, cp, cnt);
break;
}
break;
case UIO_NOCOPY:
break;
}
if (__predict_false(mapped)) {
pmap_unmap_io_transient(&ma[offset >> PAGE_SHIFT],
&vaddr, 1, true);
mapped = false;
}
iov->iov_base = (char *)iov->iov_base + cnt;
iov->iov_len -= cnt;
uio->uio_resid -= cnt;
uio->uio_offset += cnt;
offset += cnt;
n -= cnt;
}
out:
if (__predict_false(mapped)) {
panic("TODO 3");
pmap_unmap_io_transient(&ma[offset >> PAGE_SHIFT], &vaddr, 1,
true);
}
if (save == 0)
td->td_pflags &= ~TDP_DEADLKTREAT;
return (error);
}