1 /*-
2 * Copyright (c) 2015-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: stable/12/sys/dev/bhnd/nvram/bhnd_nvram_data.c 315866 2017-03-23 19:29:12Z landonf $");
32
33
34 #ifdef _KERNEL
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38
39 #include <machine/_inttypes.h>
40
41 #else /* !_KERNEL */
42
43 #include <errno.h>
44 #include <stdint.h>
45 #include <stdlib.h>
46 #include <string.h>
47
48 #endif /* _KERNEL */
49
50 #include "bhnd_nvram_private.h"
51 #include "bhnd_nvram_io.h"
52
53 #include "bhnd_nvram_datavar.h"
54 #include "bhnd_nvram_data.h"
55
56 /**
57 * Return a human-readable description for the given NVRAM data class.
58 *
59 * @param cls The NVRAM class.
60 */
61 const char *
bhnd_nvram_data_class_desc(bhnd_nvram_data_class * cls)62 bhnd_nvram_data_class_desc(bhnd_nvram_data_class *cls)
63 {
64 return (cls->desc);
65 }
66
67 /**
68 * Return the class-level capability flags (@see BHND_NVRAM_DATA_CAP_*) for
69 * of @p cls.
70 *
71 * @param cls The NVRAM class.
72 */
73 uint32_t
bhnd_nvram_data_class_caps(bhnd_nvram_data_class * cls)74 bhnd_nvram_data_class_caps(bhnd_nvram_data_class *cls)
75 {
76 return (cls->caps);
77 }
78
79 /**
80 * Serialize all NVRAM properties in @p plist using @p cls's NVRAM data
81 * format, writing the result to @p outp.
82 *
83 * @param cls The NVRAM data class to be used to perform
84 * serialization.
85 * @param props The raw property values to be serialized to
86 * @p outp, in serialization order.
87 * @param options Serialization options for @p cls, or NULL.
88 * @param[out] outp On success, the serialed NVRAM data will be
89 * written to this buffer. This argment may be
90 * NULL if the value is not desired.
91 * @param[in,out] olen The capacity of @p buf. On success, will be set
92 * to the actual length of the serialized data.
93 *
94 * @retval 0 success
95 *
96 * @retval ENOMEM If @p outp is non-NULL and a buffer of @p olen is too
97 * small to hold the serialized data.
98 * @retval EINVAL If a property value required by @p cls is not found in
99 * @p plist.
100 * @retval EFTYPE If a property value in @p plist cannot be represented
101 * as the data type required by @p cls.
102 * @retval ERANGE If a property value in @p plist would would overflow
103 * (or underflow) the data type required by @p cls.
104 * @retval non-zero If serialization otherwise fails, a regular unix error
105 * code will be returned.
106 */
107 int
bhnd_nvram_data_serialize(bhnd_nvram_data_class * cls,bhnd_nvram_plist * props,bhnd_nvram_plist * options,void * outp,size_t * olen)108 bhnd_nvram_data_serialize(bhnd_nvram_data_class *cls,
109 bhnd_nvram_plist *props, bhnd_nvram_plist *options, void *outp,
110 size_t *olen)
111 {
112 return (cls->op_serialize(cls, props, options, outp, olen));
113 }
114
115 /**
116 * Probe to see if this NVRAM data class class supports the data mapped by the
117 * given I/O context, returning a BHND_NVRAM_DATA_PROBE probe result.
118 *
119 * @param cls The NVRAM class.
120 * @param io An I/O context mapping the NVRAM data.
121 *
122 * @retval 0 if this is the only possible NVRAM data class for @p io.
123 * @retval negative if the probe succeeds, a negative value should be returned;
124 * the class returning the highest negative value should be selected to handle
125 * NVRAM parsing.
126 * @retval ENXIO If the NVRAM format is not handled by @p cls.
127 * @retval positive if an error occurs during probing, a regular unix error
128 * code should be returned.
129 */
130 int
bhnd_nvram_data_probe(bhnd_nvram_data_class * cls,struct bhnd_nvram_io * io)131 bhnd_nvram_data_probe(bhnd_nvram_data_class *cls, struct bhnd_nvram_io *io)
132 {
133 return (cls->op_probe(io));
134 }
135
136 /**
137 * Probe to see if an NVRAM data class in @p classes supports parsing
138 * of the data mapped by @p io, returning the parsed data in @p data.
139 *
140 * The caller is responsible for deallocating the returned instance via
141 * bhnd_nvram_data_release().
142 *
143 * @param[out] data On success, the parsed NVRAM data instance.
144 * @param io An I/O context mapping the NVRAM data to be copied and parsed.
145 * @param classes An array of NVRAM data classes to be probed, or NULL to
146 * probe the default supported set.
147 * @param num_classes The number of NVRAM data classes in @p classes.
148 *
149 * @retval 0 success
150 * @retval ENXIO if no class is found capable of parsing @p io.
151 * @retval non-zero if an error otherwise occurs during allocation,
152 * initialization, or parsing of the NVRAM data, a regular unix error code
153 * will be returned.
154 */
155 int
bhnd_nvram_data_probe_classes(struct bhnd_nvram_data ** data,struct bhnd_nvram_io * io,bhnd_nvram_data_class * classes[],size_t num_classes)156 bhnd_nvram_data_probe_classes(struct bhnd_nvram_data **data,
157 struct bhnd_nvram_io *io, bhnd_nvram_data_class *classes[],
158 size_t num_classes)
159 {
160 bhnd_nvram_data_class *cls;
161 int error, prio, result;
162
163 cls = NULL;
164 prio = 0;
165 *data = NULL;
166
167 /* If class array is NULL, default to our linker set */
168 if (classes == NULL) {
169 classes = SET_BEGIN(bhnd_nvram_data_class_set);
170 num_classes = SET_COUNT(bhnd_nvram_data_class_set);
171 }
172
173 /* Try to find the best data class capable of parsing io */
174 for (size_t i = 0; i < num_classes; i++) {
175 bhnd_nvram_data_class *next_cls;
176
177 next_cls = classes[i];
178
179 /* Try to probe */
180 result = bhnd_nvram_data_probe(next_cls, io);
181
182 /* The parser did not match if an error was returned */
183 if (result > 0)
184 continue;
185
186 /* Lower priority than previous match; keep
187 * searching */
188 if (cls != NULL && result <= prio)
189 continue;
190
191 /* Drop any previously parsed data */
192 if (*data != NULL) {
193 bhnd_nvram_data_release(*data);
194 *data = NULL;
195 }
196
197 /* If this is a 'maybe' match, attempt actual parsing to
198 * verify that this does in fact match */
199 if (result <= BHND_NVRAM_DATA_PROBE_MAYBE) {
200 /* If parsing fails, keep searching */
201 error = bhnd_nvram_data_new(next_cls, data, io);
202 if (error)
203 continue;
204 }
205
206 /* Record best new match */
207 prio = result;
208 cls = next_cls;
209
210
211 /* Terminate search immediately on
212 * BHND_NVRAM_DATA_PROBE_SPECIFIC */
213 if (result == BHND_NVRAM_DATA_PROBE_SPECIFIC)
214 break;
215 }
216
217 /* If no match, return error */
218 if (cls == NULL)
219 return (ENXIO);
220
221 /* If the NVRAM data was not parsed above, do so now */
222 if (*data == NULL) {
223 if ((error = bhnd_nvram_data_new(cls, data, io)))
224 return (error);
225 }
226
227 return (0);
228 }
229
230 /**
231 * Read a variable directly from @p io and decode as @p type.
232 *
233 * This may be used to perform reading of NVRAM variables during the very
234 * early boot process, prior to the availability of the kernel allocator.
235 *
236 * @param cls An NVRAM class capable of parsing @p io.
237 * @param io NVRAM data to be parsed.
238 * @param name The raw name of the variable to be fetched,
239 * including any device path (/pci/1/1/varname) or
240 * alias prefix (0:varname).
241 * @param[out] buf On success, the requested value will be written
242 * to this buffer. This argment may be NULL if
243 * the value is not desired.
244 * @param[in,out] len The capacity of @p buf. On success, will be set
245 * to the actual size of the requested value.
246 * @param type The data type to be written to @p buf.
247 *
248 * @retval 0 success
249 * @retval ENOMEM If @p buf is non-NULL and a buffer of @p len is too
250 * small to hold the requested value.
251 * @retval ENOENT If @p name is not found in @p io.
252 * @retval EFTYPE If the variable data cannot be coerced to @p type.
253 * @retval ERANGE If value coercion would overflow @p type.
254 * @retval non-zero If parsing @p io otherwise fails, a regular unix error
255 * code will be returned.
256 */
257 int
bhnd_nvram_data_getvar_direct(bhnd_nvram_data_class * cls,struct bhnd_nvram_io * io,const char * name,void * buf,size_t * len,bhnd_nvram_type type)258 bhnd_nvram_data_getvar_direct(bhnd_nvram_data_class *cls,
259 struct bhnd_nvram_io *io, const char *name, void *buf, size_t *len,
260 bhnd_nvram_type type)
261 {
262 return (cls->op_getvar_direct(io, name, buf, len, type));
263 }
264
265 /**
266 * Allocate and initialize a new instance of data class @p cls, copying and
267 * parsing NVRAM data from @p io.
268 *
269 * The caller is responsible for releasing the returned parser instance
270 * reference via bhnd_nvram_data_release().
271 *
272 * @param cls If non-NULL, the data class to be allocated. If NULL,
273 * bhnd_nvram_data_probe_classes() will be used to determine the data format.
274 * @param[out] nv On success, a pointer to the newly allocated NVRAM data instance.
275 * @param io An I/O context mapping the NVRAM data to be copied and parsed.
276 *
277 * @retval 0 success
278 * @retval non-zero if an error occurs during allocation or initialization, a
279 * regular unix error code will be returned.
280 */
281 int
bhnd_nvram_data_new(bhnd_nvram_data_class * cls,struct bhnd_nvram_data ** nv,struct bhnd_nvram_io * io)282 bhnd_nvram_data_new(bhnd_nvram_data_class *cls, struct bhnd_nvram_data **nv,
283 struct bhnd_nvram_io *io)
284 {
285 struct bhnd_nvram_data *data;
286 int error;
287
288 /* If NULL, try to identify the appropriate class */
289 if (cls == NULL)
290 return (bhnd_nvram_data_probe_classes(nv, io, NULL, 0));
291
292 /* Allocate new instance */
293 BHND_NV_ASSERT(sizeof(struct bhnd_nvram_data) <= cls->size,
294 ("instance size %zu less than minimum %zu", cls->size,
295 sizeof(struct bhnd_nvram_data)));
296
297 data = bhnd_nv_calloc(1, cls->size);
298 data->cls = cls;
299 refcount_init(&data->refs, 1);
300
301 /* Let the class handle initialization */
302 if ((error = cls->op_new(data, io))) {
303 bhnd_nv_free(data);
304 return (error);
305 }
306
307 *nv = data;
308 return (0);
309 }
310
311 /**
312 * Retain and return a reference to the given data instance.
313 *
314 * @param nv The reference to be retained.
315 */
316 struct bhnd_nvram_data *
bhnd_nvram_data_retain(struct bhnd_nvram_data * nv)317 bhnd_nvram_data_retain(struct bhnd_nvram_data *nv)
318 {
319 refcount_acquire(&nv->refs);
320 return (nv);
321 }
322
323 /**
324 * Release a reference to the given data instance.
325 *
326 * If this is the last reference, the data instance and its associated
327 * resources will be freed.
328 *
329 * @param nv The reference to be released.
330 */
331 void
bhnd_nvram_data_release(struct bhnd_nvram_data * nv)332 bhnd_nvram_data_release(struct bhnd_nvram_data *nv)
333 {
334 if (!refcount_release(&nv->refs))
335 return;
336
337 /* Free any internal resources */
338 nv->cls->op_free(nv);
339
340 /* Free the instance allocation */
341 bhnd_nv_free(nv);
342 }
343
344 /**
345 * Return a pointer to @p nv's data class.
346 *
347 * @param nv The NVRAM data instance to be queried.
348 */
349 bhnd_nvram_data_class *
bhnd_nvram_data_get_class(struct bhnd_nvram_data * nv)350 bhnd_nvram_data_get_class(struct bhnd_nvram_data *nv)
351 {
352 return (nv->cls);
353 }
354
355 /**
356 * Return the number of variables in @p nv.
357 *
358 * @param nv The NVRAM data to be queried.
359 */
360 size_t
bhnd_nvram_data_count(struct bhnd_nvram_data * nv)361 bhnd_nvram_data_count(struct bhnd_nvram_data *nv)
362 {
363 return (nv->cls->op_count(nv));
364 }
365
366 /**
367 * Return a borrowed reference to the serialization options for @p nv,
368 * suitable for use with bhnd_nvram_data_serialize(), or NULL if none.
369 *
370 * @param nv The NVRAM data to be queried.
371 */
372 bhnd_nvram_plist *
bhnd_nvram_data_options(struct bhnd_nvram_data * nv)373 bhnd_nvram_data_options(struct bhnd_nvram_data *nv)
374 {
375 return (nv->cls->op_options(nv));
376 }
377
378 /**
379 * Return the capability flags (@see BHND_NVRAM_DATA_CAP_*) for @p nv.
380 *
381 * @param nv The NVRAM data to be queried.
382 */
383 uint32_t
bhnd_nvram_data_caps(struct bhnd_nvram_data * nv)384 bhnd_nvram_data_caps(struct bhnd_nvram_data *nv)
385 {
386 return (nv->cls->op_caps(nv));
387 }
388
389 /**
390 * Iterate over @p nv, returning the names of subsequent variables.
391 *
392 * @param nv The NVRAM data to be iterated.
393 * @param[in,out] cookiep A pointer to a cookiep value previously returned
394 * by bhnd_nvram_data_next(), or a NULL value to
395 * begin iteration.
396 *
397 * @return Returns the next variable name, or NULL if there are no more
398 * variables defined in @p nv.
399 */
400 const char *
bhnd_nvram_data_next(struct bhnd_nvram_data * nv,void ** cookiep)401 bhnd_nvram_data_next(struct bhnd_nvram_data *nv, void **cookiep)
402 {
403 const char *name;
404 #ifdef BHND_NV_INVARIANTS
405 void *prev = *cookiep;
406 #endif
407
408 /* Fetch next */
409 if ((name = nv->cls->op_next(nv, cookiep)) == NULL)
410 return (NULL);
411
412 /* Enforce precedence ordering invariant between bhnd_nvram_data_next()
413 * and bhnd_nvram_data_getvar_order() */
414 #ifdef BHND_NV_INVARIANTS
415 if (prev != NULL &&
416 bhnd_nvram_data_getvar_order(nv, prev, *cookiep) > 0)
417 {
418 BHND_NV_PANIC("%s: returned out-of-order entry", __FUNCTION__);
419 }
420 #endif
421
422 return (name);
423 }
424
425 /**
426 * Search @p nv for a named variable, returning the variable's opaque reference
427 * if found, or NULL if unavailable.
428 *
429 * The BHND_NVRAM_DATA_CAP_INDEXED capability flag will be returned by
430 * bhnd_nvram_data_caps() if @p nv supports effecient name-based
431 * lookups.
432 *
433 * @param nv The NVRAM data to search.
434 * @param name The name to search for.
435 *
436 * @retval non-NULL If @p name is found, the opaque cookie value will be
437 * returned.
438 * @retval NULL If @p name is not found.
439 */
440 void *
bhnd_nvram_data_find(struct bhnd_nvram_data * nv,const char * name)441 bhnd_nvram_data_find(struct bhnd_nvram_data *nv, const char *name)
442 {
443 return (nv->cls->op_find(nv, name));
444 }
445
446 /**
447 * A generic implementation of bhnd_nvram_data_find().
448 *
449 * This implementation will use bhnd_nvram_data_next() to perform a
450 * simple O(n) case-insensitve search for @p name.
451 */
452 void *
bhnd_nvram_data_generic_find(struct bhnd_nvram_data * nv,const char * name)453 bhnd_nvram_data_generic_find(struct bhnd_nvram_data *nv, const char *name)
454 {
455 const char *next;
456 void *cookiep;
457
458 cookiep = NULL;
459 while ((next = bhnd_nvram_data_next(nv, &cookiep))) {
460 if (strcmp(name, next) == 0)
461 return (cookiep);
462 }
463
464 /* Not found */
465 return (NULL);
466 }
467
468 /**
469 * Compare the declaration order of two NVRAM variables.
470 *
471 * Variable declaration order is used to determine the current order of
472 * the variables in the source data, as well as to determine the precedence
473 * of variable declarations in data sources that define duplicate names.
474 *
475 * The comparison order will match the order of variables returned via
476 * bhnd_nvstore_path_data_next().
477 *
478 * @param nv The NVRAM data.
479 * @param cookiep1 An NVRAM variable cookie previously
480 * returned via bhnd_nvram_data_next() or
481 * bhnd_nvram_data_find().
482 * @param cookiep2 An NVRAM variable cookie previously
483 * returned via bhnd_nvram_data_next() or
484 * bhnd_nvram_data_find().
485 *
486 * @retval <= -1 If @p cookiep1 has an earlier declaration order than
487 * @p cookiep2.
488 * @retval 0 If @p cookiep1 and @p cookiep2 are identical.
489 * @retval >= 1 If @p cookiep has a later declaration order than
490 * @p cookiep2.
491 */
492 int
bhnd_nvram_data_getvar_order(struct bhnd_nvram_data * nv,void * cookiep1,void * cookiep2)493 bhnd_nvram_data_getvar_order(struct bhnd_nvram_data *nv, void *cookiep1,
494 void *cookiep2)
495 {
496 return (nv->cls->op_getvar_order(nv, cookiep1, cookiep2));
497 }
498
499 /**
500 * Read a variable and decode as @p type.
501 *
502 * @param nv The NVRAM data.
503 * @param cookiep An NVRAM variable cookie previously returned
504 * via bhnd_nvram_data_next() or
505 * bhnd_nvram_data_find().
506 * @param[out] buf On success, the requested value will be written
507 * to this buffer. This argment may be NULL if
508 * the value is not desired.
509 * @param[in,out] len The capacity of @p buf. On success, will be set
510 * to the actual size of the requested value.
511 * @param type The data type to be written to @p buf.
512 *
513 * @retval 0 success
514 * @retval ENOMEM If @p buf is non-NULL and a buffer of @p len is too
515 * small to hold the requested value.
516 * @retval EFTYPE If the variable data cannot be coerced to @p type.
517 * @retval ERANGE If value coercion would overflow @p type.
518 */
519 int
bhnd_nvram_data_getvar(struct bhnd_nvram_data * nv,void * cookiep,void * buf,size_t * len,bhnd_nvram_type type)520 bhnd_nvram_data_getvar(struct bhnd_nvram_data *nv, void *cookiep, void *buf,
521 size_t *len, bhnd_nvram_type type)
522 {
523 return (nv->cls->op_getvar(nv, cookiep, buf, len, type));
524 }
525
526 /*
527 * Common bhnd_nvram_data_getvar_ptr() wrapper used by
528 * bhnd_nvram_data_generic_rp_getvar() and
529 * bhnd_nvram_data_generic_rp_copy_val().
530 *
531 * If a variable definition for the requested variable is found via
532 * bhnd_nvram_find_vardefn(), the definition will be used to populate fmt.
533 */
534 static const void *
bhnd_nvram_data_getvar_ptr_info(struct bhnd_nvram_data * nv,void * cookiep,size_t * len,bhnd_nvram_type * type,const bhnd_nvram_val_fmt ** fmt)535 bhnd_nvram_data_getvar_ptr_info(struct bhnd_nvram_data *nv, void *cookiep,
536 size_t *len, bhnd_nvram_type *type, const bhnd_nvram_val_fmt **fmt)
537 {
538 const struct bhnd_nvram_vardefn *vdefn;
539 const char *name;
540 const void *vptr;
541
542 BHND_NV_ASSERT(bhnd_nvram_data_caps(nv) & BHND_NVRAM_DATA_CAP_READ_PTR,
543 ("instance does not advertise READ_PTR support"));
544
545 /* Fetch pointer to variable data */
546 vptr = bhnd_nvram_data_getvar_ptr(nv, cookiep, len, type);
547 if (vptr == NULL)
548 return (NULL);
549
550 /* Select a default value format implementation */
551
552
553 /* Fetch the reference variable name */
554 name = bhnd_nvram_data_getvar_name(nv, cookiep);
555
556 /* Trim path prefix, if any; the Broadcom NVRAM format assumes a global
557 * namespace for all variable definitions */
558 if (bhnd_nvram_data_caps(nv) & BHND_NVRAM_DATA_CAP_DEVPATHS)
559 name = bhnd_nvram_trim_path_name(name);
560
561 /* Check the variable definition table for a matching entry; if
562 * it exists, use it to populate the value format. */
563 vdefn = bhnd_nvram_find_vardefn(name);
564 if (vdefn != NULL) {
565 BHND_NV_ASSERT(vdefn->fmt != NULL,
566 ("NULL format for %s", name));
567 *fmt = vdefn->fmt;
568 } else if (*type == BHND_NVRAM_TYPE_STRING) {
569 /* Default to Broadcom-specific string interpretation */
570 *fmt = &bhnd_nvram_val_bcm_string_fmt;
571 } else {
572 /* Fall back on native formatting */
573 *fmt = bhnd_nvram_val_default_fmt(*type);
574 }
575
576 return (vptr);
577 }
578
579 /**
580 * A generic implementation of bhnd_nvram_data_getvar().
581 *
582 * This implementation will call bhnd_nvram_data_getvar_ptr() to fetch
583 * a pointer to the variable data and perform data coercion on behalf
584 * of the caller.
585 *
586 * If a variable definition for the requested variable is available via
587 * bhnd_nvram_find_vardefn(), the definition will be used to provide a
588 * formatting instance to bhnd_nvram_val_init().
589 */
590 int
bhnd_nvram_data_generic_rp_getvar(struct bhnd_nvram_data * nv,void * cookiep,void * outp,size_t * olen,bhnd_nvram_type otype)591 bhnd_nvram_data_generic_rp_getvar(struct bhnd_nvram_data *nv, void *cookiep,
592 void *outp, size_t *olen, bhnd_nvram_type otype)
593 {
594 bhnd_nvram_val val;
595 const bhnd_nvram_val_fmt *fmt;
596 const void *vptr;
597 bhnd_nvram_type vtype;
598 size_t vlen;
599 int error;
600
601 BHND_NV_ASSERT(bhnd_nvram_data_caps(nv) & BHND_NVRAM_DATA_CAP_READ_PTR,
602 ("instance does not advertise READ_PTR support"));
603
604 /* Fetch variable data and value format*/
605 vptr = bhnd_nvram_data_getvar_ptr_info(nv, cookiep, &vlen, &vtype,
606 &fmt);
607 if (vptr == NULL)
608 return (EINVAL);
609
610 /* Attempt value coercion */
611 error = bhnd_nvram_val_init(&val, fmt, vptr, vlen, vtype,
612 BHND_NVRAM_VAL_BORROW_DATA);
613 if (error)
614 return (error);
615
616 error = bhnd_nvram_val_encode(&val, outp, olen, otype);
617
618 /* Clean up */
619 bhnd_nvram_val_release(&val);
620 return (error);
621 }
622
623 /**
624 * Return a caller-owned copy of an NVRAM entry's variable data.
625 *
626 * The caller is responsible for deallocating the returned value via
627 * bhnd_nvram_val_release().
628 *
629 * @param nv The NVRAM data.
630 * @param cookiep An NVRAM variable cookie previously returned
631 * via bhnd_nvram_data_next() or bhnd_nvram_data_find().
632 * @param[out] value On success, the caller-owned value instance.
633 *
634 * @retval 0 success
635 * @retval ENOMEM If allocation fails.
636 * @retval non-zero If initialization of the value otherwise fails, a
637 * regular unix error code will be returned.
638 */
639 int
bhnd_nvram_data_copy_val(struct bhnd_nvram_data * nv,void * cookiep,bhnd_nvram_val ** value)640 bhnd_nvram_data_copy_val(struct bhnd_nvram_data *nv, void *cookiep,
641 bhnd_nvram_val **value)
642 {
643 return (nv->cls->op_copy_val(nv, cookiep, value));
644 }
645
646 /**
647 * A generic implementation of bhnd_nvram_data_copy_val().
648 *
649 * This implementation will call bhnd_nvram_data_getvar_ptr() to fetch
650 * a pointer to the variable data and perform data coercion on behalf
651 * of the caller.
652 *
653 * If a variable definition for the requested variable is available via
654 * bhnd_nvram_find_vardefn(), the definition will be used to provide a
655 * formatting instance to bhnd_nvram_val_init().
656 */
657 int
bhnd_nvram_data_generic_rp_copy_val(struct bhnd_nvram_data * nv,void * cookiep,bhnd_nvram_val ** value)658 bhnd_nvram_data_generic_rp_copy_val(struct bhnd_nvram_data *nv,
659 void *cookiep, bhnd_nvram_val **value)
660 {
661 const bhnd_nvram_val_fmt *fmt;
662 const void *vptr;
663 bhnd_nvram_type vtype;
664 size_t vlen;
665
666 BHND_NV_ASSERT(bhnd_nvram_data_caps(nv) & BHND_NVRAM_DATA_CAP_READ_PTR,
667 ("instance does not advertise READ_PTR support"));
668
669 /* Fetch variable data and value format*/
670 vptr = bhnd_nvram_data_getvar_ptr_info(nv, cookiep, &vlen, &vtype,
671 &fmt);
672 if (vptr == NULL)
673 return (EINVAL);
674
675 /* Allocate and return the new value instance */
676 return (bhnd_nvram_val_new(value, fmt, vptr, vlen, vtype,
677 BHND_NVRAM_VAL_DYNAMIC));
678 }
679
680 /**
681 * If available and supported by the NVRAM data instance, return a reference
682 * to the internal buffer containing an entry's variable data,
683 *
684 * Note that string values may not be NUL terminated.
685 *
686 * @param nv The NVRAM data.
687 * @param cookiep An NVRAM variable cookie previously returned
688 * via bhnd_nvram_data_next() or
689 * bhnd_nvram_data_find().
690 * @param[out] len On success, will be set to the actual size of
691 * the requested value.
692 * @param[out] type The data type of the entry data.
693 *
694 * @retval non-NULL success
695 * @retval NULL if direct data access is unsupported by @p nv, or
696 * unavailable for @p cookiep.
697 */
698 const void *
bhnd_nvram_data_getvar_ptr(struct bhnd_nvram_data * nv,void * cookiep,size_t * len,bhnd_nvram_type * type)699 bhnd_nvram_data_getvar_ptr(struct bhnd_nvram_data *nv, void *cookiep,
700 size_t *len, bhnd_nvram_type *type)
701 {
702 return (nv->cls->op_getvar_ptr(nv, cookiep, len, type));
703 }
704
705
706 /**
707 * Return the variable name associated with a given @p cookiep.
708 * @param nv The NVRAM data to be iterated.
709 * @param[in,out] cookiep A pointer to a cookiep value previously returned
710 * via bhnd_nvram_data_next() or
711 * bhnd_nvram_data_find().
712 *
713 * @return Returns the variable's name.
714 */
715 const char *
bhnd_nvram_data_getvar_name(struct bhnd_nvram_data * nv,void * cookiep)716 bhnd_nvram_data_getvar_name(struct bhnd_nvram_data *nv, void *cookiep)
717 {
718 return (nv->cls->op_getvar_name(nv, cookiep));
719 }
720
721 /**
722 * Filter a request to set variable @p name with @p value.
723 *
724 * On success, the caller owns a reference to @p result, and must release
725 * any held resources via bhnd_nvram_val_release().
726 *
727 * @param nv The NVRAM data instance.
728 * @param name The name of the variable to be set.
729 * @param value The proposed value to be set.
730 * @param[out] result On success, a caller-owned reference to the filtered
731 * value to be set.
732 *
733 * @retval 0 success
734 * @retval ENOENT if @p name is unrecognized by @p nv.
735 * @retval EINVAL if @p name is read-only.
736 * @retval EINVAL if @p value cannot be converted to the required value
737 * type.
738 */
739 int
bhnd_nvram_data_filter_setvar(struct bhnd_nvram_data * nv,const char * name,bhnd_nvram_val * value,bhnd_nvram_val ** result)740 bhnd_nvram_data_filter_setvar(struct bhnd_nvram_data *nv, const char *name,
741 bhnd_nvram_val *value, bhnd_nvram_val **result)
742 {
743 return (nv->cls->op_filter_setvar(nv, name, value, result));
744 }
745
746 /**
747 * Filter a request to delete variable @p name.
748 *
749 * @param nv The NVRAM data instance.
750 * @param name The name of the variable to be deleted.
751 *
752 * @retval 0 success
753 * @retval ENOENT if @p name is unrecognized by @p nv.
754 * @retval EINVAL if @p name is read-only.
755 */
756 int
bhnd_nvram_data_filter_unsetvar(struct bhnd_nvram_data * nv,const char * name)757 bhnd_nvram_data_filter_unsetvar(struct bhnd_nvram_data *nv, const char *name)
758 {
759 return (nv->cls->op_filter_unsetvar(nv, name));
760 }
761