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