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 #ifdef _KERNEL 32 #include <sys/param.h> 33 #include <sys/malloc.h> 34 #include <sys/systm.h> 35 #else /* !_KERNEL */ 36 #include <errno.h> 37 #include <stdint.h> 38 #include <stdlib.h> 39 #include <string.h> 40 #endif /* _KERNEL */ 41 42 #include "bhnd_nvram_private.h" 43 44 #include "bhnd_nvram_io.h" 45 #include "bhnd_nvram_iovar.h" 46 47 /** 48 * Memory-backed NVRAM I/O context. 49 * 50 * ioptr instances are gauranteed to provide persistent references to its 51 * backing contigious memory via bhnd_nvram_io_read_ptr() and 52 * bhnd_nvram_io_write_ptr(). 53 */ 54 struct bhnd_nvram_ioptr { 55 struct bhnd_nvram_io io; /**< common I/O instance state */ 56 void *ptr; /**< backing memory */ 57 size_t size; /**< size at @p ptr */ 58 size_t capacity; /**< capacity at @p ptr */ 59 uint32_t flags; /**< flags (see BHND_NVRAM_IOPTR_*) */ 60 }; 61 62 BHND_NVRAM_IOPS_DEFN(ioptr) 63 64 /** 65 * Allocate and return a new I/O context, mapping @p size bytes at @p ptr. 66 67 * The caller is responsible for deallocating the returned I/O context via 68 * bhnd_nvram_io_free(). 69 * 70 * @param ptr The pointer to be mapped by the returned I/O 71 * context. Must remain valid for the lifetime of 72 * the returned I/O context. 73 * @param size The total number of bytes mapped at @p ptr. 74 * @param capacity The maximum number of bytes that may be mapped 75 * at @p ptr via bhnd_nvram_ioptr_setsize(). 76 * @param flags Access flags (see BHND_NVRAM_IOPTR_*). 77 * 78 * @retval bhnd_nvram_io success. 79 * @retval NULL allocation failed. 80 * @retval NULL the requested @p capacity is less than @p size. 81 */ 82 struct bhnd_nvram_io * 83 bhnd_nvram_ioptr_new(const void *ptr, size_t size, size_t capacity, 84 uint32_t flags) 85 { 86 struct bhnd_nvram_ioptr *ioptr; 87 88 /* Sanity check the capacity */ 89 if (size > capacity) 90 return (NULL); 91 92 /* Allocate I/O context */ 93 ioptr = bhnd_nv_malloc(sizeof(*ioptr)); 94 if (ioptr == NULL) 95 return (NULL); 96 97 ioptr->io.iops = &bhnd_nvram_ioptr_ops; 98 ioptr->ptr = __DECONST(void *, ptr); 99 ioptr->size = size; 100 ioptr->capacity = capacity; 101 ioptr->flags = flags; 102 103 return (&ioptr->io); 104 } 105 106 static void 107 bhnd_nvram_ioptr_free(struct bhnd_nvram_io *io) 108 { 109 bhnd_nv_free(io); 110 } 111 112 static size_t 113 bhnd_nvram_ioptr_getsize(struct bhnd_nvram_io *io) 114 { 115 struct bhnd_nvram_ioptr *ioptr = (struct bhnd_nvram_ioptr *)io; 116 return (ioptr->size); 117 } 118 119 static int 120 bhnd_nvram_ioptr_setsize(struct bhnd_nvram_io *io, size_t size) 121 { 122 struct bhnd_nvram_ioptr *ioptr = (struct bhnd_nvram_ioptr *)io; 123 124 /* Must be writable */ 125 if (!(ioptr->flags & BHND_NVRAM_IOPTR_RDWR)) 126 return (ENODEV); 127 128 /* Can't exceed the actual capacity */ 129 if (size > ioptr->capacity) 130 return (ENXIO); 131 132 ioptr->size = size; 133 return (0); 134 } 135 136 /* Common ioptr_(read|write)_ptr implementation */ 137 static int 138 bhnd_nvram_ioptr_ptr(struct bhnd_nvram_ioptr *ioptr, size_t offset, void **ptr, 139 size_t nbytes, size_t *navail) 140 { 141 size_t avail; 142 143 /* Verify offset+nbytes fall within the buffer range */ 144 if (offset > ioptr->size) 145 return (ENXIO); 146 147 avail = ioptr->size - offset; 148 if (avail < nbytes) 149 return (ENXIO); 150 151 /* Valid I/O range, provide a pointer to the buffer and the 152 * total count of available bytes */ 153 *ptr = ((uint8_t *)ioptr->ptr) + offset; 154 if (navail != NULL) 155 *navail = avail; 156 157 return (0); 158 } 159 160 static int 161 bhnd_nvram_ioptr_read_ptr(struct bhnd_nvram_io *io, size_t offset, 162 const void **ptr, size_t nbytes, size_t *navail) 163 { 164 struct bhnd_nvram_ioptr *ioptr; 165 void *writep; 166 int error; 167 168 ioptr = (struct bhnd_nvram_ioptr *) io; 169 170 /* Return a pointer into our backing buffer */ 171 error = bhnd_nvram_ioptr_ptr(ioptr, offset, &writep, nbytes, navail); 172 if (error) 173 return (error); 174 175 *ptr = writep; 176 177 return (0); 178 } 179 180 static int 181 bhnd_nvram_ioptr_write_ptr(struct bhnd_nvram_io *io, size_t offset, 182 void **ptr, size_t nbytes, size_t *navail) 183 { 184 struct bhnd_nvram_ioptr *ioptr; 185 186 ioptr = (struct bhnd_nvram_ioptr *) io; 187 188 /* Must be writable */ 189 if (!(ioptr->flags & BHND_NVRAM_IOPTR_RDWR)) 190 return (ENODEV); 191 192 /* Return a pointer into our backing buffer */ 193 return (bhnd_nvram_ioptr_ptr(ioptr, offset, ptr, nbytes, navail)); 194 } 195 196 static int 197 bhnd_nvram_ioptr_read(struct bhnd_nvram_io *io, size_t offset, void *buffer, 198 size_t nbytes) 199 { 200 const void *ptr; 201 int error; 202 203 /* Try to fetch a direct pointer for at least nbytes */ 204 if ((error = bhnd_nvram_io_read_ptr(io, offset, &ptr, nbytes, NULL))) 205 return (error); 206 207 /* Copy out the requested data */ 208 memcpy(buffer, ptr, nbytes); 209 return (0); 210 } 211 212 static int 213 bhnd_nvram_ioptr_write(struct bhnd_nvram_io *io, size_t offset, 214 void *buffer, size_t nbytes) 215 { 216 void *ptr; 217 int error; 218 219 /* Try to fetch a direct pointer for at least nbytes */ 220 if ((error = bhnd_nvram_io_write_ptr(io, offset, &ptr, nbytes, NULL))) 221 return (error); 222 223 /* Copy in the provided data */ 224 memcpy(ptr, buffer, nbytes); 225 return (0); 226 } 227