blob: 3b76870ed9e8d6617e59b650a6cadf4c2ec8669e [file] [log] [blame]
Patrick Venture33569752018-03-12 18:56:14 -07001/**
2 * Copyright 2017 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
Kumar Thangavel0269eaf2021-08-11 15:45:18 +053017#ifdef ENABLE_IPMI_SNOOP
18#include "ipmisnoop/ipmisnoop.hpp"
19#endif
20
Patrick Ventureb5754fd2018-09-10 13:13:58 -070021#include "lpcsnoop/snoop.hpp"
22
William A. Kennington III6dac4c52019-12-13 15:05:00 -080023#include <endian.h>
Patrick Venture33569752018-03-12 18:56:14 -070024#include <fcntl.h>
Benjamin Faire7b07f02018-07-02 09:51:37 -070025#include <getopt.h>
Patrick Ventureb5754fd2018-09-10 13:13:58 -070026#include <sys/epoll.h>
27#include <systemd/sd-event.h>
Patrick Venture33569752018-03-12 18:56:14 -070028#include <unistd.h>
29
Patrick Venture33569752018-03-12 18:56:14 -070030#include <cstdint>
Kun Yi1c16ad82018-09-12 10:01:49 -070031#include <exception>
Willy Tud1ac1972022-03-21 16:20:39 -070032#include <functional>
Patrick Venture33569752018-03-12 18:56:14 -070033#include <iostream>
William A. Kennington IIIb3baa682021-12-19 20:47:05 -080034#include <optional>
Kun Yi1c16ad82018-09-12 10:01:49 -070035#include <sdeventplus/event.hpp>
36#include <sdeventplus/source/event.hpp>
37#include <sdeventplus/source/io.hpp>
William A. Kennington III6a5e0a12021-12-19 20:47:34 -080038#include <sdeventplus/source/signal.hpp>
William A. Kennington III30751ec2022-11-21 18:38:36 -080039#include <sdeventplus/utility/sdbus.hpp>
Kumar Thangavel0269eaf2021-08-11 15:45:18 +053040#include <span>
William A. Kennington III6a5e0a12021-12-19 20:47:34 -080041#include <stdplus/signal.hpp>
Patrick Venture33569752018-03-12 18:56:14 -070042#include <thread>
43
Kumar Thangavel0269eaf2021-08-11 15:45:18 +053044#ifdef ENABLE_IPMI_SNOOP
45#include <xyz/openbmc_project/State/Boot/Raw/server.hpp>
46#endif
47
Benjamin Fairf69ad7e2018-07-13 13:41:10 -070048static size_t codeSize = 1; /* Size of each POST code in bytes */
Kumar Thangavel0269eaf2021-08-11 15:45:18 +053049const char* defaultHostInstances = "0";
Brad Bishop8f6c0ce2022-05-03 17:29:05 -040050#ifdef ENABLE_IPMI_SNOOP
Kumar Thangavel0269eaf2021-08-11 15:45:18 +053051const uint8_t minPositionVal = 0;
52const uint8_t maxPositionVal = 5;
Brad Bishop8f6c0ce2022-05-03 17:29:05 -040053#endif
Kumar Thangavel0269eaf2021-08-11 15:45:18 +053054
55#ifdef ENABLE_IPMI_SNOOP
56std::vector<std::unique_ptr<IpmiPostReporter>> reporters;
57#endif
58
59#ifdef ENABLE_IPMI_SNOOP
Patrick Williamsaebf87c2022-07-22 19:26:54 -050060void IpmiPostReporter::getSelectorPositionSignal(sdbusplus::bus_t& bus)
Kumar Thangavel0269eaf2021-08-11 15:45:18 +053061{
62 size_t posVal = 0;
63
64 matchSignal = std::make_unique<sdbusplus::bus::match_t>(
65 bus,
66 sdbusplus::bus::match::rules::propertiesChanged(selectorObject,
67 selectorIface),
Patrick Williamsaebf87c2022-07-22 19:26:54 -050068 [&](sdbusplus::message_t& msg) {
Kumar Thangavel0269eaf2021-08-11 15:45:18 +053069 std::string objectName;
70 std::map<std::string, Selector::PropertiesVariant> msgData;
71 msg.read(objectName, msgData);
72
73 auto valPropMap = msgData.find("Position");
74 {
75 if (valPropMap == msgData.end())
76 {
77 std::cerr << "Position property not found " << std::endl;
78 return;
79 }
80
81 posVal = std::get<size_t>(valPropMap->second);
82
83 if (posVal > minPositionVal && posVal < maxPositionVal)
84 {
85 std::tuple<uint64_t, secondary_post_code_t> postcodes =
86 reporters[posVal - 1]->value();
87 uint64_t postcode = std::get<uint64_t>(postcodes);
88
89 // write postcode into seven segment display
90 if (postCodeDisplay(postcode) < 0)
91 {
92 fprintf(stderr, "Error in display the postcode\n");
93 }
94 }
95 }
96 });
97}
98#endif
Benjamin Faire7b07f02018-07-02 09:51:37 -070099
Benjamin Faire7b07f02018-07-02 09:51:37 -0700100static void usage(const char* name)
101{
102 fprintf(stderr,
103 "Usage: %s [-d <DEVICE>]\n"
Benjamin Fairf69ad7e2018-07-13 13:41:10 -0700104 " -b, --bytes <SIZE> set POST code length to <SIZE> bytes. "
105 "Default is %zu\n"
Manojkiran Edaaade4ad2021-02-19 11:20:33 +0530106 " -d, --device <DEVICE> use <DEVICE> file.\n"
Kumar Thangavel0269eaf2021-08-11 15:45:18 +0530107 " -h, --host <host instances> . Default is '%s'\n"
William A. Kennington III66efa632020-04-16 18:46:20 -0700108 " -v, --verbose Prints verbose information while running\n\n",
Kumar Thangavel0269eaf2021-08-11 15:45:18 +0530109 name, codeSize, defaultHostInstances);
Benjamin Fairf69ad7e2018-07-13 13:41:10 -0700110}
111
Patrick Venture33569752018-03-12 18:56:14 -0700112/*
Kun Yieb312312018-06-13 09:20:50 -0700113 * Callback handling IO event from the POST code fd. i.e. there is new
114 * POST code available to read.
115 */
Willy Tud1ac1972022-03-21 16:20:39 -0700116void PostCodeEventHandler(PostReporter* reporter, bool verbose,
117 sdeventplus::source::IO& s, int postFd, uint32_t)
Kun Yieb312312018-06-13 09:20:50 -0700118{
William A. Kennington III6dac4c52019-12-13 15:05:00 -0800119 uint64_t code = 0;
William A. Kennington III0f964b42020-04-16 18:46:03 -0700120 ssize_t readb;
121 while ((readb = read(postFd, &code, codeSize)) > 0)
Kun Yi1c16ad82018-09-12 10:01:49 -0700122 {
William A. Kennington IIIf21475a2019-12-13 17:21:24 -0800123 code = le64toh(code);
William A. Kennington III66efa632020-04-16 18:46:20 -0700124 if (verbose)
125 {
126 fprintf(stderr, "Code: 0x%" PRIx64 "\n", code);
127 }
William A. Kennington IIIf21475a2019-12-13 17:21:24 -0800128 // HACK: Always send property changed signal even for the same code
129 // since we are single threaded, external users will never see the
130 // first value.
Manojkiran Edaba5258f2021-02-25 13:23:33 +0530131 reporter->value(std::make_tuple(~code, secondary_post_code_t{}), true);
132 reporter->value(std::make_tuple(code, secondary_post_code_t{}));
William A. Kennington III0f964b42020-04-16 18:46:03 -0700133
134 // read depends on old data being cleared since it doens't always read
135 // the full code size
136 code = 0;
Kun Yi1c16ad82018-09-12 10:01:49 -0700137 }
William A. Kennington III0f964b42020-04-16 18:46:03 -0700138
139 if (readb < 0 && (errno == EAGAIN || errno == EWOULDBLOCK))
140 {
141 return;
142 }
143
144 /* Read failure. */
145 if (readb == 0)
146 {
147 fprintf(stderr, "Unexpected EOF reading postcode\n");
148 }
149 else
150 {
151 fprintf(stderr, "Failed to read postcode: %s\n", strerror(errno));
152 }
153 s.get_event().exit(1);
Kun Yieb312312018-06-13 09:20:50 -0700154}
155
Kumar Thangavel0269eaf2021-08-11 15:45:18 +0530156#ifdef ENABLE_IPMI_SNOOP
157// handle muti-host D-bus
158int postCodeIpmiHandler(const std::string& snoopObject,
Patrick Williamsaebf87c2022-07-22 19:26:54 -0500159 const std::string& snoopDbus, sdbusplus::bus_t& bus,
Kumar Thangavel0269eaf2021-08-11 15:45:18 +0530160 std::span<std::string> host)
161{
162 int ret = 0;
163
164 try
165 {
166 for (size_t iteration = 0; iteration < host.size(); iteration++)
167 {
168 std::string objPathInst = snoopObject + host[iteration];
169
170 sdbusplus::server::manager_t m{bus, objPathInst.c_str()};
171
172 /* Create a monitor object and let it do all the rest */
173 reporters.emplace_back(
174 std::make_unique<IpmiPostReporter>(bus, objPathInst.c_str()));
175
176 reporters[iteration]->emit_object_added();
177 }
178
179 bus.request_name(snoopDbus.c_str());
Kumar Thangavelaee65402022-08-09 17:21:48 +0530180
181 /* sevenSegmentLedEnabled flag is unset when GPIO pins are not there 7
182 seg display for fewer platforms. So, the code for postcode dispay and
183 Get Selector position can be skipped in those platforms.
184 */
185 if (sevenSegmentLedEnabled)
186 {
187 reporters[0]->getSelectorPositionSignal(bus);
188 }
189 else
190 {
191 reporters.clear();
192 }
Kumar Thangavel0269eaf2021-08-11 15:45:18 +0530193 }
194 catch (const std::exception& e)
195 {
196 fprintf(stderr, "%s\n", e.what());
197 }
198
199 // Configure seven segment dsiplay connected to GPIOs as output
200 ret = configGPIODirOutput();
201 if (ret < 0)
202 {
Kumar Thangavelaee65402022-08-09 17:21:48 +0530203 fprintf(stderr, "Failed find the gpio line. Cannot display postcodes "
204 "in seven segment display..\n");
Kumar Thangavel0269eaf2021-08-11 15:45:18 +0530205 }
206
207 while (true)
208 {
209 bus.process_discard();
210 bus.wait();
211 }
212 exit(EXIT_SUCCESS);
213}
214#endif
215
Kun Yieb312312018-06-13 09:20:50 -0700216/*
Patrick Venture33569752018-03-12 18:56:14 -0700217 * TODO(venture): this only listens one of the possible snoop ports, but
218 * doesn't share the namespace.
219 *
220 * This polls() the lpc snoop character device and it owns the dbus object
221 * whose value is the latest port 80h value.
222 */
223int main(int argc, char* argv[])
224{
Patrick Venture33569752018-03-12 18:56:14 -0700225
Kumar Thangavel0269eaf2021-08-11 15:45:18 +0530226#ifndef ENABLE_IPMI_SNOOP
227 int postFd = -1;
228#endif
229
230 int opt;
231 bool verbose = false;
232
233#ifdef ENABLE_IPMI_SNOOP
234 std::vector<std::string> host;
235#endif
Patrick Venture33569752018-03-12 18:56:14 -0700236 /*
237 * These string constants are only used in this method within this object
238 * and this object is the only object feeding into the final binary.
239 *
240 * If however, another object is added to this binary it would be proper
241 * to move these declarations to be global and extern to the other object.
242 */
Patrick Venture33569752018-03-12 18:56:14 -0700243
Patrick Venture1ceb21b2018-08-08 11:29:36 -0700244 // clang-format off
Benjamin Faire7b07f02018-07-02 09:51:37 -0700245 static const struct option long_options[] = {
Kumar Thangavel0269eaf2021-08-11 15:45:18 +0530246 #ifdef ENABLE_IPMI_SNOOP
247 {"host", optional_argument, NULL, 'h'},
248 #endif
Patrick Venture1ceb21b2018-08-08 11:29:36 -0700249 {"bytes", required_argument, NULL, 'b'},
Kumar Thangavel0269eaf2021-08-11 15:45:18 +0530250 #ifndef ENABLE_IPMI_SNOOP
Manojkiran Edaaade4ad2021-02-19 11:20:33 +0530251 {"device", optional_argument, NULL, 'd'},
Kumar Thangavel0269eaf2021-08-11 15:45:18 +0530252 #endif
William A. Kennington III66efa632020-04-16 18:46:20 -0700253 {"verbose", no_argument, NULL, 'v'},
Patrick Venture1ceb21b2018-08-08 11:29:36 -0700254 {0, 0, 0, 0}
255 };
256 // clang-format on
Benjamin Faire7b07f02018-07-02 09:51:37 -0700257
Kumar Thangavel0269eaf2021-08-11 15:45:18 +0530258 while ((opt = getopt_long(argc, argv, "h:b:d:v", long_options, NULL)) != -1)
Benjamin Faire7b07f02018-07-02 09:51:37 -0700259 {
260 switch (opt)
261 {
262 case 0:
263 break;
Kumar Thangavel0269eaf2021-08-11 15:45:18 +0530264#ifdef ENABLE_IPMI_SNOOP
265 case 'h': {
266 std::string_view instances = optarg;
267 size_t pos = 0;
268
269 while ((pos = instances.find(" ")) != std::string::npos)
270 {
271 host.emplace_back(instances.substr(0, pos));
272 instances.remove_prefix(pos + 1);
273 }
274 host.emplace_back(instances);
275 break;
276 }
277#endif
278 case 'b': {
Benjamin Fairf69ad7e2018-07-13 13:41:10 -0700279 codeSize = atoi(optarg);
280
281 if (codeSize < 1 || codeSize > 8)
282 {
283 fprintf(stderr,
284 "Invalid POST code size '%s'. Must be "
285 "an integer from 1 to 8.\n",
286 optarg);
287 exit(EXIT_FAILURE);
288 }
289 break;
Kumar Thangavel0269eaf2021-08-11 15:45:18 +0530290 }
291#ifndef ENABLE_IPMI_SNOOP
Benjamin Faire7b07f02018-07-02 09:51:37 -0700292 case 'd':
Kumar Thangavel0269eaf2021-08-11 15:45:18 +0530293
Manojkiran Edaaade4ad2021-02-19 11:20:33 +0530294 postFd = open(optarg, O_NONBLOCK);
295 if (postFd < 0)
296 {
297 fprintf(stderr, "Unable to open: %s\n", optarg);
298 return -1;
299 }
Benjamin Faire7b07f02018-07-02 09:51:37 -0700300 break;
Kumar Thangavel0269eaf2021-08-11 15:45:18 +0530301#endif
William A. Kennington III66efa632020-04-16 18:46:20 -0700302 case 'v':
303 verbose = true;
304 break;
Benjamin Faire7b07f02018-07-02 09:51:37 -0700305 default:
306 usage(argv[0]);
Benjamin Faire7b07f02018-07-02 09:51:37 -0700307 }
308 }
309
Patrick Venture33569752018-03-12 18:56:14 -0700310 auto bus = sdbusplus::bus::new_default();
311
Kumar Thangavel0269eaf2021-08-11 15:45:18 +0530312#ifdef ENABLE_IPMI_SNOOP
313 std::cout << "Verbose = " << verbose << std::endl;
314 int ret = postCodeIpmiHandler(ipmiSnoopObject, snoopDbus, bus, host);
315 if (ret < 0)
316 {
317 fprintf(stderr, "Error in postCodeIpmiHandler\n");
318 return ret;
319 }
320 return 0;
321#endif
322
323#ifndef ENABLE_IPMI_SNOOP
Kumar Thangavel0269eaf2021-08-11 15:45:18 +0530324
325 bool deferSignals = true;
326
Patrick Venture33569752018-03-12 18:56:14 -0700327 // Add systemd object manager.
Patrick Williamsaebf87c2022-07-22 19:26:54 -0500328 sdbusplus::server::manager_t snoopdManager(bus, snoopObject);
Patrick Venture33569752018-03-12 18:56:14 -0700329
330 PostReporter reporter(bus, snoopObject, deferSignals);
Kun Yieb312312018-06-13 09:20:50 -0700331 reporter.emit_object_added();
332 bus.request_name(snoopDbus);
Kun Yieb312312018-06-13 09:20:50 -0700333
Kun Yi1c16ad82018-09-12 10:01:49 -0700334 // Create sdevent and add IO source
335 try
336 {
Kumar Thangavel0269eaf2021-08-11 15:45:18 +0530337 sdeventplus::Event event = sdeventplus::Event::get_default();
Harvey.Wu4f26b3e2022-05-12 08:54:30 +0800338 std::optional<sdeventplus::source::IO> reporterSource;
Manojkiran Edaaade4ad2021-02-19 11:20:33 +0530339 if (postFd > 0)
340 {
Harvey.Wu4f26b3e2022-05-12 08:54:30 +0800341 reporterSource.emplace(
Manojkiran Edaaade4ad2021-02-19 11:20:33 +0530342 event, postFd, EPOLLIN | EPOLLET,
Willy Tud1ac1972022-03-21 16:20:39 -0700343 std::bind_front(PostCodeEventHandler, &reporter, verbose));
Manojkiran Edaaade4ad2021-02-19 11:20:33 +0530344 }
Kun Yi1c16ad82018-09-12 10:01:49 -0700345 // Enable bus to handle incoming IO and bus events
William A. Kennington III30751ec2022-11-21 18:38:36 -0800346 auto intCb = [](sdeventplus::source::Signal& source,
347 const struct signalfd_siginfo*) {
William A. Kennington III6a5e0a12021-12-19 20:47:34 -0800348 source.get_event().exit(0);
349 };
350 stdplus::signal::block(SIGINT);
351 sdeventplus::source::Signal(event, SIGINT, intCb).set_floating(true);
352 stdplus::signal::block(SIGTERM);
353 sdeventplus::source::Signal(event, SIGTERM, std::move(intCb))
354 .set_floating(true);
William A. Kennington III30751ec2022-11-21 18:38:36 -0800355 return sdeventplus::utility::loopWithBus(event, bus);
Kun Yi1c16ad82018-09-12 10:01:49 -0700356 }
357 catch (const std::exception& e)
358 {
359 fprintf(stderr, "%s\n", e.what());
360 }
Kun Yieb312312018-06-13 09:20:50 -0700361
Patrick Venture33569752018-03-12 18:56:14 -0700362 if (postFd > -1)
363 {
364 close(postFd);
365 }
366
Sunita Kumari56127ef2022-10-12 05:01:20 +0000367 return 0;
Kumar Thangavel0269eaf2021-08-11 15:45:18 +0530368#endif
Patrick Venture33569752018-03-12 18:56:14 -0700369}