src/: Remove g_ prefixes and _g suffixes from variables
[coreboot.git] / src / drivers / vpd / vpd.c
blobab77a01bff198f294de80b7752bd4943c64b812f
1 /*
2 * Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
7 #include <assert.h>
8 #include <console/console.h>
9 #include <cbmem.h>
10 #include <fmap.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <timestamp.h>
15 #include "vpd.h"
16 #include "vpd_decode.h"
17 #include "vpd_tables.h"
19 struct vpd_gets_arg {
20 const uint8_t *key;
21 const uint8_t *value;
22 int32_t key_len, value_len;
23 int matched;
26 struct vpd_blob vpd_blob;
29 * returns the size of data in a VPD 2.0 formatted fmap region, or 0.
30 * Also sets *base as the region's base address.
32 static int32_t get_vpd_size(const char *fmap_name, int32_t *base)
34 struct google_vpd_info info;
35 struct region_device vpd;
36 int32_t size;
38 if (fmap_locate_area_as_rdev(fmap_name, &vpd)) {
39 printk(BIOS_ERR, "%s: No %s FMAP section.\n", __func__,
40 fmap_name);
41 return 0;
44 size = region_device_sz(&vpd);
46 if ((size < GOOGLE_VPD_2_0_OFFSET + sizeof(info)) ||
47 rdev_chain(&vpd, &vpd, GOOGLE_VPD_2_0_OFFSET,
48 size - GOOGLE_VPD_2_0_OFFSET)) {
49 printk(BIOS_ERR, "%s: Too small (%d) for Google VPD 2.0.\n",
50 __func__, size);
51 return 0;
54 /* Try if we can find a google_vpd_info, otherwise read whole VPD. */
55 if (rdev_readat(&vpd, &info, *base, sizeof(info)) != sizeof(info)) {
56 printk(BIOS_ERR, "ERROR: Failed to read %s header.\n",
57 fmap_name);
58 return 0;
61 if (memcmp(info.header.magic, VPD_INFO_MAGIC, sizeof(info.header.magic))
62 == 0 && size >= info.size + sizeof(info)) {
63 *base += sizeof(info);
64 size = info.size;
65 } else if (info.header.tlv.type == VPD_TYPE_TERMINATOR ||
66 info.header.tlv.type == VPD_TYPE_IMPLICIT_TERMINATOR) {
67 printk(BIOS_WARNING, "WARNING: %s is uninitialized or empty.\n",
68 fmap_name);
69 size = 0;
70 } else {
71 size -= GOOGLE_VPD_2_0_OFFSET;
74 return size;
77 static void vpd_get_blob(void)
79 int32_t ro_vpd_base = 0;
80 int32_t rw_vpd_base = 0;
81 int32_t ro_vpd_size = get_vpd_size("RO_VPD", &ro_vpd_base);
82 int32_t rw_vpd_size = get_vpd_size("RW_VPD", &rw_vpd_base);
84 /* Return if no VPD at all */
85 if (ro_vpd_size == 0 && rw_vpd_size == 0)
86 return;
88 vpd_blob.ro_base = NULL;
89 vpd_blob.ro_size = 0;
90 vpd_blob.rw_base = NULL;
91 vpd_blob.rw_size = 0;
93 struct region_device vpd;
95 if (ro_vpd_size) {
96 if (fmap_locate_area_as_rdev("RO_VPD", &vpd)) {
97 /* shouldn't happen, but let's be extra defensive */
98 printk(BIOS_ERR, "%s: No RO_VPD FMAP section.\n",
99 __func__);
100 return;
102 rdev_chain(&vpd, &vpd, GOOGLE_VPD_2_0_OFFSET,
103 region_device_sz(&vpd) - GOOGLE_VPD_2_0_OFFSET);
104 vpd_blob.ro_base = (uint8_t *)(rdev_mmap_full(&vpd) +
105 sizeof(struct google_vpd_info));
106 vpd_blob.ro_size = ro_vpd_size;
108 if (rw_vpd_size) {
109 if (fmap_locate_area_as_rdev("RW_VPD", &vpd)) {
110 /* shouldn't happen, but let's be extra defensive */
111 printk(BIOS_ERR, "%s: No RW_VPD FMAP section.\n",
112 __func__);
113 return;
115 rdev_chain(&vpd, &vpd, GOOGLE_VPD_2_0_OFFSET,
116 region_device_sz(&vpd) - GOOGLE_VPD_2_0_OFFSET);
117 vpd_blob.rw_base = (uint8_t *)(rdev_mmap_full(&vpd) +
118 sizeof(struct google_vpd_info));
119 vpd_blob.rw_size = rw_vpd_size;
121 vpd_blob.initialized = true;
124 const struct vpd_blob *vpd_load_blob(void)
126 if (vpd_blob.initialized == false)
127 vpd_get_blob();
129 return &vpd_blob;
132 static int vpd_gets_callback(const uint8_t *key, uint32_t key_len,
133 const uint8_t *value, uint32_t value_len,
134 void *arg)
136 struct vpd_gets_arg *result = (struct vpd_gets_arg *)arg;
137 if (key_len != result->key_len ||
138 memcmp(key, result->key, key_len) != 0)
139 /* Returns VPD_DECODE_OK to continue parsing. */
140 return VPD_DECODE_OK;
142 result->matched = 1;
143 result->value = value;
144 result->value_len = value_len;
145 /* Returns VPD_DECODE_FAIL to stop parsing. */
146 return VPD_DECODE_FAIL;
149 const void *vpd_find(const char *key, int *size, enum vpd_region region)
151 struct vpd_blob blob = {0};
153 vpd_get_buffers(&blob);
154 if (blob.ro_size == 0 && blob.rw_size == 0)
155 return NULL;
157 struct vpd_gets_arg arg = {0};
158 uint32_t consumed = 0;
160 arg.key = (const uint8_t *)key;
161 arg.key_len = strlen(key);
163 if ((region == VPD_ANY || region == VPD_RO) && blob.ro_size != 0) {
164 while (vpd_decode_string(blob.ro_size, blob.ro_base,
165 &consumed, vpd_gets_callback, &arg) == VPD_DECODE_OK) {
166 /* Iterate until found or no more entries. */
170 if ((!arg.matched && region != VPD_RO) && blob.rw_size != 0) {
171 while (vpd_decode_string(blob.rw_size, blob.rw_base,
172 &consumed, vpd_gets_callback, &arg) == VPD_DECODE_OK) {
173 /* Iterate until found or no more entries. */
177 if (!arg.matched)
178 return NULL;
180 *size = arg.value_len;
181 return arg.value;
184 char *vpd_gets(const char *key, char *buffer, int size, enum vpd_region region)
186 const void *string_address;
187 int string_size;
189 string_address = vpd_find(key, &string_size, region);
191 if (!string_address)
192 return NULL;
194 assert(size > 0);
195 int copy_size = MIN(size - 1, string_size);
196 memcpy(buffer, string_address, copy_size);
197 buffer[copy_size] = '\0';
198 return buffer;
202 * Find value of boolean type vpd key.
204 * During the process, necessary checking is done, such as making
205 * sure the value length is 1, and value is either '1' or '0'.
207 bool vpd_get_bool(const char *key, enum vpd_region region, uint8_t *val)
209 int size;
210 const char *value;
212 value = vpd_find(key, &size, region);
213 if (!value) {
214 printk(BIOS_CRIT, "problem returning from vpd_find.\n");
215 return false;
218 if (size != 1)
219 return false;
221 /* Make sure the value is either '1' or '0' */
222 if (*value == '1') {
223 *val = 1;
224 return true;
225 } else if (*value == '0') {
226 *val = 0;
227 return true;
228 } else
229 return false;