1 /* $NetBSD: nv_kern_netbsd.c,v 1.7 2024/09/04 12:57:00 riastradh Exp $ */ 2 3 /*- 4 * Copyright (c) 2018 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Mindaugas Rasiukevicius. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __RCSID("$NetBSD: nv_kern_netbsd.c,v 1.7 2024/09/04 12:57:00 riastradh Exp $"); 34 35 #if !defined(_KERNEL) && !defined(_STANDALONE) 36 #include <sys/mman.h> 37 #include <errno.h> 38 #include <string.h> 39 #include <stdlib.h> 40 #include <stdio.h> 41 #endif 42 #ifdef _KERNEL 43 #include <sys/param.h> 44 #include <sys/lwp.h> 45 #include <sys/kmem.h> 46 #include <sys/malloc.h> 47 #include <sys/mman.h> 48 #include <uvm/uvm_extern.h> 49 #endif 50 #ifdef _STANDALONE 51 /* XXX */ 52 extern void *alloc(unsigned int); 53 extern void dealloc(void *, unsigned int); 54 // #include "stand.h" 55 #else 56 #include <sys/ioctl.h> 57 #endif 58 #include "nv.h" 59 #include "nv_impl.h" 60 61 #ifndef _STANDALONE 62 #ifdef _KERNEL 63 64 void 65 nv_free(void *buf) 66 { 67 if (!buf) { 68 return; 69 } 70 free(buf, M_NVLIST); 71 } 72 73 int 74 nvlist_copyin(const nvlist_ref_t *nref, nvlist_t **nvlp, size_t lim) 75 { 76 const size_t len = nref->len; 77 int flags, error; 78 nvlist_t *nvl; 79 void *buf; 80 81 if (len == 0) { 82 return EINVAL; 83 } 84 if (len >= lim) { 85 return E2BIG; 86 } 87 buf = kmem_alloc(len, KM_SLEEP); 88 error = copyin(nref->buf, buf, len); 89 if (error) { 90 kmem_free(buf, len); 91 return error; 92 } 93 flags = nref->flags & (NV_FLAG_IGNORE_CASE | NV_FLAG_NO_UNIQUE); 94 nvl = nvlist_unpack(buf, len, flags); 95 kmem_free(buf, len); 96 if (nvl == NULL) { 97 return EINVAL; 98 } 99 *nvlp = nvl; 100 return 0; 101 } 102 103 int 104 nvlist_copyout(nvlist_ref_t *nref, const nvlist_t *nvl) 105 { 106 struct proc *p = curproc; 107 void *buf, *uaddr; 108 size_t len, rlen; 109 int error; 110 111 buf = nvlist_pack(nvl, &len); 112 if (buf == NULL) { 113 return ENOMEM; 114 } 115 116 /* 117 * Map the user page(s). 118 * 119 * Note: nvlist_recv_ioctl() will unmap it. 120 */ 121 uaddr = NULL; 122 rlen = round_page(len); 123 error = uvm_mmap_anon(p, &uaddr, rlen); 124 if (error) { 125 goto err; 126 } 127 error = copyout(buf, uaddr, len); 128 if (error) { 129 uvm_unmap(&p->p_vmspace->vm_map, (vaddr_t)uaddr, 130 (vaddr_t)uaddr + rlen); 131 goto err; 132 } 133 nref->flags = nvlist_flags(nvl); 134 nref->buf = uaddr; 135 nref->len = len; 136 err: 137 free(buf, M_TEMP); 138 return error; 139 } 140 141 #else 142 143 int 144 nvlist_xfer_ioctl(int fd, unsigned long cmd, const nvlist_t *nvl, 145 nvlist_t **nvlp) 146 { 147 nvlist_ref_t nref; 148 void *buf = NULL; 149 150 memset(&nref, 0, sizeof(nvlist_ref_t)); 151 152 if (nvl) { 153 /* 154 * Sending: serialize the name-value list. 155 */ 156 buf = nvlist_pack(nvl, &nref.len); 157 if (buf == NULL) { 158 errno = ENOMEM; 159 return -1; 160 } 161 nref.buf = buf; 162 nref.flags = nvlist_flags(nvl); 163 } 164 165 /* 166 * Exchange the nvlist reference data. 167 */ 168 if (ioctl(fd, cmd, &nref) == -1) { 169 free(buf); 170 return -1; 171 } 172 free(buf); 173 174 if (nvlp) { 175 nvlist_t *retnvl; 176 177 /* 178 * Receiving: unserialize the nvlist. 179 * 180 * Note: pages are mapped by nvlist_kern_copyout() for us. 181 */ 182 if (nref.buf == NULL || nref.len == 0) { 183 errno = EIO; 184 return -1; 185 } 186 retnvl = nvlist_unpack(nref.buf, nref.len, nref.flags); 187 munmap(nref.buf, nref.len); 188 if (retnvl == NULL) { 189 errno = EIO; 190 return -1; 191 } 192 *nvlp = retnvl; 193 } 194 return 0; 195 } 196 197 int 198 nvlist_send_ioctl(int fd, unsigned long cmd, const nvlist_t *nvl) 199 { 200 return nvlist_xfer_ioctl(fd, cmd, nvl, NULL); 201 } 202 203 int 204 nvlist_recv_ioctl(int fd, unsigned long cmd, nvlist_t **nvlp) 205 { 206 return nvlist_xfer_ioctl(fd, cmd, NULL, nvlp); 207 } 208 #endif 209 #endif 210 211 void * 212 nv_calloc(size_t nelem, size_t elemsize) 213 { 214 215 if (nelem > SIZE_MAX/elemsize) 216 return NULL; 217 218 const size_t len = nelem * elemsize; 219 void *const buf = nv_malloc(len); 220 if (buf == NULL) 221 return NULL; 222 memset(buf, 0, len); 223 return buf; 224 } 225 226 char * 227 nv_strdup(const char *s1) 228 { 229 size_t len = strlen(s1); 230 char *s2; 231 232 if (len == SIZE_MAX) 233 return NULL; 234 len += 1; /* NUL terminator */ 235 236 s2 = nv_malloc(len); 237 if (s2) { 238 memcpy(s2, s1, len); 239 s2[len-1] = '\0'; 240 } 241 return s2; 242 } 243 244 #ifdef _STANDALONE 245 246 void * 247 nv_malloc(size_t len) 248 { 249 return alloc(len); 250 } 251 252 void 253 nv_free(void *buf) 254 { 255 if (buf == NULL) 256 return; 257 unsigned int *olen = (void *)((char *)buf - sizeof(unsigned int)); 258 dealloc(buf, *olen); 259 } 260 261 void * 262 nv_realloc(void *buf, size_t len) 263 { 264 if (buf == NULL) 265 return alloc(len); 266 267 unsigned int *olen = (void *)((char *)buf - sizeof(unsigned int)); 268 if (*olen < len) 269 return buf; 270 271 void *nbuf = alloc(len); 272 memcpy(nbuf, buf, *olen); 273 dealloc(buf, *olen); 274 return nbuf; 275 } 276 #endif 277