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