100f1e7c5SAugustin Cavalier /* 200f1e7c5SAugustin Cavalier * Copyright 2022, Haiku, Inc. All rights reserved. 300f1e7c5SAugustin Cavalier * Distributed under the terms of the MIT license. 400f1e7c5SAugustin Cavalier */ 500f1e7c5SAugustin Cavalier #ifndef _UTIL_IOVEC_SUPPORT_H 600f1e7c5SAugustin Cavalier #define _UTIL_IOVEC_SUPPORT_H 700f1e7c5SAugustin Cavalier 800f1e7c5SAugustin Cavalier 900f1e7c5SAugustin Cavalier #include <KernelExport.h> 1000f1e7c5SAugustin Cavalier 1100f1e7c5SAugustin Cavalier 1265cdc13eSAugustin Cavalier typedef struct generic_io_vec { 1365cdc13eSAugustin Cavalier generic_addr_t base; 1465cdc13eSAugustin Cavalier generic_size_t length; 1565cdc13eSAugustin Cavalier } generic_io_vec; 1665cdc13eSAugustin Cavalier 1765cdc13eSAugustin Cavalier 1855a46882SAugustin Cavalier #ifdef _KERNEL_VM_VM_H 1955a46882SAugustin Cavalier 2055a46882SAugustin Cavalier static inline status_t 2155a46882SAugustin Cavalier generic_memcpy(generic_addr_t dest, bool destPhysical, generic_addr_t src, bool srcPhysical, 2255a46882SAugustin Cavalier generic_size_t size, bool user = false) 2355a46882SAugustin Cavalier { 2455a46882SAugustin Cavalier if (!srcPhysical && !destPhysical) { 2555a46882SAugustin Cavalier if (user) 2655a46882SAugustin Cavalier return user_memcpy((void*)dest, (void*)src, size); 2755a46882SAugustin Cavalier memcpy((void*)dest, (void*)src, size); 2855a46882SAugustin Cavalier return B_OK; 2955a46882SAugustin Cavalier } else if (destPhysical && !srcPhysical) { 3055a46882SAugustin Cavalier return vm_memcpy_to_physical(dest, (const void*)src, size, user); 3155a46882SAugustin Cavalier } else if (!destPhysical && srcPhysical) { 3255a46882SAugustin Cavalier return vm_memcpy_from_physical((void*)dest, src, size, user); 3355a46882SAugustin Cavalier } 3455a46882SAugustin Cavalier 3555a46882SAugustin Cavalier panic("generic_memcpy: physical -> physical not supported!"); 3655a46882SAugustin Cavalier return B_NOT_SUPPORTED; 3755a46882SAugustin Cavalier } 3855a46882SAugustin Cavalier 3955a46882SAugustin Cavalier #endif 4055a46882SAugustin Cavalier 4155a46882SAugustin Cavalier 4265cdc13eSAugustin Cavalier #ifdef IS_USER_ADDRESS 4355a46882SAugustin Cavalier 44*8e56b86bSAugustin Cavalier /*! 45*8e56b86bSAugustin Cavalier * Copies an array of `iovec`s from userland. 46*8e56b86bSAugustin Cavalier * Callers must verify vecCount <= IOV_MAX and supply their own vecs buffer. 47*8e56b86bSAugustin Cavalier */ 4800f1e7c5SAugustin Cavalier static inline status_t 49*8e56b86bSAugustin Cavalier get_iovecs_from_user(const iovec* userVecs, size_t vecCount, iovec* vecs, 5000f1e7c5SAugustin Cavalier bool permitNull = false) 5100f1e7c5SAugustin Cavalier { 52*8e56b86bSAugustin Cavalier if (vecCount == 0) 5300f1e7c5SAugustin Cavalier return B_BAD_VALUE; 5400f1e7c5SAugustin Cavalier 5500f1e7c5SAugustin Cavalier if (!IS_USER_ADDRESS(userVecs)) 5600f1e7c5SAugustin Cavalier return B_BAD_ADDRESS; 5700f1e7c5SAugustin Cavalier 58*8e56b86bSAugustin Cavalier if (user_memcpy(vecs, userVecs, sizeof(iovec) * vecCount) != B_OK) 5900f1e7c5SAugustin Cavalier return B_BAD_ADDRESS; 6000f1e7c5SAugustin Cavalier 61013719cfSJérôme Duval size_t total = 0; 6200f1e7c5SAugustin Cavalier for (size_t i = 0; i < vecCount; i++) { 6300f1e7c5SAugustin Cavalier if (permitNull && vecs[i].iov_base == NULL) 6400f1e7c5SAugustin Cavalier continue; 65013719cfSJérôme Duval if (!is_user_address_range(vecs[i].iov_base, vecs[i].iov_len)) { 6600f1e7c5SAugustin Cavalier return B_BAD_ADDRESS; 6700f1e7c5SAugustin Cavalier } 68013719cfSJérôme Duval if (vecs[i].iov_len > SSIZE_MAX || total > (SSIZE_MAX - vecs[i].iov_len)) { 69013719cfSJérôme Duval return B_BAD_VALUE; 70013719cfSJérôme Duval } 71013719cfSJérôme Duval total += vecs[i].iov_len; 72013719cfSJérôme Duval } 7300f1e7c5SAugustin Cavalier 7400f1e7c5SAugustin Cavalier return B_OK; 7500f1e7c5SAugustin Cavalier } 7655a46882SAugustin Cavalier 7765cdc13eSAugustin Cavalier #endif 7800f1e7c5SAugustin Cavalier 7900f1e7c5SAugustin Cavalier 8000f1e7c5SAugustin Cavalier #endif // _UTIL_IOVEC_SUPPORT_H 81