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:
Patrick Rudolph 2018-03-08 15:43:12 +01:00 committed by Philipp Deppenwiese
parent c4b0fd0a86
commit 28cee59ca2
16 changed files with 206 additions and 140 deletions

28
src/drivers/vpd/Kconfig Normal file
View File

@ -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

View File

@ -0,0 +1,2 @@
romstage-$(CONFIG_VPD) += lib_vpd.c
ramstage-$(CONFIG_VPD) += vpd.c lib_vpd.c

113
src/drivers/vpd/lib_vpd.c Normal file
View File

@ -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;
}

View File

@ -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,7 +190,15 @@ 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,
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. */
}
@ -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;

View File

@ -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__ */

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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;
}

View File

@ -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) {

View File

@ -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;
}

View File

@ -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;