/* $NetBSD: nv_kern_netbsd.c,v 1.6 2018/10/16 13:18:25 maxv Exp $ */ /*- * Copyright (c) 2018 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Mindaugas Rasiukevicius. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include __RCSID("$NetBSD: nv_kern_netbsd.c,v 1.6 2018/10/16 13:18:25 maxv Exp $"); #if !defined(_KERNEL) && !defined(_STANDALONE) #include #include #include #include #include #endif #ifdef _KERNEL #include #include #include #include #include #include #endif #ifdef _STANDALONE /* XXX */ extern void *alloc(unsigned int); extern void dealloc(void *, unsigned int); // #include "stand.h" #else #include #endif #include "nv.h" #include "nv_impl.h" #ifndef _STANDALONE #ifdef _KERNEL void nv_free(void *buf) { if (!buf) { return; } free(buf, M_NVLIST); } int nvlist_copyin(const nvlist_ref_t *nref, nvlist_t **nvlp, size_t lim) { const size_t len = nref->len; int flags, error; nvlist_t *nvl; void *buf; if (len == 0) { return EINVAL; } if (len >= lim) { return E2BIG; } buf = kmem_alloc(len, KM_SLEEP); error = copyin(nref->buf, buf, len); if (error) { kmem_free(buf, len); return error; } flags = nref->flags & (NV_FLAG_IGNORE_CASE | NV_FLAG_NO_UNIQUE); nvl = nvlist_unpack(buf, len, flags); kmem_free(buf, len); if (nvl == NULL) { return EINVAL; } *nvlp = nvl; return 0; } int nvlist_copyout(nvlist_ref_t *nref, const nvlist_t *nvl) { struct proc *p = curproc; void *buf, *uaddr; size_t len, rlen; int error; buf = nvlist_pack(nvl, &len); if (buf == NULL) { return ENOMEM; } /* * Map the user page(s). * * Note: nvlist_recv_ioctl() will unmap it. */ uaddr = NULL; rlen = round_page(len); error = uvm_mmap_anon(p, &uaddr, rlen); if (error) { goto err; } error = copyout(buf, uaddr, len); if (error) { uvm_unmap(&p->p_vmspace->vm_map, (vaddr_t)uaddr, (vaddr_t)uaddr + rlen); goto err; } nref->flags = nvlist_flags(nvl); nref->buf = uaddr; nref->len = len; err: free(buf, M_TEMP); return error; } #else int nvlist_xfer_ioctl(int fd, unsigned long cmd, const nvlist_t *nvl, nvlist_t **nvlp) { nvlist_ref_t nref; void *buf = NULL; memset(&nref, 0, sizeof(nvlist_ref_t)); if (nvl) { /* * Sending: serialize the name-value list. */ buf = nvlist_pack(nvl, &nref.len); if (buf == NULL) { errno = ENOMEM; return -1; } nref.buf = buf; nref.flags = nvlist_flags(nvl); } /* * Exchange the nvlist reference data. */ if (ioctl(fd, cmd, &nref) == -1) { free(buf); return -1; } free(buf); if (nvlp) { nvlist_t *retnvl; /* * Receiving: unserialize the nvlist. * * Note: pages are mapped by nvlist_kern_copyout() for us. */ if (nref.buf == NULL || nref.len == 0) { errno = EIO; return -1; } retnvl = nvlist_unpack(nref.buf, nref.len, nref.flags); munmap(nref.buf, nref.len); if (retnvl == NULL) { errno = EIO; return -1; } *nvlp = retnvl; } return 0; } int nvlist_send_ioctl(int fd, unsigned long cmd, const nvlist_t *nvl) { return nvlist_xfer_ioctl(fd, cmd, nvl, NULL); } int nvlist_recv_ioctl(int fd, unsigned long cmd, nvlist_t **nvlp) { return nvlist_xfer_ioctl(fd, cmd, NULL, nvlp); } #endif #endif void * nv_calloc(size_t n, size_t s) { const size_t len = n * s; void *buf = nv_malloc(len); if (buf == NULL) return NULL; memset(buf, 0, len); return buf; } char * nv_strdup(const char *s1) { size_t len = strlen(s1) + 1; char *s2; s2 = nv_malloc(len); if (s2) { memcpy(s2, s1, len); s2[len-1] = '\0'; } return s2; } #ifdef _STANDALONE void * nv_malloc(size_t len) { return alloc(len); } void nv_free(void *buf) { if (buf == NULL) return; unsigned int *olen = (void *)((char *)buf - sizeof(unsigned int)); dealloc(buf, *olen); } void * nv_realloc(void *buf, size_t len) { if (buf == NULL) return alloc(len); unsigned int *olen = (void *)((char *)buf - sizeof(unsigned int)); if (*olen < len) return buf; void *nbuf = alloc(len); memcpy(nbuf, buf, *olen); dealloc(buf, *olen); return nbuf; } #endif