xref: /freebsd/sys/dev/bhnd/nvram/bhnd_nvram_data.c (revision f81cdf24ba5436367377f7c8e8f51f6df2a75ca7)
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 *
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
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
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
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
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
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
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 *
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
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 *
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
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 *
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
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 *
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 *
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 *
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
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
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 *
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
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
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
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 *
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 *
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
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
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