haiku/headers/private/kernel/util/iovec_support.h
Augustin Cavalier 55a468820c USB: Support physical-vector bulk requests.
Introduce a new utility method, "generic_memcpy", which takes
generic_addr_t plus indications of whether these specify virtual or
physical addresses (and potentially user addresess) and calls the
appropriate memcpy variant depending.

All bus drivers adjusted to support this at once. We don't actually
take advantage of the physical addresses in any way (yet), as USB
controllers have some pretty specific requirements that would have
to be carefully validated to use these directly.

All bus drivers tested and confirmed to still be working.

Change-Id: I66326667e148091147bb2b3d0843a26fb7e5bda6
Reviewed-on: https://review.haiku-os.org/c/haiku/+/6479
Reviewed-by: waddlesplash <waddlesplash@gmail.com>
2023-05-30 17:54:28 +00:00

86 lines
1.9 KiB
C

/*
* Copyright 2022, Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT license.
*/
#ifndef _UTIL_IOVEC_SUPPORT_H
#define _UTIL_IOVEC_SUPPORT_H
#include <KernelExport.h>
typedef struct generic_io_vec {
generic_addr_t base;
generic_size_t length;
} generic_io_vec;
#ifdef _KERNEL_VM_VM_H
static inline status_t
generic_memcpy(generic_addr_t dest, bool destPhysical, generic_addr_t src, bool srcPhysical,
generic_size_t size, bool user = false)
{
if (!srcPhysical && !destPhysical) {
if (user)
return user_memcpy((void*)dest, (void*)src, size);
memcpy((void*)dest, (void*)src, size);
return B_OK;
} else if (destPhysical && !srcPhysical) {
return vm_memcpy_to_physical(dest, (const void*)src, size, user);
} else if (!destPhysical && srcPhysical) {
return vm_memcpy_from_physical((void*)dest, src, size, user);
}
panic("generic_memcpy: physical -> physical not supported!");
return B_NOT_SUPPORTED;
}
#endif
#ifdef IS_USER_ADDRESS
static inline status_t
get_iovecs_from_user(const iovec* userVecs, size_t vecCount, iovec*& vecs,
bool permitNull = false)
{
// prevent integer overflow
if (vecCount > IOV_MAX || vecCount == 0)
return B_BAD_VALUE;
if (!IS_USER_ADDRESS(userVecs))
return B_BAD_ADDRESS;
vecs = (iovec*)malloc(sizeof(iovec) * vecCount);
if (vecs == NULL)
return B_NO_MEMORY;
if (user_memcpy(vecs, userVecs, sizeof(iovec) * vecCount) != B_OK) {
free(vecs);
return B_BAD_ADDRESS;
}
size_t total = 0;
for (size_t i = 0; i < vecCount; i++) {
if (permitNull && vecs[i].iov_base == NULL)
continue;
if (!is_user_address_range(vecs[i].iov_base, vecs[i].iov_len)) {
free(vecs);
return B_BAD_ADDRESS;
}
if (vecs[i].iov_len > SSIZE_MAX || total > (SSIZE_MAX - vecs[i].iov_len)) {
free(vecs);
return B_BAD_VALUE;
}
total += vecs[i].iov_len;
}
return B_OK;
}
#endif
#endif // _UTIL_IOVEC_SUPPORT_H