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