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