2 * Copyright (c) 2016 Landon Fuller <landonf@FreeBSD.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
34 #include <sys/param.h>
35 #include <sys/malloc.h>
36 #include <sys/systm.h>
44 #include "bhnd_nvram_private.h"
46 #include "bhnd_nvram_io.h"
47 #include "bhnd_nvram_iovar.h"
50 * Buffer-backed NVRAM I/O context.
52 * iobuf instances are gauranteed to provide persistent references to its
53 * backing contigious buffer via bhnd_nvram_io_read_ptr() and
54 * bhnd_nvram_io_write_ptr().
56 struct bhnd_nvram_iobuf {
57 struct bhnd_nvram_io io; /**< common I/O instance state */
58 void *buf; /**< backing buffer. if inline-allocated, will
59 be a reference to data[]. */
60 size_t size; /**< size of @p buf */
61 size_t capacity; /**< capacity of @p buf */
62 uint8_t data[]; /**< inline buffer allocation */
65 BHND_NVRAM_IOPS_DEFN(iobuf)
68 * Allocate and return a new I/O context with an uninitialized
69 * buffer of @p size and @p capacity.
71 * The caller is responsible for deallocating the returned I/O context via
72 * bhnd_nvram_io_free().
74 * If @p capacity is less than @p size, a capacity of @p size will be used.
76 * @param size The initial size of the I/O context.
77 * @param capacity The total capacity of the I/O context buffer;
78 * the returned I/O context may be resized up to
79 * @p capacity via bhnd_nvram_io_setsize().
81 * @retval bhnd_nvram_iobuf success.
82 * @retval NULL allocation failed.
83 * @retval NULL the requested @p capacity is less than
86 struct bhnd_nvram_io *
87 bhnd_nvram_iobuf_empty(size_t size, size_t capacity)
89 struct bhnd_nvram_iobuf *iobuf;
93 /* Sanity check the capacity */
97 /* Would sizeof(iobuf)+capacity overflow? */
98 if (SIZE_MAX - sizeof(*iobuf) < capacity) {
100 iosz = sizeof(*iobuf);
103 iosz = sizeof(*iobuf) + capacity;
106 /* Allocate I/O context */
107 iobuf = bhnd_nv_malloc(iosz);
111 iobuf->io.iops = &bhnd_nvram_iobuf_ops;
114 iobuf->capacity = capacity;
116 /* Either allocate our backing buffer, or initialize the
117 * backing buffer with a reference to our inline allocation. */
119 iobuf->buf = &iobuf->data;
121 iobuf->buf = bhnd_nv_malloc(iobuf->capacity);
124 if (iobuf->buf == NULL) {
133 * Allocate and return a new I/O context, copying @p size from @p buffer.
135 * The caller is responsible for deallocating the returned I/O context via
136 * bhnd_nvram_io_free().
138 * @param buffer The buffer data be copied by the returned I/O context.
139 * @param size The size of @p buffer, in bytes.
141 * @retval bhnd_nvram_io success.
142 * @retval NULL allocation failed.
144 struct bhnd_nvram_io *
145 bhnd_nvram_iobuf_new(const void *buffer, size_t size)
147 struct bhnd_nvram_io *io;
148 struct bhnd_nvram_iobuf *iobuf;
150 /* Allocate the iobuf */
151 if ((io = bhnd_nvram_iobuf_empty(size, size)) == NULL)
154 /* Copy the input to our new iobuf instance */
155 iobuf = (struct bhnd_nvram_iobuf *)io;
156 memcpy(iobuf->buf, buffer, iobuf->size);
162 * Allocate and return a new I/O context providing an in-memory copy
163 * of the data mapped by @p src.
165 * The caller is responsible for deallocating the returned I/O context via
166 * bhnd_nvram_io_free().
168 * @param src The I/O context to be copied.
170 * @retval bhnd_nvram_io success.
171 * @retval NULL allocation failed.
172 * @retval NULL copying @p src failed.
174 struct bhnd_nvram_io *
175 bhnd_nvram_iobuf_copy(struct bhnd_nvram_io *src)
177 return (bhnd_nvram_iobuf_copy_range(src, 0x0,
178 bhnd_nvram_io_getsize(src)));
182 * Allocate and return a new I/O context providing an in-memory copy
183 * of @p size bytes mapped at @p offset by @p src.
185 * The caller is responsible for deallocating the returned I/O context via
186 * bhnd_nvram_io_free().
188 * @param src The I/O context to be copied.
189 * @param offset The offset of the bytes to be copied from @p src.
190 * @param size The number of bytes to copy at @p offset from @p src.
192 * @retval bhnd_nvram_io success.
193 * @retval NULL allocation failed.
194 * @retval NULL copying @p src failed.
196 struct bhnd_nvram_io *
197 bhnd_nvram_iobuf_copy_range(struct bhnd_nvram_io *src, size_t offset,
200 struct bhnd_nvram_io *io;
201 struct bhnd_nvram_iobuf *iobuf;
204 /* Check if offset+size would overflow */
205 if (SIZE_MAX - size < offset)
208 /* Allocate the iobuf instance */
209 if ((io = bhnd_nvram_iobuf_empty(size, size)) == NULL)
212 /* Copy the input I/O context */
213 iobuf = (struct bhnd_nvram_iobuf *)io;
214 if ((error = bhnd_nvram_io_read(src, offset, iobuf->buf, size))) {
215 bhnd_nvram_io_free(&iobuf->io);
224 bhnd_nvram_iobuf_free(struct bhnd_nvram_io *io)
226 struct bhnd_nvram_iobuf *iobuf = (struct bhnd_nvram_iobuf *)io;
228 /* Free the backing buffer if it wasn't allocated inline */
229 if (iobuf->buf != &iobuf->data)
230 bhnd_nv_free(iobuf->buf);
236 bhnd_nvram_iobuf_getsize(struct bhnd_nvram_io *io)
238 struct bhnd_nvram_iobuf *iobuf = (struct bhnd_nvram_iobuf *)io;
239 return (iobuf->size);
243 bhnd_nvram_iobuf_setsize(struct bhnd_nvram_io *io, size_t size)
245 struct bhnd_nvram_iobuf *iobuf = (struct bhnd_nvram_iobuf *)io;
247 /* Can't exceed the actual capacity */
248 if (size > iobuf->capacity)
255 /* Common iobuf_(read|write)_ptr implementation */
257 bhnd_nvram_iobuf_ptr(struct bhnd_nvram_iobuf *iobuf, size_t offset, void **ptr,
258 size_t nbytes, size_t *navail)
262 /* Verify offset+nbytes fall within the buffer range */
263 if (offset > iobuf->size)
266 avail = iobuf->size - offset;
270 /* Valid I/O range, provide a pointer to the buffer and the
271 * total count of available bytes */
272 *ptr = ((uint8_t *)iobuf->buf) + offset;
280 bhnd_nvram_iobuf_read_ptr(struct bhnd_nvram_io *io, size_t offset,
281 const void **ptr, size_t nbytes, size_t *navail)
283 struct bhnd_nvram_iobuf *iobuf;
287 iobuf = (struct bhnd_nvram_iobuf *) io;
289 /* Return a pointer into our backing buffer */
290 error = bhnd_nvram_iobuf_ptr(iobuf, offset, &ioptr, nbytes, navail);
300 bhnd_nvram_iobuf_write_ptr(struct bhnd_nvram_io *io, size_t offset,
301 void **ptr, size_t nbytes, size_t *navail)
303 struct bhnd_nvram_iobuf *iobuf;
305 iobuf = (struct bhnd_nvram_iobuf *) io;
307 /* Return a pointer into our backing buffer */
308 return (bhnd_nvram_iobuf_ptr(iobuf, offset, ptr, nbytes, navail));
312 bhnd_nvram_iobuf_read(struct bhnd_nvram_io *io, size_t offset, void *buffer,
318 /* Try to fetch a direct pointer for at least nbytes */
319 if ((error = bhnd_nvram_io_read_ptr(io, offset, &ptr, nbytes, NULL)))
322 /* Copy out the requested data */
323 memcpy(buffer, ptr, nbytes);
328 bhnd_nvram_iobuf_write(struct bhnd_nvram_io *io, size_t offset,
329 void *buffer, size_t nbytes)
334 /* Try to fetch a direct pointer for at least nbytes */
335 if ((error = bhnd_nvram_io_write_ptr(io, offset, &ptr, nbytes, NULL)))
338 /* Copy in the provided data */
339 memcpy(ptr, buffer, nbytes);