Werner Zeh | 223498f | 2016-04-22 14:14:45 +0200 | [diff] [blame] | 1 | /* |
| 2 | * This file is part of the coreboot project. |
| 3 | * |
| 4 | * Copyright (C) 2014 Siemens AG. |
| 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify |
| 7 | * it under the terms of the GNU General Public License as published by |
| 8 | * the Free Software Foundation; version 2 of the License. |
| 9 | * |
| 10 | * This program is distributed in the hope that it will be useful, |
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 13 | * GNU General Public License for more details. |
| 14 | */ |
| 15 | |
| 16 | #include <cbfs.h> |
| 17 | #include <string.h> |
| 18 | #include <console/console.h> |
| 19 | #include <arch/io.h> |
| 20 | #include <arch/early_variables.h> |
| 21 | #include "hwilib.h" |
| 22 | |
| 23 | |
Werner Zeh | 66c20c4 | 2016-06-28 14:31:30 +0200 | [diff] [blame] | 24 | #define MAX_BLOCK_NUM 4 |
Werner Zeh | 223498f | 2016-04-22 14:14:45 +0200 | [diff] [blame] | 25 | #define LEN_HIB 0x1fd |
| 26 | #define LEN_SIB 0x121 |
| 27 | #define LEN_EIB 0x0b5 |
Werner Zeh | 66c20c4 | 2016-06-28 14:31:30 +0200 | [diff] [blame] | 28 | #define MIN_LEN_XIB 0x201 |
Werner Zeh | 223498f | 2016-04-22 14:14:45 +0200 | [diff] [blame] | 29 | #define NEXT_OFFSET_HIB 0x1dc |
| 30 | #define NEXT_OFFSET_SIB 0x104 |
| 31 | #define NEXT_OFFSET_EIB 0x0b0 |
Werner Zeh | 66c20c4 | 2016-06-28 14:31:30 +0200 | [diff] [blame] | 32 | #define NEXT_OFFSET_XIB 0x014 |
Werner Zeh | 223498f | 2016-04-22 14:14:45 +0200 | [diff] [blame] | 33 | #define LEN_UNIQUEL_NUM 0x010 |
| 34 | #define LEN_HW_REV 0x002 |
| 35 | #define LEN_MAC_ADDRESS 0x006 |
| 36 | #define LEN_SPD 0x080 |
| 37 | #define LEN_EDID 0x080 |
| 38 | #define LEN_OFFSET 0x00c |
| 39 | #define EIB_FEATRUE_OFFSET 0x00e |
| 40 | #define LEN_MAGIC_NUM 0x007 |
| 41 | #define BLOCK_MAGIC "H1W2M3I" |
| 42 | |
| 43 | /* Define all supported block types. */ |
| 44 | enum { |
| 45 | BLK_HIB, |
| 46 | BLK_SIB, |
| 47 | BLK_EIB, |
Werner Zeh | 66c20c4 | 2016-06-28 14:31:30 +0200 | [diff] [blame] | 48 | BLK_XIB |
Werner Zeh | 223498f | 2016-04-22 14:14:45 +0200 | [diff] [blame] | 49 | }; |
| 50 | |
| 51 | /* This structure holds a valid position for a given field |
| 52 | * Every field can have multiple positions of which the first available |
| 53 | * will be taken by the library. |
| 54 | */ |
| 55 | struct param_pos { |
| 56 | uint8_t blk_type; /* Valid for a specific block type */ |
| 57 | uint32_t offset; /* Offset in given block */ |
| 58 | uint32_t len; /* Length for the field in this block */ |
| 59 | }; |
| 60 | |
| 61 | /* This structure holds all the needed information for a given field type |
| 62 | * and a pointer to a function which is able to extract the desired data. |
| 63 | */ |
| 64 | struct param_info { |
| 65 | struct param_pos pos[MAX_BLOCK_NUM]; |
| 66 | uint64_t mask; |
| 67 | uint8_t mask_offset; |
| 68 | uint32_t (*get_field)(const struct param_info *param, uint8_t *dst, |
| 69 | uint32_t maxlen); |
| 70 | }; |
| 71 | |
| 72 | /* Storage for pointers to the different blocks. The contents will be filled |
| 73 | * in hwilib_find_blocks(). |
| 74 | */ |
| 75 | static uint8_t *all_blocks[MAX_BLOCK_NUM] CAR_GLOBAL; |
| 76 | |
Werner Zeh | 66c20c4 | 2016-06-28 14:31:30 +0200 | [diff] [blame] | 77 | /* As the length of extended block is variable, save all length to a global |
| 78 | * variable so that they can be used later to check boundaries. |
| 79 | */ |
| 80 | static uint16_t all_blk_size[MAX_BLOCK_NUM] CAR_GLOBAL; |
| 81 | |
| 82 | |
Werner Zeh | 223498f | 2016-04-22 14:14:45 +0200 | [diff] [blame] | 83 | static uint32_t hwilib_read_bytes (const struct param_info *param, uint8_t *dst, |
| 84 | uint32_t maxlen); |
| 85 | |
| 86 | /* Add all supported fields to this variable. It is important to use the |
| 87 | * field type of a given field as the array index so that all the information |
| 88 | * is on the appropriate place inside the array. In this way one do not need |
| 89 | * to search for fields but can simply use an index into the array. |
| 90 | */ |
| 91 | static const struct param_info params[] = { |
| 92 | [HIB_VerID] = { |
| 93 | .pos[0] = {.blk_type = BLK_HIB, .offset = 0x8, .len = 4}, |
| 94 | .get_field = hwilib_read_bytes }, |
| 95 | [SIB_VerID] = { |
| 96 | .pos[0] = {.blk_type = BLK_SIB, .offset = 0x8, .len = 4}, |
| 97 | .get_field = hwilib_read_bytes }, |
| 98 | [EIB_VerID] = { |
| 99 | .pos[0] = {.blk_type = BLK_EIB, .offset = 0x8, .len = 4}, |
| 100 | .get_field = hwilib_read_bytes }, |
Werner Zeh | 66c20c4 | 2016-06-28 14:31:30 +0200 | [diff] [blame] | 101 | [XIB_VerID] = { |
| 102 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x8, .len = 4}, |
| 103 | .get_field = hwilib_read_bytes }, |
Werner Zeh | 223498f | 2016-04-22 14:14:45 +0200 | [diff] [blame] | 104 | [HIB_HwRev] = { |
| 105 | .pos[0] = {.blk_type = BLK_HIB, .offset = 0xbe, .len = 2}, |
| 106 | .get_field = hwilib_read_bytes }, |
| 107 | [SIB_HwRev] = { |
| 108 | .pos[0] = {.blk_type = BLK_SIB, .offset = 0xc8, .len = 2}, |
| 109 | .get_field = hwilib_read_bytes }, |
Werner Zeh | ba7525d | 2016-11-23 07:31:35 +0100 | [diff] [blame] | 110 | [HWID] = { |
| 111 | .pos[0] = {.blk_type = BLK_HIB, .offset = 0x1a8, .len = 4}, |
| 112 | .pos[1] = {.blk_type = BLK_SIB, .offset = 0xd0, .len = 4}, |
| 113 | .get_field = hwilib_read_bytes }, |
Werner Zeh | 223498f | 2016-04-22 14:14:45 +0200 | [diff] [blame] | 114 | [UniqueNum] = { |
| 115 | .pos[0] = {.blk_type = BLK_HIB, .offset = 0xa2, .len = 10}, |
| 116 | .pos[1] = {.blk_type = BLK_SIB, .offset = 0xa2, .len = 10}, |
| 117 | .get_field = hwilib_read_bytes }, |
| 118 | [Mac1] = { |
| 119 | .pos[0] = {.blk_type = BLK_HIB, .offset = 0xc0, .len = 6}, |
| 120 | .get_field = hwilib_read_bytes }, |
| 121 | [Mac1Aux] = { |
| 122 | .pos[0] = {.blk_type = BLK_HIB, .offset = 0xc6, .len = 1}, |
| 123 | .get_field = hwilib_read_bytes }, |
| 124 | [Mac2] = { |
| 125 | .pos[0] = {.blk_type = BLK_HIB, .offset = 0xc8, .len = 6}, |
| 126 | .get_field = hwilib_read_bytes }, |
| 127 | [Mac2Aux] = { |
| 128 | .pos[0] = {.blk_type = BLK_HIB, .offset = 0xce, .len = 1}, |
| 129 | .get_field = hwilib_read_bytes }, |
| 130 | [Mac3] = { |
| 131 | .pos[0] = {.blk_type = BLK_HIB, .offset = 0xd0, .len = 6}, |
| 132 | .get_field = hwilib_read_bytes }, |
| 133 | [Mac3Aux] = { |
| 134 | .pos[0] = {.blk_type = BLK_HIB, .offset = 0xd6, .len = 1}, |
| 135 | .get_field = hwilib_read_bytes }, |
| 136 | [Mac4] = { |
| 137 | .pos[0] = {.blk_type = BLK_HIB, .offset = 0xd8, .len = 6}, |
| 138 | .get_field = hwilib_read_bytes }, |
| 139 | [Mac4Aux] = { |
| 140 | .pos[0] = {.blk_type = BLK_HIB, .offset = 0xde, .len = 1}, |
| 141 | .get_field = hwilib_read_bytes }, |
| 142 | [SPD] = { |
| 143 | .pos[0] = {.blk_type = BLK_HIB, .offset = 0xe0, .len = 0x80}, |
| 144 | .get_field = hwilib_read_bytes }, |
| 145 | [FF_FreezeDis] = { |
| 146 | .pos[0] = {.blk_type = BLK_HIB, .offset = 0x1b8, .len = 4}, |
| 147 | .mask = 0x10, |
| 148 | .mask_offset = 4, |
| 149 | .get_field = hwilib_read_bytes }, |
| 150 | [FF_FanReq] = { |
| 151 | .pos[0] = {.blk_type = BLK_HIB, .offset = 0x1b8, .len = 4}, |
| 152 | .mask = 0x400, |
| 153 | .mask_offset = 10, |
| 154 | .get_field = hwilib_read_bytes }, |
| 155 | [BiosFlags] = { |
| 156 | .pos[0] = {.blk_type = BLK_HIB, .offset = 0x1c0, .len = 4}, |
| 157 | .get_field = hwilib_read_bytes }, |
| 158 | [MacMapping1] = { |
| 159 | .pos[0] = {.blk_type = BLK_HIB, .offset = 0x1cc, .len = 4}, |
| 160 | .get_field = hwilib_read_bytes }, |
| 161 | [MacMapping2] = { |
| 162 | .pos[0] = {.blk_type = BLK_HIB, .offset = 0x1d0, .len = 4}, |
| 163 | .get_field = hwilib_read_bytes }, |
| 164 | [MacMapping3] = { |
| 165 | .pos[0] = {.blk_type = BLK_HIB, .offset = 0x1d4, .len = 4}, |
| 166 | .get_field = hwilib_read_bytes }, |
| 167 | [MacMapping4] = { |
| 168 | .pos[0] = {.blk_type = BLK_HIB, .offset = 0x1d8, .len = 4}, |
| 169 | .get_field = hwilib_read_bytes }, |
Werner Zeh | 66c20c4 | 2016-06-28 14:31:30 +0200 | [diff] [blame] | 170 | [RTCType] = { |
| 171 | .pos[0] = {.blk_type = BLK_HIB, .offset = 0x1e8, .len = 1}, |
| 172 | .get_field = hwilib_read_bytes }, |
Werner Zeh | 223498f | 2016-04-22 14:14:45 +0200 | [diff] [blame] | 173 | [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 Zeh | 66c20c4 | 2016-06-28 14:31:30 +0200 | [diff] [blame] | 190 | [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 }, |
| 343 | [FANStartpeed] = { |
| 344 | .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 }, |
| 379 | |
Werner Zeh | 223498f | 2016-04-22 14:14:45 +0200 | [diff] [blame] | 380 | }; |
| 381 | |
| 382 | /** \brief This functions reads the given field from the first valid hwinfo |
| 383 | * block |
| 384 | * @param *param Parameter to read from hwinfo |
| 385 | * @param *dst Pointer to memory where the data will be stored in |
| 386 | * @return number of copied bytes on success, 0 on error |
| 387 | */ |
| 388 | static uint32_t hwilib_read_bytes (const struct param_info *param, uint8_t *dst, |
| 389 | uint32_t maxlen) |
| 390 | { |
| 391 | uint8_t i = 0, *blk = NULL; |
| 392 | uint8_t **blk_ptr = car_get_var_ptr(&all_blocks[0]); |
Werner Zeh | 66c20c4 | 2016-06-28 14:31:30 +0200 | [diff] [blame] | 393 | uint16_t *all_blk_size_ptr = car_get_var_ptr(&all_blk_size[0]); |
Werner Zeh | 223498f | 2016-04-22 14:14:45 +0200 | [diff] [blame] | 394 | |
| 395 | if (!param || !dst) |
| 396 | return 0; |
| 397 | /* Take the first valid block to get the parameter from */ |
| 398 | do { |
Werner Zeh | 8f91623 | 2016-12-01 10:53:14 +0100 | [diff] [blame] | 399 | if ((param->pos[i].len) && (param->pos[i].offset) && |
| 400 | (blk_ptr[param->pos[i].blk_type])) { |
Werner Zeh | 223498f | 2016-04-22 14:14:45 +0200 | [diff] [blame] | 401 | blk = blk_ptr[param->pos[i].blk_type]; |
| 402 | 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 > |
Werner Zeh | 66c20c4 | 2016-06-28 14:31:30 +0200 | [diff] [blame] | 412 | all_blk_size_ptr[param->pos[i].blk_type])) |
Werner Zeh | 223498f | 2016-04-22 14:14:45 +0200 | [diff] [blame] | 413 | 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 | */ |
| 455 | enum cb_err hwilib_find_blocks (const char *hwi_filename) |
| 456 | { |
| 457 | uint8_t *ptr = NULL, *base = NULL; |
| 458 | uint32_t next_offset = 1; |
| 459 | uint8_t **blk_ptr = car_get_var_ptr(&all_blocks[0]); |
Werner Zeh | 66c20c4 | 2016-06-28 14:31:30 +0200 | [diff] [blame] | 460 | uint16_t *all_blk_size_ptr = car_get_var_ptr(&all_blk_size[0]); |
Werner Zeh | 223498f | 2016-04-22 14:14:45 +0200 | [diff] [blame] | 461 | size_t filesize = 0; |
| 462 | |
| 463 | /* Check for a valid parameter */ |
| 464 | if (!hwi_filename) |
| 465 | return CB_ERR_ARG; |
| 466 | ptr = cbfs_boot_map_with_leak(hwi_filename, CBFS_TYPE_RAW, &filesize); |
| 467 | if (!ptr) { |
| 468 | printk(BIOS_ERR,"HWILIB: Missing file \"%s\" in cbfs.\n", |
| 469 | hwi_filename); |
| 470 | return CB_ERR; |
| 471 | } |
| 472 | /* Ensure the block has the right magic */ |
| 473 | if (strncmp((char*)ptr, BLOCK_MAGIC, LEN_MAGIC_NUM)) { |
| 474 | printk(BIOS_ERR, "HWILIB: Bad magic at start of block!\n"); |
| 475 | return CB_ERR; |
| 476 | } |
| 477 | /* Reset all static pointers to blocks as they might have been set |
| 478 | * in prior calls to this function. |
| 479 | * This way the caller do not need to "close" already opened blocks. |
| 480 | */ |
| 481 | memset(blk_ptr, 0, (MAX_BLOCK_NUM * sizeof (uint8_t *))); |
| 482 | /* Check which blocks are available by examining the length field. */ |
| 483 | base = ptr; |
Werner Zeh | 66c20c4 | 2016-06-28 14:31:30 +0200 | [diff] [blame] | 484 | /* Fill in sizes of all fixed length blocks. */ |
| 485 | all_blk_size_ptr[BLK_HIB] = LEN_HIB; |
| 486 | all_blk_size_ptr[BLK_SIB] = LEN_SIB; |
| 487 | all_blk_size_ptr[BLK_EIB] = LEN_EIB; |
| 488 | /* Length of BLK_XIB is variable and will be filled if block is found */ |
| 489 | all_blk_size_ptr[BLK_XIB] = 0; |
Werner Zeh | 223498f | 2016-04-22 14:14:45 +0200 | [diff] [blame] | 490 | while(!(strncmp((char *)ptr, BLOCK_MAGIC, LEN_MAGIC_NUM)) && |
| 491 | next_offset) { |
| 492 | uint16_t len = read16(ptr + LEN_OFFSET); |
| 493 | /* Ensure file size boundaries for a given block. */ |
| 494 | if ((ptr - base + len) > filesize) |
| 495 | break; |
| 496 | if (len == LEN_HIB) { |
| 497 | blk_ptr[BLK_HIB] = ptr; |
| 498 | next_offset = read32(ptr + NEXT_OFFSET_HIB); |
| 499 | if (next_offset) |
| 500 | ptr = base + next_offset; |
| 501 | } else if (len == LEN_SIB) { |
| 502 | blk_ptr[BLK_SIB] = ptr; |
| 503 | next_offset = read32(ptr + NEXT_OFFSET_SIB); |
| 504 | if (next_offset) |
| 505 | ptr = base + next_offset; |
| 506 | } else if (len == LEN_EIB) { |
| 507 | /* Skip preliminary blocks */ |
| 508 | if (!(read16(ptr + EIB_FEATRUE_OFFSET) & 0x01)) |
| 509 | blk_ptr[BLK_EIB] = ptr; |
| 510 | next_offset = read32(ptr + NEXT_OFFSET_EIB); |
| 511 | if (next_offset) |
| 512 | ptr = base + next_offset; |
Werner Zeh | 66c20c4 | 2016-06-28 14:31:30 +0200 | [diff] [blame] | 513 | } else if (len >= MIN_LEN_XIB) { |
| 514 | blk_ptr[BLK_XIB] = ptr; |
| 515 | next_offset = read32(ptr + NEXT_OFFSET_XIB); |
| 516 | all_blk_size_ptr[BLK_XIB] = len; |
| 517 | if (next_offset) |
| 518 | ptr = base + next_offset; |
Werner Zeh | 223498f | 2016-04-22 14:14:45 +0200 | [diff] [blame] | 519 | } else { |
| 520 | next_offset = 0; |
| 521 | } |
| 522 | } |
| 523 | /* We should have found at least one valid block */ |
Werner Zeh | 66c20c4 | 2016-06-28 14:31:30 +0200 | [diff] [blame] | 524 | if (blk_ptr[BLK_HIB] || blk_ptr[BLK_SIB] || blk_ptr[BLK_EIB] || |
| 525 | blk_ptr[BLK_XIB]) |
Werner Zeh | 223498f | 2016-04-22 14:14:45 +0200 | [diff] [blame] | 526 | return CB_SUCCESS; |
| 527 | else |
| 528 | return CB_ERR; |
| 529 | } |
| 530 | |
| 531 | /** \brief This functions is used from caller to get a specific field from |
| 532 | * hwinfo block. |
| 533 | * @param field Field type to read from hwinfo |
| 534 | * @param *dst Pointer to memory where the data will be stored in |
| 535 | * @return number of copied bytes on success, 0 on error |
| 536 | */ |
| 537 | uint32_t hwilib_get_field (hwinfo_field_t field, uint8_t *dst, uint32_t maxlen) |
| 538 | { |
| 539 | /* Check the boundaries of params-variable */ |
| 540 | if ((uint32_t)field < ARRAY_SIZE(params)) |
| 541 | return params[field].get_field(¶ms[field], dst, maxlen); |
| 542 | else |
| 543 | return 0; |
| 544 | } |