xref: /haiku/headers/private/kernel/util/iovec_support.h (revision 8e56b86bdd555b2d587177ba9df4a03d98868a82)
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