xref: /openbmc/entity-manager/src/fru_reader.cpp (revision b7077437d4a6b2cc935e1ba8d71f365ed324eb41)
1309c0b13SZev Weiss /*
2309c0b13SZev Weiss // Copyright (c) 2022 Equinix, Inc.
3309c0b13SZev Weiss //
4309c0b13SZev Weiss // Licensed under the Apache License, Version 2.0 (the "License");
5309c0b13SZev Weiss // you may not use this file except in compliance with the License.
6309c0b13SZev Weiss // You may obtain a copy of the License at
7309c0b13SZev Weiss //
8309c0b13SZev Weiss //      http://www.apache.org/licenses/LICENSE-2.0
9309c0b13SZev Weiss //
10309c0b13SZev Weiss // Unless required by applicable law or agreed to in writing, software
11309c0b13SZev Weiss // distributed under the License is distributed on an "AS IS" BASIS,
12309c0b13SZev Weiss // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13309c0b13SZev Weiss // See the License for the specific language governing permissions and
14309c0b13SZev Weiss // limitations under the License.
15309c0b13SZev Weiss */
16309c0b13SZev Weiss 
17309c0b13SZev Weiss #include "fru_reader.hpp"
18309c0b13SZev Weiss 
19309c0b13SZev Weiss #include <cstring>
20309c0b13SZev Weiss 
read(off_t start,size_t len,uint8_t * outbuf)21309c0b13SZev Weiss ssize_t FRUReader::read(off_t start, size_t len, uint8_t* outbuf)
22309c0b13SZev Weiss {
23309c0b13SZev Weiss     size_t done = 0;
24309c0b13SZev Weiss     size_t remaining = len;
25309c0b13SZev Weiss     size_t cursor = start;
26309c0b13SZev Weiss     while (done < len)
27309c0b13SZev Weiss     {
28309c0b13SZev Weiss         if (eof.has_value() && cursor >= eof.value())
29309c0b13SZev Weiss         {
30309c0b13SZev Weiss             break;
31309c0b13SZev Weiss         }
32309c0b13SZev Weiss 
333013fb49SEd Tanous         const uint8_t* blkData = nullptr;
343013fb49SEd Tanous         size_t available = 0;
35309c0b13SZev Weiss         size_t blk = cursor / cacheBlockSize;
36309c0b13SZev Weiss         size_t blkOffset = cursor % cacheBlockSize;
37309c0b13SZev Weiss         auto findBlk = cache.find(blk);
38309c0b13SZev Weiss         if (findBlk == cache.end())
39309c0b13SZev Weiss         {
40309c0b13SZev Weiss             // miss, populate cache
41309c0b13SZev Weiss             uint8_t* newData = cache[blk].data();
42*b7077437SPatrick Williams             int64_t ret =
43*b7077437SPatrick Williams                 readFunc(blk * cacheBlockSize, cacheBlockSize, newData);
44309c0b13SZev Weiss 
45309c0b13SZev Weiss             // if we've reached the end of the eeprom, record its size
46309c0b13SZev Weiss             if (ret >= 0 && static_cast<size_t>(ret) < cacheBlockSize)
47309c0b13SZev Weiss             {
48309c0b13SZev Weiss                 eof = (blk * cacheBlockSize) + ret;
49309c0b13SZev Weiss             }
50309c0b13SZev Weiss 
51309c0b13SZev Weiss             if (ret <= 0)
52309c0b13SZev Weiss             {
53309c0b13SZev Weiss                 // don't leave empty blocks in the cache
54309c0b13SZev Weiss                 cache.erase(blk);
553013fb49SEd Tanous                 return done != 0U ? done : ret;
56309c0b13SZev Weiss             }
57309c0b13SZev Weiss 
58309c0b13SZev Weiss             blkData = newData;
59309c0b13SZev Weiss             available = ret;
60309c0b13SZev Weiss         }
61309c0b13SZev Weiss         else
62309c0b13SZev Weiss         {
63309c0b13SZev Weiss             // hit, use cached data
64309c0b13SZev Weiss             blkData = findBlk->second.data();
65309c0b13SZev Weiss 
66309c0b13SZev Weiss             // if the hit is to the block containing the (previously
67309c0b13SZev Weiss             // discovered on the miss that populated it) end of the eeprom,
68309c0b13SZev Weiss             // don't copy spurious bytes past the end
69309c0b13SZev Weiss             if (eof.has_value() && (eof.value() / cacheBlockSize == blk))
70309c0b13SZev Weiss             {
71309c0b13SZev Weiss                 available = eof.value() % cacheBlockSize;
72309c0b13SZev Weiss             }
73309c0b13SZev Weiss             else
74309c0b13SZev Weiss             {
75309c0b13SZev Weiss                 available = cacheBlockSize;
76309c0b13SZev Weiss             }
77309c0b13SZev Weiss         }
78309c0b13SZev Weiss 
79309c0b13SZev Weiss         size_t toCopy = (blkOffset >= available)
80309c0b13SZev Weiss                             ? 0
81309c0b13SZev Weiss                             : std::min(available - blkOffset, remaining);
82309c0b13SZev Weiss 
833013fb49SEd Tanous         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
84309c0b13SZev Weiss         memcpy(outbuf + done, blkData + blkOffset, toCopy);
85309c0b13SZev Weiss         cursor += toCopy;
86309c0b13SZev Weiss         done += toCopy;
87309c0b13SZev Weiss         remaining -= toCopy;
88309c0b13SZev Weiss     }
89309c0b13SZev Weiss 
90309c0b13SZev Weiss     return done;
91309c0b13SZev Weiss }
92