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