blob: 4bfd36b2411e0c06bdc2aa5c64599ff9f984cb03 [file] [log] [blame]
Angel Pons3ef916f2020-04-02 23:49:13 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Werner Zeh223498f2016-04-22 14:14:45 +02002
3#include <cbfs.h>
4#include <string.h>
5#include <console/console.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +02006#include <device/mmio.h>
Elyes HAOUAS5fd93e02019-05-15 21:07:30 +02007#include <types.h>
Werner Zeh223498f2016-04-22 14:14:45 +02008
Elyes HAOUAS5fd93e02019-05-15 21:07:30 +02009#include "hwilib.h"
Werner Zeh223498f2016-04-22 14:14:45 +020010
Werner Zeh66c20c42016-06-28 14:31:30 +020011#define MAX_BLOCK_NUM 4
Werner Zeh223498f2016-04-22 14:14:45 +020012#define LEN_HIB 0x1fd
13#define LEN_SIB 0x121
14#define LEN_EIB 0x0b5
Werner Zeh66c20c42016-06-28 14:31:30 +020015#define MIN_LEN_XIB 0x201
Werner Zeh223498f2016-04-22 14:14:45 +020016#define NEXT_OFFSET_HIB 0x1dc
17#define NEXT_OFFSET_SIB 0x104
18#define NEXT_OFFSET_EIB 0x0b0
Werner Zeh66c20c42016-06-28 14:31:30 +020019#define NEXT_OFFSET_XIB 0x014
Werner Zeh223498f2016-04-22 14:14:45 +020020#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"
Werner Zehd35a4812019-02-20 06:38:04 +010029#define HWI_MAX_NAME_LEN 32
Werner Zeh223498f2016-04-22 14:14:45 +020030
31/* Define all supported block types. */
32enum {
33 BLK_HIB,
34 BLK_SIB,
35 BLK_EIB,
Werner Zeh66c20c42016-06-28 14:31:30 +020036 BLK_XIB
Werner Zeh223498f2016-04-22 14:14:45 +020037};
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 */
43struct param_pos {
44 uint8_t blk_type; /* Valid for a specific block type */
45 uint32_t offset; /* Offset in given block */
46 uint32_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 */
52struct param_info {
53 struct param_pos pos[MAX_BLOCK_NUM];
54 uint64_t mask;
55 uint8_t mask_offset;
56 uint32_t (*get_field)(const struct param_info *param, uint8_t *dst,
57 uint32_t maxlen);
58};
59
60/* Storage for pointers to the different blocks. The contents will be filled
61 * in hwilib_find_blocks().
62 */
Arthur Heymansb6c9a5d2019-11-20 19:35:59 +010063static uint8_t *all_blocks[MAX_BLOCK_NUM];
Werner Zeh223498f2016-04-22 14:14:45 +020064
Werner Zeh66c20c42016-06-28 14:31:30 +020065/* As the length of extended block is variable, save all length to a global
66 * variable so that they can be used later to check boundaries.
67 */
Arthur Heymansb6c9a5d2019-11-20 19:35:59 +010068static uint16_t all_blk_size[MAX_BLOCK_NUM];
Werner Zeh66c20c42016-06-28 14:31:30 +020069
Werner Zehd35a4812019-02-20 06:38:04 +010070/* Storage for the cbfs file name of the currently open hwi file. */
Arthur Heymansb6c9a5d2019-11-20 19:35:59 +010071static char current_hwi[HWI_MAX_NAME_LEN];
Werner Zehd35a4812019-02-20 06:38:04 +010072
Werner Zeh66c20c42016-06-28 14:31:30 +020073
Werner Zeh223498f2016-04-22 14:14:45 +020074static uint32_t hwilib_read_bytes (const struct param_info *param, uint8_t *dst,
75 uint32_t maxlen);
76
77/* Add all supported fields to this variable. It is important to use the
78 * field type of a given field as the array index so that all the information
79 * is on the appropriate place inside the array. In this way one do not need
80 * to search for fields but can simply use an index into the array.
81 */
82static const struct param_info params[] = {
83 [HIB_VerID] = {
84 .pos[0] = {.blk_type = BLK_HIB, .offset = 0x8, .len = 4},
85 .get_field = hwilib_read_bytes },
86 [SIB_VerID] = {
87 .pos[0] = {.blk_type = BLK_SIB, .offset = 0x8, .len = 4},
88 .get_field = hwilib_read_bytes },
89 [EIB_VerID] = {
90 .pos[0] = {.blk_type = BLK_EIB, .offset = 0x8, .len = 4},
91 .get_field = hwilib_read_bytes },
Werner Zeh66c20c42016-06-28 14:31:30 +020092 [XIB_VerID] = {
93 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x8, .len = 4},
94 .get_field = hwilib_read_bytes },
Werner Zeh223498f2016-04-22 14:14:45 +020095 [HIB_HwRev] = {
96 .pos[0] = {.blk_type = BLK_HIB, .offset = 0xbe, .len = 2},
97 .get_field = hwilib_read_bytes },
98 [SIB_HwRev] = {
99 .pos[0] = {.blk_type = BLK_SIB, .offset = 0xc8, .len = 2},
100 .get_field = hwilib_read_bytes },
Werner Zehba7525d2016-11-23 07:31:35 +0100101 [HWID] = {
102 .pos[0] = {.blk_type = BLK_HIB, .offset = 0x1a8, .len = 4},
103 .pos[1] = {.blk_type = BLK_SIB, .offset = 0xd0, .len = 4},
104 .get_field = hwilib_read_bytes },
Werner Zeh223498f2016-04-22 14:14:45 +0200105 [UniqueNum] = {
106 .pos[0] = {.blk_type = BLK_HIB, .offset = 0xa2, .len = 10},
107 .pos[1] = {.blk_type = BLK_SIB, .offset = 0xa2, .len = 10},
108 .get_field = hwilib_read_bytes },
109 [Mac1] = {
110 .pos[0] = {.blk_type = BLK_HIB, .offset = 0xc0, .len = 6},
111 .get_field = hwilib_read_bytes },
112 [Mac1Aux] = {
113 .pos[0] = {.blk_type = BLK_HIB, .offset = 0xc6, .len = 1},
114 .get_field = hwilib_read_bytes },
115 [Mac2] = {
116 .pos[0] = {.blk_type = BLK_HIB, .offset = 0xc8, .len = 6},
117 .get_field = hwilib_read_bytes },
118 [Mac2Aux] = {
119 .pos[0] = {.blk_type = BLK_HIB, .offset = 0xce, .len = 1},
120 .get_field = hwilib_read_bytes },
121 [Mac3] = {
122 .pos[0] = {.blk_type = BLK_HIB, .offset = 0xd0, .len = 6},
123 .get_field = hwilib_read_bytes },
124 [Mac3Aux] = {
125 .pos[0] = {.blk_type = BLK_HIB, .offset = 0xd6, .len = 1},
126 .get_field = hwilib_read_bytes },
127 [Mac4] = {
128 .pos[0] = {.blk_type = BLK_HIB, .offset = 0xd8, .len = 6},
129 .get_field = hwilib_read_bytes },
130 [Mac4Aux] = {
131 .pos[0] = {.blk_type = BLK_HIB, .offset = 0xde, .len = 1},
132 .get_field = hwilib_read_bytes },
133 [SPD] = {
134 .pos[0] = {.blk_type = BLK_HIB, .offset = 0xe0, .len = 0x80},
135 .get_field = hwilib_read_bytes },
136 [FF_FreezeDis] = {
Werner Zeh5e21cd42017-06-30 10:05:06 +0200137 .pos[0] = {.blk_type = BLK_HIB, .offset = 0x1b8, .len = 1},
Werner Zeh223498f2016-04-22 14:14:45 +0200138 .mask = 0x10,
139 .mask_offset = 4,
140 .get_field = hwilib_read_bytes },
141 [FF_FanReq] = {
Werner Zeh5e21cd42017-06-30 10:05:06 +0200142 .pos[0] = {.blk_type = BLK_HIB, .offset = 0x1b9, .len = 1},
143 .mask = 0x04,
144 .mask_offset = 2,
Werner Zeh223498f2016-04-22 14:14:45 +0200145 .get_field = hwilib_read_bytes },
Mario Scheithauer59dd4662017-06-12 09:46:09 +0200146 [NvramVirtTimeDsaveReset] = {
147 .pos[0] = {.blk_type = BLK_HIB, .offset = 0x1be, .len = 2},
148 .get_field = hwilib_read_bytes },
Werner Zeh223498f2016-04-22 14:14:45 +0200149 [BiosFlags] = {
150 .pos[0] = {.blk_type = BLK_HIB, .offset = 0x1c0, .len = 4},
151 .get_field = hwilib_read_bytes },
152 [MacMapping1] = {
153 .pos[0] = {.blk_type = BLK_HIB, .offset = 0x1cc, .len = 4},
154 .get_field = hwilib_read_bytes },
155 [MacMapping2] = {
156 .pos[0] = {.blk_type = BLK_HIB, .offset = 0x1d0, .len = 4},
157 .get_field = hwilib_read_bytes },
158 [MacMapping3] = {
159 .pos[0] = {.blk_type = BLK_HIB, .offset = 0x1d4, .len = 4},
160 .get_field = hwilib_read_bytes },
161 [MacMapping4] = {
162 .pos[0] = {.blk_type = BLK_HIB, .offset = 0x1d8, .len = 4},
163 .get_field = hwilib_read_bytes },
Werner Zeh66c20c42016-06-28 14:31:30 +0200164 [RTCType] = {
165 .pos[0] = {.blk_type = BLK_HIB, .offset = 0x1e8, .len = 1},
166 .get_field = hwilib_read_bytes },
Mario Scheithauer59dd4662017-06-12 09:46:09 +0200167 [BL_Brightness] = {
168 .pos[0] = {.blk_type = BLK_SIB, .offset = 0xd8, .len = 1},
169 .get_field = hwilib_read_bytes },
170 [PF_PwmFreq] = {
171 .pos[0] = {.blk_type = BLK_SIB, .offset = 0xe7, .len = 1},
172 .get_field = hwilib_read_bytes },
Werner Zeh223498f2016-04-22 14:14:45 +0200173 [PF_Color_Depth] = {
174 .pos[0] = {.blk_type = BLK_SIB, .offset = 0xea, .len = 1},
175 .mask = 0x03,
176 .mask_offset = 0,
177 .get_field = hwilib_read_bytes },
178 [PF_DisplType] = {
179 .pos[0] = {.blk_type = BLK_SIB, .offset = 0xe3, .len = 1},
180 .get_field = hwilib_read_bytes },
181 [PF_DisplCon] = {
182 .pos[0] = {.blk_type = BLK_SIB, .offset = 0xf2, .len = 1},
183 .get_field = hwilib_read_bytes },
184 [Edid] = {
185 .pos[0] = {.blk_type = BLK_EIB, .offset = 0x10, .len = 0x80},
186 .get_field = hwilib_read_bytes },
187 [VddRef] = {
188 .pos[0] = {.blk_type = BLK_EIB, .offset = 0x90, .len = 2},
189 .get_field = hwilib_read_bytes },
Werner Zeh66c20c42016-06-28 14:31:30 +0200190 [XMac1] = {
191 .pos[0] = {.blk_type = BLK_XIB, .offset = 0xfc, .len = 6},
192 .get_field = hwilib_read_bytes },
193 [XMac1Aux] = {
194 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x102, .len = 1},
195 .get_field = hwilib_read_bytes },
196 [XMac2] = {
197 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x114, .len = 6},
198 .get_field = hwilib_read_bytes },
199 [XMac2Aux] = {
200 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x11a, .len = 1},
201 .get_field = hwilib_read_bytes },
202 [XMac3] = {
203 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x12c, .len = 6},
204 .get_field = hwilib_read_bytes },
205 [XMac3Aux] = {
206 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x132, .len = 1},
207 .get_field = hwilib_read_bytes },
208 [XMac4] = {
209 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x144, .len = 6},
210 .get_field = hwilib_read_bytes },
211 [XMac4Aux] = {
212 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x14a, .len = 1},
213 .get_field = hwilib_read_bytes },
214 [XMac5] = {
215 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x15c, .len = 6},
216 .get_field = hwilib_read_bytes },
217 [XMac5Aux] = {
218 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x162, .len = 1},
219 .get_field = hwilib_read_bytes },
220 [XMac6] = {
221 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x174, .len = 6},
222 .get_field = hwilib_read_bytes },
223 [XMac6Aux] = {
224 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x17a, .len = 1},
225 .get_field = hwilib_read_bytes },
226 [XMac7] = {
227 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x18c, .len = 6},
228 .get_field = hwilib_read_bytes },
229 [XMac7Aux] = {
230 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x192, .len = 1},
231 .get_field = hwilib_read_bytes },
232 [XMac8] = {
233 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x1a4, .len = 6},
234 .get_field = hwilib_read_bytes },
235 [XMac8Aux] = {
236 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x1aa, .len = 1},
237 .get_field = hwilib_read_bytes },
238 [XMac9] = {
239 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x1bc, .len = 6},
240 .get_field = hwilib_read_bytes },
241 [XMac9Aux] = {
242 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x1c2, .len = 1},
243 .get_field = hwilib_read_bytes },
244 [XMac10] = {
245 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x1d4, .len = 6},
246 .get_field = hwilib_read_bytes },
247 [XMac10Aux] = {
248 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x1da, .len = 1},
249 .get_field = hwilib_read_bytes },
250 [XMac1Mapping] = {
251 .pos[0] = {.blk_type = BLK_XIB, .offset = 0xec, .len = 16},
252 .get_field = hwilib_read_bytes },
253 [XMac2Mapping] = {
254 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x104, .len = 16},
255 .get_field = hwilib_read_bytes },
256 [XMac3Mapping] = {
257 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x11c, .len = 16},
258 .get_field = hwilib_read_bytes },
259 [XMac4Mapping] = {
260 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x134, .len = 16},
261 .get_field = hwilib_read_bytes },
262 [XMac5Mapping] = {
263 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x14c, .len = 16},
264 .get_field = hwilib_read_bytes },
265 [XMac6Mapping] = {
266 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x164, .len = 16},
267 .get_field = hwilib_read_bytes },
268 [XMac7Mapping] = {
269 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x17c, .len = 16},
270 .get_field = hwilib_read_bytes },
271 [XMac8Mapping] = {
272 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x194, .len = 16},
273 .get_field = hwilib_read_bytes },
274 [XMac9Mapping] = {
275 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x1ac, .len = 16},
276 .get_field = hwilib_read_bytes },
277 [XMac10Mapping] = {
278 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x1c4, .len = 16},
279 .get_field = hwilib_read_bytes },
280 [netKind1] = {
281 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x103, .len = 1},
282 .get_field = hwilib_read_bytes },
283 [netKind2] = {
284 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x11b, .len = 1},
285 .get_field = hwilib_read_bytes },
286 [netKind3] = {
287 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x133, .len = 1},
288 .get_field = hwilib_read_bytes },
289 [netKind4] = {
290 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x14b, .len = 1},
291 .get_field = hwilib_read_bytes },
292 [netKind5] = {
293 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x163, .len = 1},
294 .get_field = hwilib_read_bytes },
295 [netKind6] = {
296 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x17b, .len = 1},
297 .get_field = hwilib_read_bytes },
298 [netKind7] = {
299 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x193, .len = 1},
300 .get_field = hwilib_read_bytes },
301 [netKind8] = {
302 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x1ab, .len = 1},
303 .get_field = hwilib_read_bytes },
304 [netKind9] = {
305 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x1c3, .len = 1},
306 .get_field = hwilib_read_bytes },
307 [netKind10] = {
308 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x1db, .len = 1},
309 .get_field = hwilib_read_bytes },
310 [T_Warn] = {
311 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x18, .len = 4},
312 .get_field = hwilib_read_bytes },
313 [T_Crit] = {
314 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x1c, .len = 4},
315 .get_field = hwilib_read_bytes },
316 [FANSamplingTime] = {
317 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x20, .len = 4},
318 .get_field = hwilib_read_bytes },
319 [FANSetPoint] = {
320 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x24, .len = 4},
321 .get_field = hwilib_read_bytes },
322 [FANKp] = {
323 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x28, .len = 4},
324 .get_field = hwilib_read_bytes },
325 [FANKi] = {
326 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x2c, .len = 4},
327 .get_field = hwilib_read_bytes },
328 [FANKd] = {
329 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x30, .len = 4},
330 .get_field = hwilib_read_bytes },
331 [FANHystVal] = {
332 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x34, .len = 4},
333 .get_field = hwilib_read_bytes },
334 [FANHystThreshold] = {
335 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x38, .len = 4},
336 .get_field = hwilib_read_bytes },
337 [FANHystCtrl] = {
338 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x3c, .len = 4},
339 .get_field = hwilib_read_bytes },
340 [FANMaxSpeed] = {
341 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x40, .len = 2},
342 .get_field = hwilib_read_bytes },
Werner Zeh909536a2017-07-27 13:43:24 +0200343 [FANStartSpeed] = {
Werner Zeh66c20c42016-06-28 14:31:30 +0200344 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x42, .len = 2},
345 .get_field = hwilib_read_bytes },
346 [FANSensorDelay] = {
347 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x44, .len = 4},
348 .get_field = hwilib_read_bytes },
349 [FANSensorNum] = {
350 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x48, .len = 1},
351 .get_field = hwilib_read_bytes },
352 [FANSensorSelect] = {
353 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x49, .len = 1},
354 .get_field = hwilib_read_bytes },
355 [FANSensorCfg0] = {
356 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x4c, .len = 20},
357 .get_field = hwilib_read_bytes },
358 [FANSensorCfg1] = {
359 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x60, .len = 20},
360 .get_field = hwilib_read_bytes },
361 [FANSensorCfg2] = {
362 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x74, .len = 20},
363 .get_field = hwilib_read_bytes },
364 [FANSensorCfg3] = {
365 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x88, .len = 20},
366 .get_field = hwilib_read_bytes },
367 [FANSensorCfg4] = {
368 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x9c, .len = 20},
369 .get_field = hwilib_read_bytes },
370 [FANSensorCfg5] = {
371 .pos[0] = {.blk_type = BLK_XIB, .offset = 0xb0, .len = 20},
372 .get_field = hwilib_read_bytes },
373 [FANSensorCfg6] = {
374 .pos[0] = {.blk_type = BLK_XIB, .offset = 0xc4, .len = 20},
375 .get_field = hwilib_read_bytes },
376 [FANSensorCfg7] = {
377 .pos[0] = {.blk_type = BLK_XIB, .offset = 0xd8, .len = 20},
378 .get_field = hwilib_read_bytes },
Werner Zeh461797e2017-09-12 07:58:14 +0200379 [LegacyDelay] = {
380 .pos[0] = {.blk_type = BLK_XIB, .offset = 0x20c, .len = 4},
381 .get_field = hwilib_read_bytes },
Werner Zeh223498f2016-04-22 14:14:45 +0200382};
383
384/** \brief This functions reads the given field from the first valid hwinfo
385 * block
386 * @param *param Parameter to read from hwinfo
387 * @param *dst Pointer to memory where the data will be stored in
388 * @return number of copied bytes on success, 0 on error
389 */
390static uint32_t hwilib_read_bytes (const struct param_info *param, uint8_t *dst,
391 uint32_t maxlen)
392{
393 uint8_t i = 0, *blk = NULL;
Werner Zeh223498f2016-04-22 14:14:45 +0200394
395 if (!param || !dst)
396 return 0;
397 /* Take the first valid block to get the parameter from */
398 do {
Werner Zeh8f916232016-12-01 10:53:14 +0100399 if ((param->pos[i].len) && (param->pos[i].offset) &&
Arthur Heymansb6c9a5d2019-11-20 19:35:59 +0100400 (all_blocks[param->pos[i].blk_type])) {
401 blk = all_blocks[param->pos[i].blk_type];
Werner Zeh223498f2016-04-22 14:14:45 +0200402 break;
403 }
404 i++;
405 } while (i < MAX_BLOCK_NUM);
406
407 /* Ensure there is a valid block available for this parameter and
408 * the length of the parameter do not exceed maxlen or block len.
409 */
410 if ((!blk) || (param->pos[i].len > maxlen) ||
411 (param->pos[i].len + param->pos[i].offset >
Arthur Heymansb6c9a5d2019-11-20 19:35:59 +0100412 all_blk_size[param->pos[i].blk_type]))
Werner Zeh223498f2016-04-22 14:14:45 +0200413 return 0;
414 /* We can now copy the wanted data. */
415 memcpy(dst, (blk + param->pos[i].offset), param->pos[i].len);
416 /* If there is a mask given, apply it only for parameters with a
417 * length of 1, 2, 4 or 8 bytes.
418 */
419 if (param->mask) {
420 switch (param->pos[i].len) {
421 case 1:
422 /* Apply a mask on a 8 bit value */
423 *dst &= (param->mask & 0xff);
424 *dst >>= (param->mask_offset);
425 break;
426 case 2:
427 /* Apply mask on a 16 bit value */
428 *((uint16_t *)(dst)) &= (param->mask & 0xffff);
429 *((uint16_t *)(dst)) >>= (param->mask_offset);
430 break;
431 case 4:
432 /* Apply mask on a 32 bit value */
433 *((uint32_t *)(dst)) &= (param->mask & 0xffffffff);
434 *((uint32_t *)(dst)) >>= (param->mask_offset);
435 break;
436 case 8:
437 /* Apply mask on a 64 bit value */
438 *((uint64_t *)(dst)) &= (param->mask);
439 *((uint64_t *)(dst)) >>= (param->mask_offset);
440 break;
441 default:
442 /* Warn if there is a mask for an invalid length. */
443 printk(BIOS_WARNING,
444 "HWILIB: Invalid field length for given mask.\n");
445 break;
446 }
447 }
448 return param->pos[i].len;
449}
450
451/** \brief This function finds all available block types in a given cbfs file.
452 * @param *hwi_filename Name of the cbfs-file to use.
453 * @return CB_SUCCESS when no error, otherwise error code
454 */
455enum cb_err hwilib_find_blocks (const char *hwi_filename)
456{
457 uint8_t *ptr = NULL, *base = NULL;
458 uint32_t next_offset = 1;
Werner Zeh223498f2016-04-22 14:14:45 +0200459 size_t filesize = 0;
460
461 /* Check for a valid parameter */
462 if (!hwi_filename)
463 return CB_ERR_ARG;
Werner Zehd35a4812019-02-20 06:38:04 +0100464 /* Check if this file is already open. If yes, just leave as there is
465 nothing left to do here. */
Arthur Heymans5b0db352019-11-21 08:00:27 +0100466 if (!strncmp(current_hwi, hwi_filename, HWI_MAX_NAME_LEN)) {
Werner Zehd35a4812019-02-20 06:38:04 +0100467 printk(BIOS_SPEW, "HWILIB: File \"%s\" already open.\n",
468 hwi_filename);
469 return CB_SUCCESS;
470 }
471
Julius Werner834b3ec2020-03-04 16:52:08 -0800472 ptr = cbfs_map(hwi_filename, &filesize);
Werner Zeh223498f2016-04-22 14:14:45 +0200473 if (!ptr) {
474 printk(BIOS_ERR,"HWILIB: Missing file \"%s\" in cbfs.\n",
475 hwi_filename);
476 return CB_ERR;
477 }
478 /* Ensure the block has the right magic */
479 if (strncmp((char*)ptr, BLOCK_MAGIC, LEN_MAGIC_NUM)) {
480 printk(BIOS_ERR, "HWILIB: Bad magic at start of block!\n");
481 return CB_ERR;
482 }
483 /* Reset all static pointers to blocks as they might have been set
484 * in prior calls to this function.
485 * This way the caller do not need to "close" already opened blocks.
486 */
Arthur Heymansb6c9a5d2019-11-20 19:35:59 +0100487 memset(all_blocks, 0, (MAX_BLOCK_NUM * sizeof (uint8_t *)));
Werner Zeh223498f2016-04-22 14:14:45 +0200488 /* Check which blocks are available by examining the length field. */
489 base = ptr;
Werner Zeh66c20c42016-06-28 14:31:30 +0200490 /* Fill in sizes of all fixed length blocks. */
Arthur Heymansb6c9a5d2019-11-20 19:35:59 +0100491 all_blk_size[BLK_HIB] = LEN_HIB;
492 all_blk_size[BLK_SIB] = LEN_SIB;
493 all_blk_size[BLK_EIB] = LEN_EIB;
Werner Zeh66c20c42016-06-28 14:31:30 +0200494 /* Length of BLK_XIB is variable and will be filled if block is found */
Arthur Heymansb6c9a5d2019-11-20 19:35:59 +0100495 all_blk_size[BLK_XIB] = 0;
Werner Zeh223498f2016-04-22 14:14:45 +0200496 while(!(strncmp((char *)ptr, BLOCK_MAGIC, LEN_MAGIC_NUM)) &&
497 next_offset) {
498 uint16_t len = read16(ptr + LEN_OFFSET);
499 /* Ensure file size boundaries for a given block. */
500 if ((ptr - base + len) > filesize)
501 break;
502 if (len == LEN_HIB) {
Arthur Heymansb6c9a5d2019-11-20 19:35:59 +0100503 all_blocks[BLK_HIB] = ptr;
Werner Zeh223498f2016-04-22 14:14:45 +0200504 next_offset = read32(ptr + NEXT_OFFSET_HIB);
505 if (next_offset)
506 ptr = base + next_offset;
507 } else if (len == LEN_SIB) {
Arthur Heymansb6c9a5d2019-11-20 19:35:59 +0100508 all_blocks[BLK_SIB] = ptr;
Werner Zeh223498f2016-04-22 14:14:45 +0200509 next_offset = read32(ptr + NEXT_OFFSET_SIB);
510 if (next_offset)
511 ptr = base + next_offset;
512 } else if (len == LEN_EIB) {
513 /* Skip preliminary blocks */
514 if (!(read16(ptr + EIB_FEATRUE_OFFSET) & 0x01))
Arthur Heymansb6c9a5d2019-11-20 19:35:59 +0100515 all_blocks[BLK_EIB] = ptr;
Werner Zeh223498f2016-04-22 14:14:45 +0200516 next_offset = read32(ptr + NEXT_OFFSET_EIB);
517 if (next_offset)
518 ptr = base + next_offset;
Werner Zeh66c20c42016-06-28 14:31:30 +0200519 } else if (len >= MIN_LEN_XIB) {
Arthur Heymansb6c9a5d2019-11-20 19:35:59 +0100520 all_blocks[BLK_XIB] = ptr;
Werner Zeh66c20c42016-06-28 14:31:30 +0200521 next_offset = read32(ptr + NEXT_OFFSET_XIB);
Arthur Heymansb6c9a5d2019-11-20 19:35:59 +0100522 all_blk_size[BLK_XIB] = len;
Werner Zeh66c20c42016-06-28 14:31:30 +0200523 if (next_offset)
524 ptr = base + next_offset;
Werner Zeh223498f2016-04-22 14:14:45 +0200525 } else {
526 next_offset = 0;
527 }
528 }
529 /* We should have found at least one valid block */
Arthur Heymansb6c9a5d2019-11-20 19:35:59 +0100530 if (all_blocks[BLK_HIB] || all_blocks[BLK_SIB] || all_blocks[BLK_EIB] ||
531 all_blocks[BLK_XIB]) {
Werner Zehd35a4812019-02-20 06:38:04 +0100532 /* Save currently opened hwi filename. */
Arthur Heymans5b0db352019-11-21 08:00:27 +0100533 strncpy(current_hwi, hwi_filename, HWI_MAX_NAME_LEN);
Werner Zeh223498f2016-04-22 14:14:45 +0200534 return CB_SUCCESS;
Werner Zehd35a4812019-02-20 06:38:04 +0100535 }
Werner Zeh223498f2016-04-22 14:14:45 +0200536 else
537 return CB_ERR;
538}
539
540/** \brief This functions is used from caller to get a specific field from
541 * hwinfo block.
542 * @param field Field type to read from hwinfo
543 * @param *dst Pointer to memory where the data will be stored in
544 * @return number of copied bytes on success, 0 on error
545 */
546uint32_t hwilib_get_field (hwinfo_field_t field, uint8_t *dst, uint32_t maxlen)
547{
548 /* Check the boundaries of params-variable */
549 if ((uint32_t)field < ARRAY_SIZE(params))
550 return params[field].get_field(&params[field], dst, maxlen);
551 else
552 return 0;
553}