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.
8 #include <console/console.h>
13 #include <timestamp.h>
16 #include "vpd_decode.h"
17 #include "vpd_tables.h"
22 int32_t key_len
, value_len
;
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
;
38 if (fmap_locate_area_as_rdev(fmap_name
, &vpd
)) {
39 printk(BIOS_ERR
, "%s: No %s FMAP section.\n", __func__
,
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",
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",
61 if (memcmp(info
.header
.magic
, VPD_INFO_MAGIC
, sizeof(info
.header
.magic
))
62 == 0 && size
>= info
.size
+ sizeof(info
)) {
63 *base
+= sizeof(info
);
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",
71 size
-= GOOGLE_VPD_2_0_OFFSET
;
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)
88 vpd_blob
.ro_base
= NULL
;
90 vpd_blob
.rw_base
= NULL
;
93 struct region_device vpd
;
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",
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
;
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",
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)
132 static int vpd_gets_callback(const uint8_t *key
, uint32_t key_len
,
133 const uint8_t *value
, uint32_t value_len
,
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
;
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)
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. */
180 *size
= arg
.value_len
;
184 char *vpd_gets(const char *key
, char *buffer
, int size
, enum vpd_region region
)
186 const void *string_address
;
189 string_address
= vpd_find(key
, &string_size
, region
);
195 int copy_size
= MIN(size
- 1, string_size
);
196 memcpy(buffer
, string_address
, copy_size
);
197 buffer
[copy_size
] = '\0';
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
)
212 value
= vpd_find(key
, &size
, region
);
214 printk(BIOS_CRIT
, "problem returning from vpd_find.\n");
221 /* Make sure the value is either '1' or '0' */
225 } else if (*value
== '0') {