#include <sys/types.h>
#include <sys/systm.h>
#include <cpu/lwbuf.h>
#include <vm/vm_page.h>
#include <vm/vm_extern.h>
#include <vm/pmap.h>
#include <assert.h>
#include <sys/stat.h>
#include <sys/mman.h>
uint64_t
casu64(volatile uint64_t *p, uint64_t oldval, uint64_t newval)
{
struct vmspace *vm = curproc->p_vmspace;
vm_offset_t kva;
vm_page_t m;
volatile uint64_t *dest;
uint64_t res;
int error;
int busy;
if (PAGE_SIZE - ((vm_offset_t)p & PAGE_MASK) < sizeof(uint64_t))
return -1;
m = vm_fault_page(&vm->vm_map, trunc_page((vm_offset_t)p),
VM_PROT_READ|VM_PROT_WRITE,
VM_FAULT_NORMAL,
&error, &busy);
if (error)
return -1;
kva = PHYS_TO_DMAP(VM_PAGE_TO_PHYS(m));
dest = (uint64_t *)(kva + ((vm_offset_t)p & PAGE_MASK));
res = oldval;
__asm __volatile(MPLOCKED "cmpxchgq %2,%1; " \
: "+a" (res), "=m" (*dest) \
: "r" (newval), "m" (*dest) \
: "memory");
if (busy)
vm_page_wakeup(m);
else
vm_page_unhold(m);
return res;
}
u_int
casu32(volatile u_int *p, u_int oldval, u_int newval)
{
struct vmspace *vm = curproc->p_vmspace;
vm_offset_t kva;
vm_page_t m;
volatile u_int *dest;
u_int res;
int error;
int busy;
if (PAGE_SIZE - ((vm_offset_t)p & PAGE_MASK) < sizeof(u_int))
return -1;
m = vm_fault_page(&vm->vm_map, trunc_page((vm_offset_t)p),
VM_PROT_READ|VM_PROT_WRITE,
VM_FAULT_NORMAL,
&error, &busy);
if (error)
return -1;
kva = PHYS_TO_DMAP(VM_PAGE_TO_PHYS(m));
dest = (u_int *)(kva + ((vm_offset_t)p & PAGE_MASK));
res = oldval;
__asm __volatile(MPLOCKED "cmpxchgl %2,%1; " \
: "+a" (res), "=m" (*dest) \
: "r" (newval), "m" (*dest) \
: "memory");
if (busy)
vm_page_wakeup(m);
else
vm_page_unhold(m);
return res;
}
uint64_t
swapu64(volatile uint64_t *p, uint64_t val)
{
struct vmspace *vm = curproc->p_vmspace;
vm_offset_t kva;
vm_page_t m;
uint64_t res;
int error;
int busy;
if (PAGE_SIZE - ((vm_offset_t)p & PAGE_MASK) < sizeof(uint64_t))
return -1;
m = vm_fault_page(&vm->vm_map, trunc_page((vm_offset_t)p),
VM_PROT_READ|VM_PROT_WRITE,
VM_FAULT_NORMAL,
&error, &busy);
if (error)
return -1;
kva = PHYS_TO_DMAP(VM_PAGE_TO_PHYS(m));
res = atomic_swap_long((uint64_t *)(kva + ((vm_offset_t)p & PAGE_MASK)),
val);
if (busy)
vm_page_wakeup(m);
else
vm_page_unhold(m);
return res;
}
uint32_t
swapu32(volatile uint32_t *p, uint32_t val)
{
struct vmspace *vm = curproc->p_vmspace;
vm_offset_t kva;
vm_page_t m;
u_int res;
int error;
int busy;
if (PAGE_SIZE - ((vm_offset_t)p & PAGE_MASK) < sizeof(uint64_t))
return -1;
m = vm_fault_page(&vm->vm_map, trunc_page((vm_offset_t)p),
VM_PROT_READ|VM_PROT_WRITE,
VM_FAULT_NORMAL,
&error, &busy);
if (error)
return -1;
kva = PHYS_TO_DMAP(VM_PAGE_TO_PHYS(m));
res = atomic_swap_int((u_int *)(kva + ((vm_offset_t)p & PAGE_MASK)),
val);
if (busy)
vm_page_wakeup(m);
else
vm_page_unhold(m);
return res;
}
uint64_t
fuwordadd64(volatile uint64_t *p, uint64_t val)
{
struct vmspace *vm = curproc->p_vmspace;
vm_offset_t kva;
vm_page_t m;
uint64_t res;
int error;
int busy;
if (PAGE_SIZE - ((vm_offset_t)p & PAGE_MASK) < sizeof(uint64_t))
return -1;
m = vm_fault_page(&vm->vm_map, trunc_page((vm_offset_t)p),
VM_PROT_READ|VM_PROT_WRITE,
VM_FAULT_NORMAL,
&error, &busy);
if (error)
return -1;
kva = PHYS_TO_DMAP(VM_PAGE_TO_PHYS(m));
res = atomic_fetchadd_long((uint64_t *)(kva + ((vm_offset_t)p & PAGE_MASK)),
val);
if (busy)
vm_page_wakeup(m);
else
vm_page_unhold(m);
return res;
}
uint32_t
fuwordadd32(volatile uint32_t *p, uint32_t val)
{
struct vmspace *vm = curproc->p_vmspace;
vm_offset_t kva;
vm_page_t m;
u_int res;
int error;
int busy;
if (PAGE_SIZE - ((vm_offset_t)p & PAGE_MASK) < sizeof(uint64_t))
return -1;
m = vm_fault_page(&vm->vm_map, trunc_page((vm_offset_t)p),
VM_PROT_READ|VM_PROT_WRITE,
VM_FAULT_NORMAL,
&error, &busy);
if (error)
return -1;
kva = PHYS_TO_DMAP(VM_PAGE_TO_PHYS(m));
res = atomic_fetchadd_int((u_int *)(kva + ((vm_offset_t)p & PAGE_MASK)),
val);
if (busy)
vm_page_wakeup(m);
else
vm_page_unhold(m);
return res;
}
int
copystr(const void *kfaddr, void *kdaddr, size_t len, size_t *lencopied)
{
size_t i;
for (i = 0; i < len; ++i) {
if ((((char *)kdaddr)[i] = ((const char *)kfaddr)[i]) == 0) {
if (lencopied)
*lencopied = i + 1;
return(0);
}
}
return (ENAMETOOLONG);
}
int
copyinstr(const void *udaddr, void *kaddr, size_t len, size_t *res)
{
int error;
size_t n;
const char *uptr = udaddr;
char *kptr = kaddr;
if (res)
*res = 0;
while (len) {
n = PAGE_SIZE - ((vm_offset_t)uptr & PAGE_MASK);
if (n > 32)
n = 32;
if (n > len)
n = len;
if ((error = copyin(uptr, kptr, n)) != 0)
return(error);
while (n) {
if (res)
++*res;
if (*kptr == 0)
return(0);
++kptr;
++uptr;
--n;
--len;
}
}
return(ENAMETOOLONG);
}
int
copyin(const void *udaddr, void *kaddr, size_t len)
{
struct vmspace *vm = curproc->p_vmspace;
struct lwbuf *lwb;
struct lwbuf lwb_cache;
vm_page_t m;
int error;
size_t n;
error = 0;
while (len) {
m = vm_fault_page(&vm->vm_map, trunc_page((vm_offset_t)udaddr),
VM_PROT_READ,
VM_FAULT_NORMAL,
&error, NULL);
if (error)
break;
n = PAGE_SIZE - ((vm_offset_t)udaddr & PAGE_MASK);
if (n > len)
n = len;
lwb = lwbuf_alloc(m, &lwb_cache);
bcopy((char *)lwbuf_kva(lwb)+((vm_offset_t)udaddr & PAGE_MASK),
kaddr, n);
len -= n;
udaddr = (const char *)udaddr + n;
kaddr = (char *)kaddr + n;
lwbuf_free(lwb);
vm_page_unhold(m);
}
if (error)
error = EFAULT;
return (error);
}
int
copyout(const void *kaddr, void *udaddr, size_t len)
{
struct vmspace *vm = curproc->p_vmspace;
struct lwbuf *lwb;
struct lwbuf lwb_cache;
vm_page_t m;
int error;
int busy;
size_t n;
error = 0;
while (len) {
m = vm_fault_page(&vm->vm_map, trunc_page((vm_offset_t)udaddr),
VM_PROT_READ|VM_PROT_WRITE,
VM_FAULT_NORMAL,
&error, &busy);
if (error)
break;
n = PAGE_SIZE - ((vm_offset_t)udaddr & PAGE_MASK);
if (n > len)
n = len;
lwb = lwbuf_alloc(m, &lwb_cache);
bcopy(kaddr, (char *)lwbuf_kva(lwb) +
((vm_offset_t)udaddr & PAGE_MASK), n);
len -= n;
udaddr = (char *)udaddr + n;
kaddr = (const char *)kaddr + n;
lwbuf_free(lwb);
if (busy)
vm_page_wakeup(m);
else
vm_page_unhold(m);
}
if (error)
error = EFAULT;
return (error);
}
int
fubyte(const uint8_t *base)
{
uint8_t c;
if (copyin(base, &c, 1) == 0)
return((int)c);
return(-1);
}
int
subyte(uint8_t *base, uint8_t byte)
{
uint8_t c = byte;
if (copyout(&c, base, 1) == 0)
return(0);
return(-1);
}
int32_t
fuword32(const uint32_t *base)
{
uint32_t v;
if (copyin(base, &v, sizeof(v)) == 0)
return(v);
return(-1);
}
int64_t
fuword64(const uint64_t *base)
{
uint64_t v;
if (copyin(base, &v, sizeof(v)) == 0)
return(v);
return(-1);
}
int
suword64(uint64_t *base, uint64_t word)
{
if (copyout(&word, base, sizeof(word)) == 0)
return(0);
return(-1);
}
int
suword32(uint32_t *base, int word)
{
if (copyout(&word, base, sizeof(word)) == 0)
return(0);
return(-1);
}