1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <string.h> 29 #include <stdlib.h> 30 31 #include "PayloadReader.h" 32 33 #define ITER_CONT_BYTE_LEN 4 34 #define IS_ITERATED(pathDef) \ 35 (pathDef->def->iterationType != FRU_NOT_ITERATED) 36 37 // functions to place bit data properly. 38 static fru_errno_t 39 writeBits(uint64_t bitData, size_t bitLength, 40 uint8_t *data, size_t dataLength, size_t bitOffset) 41 { 42 if ((bitLength > 64) && 43 (bitOffset > 64) && 44 (dataLength > 8) && 45 (bitOffset > (dataLength * 8))) 46 return (FRU_FAILURE); 47 // move the bit data into place 48 bitData = (bitData << (64-bitLength)); 49 bitData = (bitData >> bitOffset); 50 51 // create a mask to clear the old data. 52 uint64_t mask = 0; 53 for (size_t i = 0; i < bitLength; i++) { 54 mask = ((mask << 1) + 1); 55 } 56 mask = (mask << (64-bitLength)); 57 mask = (mask >> bitOffset); 58 mask = (mask ^ 0xFFFFFFFFFFFFFFFFULL); 59 60 // get the data out of the byte array. 61 uint64_t rd = 0; 62 memcpy((void *)&rd, (void *)data, dataLength); 63 64 // clear the old data 65 rd = (rd & mask); 66 // put in the new data. 67 rd = (rd | bitData); 68 69 // write the data back to the buffer. 70 memcpy((void *)data, (void *)&rd, dataLength); 71 return (FRU_SUCCESS); 72 } 73 74 static fru_errno_t 75 readBits(size_t bitLength, uint8_t *data, 76 size_t dataLength, int bitOffset, uint64_t *ret) 77 { 78 if ((bitLength > 64) || 79 (bitLength < 0) || 80 (bitOffset > 64) || 81 (dataLength > 8) || 82 (bitOffset > (dataLength * 8))) 83 return (FRU_FAILURE); 84 // get the data out of the byte array. 85 uint64_t rc = 0; 86 memcpy((void *)&rc, (void *)data, dataLength); 87 88 rc = (rc << bitOffset); 89 rc = (rc >> (64 - bitLength)); 90 *ret = rc; 91 return (FRU_SUCCESS); 92 } 93 94 // =========================================================================== 95 // caller is to be sure elemDef is contained by recDef. 96 int 97 PayloadReader::getOffsetIntoRecord(fru_regdef_t *recDef, 98 fru_regdef_t *elemDef) 99 { 100 int rc = 0; 101 for (int i = 0; i < recDef->enumCount; i++) { 102 if (strcmp(recDef->enumTable[i].text, elemDef->name) == 0) 103 return (rc); 104 const fru_regdef_t *tmpDef = fru_reg_lookup_def_by_name( 105 (char *)recDef->enumTable[i].text); 106 rc += tmpDef->payloadLen; 107 } 108 return(0); 109 } 110 111 // =========================================================================== 112 // return -1 on error. 113 int 114 PayloadReader::calcOffset(int iterType, 115 uint8_t head, uint8_t tail, 116 uint8_t iterThere, uint8_t iterPoss, 117 size_t length, int index, 118 fru_errno_t *err) 119 { 120 *err = FRU_SUCCESS; 121 switch (iterType) { 122 case FRU_FIFO: 123 case FRU_Linear: 124 { 125 if (index == PathDef::lastIteration) 126 return (length * tail); 127 return (length * index); 128 break; 129 } 130 case FRU_Circular: 131 case FRU_LIFO: 132 { 133 if (index == PathDef::lastIteration) { 134 if (iterType == FRU_LIFO) 135 return (length * head); 136 return (length * tail); 137 } 138 139 // For reading they are oposite. 140 if (iterType == FRU_Circular) { 141 return (length * ((head + index) % iterPoss)); 142 } else { 143 int abs = tail - index; 144 if (abs < 0) 145 // abs is negative here 146 abs = iterPoss + abs; 147 return (length * abs); 148 } 149 break; 150 } 151 } 152 *err = FRU_FAILURE; 153 return (-1); 154 } 155 156 // =========================================================================== 157 // return -1 on error. 158 int 159 PayloadReader::getIterationOffset(uint8_t *iter, int iterLen, 160 PathDef *path, int *rcIterThere, 161 fru_errno_t *err, 162 int onlyFindingIterThereFlag) 163 { 164 int rc = 0; 165 166 // read the iteration control bytes first because we may ONLY need 167 // them. 168 uint8_t head = iter[0]; 169 uint8_t tail = iter[1]; 170 uint8_t iterThere = iter[2]; 171 uint8_t iterPoss = iter[3]; 172 173 // the '+' symbol on anything is an error here 174 if (path->iterIndex == PathDef::addIteration) { 175 *err = FRU_INVALPATH; 176 return (-1); 177 } 178 179 // check assumptions for next calls. 180 if (iterPoss != path->def->iterationCount) { 181 *err = FRU_DATACORRUPT; 182 return (-1); 183 } 184 185 if (onlyFindingIterThereFlag == ITER_THERE_ONLY) { 186 if (rcIterThere != NULL) { 187 *rcIterThere = iterThere; 188 } 189 *err = FRU_SUCCESS; 190 return (ITER_CONT_BYTE_LEN); 191 } 192 193 if ((path->iterIndex != PathDef::addIteration) && 194 (path->iterIndex != PathDef::lastIteration) && 195 (path->iterIndex >= iterThere)) { 196 *err = FRU_DATANOTFOUND; 197 return (-1); 198 } 199 200 // don't forget to skip the iteration control bytes!!! 201 int length = ((path->def->payloadLen - ITER_CONT_BYTE_LEN) 202 /path->def->iterationCount); 203 204 rc = calcOffset(path->def->iterationType, 205 head, tail, iterThere, iterPoss, 206 length, path->iterIndex, err); 207 if (rc == -1) { 208 // error set by calcOffset 209 return (-1); 210 } 211 212 *err = FRU_SUCCESS; 213 return (ITER_CONT_BYTE_LEN + rc); 214 } 215 216 // =========================================================================== 217 // Iff onlyFindingIterThereFlag is set data is ignored and dataLen will be set 218 // to the number of iterations which are actually in the seeprom. 219 fru_errno_t 220 PayloadReader::readRecurse(PathDef *path, 221 uint8_t *cur, size_t curLen, 222 void **data, size_t *dataLen, 223 int onlyFindingIterThereFlag) 224 { 225 fru_errno_t rc = FRU_SUCCESS; 226 size_t calc_data_len = 0; 227 228 if (path->next == NULL) { 229 230 // alway go ahead and do the iterated thing. If we are not a 231 // field then the onlyFindingIterThereFlag should be set. 232 // Check this afterward. 233 int offset = 0; 234 int iterThere = 0; 235 // zzz altering the length things again... 236 if (IS_ITERATED(path)) { 237 // we are iterated. 238 calc_data_len = (path->def->payloadLen 239 -ITER_CONT_BYTE_LEN)/ 240 path->def->iterationCount; 241 // zzz still have to figure out the bit offsets for bit iterations... 242 offset = getIterationOffset(cur, curLen, path, 243 &iterThere, &rc, 244 onlyFindingIterThereFlag); 245 if (offset == -1) 246 return (rc); 247 248 // done 249 if (onlyFindingIterThereFlag) { 250 *dataLen = iterThere; 251 return (FRU_SUCCESS); 252 } 253 } else { 254 // done but this thing was not an iteration!!! 255 if (onlyFindingIterThereFlag) { 256 return (FRU_INVALPATH); 257 } 258 259 calc_data_len = path->def->payloadLen; 260 offset = 0; 261 } 262 // end zzz 263 264 // now make sure we have a field. 265 if (path->def->dataType == FDTYPE_Record) { 266 return (FRU_NOTFIELD); 267 } 268 269 // allocate and copy. 270 if (path->def->dataType == FDTYPE_Binary) { 271 uint64_t *eData = (uint64_t *)malloc(sizeof (*eData)); 272 if (eData == NULL) { 273 return (FRU_FAILURE); 274 } 275 276 int bitLength = path->def->dataLength; 277 // iterated bit field adjust acordingly. 278 if (IS_ITERATED(path)) { 279 bitLength = (bitLength-(ITER_CONT_BYTE_LEN*8))/ 280 path->def->iterationCount; 281 } 282 283 rc = readBits(bitLength, &(cur[offset]), 284 calc_data_len, 0, eData); 285 if (rc != FRU_SUCCESS) { 286 free(eData); 287 return (rc); 288 } 289 *data = (void *)eData; 290 *dataLen = sizeof (*eData); 291 } else if (path->def->dataType == FDTYPE_Enumeration) { 292 unsigned char *eData 293 = (unsigned char *)malloc(sizeof (uint64_t)); 294 if (eData == NULL) { 295 return (FRU_FAILURE); 296 } 297 /* copy the correct number of bytes to eData */ 298 memset(eData, 0x00, sizeof (uint64_t)); 299 memcpy(&(eData[(sizeof (uint64_t) - (calc_data_len))]), 300 &(cur[offset]), 301 (calc_data_len)); 302 *data = (void*)eData; 303 *dataLen = sizeof (uint64_t); 304 } else { 305 void *rc_data = malloc(calc_data_len); 306 if (rc_data == NULL) { 307 return (FRU_FAILURE); 308 } 309 memcpy(rc_data, &(cur[offset]), calc_data_len); 310 *data = rc_data; 311 *dataLen = calc_data_len; 312 } 313 314 return (FRU_SUCCESS); 315 } 316 317 // At this point we know the entry is some sort of record. 318 319 int newOffset = 0, newLength = 0; 320 if (IS_ITERATED(path)) { 321 322 // zzz still have to figure out the bit offsets for bit iterations... 323 newOffset = getIterationOffset(cur, curLen, 324 path, NULL, &rc, NORMAL_READ); 325 if (newOffset == -1) 326 return (rc); 327 } 328 329 newOffset += getOffsetIntoRecord(path->def, path->next->def); 330 newLength = path->next->def->payloadLen; 331 332 return (readRecurse(path->next, &(cur[newOffset]), newLength, 333 data, dataLen, onlyFindingIterThereFlag)); 334 } 335 336 // =========================================================================== 337 // will send the data back in (data,dataLen) 338 fru_errno_t 339 PayloadReader::readData(PathDef *path, Ancestor *curDef, 340 int instWICur, 341 uint8_t *payload, size_t payloadLen, 342 void **data, size_t *dataLen) 343 { 344 int offset = curDef->getInstOffset(instWICur); 345 return (readRecurse(path, &(payload[offset]), payloadLen-offset, 346 data, dataLen, NORMAL_READ)); 347 } 348 349 // =========================================================================== 350 fru_errno_t 351 PayloadReader::findIterThere(PathDef *path, Ancestor *curDef, 352 int instWICur, 353 uint8_t *payload, size_t payloadLen, 354 int *numThere) 355 { 356 int offset = curDef->getInstOffset(instWICur); 357 size_t tmp_num = 0; 358 fru_errno_t err = readRecurse(path, &(payload[offset]), 359 payloadLen-offset, NULL, &tmp_num, ITER_THERE_ONLY); 360 361 if (err == FRU_SUCCESS) { 362 int tmp_num_there = (int)tmp_num; 363 if (tmp_num_there != tmp_num) { 364 return (FRU_FAILURE); 365 } 366 *numThere = tmp_num_there; 367 } 368 return (err); 369 } 370 371 static fru_errno_t 372 update_iter_cont_bytes(PathDef *path, uint8_t *cur, size_t curLen) 373 { 374 // update the iteration control information 375 uint8_t *head = &(cur[0]); 376 uint8_t *tail = &(cur[1]); 377 uint8_t *numThere = &(cur[2]); 378 // This never changes. 379 uint8_t numPoss = cur[3]; 380 381 if (numPoss != path->def->iterationCount) { 382 return (FRU_DATACORRUPT); 383 } 384 385 // Remember that when the iteration is added the head and the tail both 386 // equal 0 (ie point to 0). So if we are empty when we are updating 387 // then we don't have to alter the head or tail values. We simply add 388 // one to the numThere. 389 if (*numThere != 0) { 390 switch (path->def->iterationType) { 391 case FRU_Linear: 392 // this will flag an error when Linear can't 393 // hold anymore. 394 if ((*tail + 1) == numPoss) 395 return (FRU_ITERFULL); 396 /* Fall through */ 397 case FRU_FIFO: 398 // if we are not at the end move the tail. 399 if (*tail != (numPoss-1)) 400 *tail = *tail+1; 401 break; 402 403 case FRU_Circular: 404 case FRU_LIFO: 405 // this is the same except LIFO is read 406 // BACKWARDS 407 408 // move the tail. 409 *tail = *tail + 1; 410 // if the tail hits the end wrap around. 411 if (*tail == numPoss) 412 *tail = 0; 413 // if tail catches head move the head. 414 if (*tail == *head) { 415 // if head hits the end wrap around. 416 if (++(*head) == numPoss) 417 *head = 0; 418 } 419 break; 420 } 421 } 422 if ((*numThere) < numPoss) { 423 // add one IFF we are not full 424 *numThere = *numThere + 1; 425 } 426 427 return (FRU_SUCCESS); 428 } 429 430 // =========================================================================== 431 fru_errno_t 432 PayloadReader::updateRecurse(PathDef *path, 433 uint8_t *cur, size_t curLen, 434 void *data, size_t dataLen) 435 { 436 fru_errno_t rc = FRU_SUCCESS; 437 438 if (path->next == NULL) { 439 440 // Delay checking for Records until after this which will 441 // allow for [+] notation for Iterated Records. 442 // if this is updating an iteration AND we are adding one... 443 if (IS_ITERATED(path) && 444 (path->iterIndex == PathDef::addIteration)) { 445 return (update_iter_cont_bytes(path, cur, curLen)); 446 } 447 448 if (path->def->dataType == FDTYPE_Record) { 449 return (FRU_NOTFIELD); 450 } 451 452 int offset = 0; 453 int calcLen = 0; 454 int dummy = 0; 455 // zzz altering the length things again... 456 if (IS_ITERATED(path)) { 457 // we are iterated. 458 calcLen = (path->def->payloadLen-ITER_CONT_BYTE_LEN)/ 459 path->def->iterationCount; 460 // zzz still have to figure out the bit offsets 461 offset = getIterationOffset(cur, curLen, 462 path, &dummy, &rc, NORMAL_READ); 463 if (offset == -1) 464 return (rc); 465 } else { 466 calcLen = path->def->payloadLen; 467 offset = 0; 468 } 469 // end zzz 470 471 // once again convert enums for the user again. 472 if (path->def->dataType == FDTYPE_Binary) { 473 int bitLength = path->def->dataLength; 474 // iterated bit field adjust acordingly. 475 if (path->def->iterationType != FRU_NOT_ITERATED) { 476 bitLength = (bitLength - 32)/ 477 path->def->iterationCount; 478 } 479 480 rc = writeBits (*(uint64_t *)data, bitLength, 481 &(cur[offset]), calcLen, 0); 482 if (rc != FRU_SUCCESS) 483 return (rc); 484 } else if (path->def->dataType == FDTYPE_Enumeration) { 485 unsigned char *tmp = (unsigned char *)data; 486 memcpy(&(cur[offset]), 487 &(tmp[(sizeof (uint64_t) - (calcLen))]), 488 calcLen); 489 } else { 490 // copy into and return. 491 memcpy(&(cur[offset]), data, dataLen); 492 } 493 494 return (FRU_SUCCESS); 495 } 496 497 int newOffset = 0, newLength = 0; 498 int dummy = 0; 499 if (path->def->iterationType != FRU_NOT_ITERATED) { 500 501 // zzz still have to figure out the bit offsets 502 newOffset = getIterationOffset(cur, curLen, path, 503 &dummy, &rc, NORMAL_READ); 504 if (newOffset == -1) 505 return (rc); 506 } 507 newOffset += getOffsetIntoRecord(path->def, path->next->def); 508 newLength = path->next->def->payloadLen; 509 510 return (updateRecurse(path->next, &(cur[newOffset]), newLength, 511 data, dataLen)); 512 } 513 514 // =========================================================================== 515 // will update the data in payload which can then be written back. 516 fru_errno_t 517 PayloadReader::updateData(PathDef *path, Ancestor *ancestorDef, 518 int instWICur, 519 uint8_t *payload, size_t payloadLen, 520 void *data, size_t dataLen) 521 { 522 // verify the user data first before doing any major work. 523 int calcLen = 0; 524 PathDef *prev = path; 525 PathDef *cur = path; 526 while (cur != NULL) { 527 prev = cur; 528 cur = cur->next; 529 } 530 531 // unless we are updateing with [+] symbol 532 // (which means we don't have any data length at all.) 533 if (prev->iterIndex != PathDef::addIteration) { 534 if (IS_ITERATED(prev)) { 535 calcLen = (prev->def->payloadLen-ITER_CONT_BYTE_LEN)/ 536 prev->def->iterationCount; 537 } else { 538 calcLen = prev->def->payloadLen; 539 } 540 // the sizeof the data for Binary or Enumeration MUST 541 // be uint64_t 542 if ((prev->def->dataType == FDTYPE_Enumeration) || 543 (prev->def->dataType == FDTYPE_Binary)) { 544 if (dataLen != sizeof (uint64_t)) 545 return (FRU_INVALDATASIZE); 546 // all others must be shorter than the space available. 547 } else { 548 if (dataLen > calcLen) 549 return (FRU_INVALDATASIZE); 550 } 551 } 552 553 int offset = ancestorDef->getInstOffset(instWICur); 554 return (updateRecurse(path, &(payload[offset]), payloadLen-offset, 555 data, dataLen)); 556 } 557