drivers/vpd: Add VPD support
VPD reference: https://chromium.googlesource.com/chromiumos/platform/vpd/+/master/README.md Copy ChromeOS VPD driver to add support for VPD without CROMEOS. Possible use case: * Storing calibration data * Storing MAC address * Storing serial * Storing boot options + Now it's possible to define the VPD space by choosing one of the following enums: VPD_ANY, VPD_RW, VPD_RO. + CHROMEOS selects now VPD as part of it. + VPD is implemented as driver. Change-Id: Id9263bd39bf25d024e93daa57053fefcb1adc53a Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com> Reviewed-on: https://review.coreboot.org/25046 Reviewed-by: David Hendricks <david.hendricks@gmail.com> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
parent
c4b0fd0a86
commit
28cee59ca2
|
@ -0,0 +1,28 @@
|
|||
##
|
||||
## This file is part of the coreboot project.
|
||||
##
|
||||
## Copyright (C) 2012 The Chromium OS Authors. All rights reserved.
|
||||
##
|
||||
## This program is free software; you can redistribute it and/or modify
|
||||
## it under the terms of the GNU General Public License as published by
|
||||
## the Free Software Foundation; version 2 of the License.
|
||||
##
|
||||
## This program is distributed in the hope that it will be useful,
|
||||
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
## GNU General Public License for more details.
|
||||
##
|
||||
|
||||
config VPD
|
||||
bool "Support for Vital Product Data tables"
|
||||
default n
|
||||
help
|
||||
Enable support for flash based vital product data.
|
||||
|
||||
if VPD
|
||||
|
||||
config VPD_DEBUG
|
||||
bool "Enable VPD debug output"
|
||||
default n
|
||||
|
||||
endif
|
|
@ -0,0 +1,2 @@
|
|||
romstage-$(CONFIG_VPD) += lib_vpd.c
|
||||
ramstage-$(CONFIG_VPD) += vpd.c lib_vpd.c
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include "lib_vpd.h"
|
||||
|
||||
/* Given an encoded string, this functions decodes the length field which varies
|
||||
* from 1 byte to many bytes.
|
||||
*
|
||||
* The in points the actual byte going to be decoded. The *length returns
|
||||
* the decoded length field. The number of consumed bytes will be stroed in
|
||||
* decoded_len.
|
||||
*
|
||||
* Returns VPD_FAIL if more bit is 1, but actually reaches the end of string.
|
||||
*/
|
||||
int decodeLen(const int32_t max_len,
|
||||
const uint8_t *in,
|
||||
int32_t *length,
|
||||
int32_t *decoded_len)
|
||||
{
|
||||
uint8_t more;
|
||||
int i = 0;
|
||||
|
||||
assert(length);
|
||||
assert(decoded_len);
|
||||
|
||||
*length = 0;
|
||||
do {
|
||||
if (i >= max_len)
|
||||
return VPD_FAIL;
|
||||
|
||||
more = in[i] & 0x80;
|
||||
*length <<= 7;
|
||||
*length |= in[i] & 0x7f;
|
||||
++i;
|
||||
} while (more);
|
||||
|
||||
*decoded_len = i;
|
||||
|
||||
return VPD_OK;
|
||||
}
|
||||
|
||||
/* Given the encoded string, this function invokes callback with extracted
|
||||
* (key, value). The *consumed will be plused the number of bytes consumed in
|
||||
* this function.
|
||||
*
|
||||
* The input_buf points to the first byte of the input buffer.
|
||||
*
|
||||
* The *consumed starts from 0, which is actually the next byte to be decoded.
|
||||
* It can be non-zero to be used in multiple calls.
|
||||
*
|
||||
* If one entry is successfully decoded, sends it to callback and returns the
|
||||
* result.
|
||||
*/
|
||||
int decodeVpdString(const int32_t max_len,
|
||||
const uint8_t *input_buf,
|
||||
int32_t *consumed,
|
||||
VpdDecodeCallback callback,
|
||||
void *callback_arg)
|
||||
{
|
||||
int type;
|
||||
int32_t key_len, value_len;
|
||||
int32_t decoded_len;
|
||||
const uint8_t *key, *value;
|
||||
|
||||
/* type */
|
||||
if (*consumed >= max_len)
|
||||
return VPD_FAIL;
|
||||
|
||||
type = input_buf[*consumed];
|
||||
switch (type) {
|
||||
case VPD_TYPE_INFO:
|
||||
case VPD_TYPE_STRING:
|
||||
(*consumed)++;
|
||||
/* key */
|
||||
if (VPD_OK != decodeLen(max_len - *consumed,
|
||||
&input_buf[*consumed], &key_len,
|
||||
&decoded_len) ||
|
||||
*consumed + decoded_len >= max_len) {
|
||||
return VPD_FAIL;
|
||||
}
|
||||
|
||||
*consumed += decoded_len;
|
||||
key = &input_buf[*consumed];
|
||||
*consumed += key_len;
|
||||
|
||||
/* value */
|
||||
if (VPD_OK != decodeLen(max_len - *consumed,
|
||||
&input_buf[*consumed],
|
||||
&value_len, &decoded_len) ||
|
||||
*consumed + decoded_len > max_len) {
|
||||
return VPD_FAIL;
|
||||
}
|
||||
*consumed += decoded_len;
|
||||
value = &input_buf[*consumed];
|
||||
*consumed += value_len;
|
||||
|
||||
if (type == VPD_TYPE_STRING)
|
||||
return callback(key, key_len, value, value_len,
|
||||
callback_arg);
|
||||
|
||||
return VPD_OK;
|
||||
|
||||
default:
|
||||
return VPD_FAIL;
|
||||
break;
|
||||
}
|
||||
|
||||
return VPD_OK;
|
||||
}
|
|
@ -11,25 +11,25 @@
|
|||
#include <inttypes.h>
|
||||
|
||||
enum {
|
||||
VPD_OK = 0,
|
||||
VPD_FAIL,
|
||||
VPD_OK = 0,
|
||||
VPD_FAIL,
|
||||
};
|
||||
|
||||
enum {
|
||||
VPD_TYPE_TERMINATOR = 0,
|
||||
VPD_TYPE_STRING,
|
||||
VPD_TYPE_INFO = 0xfe,
|
||||
VPD_TYPE_IMPLICIT_TERMINATOR = 0xff,
|
||||
VPD_TYPE_TERMINATOR = 0,
|
||||
VPD_TYPE_STRING,
|
||||
VPD_TYPE_INFO = 0xfe,
|
||||
VPD_TYPE_IMPLICIT_TERMINATOR = 0xff,
|
||||
};
|
||||
|
||||
enum {
|
||||
VPD_AS_LONG_AS = -1,
|
||||
VPD_AS_LONG_AS = -1,
|
||||
};
|
||||
|
||||
enum { /* export_type */
|
||||
VPD_EXPORT_KEY_VALUE = 1,
|
||||
VPD_EXPORT_VALUE,
|
||||
VPD_EXPORT_AS_PARAMETER,
|
||||
VPD_EXPORT_KEY_VALUE = 1,
|
||||
VPD_EXPORT_VALUE,
|
||||
VPD_EXPORT_AS_PARAMETER,
|
||||
};
|
||||
|
||||
/* Callback for decodeVpdString to invoke. */
|
||||
|
@ -39,15 +39,15 @@ typedef int VpdDecodeCallback(const uint8_t *key, int32_t key_len,
|
|||
|
||||
/* Container data types */
|
||||
struct StringPair {
|
||||
uint8_t *key;
|
||||
uint8_t *value;
|
||||
int pad_len;
|
||||
int filter_out; /* TRUE means not exported. */
|
||||
struct StringPair *next;
|
||||
uint8_t *key;
|
||||
uint8_t *value;
|
||||
int pad_len;
|
||||
int filter_out; /* TRUE means not exported. */
|
||||
struct StringPair *next;
|
||||
};
|
||||
|
||||
struct PairContainer {
|
||||
struct StringPair *first;
|
||||
struct StringPair *first;
|
||||
};
|
||||
|
||||
|
|
@ -5,14 +5,13 @@
|
|||
*/
|
||||
|
||||
#include <console/console.h>
|
||||
|
||||
#include <cbmem.h>
|
||||
#include <fmap.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <timestamp.h>
|
||||
|
||||
#include "cros_vpd.h"
|
||||
#include "vpd.h"
|
||||
#include "lib_vpd.h"
|
||||
#include "vpd_tables.h"
|
||||
|
||||
|
@ -178,7 +177,7 @@ static int vpd_gets_callback(const uint8_t *key, int32_t key_len,
|
|||
return VPD_FAIL;
|
||||
}
|
||||
|
||||
const void *cros_vpd_find(const char *key, int *size)
|
||||
const void *vpd_find(const char *key, int *size, enum vpd_region region)
|
||||
{
|
||||
struct vpd_gets_arg arg = {0};
|
||||
int consumed = 0;
|
||||
|
@ -191,10 +190,18 @@ const void *cros_vpd_find(const char *key, int *size)
|
|||
arg.key = (const uint8_t *)key;
|
||||
arg.key_len = strlen(key);
|
||||
|
||||
while (VPD_OK == decodeVpdString(vpd->ro_size, vpd->blob, &consumed,
|
||||
vpd_gets_callback, &arg)) {
|
||||
if (region == VPD_ANY || region == VPD_RO)
|
||||
while (VPD_OK == decodeVpdString(vpd->ro_size, vpd->blob,
|
||||
&consumed, vpd_gets_callback, &arg)) {
|
||||
/* Iterate until found or no more entries. */
|
||||
}
|
||||
}
|
||||
|
||||
if (!arg.matched && region != VPD_RO)
|
||||
while (VPD_OK == decodeVpdString(vpd->rw_size,
|
||||
vpd->blob + vpd->ro_size, &consumed,
|
||||
vpd_gets_callback, &arg)) {
|
||||
/* Iterate until found or no more entries. */
|
||||
}
|
||||
|
||||
if (!arg.matched)
|
||||
return NULL;
|
||||
|
@ -203,12 +210,12 @@ const void *cros_vpd_find(const char *key, int *size)
|
|||
return arg.value;
|
||||
}
|
||||
|
||||
char *cros_vpd_gets(const char *key, char *buffer, int size)
|
||||
char *vpd_gets(const char *key, char *buffer, int size, enum vpd_region region)
|
||||
{
|
||||
const void *string_address;
|
||||
int string_size;
|
||||
|
||||
string_address = cros_vpd_find(key, &string_size);
|
||||
string_address = vpd_find(key, &string_size, region);
|
||||
|
||||
if (!string_address)
|
||||
return NULL;
|
|
@ -4,12 +4,14 @@
|
|||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef __CROS_VPD_H__
|
||||
#define __CROS_VPD_H__
|
||||
|
||||
#define CROS_VPD_REGION_NAME "region"
|
||||
#define CROS_VPD_WIFI_SAR_NAME "wifi_sar"
|
||||
#ifndef __VPD_H__
|
||||
#define __VPD_H__
|
||||
|
||||
enum vpd_region {
|
||||
VPD_ANY = 0,
|
||||
VPD_RO = 1,
|
||||
VPD_RW = 2
|
||||
};
|
||||
/*
|
||||
* Reads VPD string value by key.
|
||||
*
|
||||
|
@ -19,7 +21,7 @@
|
|||
*
|
||||
* Returns NULL if key is not found, otherwise buffer.
|
||||
*/
|
||||
char *cros_vpd_gets(const char *key, char *buffer, int size);
|
||||
char *vpd_gets(const char *key, char *buffer, int size, enum vpd_region region);
|
||||
|
||||
/*
|
||||
* Find VPD value by key.
|
||||
|
@ -35,6 +37,6 @@ char *cros_vpd_gets(const char *key, char *buffer, int size);
|
|||
* Returns NULL if key is not found.
|
||||
*/
|
||||
|
||||
const void *cros_vpd_find(const char *key, int *size);
|
||||
const void *vpd_find(const char *key, int *size, enum vpd_region region);
|
||||
|
||||
#endif /* __CROS_VPD_H__ */
|
||||
#endif /* __VPD_H__ */
|
|
@ -16,7 +16,7 @@
|
|||
#include <string.h>
|
||||
#include <baseboard/variants.h>
|
||||
#include <ec/google/chromeec/ec.h>
|
||||
#include <vendorcode/google/chromeos/cros_vpd.h>
|
||||
#include <drivers/vpd/vpd.h>
|
||||
#include <soc/cpu.h>
|
||||
#include <soc/intel/apollolake/chip.h>
|
||||
|
||||
|
@ -59,7 +59,7 @@ uint8_t variant_board_sku(void)
|
|||
if (!IS_ENABLED(CONFIG_CHROMEOS))
|
||||
return board_sku_num;
|
||||
|
||||
if (!cros_vpd_gets(vpd_skuid, vpd_buffer, ARRAY_SIZE(vpd_buffer)))
|
||||
if (!vpd_gets(vpd_skuid, vpd_buffer, ARRAY_SIZE(vpd_buffer), VPD_ANY))
|
||||
return board_sku_num;
|
||||
|
||||
vpd_len = strlen(vpd_buffer);
|
||||
|
|
|
@ -24,6 +24,7 @@ config CHROMEOS
|
|||
select ELOG if BOOT_DEVICE_SUPPORTS_WRITES
|
||||
select COLLECT_TIMESTAMPS
|
||||
select VBOOT
|
||||
select VPD
|
||||
help
|
||||
Enable ChromeOS specific features like the GPIO sub table in
|
||||
the coreboot table. NOTE: Enabling this option on an unsupported
|
||||
|
|
|
@ -17,8 +17,7 @@ ramstage-$(CONFIG_ELOG) += elog.c
|
|||
ramstage-$(CONFIG_HAVE_ACPI_TABLES) += gnvs.c
|
||||
ramstage-$(CONFIG_HAVE_ACPI_TABLES) += acpi.c
|
||||
ramstage-$(CONFIG_CHROMEOS_RAMOOPS) += ramoops.c
|
||||
romstage-y += vpd_decode.c
|
||||
ramstage-y += vpd_decode.c cros_vpd.c vpd_mac.c vpd_serialno.c vpd_calibration.c
|
||||
ramstage-y += vpd_mac.c vpd_serialno.c vpd_calibration.c
|
||||
ramstage-$(CONFIG_CHROMEOS_DISABLE_PLATFORM_HIERARCHY_ON_RESUME) += tpm2.c
|
||||
ramstage-$(CONFIG_HAVE_REGULATORY_DOMAIN) += wrdd.c
|
||||
ramstage-$(CONFIG_USE_SAR) += sar.c
|
||||
|
|
|
@ -19,9 +19,10 @@
|
|||
#include <types.h>
|
||||
#include <string.h>
|
||||
#include <sar.h>
|
||||
#include "cros_vpd.h"
|
||||
#include <drivers/vpd/vpd.h>
|
||||
|
||||
#define WIFI_SAR_CBFS_FILENAME "wifi_sar_defaults.hex"
|
||||
#define CROS_VPD_WIFI_SAR_NAME "wifi_sar"
|
||||
|
||||
static int load_sar_file_from_cbfs(void *buf, size_t buffer_size)
|
||||
{
|
||||
|
@ -55,7 +56,7 @@ For [WGDS_VERSION] 0x00,
|
|||
int get_wifi_sar_limits(struct wifi_sar_limits *sar_limits)
|
||||
{
|
||||
const char *wifi_sar_limit_key = CROS_VPD_WIFI_SAR_NAME;
|
||||
/* cros_vpd_gets() reads in one less than size characters from the VPD
|
||||
/* vpd_gets() reads in one less than size characters from the VPD
|
||||
* with a terminating null byte ('\0') stored as the last character into
|
||||
* the buffer, thus the increasing by 1 for buffer_size. */
|
||||
const size_t buffer_size = (sizeof(struct wifi_sar_limits) /
|
||||
|
@ -79,8 +80,8 @@ int get_wifi_sar_limits(struct wifi_sar_limits *sar_limits)
|
|||
}
|
||||
|
||||
/* Try to read the SAR limit entry from VPD */
|
||||
if (!cros_vpd_gets(wifi_sar_limit_key, wifi_sar_limit_str,
|
||||
buffer_size)) {
|
||||
if (!vpd_gets(wifi_sar_limit_key, wifi_sar_limit_str,
|
||||
buffer_size, VPD_ANY)) {
|
||||
printk(BIOS_ERR, "Error: Could not locate '%s' in VPD.\n",
|
||||
wifi_sar_limit_key);
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#include <string.h>
|
||||
|
||||
#include <vendorcode/google/chromeos/chromeos.h>
|
||||
#include <vendorcode/google/chromeos/cros_vpd.h>
|
||||
#include <drivers/vpd/vpd.h>
|
||||
|
||||
/*
|
||||
* This file provides functions looking in the VPD for WiFi calibration data,
|
||||
|
@ -112,7 +112,7 @@ static size_t fill_up_entries_cache(struct vpd_blob_cache_t *cache,
|
|||
strcpy(cache->key_name, templates[i]);
|
||||
cache->key_name[index_location] = j + '0';
|
||||
|
||||
payload = cros_vpd_find(cache->key_name, &payload_size);
|
||||
payload = vpd_find(cache->key_name, &payload_size, VPD_ANY);
|
||||
if (!payload)
|
||||
continue;
|
||||
|
||||
|
|
|
@ -1,89 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include "lib_vpd.h"
|
||||
|
||||
int decodeLen(
|
||||
const int32_t max_len,
|
||||
const uint8_t *in,
|
||||
int32_t *length,
|
||||
int32_t *decoded_len) {
|
||||
uint8_t more;
|
||||
int i = 0;
|
||||
|
||||
assert(length);
|
||||
assert(decoded_len);
|
||||
|
||||
*length = 0;
|
||||
do {
|
||||
if (i >= max_len) return VPD_FAIL;
|
||||
more = in[i] & 0x80;
|
||||
*length <<= 7;
|
||||
*length |= in[i] & 0x7f;
|
||||
++i;
|
||||
} while (more);
|
||||
|
||||
*decoded_len = i;
|
||||
|
||||
return VPD_OK;
|
||||
}
|
||||
|
||||
/* Sequentially decodes type, key, and value.
|
||||
*/
|
||||
int decodeVpdString(
|
||||
const int32_t max_len,
|
||||
const uint8_t *input_buf,
|
||||
int32_t *consumed,
|
||||
VpdDecodeCallback callback,
|
||||
void *callback_arg) {
|
||||
int type;
|
||||
int32_t key_len, value_len;
|
||||
int32_t decoded_len;
|
||||
const uint8_t *key, *value;
|
||||
|
||||
/* type */
|
||||
if (*consumed >= max_len)
|
||||
return VPD_FAIL;
|
||||
|
||||
type = input_buf[*consumed];
|
||||
switch (type) {
|
||||
case VPD_TYPE_INFO:
|
||||
case VPD_TYPE_STRING:
|
||||
(*consumed)++;
|
||||
|
||||
/* key */
|
||||
if (VPD_OK != decodeLen(max_len - *consumed, &input_buf[*consumed],
|
||||
&key_len, &decoded_len) ||
|
||||
*consumed + decoded_len >= max_len) {
|
||||
return VPD_FAIL;
|
||||
}
|
||||
|
||||
*consumed += decoded_len;
|
||||
key = &input_buf[*consumed];
|
||||
*consumed += key_len;
|
||||
|
||||
/* value */
|
||||
if (VPD_OK != decodeLen(max_len - *consumed, &input_buf[*consumed],
|
||||
&value_len, &decoded_len) ||
|
||||
*consumed + decoded_len > max_len) {
|
||||
return VPD_FAIL;
|
||||
}
|
||||
*consumed += decoded_len;
|
||||
value = &input_buf[*consumed];
|
||||
*consumed += value_len;
|
||||
|
||||
if (type == VPD_TYPE_STRING)
|
||||
return callback(key, key_len, value, value_len, callback_arg);
|
||||
|
||||
return VPD_OK;
|
||||
|
||||
default:
|
||||
return VPD_FAIL;
|
||||
break;
|
||||
}
|
||||
return VPD_OK;
|
||||
}
|
|
@ -17,7 +17,7 @@
|
|||
#include <console/console.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <vendorcode/google/chromeos/cros_vpd.h>
|
||||
#include <drivers/vpd/vpd.h>
|
||||
|
||||
/*
|
||||
* Decode string representation of the MAC address (a string of 12 hex
|
||||
|
@ -84,8 +84,8 @@ void lb_table_add_macs_from_vpd(struct lb_header *header)
|
|||
* If there are no more MAC addresses of this template
|
||||
* in the VPD - move on.
|
||||
*/
|
||||
if (!cros_vpd_gets(mac_addr_key, mac_addr_str,
|
||||
sizeof(mac_addr_str)))
|
||||
if (!vpd_gets(mac_addr_key, mac_addr_str,
|
||||
sizeof(mac_addr_str), VPD_ANY))
|
||||
break;
|
||||
|
||||
if (!macs) {
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <vendorcode/google/chromeos/cros_vpd.h>
|
||||
#include <drivers/vpd/vpd.h>
|
||||
|
||||
void lb_table_add_serialno_from_vpd(struct lb_header *header)
|
||||
{
|
||||
|
@ -27,8 +27,8 @@ void lb_table_add_serialno_from_vpd(struct lb_header *header)
|
|||
char serialno[32];
|
||||
size_t len;
|
||||
|
||||
if (!cros_vpd_gets(serialno_key, serialno,
|
||||
sizeof(serialno))) {
|
||||
if (!vpd_gets(serialno_key, serialno,
|
||||
sizeof(serialno), VPD_ANY)) {
|
||||
printk(BIOS_ERR, "no serial number in vpd\n");
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -18,7 +18,9 @@
|
|||
#include <types.h>
|
||||
#include <string.h>
|
||||
#include <wrdd.h>
|
||||
#include "cros_vpd.h"
|
||||
#include <drivers/vpd/vpd.h>
|
||||
|
||||
#define CROS_VPD_REGION_NAME "region"
|
||||
|
||||
/*
|
||||
* wrdd_domain_value is ISO 3166-2
|
||||
|
@ -59,8 +61,8 @@ uint16_t wifi_regulatory_domain(void)
|
|||
char *separator;
|
||||
|
||||
/* If not found for any reason fall backto the default value */
|
||||
if (!cros_vpd_gets(wrdd_domain_key, wrdd_domain_code,
|
||||
ARRAY_SIZE(wrdd_domain_code))) {
|
||||
if (!vpd_gets(wrdd_domain_key, wrdd_domain_code,
|
||||
ARRAY_SIZE(wrdd_domain_code), VPD_ANY)) {
|
||||
printk(BIOS_DEBUG,
|
||||
"Error: Could not locate '%s' in VPD\n", wrdd_domain_key);
|
||||
return WRDD_DEFAULT_REGULATORY_DOMAIN;
|
||||
|
|
Loading…
Reference in New Issue