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.
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.
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]
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
31 #include "PayloadReader.h"
33 #define ITER_CONT_BYTE_LEN 4
34 #define IS_ITERATED(pathDef) \
35 (pathDef->def->iterationType != FRU_NOT_ITERATED)
37 // functions to place bit data properly.
39 writeBits(uint64_t bitData
, size_t bitLength
,
40 uint8_t *data
, size_t dataLength
, size_t bitOffset
)
42 if ((bitLength
> 64) &&
45 (bitOffset
> (dataLength
* 8)))
47 // move the bit data into place
48 bitData
= (bitData
<< (64-bitLength
));
49 bitData
= (bitData
>> bitOffset
);
51 // create a mask to clear the old data.
53 for (size_t i
= 0; i
< bitLength
; i
++) {
54 mask
= ((mask
<< 1) + 1);
56 mask
= (mask
<< (64-bitLength
));
57 mask
= (mask
>> bitOffset
);
58 mask
= (mask
^ 0xFFFFFFFFFFFFFFFFULL
);
60 // get the data out of the byte array.
62 memcpy((void *)&rd
, (void *)data
, dataLength
);
66 // put in the new data.
69 // write the data back to the buffer.
70 memcpy((void *)data
, (void *)&rd
, dataLength
);
75 readBits(size_t bitLength
, uint8_t *data
,
76 size_t dataLength
, int bitOffset
, uint64_t *ret
)
78 if ((bitLength
> 64) ||
82 (bitOffset
> (dataLength
* 8)))
84 // get the data out of the byte array.
86 memcpy((void *)&rc
, (void *)data
, dataLength
);
88 rc
= (rc
<< bitOffset
);
89 rc
= (rc
>> (64 - bitLength
));
94 // ===========================================================================
95 // caller is to be sure elemDef is contained by recDef.
97 PayloadReader::getOffsetIntoRecord(fru_regdef_t
*recDef
,
98 fru_regdef_t
*elemDef
)
101 for (int i
= 0; i
< recDef
->enumCount
; i
++) {
102 if (strcmp(recDef
->enumTable
[i
].text
, elemDef
->name
) == 0)
104 const fru_regdef_t
*tmpDef
= fru_reg_lookup_def_by_name(
105 (char *)recDef
->enumTable
[i
].text
);
106 rc
+= tmpDef
->payloadLen
;
111 // ===========================================================================
112 // return -1 on error.
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
,
125 if (index
== PathDef::lastIteration
)
126 return (length
* tail
);
127 return (length
* index
);
133 if (index
== PathDef::lastIteration
) {
134 if (iterType
== FRU_LIFO
)
135 return (length
* head
);
136 return (length
* tail
);
139 // For reading they are oposite.
140 if (iterType
== FRU_Circular
) {
141 return (length
* ((head
+ index
) % iterPoss
));
143 int abs
= tail
- index
;
145 // abs is negative here
146 abs
= iterPoss
+ abs
;
147 return (length
* abs
);
156 // ===========================================================================
157 // return -1 on error.
159 PayloadReader::getIterationOffset(uint8_t *iter
, int iterLen
,
160 PathDef
*path
, int *rcIterThere
,
162 int onlyFindingIterThereFlag
)
166 // read the iteration control bytes first because we may ONLY need
168 uint8_t head
= iter
[0];
169 uint8_t tail
= iter
[1];
170 uint8_t iterThere
= iter
[2];
171 uint8_t iterPoss
= iter
[3];
173 // the '+' symbol on anything is an error here
174 if (path
->iterIndex
== PathDef::addIteration
) {
175 *err
= FRU_INVALPATH
;
179 // check assumptions for next calls.
180 if (iterPoss
!= path
->def
->iterationCount
) {
181 *err
= FRU_DATACORRUPT
;
185 if (onlyFindingIterThereFlag
== ITER_THERE_ONLY
) {
186 if (rcIterThere
!= NULL
) {
187 *rcIterThere
= iterThere
;
190 return (ITER_CONT_BYTE_LEN
);
193 if ((path
->iterIndex
!= PathDef::addIteration
) &&
194 (path
->iterIndex
!= PathDef::lastIteration
) &&
195 (path
->iterIndex
>= iterThere
)) {
196 *err
= FRU_DATANOTFOUND
;
200 // don't forget to skip the iteration control bytes!!!
201 int length
= ((path
->def
->payloadLen
- ITER_CONT_BYTE_LEN
)
202 /path
->def
->iterationCount
);
204 rc
= calcOffset(path
->def
->iterationType
,
205 head
, tail
, iterThere
, iterPoss
,
206 length
, path
->iterIndex
, err
);
208 // error set by calcOffset
213 return (ITER_CONT_BYTE_LEN
+ rc
);
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.
220 PayloadReader::readRecurse(PathDef
*path
,
221 uint8_t *cur
, size_t curLen
,
222 void **data
, size_t *dataLen
,
223 int onlyFindingIterThereFlag
)
225 fru_errno_t rc
= FRU_SUCCESS
;
226 size_t calc_data_len
= 0;
228 if (path
->next
== NULL
) {
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.
235 // zzz altering the length things again...
236 if (IS_ITERATED(path
)) {
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
,
244 onlyFindingIterThereFlag
);
249 if (onlyFindingIterThereFlag
) {
250 *dataLen
= iterThere
;
251 return (FRU_SUCCESS
);
254 // done but this thing was not an iteration!!!
255 if (onlyFindingIterThereFlag
) {
256 return (FRU_INVALPATH
);
259 calc_data_len
= path
->def
->payloadLen
;
264 // now make sure we have a field.
265 if (path
->def
->dataType
== FDTYPE_Record
) {
266 return (FRU_NOTFIELD
);
269 // allocate and copy.
270 if (path
->def
->dataType
== FDTYPE_Binary
) {
271 uint64_t *eData
= (uint64_t *)malloc(sizeof (*eData
));
273 return (FRU_FAILURE
);
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
;
283 rc
= readBits(bitLength
, &(cur
[offset
]),
284 calc_data_len
, 0, eData
);
285 if (rc
!= FRU_SUCCESS
) {
289 *data
= (void *)eData
;
290 *dataLen
= sizeof (*eData
);
291 } else if (path
->def
->dataType
== FDTYPE_Enumeration
) {
293 = (unsigned char *)malloc(sizeof (uint64_t));
295 return (FRU_FAILURE
);
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
))]),
302 *data
= (void*)eData
;
303 *dataLen
= sizeof (uint64_t);
305 void *rc_data
= malloc(calc_data_len
);
306 if (rc_data
== NULL
) {
307 return (FRU_FAILURE
);
309 memcpy(rc_data
, &(cur
[offset
]), calc_data_len
);
311 *dataLen
= calc_data_len
;
314 return (FRU_SUCCESS
);
317 // At this point we know the entry is some sort of record.
319 int newOffset
= 0, newLength
= 0;
320 if (IS_ITERATED(path
)) {
322 // zzz still have to figure out the bit offsets for bit iterations...
323 newOffset
= getIterationOffset(cur
, curLen
,
324 path
, NULL
, &rc
, NORMAL_READ
);
329 newOffset
+= getOffsetIntoRecord(path
->def
, path
->next
->def
);
330 newLength
= path
->next
->def
->payloadLen
;
332 return (readRecurse(path
->next
, &(cur
[newOffset
]), newLength
,
333 data
, dataLen
, onlyFindingIterThereFlag
));
336 // ===========================================================================
337 // will send the data back in (data,dataLen)
339 PayloadReader::readData(PathDef
*path
, Ancestor
*curDef
,
341 uint8_t *payload
, size_t payloadLen
,
342 void **data
, size_t *dataLen
)
344 int offset
= curDef
->getInstOffset(instWICur
);
345 return (readRecurse(path
, &(payload
[offset
]), payloadLen
-offset
,
346 data
, dataLen
, NORMAL_READ
));
349 // ===========================================================================
351 PayloadReader::findIterThere(PathDef
*path
, Ancestor
*curDef
,
353 uint8_t *payload
, size_t payloadLen
,
356 int offset
= curDef
->getInstOffset(instWICur
);
358 fru_errno_t err
= readRecurse(path
, &(payload
[offset
]),
359 payloadLen
-offset
, NULL
, &tmp_num
, ITER_THERE_ONLY
);
361 if (err
== FRU_SUCCESS
) {
362 int tmp_num_there
= (int)tmp_num
;
363 if (tmp_num_there
!= tmp_num
) {
364 return (FRU_FAILURE
);
366 *numThere
= tmp_num_there
;
372 update_iter_cont_bytes(PathDef
*path
, uint8_t *cur
, size_t curLen
)
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];
381 if (numPoss
!= path
->def
->iterationCount
) {
382 return (FRU_DATACORRUPT
);
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
) {
392 // this will flag an error when Linear can't
394 if ((*tail
+ 1) == numPoss
)
395 return (FRU_ITERFULL
);
398 // if we are not at the end move the tail.
399 if (*tail
!= (numPoss
-1))
405 // this is the same except LIFO is read
410 // if the tail hits the end wrap around.
411 if (*tail
== numPoss
)
413 // if tail catches head move the head.
414 if (*tail
== *head
) {
415 // if head hits the end wrap around.
416 if (++(*head
) == numPoss
)
422 if ((*numThere
) < numPoss
) {
423 // add one IFF we are not full
424 *numThere
= *numThere
+ 1;
427 return (FRU_SUCCESS
);
430 // ===========================================================================
432 PayloadReader::updateRecurse(PathDef
*path
,
433 uint8_t *cur
, size_t curLen
,
434 void *data
, size_t dataLen
)
436 fru_errno_t rc
= FRU_SUCCESS
;
438 if (path
->next
== NULL
) {
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
));
448 if (path
->def
->dataType
== FDTYPE_Record
) {
449 return (FRU_NOTFIELD
);
455 // zzz altering the length things again...
456 if (IS_ITERATED(path
)) {
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
);
466 calcLen
= path
->def
->payloadLen
;
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
;
480 rc
= writeBits (*(uint64_t *)data
, bitLength
,
481 &(cur
[offset
]), calcLen
, 0);
482 if (rc
!= FRU_SUCCESS
)
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
))]),
490 // copy into and return.
491 memcpy(&(cur
[offset
]), data
, dataLen
);
494 return (FRU_SUCCESS
);
497 int newOffset
= 0, newLength
= 0;
499 if (path
->def
->iterationType
!= FRU_NOT_ITERATED
) {
501 // zzz still have to figure out the bit offsets
502 newOffset
= getIterationOffset(cur
, curLen
, path
,
503 &dummy
, &rc
, NORMAL_READ
);
507 newOffset
+= getOffsetIntoRecord(path
->def
, path
->next
->def
);
508 newLength
= path
->next
->def
->payloadLen
;
510 return (updateRecurse(path
->next
, &(cur
[newOffset
]), newLength
,
514 // ===========================================================================
515 // will update the data in payload which can then be written back.
517 PayloadReader::updateData(PathDef
*path
, Ancestor
*ancestorDef
,
519 uint8_t *payload
, size_t payloadLen
,
520 void *data
, size_t dataLen
)
522 // verify the user data first before doing any major work.
524 PathDef
*prev
= path
;
526 while (cur
!= NULL
) {
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
;
538 calcLen
= prev
->def
->payloadLen
;
540 // the sizeof the data for Binary or Enumeration MUST
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.
548 if (dataLen
> calcLen
)
549 return (FRU_INVALDATASIZE
);
553 int offset
= ancestorDef
->getInstOffset(instWICur
);
554 return (updateRecurse(path
, &(payload
[offset
]), payloadLen
-offset
,