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