blob: 43d2aa16cf3c2b3af8da2c510c29831d48f78c66 [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
Suraj Jitindar Singh8d65bb42017-05-01 16:05:17 +100045#include "config.h"
Cyril Burc85e34d2016-11-15 11:50:41 +110046#include "mbox.h"
47#include "common.h"
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +110048#include "dbus.h"
49#include "mboxd_dbus.h"
50#include "mboxd_flash.h"
51#include "mboxd_lpc.h"
52#include "mboxd_msg.h"
53#include "mboxd_windows.h"
Deepak Kodihalli6c2fa902017-05-01 06:36:02 -050054#include "mboxd_pnor_partition_table.h"
Cyril Burc85e34d2016-11-15 11:50:41 +110055
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +110056#define USAGE \
57"\nUsage: %s [-V | --version] [-h | --help] [-v[v] | --verbose] [-s | --syslog]\n" \
Suraj Jitindar Singhc29172e2017-04-12 14:26:47 +100058"\t\t[-n | --window-num <num>]\n" \
59"\t\t[-w | --window-size <size>M]\n" \
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +110060"\t\t-f | --flash <size>[K|M]\n\n" \
61"\t-v | --verbose\t\tBe [more] verbose\n" \
62"\t-s | --syslog\t\tLog output to syslog (pointless without -v)\n" \
63"\t-n | --window-num\tThe number of windows\n" \
Suraj Jitindar Singhc29172e2017-04-12 14:26:47 +100064"\t\t\t\t(default: fill the reserved memory region)\n" \
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +110065"\t-w | --window-size\tThe window size (power of 2) in MB\n" \
Suraj Jitindar Singhc29172e2017-04-12 14:26:47 +100066"\t\t\t\t(default: 1MB)\n" \
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +110067"\t-f | --flash\t\tSize of flash in [K|M] bytes\n\n"
Cyril Burc85e34d2016-11-15 11:50:41 +110068
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +110069static int poll_loop(struct mbox_context *context)
Cyril Burc85e34d2016-11-15 11:50:41 +110070{
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +110071 int rc = 0, i;
Cyril Bur46233672017-01-16 13:33:26 +110072
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +110073 /* Set POLLIN on polling file descriptors */
74 for (i = 0; i < POLL_FDS; i++) {
75 context->fds[i].events = POLLIN;
Cyril Bur46233672017-01-16 13:33:26 +110076 }
77
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +110078 while (1) {
79 rc = poll(context->fds, POLL_FDS, -1);
80
81 if (rc < 0) { /* Error */
82 MSG_ERR("Error from poll(): %s\n", strerror(errno));
83 break; /* This should mean we clean up nicely */
84 }
85
86 /* Event on Polled File Descriptor - Handle It */
87 if (context->fds[SIG_FD].revents & POLLIN) { /* Signal */
88 struct signalfd_siginfo info = { 0 };
89
90 rc = read(context->fds[SIG_FD].fd, (void *) &info,
91 sizeof(info));
92 if (rc != sizeof(info)) {
93 MSG_ERR("Error reading signal event: %s\n",
94 strerror(errno));
95 }
96
Suraj Jitindar Singh28519592017-04-27 14:48:58 +100097 MSG_DBG("Received signal: %d\n", info.ssi_signo);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +110098 switch (info.ssi_signo) {
99 case SIGINT:
100 case SIGTERM:
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000101 MSG_INFO("Caught Signal - Exiting...\n");
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100102 context->terminate = true;
103 break;
104 case SIGHUP:
105 /* Host didn't request reset -> Notify it */
106 reset_all_windows(context, SET_BMC_EVENT);
Deepak Kodihalli017e45c2017-07-12 01:06:30 -0500107 rc = reset_lpc(context);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100108 if (rc < 0) {
109 MSG_ERR("WARNING: Failed to point the "
110 "LPC bus back to flash on "
111 "SIGHUP\nIf the host requires "
112 "this expect problems...\n");
113 }
114 break;
115 default:
116 MSG_ERR("Unhandled Signal: %d\n",
117 info.ssi_signo);
118 break;
119 }
120 }
121 if (context->fds[DBUS_FD].revents & POLLIN) { /* DBUS */
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000122 while ((rc = sd_bus_process(context->bus, NULL)) > 0) {
123 MSG_DBG("DBUS Event\n");
124 }
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100125 if (rc < 0) {
126 MSG_ERR("Error handling DBUS event: %s\n",
127 strerror(-rc));
128 }
129 }
130 if (context->terminate) {
131 break; /* This should mean we clean up nicely */
132 }
133 if (context->fds[MBOX_FD].revents & POLLIN) { /* MBOX */
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000134 MSG_DBG("MBOX Event\n");
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100135 rc = dispatch_mbox(context);
136 if (rc < 0) {
137 MSG_ERR("Error handling MBOX event\n");
138 }
139 }
140 }
141
Deepak Kodihalli017e45c2017-07-12 01:06:30 -0500142 /* Best to reset windows and the lpc mapping for safety */
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100143 /* Host didn't request reset -> Notify it */
144 reset_all_windows(context, SET_BMC_EVENT);
Deepak Kodihalli017e45c2017-07-12 01:06:30 -0500145 rc = reset_lpc(context);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100146 /* Not much we can do if this fails */
147 if (rc < 0) {
148 MSG_ERR("WARNING: Failed to point the LPC bus back to flash\n"
149 "If the host requires this expect problems...\n");
150 }
151
152 return rc;
Cyril Burc85e34d2016-11-15 11:50:41 +1100153}
154
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100155static int init_signals(struct mbox_context *context, sigset_t *set)
Cyril Burc85e34d2016-11-15 11:50:41 +1100156{
157 int rc;
Cyril Burc85e34d2016-11-15 11:50:41 +1100158
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100159 /* Block SIGHUPs, SIGTERMs and SIGINTs */
160 sigemptyset(set);
161 sigaddset(set, SIGHUP);
162 sigaddset(set, SIGINT);
163 sigaddset(set, SIGTERM);
164 rc = sigprocmask(SIG_BLOCK, set, NULL);
165 if (rc < 0) {
166 MSG_ERR("Failed to set SIG_BLOCK mask %s\n", strerror(errno));
167 return rc;
Cyril Burc85e34d2016-11-15 11:50:41 +1100168 }
169
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100170 /* Get Signal File Descriptor */
171 rc = signalfd(-1, set, SFD_NONBLOCK);
172 if (rc < 0) {
173 MSG_ERR("Failed to get signalfd %s\n", strerror(errno));
174 return rc;
Cyril Burc85e34d2016-11-15 11:50:41 +1100175 }
176
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100177 context->fds[SIG_FD].fd = rc;
Cyril Burc85e34d2016-11-15 11:50:41 +1100178 return 0;
179}
180
Cyril Burc85e34d2016-11-15 11:50:41 +1100181static void usage(const char *name)
182{
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100183 printf(USAGE, name);
Cyril Burc85e34d2016-11-15 11:50:41 +1100184}
185
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100186static bool parse_cmdline(int argc, char **argv,
187 struct mbox_context *context)
Cyril Burc85e34d2016-11-15 11:50:41 +1100188{
Cyril Bure8f2de12017-01-17 16:56:02 +1100189 char *endptr;
Suraj Jitindar Singhc29172e2017-04-12 14:26:47 +1000190 int opt;
Cyril Burc85e34d2016-11-15 11:50:41 +1100191
192 static const struct option long_options[] = {
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100193 { "flash", required_argument, 0, 'f' },
194 { "window-size", optional_argument, 0, 'w' },
195 { "window-num", optional_argument, 0, 'n' },
196 { "verbose", no_argument, 0, 'v' },
197 { "syslog", no_argument, 0, 's' },
198 { "version", no_argument, 0, 'V' },
199 { "help", no_argument, 0, 'h' },
200 { 0, 0, 0, 0 }
Cyril Burc85e34d2016-11-15 11:50:41 +1100201 };
202
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100203 verbosity = MBOX_LOG_NONE;
Cyril Burc85e34d2016-11-15 11:50:41 +1100204 mbox_vlog = &mbox_log_console;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100205
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100206 context->current = NULL; /* No current window */
207
208 while ((opt = getopt_long(argc, argv, "f:w::n::vsVh", long_options, NULL))
209 != -1) {
Cyril Burc85e34d2016-11-15 11:50:41 +1100210 switch (opt) {
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100211 case 0:
212 break;
213 case 'f':
214 context->flash_size = strtol(optarg, &endptr, 10);
215 if (optarg == endptr) {
216 fprintf(stderr, "Unparseable flash size\n");
217 return false;
218 }
219 switch (*endptr) {
220 case '\0':
Cyril Burc85e34d2016-11-15 11:50:41 +1100221 break;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100222 case 'M':
223 context->flash_size <<= 10;
224 case 'K':
225 context->flash_size <<= 10;
Cyril Burc85e34d2016-11-15 11:50:41 +1100226 break;
227 default:
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100228 fprintf(stderr, "Unknown units '%c'\n",
229 *endptr);
230 return false;
231 }
232 break;
233 case 'n':
234 context->windows.num = strtol(argv[optind], &endptr,
235 10);
236 if (optarg == endptr || *endptr != '\0') {
237 fprintf(stderr, "Unparseable window num\n");
238 return false;
239 }
240 break;
241 case 'w':
242 context->windows.default_size = strtol(argv[optind],
243 &endptr, 10);
244 context->windows.default_size <<= 20; /* Given in MB */
245 if (optarg == endptr || (*endptr != '\0' &&
246 *endptr != 'M')) {
247 fprintf(stderr, "Unparseable window size\n");
248 return false;
249 }
Suraj Jitindar Singh0aff80c2017-04-12 14:37:24 +1000250 if (!is_power_of_2(context->windows.default_size)) {
251 fprintf(stderr, "Window size not power of 2\n");
252 return false;
253 }
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100254 break;
255 case 'v':
256 verbosity++;
257 break;
258 case 's':
259 /* Avoid a double openlog() */
260 if (mbox_vlog != &vsyslog) {
261 openlog(PREFIX, LOG_ODELAY, LOG_DAEMON);
262 mbox_vlog = &vsyslog;
263 }
264 break;
265 case 'V':
Suraj Jitindar Singh8d65bb42017-05-01 16:05:17 +1000266 printf("%s V%s\n", THIS_NAME, PACKAGE_VERSION);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100267 exit(0);
268 case 'h':
269 return false; /* This will print the usage message */
270 default:
271 return false;
Cyril Burc85e34d2016-11-15 11:50:41 +1100272 }
273 }
274
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100275 if (!context->flash_size) {
Cyril Bure8f2de12017-01-17 16:56:02 +1100276 fprintf(stderr, "Must specify a non-zero flash size\n");
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100277 return false;
Cyril Bure8f2de12017-01-17 16:56:02 +1100278 }
279
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000280 MSG_INFO("Flash size: 0x%.8x\n", context->flash_size);
Cyril Burc85e34d2016-11-15 11:50:41 +1100281
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100282 if (verbosity) {
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000283 MSG_INFO("%s logging\n", verbosity == MBOX_LOG_DEBUG ? "Debug" :
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100284 "Verbose");
Cyril Burc85e34d2016-11-15 11:50:41 +1100285 }
286
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100287 return true;
Cyril Burc85e34d2016-11-15 11:50:41 +1100288}
289
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100290int main(int argc, char **argv)
291{
292 struct mbox_context *context;
293 char *name = argv[0];
294 sigset_t set;
295 int rc, i;
296
297 context = calloc(1, sizeof(*context));
298 if (!context) {
299 fprintf(stderr, "Memory allocation failed\n");
300 exit(1);
301 }
302
303 if (!parse_cmdline(argc, argv, context)) {
304 usage(name);
305 free(context);
306 exit(0);
307 }
308
309 for (i = 0; i < TOTAL_FDS; i++) {
310 context->fds[i].fd = -1;
311 }
312
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000313 MSG_INFO("Starting Daemon\n");
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100314
315 rc = init_signals(context, &set);
316 if (rc) {
317 goto finish;
318 }
319
320 rc = init_mbox_dev(context);
321 if (rc) {
322 goto finish;
323 }
324
325 rc = init_lpc_dev(context);
326 if (rc) {
327 goto finish;
328 }
329
330 /* We've found the reserved memory region -> we can assign to windows */
Suraj Jitindar Singhc29172e2017-04-12 14:26:47 +1000331 rc = init_windows(context);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100332 if (rc) {
333 goto finish;
334 }
335
336 rc = init_flash_dev(context);
337 if (rc) {
338 goto finish;
339 }
340
341 rc = init_mboxd_dbus(context);
342 if (rc) {
343 goto finish;
344 }
345
Deepak Kodihalli017e45c2017-07-12 01:06:30 -0500346#ifdef VIRTUAL_PNOR_ENABLED
347 vpnor_create_partition_table(context);
348
349 strcpy(context->paths.ro_loc, PARTITION_FILES_RO_LOC);
350 strcpy(context->paths.rw_loc, PARTITION_FILES_RW_LOC);
351 strcpy(context->paths.prsv_loc, PARTITION_FILES_PRSV_LOC);
352#endif
353
354 /* Set the LPC bus mapping */
355 rc = reset_lpc(context);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100356 if (rc) {
357 goto finish;
358 }
359
360 rc = set_bmc_events(context, BMC_EVENT_DAEMON_READY, SET_BMC_EVENT);
361 if (rc) {
362 goto finish;
363 }
364
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000365 MSG_INFO("Entering Polling Loop\n");
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100366 rc = poll_loop(context);
367
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000368 MSG_INFO("Exiting Poll Loop: %d\n", rc);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100369
370finish:
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000371 MSG_INFO("Daemon Exiting...\n");
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100372 clr_bmc_events(context, BMC_EVENT_DAEMON_READY, SET_BMC_EVENT);
373
374 free_mboxd_dbus(context);
375 free_flash_dev(context);
376 free_lpc_dev(context);
377 free_mbox_dev(context);
Suraj Jitindar Singhc29172e2017-04-12 14:26:47 +1000378 free_windows(context);
Deepak Kodihalli6c2fa902017-05-01 06:36:02 -0500379#ifdef VIRTUAL_PNOR_ENABLED
380 vpnor_destroy_partition_table(context);
381#endif
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100382 free(context);
383
384 return rc;
385}