diff options
author | Landon J. Fuller <landonf@FreeBSD.org> | 2016-12-19 20:23:19 +0000 |
---|---|---|
committer | Landon J. Fuller <landonf@FreeBSD.org> | 2016-12-19 20:23:19 +0000 |
commit | 6cffadf0f0719b1e05d710fa78bed272d81a6f2a (patch) | |
tree | 123775e0d43741dea04a917565ac7ad923b0881a /sys/dev/bhnd/nvram/bhnd_nvram_value.c | |
parent | 9be0790d198726d551148198401dd3d1c35ffb56 (diff) | |
download | src-6cffadf0f0719b1e05d710fa78bed272d81a6f2a.tar.gz src-6cffadf0f0719b1e05d710fa78bed272d81a6f2a.zip |
bhnd(4): Add support for three new NVRAM value types; booleans,
NULL (which we'll use to denote deleted values in bhnd_nvram_store), and
opaque data (aka octet-strings).
Approved by: adrian (mentor)
Differential Revision: https://reviews.freebsd.org/D8758
Notes
Notes:
svn path=/head/; revision=310293
Diffstat (limited to 'sys/dev/bhnd/nvram/bhnd_nvram_value.c')
-rw-r--r-- | sys/dev/bhnd/nvram/bhnd_nvram_value.c | 331 |
1 files changed, 330 insertions, 1 deletions
diff --git a/sys/dev/bhnd/nvram/bhnd_nvram_value.c b/sys/dev/bhnd/nvram/bhnd_nvram_value.c index d3971bd6627b..a84a31498410 100644 --- a/sys/dev/bhnd/nvram/bhnd_nvram_value.c +++ b/sys/dev/bhnd/nvram/bhnd_nvram_value.c @@ -66,9 +66,19 @@ static int bhnd_nvram_val_set(bhnd_nvram_val *value, const void *inp, static int bhnd_nvram_val_set_inline(bhnd_nvram_val *value, const void *inp, size_t ilen, bhnd_nvram_type itype); + +static int bhnd_nvram_val_encode_data(const void *inp, size_t ilen, + bhnd_nvram_type itype, void *outp, size_t *olen, + bhnd_nvram_type otype); static int bhnd_nvram_val_encode_int(const void *inp, size_t ilen, bhnd_nvram_type itype, void *outp, size_t *olen, bhnd_nvram_type otype); +static int bhnd_nvram_val_encode_null(const void *inp, size_t ilen, + bhnd_nvram_type itype, void *outp, size_t *olen, + bhnd_nvram_type otype); +static int bhnd_nvram_val_encode_bool(const void *inp, size_t ilen, + bhnd_nvram_type itype, void *outp, size_t *olen, + bhnd_nvram_type otype); static int bhnd_nvram_val_encode_string(const void *inp, size_t ilen, bhnd_nvram_type itype, void *outp, size_t *olen, bhnd_nvram_type otype); @@ -83,7 +93,6 @@ static int bhnd_nvram_val_encode_string(const void *inp, size_t ilen, .data_storage = BHND_NVRAM_VAL_DATA_NONE, \ }; - /** Assert that @p value's backing representation state has initialized * as empty. */ #define BHND_NVRAM_VAL_ASSERT_EMPTY(_value) \ @@ -120,6 +129,16 @@ bhnd_nvram_val_data_storage data_storage; /**< data storage */ bhnd_nvram_type data_type; /**< data type */ size_t data_len; /**< data size */ +/* Shared NULL value instance */ +bhnd_nvram_val bhnd_nvram_val_null = { + .refs = 1, + .val_storage = BHND_NVRAM_VAL_STORAGE_STATIC, + .fmt = &bhnd_nvram_val_null_fmt, + .data_storage = BHND_NVRAM_VAL_DATA_INLINE, + .data_type = BHND_NVRAM_TYPE_NULL, + .data_len = 0, +}; + /** * Return the human-readable name of @p fmt. */ @@ -156,6 +175,12 @@ bhnd_nvram_val_default_fmt(bhnd_nvram_type type) return (&bhnd_nvram_val_char_fmt); case BHND_NVRAM_TYPE_STRING: return (&bhnd_nvram_val_string_fmt); + case BHND_NVRAM_TYPE_BOOL: + return (&bhnd_nvram_val_bool_fmt); + case BHND_NVRAM_TYPE_NULL: + return (&bhnd_nvram_val_null_fmt); + case BHND_NVRAM_TYPE_DATA: + return (&bhnd_nvram_val_data_fmt); case BHND_NVRAM_TYPE_UINT8_ARRAY: return (&bhnd_nvram_val_uint8_array_fmt); case BHND_NVRAM_TYPE_UINT16_ARRAY: @@ -176,6 +201,8 @@ bhnd_nvram_val_default_fmt(bhnd_nvram_type type) return (&bhnd_nvram_val_char_array_fmt); case BHND_NVRAM_TYPE_STRING_ARRAY: return (&bhnd_nvram_val_string_array_fmt); + case BHND_NVRAM_TYPE_BOOL_ARRAY: + return (&bhnd_nvram_val_bool_array_fmt); } /* Quiesce gcc4.2 */ @@ -635,6 +662,156 @@ bhnd_nvram_val_release(bhnd_nvram_val *value) } /** + * Standard BHND_NVRAM_TYPE_NULL encoding implementation. + */ +static int +bhnd_nvram_val_encode_null(const void *inp, size_t ilen, bhnd_nvram_type itype, + void *outp, size_t *olen, bhnd_nvram_type otype) +{ + size_t limit, nbytes; + + BHND_NV_ASSERT(itype == BHND_NVRAM_TYPE_NULL, + ("unsupported type: %d", itype)); + + /* Determine output byte limit */ + if (outp != NULL) + limit = *olen; + else + limit = 0; + + nbytes = 0; + + /* Write to output */ + switch (otype) { + case BHND_NVRAM_TYPE_NULL: + /* Can be directly encoded as a zero-length NULL value */ + nbytes = 0; + break; + default: + /* Not representable */ + return (EFTYPE); + } + + /* Provide required length */ + *olen = nbytes; + if (limit < *olen) { + if (outp == NULL) + return (0); + + return (ENOMEM); + } + + return (0); +} + +/** + * Standard BHND_NVRAM_TYPE_BOOL encoding implementation. + */ +static int +bhnd_nvram_val_encode_bool(const void *inp, size_t ilen, bhnd_nvram_type itype, + void *outp, size_t *olen, bhnd_nvram_type otype) +{ + bhnd_nvram_bool_t bval; + size_t limit, nbytes, nelem; + int error; + + BHND_NV_ASSERT(itype == BHND_NVRAM_TYPE_BOOL, + ("unsupported type: %d", itype)); + + /* Determine output byte limit */ + if (outp != NULL) + limit = *olen; + else + limit = 0; + + /* Must be exactly one element in input */ + if ((error = bhnd_nvram_value_nelem(inp, ilen, itype, &nelem))) + return (error); + + if (nelem != 1) + return (EFTYPE); + + /* Fetch (and normalize) boolean value */ + bval = (*(const bhnd_nvram_bool_t *)inp != 0) ? true : false; + + /* Write to output */ + switch (otype) { + case BHND_NVRAM_TYPE_NULL: + /* False can be directly encoded as a zero-length NULL value */ + if (bval != false) + return (EFTYPE); + + nbytes = 0; + break; + + case BHND_NVRAM_TYPE_STRING: + case BHND_NVRAM_TYPE_STRING_ARRAY: { + /* Can encode as "true" or "false" */ + const char *str = bval ? "true" : "false"; + + nbytes = strlen(str) + 1; + if (limit > nbytes) + strcpy(outp, str); + + break; + } + + default: + /* If output type is an integer, we can delegate to standard + * integer encoding to encode as zero or one. */ + if (bhnd_nvram_is_int_type(otype)) { + uint8_t ival = bval ? 1 : 0; + + return (bhnd_nvram_val_encode_int(&ival, sizeof(ival), + BHND_NVRAM_TYPE_UINT8, outp, olen, otype)); + } + + /* Otherwise not representable */ + return (EFTYPE); + } + + /* Provide required length */ + *olen = nbytes; + if (limit < *olen) { + if (outp == NULL) + return (0); + + return (ENOMEM); + } + + return (0); +} + +/** + * Standard BHND_NVRAM_TYPE_DATA encoding implementation. + */ +static int +bhnd_nvram_val_encode_data(const void *inp, size_t ilen, bhnd_nvram_type itype, + void *outp, size_t *olen, bhnd_nvram_type otype) +{ + BHND_NV_ASSERT(itype == BHND_NVRAM_TYPE_DATA, + ("unsupported type: %d", itype)); + + /* Write to output */ + switch (otype) { + case BHND_NVRAM_TYPE_STRING: + case BHND_NVRAM_TYPE_STRING_ARRAY: + /* If encoding as a string, produce an EFI-style hexadecimal + * byte array (HF1F...) by interpreting the octet string + * as an array of uint8 values */ + return (bhnd_nvram_value_printf("H%[]02hhX", inp, ilen, + BHND_NVRAM_TYPE_UINT8_ARRAY, outp, olen, "")); + + default: + /* Fall back on direct interpretation as an array of 8-bit + * integers array */ + return (bhnd_nvram_value_coerce(inp, ilen, + BHND_NVRAM_TYPE_UINT8_ARRAY, outp, olen, otype)); + } +} + + +/** * Standard string/char array/char encoding implementation. * * Input type must be one of: @@ -673,6 +850,14 @@ bhnd_nvram_val_encode_string(const void *inp, size_t ilen, /* Parse the string data and write to output */ switch (otype) { + case BHND_NVRAM_TYPE_NULL: + /* Only an empty string may be represented as a NULL value */ + if (cstr_len != 0) + return (EFTYPE); + + *olen = 0; + return (0); + case BHND_NVRAM_TYPE_CHAR: case BHND_NVRAM_TYPE_CHAR_ARRAY: /* String must contain exactly 1 non-terminating-NUL character @@ -696,6 +881,99 @@ bhnd_nvram_val_encode_string(const void *inp, size_t ilen, return (0); + case BHND_NVRAM_TYPE_BOOL: + case BHND_NVRAM_TYPE_BOOL_ARRAY: { + const char *p; + size_t plen; + bhnd_nvram_bool_t bval; + + /* Trim leading/trailing whitespace */ + p = cstr; + plen = bhnd_nvram_trim_field(&p, cstr_len, '\0'); + + /* Parse string representation */ + if (strncasecmp(p, "true", plen) == 0 || + strncasecmp(p, "yes", plen) == 0 || + strncmp(p, "1", plen) == 0) + { + bval = true; + } else if (strncasecmp(p, "false", plen) == 0 || + strncasecmp(p, "no", plen) == 0 || + strncmp(p, "0", plen) == 0) + { + bval = false; + } else { + /* Not a recognized boolean string */ + return (EFTYPE); + } + + /* Write to output */ + nbytes = sizeof(bhnd_nvram_bool_t); + if (limit >= nbytes) + *((bhnd_nvram_bool_t *)outp) = bval; + + /* Provide required length */ + *olen = nbytes; + if (limit < *olen && outp != NULL) + return (ENOMEM); + + return (0); + } + + case BHND_NVRAM_TYPE_DATA: { + const char *p; + size_t plen, parsed_len; + int error; + + /* Trim leading/trailing whitespace */ + p = cstr; + plen = bhnd_nvram_trim_field(&p, cstr_len, '\0'); + + /* Check for EFI-style hexadecimal byte array string format. + * Must have a 'H' prefix */ + if (plen < 1 || bhnd_nv_toupper(*p) != 'H') + return (EFTYPE); + + /* Skip leading 'H' */ + p++; + plen--; + + /* Parse the input string's two-char octets until the end + * of input is reached. The last octet may contain only + * one char */ + while (plen > 0) { + uint8_t byte; + size_t byte_len = sizeof(byte); + + /* Parse next two-character hex octet */ + error = bhnd_nvram_parse_int(p, bhnd_nv_ummin(plen, 2), + 16, &parsed_len, &byte, &byte_len, otype_base); + if (error) { + BHND_NV_DEBUG("error parsing '%.*s' as " + "integer: %d\n", BHND_NV_PRINT_WIDTH(plen), + p, error); + + return (error); + } + + /* Write to output */ + if (limit > nbytes) + *((uint8_t *)outp + nbytes) = byte; + nbytes++; + + /* Advance input */ + p += parsed_len; + plen -= parsed_len; + } + + /* Provide required length */ + *olen = nbytes; + if (limit < *olen && outp != NULL) + return (ENOMEM); + + return (0); + } + case BHND_NVRAM_TYPE_UINT8: case BHND_NVRAM_TYPE_UINT8_ARRAY: case BHND_NVRAM_TYPE_UINT16: @@ -896,8 +1174,30 @@ bhnd_nvram_val_encode_int(const void *inp, size_t ilen, bhnd_nvram_type itype, /* Write output */ switch (otype) { + case BHND_NVRAM_TYPE_NULL: + /* Cannot encode an integer value as NULL */ + return (EFTYPE); + + case BHND_NVRAM_TYPE_BOOL: { + bhnd_nvram_bool_t bval; + + if (intv.u64 == 0 || intv.u64 == 1) { + bval = intv.u64; + } else { + /* Encoding as a bool would lose information */ + return (ERANGE); + } + + nbytes = sizeof(bhnd_nvram_bool_t); + if (limit >= nbytes) + *((bhnd_nvram_bool_t *)outp) = bval; + + break; + } + case BHND_NVRAM_TYPE_CHAR: case BHND_NVRAM_TYPE_CHAR_ARRAY: + case BHND_NVRAM_TYPE_DATA: case BHND_NVRAM_TYPE_UINT8: case BHND_NVRAM_TYPE_UINT8_ARRAY: if (intv.u64 > UINT8_MAX) @@ -1335,11 +1635,23 @@ bhnd_nvram_val_generic_encode_elem(bhnd_nvram_val *value, const void *inp, itype = bhnd_nvram_val_elem_type(value); switch (itype) { + case BHND_NVRAM_TYPE_NULL: + return (bhnd_nvram_val_encode_null(inp, ilen, itype, outp, olen, + otype)); + + case BHND_NVRAM_TYPE_DATA: + return (bhnd_nvram_val_encode_data(inp, ilen, itype, outp, + olen, otype)); + case BHND_NVRAM_TYPE_STRING: case BHND_NVRAM_TYPE_CHAR: return (bhnd_nvram_val_encode_string(inp, ilen, itype, outp, olen, otype)); + case BHND_NVRAM_TYPE_BOOL: + return (bhnd_nvram_val_encode_bool(inp, ilen, itype, outp, olen, + otype)); + case BHND_NVRAM_TYPE_UINT8: case BHND_NVRAM_TYPE_UINT16: case BHND_NVRAM_TYPE_UINT32: @@ -1486,10 +1798,22 @@ bhnd_nvram_val_set_inline(bhnd_nvram_val *value, const void *inp, size_t ilen, /* Attempt to copy to inline storage */ switch (itype) { + case BHND_NVRAM_TYPE_NULL: + if (ilen != 0) + return (EFAULT); + + /* Nothing to copy */ + NV_STORE_INIT_INLINE(); + return (0); + case BHND_NVRAM_TYPE_CHAR: NV_STORE_INLINE(uint8_t, ch); return (0); + case BHND_NVRAM_TYPE_BOOL: + NV_STORE_INLINE(bhnd_nvram_bool_t, b); + return(0); + case BHND_NVRAM_TYPE_UINT8: case BHND_NVRAM_TYPE_INT8: NV_STORE_INLINE(uint8_t, u8); @@ -1514,6 +1838,7 @@ bhnd_nvram_val_set_inline(bhnd_nvram_val *value, const void *inp, size_t ilen, NV_COPY_ARRRAY_INLINE(uint8_t, ch); return (0); + case BHND_NVRAM_TYPE_DATA: case BHND_NVRAM_TYPE_UINT8_ARRAY: case BHND_NVRAM_TYPE_INT8_ARRAY: NV_COPY_ARRRAY_INLINE(uint8_t, u8); @@ -1534,6 +1859,10 @@ bhnd_nvram_val_set_inline(bhnd_nvram_val *value, const void *inp, size_t ilen, NV_COPY_ARRRAY_INLINE(uint64_t, u64); return (0); + case BHND_NVRAM_TYPE_BOOL_ARRAY: + NV_COPY_ARRRAY_INLINE(bhnd_nvram_bool_t, b); + return(0); + case BHND_NVRAM_TYPE_STRING: case BHND_NVRAM_TYPE_STRING_ARRAY: if (ilen > sizeof(value->data.ch)) |