Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/dev/bhnd/nvram/bhnd_nvram_data_bcmraw.c
39536 views
1
/*-
2
* Copyright (c) 2016 Landon Fuller <[email protected]>
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/ctype.h>
35
#include <sys/malloc.h>
36
#include <sys/systm.h>
37
38
#else /* !_KERNEL */
39
40
#include <ctype.h>
41
#include <stdint.h>
42
#include <stdio.h>
43
#include <stdlib.h>
44
#include <string.h>
45
46
#endif /* _KERNEL */
47
48
#include "bhnd_nvram_private.h"
49
50
#include "bhnd_nvram_datavar.h"
51
#include "bhnd_nvram_data_bcmvar.h"
52
53
/*
54
* Broadcom-RAW NVRAM data class.
55
*
56
* The Broadcom NVRAM NUL-delimited ASCII format is used by most
57
* Broadcom SoCs.
58
*
59
* The NVRAM data is encoded as a stream of NUL-terminated 'key=value'
60
* strings; the end of the stream is denoted by a single extra NUL character.
61
*/
62
63
struct bhnd_nvram_bcmraw;
64
65
/** BCM-RAW NVRAM data class instance */
66
struct bhnd_nvram_bcmraw {
67
struct bhnd_nvram_data nv; /**< common instance state */
68
char *data; /**< backing buffer */
69
size_t size; /**< buffer size */
70
size_t count; /**< variable count */
71
};
72
73
BHND_NVRAM_DATA_CLASS_DEFN(bcmraw, "Broadcom (RAW)",
74
BHND_NVRAM_DATA_CAP_DEVPATHS, sizeof(struct bhnd_nvram_bcmraw))
75
76
static int
77
bhnd_nvram_bcmraw_probe(struct bhnd_nvram_io *io)
78
{
79
char envp[16];
80
size_t envp_len;
81
size_t io_size;
82
int error;
83
84
io_size = bhnd_nvram_io_getsize(io);
85
86
/*
87
* Fetch initial bytes
88
*/
89
envp_len = bhnd_nv_ummin(sizeof(envp), io_size);
90
if ((error = bhnd_nvram_io_read(io, 0x0, envp, envp_len)))
91
return (error);
92
93
/* An empty BCM-RAW buffer should still contain a single terminating
94
* NUL */
95
if (envp_len == 0)
96
return (ENXIO);
97
98
if (envp_len == 1) {
99
if (envp[0] != '\0')
100
return (ENXIO);
101
102
return (BHND_NVRAM_DATA_PROBE_MAYBE);
103
}
104
105
/* Must contain only printable ASCII characters delimited
106
* by NUL record delimiters */
107
for (size_t i = 0; i < envp_len; i++) {
108
char c = envp[i];
109
110
/* If we hit a newline, this is probably BCM-TXT */
111
if (c == '\n')
112
return (ENXIO);
113
114
if (c == '\0' && !bhnd_nv_isprint(c))
115
continue;
116
}
117
118
/* A valid BCM-RAW buffer should contain a terminating NUL for
119
* the last record, followed by a final empty record terminated by
120
* NUL */
121
envp_len = 2;
122
if (io_size < envp_len)
123
return (ENXIO);
124
125
if ((error = bhnd_nvram_io_read(io, io_size-envp_len, envp, envp_len)))
126
return (error);
127
128
if (envp[0] != '\0' || envp[1] != '\0')
129
return (ENXIO);
130
131
return (BHND_NVRAM_DATA_PROBE_MAYBE + 1);
132
}
133
134
static int
135
bhnd_nvram_bcmraw_getvar_direct(struct bhnd_nvram_io *io, const char *name,
136
void *buf, size_t *len, bhnd_nvram_type type)
137
{
138
return (bhnd_nvram_bcm_getvar_direct_common(io, name, buf, len, type,
139
false));
140
}
141
142
static int
143
bhnd_nvram_bcmraw_serialize(bhnd_nvram_data_class *cls, bhnd_nvram_plist *props,
144
bhnd_nvram_plist *options, void *outp, size_t *olen)
145
{
146
bhnd_nvram_prop *prop;
147
size_t limit, nbytes;
148
int error;
149
150
/* Determine output byte limit */
151
if (outp != NULL)
152
limit = *olen;
153
else
154
limit = 0;
155
156
nbytes = 0;
157
158
/* Write all properties */
159
prop = NULL;
160
while ((prop = bhnd_nvram_plist_next(props, prop)) != NULL) {
161
const char *name;
162
char *p;
163
size_t prop_limit;
164
size_t name_len, value_len;
165
166
if (outp == NULL || limit < nbytes) {
167
p = NULL;
168
prop_limit = 0;
169
} else {
170
p = ((char *)outp) + nbytes;
171
prop_limit = limit - nbytes;
172
}
173
174
/* Fetch and write name + '=' to output */
175
name = bhnd_nvram_prop_name(prop);
176
name_len = strlen(name) + 1;
177
178
if (prop_limit > name_len) {
179
memcpy(p, name, name_len - 1);
180
p[name_len - 1] = '=';
181
182
prop_limit -= name_len;
183
p += name_len;
184
} else {
185
prop_limit = 0;
186
p = NULL;
187
}
188
189
/* Advance byte count */
190
if (SIZE_MAX - nbytes < name_len)
191
return (EFTYPE); /* would overflow size_t */
192
193
nbytes += name_len;
194
195
/* Attempt to write NUL-terminated value to output */
196
value_len = prop_limit;
197
error = bhnd_nvram_prop_encode(prop, p, &value_len,
198
BHND_NVRAM_TYPE_STRING);
199
200
/* If encoding failed for any reason other than ENOMEM (which
201
* we'll detect and report after encoding all properties),
202
* return immediately */
203
if (error && error != ENOMEM) {
204
BHND_NV_LOG("error serializing %s to required type "
205
"%s: %d\n", name,
206
bhnd_nvram_type_name(BHND_NVRAM_TYPE_STRING),
207
error);
208
return (error);
209
}
210
211
/* Advance byte count */
212
if (SIZE_MAX - nbytes < value_len)
213
return (EFTYPE); /* would overflow size_t */
214
215
nbytes += value_len;
216
}
217
218
/* Write terminating '\0' */
219
if (limit > nbytes)
220
*((char *)outp + nbytes) = '\0';
221
222
if (nbytes == SIZE_MAX)
223
return (EFTYPE); /* would overflow size_t */
224
else
225
nbytes++;
226
227
/* Provide required length */
228
*olen = nbytes;
229
if (limit < *olen) {
230
if (outp == NULL)
231
return (0);
232
233
return (ENOMEM);
234
}
235
236
return (0);
237
}
238
239
/**
240
* Initialize @p bcm with the provided NVRAM data mapped by @p src.
241
*
242
* @param bcm A newly allocated data instance.
243
*/
244
static int
245
bhnd_nvram_bcmraw_init(struct bhnd_nvram_bcmraw *bcm, struct bhnd_nvram_io *src)
246
{
247
size_t io_size;
248
size_t capacity, offset;
249
int error;
250
251
/* Fetch the input image size */
252
io_size = bhnd_nvram_io_getsize(src);
253
254
/* Allocate a buffer large enough to hold the NVRAM image, and
255
* an extra EOF-signaling NUL (on the chance it's missing from the
256
* source data) */
257
if (io_size == SIZE_MAX)
258
return (ENOMEM);
259
260
capacity = io_size + 1 /* room for extra NUL */;
261
bcm->size = io_size;
262
if ((bcm->data = bhnd_nv_malloc(capacity)) == NULL)
263
return (ENOMEM);
264
265
/* Copy in the NVRAM image */
266
if ((error = bhnd_nvram_io_read(src, 0x0, bcm->data, io_size)))
267
return (error);
268
269
/* Process the buffer */
270
bcm->count = 0;
271
for (offset = 0; offset < bcm->size; offset++) {
272
char *envp;
273
const char *name, *value;
274
size_t envp_len;
275
size_t name_len, value_len;
276
277
/* Parse the key=value string */
278
envp = (char *) (bcm->data + offset);
279
envp_len = strnlen(envp, bcm->size - offset);
280
error = bhnd_nvram_parse_env(envp, envp_len, '=', &name,
281
&name_len, &value, &value_len);
282
if (error) {
283
BHND_NV_LOG("error parsing envp at offset %#zx: %d\n",
284
offset, error);
285
return (error);
286
}
287
288
/* Insert a '\0' character, replacing the '=' delimiter and
289
* allowing us to vend references directly to the variable
290
* name */
291
*(envp + name_len) = '\0';
292
293
/* Add to variable count */
294
bcm->count++;
295
296
/* Seek past the value's terminating '\0' */
297
offset += envp_len;
298
if (offset == io_size) {
299
BHND_NV_LOG("missing terminating NUL at offset %#zx\n",
300
offset);
301
return (EINVAL);
302
}
303
304
/* If we hit EOF without finding a terminating NUL
305
* byte, we need to append it */
306
if (++offset == bcm->size) {
307
BHND_NV_ASSERT(offset < capacity,
308
("appending past end of buffer"));
309
bcm->size++;
310
*(bcm->data + offset) = '\0';
311
}
312
313
/* Check for explicit EOF (encoded as a single empty NUL
314
* terminated string) */
315
if (*(bcm->data + offset) == '\0')
316
break;
317
}
318
319
/* Reclaim any unused space in the backing buffer */
320
if (offset < bcm->size) {
321
bcm->data = bhnd_nv_reallocf(bcm->data, bcm->size);
322
if (bcm->data == NULL)
323
return (ENOMEM);
324
}
325
326
return (0);
327
}
328
329
static int
330
bhnd_nvram_bcmraw_new(struct bhnd_nvram_data *nv, struct bhnd_nvram_io *io)
331
{
332
struct bhnd_nvram_bcmraw *bcm;
333
int error;
334
335
bcm = (struct bhnd_nvram_bcmraw *)nv;
336
337
/* Parse the BCM input data and initialize our backing
338
* data representation */
339
if ((error = bhnd_nvram_bcmraw_init(bcm, io))) {
340
bhnd_nvram_bcmraw_free(nv);
341
return (error);
342
}
343
344
return (0);
345
}
346
347
static void
348
bhnd_nvram_bcmraw_free(struct bhnd_nvram_data *nv)
349
{
350
struct bhnd_nvram_bcmraw *bcm = (struct bhnd_nvram_bcmraw *)nv;
351
352
if (bcm->data != NULL)
353
bhnd_nv_free(bcm->data);
354
}
355
356
static bhnd_nvram_plist *
357
bhnd_nvram_bcmraw_options(struct bhnd_nvram_data *nv)
358
{
359
return (NULL);
360
}
361
362
static size_t
363
bhnd_nvram_bcmraw_count(struct bhnd_nvram_data *nv)
364
{
365
struct bhnd_nvram_bcmraw *bcm = (struct bhnd_nvram_bcmraw *)nv;
366
367
return (bcm->count);
368
}
369
370
static uint32_t
371
bhnd_nvram_bcmraw_caps(struct bhnd_nvram_data *nv)
372
{
373
return (BHND_NVRAM_DATA_CAP_READ_PTR|BHND_NVRAM_DATA_CAP_DEVPATHS);
374
}
375
376
static const char *
377
bhnd_nvram_bcmraw_next(struct bhnd_nvram_data *nv, void **cookiep)
378
{
379
struct bhnd_nvram_bcmraw *bcm;
380
const char *envp;
381
382
bcm = (struct bhnd_nvram_bcmraw *)nv;
383
384
if (*cookiep == NULL) {
385
/* Start at the first NVRAM data record */
386
envp = bcm->data;
387
} else {
388
/* Seek to next record */
389
envp = *cookiep;
390
envp += strlen(envp) + 1; /* key + '\0' */
391
envp += strlen(envp) + 1; /* value + '\0' */
392
}
393
394
/* EOF? */
395
if (*envp == '\0')
396
return (NULL);
397
398
*cookiep = (void *)(uintptr_t)envp;
399
return (envp);
400
}
401
402
static void *
403
bhnd_nvram_bcmraw_find(struct bhnd_nvram_data *nv, const char *name)
404
{
405
return (bhnd_nvram_data_generic_find(nv, name));
406
}
407
408
static int
409
bhnd_nvram_bcmraw_getvar_order(struct bhnd_nvram_data *nv, void *cookiep1,
410
void *cookiep2)
411
{
412
if (cookiep1 < cookiep2)
413
return (-1);
414
415
if (cookiep1 > cookiep2)
416
return (1);
417
418
return (0);
419
}
420
421
static int
422
bhnd_nvram_bcmraw_getvar(struct bhnd_nvram_data *nv, void *cookiep, void *buf,
423
size_t *len, bhnd_nvram_type type)
424
{
425
return (bhnd_nvram_data_generic_rp_getvar(nv, cookiep, buf, len, type));
426
}
427
428
static int
429
bhnd_nvram_bcmraw_copy_val(struct bhnd_nvram_data *nv, void *cookiep,
430
bhnd_nvram_val **value)
431
{
432
return (bhnd_nvram_data_generic_rp_copy_val(nv, cookiep, value));
433
}
434
435
static const void *
436
bhnd_nvram_bcmraw_getvar_ptr(struct bhnd_nvram_data *nv, void *cookiep,
437
size_t *len, bhnd_nvram_type *type)
438
{
439
const char *envp;
440
441
/* Cookie points to key\0value\0 -- get the value address */
442
envp = cookiep;
443
envp += strlen(envp) + 1; /* key + '\0' */
444
*len = strlen(envp) + 1; /* value + '\0' */
445
*type = BHND_NVRAM_TYPE_STRING;
446
447
return (envp);
448
}
449
450
static const char *
451
bhnd_nvram_bcmraw_getvar_name(struct bhnd_nvram_data *nv, void *cookiep)
452
{
453
/* Cookie points to key\0value\0 */
454
return (cookiep);
455
}
456
457
static int
458
bhnd_nvram_bcmraw_filter_setvar(struct bhnd_nvram_data *nv, const char *name,
459
bhnd_nvram_val *value, bhnd_nvram_val **result)
460
{
461
bhnd_nvram_val *str;
462
int error;
463
464
/* Name (trimmed of any path prefix) must be valid */
465
if (!bhnd_nvram_validate_name(bhnd_nvram_trim_path_name(name)))
466
return (EINVAL);
467
468
/* Value must be bcm-formatted string */
469
error = bhnd_nvram_val_convert_new(&str, &bhnd_nvram_val_bcm_string_fmt,
470
value, BHND_NVRAM_VAL_DYNAMIC);
471
if (error)
472
return (error);
473
474
/* Success. Transfer result ownership to the caller. */
475
*result = str;
476
return (0);
477
}
478
479
static int
480
bhnd_nvram_bcmraw_filter_unsetvar(struct bhnd_nvram_data *nv, const char *name)
481
{
482
/* We permit deletion of any variable */
483
return (0);
484
}
485
486