xref: /openbmc/google-ipmi-sys/cpld.cpp (revision 4d49ae65)
1*4d49ae65SPatrick Venture /*
2*4d49ae65SPatrick Venture  * Copyright 2018 Google Inc.
3*4d49ae65SPatrick Venture  *
4*4d49ae65SPatrick Venture  * Licensed under the Apache License, Version 2.0 (the "License");
5*4d49ae65SPatrick Venture  * you may not use this file except in compliance with the License.
6*4d49ae65SPatrick Venture  * You may obtain a copy of the License at
7*4d49ae65SPatrick Venture  *
8*4d49ae65SPatrick Venture  *     http://www.apache.org/licenses/LICENSE-2.0
9*4d49ae65SPatrick Venture  *
10*4d49ae65SPatrick Venture  * Unless required by applicable law or agreed to in writing, software
11*4d49ae65SPatrick Venture  * distributed under the License is distributed on an "AS IS" BASIS,
12*4d49ae65SPatrick Venture  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*4d49ae65SPatrick Venture  * See the License for the specific language governing permissions and
14*4d49ae65SPatrick Venture  * limitations under the License.
15*4d49ae65SPatrick Venture  */
16*4d49ae65SPatrick Venture 
17*4d49ae65SPatrick Venture #include "cpld.hpp"
18*4d49ae65SPatrick Venture 
19*4d49ae65SPatrick Venture #include "main.hpp"
20*4d49ae65SPatrick Venture 
21*4d49ae65SPatrick Venture #include <experimental/filesystem>
22*4d49ae65SPatrick Venture #include <fstream>
23*4d49ae65SPatrick Venture #include <sstream>
24*4d49ae65SPatrick Venture 
25*4d49ae65SPatrick Venture namespace google
26*4d49ae65SPatrick Venture {
27*4d49ae65SPatrick Venture namespace ipmi
28*4d49ae65SPatrick Venture {
29*4d49ae65SPatrick Venture namespace fs = std::experimental::filesystem;
30*4d49ae65SPatrick Venture 
31*4d49ae65SPatrick Venture struct CpldRequest
32*4d49ae65SPatrick Venture {
33*4d49ae65SPatrick Venture     uint8_t subcommand;
34*4d49ae65SPatrick Venture     uint8_t id;
35*4d49ae65SPatrick Venture } __attribute__((packed));
36*4d49ae65SPatrick Venture 
37*4d49ae65SPatrick Venture struct CpldReply
38*4d49ae65SPatrick Venture {
39*4d49ae65SPatrick Venture     uint8_t subcommand;
40*4d49ae65SPatrick Venture     uint8_t major;
41*4d49ae65SPatrick Venture     uint8_t minor;
42*4d49ae65SPatrick Venture     uint8_t point;
43*4d49ae65SPatrick Venture     uint8_t subpoint;
44*4d49ae65SPatrick Venture } __attribute__((packed));
45*4d49ae65SPatrick Venture 
46*4d49ae65SPatrick Venture //
47*4d49ae65SPatrick Venture // Handle reading the cpld version from the tmpfs.
48*4d49ae65SPatrick Venture //
49*4d49ae65SPatrick Venture ipmi_ret_t CpldVersion(const uint8_t* reqBuf, uint8_t* replyBuf,
50*4d49ae65SPatrick Venture                        size_t* dataLen)
51*4d49ae65SPatrick Venture {
52*4d49ae65SPatrick Venture     if ((*dataLen) < sizeof(struct CpldRequest))
53*4d49ae65SPatrick Venture     {
54*4d49ae65SPatrick Venture         fprintf(stderr, "Invalid command length: %lu\n", (*dataLen));
55*4d49ae65SPatrick Venture         return IPMI_CC_INVALID;
56*4d49ae65SPatrick Venture     }
57*4d49ae65SPatrick Venture 
58*4d49ae65SPatrick Venture     // reqBuf[0] is the subcommand.
59*4d49ae65SPatrick Venture     // reqBuf[1] is the CPLD id. "/run/cpld{id}.version" is what we read.
60*4d49ae65SPatrick Venture     // Verified that this cast actually returns the value 255 and not something
61*4d49ae65SPatrick Venture     // negative in the case where reqBuf[1] is 0xff.  However, it looks weird
62*4d49ae65SPatrick Venture     // since I would expect int(uint8(0xff)) to be -1.  So, just cast it
63*4d49ae65SPatrick Venture     // unsigned. we're casting to an int width to avoid it thinking it's a
64*4d49ae65SPatrick Venture     // letter, because it does that.
65*4d49ae65SPatrick Venture 
66*4d49ae65SPatrick Venture     const auto request =
67*4d49ae65SPatrick Venture         reinterpret_cast<const struct CpldRequest*>(&reqBuf[0]);
68*4d49ae65SPatrick Venture 
69*4d49ae65SPatrick Venture     std::ostringstream opath;
70*4d49ae65SPatrick Venture     opath << "/run/cpld" << static_cast<unsigned int>(request->id)
71*4d49ae65SPatrick Venture           << ".version";
72*4d49ae65SPatrick Venture     // Check for file
73*4d49ae65SPatrick Venture 
74*4d49ae65SPatrick Venture     std::error_code ec;
75*4d49ae65SPatrick Venture     if (!fs::exists(opath.str(), ec))
76*4d49ae65SPatrick Venture     {
77*4d49ae65SPatrick Venture         fprintf(stderr, "Path: '%s' doesn't exist.\n", opath.str().c_str());
78*4d49ae65SPatrick Venture         return IPMI_CC_INVALID;
79*4d49ae65SPatrick Venture     }
80*4d49ae65SPatrick Venture     // We're uninterested in the state of ec.
81*4d49ae65SPatrick Venture 
82*4d49ae65SPatrick Venture     // If file exists, read.
83*4d49ae65SPatrick Venture     std::ifstream ifs;
84*4d49ae65SPatrick Venture     ifs.exceptions(std::ifstream::failbit);
85*4d49ae65SPatrick Venture     std::string value;
86*4d49ae65SPatrick Venture     try
87*4d49ae65SPatrick Venture     {
88*4d49ae65SPatrick Venture         ifs.open(opath.str());
89*4d49ae65SPatrick Venture         ifs >> value;
90*4d49ae65SPatrick Venture     }
91*4d49ae65SPatrick Venture     catch (std::ios_base::failure& fail)
92*4d49ae65SPatrick Venture     {
93*4d49ae65SPatrick Venture         return IPMI_CC_INVALID;
94*4d49ae65SPatrick Venture     }
95*4d49ae65SPatrick Venture 
96*4d49ae65SPatrick Venture     // If value parses as expected, return version.
97*4d49ae65SPatrick Venture     int major = 0;
98*4d49ae65SPatrick Venture     int minor = 0;
99*4d49ae65SPatrick Venture     int point = 0;
100*4d49ae65SPatrick Venture     int subpoint = 0;
101*4d49ae65SPatrick Venture 
102*4d49ae65SPatrick Venture     int num_fields =
103*4d49ae65SPatrick Venture         sscanf(value.c_str(), "%d.%d.%d.%d", &major, &minor, &point, &subpoint);
104*4d49ae65SPatrick Venture     if (num_fields == 0)
105*4d49ae65SPatrick Venture     {
106*4d49ae65SPatrick Venture         fprintf(stderr, "Invalid version.\n");
107*4d49ae65SPatrick Venture         return IPMI_CC_INVALID;
108*4d49ae65SPatrick Venture     }
109*4d49ae65SPatrick Venture 
110*4d49ae65SPatrick Venture     // Truncate if the version is too high (documented).
111*4d49ae65SPatrick Venture     struct CpldReply reply;
112*4d49ae65SPatrick Venture     reply.subcommand = SysCpldVersion;
113*4d49ae65SPatrick Venture     reply.major = static_cast<uint8_t>(major);
114*4d49ae65SPatrick Venture     reply.minor = static_cast<uint8_t>(minor);
115*4d49ae65SPatrick Venture     reply.point = static_cast<uint8_t>(point);
116*4d49ae65SPatrick Venture     reply.subpoint = static_cast<uint8_t>(subpoint);
117*4d49ae65SPatrick Venture 
118*4d49ae65SPatrick Venture     memcpy(&replyBuf[0], &reply, sizeof(struct CpldReply));
119*4d49ae65SPatrick Venture     (*dataLen) = sizeof(struct CpldReply);
120*4d49ae65SPatrick Venture 
121*4d49ae65SPatrick Venture     return IPMI_CC_OK;
122*4d49ae65SPatrick Venture }
123*4d49ae65SPatrick Venture 
124*4d49ae65SPatrick Venture } // namespace ipmi
125*4d49ae65SPatrick Venture } // namespace google
126