1 /* 2 * Mailbox Daemon Implementation 3 * 4 * Copyright 2016 IBM 5 * 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 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * 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. 17 * 18 */ 19 20 #define _GNU_SOURCE 21 #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> 33 #include <signal.h> 34 #include <sys/ioctl.h> 35 #include <sys/mman.h> 36 #include <sys/stat.h> 37 #include <sys/timerfd.h> 38 #include <sys/types.h> 39 #include <sys/signalfd.h> 40 #include <time.h> 41 #include <unistd.h> 42 #include <inttypes.h> 43 #include <systemd/sd-bus.h> 44 45 #include "config.h" 46 #include "mbox.h" 47 #include "common.h" 48 #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" 54 55 #define USAGE \ 56 "\nUsage: %s [-V | --version] [-h | --help] [-v[v] | --verbose] [-s | --syslog]\n" \ 57 "\t\t[-n | --window-num <num>]\n" \ 58 "\t\t[-w | --window-size <size>M]\n" \ 59 "\t\t-f | --flash <size>[K|M]\n\n" \ 60 "\t-v | --verbose\t\tBe [more] verbose\n" \ 61 "\t-s | --syslog\t\tLog output to syslog (pointless without -v)\n" \ 62 "\t-n | --window-num\tThe number of windows\n" \ 63 "\t\t\t\t(default: fill the reserved memory region)\n" \ 64 "\t-w | --window-size\tThe window size (power of 2) in MB\n" \ 65 "\t\t\t\t(default: 1MB)\n" \ 66 "\t-f | --flash\t\tSize of flash in [K|M] bytes\n\n" 67 68 static int poll_loop(struct mbox_context *context) 69 { 70 int rc = 0, i; 71 72 /* Set POLLIN on polling file descriptors */ 73 for (i = 0; i < POLL_FDS; i++) { 74 context->fds[i].events = POLLIN; 75 } 76 77 while (1) { 78 rc = poll(context->fds, POLL_FDS, -1); 79 80 if (rc < 0) { /* Error */ 81 MSG_ERR("Error from poll(): %s\n", strerror(errno)); 82 break; /* This should mean we clean up nicely */ 83 } 84 85 /* Event on Polled File Descriptor - Handle It */ 86 if (context->fds[SIG_FD].revents & POLLIN) { /* Signal */ 87 struct signalfd_siginfo info = { 0 }; 88 89 rc = read(context->fds[SIG_FD].fd, (void *) &info, 90 sizeof(info)); 91 if (rc != sizeof(info)) { 92 MSG_ERR("Error reading signal event: %s\n", 93 strerror(errno)); 94 } 95 96 MSG_DBG("Received signal: %d\n", info.ssi_signo); 97 switch (info.ssi_signo) { 98 case SIGINT: 99 case SIGTERM: 100 MSG_INFO("Caught Signal - Exiting...\n"); 101 context->terminate = true; 102 break; 103 case SIGHUP: 104 /* Host didn't request reset -> Notify it */ 105 reset_all_windows(context, SET_BMC_EVENT); 106 rc = point_to_flash(context); 107 if (rc < 0) { 108 MSG_ERR("WARNING: Failed to point the " 109 "LPC bus back to flash on " 110 "SIGHUP\nIf the host requires " 111 "this expect problems...\n"); 112 } 113 break; 114 default: 115 MSG_ERR("Unhandled Signal: %d\n", 116 info.ssi_signo); 117 break; 118 } 119 } 120 if (context->fds[DBUS_FD].revents & POLLIN) { /* DBUS */ 121 while ((rc = sd_bus_process(context->bus, NULL)) > 0) { 122 MSG_DBG("DBUS Event\n"); 123 } 124 if (rc < 0) { 125 MSG_ERR("Error handling DBUS event: %s\n", 126 strerror(-rc)); 127 } 128 } 129 if (context->terminate) { 130 break; /* This should mean we clean up nicely */ 131 } 132 if (context->fds[MBOX_FD].revents & POLLIN) { /* MBOX */ 133 MSG_DBG("MBOX Event\n"); 134 rc = dispatch_mbox(context); 135 if (rc < 0) { 136 MSG_ERR("Error handling MBOX event\n"); 137 } 138 } 139 } 140 141 /* Best to reset windows and point back to flash for safety */ 142 /* Host didn't request reset -> Notify it */ 143 reset_all_windows(context, SET_BMC_EVENT); 144 rc = point_to_flash(context); 145 /* Not much we can do if this fails */ 146 if (rc < 0) { 147 MSG_ERR("WARNING: Failed to point the LPC bus back to flash\n" 148 "If the host requires this expect problems...\n"); 149 } 150 151 return rc; 152 } 153 154 static int init_signals(struct mbox_context *context, sigset_t *set) 155 { 156 int rc; 157 158 /* Block SIGHUPs, SIGTERMs and SIGINTs */ 159 sigemptyset(set); 160 sigaddset(set, SIGHUP); 161 sigaddset(set, SIGINT); 162 sigaddset(set, SIGTERM); 163 rc = sigprocmask(SIG_BLOCK, set, NULL); 164 if (rc < 0) { 165 MSG_ERR("Failed to set SIG_BLOCK mask %s\n", strerror(errno)); 166 return rc; 167 } 168 169 /* Get Signal File Descriptor */ 170 rc = signalfd(-1, set, SFD_NONBLOCK); 171 if (rc < 0) { 172 MSG_ERR("Failed to get signalfd %s\n", strerror(errno)); 173 return rc; 174 } 175 176 context->fds[SIG_FD].fd = rc; 177 return 0; 178 } 179 180 static void usage(const char *name) 181 { 182 printf(USAGE, name); 183 } 184 185 static bool parse_cmdline(int argc, char **argv, 186 struct mbox_context *context) 187 { 188 char *endptr; 189 int opt; 190 191 static const struct option long_options[] = { 192 { "flash", required_argument, 0, 'f' }, 193 { "window-size", optional_argument, 0, 'w' }, 194 { "window-num", optional_argument, 0, 'n' }, 195 { "verbose", no_argument, 0, 'v' }, 196 { "syslog", no_argument, 0, 's' }, 197 { "version", no_argument, 0, 'V' }, 198 { "help", no_argument, 0, 'h' }, 199 { 0, 0, 0, 0 } 200 }; 201 202 verbosity = MBOX_LOG_NONE; 203 mbox_vlog = &mbox_log_console; 204 205 context->current = NULL; /* No current window */ 206 207 while ((opt = getopt_long(argc, argv, "f:w::n::vsVh", long_options, NULL)) 208 != -1) { 209 switch (opt) { 210 case 0: 211 break; 212 case 'f': 213 context->flash_size = strtol(optarg, &endptr, 10); 214 if (optarg == endptr) { 215 fprintf(stderr, "Unparseable flash size\n"); 216 return false; 217 } 218 switch (*endptr) { 219 case '\0': 220 break; 221 case 'M': 222 context->flash_size <<= 10; 223 case 'K': 224 context->flash_size <<= 10; 225 break; 226 default: 227 fprintf(stderr, "Unknown units '%c'\n", 228 *endptr); 229 return false; 230 } 231 break; 232 case 'n': 233 context->windows.num = strtol(argv[optind], &endptr, 234 10); 235 if (optarg == endptr || *endptr != '\0') { 236 fprintf(stderr, "Unparseable window num\n"); 237 return false; 238 } 239 break; 240 case 'w': 241 context->windows.default_size = strtol(argv[optind], 242 &endptr, 10); 243 context->windows.default_size <<= 20; /* Given in MB */ 244 if (optarg == endptr || (*endptr != '\0' && 245 *endptr != 'M')) { 246 fprintf(stderr, "Unparseable window size\n"); 247 return false; 248 } 249 if (!is_power_of_2(context->windows.default_size)) { 250 fprintf(stderr, "Window size not power of 2\n"); 251 return false; 252 } 253 break; 254 case 'v': 255 verbosity++; 256 break; 257 case 's': 258 /* Avoid a double openlog() */ 259 if (mbox_vlog != &vsyslog) { 260 openlog(PREFIX, LOG_ODELAY, LOG_DAEMON); 261 mbox_vlog = &vsyslog; 262 } 263 break; 264 case 'V': 265 printf("%s V%s\n", THIS_NAME, PACKAGE_VERSION); 266 exit(0); 267 case 'h': 268 return false; /* This will print the usage message */ 269 default: 270 return false; 271 } 272 } 273 274 if (!context->flash_size) { 275 fprintf(stderr, "Must specify a non-zero flash size\n"); 276 return false; 277 } 278 279 MSG_INFO("Flash size: 0x%.8x\n", context->flash_size); 280 281 if (verbosity) { 282 MSG_INFO("%s logging\n", verbosity == MBOX_LOG_DEBUG ? "Debug" : 283 "Verbose"); 284 } 285 286 return true; 287 } 288 289 int main(int argc, char **argv) 290 { 291 struct mbox_context *context; 292 char *name = argv[0]; 293 sigset_t set; 294 int rc, i; 295 296 context = calloc(1, sizeof(*context)); 297 if (!context) { 298 fprintf(stderr, "Memory allocation failed\n"); 299 exit(1); 300 } 301 302 if (!parse_cmdline(argc, argv, context)) { 303 usage(name); 304 free(context); 305 exit(0); 306 } 307 308 for (i = 0; i < TOTAL_FDS; i++) { 309 context->fds[i].fd = -1; 310 } 311 312 MSG_INFO("Starting Daemon\n"); 313 314 rc = init_signals(context, &set); 315 if (rc) { 316 goto finish; 317 } 318 319 rc = init_mbox_dev(context); 320 if (rc) { 321 goto finish; 322 } 323 324 rc = init_lpc_dev(context); 325 if (rc) { 326 goto finish; 327 } 328 329 /* We've found the reserved memory region -> we can assign to windows */ 330 rc = init_windows(context); 331 if (rc) { 332 goto finish; 333 } 334 335 rc = init_flash_dev(context); 336 if (rc) { 337 goto finish; 338 } 339 340 rc = init_mboxd_dbus(context); 341 if (rc) { 342 goto finish; 343 } 344 345 /* Set the LPC bus mapping to point to the physical flash device */ 346 rc = point_to_flash(context); 347 if (rc) { 348 goto finish; 349 } 350 351 rc = set_bmc_events(context, BMC_EVENT_DAEMON_READY, SET_BMC_EVENT); 352 if (rc) { 353 goto finish; 354 } 355 356 MSG_INFO("Entering Polling Loop\n"); 357 rc = poll_loop(context); 358 359 MSG_INFO("Exiting Poll Loop: %d\n", rc); 360 361 finish: 362 MSG_INFO("Daemon Exiting...\n"); 363 clr_bmc_events(context, BMC_EVENT_DAEMON_READY, SET_BMC_EVENT); 364 365 free_mboxd_dbus(context); 366 free_flash_dev(context); 367 free_lpc_dev(context); 368 free_mbox_dev(context); 369 free_windows(context); 370 free(context); 371 372 return rc; 373 } 374