Coreboot populates a memory copy of the vital product data (VPD) during
boot. Read this data structure and print out the contents in the
cbsysinfo command.

Example: (redacted some things)

 Chrome OS VPD: 00000000ffffd000
 RO size     : 24e
 RW size     : 122
  "region" = "us"
  "bluetooth_mac0" = "8C:FD:F0:40:15:28"
  "wifi_mac0" = "8C:FD:F0:40:15:22"
  "in_accel_x_lid_calibbias" = "38"
  "in_accel_y_lid_calibbias" = "11"
  ...

Signed-off-by: Stephen Boyd <swb...@chromium.org>
---
 cmd/cbsysinfo.c           | 34 +++++++++++++++++++++++++++++++++
 include/cb_sysinfo.h      |  4 ++++
 include/coreboot_tables.h | 13 +++++++++++++
 lib/coreboot/cb_sysinfo.c | 40 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 91 insertions(+)

diff --git a/cmd/cbsysinfo.c b/cmd/cbsysinfo.c
index d6ab71a3db8d..74a66f8c1b9c 100644
--- a/cmd/cbsysinfo.c
+++ b/cmd/cbsysinfo.c
@@ -436,6 +436,40 @@ static void show_table(struct sysinfo_t *info, bool 
verbose)
        print_hex("MTC size", info->mtc_size);
 
        print_ptr("Chrome OS VPD", info->chromeos_vpd);
+       if (info->chromeos_vpd) {
+               struct vpd_cbmem *vpd = info->chromeos_vpd;
+
+               print_hex("RO size", vpd->ro_size);
+               print_hex("RW size", vpd->rw_size);
+
+               unsigned int i = 0;
+               unsigned int len = vpd->ro_size;
+               const u8 *blob = vpd->blob;
+
+               while (i < len) {
+                       unsigned int vpd_type = blob[i];
+
+                       switch (vpd_type) {
+                       case VPD_TYPE_INFO:
+                       case VPD_TYPE_STRING:
+                               i++;
+                               unsigned int key_offset;
+                               unsigned int key_len;
+                               unsigned int val_offset;
+                               unsigned int val_len;
+
+                               i = vpd_cbmem_parse_key_value(blob, i, 
&key_offset, &key_len, &val_offset, &val_len);
+                               if (vpd_type == VPD_TYPE_STRING)
+                                       printf("  \"%.*s\" = \"%.*s\"\n", 
key_len, blob + key_offset, val_len, blob + val_offset);
+
+                               break;
+                       default:
+                               i++;
+                               break;
+                       }
+               }
+       }
+
        print_ptr("RSDP", info->rsdp);
        printf("%-12s: ", "Unimpl.");
        if (info->unimpl_count) {
diff --git a/include/cb_sysinfo.h b/include/cb_sysinfo.h
index b2128bb20a19..f6c4f3a5edea 100644
--- a/include/cb_sysinfo.h
+++ b/include/cb_sysinfo.h
@@ -264,6 +264,10 @@ int coreboot_early_init(void);
  */
 const struct sysinfo_t *cb_get_sysinfo(void);
 
+unsigned int vpd_cbmem_parse_key_value(const u8 *blob, unsigned int offset,
+               unsigned int *key_offset, unsigned int *key_len,
+               unsigned int *val_offset, unsigned int *val_len);
+
 /**
  * fdt_fixup_coreboot() - Add the /firmware/coreboot node to the FDT
  *
diff --git a/include/coreboot_tables.h b/include/coreboot_tables.h
index 6e7686e360c5..7d54ff94cf93 100644
--- a/include/coreboot_tables.h
+++ b/include/coreboot_tables.h
@@ -551,6 +551,19 @@ struct cbmem_entry {
 #define CBMEM_ID_CONSOLE               0x434f4e53
 #define CBMEM_ID_NONE                  0x00000000
 
+struct vpd_cbmem {
+       u32 magic;
+       u32 version;
+       u32 ro_size;
+       u32 rw_size;
+       u8 blob[];
+};
+
+#define VPD_TYPE_TERMINATOR            0x00
+#define VPD_TYPE_STRING                        0x01
+#define VPD_TYPE_INFO                  0xfe
+#define VPD_TYPE_IMPLICIT_TERMINATOR   0xff
+
 /**
  * high_table_reserve() - reserve configuration table in high memory
  *
diff --git a/lib/coreboot/cb_sysinfo.c b/lib/coreboot/cb_sysinfo.c
index ec9a47242e34..d2e5e6d9bb6e 100644
--- a/lib/coreboot/cb_sysinfo.c
+++ b/lib/coreboot/cb_sysinfo.c
@@ -634,3 +634,43 @@ clean_coreboot:
        fdt_del_node_and_alias(blob, node);
 }
 #endif
+
+/*
+ * Parse the length header that is 7 bits of length and a top bit indicating
+ * "more" to the length.
+ *
+ * |  7   | 6   5   4  3  2  1   0 |
+ * |------+------------------------|
+ * | more |        length          |
+ *
+ * The "more" bit indicates the next byte after this one has more lower
+ * significant 7 bits. This can be repeated multiple times to make long keys or
+ * values.
+ */
+static unsigned int vpd_cbmem_parse_len(const u8 *blob, unsigned int i,
+                                       unsigned int *start, unsigned int *_len)
+{
+       u8 more;
+       unsigned int len = 0;
+
+       do {
+               more = blob[i] & 0x80;
+               len <<= 7;
+               len |= blob[i] & 0x7f;
+               i++;
+       } while (more);
+
+       *_len = len;
+       *start = i;
+
+       return i + len;
+}
+
+unsigned int vpd_cbmem_parse_key_value(const u8 *blob, unsigned int offset,
+               unsigned int *key_offset, unsigned int *key_len,
+               unsigned int *val_offset, unsigned int *val_len)
+{
+       offset = vpd_cbmem_parse_len(blob, offset, key_offset, key_len);
+
+       return vpd_cbmem_parse_len(blob, offset, val_offset, val_len);
+}
-- 
Sent by a computer, using git, on the internet

Reply via email to