1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright (C) 2018 IBM Corp. 3 4 #define _GNU_SOURCE 5 #include <assert.h> 6 #include <errno.h> 7 #include <fcntl.h> 8 #include <getopt.h> 9 #include <limits.h> 10 #include <poll.h> 11 #include <stdbool.h> 12 #include <stdint.h> 13 #include <stdio.h> 14 #include <stdlib.h> 15 #include <string.h> 16 #include <syslog.h> 17 #include <signal.h> 18 #include <sys/ioctl.h> 19 #include <sys/mman.h> 20 #include <sys/stat.h> 21 #include <sys/timerfd.h> 22 #include <sys/types.h> 23 #include <sys/signalfd.h> 24 #include <time.h> 25 #include <unistd.h> 26 #include <inttypes.h> 27 #include <systemd/sd-bus.h> 28 29 #include "config.h" 30 #include "mboxd.h" 31 #include "common.h" 32 #include "dbus.h" 33 #include "control_dbus.h" 34 #include "flash.h" 35 #include "lpc.h" 36 #include "transport_mbox.h" 37 #include "transport_dbus.h" 38 #include "windows.h" 39 #include "vpnor/mboxd_pnor_partition_table.h" 40 41 #define USAGE \ 42 "\nUsage: %s [-V | --version] [-h | --help] [-v[v] | --verbose] [-s | --syslog]\n" \ 43 "\t\t[-n | --window-num <num>]\n" \ 44 "\t\t[-w | --window-size <size>M]\n" \ 45 "\t\t-f | --flash <size>[K|M]\n\n" \ 46 "\t-v | --verbose\t\tBe [more] verbose\n" \ 47 "\t-s | --syslog\t\tLog output to syslog (pointless without -v)\n" \ 48 "\t-n | --window-num\tThe number of windows\n" \ 49 "\t\t\t\t(default: fill the reserved memory region)\n" \ 50 "\t-w | --window-size\tThe window size (power of 2) in MB\n" \ 51 "\t\t\t\t(default: 1MB)\n" \ 52 "\t-f | --flash\t\tSize of flash in [K|M] bytes\n\n" 53 54 static int dbus_init(struct mbox_context *context, 55 const struct transport_ops **ops) 56 { 57 int rc; 58 59 rc = sd_bus_default_system(&context->bus); 60 if (rc < 0) { 61 MSG_ERR("Failed to connect to the system bus: %s\n", 62 strerror(-rc)); 63 return rc; 64 } 65 66 rc = control_legacy_init(context); 67 if (rc < 0) { 68 MSG_ERR("Failed to initialise legacy DBus interface: %s\n", 69 strerror(-rc)); 70 return rc; 71 } 72 73 rc = control_dbus_init(context); 74 if (rc < 0) { 75 MSG_ERR("Failed to initialise DBus control interface: %s\n", 76 strerror(-rc)); 77 return rc; 78 } 79 80 rc = transport_dbus_init(context, ops); 81 if (rc < 0) { 82 MSG_ERR("Failed to initialise DBus protocol interface: %s\n", 83 strerror(-rc)); 84 return rc; 85 } 86 87 rc = sd_bus_request_name(context->bus, MBOX_DBUS_NAME, 88 SD_BUS_NAME_ALLOW_REPLACEMENT | 89 SD_BUS_NAME_REPLACE_EXISTING); 90 if (rc < 0) { 91 MSG_ERR("Failed to request DBus name: %s\n", strerror(-rc)); 92 return rc; 93 } 94 95 rc = sd_bus_get_fd(context->bus); 96 if (rc < 0) { 97 MSG_ERR("Failed to get bus fd: %s\n", strerror(-rc)); 98 return rc; 99 } 100 101 context->fds[DBUS_FD].fd = rc; 102 103 return 0; 104 } 105 106 static void dbus_free(struct mbox_context *context) 107 { 108 transport_dbus_free(context); 109 control_dbus_free(context); 110 control_legacy_free(context); 111 sd_bus_unref(context->bus); 112 } 113 114 static int poll_loop(struct mbox_context *context) 115 { 116 int rc = 0, i; 117 118 /* Set POLLIN on polling file descriptors */ 119 for (i = 0; i < POLL_FDS; i++) { 120 context->fds[i].events = POLLIN; 121 } 122 123 while (1) { 124 rc = poll(context->fds, POLL_FDS, -1); 125 126 if (rc < 0) { /* Error */ 127 MSG_ERR("Error from poll(): %s\n", strerror(errno)); 128 break; /* This should mean we clean up nicely */ 129 } 130 131 /* Event on Polled File Descriptor - Handle It */ 132 if (context->fds[SIG_FD].revents & POLLIN) { /* Signal */ 133 struct signalfd_siginfo info = { 0 }; 134 135 rc = read(context->fds[SIG_FD].fd, (void *) &info, 136 sizeof(info)); 137 if (rc != sizeof(info)) { 138 MSG_ERR("Error reading signal event: %s\n", 139 strerror(errno)); 140 } 141 142 MSG_DBG("Received signal: %d\n", info.ssi_signo); 143 switch (info.ssi_signo) { 144 case SIGINT: 145 case SIGTERM: 146 MSG_INFO("Caught Signal - Exiting...\n"); 147 context->terminate = true; 148 break; 149 case SIGHUP: 150 /* Host didn't request reset -> Notify it */ 151 if (windows_reset_all(context)) { 152 rc = protocol_events_set(context, 153 BMC_EVENT_WINDOW_RESET); 154 if (rc < 0) { 155 MSG_ERR("Failed to notify host of reset, expect host-side corruption\n"); 156 break; 157 } 158 } 159 rc = lpc_reset(context); 160 if (rc < 0) { 161 MSG_ERR("WARNING: Failed to point the " 162 "LPC bus back to flash on " 163 "SIGHUP\nIf the host requires " 164 "this expect problems...\n"); 165 } 166 break; 167 default: 168 MSG_ERR("Unhandled Signal: %d\n", 169 info.ssi_signo); 170 break; 171 } 172 } 173 if (context->fds[DBUS_FD].revents & POLLIN) { /* DBUS */ 174 while ((rc = sd_bus_process(context->bus, NULL)) > 0) { 175 MSG_DBG("DBUS Event\n"); 176 } 177 if (rc < 0) { 178 MSG_ERR("Error handling DBUS event: %s\n", 179 strerror(-rc)); 180 } 181 } 182 if (context->terminate) { 183 break; /* This should mean we clean up nicely */ 184 } 185 if (context->fds[MBOX_FD].revents & POLLIN) { /* MBOX */ 186 MSG_DBG("MBOX Event\n"); 187 rc = transport_mbox_dispatch(context); 188 if (rc < 0) { 189 MSG_ERR("Error handling MBOX event\n"); 190 } 191 } 192 } 193 194 /* Best to reset windows and the lpc mapping for safety */ 195 /* Host didn't request reset -> Notify it */ 196 windows_reset_all(context); 197 198 rc = lpc_reset(context); 199 /* Not much we can do if this fails */ 200 if (rc < 0) { 201 MSG_ERR("WARNING: Failed to point the LPC bus back to flash\n" 202 "If the host requires this expect problems...\n"); 203 } 204 205 return rc; 206 } 207 208 static int init_signals(struct mbox_context *context, sigset_t *set) 209 { 210 int rc; 211 212 /* Block SIGHUPs, SIGTERMs and SIGINTs */ 213 sigemptyset(set); 214 sigaddset(set, SIGHUP); 215 sigaddset(set, SIGINT); 216 sigaddset(set, SIGTERM); 217 rc = sigprocmask(SIG_BLOCK, set, NULL); 218 if (rc < 0) { 219 MSG_ERR("Failed to set SIG_BLOCK mask %s\n", strerror(errno)); 220 return rc; 221 } 222 223 /* Get Signal File Descriptor */ 224 rc = signalfd(-1, set, SFD_NONBLOCK); 225 if (rc < 0) { 226 MSG_ERR("Failed to get signalfd %s\n", strerror(errno)); 227 return rc; 228 } 229 230 context->fds[SIG_FD].fd = rc; 231 return 0; 232 } 233 234 static void usage(const char *name) 235 { 236 printf(USAGE, name); 237 } 238 239 static bool parse_cmdline(int argc, char **argv, 240 struct mbox_context *context) 241 { 242 char *endptr; 243 int opt; 244 245 static const struct option long_options[] = { 246 { "flash", required_argument, 0, 'f' }, 247 { "window-size", optional_argument, 0, 'w' }, 248 { "window-num", optional_argument, 0, 'n' }, 249 { "verbose", no_argument, 0, 'v' }, 250 { "syslog", no_argument, 0, 's' }, 251 { "version", no_argument, 0, 'V' }, 252 { "help", no_argument, 0, 'h' }, 253 { 0, 0, 0, 0 } 254 }; 255 256 verbosity = MBOX_LOG_NONE; 257 mbox_vlog = &mbox_log_console; 258 259 context->current = NULL; /* No current window */ 260 261 while ((opt = getopt_long(argc, argv, "f:w::n::vsVh", long_options, NULL)) 262 != -1) { 263 switch (opt) { 264 case 0: 265 break; 266 case 'f': 267 context->flash_size = strtol(optarg, &endptr, 10); 268 if (optarg == endptr) { 269 fprintf(stderr, "Unparseable flash size\n"); 270 return false; 271 } 272 switch (*endptr) { 273 case '\0': 274 break; 275 case 'M': 276 context->flash_size <<= 10; 277 case 'K': 278 context->flash_size <<= 10; 279 break; 280 default: 281 fprintf(stderr, "Unknown units '%c'\n", 282 *endptr); 283 return false; 284 } 285 break; 286 case 'n': 287 context->windows.num = strtol(argv[optind], &endptr, 288 10); 289 if (optarg == endptr || *endptr != '\0') { 290 fprintf(stderr, "Unparseable window num\n"); 291 return false; 292 } 293 break; 294 case 'w': 295 context->windows.default_size = strtol(argv[optind], 296 &endptr, 10); 297 context->windows.default_size <<= 20; /* Given in MB */ 298 if (optarg == endptr || (*endptr != '\0' && 299 *endptr != 'M')) { 300 fprintf(stderr, "Unparseable window size\n"); 301 return false; 302 } 303 if (!is_power_of_2(context->windows.default_size)) { 304 fprintf(stderr, "Window size not power of 2\n"); 305 return false; 306 } 307 break; 308 case 'v': 309 verbosity++; 310 break; 311 case 's': 312 /* Avoid a double openlog() */ 313 if (mbox_vlog != &vsyslog) { 314 openlog(PREFIX, LOG_ODELAY, LOG_DAEMON); 315 mbox_vlog = &vsyslog; 316 } 317 break; 318 case 'V': 319 printf("%s V%s\n", THIS_NAME, PACKAGE_VERSION); 320 exit(0); 321 case 'h': 322 return false; /* This will print the usage message */ 323 default: 324 return false; 325 } 326 } 327 328 if (!context->flash_size) { 329 fprintf(stderr, "Must specify a non-zero flash size\n"); 330 return false; 331 } 332 333 MSG_INFO("Flash size: 0x%.8x\n", context->flash_size); 334 335 if (verbosity) { 336 MSG_INFO("%s logging\n", verbosity == MBOX_LOG_DEBUG ? "Debug" : 337 "Verbose"); 338 } 339 340 return true; 341 } 342 343 int main(int argc, char **argv) 344 { 345 const struct transport_ops *mbox_ops, *dbus_ops; 346 struct mbox_context *context; 347 char *name = argv[0]; 348 sigset_t set; 349 int rc, i; 350 351 context = calloc(1, sizeof(*context)); 352 if (!context) { 353 fprintf(stderr, "Memory allocation failed\n"); 354 exit(1); 355 } 356 357 if (!parse_cmdline(argc, argv, context)) { 358 usage(name); 359 free(context); 360 exit(0); 361 } 362 363 for (i = 0; i < TOTAL_FDS; i++) { 364 context->fds[i].fd = -1; 365 } 366 367 MSG_INFO("Starting Daemon\n"); 368 369 rc = init_signals(context, &set); 370 if (rc) { 371 goto finish; 372 } 373 374 rc = protocol_init(context); 375 if (rc) { 376 goto finish; 377 } 378 379 rc = transport_mbox_init(context, &mbox_ops); 380 if (rc) { 381 goto finish; 382 } 383 384 rc = lpc_dev_init(context); 385 if (rc) { 386 goto finish; 387 } 388 389 /* We've found the reserved memory region -> we can assign to windows */ 390 rc = windows_init(context); 391 if (rc) { 392 goto finish; 393 } 394 395 rc = flash_dev_init(context); 396 if (rc) { 397 goto finish; 398 } 399 400 rc = dbus_init(context, &dbus_ops); 401 if (rc) { 402 goto finish; 403 } 404 405 #ifdef VIRTUAL_PNOR_ENABLED 406 init_vpnor(context); 407 #endif 408 409 /* Set the LPC bus mapping */ 410 rc = lpc_reset(context); 411 if (rc) { 412 MSG_ERR("LPC configuration failed, RESET required: %d\n", rc); 413 } 414 415 /* We're ready to go, alert the host */ 416 context->bmc_events |= BMC_EVENT_DAEMON_READY; 417 context->bmc_events |= BMC_EVENT_PROTOCOL_RESET; 418 419 /* Alert on all supported transports */ 420 rc = protocol_events_put(context, mbox_ops); 421 if (rc) { 422 goto finish; 423 } 424 425 rc = protocol_events_put(context, dbus_ops); 426 if (rc) { 427 goto finish; 428 } 429 430 MSG_INFO("Entering Polling Loop\n"); 431 rc = poll_loop(context); 432 433 MSG_INFO("Exiting Poll Loop: %d\n", rc); 434 435 finish: 436 MSG_INFO("Daemon Exiting...\n"); 437 context->bmc_events &= ~BMC_EVENT_DAEMON_READY; 438 context->bmc_events |= BMC_EVENT_PROTOCOL_RESET; 439 440 /* Alert on all supported transports */ 441 protocol_events_put(context, mbox_ops); 442 protocol_events_put(context, dbus_ops); 443 444 #ifdef VIRTUAL_PNOR_ENABLED 445 destroy_vpnor(context); 446 #endif 447 dbus_free(context); 448 flash_dev_free(context); 449 lpc_dev_free(context); 450 transport_mbox_free(context); 451 windows_free(context); 452 protocol_free(context); 453 free(context); 454 455 return rc; 456 } 457