1 /*- 2 * Copyright (c) 2016 Landon Fuller <landonf@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer, 10 * without modification. 11 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 13 * redistribution must be conditioned upon including a substantially 14 * similar Disclaimer requirement for further binary redistribution. 15 * 16 * NO WARRANTY 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 20 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 21 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 22 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 * THE POSSIBILITY OF SUCH DAMAGES. 28 */ 29 30 #include <sys/cdefs.h> 31 __FBSDID("$FreeBSD$"); 32 33 #ifdef _KERNEL 34 #include <sys/param.h> 35 #include <sys/malloc.h> 36 #include <sys/systm.h> 37 #else /* !_KERNEL */ 38 #include <errno.h> 39 #include <stdint.h> 40 #include <stdlib.h> 41 #include <string.h> 42 #endif /* _KERNEL */ 43 44 #include "bhnd_nvram_private.h" 45 46 #include "bhnd_nvram_io.h" 47 #include "bhnd_nvram_iovar.h" 48 49 /** 50 * Memory-backed NVRAM I/O context. 51 * 52 * ioptr instances are gauranteed to provide persistent references to its 53 * backing contigious memory via bhnd_nvram_io_read_ptr() and 54 * bhnd_nvram_io_write_ptr(). 55 */ 56 struct bhnd_nvram_ioptr { 57 struct bhnd_nvram_io io; /**< common I/O instance state */ 58 void *ptr; /**< backing memory */ 59 size_t size; /**< size at @p ptr */ 60 size_t capacity; /**< capacity at @p ptr */ 61 uint32_t flags; /**< flags (see BHND_NVRAM_IOPTR_*) */ 62 }; 63 64 BHND_NVRAM_IOPS_DEFN(ioptr) 65 66 /** 67 * Allocate and return a new I/O context, mapping @p size bytes at @p ptr. 68 69 * The caller is responsible for deallocating the returned I/O context via 70 * bhnd_nvram_io_free(). 71 * 72 * @param ptr The pointer to be mapped by the returned I/O 73 * context. Must remain valid for the lifetime of 74 * the returned I/O context. 75 * @param size The total number of bytes mapped at @p ptr. 76 * @param capacity The maximum number of bytes that may be mapped 77 * at @p ptr via bhnd_nvram_ioptr_setsize(). 78 * @param flags Access flags (see BHND_NVRAM_IOPTR_*). 79 * 80 * @retval bhnd_nvram_io success. 81 * @retval NULL allocation failed. 82 * @retval NULL the requested @p capacity is less than @p size. 83 */ 84 struct bhnd_nvram_io * 85 bhnd_nvram_ioptr_new(const void *ptr, size_t size, size_t capacity, 86 uint32_t flags) 87 { 88 struct bhnd_nvram_ioptr *ioptr; 89 90 /* Sanity check the capacity */ 91 if (size > capacity) 92 return (NULL); 93 94 /* Allocate I/O context */ 95 ioptr = bhnd_nv_malloc(sizeof(*ioptr)); 96 if (ioptr == NULL) 97 return (NULL); 98 99 ioptr->io.iops = &bhnd_nvram_ioptr_ops; 100 ioptr->ptr = __DECONST(void *, ptr); 101 ioptr->size = size; 102 ioptr->capacity = capacity; 103 ioptr->flags = flags; 104 105 return (&ioptr->io); 106 } 107 108 static void 109 bhnd_nvram_ioptr_free(struct bhnd_nvram_io *io) 110 { 111 bhnd_nv_free(io); 112 } 113 114 static size_t 115 bhnd_nvram_ioptr_getsize(struct bhnd_nvram_io *io) 116 { 117 struct bhnd_nvram_ioptr *ioptr = (struct bhnd_nvram_ioptr *)io; 118 return (ioptr->size); 119 } 120 121 static int 122 bhnd_nvram_ioptr_setsize(struct bhnd_nvram_io *io, size_t size) 123 { 124 struct bhnd_nvram_ioptr *ioptr = (struct bhnd_nvram_ioptr *)io; 125 126 /* Must be writable */ 127 if (!(ioptr->flags & BHND_NVRAM_IOPTR_RDWR)) 128 return (ENODEV); 129 130 /* Can't exceed the actual capacity */ 131 if (size > ioptr->capacity) 132 return (ENXIO); 133 134 ioptr->size = size; 135 return (0); 136 } 137 138 /* Common ioptr_(read|write)_ptr implementation */ 139 static int 140 bhnd_nvram_ioptr_ptr(struct bhnd_nvram_ioptr *ioptr, size_t offset, void **ptr, 141 size_t nbytes, size_t *navail) 142 { 143 size_t avail; 144 145 /* Verify offset+nbytes fall within the buffer range */ 146 if (offset > ioptr->size) 147 return (ENXIO); 148 149 avail = ioptr->size - offset; 150 if (avail < nbytes) 151 return (ENXIO); 152 153 /* Valid I/O range, provide a pointer to the buffer and the 154 * total count of available bytes */ 155 *ptr = ((uint8_t *)ioptr->ptr) + offset; 156 if (navail != NULL) 157 *navail = avail; 158 159 return (0); 160 } 161 162 static int 163 bhnd_nvram_ioptr_read_ptr(struct bhnd_nvram_io *io, size_t offset, 164 const void **ptr, size_t nbytes, size_t *navail) 165 { 166 struct bhnd_nvram_ioptr *ioptr; 167 void *writep; 168 int error; 169 170 ioptr = (struct bhnd_nvram_ioptr *) io; 171 172 /* Return a pointer into our backing buffer */ 173 error = bhnd_nvram_ioptr_ptr(ioptr, offset, &writep, nbytes, navail); 174 if (error) 175 return (error); 176 177 *ptr = writep; 178 179 return (0); 180 } 181 182 static int 183 bhnd_nvram_ioptr_write_ptr(struct bhnd_nvram_io *io, size_t offset, 184 void **ptr, size_t nbytes, size_t *navail) 185 { 186 struct bhnd_nvram_ioptr *ioptr; 187 188 ioptr = (struct bhnd_nvram_ioptr *) io; 189 190 /* Must be writable */ 191 if (!(ioptr->flags & BHND_NVRAM_IOPTR_RDWR)) 192 return (ENODEV); 193 194 /* Return a pointer into our backing buffer */ 195 return (bhnd_nvram_ioptr_ptr(ioptr, offset, ptr, nbytes, navail)); 196 } 197 198 static int 199 bhnd_nvram_ioptr_read(struct bhnd_nvram_io *io, size_t offset, void *buffer, 200 size_t nbytes) 201 { 202 const void *ptr; 203 int error; 204 205 /* Try to fetch a direct pointer for at least nbytes */ 206 if ((error = bhnd_nvram_io_read_ptr(io, offset, &ptr, nbytes, NULL))) 207 return (error); 208 209 /* Copy out the requested data */ 210 memcpy(buffer, ptr, nbytes); 211 return (0); 212 } 213 214 static int 215 bhnd_nvram_ioptr_write(struct bhnd_nvram_io *io, size_t offset, 216 void *buffer, size_t nbytes) 217 { 218 void *ptr; 219 int error; 220 221 /* Try to fetch a direct pointer for at least nbytes */ 222 if ((error = bhnd_nvram_io_write_ptr(io, offset, &ptr, nbytes, NULL))) 223 return (error); 224 225 /* Copy in the provided data */ 226 memcpy(ptr, buffer, nbytes); 227 return (0); 228 } 229