xref: /openbmc/google-ipmi-sys/cpld.cpp (revision 0e9aae5d)
1 /*
2  * Copyright 2018 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "cpld.hpp"
18 
19 #include "commands.hpp"
20 #include "errors.hpp"
21 #include "handler.hpp"
22 
23 #include <cstring>
24 
25 namespace google
26 {
27 namespace ipmi
28 {
29 
30 struct CpldRequest
31 {
32     uint8_t subcommand;
33     uint8_t id;
34 } __attribute__((packed));
35 
36 struct CpldReply
37 {
38     uint8_t subcommand;
39     uint8_t major;
40     uint8_t minor;
41     uint8_t point;
42     uint8_t subpoint;
43 } __attribute__((packed));
44 
45 //
46 // Handle reading the cpld version from the tmpfs.
47 //
48 ipmi_ret_t cpldVersion(const uint8_t* reqBuf, uint8_t* replyBuf,
49                        size_t* dataLen, const HandlerInterface* handler)
50 {
51     struct CpldRequest request;
52 
53     if ((*dataLen) < sizeof(request))
54     {
55         std::fprintf(stderr, "Invalid command length: %u\n",
56                      static_cast<uint32_t>(*dataLen));
57         return IPMI_CC_REQ_DATA_LEN_INVALID;
58     }
59 
60     // reqBuf[0] is the subcommand.
61     // reqBuf[1] is the CPLD id. "/run/cpld{id}.version" is what we read.
62     // Verified that this cast actually returns the value 255 and not something
63     // negative in the case where reqBuf[1] is 0xff.  However, it looks weird
64     // since I would expect int(uint8(0xff)) to be -1.  So, just cast it
65     // unsigned. we're casting to an int width to avoid it thinking it's a
66     // letter, because it does that.
67     std::memcpy(&request, &reqBuf[0], sizeof(request));
68 
69     try
70     {
71         auto values =
72             handler->getCpldVersion(static_cast<unsigned int>(request.id));
73 
74         // Truncate if the version is too high (documented).
75         struct CpldReply reply;
76         reply.subcommand = SysCpldVersion;
77         reply.major = std::get<0>(values);
78         reply.minor = std::get<1>(values);
79         reply.point = std::get<2>(values);
80         reply.subpoint = std::get<3>(values);
81 
82         std::memcpy(&replyBuf[0], &reply, sizeof(reply));
83         (*dataLen) = sizeof(reply);
84         return IPMI_CC_OK;
85     }
86     catch (const IpmiException& e)
87     {
88         return e.getIpmiError();
89     }
90 }
91 
92 } // namespace ipmi
93 } // namespace google
94