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