blob: 2e79e2d8a2252eb9ba6ea39507cb79271a671180 [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
17#include <fcntl.h>
Benjamin Faire7b07f02018-07-02 09:51:37 -070018#include <getopt.h>
Patrick Venture33569752018-03-12 18:56:14 -070019#include <poll.h>
20#include <unistd.h>
21
22#include <array>
23#include <cstdint>
24#include <iostream>
25#include <memory>
26#include <thread>
27
28#include <sdbusplus/bus.hpp>
29#include <sdbusplus/server.hpp>
30#include "xyz/openbmc_project/State/Boot/Raw/server.hpp"
31
32#include "lpcsnoop/snoop.hpp"
33
34template <typename... T>
35using ServerObject = typename sdbusplus::server::object::object<T...>;
36using PostInterface = sdbusplus::xyz::openbmc_project::State::Boot::server::Raw;
37using PostObject = ServerObject<PostInterface>;
38
39class PostReporter : public PostObject
40{
41 public:
42 PostReporter(sdbusplus::bus::bus& bus, const char* objPath, bool defer) :
43 PostObject(bus, objPath, defer)
44 {
45 }
46};
47
Benjamin Faire7b07f02018-07-02 09:51:37 -070048static const char* snoopFilename = "/dev/aspeed-lpc-snoop0";
49
Patrick Venture33569752018-03-12 18:56:14 -070050/*
51 * 256 bytes is a nice amount. It's improbable we'd need this many, but its
52 * gives us leg room in the event the driver poll doesn't return in a timely
53 * fashion. So, mostly arbitrarily chosen.
54 */
55static constexpr size_t BUFFER_SIZE = 256;
56
57/*
58 * Process any incoming dbus inquiries, which include introspection etc.
59 */
60void ProcessDbus(sdbusplus::bus::bus& bus)
61{
62 while (true)
63 {
64 bus.process_discard();
65 bus.wait(); // wait indefinitely
66 }
67
68 return;
69}
70
Benjamin Faire7b07f02018-07-02 09:51:37 -070071static void usage(const char* name)
72{
73 fprintf(stderr,
74 "Usage: %s [-d <DEVICE>]\n"
75 " -d, --device <DEVICE> use <DEVICE> file. Default is '%s'\n\n",
76 name, snoopFilename);
77}
78
Patrick Venture33569752018-03-12 18:56:14 -070079/*
80 * TODO(venture): this only listens one of the possible snoop ports, but
81 * doesn't share the namespace.
82 *
83 * This polls() the lpc snoop character device and it owns the dbus object
84 * whose value is the latest port 80h value.
85 */
86int main(int argc, char* argv[])
87{
88 int rc = 0;
Benjamin Faire7b07f02018-07-02 09:51:37 -070089 int opt;
Patrick Venture33569752018-03-12 18:56:14 -070090 struct pollfd pollset;
91 int pollr;
92 int readb;
93 int postFd = -1;
94 std::array<uint8_t, BUFFER_SIZE> buffer;
95
96 /*
97 * These string constants are only used in this method within this object
98 * and this object is the only object feeding into the final binary.
99 *
100 * If however, another object is added to this binary it would be proper
101 * to move these declarations to be global and extern to the other object.
102 */
103 const char* snoopObject = SNOOP_OBJECTPATH;
104 const char* snoopDbus = SNOOP_BUSNAME;
Benjamin Faire7b07f02018-07-02 09:51:37 -0700105
Patrick Venture33569752018-03-12 18:56:14 -0700106 bool deferSignals = true;
107
Benjamin Faire7b07f02018-07-02 09:51:37 -0700108 static const struct option long_options[] = {
109 {"device", required_argument, NULL, 'd'}, {0, 0, 0, 0}};
110
111 while ((opt = getopt_long(argc, argv, "d:", long_options, NULL)) != -1)
112 {
113 switch (opt)
114 {
115 case 0:
116 break;
117 case 'd':
118 snoopFilename = optarg;
119 break;
120 default:
121 usage(argv[0]);
122 exit(EXIT_FAILURE);
123 }
124 }
125
Patrick Venture33569752018-03-12 18:56:14 -0700126 postFd = open(snoopFilename, 0);
127 if (postFd < 0)
128 {
129 fprintf(stderr, "Unable to open: %s\n", snoopFilename);
130 return -1;
131 }
132
133 pollset.fd = postFd;
134 pollset.events |= POLLIN;
135
136 auto bus = sdbusplus::bus::new_default();
137
138 // Add systemd object manager.
139 sdbusplus::server::manager::manager(bus, snoopObject);
140
141 PostReporter reporter(bus, snoopObject, deferSignals);
142 reporter.emit_object_added();
143
144 bus.request_name(snoopDbus);
145
146 /*
147 * I don't see a public interface for getting the underlying sd_bus*
148 * so instead of poll(bus, driver), I'll just create a separate thread.
149 *
150 * TODO(venture): There may be a way to use sdevent to poll both the file
151 * and the dbus in the same event loop. If I could get the sdbus pointer
152 * from bus directly, I'd grab a file handler from it, and then just poll on
153 * both in one loop. From a cursory look at sdevent, I should be able to do
154 * something similar with that at some point.
155 */
156 std::thread lt(ProcessDbus, std::ref(bus));
157
158 /* infinitely listen for POST codes and broadcast. */
159 while (true)
160 {
161 pollr = poll(&pollset, 1, -1); /* polls indefinitely. */
162 if (pollr < 0)
163 {
164 /* poll returned error. */
165 rc = -errno;
166 goto exit;
167 }
168
169 if (pollr > 0)
170 {
171 if (pollset.revents & POLLIN)
172 {
173 readb = read(postFd, buffer.data(), buffer.size());
174 if (readb < 0)
175 {
176 /* Read failure. */
177 rc = readb;
178 goto exit;
179 }
180 else
181 {
182 /* Broadcast the bytes read. */
183 for (int i = 0; i < readb; i++)
184 {
185 reporter.value(buffer[i]);
186 }
187 }
188 }
189 }
190 }
191
192exit:
193 if (postFd > -1)
194 {
195 close(postFd);
196 }
197
198 lt.join();
199
200 return rc;
201}