xref: /openbmc/google-ipmi-sys/cpld.cpp (revision fff98617)
14d49ae65SPatrick Venture /*
24d49ae65SPatrick Venture  * Copyright 2018 Google Inc.
34d49ae65SPatrick Venture  *
44d49ae65SPatrick Venture  * Licensed under the Apache License, Version 2.0 (the "License");
54d49ae65SPatrick Venture  * you may not use this file except in compliance with the License.
64d49ae65SPatrick Venture  * You may obtain a copy of the License at
74d49ae65SPatrick Venture  *
84d49ae65SPatrick Venture  *     http://www.apache.org/licenses/LICENSE-2.0
94d49ae65SPatrick Venture  *
104d49ae65SPatrick Venture  * Unless required by applicable law or agreed to in writing, software
114d49ae65SPatrick Venture  * distributed under the License is distributed on an "AS IS" BASIS,
124d49ae65SPatrick Venture  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134d49ae65SPatrick Venture  * See the License for the specific language governing permissions and
144d49ae65SPatrick Venture  * limitations under the License.
154d49ae65SPatrick Venture  */
164d49ae65SPatrick Venture 
174d49ae65SPatrick Venture #include "cpld.hpp"
184d49ae65SPatrick Venture 
194d49ae65SPatrick Venture #include "main.hpp"
204d49ae65SPatrick Venture 
21ce07ee0aSPatrick Venture #include <cstring>
224d49ae65SPatrick Venture #include <experimental/filesystem>
234d49ae65SPatrick Venture #include <fstream>
244d49ae65SPatrick Venture #include <sstream>
254d49ae65SPatrick Venture 
264d49ae65SPatrick Venture namespace google
274d49ae65SPatrick Venture {
284d49ae65SPatrick Venture namespace ipmi
294d49ae65SPatrick Venture {
304d49ae65SPatrick Venture namespace fs = std::experimental::filesystem;
314d49ae65SPatrick Venture 
324d49ae65SPatrick Venture struct CpldRequest
334d49ae65SPatrick Venture {
344d49ae65SPatrick Venture     uint8_t subcommand;
354d49ae65SPatrick Venture     uint8_t id;
364d49ae65SPatrick Venture } __attribute__((packed));
374d49ae65SPatrick Venture 
384d49ae65SPatrick Venture struct CpldReply
394d49ae65SPatrick Venture {
404d49ae65SPatrick Venture     uint8_t subcommand;
414d49ae65SPatrick Venture     uint8_t major;
424d49ae65SPatrick Venture     uint8_t minor;
434d49ae65SPatrick Venture     uint8_t point;
444d49ae65SPatrick Venture     uint8_t subpoint;
454d49ae65SPatrick Venture } __attribute__((packed));
464d49ae65SPatrick Venture 
474d49ae65SPatrick Venture //
484d49ae65SPatrick Venture // Handle reading the cpld version from the tmpfs.
494d49ae65SPatrick Venture //
504d49ae65SPatrick Venture ipmi_ret_t CpldVersion(const uint8_t* reqBuf, uint8_t* replyBuf,
514d49ae65SPatrick Venture                        size_t* dataLen)
524d49ae65SPatrick Venture {
53acd5423aSPatrick Venture     struct CpldRequest request;
54acd5423aSPatrick Venture 
55acd5423aSPatrick Venture     if ((*dataLen) < sizeof(request))
564d49ae65SPatrick Venture     {
57ce07ee0aSPatrick Venture         std::fprintf(stderr, "Invalid command length: %u\n",
580dede335SPatrick Venture                      static_cast<uint32_t>(*dataLen));
59*fff98617SPatrick Venture         return IPMI_CC_REQ_DATA_LEN_INVALID;
604d49ae65SPatrick Venture     }
614d49ae65SPatrick Venture 
624d49ae65SPatrick Venture     // reqBuf[0] is the subcommand.
634d49ae65SPatrick Venture     // reqBuf[1] is the CPLD id. "/run/cpld{id}.version" is what we read.
644d49ae65SPatrick Venture     // Verified that this cast actually returns the value 255 and not something
654d49ae65SPatrick Venture     // negative in the case where reqBuf[1] is 0xff.  However, it looks weird
664d49ae65SPatrick Venture     // since I would expect int(uint8(0xff)) to be -1.  So, just cast it
674d49ae65SPatrick Venture     // unsigned. we're casting to an int width to avoid it thinking it's a
684d49ae65SPatrick Venture     // letter, because it does that.
69acd5423aSPatrick Venture     std::memcpy(&request, &reqBuf[0], sizeof(request));
704d49ae65SPatrick Venture 
714d49ae65SPatrick Venture     std::ostringstream opath;
72acd5423aSPatrick Venture     opath << "/run/cpld" << static_cast<unsigned int>(request.id) << ".version";
734d49ae65SPatrick Venture     // Check for file
744d49ae65SPatrick Venture 
754d49ae65SPatrick Venture     std::error_code ec;
764d49ae65SPatrick Venture     if (!fs::exists(opath.str(), ec))
774d49ae65SPatrick Venture     {
78ce07ee0aSPatrick Venture         std::fprintf(stderr, "Path: '%s' doesn't exist.\n",
79ce07ee0aSPatrick Venture                      opath.str().c_str());
80*fff98617SPatrick Venture         return IPMI_CC_INVALID_FIELD_REQUEST;
814d49ae65SPatrick Venture     }
824d49ae65SPatrick Venture     // We're uninterested in the state of ec.
834d49ae65SPatrick Venture 
844d49ae65SPatrick Venture     // If file exists, read.
854d49ae65SPatrick Venture     std::ifstream ifs;
864d49ae65SPatrick Venture     ifs.exceptions(std::ifstream::failbit);
874d49ae65SPatrick Venture     std::string value;
884d49ae65SPatrick Venture     try
894d49ae65SPatrick Venture     {
904d49ae65SPatrick Venture         ifs.open(opath.str());
914d49ae65SPatrick Venture         ifs >> value;
924d49ae65SPatrick Venture     }
934d49ae65SPatrick Venture     catch (std::ios_base::failure& fail)
944d49ae65SPatrick Venture     {
95*fff98617SPatrick Venture         return IPMI_CC_UNSPECIFIED_ERROR;
964d49ae65SPatrick Venture     }
974d49ae65SPatrick Venture 
984d49ae65SPatrick Venture     // If value parses as expected, return version.
994d49ae65SPatrick Venture     int major = 0;
1004d49ae65SPatrick Venture     int minor = 0;
1014d49ae65SPatrick Venture     int point = 0;
1024d49ae65SPatrick Venture     int subpoint = 0;
1034d49ae65SPatrick Venture 
1044d49ae65SPatrick Venture     int num_fields =
1054d49ae65SPatrick Venture         sscanf(value.c_str(), "%d.%d.%d.%d", &major, &minor, &point, &subpoint);
1064d49ae65SPatrick Venture     if (num_fields == 0)
1074d49ae65SPatrick Venture     {
108ce07ee0aSPatrick Venture         std::fprintf(stderr, "Invalid version.\n");
109*fff98617SPatrick Venture         return IPMI_CC_UNSPECIFIED_ERROR;
1104d49ae65SPatrick Venture     }
1114d49ae65SPatrick Venture 
1124d49ae65SPatrick Venture     // Truncate if the version is too high (documented).
1134d49ae65SPatrick Venture     struct CpldReply reply;
1144d49ae65SPatrick Venture     reply.subcommand = SysCpldVersion;
1154d49ae65SPatrick Venture     reply.major = static_cast<uint8_t>(major);
1164d49ae65SPatrick Venture     reply.minor = static_cast<uint8_t>(minor);
1174d49ae65SPatrick Venture     reply.point = static_cast<uint8_t>(point);
1184d49ae65SPatrick Venture     reply.subpoint = static_cast<uint8_t>(subpoint);
1194d49ae65SPatrick Venture 
120acd5423aSPatrick Venture     std::memcpy(&replyBuf[0], &reply, sizeof(reply));
121acd5423aSPatrick Venture     (*dataLen) = sizeof(reply);
1224d49ae65SPatrick Venture 
1234d49ae65SPatrick Venture     return IPMI_CC_OK;
1244d49ae65SPatrick Venture }
1254d49ae65SPatrick Venture 
1264d49ae65SPatrick Venture } // namespace ipmi
1274d49ae65SPatrick Venture } // namespace google
128