blob: 1307fe63630e0a8718797bca406da2e4c8253014 [file] [log] [blame]
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +11001/*
2 * Mailbox Daemon Implementation
3 *
4 * Copyright 2016 IBM
Cyril Burc85e34d2016-11-15 11:50:41 +11005 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +110010 * http://www.apache.org/licenses/LICENSE-2.0
Cyril Burc85e34d2016-11-15 11:50:41 +110011 *
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +110012 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
Cyril Burc85e34d2016-11-15 11:50:41 +110017 *
18 */
19
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +110020#define _GNU_SOURCE
Cyril Burc85e34d2016-11-15 11:50:41 +110021#include <assert.h>
22#include <errno.h>
23#include <fcntl.h>
24#include <getopt.h>
25#include <limits.h>
26#include <poll.h>
27#include <stdbool.h>
28#include <stdint.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32#include <syslog.h>
Michael Neuling899ebac2017-01-14 11:20:26 -060033#include <signal.h>
Cyril Burc85e34d2016-11-15 11:50:41 +110034#include <sys/ioctl.h>
35#include <sys/mman.h>
36#include <sys/stat.h>
37#include <sys/timerfd.h>
38#include <sys/types.h>
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +110039#include <sys/signalfd.h>
Cyril Burc85e34d2016-11-15 11:50:41 +110040#include <time.h>
41#include <unistd.h>
Andrew Jeffery78210b92017-01-13 13:06:09 +103042#include <inttypes.h>
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +110043#include <systemd/sd-bus.h>
Cyril Burc85e34d2016-11-15 11:50:41 +110044
45#include "mbox.h"
46#include "common.h"
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +110047#include "dbus.h"
48#include "mboxd_dbus.h"
49#include "mboxd_flash.h"
50#include "mboxd_lpc.h"
51#include "mboxd_msg.h"
52#include "mboxd_windows.h"
Cyril Burc85e34d2016-11-15 11:50:41 +110053
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +110054#define USAGE \
55"\nUsage: %s [-V | --version] [-h | --help] [-v[v] | --verbose] [-s | --syslog]\n" \
Suraj Jitindar Singhc29172e2017-04-12 14:26:47 +100056"\t\t[-n | --window-num <num>]\n" \
57"\t\t[-w | --window-size <size>M]\n" \
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +110058"\t\t-f | --flash <size>[K|M]\n\n" \
59"\t-v | --verbose\t\tBe [more] verbose\n" \
60"\t-s | --syslog\t\tLog output to syslog (pointless without -v)\n" \
61"\t-n | --window-num\tThe number of windows\n" \
Suraj Jitindar Singhc29172e2017-04-12 14:26:47 +100062"\t\t\t\t(default: fill the reserved memory region)\n" \
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +110063"\t-w | --window-size\tThe window size (power of 2) in MB\n" \
Suraj Jitindar Singhc29172e2017-04-12 14:26:47 +100064"\t\t\t\t(default: 1MB)\n" \
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +110065"\t-f | --flash\t\tSize of flash in [K|M] bytes\n\n"
Cyril Burc85e34d2016-11-15 11:50:41 +110066
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +110067static int poll_loop(struct mbox_context *context)
Cyril Burc85e34d2016-11-15 11:50:41 +110068{
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +110069 int rc = 0, i;
Cyril Bur46233672017-01-16 13:33:26 +110070
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +110071 /* Set POLLIN on polling file descriptors */
72 for (i = 0; i < POLL_FDS; i++) {
73 context->fds[i].events = POLLIN;
Cyril Bur46233672017-01-16 13:33:26 +110074 }
75
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +110076 while (1) {
77 rc = poll(context->fds, POLL_FDS, -1);
78
79 if (rc < 0) { /* Error */
80 MSG_ERR("Error from poll(): %s\n", strerror(errno));
81 break; /* This should mean we clean up nicely */
82 }
83
84 /* Event on Polled File Descriptor - Handle It */
85 if (context->fds[SIG_FD].revents & POLLIN) { /* Signal */
86 struct signalfd_siginfo info = { 0 };
87
88 rc = read(context->fds[SIG_FD].fd, (void *) &info,
89 sizeof(info));
90 if (rc != sizeof(info)) {
91 MSG_ERR("Error reading signal event: %s\n",
92 strerror(errno));
93 }
94
95 switch (info.ssi_signo) {
96 case SIGINT:
97 case SIGTERM:
98 MSG_OUT("Caught Signal - Exiting...\n");
99 context->terminate = true;
100 break;
101 case SIGHUP:
102 /* Host didn't request reset -> Notify it */
103 reset_all_windows(context, SET_BMC_EVENT);
104 rc = point_to_flash(context);
105 if (rc < 0) {
106 MSG_ERR("WARNING: Failed to point the "
107 "LPC bus back to flash on "
108 "SIGHUP\nIf the host requires "
109 "this expect problems...\n");
110 }
111 break;
112 default:
113 MSG_ERR("Unhandled Signal: %d\n",
114 info.ssi_signo);
115 break;
116 }
117 }
118 if (context->fds[DBUS_FD].revents & POLLIN) { /* DBUS */
119 while ((rc = sd_bus_process(context->bus, NULL)) > 0);
120 if (rc < 0) {
121 MSG_ERR("Error handling DBUS event: %s\n",
122 strerror(-rc));
123 }
124 }
125 if (context->terminate) {
126 break; /* This should mean we clean up nicely */
127 }
128 if (context->fds[MBOX_FD].revents & POLLIN) { /* MBOX */
129 rc = dispatch_mbox(context);
130 if (rc < 0) {
131 MSG_ERR("Error handling MBOX event\n");
132 }
133 }
134 }
135
136 /* Best to reset windows and point back to flash for safety */
137 /* Host didn't request reset -> Notify it */
138 reset_all_windows(context, SET_BMC_EVENT);
139 rc = point_to_flash(context);
140 /* Not much we can do if this fails */
141 if (rc < 0) {
142 MSG_ERR("WARNING: Failed to point the LPC bus back to flash\n"
143 "If the host requires this expect problems...\n");
144 }
145
146 return rc;
Cyril Burc85e34d2016-11-15 11:50:41 +1100147}
148
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100149static int init_signals(struct mbox_context *context, sigset_t *set)
Cyril Burc85e34d2016-11-15 11:50:41 +1100150{
151 int rc;
Cyril Burc85e34d2016-11-15 11:50:41 +1100152
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100153 /* Block SIGHUPs, SIGTERMs and SIGINTs */
154 sigemptyset(set);
155 sigaddset(set, SIGHUP);
156 sigaddset(set, SIGINT);
157 sigaddset(set, SIGTERM);
158 rc = sigprocmask(SIG_BLOCK, set, NULL);
159 if (rc < 0) {
160 MSG_ERR("Failed to set SIG_BLOCK mask %s\n", strerror(errno));
161 return rc;
Cyril Burc85e34d2016-11-15 11:50:41 +1100162 }
163
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100164 /* Get Signal File Descriptor */
165 rc = signalfd(-1, set, SFD_NONBLOCK);
166 if (rc < 0) {
167 MSG_ERR("Failed to get signalfd %s\n", strerror(errno));
168 return rc;
Cyril Burc85e34d2016-11-15 11:50:41 +1100169 }
170
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100171 context->fds[SIG_FD].fd = rc;
Cyril Burc85e34d2016-11-15 11:50:41 +1100172 return 0;
173}
174
Cyril Burc85e34d2016-11-15 11:50:41 +1100175static void usage(const char *name)
176{
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100177 printf(USAGE, name);
Cyril Burc85e34d2016-11-15 11:50:41 +1100178}
179
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100180static bool parse_cmdline(int argc, char **argv,
181 struct mbox_context *context)
Cyril Burc85e34d2016-11-15 11:50:41 +1100182{
Cyril Bure8f2de12017-01-17 16:56:02 +1100183 char *endptr;
Suraj Jitindar Singhc29172e2017-04-12 14:26:47 +1000184 int opt;
Cyril Burc85e34d2016-11-15 11:50:41 +1100185
186 static const struct option long_options[] = {
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100187 { "flash", required_argument, 0, 'f' },
188 { "window-size", optional_argument, 0, 'w' },
189 { "window-num", optional_argument, 0, 'n' },
190 { "verbose", no_argument, 0, 'v' },
191 { "syslog", no_argument, 0, 's' },
192 { "version", no_argument, 0, 'V' },
193 { "help", no_argument, 0, 'h' },
194 { 0, 0, 0, 0 }
Cyril Burc85e34d2016-11-15 11:50:41 +1100195 };
196
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100197 verbosity = MBOX_LOG_NONE;
Cyril Burc85e34d2016-11-15 11:50:41 +1100198 mbox_vlog = &mbox_log_console;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100199
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100200 context->current = NULL; /* No current window */
201
202 while ((opt = getopt_long(argc, argv, "f:w::n::vsVh", long_options, NULL))
203 != -1) {
Cyril Burc85e34d2016-11-15 11:50:41 +1100204 switch (opt) {
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100205 case 0:
206 break;
207 case 'f':
208 context->flash_size = strtol(optarg, &endptr, 10);
209 if (optarg == endptr) {
210 fprintf(stderr, "Unparseable flash size\n");
211 return false;
212 }
213 switch (*endptr) {
214 case '\0':
Cyril Burc85e34d2016-11-15 11:50:41 +1100215 break;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100216 case 'M':
217 context->flash_size <<= 10;
218 case 'K':
219 context->flash_size <<= 10;
Cyril Burc85e34d2016-11-15 11:50:41 +1100220 break;
221 default:
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100222 fprintf(stderr, "Unknown units '%c'\n",
223 *endptr);
224 return false;
225 }
226 break;
227 case 'n':
228 context->windows.num = strtol(argv[optind], &endptr,
229 10);
230 if (optarg == endptr || *endptr != '\0') {
231 fprintf(stderr, "Unparseable window num\n");
232 return false;
233 }
234 break;
235 case 'w':
236 context->windows.default_size = strtol(argv[optind],
237 &endptr, 10);
238 context->windows.default_size <<= 20; /* Given in MB */
239 if (optarg == endptr || (*endptr != '\0' &&
240 *endptr != 'M')) {
241 fprintf(stderr, "Unparseable window size\n");
242 return false;
243 }
Suraj Jitindar Singh0aff80c2017-04-12 14:37:24 +1000244 if (!is_power_of_2(context->windows.default_size)) {
245 fprintf(stderr, "Window size not power of 2\n");
246 return false;
247 }
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100248 break;
249 case 'v':
250 verbosity++;
251 break;
252 case 's':
253 /* Avoid a double openlog() */
254 if (mbox_vlog != &vsyslog) {
255 openlog(PREFIX, LOG_ODELAY, LOG_DAEMON);
256 mbox_vlog = &vsyslog;
257 }
258 break;
259 case 'V':
260 printf("%s v%d.%.2d\n", THIS_NAME, API_MAX_VERSION,
261 SUB_VERSION);
262 exit(0);
263 case 'h':
264 return false; /* This will print the usage message */
265 default:
266 return false;
Cyril Burc85e34d2016-11-15 11:50:41 +1100267 }
268 }
269
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100270 if (!context->flash_size) {
Cyril Bure8f2de12017-01-17 16:56:02 +1100271 fprintf(stderr, "Must specify a non-zero flash size\n");
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100272 return false;
Cyril Bure8f2de12017-01-17 16:56:02 +1100273 }
274
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100275 MSG_OUT("Flash size: 0x%.8x\n", context->flash_size);
Cyril Burc85e34d2016-11-15 11:50:41 +1100276
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100277 if (verbosity) {
278 MSG_OUT("%s logging\n", verbosity == MBOX_LOG_DEBUG ? "Debug" :
279 "Verbose");
Cyril Burc85e34d2016-11-15 11:50:41 +1100280 }
281
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100282 return true;
Cyril Burc85e34d2016-11-15 11:50:41 +1100283}
284
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100285int main(int argc, char **argv)
286{
287 struct mbox_context *context;
288 char *name = argv[0];
289 sigset_t set;
290 int rc, i;
291
292 context = calloc(1, sizeof(*context));
293 if (!context) {
294 fprintf(stderr, "Memory allocation failed\n");
295 exit(1);
296 }
297
298 if (!parse_cmdline(argc, argv, context)) {
299 usage(name);
300 free(context);
301 exit(0);
302 }
303
304 for (i = 0; i < TOTAL_FDS; i++) {
305 context->fds[i].fd = -1;
306 }
307
308 MSG_OUT("Starting Daemon\n");
309
310 rc = init_signals(context, &set);
311 if (rc) {
312 goto finish;
313 }
314
315 rc = init_mbox_dev(context);
316 if (rc) {
317 goto finish;
318 }
319
320 rc = init_lpc_dev(context);
321 if (rc) {
322 goto finish;
323 }
324
325 /* We've found the reserved memory region -> we can assign to windows */
Suraj Jitindar Singhc29172e2017-04-12 14:26:47 +1000326 rc = init_windows(context);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100327 if (rc) {
328 goto finish;
329 }
330
331 rc = init_flash_dev(context);
332 if (rc) {
333 goto finish;
334 }
335
336 rc = init_mboxd_dbus(context);
337 if (rc) {
338 goto finish;
339 }
340
341 /* Set the LPC bus mapping to point to the physical flash device */
342 rc = point_to_flash(context);
343 if (rc) {
344 goto finish;
345 }
346
347 rc = set_bmc_events(context, BMC_EVENT_DAEMON_READY, SET_BMC_EVENT);
348 if (rc) {
349 goto finish;
350 }
351
352 MSG_OUT("Entering Polling Loop\n");
353 rc = poll_loop(context);
354
355 MSG_OUT("Exiting Poll Loop: %d\n", rc);
356
357finish:
358 MSG_OUT("Daemon Exiting...\n");
359 clr_bmc_events(context, BMC_EVENT_DAEMON_READY, SET_BMC_EVENT);
360
361 free_mboxd_dbus(context);
362 free_flash_dev(context);
363 free_lpc_dev(context);
364 free_mbox_dev(context);
Suraj Jitindar Singhc29172e2017-04-12 14:26:47 +1000365 free_windows(context);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100366 free(context);
367
368 return rc;
369}