xref: /haiku/headers/private/kernel/util/iovec_support.h (revision 55a468820cfb785e1434275161558c4375a432fb)
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 
18*55a46882SAugustin Cavalier #ifdef _KERNEL_VM_VM_H
19*55a46882SAugustin Cavalier 
20*55a46882SAugustin Cavalier static inline status_t
21*55a46882SAugustin Cavalier generic_memcpy(generic_addr_t dest, bool destPhysical, generic_addr_t src, bool srcPhysical,
22*55a46882SAugustin Cavalier 	generic_size_t size, bool user = false)
23*55a46882SAugustin Cavalier {
24*55a46882SAugustin Cavalier 	if (!srcPhysical && !destPhysical) {
25*55a46882SAugustin Cavalier 		if (user)
26*55a46882SAugustin Cavalier 			return user_memcpy((void*)dest, (void*)src, size);
27*55a46882SAugustin Cavalier 		memcpy((void*)dest, (void*)src, size);
28*55a46882SAugustin Cavalier 		return B_OK;
29*55a46882SAugustin Cavalier 	} else if (destPhysical && !srcPhysical) {
30*55a46882SAugustin Cavalier 		return vm_memcpy_to_physical(dest, (const void*)src, size, user);
31*55a46882SAugustin Cavalier 	} else if (!destPhysical && srcPhysical) {
32*55a46882SAugustin Cavalier 		return vm_memcpy_from_physical((void*)dest, src, size, user);
33*55a46882SAugustin Cavalier 	}
34*55a46882SAugustin Cavalier 
35*55a46882SAugustin Cavalier 	panic("generic_memcpy: physical -> physical not supported!");
36*55a46882SAugustin Cavalier 	return B_NOT_SUPPORTED;
37*55a46882SAugustin Cavalier }
38*55a46882SAugustin Cavalier 
39*55a46882SAugustin Cavalier #endif
40*55a46882SAugustin Cavalier 
41*55a46882SAugustin Cavalier 
4265cdc13eSAugustin Cavalier #ifdef IS_USER_ADDRESS
43*55a46882SAugustin Cavalier 
4400f1e7c5SAugustin Cavalier static inline status_t
4500f1e7c5SAugustin Cavalier get_iovecs_from_user(const iovec* userVecs, size_t vecCount, iovec*& vecs,
4600f1e7c5SAugustin Cavalier 	bool permitNull = false)
4700f1e7c5SAugustin Cavalier {
4800f1e7c5SAugustin Cavalier 	// prevent integer overflow
49013719cfSJérôme Duval 	if (vecCount > IOV_MAX || vecCount == 0)
5000f1e7c5SAugustin Cavalier 		return B_BAD_VALUE;
5100f1e7c5SAugustin Cavalier 
5200f1e7c5SAugustin Cavalier 	if (!IS_USER_ADDRESS(userVecs))
5300f1e7c5SAugustin Cavalier 		return B_BAD_ADDRESS;
5400f1e7c5SAugustin Cavalier 
5500f1e7c5SAugustin Cavalier 	vecs = (iovec*)malloc(sizeof(iovec) * vecCount);
5600f1e7c5SAugustin Cavalier 	if (vecs == NULL)
5700f1e7c5SAugustin Cavalier 		return B_NO_MEMORY;
5800f1e7c5SAugustin Cavalier 
59013719cfSJérôme Duval 	if (user_memcpy(vecs, userVecs, sizeof(iovec) * vecCount) != B_OK) {
60013719cfSJérôme Duval 		free(vecs);
6100f1e7c5SAugustin Cavalier 		return B_BAD_ADDRESS;
62013719cfSJérôme Duval 	}
6300f1e7c5SAugustin Cavalier 
64013719cfSJérôme Duval 	size_t total = 0;
6500f1e7c5SAugustin Cavalier 	for (size_t i = 0; i < vecCount; i++) {
6600f1e7c5SAugustin Cavalier 		if (permitNull && vecs[i].iov_base == NULL)
6700f1e7c5SAugustin Cavalier 			continue;
68013719cfSJérôme Duval 		if (!is_user_address_range(vecs[i].iov_base, vecs[i].iov_len)) {
69013719cfSJérôme Duval 			free(vecs);
7000f1e7c5SAugustin Cavalier 			return B_BAD_ADDRESS;
7100f1e7c5SAugustin Cavalier 		}
72013719cfSJérôme Duval 		if (vecs[i].iov_len > SSIZE_MAX || total > (SSIZE_MAX - vecs[i].iov_len)) {
73013719cfSJérôme Duval 			free(vecs);
74013719cfSJérôme Duval 			return B_BAD_VALUE;
75013719cfSJérôme Duval 		}
76013719cfSJérôme Duval 		total += vecs[i].iov_len;
77013719cfSJérôme Duval 	}
7800f1e7c5SAugustin Cavalier 
7900f1e7c5SAugustin Cavalier 	return B_OK;
8000f1e7c5SAugustin Cavalier }
81*55a46882SAugustin Cavalier 
8265cdc13eSAugustin Cavalier #endif
8300f1e7c5SAugustin Cavalier 
8400f1e7c5SAugustin Cavalier 
8500f1e7c5SAugustin Cavalier #endif	// _UTIL_IOVEC_SUPPORT_H
86