blob: 6f060d8ab648964934ba1119a8c8c065d378069c [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" \
56"\t\t-n | --window-num <num>\n" \
57"\t\t-w | --window-size <size>M\n" \
58"\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" \
62"\t-w | --window-size\tThe window size (power of 2) in MB\n" \
63"\t-f | --flash\t\tSize of flash in [K|M] bytes\n\n"
Cyril Burc85e34d2016-11-15 11:50:41 +110064
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +110065static int poll_loop(struct mbox_context *context)
Cyril Burc85e34d2016-11-15 11:50:41 +110066{
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +110067 int rc = 0, i;
Cyril Bur46233672017-01-16 13:33:26 +110068
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +110069 /* Set POLLIN on polling file descriptors */
70 for (i = 0; i < POLL_FDS; i++) {
71 context->fds[i].events = POLLIN;
Cyril Bur46233672017-01-16 13:33:26 +110072 }
73
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +110074 while (1) {
75 rc = poll(context->fds, POLL_FDS, -1);
76
77 if (rc < 0) { /* Error */
78 MSG_ERR("Error from poll(): %s\n", strerror(errno));
79 break; /* This should mean we clean up nicely */
80 }
81
82 /* Event on Polled File Descriptor - Handle It */
83 if (context->fds[SIG_FD].revents & POLLIN) { /* Signal */
84 struct signalfd_siginfo info = { 0 };
85
86 rc = read(context->fds[SIG_FD].fd, (void *) &info,
87 sizeof(info));
88 if (rc != sizeof(info)) {
89 MSG_ERR("Error reading signal event: %s\n",
90 strerror(errno));
91 }
92
93 switch (info.ssi_signo) {
94 case SIGINT:
95 case SIGTERM:
96 MSG_OUT("Caught Signal - Exiting...\n");
97 context->terminate = true;
98 break;
99 case SIGHUP:
100 /* Host didn't request reset -> Notify it */
101 reset_all_windows(context, SET_BMC_EVENT);
102 rc = point_to_flash(context);
103 if (rc < 0) {
104 MSG_ERR("WARNING: Failed to point the "
105 "LPC bus back to flash on "
106 "SIGHUP\nIf the host requires "
107 "this expect problems...\n");
108 }
109 break;
110 default:
111 MSG_ERR("Unhandled Signal: %d\n",
112 info.ssi_signo);
113 break;
114 }
115 }
116 if (context->fds[DBUS_FD].revents & POLLIN) { /* DBUS */
117 while ((rc = sd_bus_process(context->bus, NULL)) > 0);
118 if (rc < 0) {
119 MSG_ERR("Error handling DBUS event: %s\n",
120 strerror(-rc));
121 }
122 }
123 if (context->terminate) {
124 break; /* This should mean we clean up nicely */
125 }
126 if (context->fds[MBOX_FD].revents & POLLIN) { /* MBOX */
127 rc = dispatch_mbox(context);
128 if (rc < 0) {
129 MSG_ERR("Error handling MBOX event\n");
130 }
131 }
132 }
133
134 /* Best to reset windows and point back to flash for safety */
135 /* Host didn't request reset -> Notify it */
136 reset_all_windows(context, SET_BMC_EVENT);
137 rc = point_to_flash(context);
138 /* Not much we can do if this fails */
139 if (rc < 0) {
140 MSG_ERR("WARNING: Failed to point the LPC bus back to flash\n"
141 "If the host requires this expect problems...\n");
142 }
143
144 return rc;
Cyril Burc85e34d2016-11-15 11:50:41 +1100145}
146
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100147static int init_signals(struct mbox_context *context, sigset_t *set)
Cyril Burc85e34d2016-11-15 11:50:41 +1100148{
149 int rc;
Cyril Burc85e34d2016-11-15 11:50:41 +1100150
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100151 /* Block SIGHUPs, SIGTERMs and SIGINTs */
152 sigemptyset(set);
153 sigaddset(set, SIGHUP);
154 sigaddset(set, SIGINT);
155 sigaddset(set, SIGTERM);
156 rc = sigprocmask(SIG_BLOCK, set, NULL);
157 if (rc < 0) {
158 MSG_ERR("Failed to set SIG_BLOCK mask %s\n", strerror(errno));
159 return rc;
Cyril Burc85e34d2016-11-15 11:50:41 +1100160 }
161
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100162 /* Get Signal File Descriptor */
163 rc = signalfd(-1, set, SFD_NONBLOCK);
164 if (rc < 0) {
165 MSG_ERR("Failed to get signalfd %s\n", strerror(errno));
166 return rc;
Cyril Burc85e34d2016-11-15 11:50:41 +1100167 }
168
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100169 context->fds[SIG_FD].fd = rc;
Cyril Burc85e34d2016-11-15 11:50:41 +1100170 return 0;
171}
172
Cyril Burc85e34d2016-11-15 11:50:41 +1100173static void usage(const char *name)
174{
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100175 printf(USAGE, name);
Cyril Burc85e34d2016-11-15 11:50:41 +1100176}
177
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100178static bool parse_cmdline(int argc, char **argv,
179 struct mbox_context *context)
Cyril Burc85e34d2016-11-15 11:50:41 +1100180{
Cyril Bure8f2de12017-01-17 16:56:02 +1100181 char *endptr;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100182 int opt, i;
Cyril Burc85e34d2016-11-15 11:50:41 +1100183
184 static const struct option long_options[] = {
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100185 { "flash", required_argument, 0, 'f' },
186 { "window-size", optional_argument, 0, 'w' },
187 { "window-num", optional_argument, 0, 'n' },
188 { "verbose", no_argument, 0, 'v' },
189 { "syslog", no_argument, 0, 's' },
190 { "version", no_argument, 0, 'V' },
191 { "help", no_argument, 0, 'h' },
192 { 0, 0, 0, 0 }
Cyril Burc85e34d2016-11-15 11:50:41 +1100193 };
194
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100195 verbosity = MBOX_LOG_NONE;
Cyril Burc85e34d2016-11-15 11:50:41 +1100196 mbox_vlog = &mbox_log_console;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100197
198 /* Default to 1 window of size flash_size */
199 context->windows.default_size = context->flash_size;
200 context->windows.num = 1;
201 context->current = NULL; /* No current window */
202
203 while ((opt = getopt_long(argc, argv, "f:w::n::vsVh", long_options, NULL))
204 != -1) {
Cyril Burc85e34d2016-11-15 11:50:41 +1100205 switch (opt) {
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100206 case 0:
207 break;
208 case 'f':
209 context->flash_size = strtol(optarg, &endptr, 10);
210 if (optarg == endptr) {
211 fprintf(stderr, "Unparseable flash size\n");
212 return false;
213 }
214 switch (*endptr) {
215 case '\0':
Cyril Burc85e34d2016-11-15 11:50:41 +1100216 break;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100217 case 'M':
218 context->flash_size <<= 10;
219 case 'K':
220 context->flash_size <<= 10;
Cyril Burc85e34d2016-11-15 11:50:41 +1100221 break;
222 default:
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100223 fprintf(stderr, "Unknown units '%c'\n",
224 *endptr);
225 return false;
226 }
227 break;
228 case 'n':
229 context->windows.num = strtol(argv[optind], &endptr,
230 10);
231 if (optarg == endptr || *endptr != '\0') {
232 fprintf(stderr, "Unparseable window num\n");
233 return false;
234 }
235 break;
236 case 'w':
237 context->windows.default_size = strtol(argv[optind],
238 &endptr, 10);
239 context->windows.default_size <<= 20; /* Given in MB */
240 if (optarg == endptr || (*endptr != '\0' &&
241 *endptr != 'M')) {
242 fprintf(stderr, "Unparseable window size\n");
243 return false;
244 }
245 break;
246 case 'v':
247 verbosity++;
248 break;
249 case 's':
250 /* Avoid a double openlog() */
251 if (mbox_vlog != &vsyslog) {
252 openlog(PREFIX, LOG_ODELAY, LOG_DAEMON);
253 mbox_vlog = &vsyslog;
254 }
255 break;
256 case 'V':
257 printf("%s v%d.%.2d\n", THIS_NAME, API_MAX_VERSION,
258 SUB_VERSION);
259 exit(0);
260 case 'h':
261 return false; /* This will print the usage message */
262 default:
263 return false;
Cyril Burc85e34d2016-11-15 11:50:41 +1100264 }
265 }
266
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100267 if (!context->flash_size) {
Cyril Bure8f2de12017-01-17 16:56:02 +1100268 fprintf(stderr, "Must specify a non-zero flash size\n");
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100269 return false;
Cyril Bure8f2de12017-01-17 16:56:02 +1100270 }
271
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100272 if (!context->windows.num) {
273 fprintf(stderr, "Must specify a non-zero number of windows\n"
274 "If unsure - select 4 (-n 4)\n");
275 return false;
276 }
Cyril Burc85e34d2016-11-15 11:50:41 +1100277
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100278 if (!context->windows.default_size) {
279 fprintf(stderr, "Must specify a non-zero window size\n"
280 "If unsure - select 1M (-w 1)\n");
281 return false;
282 }
Cyril Burc85e34d2016-11-15 11:50:41 +1100283
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100284 MSG_OUT("Flash size: 0x%.8x\n", context->flash_size);
285 MSG_OUT("Number of Windows: %d\n", context->windows.num);
286 MSG_OUT("Window size: 0x%.8x\n", context->windows.default_size);
287
288 context->windows.window = calloc(context->windows.num,
289 sizeof(*context->windows.window));
290 if (!context->windows.window) {
291 MSG_ERR("Memory allocation failed\n");
292 free(context);
Michael Neuling899ebac2017-01-14 11:20:26 -0600293 exit(1);
294 }
Michael Neuling899ebac2017-01-14 11:20:26 -0600295
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100296 for (i = 0; i < context->windows.num; i++) {
297 init_window_state(&context->windows.window[i],
298 context->windows.default_size);
Cyril Burc85e34d2016-11-15 11:50:41 +1100299 }
300
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100301 if (verbosity) {
302 MSG_OUT("%s logging\n", verbosity == MBOX_LOG_DEBUG ? "Debug" :
303 "Verbose");
Cyril Burc85e34d2016-11-15 11:50:41 +1100304 }
305
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100306 return true;
Cyril Burc85e34d2016-11-15 11:50:41 +1100307}
308
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100309int main(int argc, char **argv)
310{
311 struct mbox_context *context;
312 char *name = argv[0];
313 sigset_t set;
314 int rc, i;
315
316 context = calloc(1, sizeof(*context));
317 if (!context) {
318 fprintf(stderr, "Memory allocation failed\n");
319 exit(1);
320 }
321
322 if (!parse_cmdline(argc, argv, context)) {
323 usage(name);
324 free(context);
325 exit(0);
326 }
327
328 for (i = 0; i < TOTAL_FDS; i++) {
329 context->fds[i].fd = -1;
330 }
331
332 MSG_OUT("Starting Daemon\n");
333
334 rc = init_signals(context, &set);
335 if (rc) {
336 goto finish;
337 }
338
339 rc = init_mbox_dev(context);
340 if (rc) {
341 goto finish;
342 }
343
344 rc = init_lpc_dev(context);
345 if (rc) {
346 goto finish;
347 }
348
349 /* We've found the reserved memory region -> we can assign to windows */
350 rc = init_window_mem(context);
351 if (rc) {
352 goto finish;
353 }
354
355 rc = init_flash_dev(context);
356 if (rc) {
357 goto finish;
358 }
359
360 rc = init_mboxd_dbus(context);
361 if (rc) {
362 goto finish;
363 }
364
365 /* Set the LPC bus mapping to point to the physical flash device */
366 rc = point_to_flash(context);
367 if (rc) {
368 goto finish;
369 }
370
371 rc = set_bmc_events(context, BMC_EVENT_DAEMON_READY, SET_BMC_EVENT);
372 if (rc) {
373 goto finish;
374 }
375
376 MSG_OUT("Entering Polling Loop\n");
377 rc = poll_loop(context);
378
379 MSG_OUT("Exiting Poll Loop: %d\n", rc);
380
381finish:
382 MSG_OUT("Daemon Exiting...\n");
383 clr_bmc_events(context, BMC_EVENT_DAEMON_READY, SET_BMC_EVENT);
384
385 free_mboxd_dbus(context);
386 free_flash_dev(context);
387 free_lpc_dev(context);
388 free_mbox_dev(context);
389 free_window_dirty_bytemap(context);
390 free(context->windows.window);
391 free(context);
392
393 return rc;
394}