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 "mbox.h" 46 #include "common.h" 47 #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" 53 54 #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\t\t\t(default: fill the reserved memory region)\n" \ 63 "\t-w | --window-size\tThe window size (power of 2) in MB\n" \ 64 "\t\t\t\t(default: 1MB)\n" \ 65 "\t-f | --flash\t\tSize of flash in [K|M] bytes\n\n" 66 67 static int poll_loop(struct mbox_context *context) 68 { 69 int rc = 0, i; 70 71 /* Set POLLIN on polling file descriptors */ 72 for (i = 0; i < POLL_FDS; i++) { 73 context->fds[i].events = POLLIN; 74 } 75 76 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; 147 } 148 149 static int init_signals(struct mbox_context *context, sigset_t *set) 150 { 151 int rc; 152 153 /* 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; 162 } 163 164 /* 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; 169 } 170 171 context->fds[SIG_FD].fd = rc; 172 return 0; 173 } 174 175 static void usage(const char *name) 176 { 177 printf(USAGE, name); 178 } 179 180 static bool parse_cmdline(int argc, char **argv, 181 struct mbox_context *context) 182 { 183 char *endptr; 184 int opt; 185 186 static const struct option long_options[] = { 187 { "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 } 195 }; 196 197 verbosity = MBOX_LOG_NONE; 198 mbox_vlog = &mbox_log_console; 199 200 context->current = NULL; /* No current window */ 201 202 while ((opt = getopt_long(argc, argv, "f:w::n::vsVh", long_options, NULL)) 203 != -1) { 204 switch (opt) { 205 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': 215 break; 216 case 'M': 217 context->flash_size <<= 10; 218 case 'K': 219 context->flash_size <<= 10; 220 break; 221 default: 222 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 } 244 if (!is_power_of_2(context->windows.default_size)) { 245 fprintf(stderr, "Window size not power of 2\n"); 246 return false; 247 } 248 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; 267 } 268 } 269 270 if (!context->flash_size) { 271 fprintf(stderr, "Must specify a non-zero flash size\n"); 272 return false; 273 } 274 275 MSG_OUT("Flash size: 0x%.8x\n", context->flash_size); 276 277 if (verbosity) { 278 MSG_OUT("%s logging\n", verbosity == MBOX_LOG_DEBUG ? "Debug" : 279 "Verbose"); 280 } 281 282 return true; 283 } 284 285 int 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 */ 326 rc = init_windows(context); 327 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 357 finish: 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); 365 free_windows(context); 366 free(context); 367 368 return rc; 369 } 370