xref: /netbsd-src/sys/external/bsd/libnv/dist/nv_kern_netbsd.c (revision 29f6afd43883d585e017d52bc489ab150de8227c)
1*29f6afd4Sriastradh /*	$NetBSD: nv_kern_netbsd.c,v 1.7 2024/09/04 12:57:00 riastradh Exp $	*/
232302d25Schristos 
332302d25Schristos /*-
432302d25Schristos  * Copyright (c) 2018 The NetBSD Foundation, Inc.
532302d25Schristos  * All rights reserved.
632302d25Schristos  *
732302d25Schristos  * This code is derived from software contributed to The NetBSD Foundation
832302d25Schristos  * by Mindaugas Rasiukevicius.
932302d25Schristos  *
1032302d25Schristos  * Redistribution and use in source and binary forms, with or without
1132302d25Schristos  * modification, are permitted provided that the following conditions
1232302d25Schristos  * are met:
1332302d25Schristos  * 1. Redistributions of source code must retain the above copyright
1432302d25Schristos  *    notice, this list of conditions and the following disclaimer.
1532302d25Schristos  * 2. Redistributions in binary form must reproduce the above copyright
1632302d25Schristos  *    notice, this list of conditions and the following disclaimer in the
1732302d25Schristos  *    documentation and/or other materials provided with the distribution.
1832302d25Schristos  *
1932302d25Schristos  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2032302d25Schristos  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2132302d25Schristos  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2232302d25Schristos  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2332302d25Schristos  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2432302d25Schristos  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2532302d25Schristos  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2632302d25Schristos  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2732302d25Schristos  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2832302d25Schristos  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2932302d25Schristos  * POSSIBILITY OF SUCH DAMAGE.
3032302d25Schristos  */
3132302d25Schristos 
3243feefbfSchristos #include <sys/cdefs.h>
33*29f6afd4Sriastradh __RCSID("$NetBSD: nv_kern_netbsd.c,v 1.7 2024/09/04 12:57:00 riastradh Exp $");
3432302d25Schristos 
3532302d25Schristos #if !defined(_KERNEL) && !defined(_STANDALONE)
3632302d25Schristos #include <sys/mman.h>
3732302d25Schristos #include <errno.h>
3832302d25Schristos #include <string.h>
3932302d25Schristos #include <stdlib.h>
4032302d25Schristos #include <stdio.h>
4132302d25Schristos #endif
4232302d25Schristos #ifdef _KERNEL
4332302d25Schristos #include <sys/param.h>
4432302d25Schristos #include <sys/lwp.h>
4532302d25Schristos #include <sys/kmem.h>
4632302d25Schristos #include <sys/malloc.h>
4732302d25Schristos #include <sys/mman.h>
4832302d25Schristos #include <uvm/uvm_extern.h>
4932302d25Schristos #endif
5032302d25Schristos #ifdef _STANDALONE
5132302d25Schristos /* XXX */
5232302d25Schristos extern void *alloc(unsigned int);
5332302d25Schristos extern void dealloc(void *, unsigned int);
5432302d25Schristos // #include "stand.h"
5532302d25Schristos #else
5632302d25Schristos #include <sys/ioctl.h>
5732302d25Schristos #endif
5832302d25Schristos #include "nv.h"
5932302d25Schristos #include "nv_impl.h"
6032302d25Schristos 
6132302d25Schristos #ifndef _STANDALONE
6232302d25Schristos #ifdef _KERNEL
6332302d25Schristos 
646bb96d27Srmind void
656bb96d27Srmind nv_free(void *buf)
666bb96d27Srmind {
676bb96d27Srmind 	if (!buf) {
686bb96d27Srmind 		return;
696bb96d27Srmind 	}
706bb96d27Srmind 	free(buf, M_NVLIST);
716bb96d27Srmind }
726bb96d27Srmind 
7332302d25Schristos int
7432302d25Schristos nvlist_copyin(const nvlist_ref_t *nref, nvlist_t **nvlp, size_t lim)
7532302d25Schristos {
7632302d25Schristos 	const size_t len = nref->len;
77655dfdeaSrmind 	int flags, error;
7832302d25Schristos 	nvlist_t *nvl;
7932302d25Schristos 	void *buf;
8032302d25Schristos 
817fc40fd5Smaxv 	if (len == 0) {
827fc40fd5Smaxv 		return EINVAL;
837fc40fd5Smaxv 	}
8432302d25Schristos 	if (len >= lim) {
8532302d25Schristos 		return E2BIG;
8632302d25Schristos 	}
8732302d25Schristos 	buf = kmem_alloc(len, KM_SLEEP);
8832302d25Schristos 	error = copyin(nref->buf, buf, len);
8932302d25Schristos 	if (error) {
9032302d25Schristos 		kmem_free(buf, len);
9132302d25Schristos 		return error;
9232302d25Schristos 	}
93655dfdeaSrmind 	flags = nref->flags & (NV_FLAG_IGNORE_CASE | NV_FLAG_NO_UNIQUE);
94655dfdeaSrmind 	nvl = nvlist_unpack(buf, len, flags);
9532302d25Schristos 	kmem_free(buf, len);
9632302d25Schristos 	if (nvl == NULL) {
9732302d25Schristos 		return EINVAL;
9832302d25Schristos 	}
9932302d25Schristos 	*nvlp = nvl;
10032302d25Schristos 	return 0;
10132302d25Schristos }
10232302d25Schristos 
10332302d25Schristos int
10432302d25Schristos nvlist_copyout(nvlist_ref_t *nref, const nvlist_t *nvl)
10532302d25Schristos {
10632302d25Schristos 	struct proc *p = curproc;
10732302d25Schristos 	void *buf, *uaddr;
10832302d25Schristos 	size_t len, rlen;
10932302d25Schristos 	int error;
11032302d25Schristos 
11132302d25Schristos 	buf = nvlist_pack(nvl, &len);
11232302d25Schristos 	if (buf == NULL) {
11332302d25Schristos 		return ENOMEM;
11432302d25Schristos 	}
11532302d25Schristos 
11632302d25Schristos 	/*
11732302d25Schristos 	 * Map the user page(s).
11832302d25Schristos 	 *
11932302d25Schristos 	 * Note: nvlist_recv_ioctl() will unmap it.
12032302d25Schristos 	 */
12132302d25Schristos 	uaddr = NULL;
12232302d25Schristos 	rlen = round_page(len);
12332302d25Schristos 	error = uvm_mmap_anon(p, &uaddr, rlen);
12432302d25Schristos 	if (error) {
12532302d25Schristos 		goto err;
12632302d25Schristos 	}
12732302d25Schristos 	error = copyout(buf, uaddr, len);
12832302d25Schristos 	if (error) {
12932302d25Schristos 		uvm_unmap(&p->p_vmspace->vm_map, (vaddr_t)uaddr,
1307fc40fd5Smaxv 		    (vaddr_t)uaddr + rlen);
13132302d25Schristos 		goto err;
13232302d25Schristos 	}
133655dfdeaSrmind 	nref->flags = nvlist_flags(nvl);
13432302d25Schristos 	nref->buf = uaddr;
13532302d25Schristos 	nref->len = len;
13632302d25Schristos err:
13732302d25Schristos 	free(buf, M_TEMP);
13832302d25Schristos 	return error;
13932302d25Schristos }
14032302d25Schristos 
14132302d25Schristos #else
14232302d25Schristos 
14332302d25Schristos int
14432302d25Schristos nvlist_xfer_ioctl(int fd, unsigned long cmd, const nvlist_t *nvl,
14532302d25Schristos     nvlist_t **nvlp)
14632302d25Schristos {
14732302d25Schristos 	nvlist_ref_t nref;
14832302d25Schristos 	void *buf = NULL;
14932302d25Schristos 
15032302d25Schristos 	memset(&nref, 0, sizeof(nvlist_ref_t));
15132302d25Schristos 
15232302d25Schristos 	if (nvl) {
15332302d25Schristos 		/*
15432302d25Schristos 		 * Sending: serialize the name-value list.
15532302d25Schristos 		 */
15632302d25Schristos 		buf = nvlist_pack(nvl, &nref.len);
15732302d25Schristos 		if (buf == NULL) {
15832302d25Schristos 			errno = ENOMEM;
15932302d25Schristos 			return -1;
16032302d25Schristos 		}
16132302d25Schristos 		nref.buf = buf;
16232302d25Schristos 		nref.flags = nvlist_flags(nvl);
16332302d25Schristos 	}
16432302d25Schristos 
16532302d25Schristos 	/*
16632302d25Schristos 	 * Exchange the nvlist reference data.
16732302d25Schristos 	 */
16832302d25Schristos 	if (ioctl(fd, cmd, &nref) == -1) {
16932302d25Schristos 		free(buf);
17032302d25Schristos 		return -1;
17132302d25Schristos 	}
17232302d25Schristos 	free(buf);
17332302d25Schristos 
17432302d25Schristos 	if (nvlp) {
17532302d25Schristos 		nvlist_t *retnvl;
17632302d25Schristos 
17732302d25Schristos 		/*
17832302d25Schristos 		 * Receiving: unserialize the nvlist.
17932302d25Schristos 		 *
18032302d25Schristos 		 * Note: pages are mapped by nvlist_kern_copyout() for us.
18132302d25Schristos 		 */
18232302d25Schristos 		if (nref.buf == NULL || nref.len == 0) {
18332302d25Schristos 			errno = EIO;
18432302d25Schristos 			return -1;
18532302d25Schristos 		}
18632302d25Schristos 		retnvl = nvlist_unpack(nref.buf, nref.len, nref.flags);
18732302d25Schristos 		munmap(nref.buf, nref.len);
18832302d25Schristos 		if (retnvl == NULL) {
18932302d25Schristos 			errno = EIO;
19032302d25Schristos 			return -1;
19132302d25Schristos 		}
19232302d25Schristos 		*nvlp = retnvl;
19332302d25Schristos 	}
19432302d25Schristos 	return 0;
19532302d25Schristos }
19632302d25Schristos 
19732302d25Schristos int
19832302d25Schristos nvlist_send_ioctl(int fd, unsigned long cmd, const nvlist_t *nvl)
19932302d25Schristos {
20032302d25Schristos 	return nvlist_xfer_ioctl(fd, cmd, nvl, NULL);
20132302d25Schristos }
20232302d25Schristos 
20332302d25Schristos int
20432302d25Schristos nvlist_recv_ioctl(int fd, unsigned long cmd, nvlist_t **nvlp)
20532302d25Schristos {
20632302d25Schristos 	return nvlist_xfer_ioctl(fd, cmd, NULL, nvlp);
20732302d25Schristos }
20832302d25Schristos #endif
20932302d25Schristos #endif
21032302d25Schristos 
21132302d25Schristos void *
212*29f6afd4Sriastradh nv_calloc(size_t nelem, size_t elemsize)
21332302d25Schristos {
214*29f6afd4Sriastradh 
215*29f6afd4Sriastradh 	if (nelem > SIZE_MAX/elemsize)
216*29f6afd4Sriastradh 		return NULL;
217*29f6afd4Sriastradh 
218*29f6afd4Sriastradh 	const size_t len = nelem * elemsize;
219*29f6afd4Sriastradh 	void *const buf = nv_malloc(len);
22032302d25Schristos 	if (buf == NULL)
22132302d25Schristos 		return NULL;
2228f74945cSrmind 	memset(buf, 0, len);
22332302d25Schristos 	return buf;
22432302d25Schristos }
22532302d25Schristos 
22632302d25Schristos char *
22732302d25Schristos nv_strdup(const char *s1)
22832302d25Schristos {
229*29f6afd4Sriastradh 	size_t len = strlen(s1);
23032302d25Schristos 	char *s2;
23132302d25Schristos 
232*29f6afd4Sriastradh 	if (len == SIZE_MAX)
233*29f6afd4Sriastradh 		return NULL;
234*29f6afd4Sriastradh 	len += 1;		/* NUL terminator */
235*29f6afd4Sriastradh 
23632302d25Schristos 	s2 = nv_malloc(len);
23732302d25Schristos 	if (s2) {
23832302d25Schristos 		memcpy(s2, s1, len);
2397fc40fd5Smaxv 		s2[len-1] = '\0';
24032302d25Schristos 	}
24132302d25Schristos 	return s2;
24232302d25Schristos }
24332302d25Schristos 
24432302d25Schristos #ifdef _STANDALONE
24532302d25Schristos 
24632302d25Schristos void *
24732302d25Schristos nv_malloc(size_t len)
24832302d25Schristos {
24932302d25Schristos 	return alloc(len);
25032302d25Schristos }
25132302d25Schristos 
25232302d25Schristos void
25332302d25Schristos nv_free(void *buf)
25432302d25Schristos {
25532302d25Schristos 	if (buf == NULL)
25632302d25Schristos 		return;
25732302d25Schristos 	unsigned int *olen = (void *)((char *)buf - sizeof(unsigned int));
25832302d25Schristos 	dealloc(buf, *olen);
25932302d25Schristos }
26032302d25Schristos 
26132302d25Schristos void *
26232302d25Schristos nv_realloc(void *buf, size_t len)
26332302d25Schristos {
26432302d25Schristos 	if (buf == NULL)
26532302d25Schristos 		return alloc(len);
26632302d25Schristos 
26732302d25Schristos 	unsigned int *olen = (void *)((char *)buf - sizeof(unsigned int));
26832302d25Schristos 	if (*olen < len)
26932302d25Schristos 		return buf;
27032302d25Schristos 
27132302d25Schristos 	void *nbuf = alloc(len);
27232302d25Schristos 	memcpy(nbuf, buf, *olen);
27332302d25Schristos 	dealloc(buf, *olen);
27432302d25Schristos 	return nbuf;
27532302d25Schristos }
27632302d25Schristos #endif
277