xref: /aosp_15_r20/external/coreboot/src/vendorcode/siemens/hwilib/hwilib.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <cbfs.h>
4 #include <string.h>
5 #include <console/console.h>
6 #include <device/mmio.h>
7 #include <types.h>
8 
9 #include "hwilib.h"
10 
11 #define MAX_BLOCK_NUM		4
12 #define LEN_HIB			0x1fd
13 #define LEN_SIB			0x121
14 #define LEN_EIB			0x0b5
15 #define MIN_LEN_XIB		0x201
16 #define NEXT_OFFSET_HIB		0x1dc
17 #define NEXT_OFFSET_SIB		0x104
18 #define NEXT_OFFSET_EIB		0x0b0
19 #define NEXT_OFFSET_XIB		0x014
20 #define LEN_UNIQUEL_NUM		0x010
21 #define LEN_HW_REV		0x002
22 #define LEN_MAC_ADDRESS		0x006
23 #define LEN_SPD			0x080
24 #define LEN_EDID		0x080
25 #define LEN_OFFSET		0x00c
26 #define EIB_FEATRUE_OFFSET	0x00e
27 #define LEN_MAGIC_NUM		0x007
28 #define BLOCK_MAGIC		"H1W2M3I"
29 #define HWI_MAX_NAME_LEN	32
30 
31 /* Define all supported block types. */
32 enum {
33 	BLK_HIB,
34 	BLK_SIB,
35 	BLK_EIB,
36 	BLK_XIB
37 };
38 
39 /* This structure holds a valid position for a given field
40  * Every field can have multiple positions of which the first available
41  * will be taken by the library.
42  */
43 struct param_pos {
44 	uint8_t blk_type;	/* Valid for a specific block type */
45 	uint32_t offset;	/* Offset in given block */
46 	size_t len;		/* Length for the field in this block */
47 };
48 
49 /* This structure holds all the needed information for a given field type
50  * and a pointer to a function which is able to extract the desired data.
51  */
52 struct param_info {
53 	struct param_pos pos[MAX_BLOCK_NUM];
54 	uint64_t mask;
55 	uint8_t mask_offset;
56 	size_t (*get_field)(const struct param_info *param, uint8_t *dst, size_t dstsize);
57 };
58 
59 /* Storage for pointers to the different blocks. The contents will be filled
60  * in hwilib_find_blocks().
61  */
62 static uint8_t *all_blocks[MAX_BLOCK_NUM];
63 
64 /* As the length of extended block is variable, save all length to a global
65  * variable so that they can be used later to check boundaries.
66  */
67 static uint16_t all_blk_size[MAX_BLOCK_NUM];
68 
69 /* Storage for the cbfs file name of the currently open hwi file. */
70 static char current_hwi[HWI_MAX_NAME_LEN];
71 
72 static size_t hwilib_read_bytes(const struct param_info *param, uint8_t *dst, size_t dstsize);
73 
74 /* Add all supported fields to this variable. It is important to use the
75  * field type of a given field as the array index so that all the information
76  * is on the appropriate place inside the array. In this way one do not need
77  * to search for fields but can simply use an index into the array.
78  */
79 static const struct param_info params[] = {
80 	[HIB_VerID] = {
81 		.pos[0] = {.blk_type = BLK_HIB, .offset = 0x8, .len = 4},
82 		.get_field = hwilib_read_bytes },
83 	[SIB_VerID] = {
84 		.pos[0] = {.blk_type = BLK_SIB, .offset = 0x8, .len = 4},
85 		.get_field = hwilib_read_bytes },
86 	[EIB_VerID] = {
87 		.pos[0] = {.blk_type = BLK_EIB, .offset = 0x8, .len = 4},
88 		.get_field = hwilib_read_bytes },
89 	[XIB_VerID] = {
90 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x8, .len = 4},
91 		.get_field = hwilib_read_bytes },
92 	[HIB_HwRev] = {
93 		.pos[0] = {.blk_type = BLK_HIB, .offset = 0xbe, .len = 2},
94 		.get_field = hwilib_read_bytes },
95 	[SIB_HwRev] = {
96 		.pos[0] = {.blk_type = BLK_SIB, .offset = 0xc8, .len = 2},
97 		.get_field = hwilib_read_bytes },
98 	[HWID] = {
99 		.pos[0] = {.blk_type = BLK_HIB, .offset = 0x1a8, .len = 4},
100 		.pos[1] = {.blk_type = BLK_SIB, .offset = 0xd0, .len = 4},
101 		.get_field = hwilib_read_bytes },
102 	[UniqueNum] = {
103 		.pos[0] = {.blk_type = BLK_HIB, .offset = 0xa2, .len = 10},
104 		.pos[1] = {.blk_type = BLK_SIB, .offset = 0xa2, .len = 10},
105 		.get_field = hwilib_read_bytes },
106 	[Mac1] = {
107 		.pos[0] = {.blk_type = BLK_HIB, .offset = 0xc0, .len = 6},
108 		.get_field = hwilib_read_bytes },
109 	[Mac1Aux] = {
110 		.pos[0] = {.blk_type = BLK_HIB, .offset = 0xc6, .len = 1},
111 		.get_field = hwilib_read_bytes },
112 	[Mac2] = {
113 		.pos[0] = {.blk_type = BLK_HIB, .offset = 0xc8, .len = 6},
114 		.get_field = hwilib_read_bytes },
115 	[Mac2Aux] = {
116 		.pos[0] = {.blk_type = BLK_HIB, .offset = 0xce, .len = 1},
117 		.get_field = hwilib_read_bytes },
118 	[Mac3] = {
119 		.pos[0] = {.blk_type = BLK_HIB, .offset = 0xd0, .len = 6},
120 		.get_field = hwilib_read_bytes },
121 	[Mac3Aux] = {
122 		.pos[0] = {.blk_type = BLK_HIB, .offset = 0xd6, .len = 1},
123 		.get_field = hwilib_read_bytes },
124 	[Mac4] = {
125 		.pos[0] = {.blk_type = BLK_HIB, .offset = 0xd8, .len = 6},
126 		.get_field = hwilib_read_bytes },
127 	[Mac4Aux] = {
128 		.pos[0] = {.blk_type = BLK_HIB, .offset = 0xde, .len = 1},
129 		.get_field = hwilib_read_bytes },
130 	[SPD] = {
131 		.pos[0] = {.blk_type = BLK_HIB, .offset = 0xe0, .len = 0x80},
132 		.get_field = hwilib_read_bytes },
133 	[FF_FreezeDis] = {
134 		.pos[0] = {.blk_type = BLK_HIB, .offset = 0x1b8, .len = 1},
135 		.mask = 0x10,
136 		.mask_offset = 4,
137 		.get_field = hwilib_read_bytes },
138 	[FF_FanReq] = {
139 		.pos[0] = {.blk_type = BLK_HIB, .offset = 0x1b9, .len = 1},
140 		.mask = 0x04,
141 		.mask_offset = 2,
142 		.get_field = hwilib_read_bytes },
143 	[NvramVirtTimeDsaveReset] = {
144 		.pos[0] = {.blk_type = BLK_HIB, .offset = 0x1be, .len = 2},
145 		.get_field = hwilib_read_bytes },
146 	[BiosFlags] = {
147 		.pos[0] = {.blk_type = BLK_HIB, .offset = 0x1c0, .len = 4},
148 		.get_field = hwilib_read_bytes },
149 	[MacMapping1] = {
150 		.pos[0] = {.blk_type = BLK_HIB, .offset = 0x1cc, .len = 4},
151 		.get_field = hwilib_read_bytes },
152 	[MacMapping2] = {
153 		.pos[0] = {.blk_type = BLK_HIB, .offset = 0x1d0, .len = 4},
154 		.get_field = hwilib_read_bytes },
155 	[MacMapping3] = {
156 		.pos[0] = {.blk_type = BLK_HIB, .offset = 0x1d4, .len = 4},
157 		.get_field = hwilib_read_bytes },
158 	[MacMapping4] = {
159 		.pos[0] = {.blk_type = BLK_HIB, .offset = 0x1d8, .len = 4},
160 		.get_field = hwilib_read_bytes },
161 	[RTCType] = {
162 		.pos[0] = {.blk_type = BLK_HIB, .offset = 0x1e8, .len = 1},
163 		.get_field = hwilib_read_bytes },
164 	[BL_Brightness] = {
165 		.pos[0] = {.blk_type = BLK_SIB, .offset = 0xd8, .len = 1},
166 		.get_field = hwilib_read_bytes },
167 	[PF_PwmFreq] = {
168 		.pos[0] = {.blk_type = BLK_SIB, .offset = 0xe7, .len = 1},
169 		.get_field = hwilib_read_bytes },
170 	[PF_Color_Depth] = {
171 		.pos[0] = {.blk_type = BLK_SIB, .offset = 0xea, .len = 1},
172 		.mask = 0x03,
173 		.mask_offset = 0,
174 		.get_field = hwilib_read_bytes },
175 	[PF_DisplType] = {
176 		.pos[0] = {.blk_type = BLK_SIB, .offset = 0xe3, .len = 1},
177 		.get_field = hwilib_read_bytes },
178 	[PF_DisplCon] = {
179 		.pos[0] = {.blk_type = BLK_SIB, .offset = 0xf2, .len = 1},
180 		.get_field = hwilib_read_bytes },
181 	[Edid] = {
182 		.pos[0] = {.blk_type = BLK_EIB, .offset = 0x10, .len = 0x80},
183 		.get_field = hwilib_read_bytes },
184 	[VddRef] = {
185 		.pos[0] = {.blk_type = BLK_EIB, .offset = 0x90, .len = 2},
186 		.get_field = hwilib_read_bytes },
187 	[XMac1] = {
188 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0xfc, .len = 6},
189 		.get_field = hwilib_read_bytes },
190 	[XMac1Aux] = {
191 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x102, .len = 1},
192 		.get_field = hwilib_read_bytes },
193 	[XMac2] = {
194 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x114, .len = 6},
195 		.get_field = hwilib_read_bytes },
196 	[XMac2Aux] = {
197 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x11a, .len = 1},
198 		.get_field = hwilib_read_bytes },
199 	[XMac3] = {
200 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x12c, .len = 6},
201 		.get_field = hwilib_read_bytes },
202 	[XMac3Aux] = {
203 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x132, .len = 1},
204 		.get_field = hwilib_read_bytes },
205 	[XMac4] = {
206 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x144, .len = 6},
207 		.get_field = hwilib_read_bytes },
208 	[XMac4Aux] = {
209 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x14a, .len = 1},
210 		.get_field = hwilib_read_bytes },
211 	[XMac5] = {
212 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x15c, .len = 6},
213 		.get_field = hwilib_read_bytes },
214 	[XMac5Aux] = {
215 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x162, .len = 1},
216 		.get_field = hwilib_read_bytes },
217 	[XMac6] = {
218 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x174, .len = 6},
219 		.get_field = hwilib_read_bytes },
220 	[XMac6Aux] = {
221 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x17a, .len = 1},
222 		.get_field = hwilib_read_bytes },
223 	[XMac7] = {
224 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x18c, .len = 6},
225 		.get_field = hwilib_read_bytes },
226 	[XMac7Aux] = {
227 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x192, .len = 1},
228 		.get_field = hwilib_read_bytes },
229 	[XMac8] = {
230 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x1a4, .len = 6},
231 		.get_field = hwilib_read_bytes },
232 	[XMac8Aux] = {
233 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x1aa, .len = 1},
234 		.get_field = hwilib_read_bytes },
235 	[XMac9] = {
236 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x1bc, .len = 6},
237 		.get_field = hwilib_read_bytes },
238 	[XMac9Aux] = {
239 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x1c2, .len = 1},
240 		.get_field = hwilib_read_bytes },
241 	[XMac10] = {
242 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x1d4, .len = 6},
243 		.get_field = hwilib_read_bytes },
244 	[XMac10Aux] = {
245 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x1da, .len = 1},
246 		.get_field = hwilib_read_bytes },
247 	[XMac1Mapping] = {
248 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0xec, .len = 16},
249 		.get_field = hwilib_read_bytes },
250 	[XMac2Mapping] = {
251 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x104, .len = 16},
252 		.get_field = hwilib_read_bytes },
253 	[XMac3Mapping] = {
254 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x11c, .len = 16},
255 		.get_field = hwilib_read_bytes },
256 	[XMac4Mapping] = {
257 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x134, .len = 16},
258 		.get_field = hwilib_read_bytes },
259 	[XMac5Mapping] = {
260 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x14c, .len = 16},
261 		.get_field = hwilib_read_bytes },
262 	[XMac6Mapping] = {
263 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x164, .len = 16},
264 		.get_field = hwilib_read_bytes },
265 	[XMac7Mapping] = {
266 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x17c, .len = 16},
267 		.get_field = hwilib_read_bytes },
268 	[XMac8Mapping] = {
269 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x194, .len = 16},
270 		.get_field = hwilib_read_bytes },
271 	[XMac9Mapping] = {
272 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x1ac, .len = 16},
273 		.get_field = hwilib_read_bytes },
274 	[XMac10Mapping] = {
275 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x1c4, .len = 16},
276 		.get_field = hwilib_read_bytes },
277 	[netKind1] = {
278 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x103, .len = 1},
279 		.get_field = hwilib_read_bytes },
280 	[netKind2] = {
281 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x11b, .len = 1},
282 		.get_field = hwilib_read_bytes },
283 	[netKind3] = {
284 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x133, .len = 1},
285 		.get_field = hwilib_read_bytes },
286 	[netKind4] = {
287 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x14b, .len = 1},
288 		.get_field = hwilib_read_bytes },
289 	[netKind5] = {
290 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x163, .len = 1},
291 		.get_field = hwilib_read_bytes },
292 	[netKind6] = {
293 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x17b, .len = 1},
294 		.get_field = hwilib_read_bytes },
295 	[netKind7] = {
296 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x193, .len = 1},
297 		.get_field = hwilib_read_bytes },
298 	[netKind8] = {
299 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x1ab, .len = 1},
300 		.get_field = hwilib_read_bytes },
301 	[netKind9] = {
302 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x1c3, .len = 1},
303 		.get_field = hwilib_read_bytes },
304 	[netKind10] = {
305 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x1db, .len = 1},
306 		.get_field = hwilib_read_bytes },
307 	[T_Warn] = {
308 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x18, .len = 4},
309 		.get_field = hwilib_read_bytes },
310 	[T_Crit] = {
311 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x1c, .len = 4},
312 		.get_field = hwilib_read_bytes },
313 	[FANSamplingTime] = {
314 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x20, .len = 4},
315 		.get_field = hwilib_read_bytes },
316 	[FANSetPoint] = {
317 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x24, .len = 4},
318 		.get_field = hwilib_read_bytes },
319 	[FANKp] = {
320 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x28, .len = 4},
321 		.get_field = hwilib_read_bytes },
322 	[FANKi] = {
323 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x2c, .len = 4},
324 		.get_field = hwilib_read_bytes },
325 	[FANKd] = {
326 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x30, .len = 4},
327 		.get_field = hwilib_read_bytes },
328 	[FANHystVal] = {
329 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x34, .len = 4},
330 		.get_field = hwilib_read_bytes },
331 	[FANHystThreshold] = {
332 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x38, .len = 4},
333 		.get_field = hwilib_read_bytes },
334 	[FANHystCtrl] = {
335 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x3c, .len = 4},
336 		.get_field = hwilib_read_bytes },
337 	[FANMaxSpeed] = {
338 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x40, .len = 2},
339 		.get_field = hwilib_read_bytes },
340 	[FANStartSpeed] = {
341 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x42, .len = 2},
342 		.get_field = hwilib_read_bytes },
343 	[FANSensorDelay] = {
344 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x44, .len = 4},
345 		.get_field = hwilib_read_bytes },
346 	[FANSensorNum] = {
347 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x48, .len = 1},
348 		.get_field = hwilib_read_bytes },
349 	[FANSensorSelect] = {
350 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x49, .len = 1},
351 		.get_field = hwilib_read_bytes },
352 	[FANSensorCfg0] = {
353 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x4c, .len = 20},
354 		.get_field = hwilib_read_bytes },
355 	[FANSensorCfg1] = {
356 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x60, .len = 20},
357 		.get_field = hwilib_read_bytes },
358 	[FANSensorCfg2] = {
359 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x74, .len = 20},
360 		.get_field = hwilib_read_bytes },
361 	[FANSensorCfg3] = {
362 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x88, .len = 20},
363 		.get_field = hwilib_read_bytes },
364 	[FANSensorCfg4] = {
365 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x9c, .len = 20},
366 		.get_field = hwilib_read_bytes },
367 	[FANSensorCfg5] = {
368 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0xb0, .len = 20},
369 		.get_field = hwilib_read_bytes },
370 	[FANSensorCfg6] = {
371 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0xc4, .len = 20},
372 		.get_field = hwilib_read_bytes },
373 	[FANSensorCfg7] = {
374 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0xd8, .len = 20},
375 		.get_field = hwilib_read_bytes },
376 	[LegacyDelay] = {
377 		.pos[0] = {.blk_type = BLK_XIB, .offset = 0x20c, .len = 4},
378 		.get_field = hwilib_read_bytes },
379 };
380 
381 /** \brief This functions reads the given field from the first valid hwinfo
382  *         block
383  * @param  *param	Parameter to read from hwinfo
384  * @param  *dst		Pointer to memory where the data will be stored in
385  * @param  dstsize	Size of the memory passed in via the *dst pointer
386  * @return		Number of copied bytes on success, 0 on error
387  */
hwilib_read_bytes(const struct param_info * param,uint8_t * dst,size_t dstsize)388 static size_t hwilib_read_bytes(const struct param_info *param, uint8_t *dst, size_t dstsize)
389 {
390 	uint8_t i = 0, *blk = NULL;
391 
392 	if (!param || !dst)
393 		return 0;
394 	/* Take the first valid block to get the parameter from */
395 	do {
396 		if ((param->pos[i].len) && (param->pos[i].offset) &&
397 		     (all_blocks[param->pos[i].blk_type])) {
398 			blk =  all_blocks[param->pos[i].blk_type];
399 			break;
400 		}
401 		i++;
402 	} while (i < MAX_BLOCK_NUM);
403 
404 	/* Ensure there is a valid block available for this parameter and
405 	 * the length of the parameter does not exceed dstsize or block len.
406 	 */
407 	if ((!blk) || (param->pos[i].len > dstsize) ||
408 	    (param->pos[i].len + param->pos[i].offset >
409 	     all_blk_size[param->pos[i].blk_type]))
410 		return 0;
411 	/* We can now copy the wanted data. */
412 	memcpy(dst, (blk + param->pos[i].offset), param->pos[i].len);
413 	/* If there is a mask given, apply it only for parameters with a
414 	 * length of 1, 2, 4 or 8 bytes.
415 	 */
416 	if (param->mask) {
417 		switch (param->pos[i].len) {
418 		case 1:
419 			/* Apply a mask on a 8 bit value */
420 			*dst &= (param->mask & 0xff);
421 			*dst >>= (param->mask_offset);
422 			break;
423 		case 2:
424 			/* Apply mask on a 16 bit value */
425 			*((uint16_t *)(dst)) &= (param->mask & 0xffff);
426 			*((uint16_t *)(dst)) >>= (param->mask_offset);
427 			break;
428 		case 4:
429 			/* Apply mask on a 32 bit value */
430 			*((uint32_t *)(dst)) &= (param->mask & 0xffffffff);
431 			*((uint32_t *)(dst)) >>= (param->mask_offset);
432 			break;
433 		case 8:
434 			/* Apply mask on a 64 bit value */
435 			*((uint64_t *)(dst)) &= (param->mask);
436 			*((uint64_t *)(dst)) >>= (param->mask_offset);
437 			break;
438 		default:
439 			/* Warn if there is a mask for an invalid length. */
440 			printk(BIOS_WARNING,
441 			      "HWILIB: Invalid field length for given mask.\n");
442 			break;
443 		}
444 	}
445 	return param->pos[i].len;
446 }
447 
448 /** \brief This function finds all available block types in a given cbfs file.
449  * @param  *hwi_filename	Name of the cbfs-file to use.
450  * @return			CB_SUCCESS when no error, otherwise error code
451  */
hwilib_find_blocks(const char * hwi_filename)452 enum cb_err hwilib_find_blocks(const char *hwi_filename)
453 {
454 	uint8_t *ptr = NULL, *base = NULL;
455 	uint32_t next_offset = 1;
456 	size_t filesize = 0;
457 
458 	/* Check for a valid parameter */
459 	if (!hwi_filename)
460 		return CB_ERR_ARG;
461 	/* Check if this file is already open. If yes, just leave as there is
462 	   nothing left to do here. */
463 	if (!strncmp(current_hwi, hwi_filename, HWI_MAX_NAME_LEN)) {
464 		printk(BIOS_SPEW, "HWILIB: File \"%s\" already open.\n",
465 			hwi_filename);
466 		return CB_SUCCESS;
467 	}
468 
469 	ptr = cbfs_map(hwi_filename, &filesize);
470 	if (!ptr) {
471 		printk(BIOS_ERR,"HWILIB: Missing file \"%s\" in cbfs.\n",
472 			hwi_filename);
473 		return CB_ERR;
474 	}
475 	/* Ensure the block has the right magic */
476 	if (strncmp((char*)ptr, BLOCK_MAGIC, LEN_MAGIC_NUM)) {
477 		printk(BIOS_ERR, "HWILIB: Bad magic at start of block!\n");
478 		return CB_ERR;
479 	}
480 	/* Reset all static pointers to blocks as they might have been set
481 	 *  in prior calls to this function.
482 	 * This way the caller do not need to "close" already opened blocks.
483 	 */
484 	memset(all_blocks, 0, (MAX_BLOCK_NUM * sizeof (uint8_t *)));
485 	/* Check which blocks are available by examining the length field. */
486 	base = ptr;
487 	/* Fill in sizes of all fixed length blocks. */
488 	all_blk_size[BLK_HIB] = LEN_HIB;
489 	all_blk_size[BLK_SIB] = LEN_SIB;
490 	all_blk_size[BLK_EIB] = LEN_EIB;
491 	/* Length of BLK_XIB is variable and will be filled if block is found */
492 	all_blk_size[BLK_XIB] = 0;
493 	while(!(strncmp((char *)ptr, BLOCK_MAGIC, LEN_MAGIC_NUM)) &&
494 		next_offset) {
495 		uint16_t len = read16(ptr + LEN_OFFSET);
496 		/* Ensure file size boundaries for a given block. */
497 		if ((ptr - base + len) > filesize)
498 			break;
499 		if (len == LEN_HIB) {
500 			all_blocks[BLK_HIB] = ptr;
501 			next_offset = read32(ptr + NEXT_OFFSET_HIB);
502 			if (next_offset)
503 				ptr = base + next_offset;
504 		} else if (len == LEN_SIB) {
505 			all_blocks[BLK_SIB] = ptr;
506 			next_offset = read32(ptr + NEXT_OFFSET_SIB);
507 			if (next_offset)
508 				ptr = base + next_offset;
509 		} else if (len == LEN_EIB) {
510 			/* Skip preliminary blocks */
511 			if (!(read16(ptr + EIB_FEATRUE_OFFSET) & 0x01))
512 				all_blocks[BLK_EIB] = ptr;
513 			next_offset = read32(ptr + NEXT_OFFSET_EIB);
514 			if (next_offset)
515 				ptr = base + next_offset;
516 		} else if (len >= MIN_LEN_XIB) {
517 			all_blocks[BLK_XIB] = ptr;
518 			next_offset = read32(ptr + NEXT_OFFSET_XIB);
519 			all_blk_size[BLK_XIB] = len;
520 			if (next_offset)
521 				ptr = base + next_offset;
522 		} else {
523 			next_offset = 0;
524 		}
525 	}
526 	/* We should have found at least one valid block */
527 	if (all_blocks[BLK_HIB] || all_blocks[BLK_SIB] || all_blocks[BLK_EIB] ||
528 	    all_blocks[BLK_XIB]) {
529 		/* Save currently opened hwi filename. */
530 		strncpy(current_hwi, hwi_filename, HWI_MAX_NAME_LEN);
531 		return CB_SUCCESS;
532 	}
533 	else
534 		return CB_ERR;
535 }
536 
537 /** \brief This functions is used from caller to get a specific field from
538  *         hwinfo block.
539  * @param  field	Field type to read from hwinfo
540  * @param  *dst		Pointer to memory where the data will be stored in
541  * @param  dstsize	Size of the memory passed in via the *dst pointer
542  * @return		Number of copied bytes on success, 0 on error
543  */
hwilib_get_field(hwinfo_field_t field,uint8_t * dst,size_t dstsize)544 size_t hwilib_get_field(hwinfo_field_t field, uint8_t *dst, size_t dstsize)
545 {
546 	/* Check the boundaries of params-variable */
547 	if ((uint32_t)field < ARRAY_SIZE(params))
548 		return params[field].get_field(&params[field], dst, dstsize);
549 	else
550 		return 0;
551 }
552