From bcd3832c06e8ed357c50f19396da21a218dc4b39 Mon Sep 17 00:00:00 2001 From: Hung-Te Lin Date: Fri, 21 Feb 2014 22:29:51 +0800 Subject: [PATCH] vendorcode: Access to ChromeOS VPD on default CBFS media. The new function "cros_vpd_gets(key, buf, size)" provides an easy and quick way to retrieve values in ChromeOS VPD section. BRANCH=none BUG=none TEST=Manually added CONFIG_FLASHMAP_OFFSET=0x00100000 in Nayn config, added a cros_vpd_gets("test", buf, sizeof(buf)) in romstage.c, emerge-nyan chromeos-coreboot-nyan # builds successfully, and then get correct VPD values in console output. Also tried x86 ("emerge-lumpy chromeos-coreboot-lumpy") Change-Id: I38e50615e515707ffaecdc4c4fae65043541b687 Signed-off-by: Hung-Te Lin Reviewed-on: https://chromium-review.googlesource.com/187430 Reviewed-by: Yung-chieh Lo --- src/vendorcode/google/chromeos/Makefile.inc | 4 +- src/vendorcode/google/chromeos/cros_vpd.c | 140 ++++++++++++++++++++ src/vendorcode/google/chromeos/cros_vpd.h | 21 +++ 3 files changed, 163 insertions(+), 2 deletions(-) create mode 100644 src/vendorcode/google/chromeos/cros_vpd.c create mode 100644 src/vendorcode/google/chromeos/cros_vpd.h diff --git a/src/vendorcode/google/chromeos/Makefile.inc b/src/vendorcode/google/chromeos/Makefile.inc index c288f6733b..7ae5d4e823 100644 --- a/src/vendorcode/google/chromeos/Makefile.inc +++ b/src/vendorcode/google/chromeos/Makefile.inc @@ -29,8 +29,8 @@ romstage-y += fmap.c ramstage-y += fmap.c ramstage-$(CONFIG_CHROMEOS_RAMOOPS) += ramoops.c smm-y += fmap.c -romstage-y += vpd_decode.c -ramstage-y += vpd_decode.c +romstage-y += vpd_decode.c cros_vpd.c +ramstage-y += vpd_decode.c cros_vpd.c ifneq ($(wildcard src/mainboard/$(MAINBOARDDIR)/chromeos.c),) ramstage-srcs += src/mainboard/$(MAINBOARDDIR)/chromeos.c romstage-srcs += src/mainboard/$(MAINBOARDDIR)/chromeos.c diff --git a/src/vendorcode/google/chromeos/cros_vpd.c b/src/vendorcode/google/chromeos/cros_vpd.c new file mode 100644 index 0000000000..26b01ee7a3 --- /dev/null +++ b/src/vendorcode/google/chromeos/cros_vpd.c @@ -0,0 +1,140 @@ +/* + * 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 + +#include +#include +#include + +#include "cros_vpd.h" +#include "fmap.h" +#include "lib_vpd.h" +#include "vpd_tables.h" + +/* + * Static variables are available in ramstage (all platforms), and romstage for + * some platforms (ex, ARM, which uses SRAM). + */ +#if defined(__PRE_RAM__) && CONFIG_ARCH_X86 +#define STATIC_VAR +#else +#define STATIC_VAR static +#endif + +/* Currently we only support Google VPD 2.0, which has a fixed offset. */ +enum { + GOOGLE_VPD_2_0_OFFSET = 0x600, +}; + +struct vpd_gets_arg { + const uint8_t *key; + const uint8_t *value; + int32_t key_len, value_len; + int matched; +}; + +static int cros_vpd_load(uint8_t **vpd_address, int32_t *vpd_size) +{ + STATIC_VAR int cached = 0; + STATIC_VAR uint8_t *cached_address = NULL; + STATIC_VAR int32_t cached_size = 0; + STATIC_VAR int result = -1; + struct google_vpd_info info; + int32_t base; + + const struct fmap_area *area; + struct cbfs_media media; + + if (cached) { + *vpd_address = cached_address; + *vpd_size = cached_size; + return result; + } + + cached = 1; + area = find_fmap_area(fmap_find(), "RO_VPD"); + if (!area) { + printk(BIOS_ERR, "%s: No RO_VPD FMAP section.\n", __func__); + return result; + } + if (area->size <= GOOGLE_VPD_2_0_OFFSET + sizeof(info)) { + printk(BIOS_ERR, "%s: Too small (%d) for Google VPD 2.0.\n", + __func__, area->size); + return result; + } + + base = area->offset + GOOGLE_VPD_2_0_OFFSET; + cached_size = area->size - GOOGLE_VPD_2_0_OFFSET; + init_default_cbfs_media(&media); + media.open(&media); + + /* Try if we can find a google_vpd_info, otherwise read whole VPD. */ + if (media.read(&media, &info, base, sizeof(info)) == sizeof(info) && + memcmp(info.header.magic, VPD_INFO_MAGIC, sizeof(info.header.magic)) + == 0 && cached_size >= info.size + sizeof(info)) { + base += sizeof(info); + cached_size = info.size; + } + + cached_address = media.map(&media, base, cached_size); + media.close(&media); + if (cached_address) { + *vpd_address = cached_address; + *vpd_size = cached_size; + printk(BIOS_DEBUG, "%s: Got VPD: %#x+%#x\n", __func__, base, + cached_size); + result = 0; + } + return result; +} + +static int vpd_gets_callback(const uint8_t *key, int32_t key_len, + const uint8_t *value, int32_t value_len, + void *arg) +{ + struct vpd_gets_arg *result = (struct vpd_gets_arg *)arg; + if (key_len != result->key_len || + memcmp(key, result->key, key_len) != 0) + /* Returns VPD_OK to continue parsing. */ + return VPD_OK; + + result->matched = 1; + result->value = value; + result->value_len = value_len; + /* Returns VPD_FAIL to stop parsing. */ + return VPD_FAIL; +} + +char *cros_vpd_gets(const char *key, char *buffer, int size) +{ + uint8_t *vpd_address = NULL; + int32_t vpd_size = 0; + struct vpd_gets_arg arg = {0}; + int consumed = 0; + + if (cros_vpd_load(&vpd_address, &vpd_size) != 0) { + return NULL; + } + + arg.key = (const uint8_t *)key; + arg.key_len = strlen(key); + + while (VPD_OK == decodeVpdString(vpd_size, vpd_address, &consumed, + vpd_gets_callback, &arg)) { + /* Iterate until found or no more entries. */ + } + + if (!arg.matched) + return NULL; + + if (size < arg.value_len + 1) + size = arg.value_len + 1; + memcpy(buffer, arg.value, size - 1); + buffer[size - 1] = '\0'; + return buffer; +} + diff --git a/src/vendorcode/google/chromeos/cros_vpd.h b/src/vendorcode/google/chromeos/cros_vpd.h new file mode 100644 index 0000000000..674dbf65d9 --- /dev/null +++ b/src/vendorcode/google/chromeos/cros_vpd.h @@ -0,0 +1,21 @@ +/* + * 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. + */ + +#ifndef __CROS_VPD_H__ +#define __CROS_VPD_H__ + +/* + * Reads VPD string value by key. + * + * Reads in at most one less than size characters from VPD and stores them + * into buffer. A terminating null byte ('\0') is stored after the last + * character in the buffer. + * + * Returns NULL if key is not found, otherwise buffer. + */ +char *cros_vpd_gets(const char *key, char *buffer, int size); + +#endif /* __CROS_VPD_H__ */