mirror of
https://review.haiku-os.org/haiku
synced 2025-02-15 01:58:36 +01:00
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>
86 lines
1.9 KiB
C
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
|