2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A/*
2N/A * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
2N/A * Use is subject to license terms.
2N/A */
2N/A
2N/A#pragma ident "%Z%%M% %I% %E% SMI"
2N/A
2N/A#include <string.h>
2N/A#include <stdlib.h>
2N/A
2N/A#include "PayloadReader.h"
2N/A
2N/A#define ITER_CONT_BYTE_LEN 4
2N/A#define IS_ITERATED(pathDef) \
2N/A(pathDef->def->iterationType != FRU_NOT_ITERATED)
2N/A
2N/A// functions to place bit data properly.
2N/Astatic fru_errno_t
2N/AwriteBits(uint64_t bitData, size_t bitLength,
2N/A uint8_t *data, size_t dataLength, size_t bitOffset)
2N/A{
2N/A if ((bitLength > 64) &&
2N/A (bitOffset > 64) &&
2N/A (dataLength > 8) &&
2N/A (bitOffset > (dataLength * 8)))
2N/A return (FRU_FAILURE);
2N/A // move the bit data into place
2N/A bitData = (bitData << (64-bitLength));
2N/A bitData = (bitData >> bitOffset);
2N/A
2N/A // create a mask to clear the old data.
2N/A uint64_t mask = 0;
2N/A for (size_t i = 0; i < bitLength; i++) {
2N/A mask = ((mask << 1) + 1);
2N/A }
2N/A mask = (mask << (64-bitLength));
2N/A mask = (mask >> bitOffset);
2N/A mask = (mask ^ 0xFFFFFFFFFFFFFFFFULL);
2N/A
2N/A // get the data out of the byte array.
2N/A uint64_t rd = 0;
2N/A memcpy((void *)&rd, (void *)data, dataLength);
2N/A
2N/A // clear the old data
2N/A rd = (rd & mask);
2N/A // put in the new data.
2N/A rd = (rd | bitData);
2N/A
2N/A // write the data back to the buffer.
2N/A memcpy((void *)data, (void *)&rd, dataLength);
2N/A return (FRU_SUCCESS);
2N/A}
2N/A
2N/Astatic fru_errno_t
2N/AreadBits(size_t bitLength, uint8_t *data,
2N/A size_t dataLength, int bitOffset, uint64_t *ret)
2N/A{
2N/A if ((bitLength > 64) ||
2N/A (bitLength < 0) ||
2N/A (bitOffset > 64) ||
2N/A (dataLength > 8) ||
2N/A (bitOffset > (dataLength * 8)))
2N/A return (FRU_FAILURE);
2N/A // get the data out of the byte array.
2N/A uint64_t rc = 0;
2N/A memcpy((void *)&rc, (void *)data, dataLength);
2N/A
2N/A rc = (rc << bitOffset);
2N/A rc = (rc >> (64 - bitLength));
2N/A *ret = rc;
2N/A return (FRU_SUCCESS);
2N/A}
2N/A
2N/A// ===========================================================================
2N/A// caller is to be sure elemDef is contained by recDef.
2N/Aint
2N/APayloadReader::getOffsetIntoRecord(fru_regdef_t *recDef,
2N/A fru_regdef_t *elemDef)
2N/A{
2N/A int rc = 0;
2N/A for (int i = 0; i < recDef->enumCount; i++) {
2N/A if (strcmp(recDef->enumTable[i].text, elemDef->name) == 0)
2N/A return (rc);
2N/A const fru_regdef_t *tmpDef = fru_reg_lookup_def_by_name(
2N/A (char *)recDef->enumTable[i].text);
2N/A rc += tmpDef->payloadLen;
2N/A }
2N/A return(0);
2N/A}
2N/A
2N/A// ===========================================================================
2N/A// return -1 on error.
2N/Aint
2N/APayloadReader::calcOffset(int iterType,
2N/A uint8_t head, uint8_t tail,
2N/A uint8_t iterThere, uint8_t iterPoss,
2N/A size_t length, int index,
2N/A fru_errno_t *err)
2N/A{
2N/A *err = FRU_SUCCESS;
2N/A switch (iterType) {
2N/A case FRU_FIFO:
2N/A case FRU_Linear:
2N/A {
2N/A if (index == PathDef::lastIteration)
2N/A return (length * tail);
2N/A return (length * index);
2N/A break;
2N/A }
2N/A case FRU_Circular:
2N/A case FRU_LIFO:
2N/A {
2N/A if (index == PathDef::lastIteration) {
2N/A if (iterType == FRU_LIFO)
2N/A return (length * head);
2N/A return (length * tail);
2N/A }
2N/A
2N/A // For reading they are oposite.
2N/A if (iterType == FRU_Circular) {
2N/A return (length * ((head + index) % iterPoss));
2N/A } else {
2N/A int abs = tail - index;
2N/A if (abs < 0)
2N/A // abs is negative here
2N/A abs = iterPoss + abs;
2N/A return (length * abs);
2N/A }
2N/A break;
2N/A }
2N/A }
2N/A *err = FRU_FAILURE;
2N/A return (-1);
2N/A}
2N/A
2N/A// ===========================================================================
2N/A// return -1 on error.
2N/Aint
2N/APayloadReader::getIterationOffset(uint8_t *iter, int iterLen,
2N/A PathDef *path, int *rcIterThere,
2N/A fru_errno_t *err,
2N/A int onlyFindingIterThereFlag)
2N/A{
2N/A int rc = 0;
2N/A
2N/A // read the iteration control bytes first because we may ONLY need
2N/A // them.
2N/A uint8_t head = iter[0];
2N/A uint8_t tail = iter[1];
2N/A uint8_t iterThere = iter[2];
2N/A uint8_t iterPoss = iter[3];
2N/A
2N/A // the '+' symbol on anything is an error here
2N/A if (path->iterIndex == PathDef::addIteration) {
2N/A *err = FRU_INVALPATH;
2N/A return (-1);
2N/A }
2N/A
2N/A // check assumptions for next calls.
2N/A if (iterPoss != path->def->iterationCount) {
2N/A *err = FRU_DATACORRUPT;
2N/A return (-1);
2N/A }
2N/A
2N/A if (onlyFindingIterThereFlag == ITER_THERE_ONLY) {
2N/A if (rcIterThere != NULL) {
2N/A *rcIterThere = iterThere;
2N/A }
2N/A *err = FRU_SUCCESS;
2N/A return (ITER_CONT_BYTE_LEN);
2N/A }
2N/A
2N/A if ((path->iterIndex != PathDef::addIteration) &&
2N/A (path->iterIndex != PathDef::lastIteration) &&
2N/A (path->iterIndex >= iterThere)) {
2N/A *err = FRU_DATANOTFOUND;
2N/A return (-1);
2N/A }
2N/A
2N/A // don't forget to skip the iteration control bytes!!!
2N/A int length = ((path->def->payloadLen - ITER_CONT_BYTE_LEN)
2N/A /path->def->iterationCount);
2N/A
2N/A rc = calcOffset(path->def->iterationType,
2N/A head, tail, iterThere, iterPoss,
2N/A length, path->iterIndex, err);
2N/A if (rc == -1) {
2N/A // error set by calcOffset
2N/A return (-1);
2N/A }
2N/A
2N/A *err = FRU_SUCCESS;
2N/A return (ITER_CONT_BYTE_LEN + rc);
2N/A}
2N/A
2N/A// ===========================================================================
2N/A// Iff onlyFindingIterThereFlag is set data is ignored and dataLen will be set
2N/A// to the number of iterations which are actually in the seeprom.
2N/Afru_errno_t
2N/APayloadReader::readRecurse(PathDef *path,
2N/A uint8_t *cur, size_t curLen,
2N/A void **data, size_t *dataLen,
2N/A int onlyFindingIterThereFlag)
2N/A{
2N/A fru_errno_t rc = FRU_SUCCESS;
2N/A size_t calc_data_len = 0;
2N/A
2N/A if (path->next == NULL) {
2N/A
2N/A // alway go ahead and do the iterated thing. If we are not a
2N/A // field then the onlyFindingIterThereFlag should be set.
2N/A // Check this afterward.
2N/A int offset = 0;
2N/A int iterThere = 0;
2N/A // zzz altering the length things again...
2N/A if (IS_ITERATED(path)) {
2N/A // we are iterated.
2N/A calc_data_len = (path->def->payloadLen
2N/A -ITER_CONT_BYTE_LEN)/
2N/A path->def->iterationCount;
2N/A// zzz still have to figure out the bit offsets for bit iterations...
2N/A offset = getIterationOffset(cur, curLen, path,
2N/A &iterThere, &rc,
2N/A onlyFindingIterThereFlag);
2N/A if (offset == -1)
2N/A return (rc);
2N/A
2N/A // done
2N/A if (onlyFindingIterThereFlag) {
2N/A *dataLen = iterThere;
2N/A return (FRU_SUCCESS);
2N/A }
2N/A } else {
2N/A // done but this thing was not an iteration!!!
2N/A if (onlyFindingIterThereFlag) {
2N/A return (FRU_INVALPATH);
2N/A }
2N/A
2N/A calc_data_len = path->def->payloadLen;
2N/A offset = 0;
2N/A }
2N/A // end zzz
2N/A
2N/A // now make sure we have a field.
2N/A if (path->def->dataType == FDTYPE_Record) {
2N/A return (FRU_NOTFIELD);
2N/A }
2N/A
2N/A // allocate and copy.
2N/A if (path->def->dataType == FDTYPE_Binary) {
2N/A uint64_t *eData = (uint64_t *)malloc(sizeof (*eData));
2N/A if (eData == NULL) {
2N/A return (FRU_FAILURE);
2N/A }
2N/A
2N/A int bitLength = path->def->dataLength;
2N/A // iterated bit field adjust acordingly.
2N/A if (IS_ITERATED(path)) {
2N/A bitLength = (bitLength-(ITER_CONT_BYTE_LEN*8))/
2N/A path->def->iterationCount;
2N/A }
2N/A
2N/A rc = readBits(bitLength, &(cur[offset]),
2N/A calc_data_len, 0, eData);
2N/A if (rc != FRU_SUCCESS) {
2N/A free(eData);
2N/A return (rc);
2N/A }
2N/A *data = (void *)eData;
2N/A *dataLen = sizeof (*eData);
2N/A } else if (path->def->dataType == FDTYPE_Enumeration) {
2N/A unsigned char *eData
2N/A = (unsigned char *)malloc(sizeof (uint64_t));
2N/A if (eData == NULL) {
2N/A return (FRU_FAILURE);
2N/A }
2N/A /* copy the correct number of bytes to eData */
2N/A memset(eData, 0x00, sizeof (uint64_t));
2N/A memcpy(&(eData[(sizeof (uint64_t) - (calc_data_len))]),
2N/A &(cur[offset]),
2N/A (calc_data_len));
2N/A *data = (void*)eData;
2N/A *dataLen = sizeof (uint64_t);
2N/A } else {
2N/A void *rc_data = malloc(calc_data_len);
2N/A if (rc_data == NULL) {
2N/A return (FRU_FAILURE);
2N/A }
2N/A memcpy(rc_data, &(cur[offset]), calc_data_len);
2N/A *data = rc_data;
2N/A *dataLen = calc_data_len;
2N/A }
2N/A
2N/A return (FRU_SUCCESS);
2N/A }
2N/A
2N/A // At this point we know the entry is some sort of record.
2N/A
2N/A int newOffset = 0, newLength = 0;
2N/A if (IS_ITERATED(path)) {
2N/A
2N/A// zzz still have to figure out the bit offsets for bit iterations...
2N/A newOffset = getIterationOffset(cur, curLen,
2N/A path, NULL, &rc, NORMAL_READ);
2N/A if (newOffset == -1)
2N/A return (rc);
2N/A }
2N/A
2N/A newOffset += getOffsetIntoRecord(path->def, path->next->def);
2N/A newLength = path->next->def->payloadLen;
2N/A
2N/A return (readRecurse(path->next, &(cur[newOffset]), newLength,
2N/A data, dataLen, onlyFindingIterThereFlag));
2N/A}
2N/A
2N/A// ===========================================================================
2N/A// will send the data back in (data,dataLen)
2N/Afru_errno_t
2N/APayloadReader::readData(PathDef *path, Ancestor *curDef,
2N/A int instWICur,
2N/A uint8_t *payload, size_t payloadLen,
2N/A void **data, size_t *dataLen)
2N/A{
2N/A int offset = curDef->getInstOffset(instWICur);
2N/A return (readRecurse(path, &(payload[offset]), payloadLen-offset,
2N/A data, dataLen, NORMAL_READ));
2N/A}
2N/A
2N/A// ===========================================================================
2N/Afru_errno_t
2N/APayloadReader::findIterThere(PathDef *path, Ancestor *curDef,
2N/A int instWICur,
2N/A uint8_t *payload, size_t payloadLen,
2N/A int *numThere)
2N/A{
2N/A int offset = curDef->getInstOffset(instWICur);
2N/A size_t tmp_num = 0;
2N/A fru_errno_t err = readRecurse(path, &(payload[offset]),
2N/A payloadLen-offset, NULL, &tmp_num, ITER_THERE_ONLY);
2N/A
2N/A if (err == FRU_SUCCESS) {
2N/A int tmp_num_there = (int)tmp_num;
2N/A if (tmp_num_there != tmp_num) {
2N/A return (FRU_FAILURE);
2N/A }
2N/A *numThere = tmp_num_there;
2N/A }
2N/A return (err);
2N/A}
2N/A
2N/Astatic fru_errno_t
2N/Aupdate_iter_cont_bytes(PathDef *path, uint8_t *cur, size_t curLen)
2N/A{
2N/A // update the iteration control information
2N/A uint8_t *head = &(cur[0]);
2N/A uint8_t *tail = &(cur[1]);
2N/A uint8_t *numThere = &(cur[2]);
2N/A // This never changes.
2N/A uint8_t numPoss = cur[3];
2N/A
2N/A if (numPoss != path->def->iterationCount) {
2N/A return (FRU_DATACORRUPT);
2N/A }
2N/A
2N/A // Remember that when the iteration is added the head and the tail both
2N/A // equal 0 (ie point to 0). So if we are empty when we are updating
2N/A // then we don't have to alter the head or tail values. We simply add
2N/A // one to the numThere.
2N/A if (*numThere != 0) {
2N/A switch (path->def->iterationType) {
2N/A case FRU_Linear:
2N/A // this will flag an error when Linear can't
2N/A // hold anymore.
2N/A if ((*tail + 1) == numPoss)
2N/A return (FRU_ITERFULL);
2N/A /* Fall through */
2N/A case FRU_FIFO:
2N/A // if we are not at the end move the tail.
2N/A if (*tail != (numPoss-1))
2N/A *tail = *tail+1;
2N/A break;
2N/A
2N/A case FRU_Circular:
2N/A case FRU_LIFO:
2N/A // this is the same except LIFO is read
2N/A // BACKWARDS
2N/A
2N/A // move the tail.
2N/A *tail = *tail + 1;
2N/A // if the tail hits the end wrap around.
2N/A if (*tail == numPoss)
2N/A *tail = 0;
2N/A // if tail catches head move the head.
2N/A if (*tail == *head) {
2N/A // if head hits the end wrap around.
2N/A if (++(*head) == numPoss)
2N/A *head = 0;
2N/A }
2N/A break;
2N/A }
2N/A }
2N/A if ((*numThere) < numPoss) {
2N/A // add one IFF we are not full
2N/A *numThere = *numThere + 1;
2N/A }
2N/A
2N/A return (FRU_SUCCESS);
2N/A}
2N/A
2N/A// ===========================================================================
2N/Afru_errno_t
2N/APayloadReader::updateRecurse(PathDef *path,
2N/A uint8_t *cur, size_t curLen,
2N/A void *data, size_t dataLen)
2N/A{
2N/A fru_errno_t rc = FRU_SUCCESS;
2N/A
2N/A if (path->next == NULL) {
2N/A
2N/A // Delay checking for Records until after this which will
2N/A // allow for [+] notation for Iterated Records.
2N/A // if this is updating an iteration AND we are adding one...
2N/A if (IS_ITERATED(path) &&
2N/A (path->iterIndex == PathDef::addIteration)) {
2N/A return (update_iter_cont_bytes(path, cur, curLen));
2N/A }
2N/A
2N/A if (path->def->dataType == FDTYPE_Record) {
2N/A return (FRU_NOTFIELD);
2N/A }
2N/A
2N/A int offset = 0;
2N/A int calcLen = 0;
2N/A int dummy = 0;
2N/A // zzz altering the length things again...
2N/A if (IS_ITERATED(path)) {
2N/A // we are iterated.
2N/A calcLen = (path->def->payloadLen-ITER_CONT_BYTE_LEN)/
2N/A path->def->iterationCount;
2N/A// zzz still have to figure out the bit offsets
2N/A offset = getIterationOffset(cur, curLen,
2N/A path, &dummy, &rc, NORMAL_READ);
2N/A if (offset == -1)
2N/A return (rc);
2N/A } else {
2N/A calcLen = path->def->payloadLen;
2N/A offset = 0;
2N/A }
2N/A // end zzz
2N/A
2N/A // once again convert enums for the user again.
2N/A if (path->def->dataType == FDTYPE_Binary) {
2N/A int bitLength = path->def->dataLength;
2N/A // iterated bit field adjust acordingly.
2N/A if (path->def->iterationType != FRU_NOT_ITERATED) {
2N/A bitLength = (bitLength - 32)/
2N/A path->def->iterationCount;
2N/A }
2N/A
2N/A rc = writeBits (*(uint64_t *)data, bitLength,
2N/A &(cur[offset]), calcLen, 0);
2N/A if (rc != FRU_SUCCESS)
2N/A return (rc);
2N/A } else if (path->def->dataType == FDTYPE_Enumeration) {
2N/A unsigned char *tmp = (unsigned char *)data;
2N/A memcpy(&(cur[offset]),
2N/A &(tmp[(sizeof (uint64_t) - (calcLen))]),
2N/A calcLen);
2N/A } else {
2N/A // copy into and return.
2N/A memcpy(&(cur[offset]), data, dataLen);
2N/A }
2N/A
2N/A return (FRU_SUCCESS);
2N/A }
2N/A
2N/A int newOffset = 0, newLength = 0;
2N/A int dummy = 0;
2N/A if (path->def->iterationType != FRU_NOT_ITERATED) {
2N/A
2N/A// zzz still have to figure out the bit offsets
2N/A newOffset = getIterationOffset(cur, curLen, path,
2N/A &dummy, &rc, NORMAL_READ);
2N/A if (newOffset == -1)
2N/A return (rc);
2N/A }
2N/A newOffset += getOffsetIntoRecord(path->def, path->next->def);
2N/A newLength = path->next->def->payloadLen;
2N/A
2N/A return (updateRecurse(path->next, &(cur[newOffset]), newLength,
2N/A data, dataLen));
2N/A}
2N/A
2N/A// ===========================================================================
2N/A// will update the data in payload which can then be written back.
2N/Afru_errno_t
2N/APayloadReader::updateData(PathDef *path, Ancestor *ancestorDef,
2N/A int instWICur,
2N/A uint8_t *payload, size_t payloadLen,
2N/A void *data, size_t dataLen)
2N/A{
2N/A // verify the user data first before doing any major work.
2N/A int calcLen = 0;
2N/A PathDef *prev = path;
2N/A PathDef *cur = path;
2N/A while (cur != NULL) {
2N/A prev = cur;
2N/A cur = cur->next;
2N/A }
2N/A
2N/A // unless we are updateing with [+] symbol
2N/A // (which means we don't have any data length at all.)
2N/A if (prev->iterIndex != PathDef::addIteration) {
2N/A if (IS_ITERATED(prev)) {
2N/A calcLen = (prev->def->payloadLen-ITER_CONT_BYTE_LEN)/
2N/A prev->def->iterationCount;
2N/A } else {
2N/A calcLen = prev->def->payloadLen;
2N/A }
2N/A // the sizeof the data for Binary or Enumeration MUST
2N/A // be uint64_t
2N/A if ((prev->def->dataType == FDTYPE_Enumeration) ||
2N/A (prev->def->dataType == FDTYPE_Binary)) {
2N/A if (dataLen != sizeof (uint64_t))
2N/A return (FRU_INVALDATASIZE);
2N/A // all others must be shorter than the space available.
2N/A } else {
2N/A if (dataLen > calcLen)
2N/A return (FRU_INVALDATASIZE);
2N/A }
2N/A }
2N/A
2N/A int offset = ancestorDef->getInstOffset(instWICur);
2N/A return (updateRecurse(path, &(payload[offset]), payloadLen-offset,
2N/A data, dataLen));
2N/A}