10 #include <asm/byteorder.h>
12 #include <file/file.h>
13 #include <talloc/talloc.h>
14 #include <list/list.h>
16 #include <process/process.h>
23 static const char *partition = "common";
24 static const char *sysparams_dir = "/sys/firmware/opal/sysparams/";
25 static const char *devtree_dir = "/proc/device-tree/";
27 struct platform_powerpc {
28 struct param_list *params;
30 int (*get_ipmi_bootdev)(
31 struct platform_powerpc *platform,
32 uint8_t *bootdev, bool *persistent);
33 int (*clear_ipmi_bootdev)(
34 struct platform_powerpc *platform,
36 int (*set_os_boot_sensor)(
37 struct platform_powerpc *platform);
38 void (*get_platform_versions)(struct system_info *info);
41 #define to_platform_powerpc(p) \
42 (struct platform_powerpc *)(p->platform_data)
44 static int parse_nvram_params(struct platform_powerpc *platform,
47 char *pos, *name, *value;
48 unsigned int paramlen;
51 /* discard 2 header lines:
58 for (i = 0; i < len; i++) {
66 fprintf(stderr, "failure parsing nvram output\n");
70 for (pos = buf + i; pos < buf + len; pos += paramlen + 1) {
74 newline = strchr(pos, '\n');
80 paramlen = strlen(pos);
83 value = strchr(pos, '=');
87 namelen = value - name;
91 if (!param_list_is_known_n(platform->params, name, namelen))
97 param_list_set(platform->params, name, value, false);
103 static int parse_nvram(struct platform_powerpc *platform)
105 struct process_stdout *stdout;
110 argv[1] = "--print-config";
111 argv[2] = "--partition";
115 rc = process_get_stdout_argv(NULL, &stdout, argv);
118 fprintf(stderr, "nvram process returned "
119 "non-zero exit status\n");
122 rc = parse_nvram_params(platform, stdout->buf, stdout->len);
129 static int write_nvram(struct platform_powerpc *platform)
131 struct process *process;
137 argv[1] = "--update-config";
139 argv[3] = "--partition";
143 process = process_create(platform);
144 process->path = "nvram";
145 process->argv = argv;
147 param_list_for_each(platform->params, param) {
150 if (!param->modified)
153 paramstr = talloc_asprintf(platform, "%s=%s",
154 param->name, param->value);
157 rc = process_run_sync(process);
159 talloc_free(paramstr);
161 if (rc || !process_exit_ok(process)) {
163 pb_log("nvram update process returned "
164 "non-zero exit status\n");
169 process_release(process);
173 static void params_update_all(struct param_list *pl,
174 const struct config *config, const struct config *defaults)
179 if (config->autoboot_enabled == defaults->autoboot_enabled)
182 val = config->autoboot_enabled ? "true" : "false";
184 param_list_set_non_empty(pl, "auto-boot?", val, true);
186 if (config->autoboot_timeout_sec == defaults->autoboot_timeout_sec)
189 val = tmp = talloc_asprintf(pl, "%d",
190 config->autoboot_timeout_sec);
192 param_list_set_non_empty(pl, "petitboot,timeout", val, true);
196 val = config->lang ?: "";
197 param_list_set_non_empty(pl, "petitboot,language", val, true);
199 if (config->allow_writes == defaults->allow_writes)
202 val = config->allow_writes ? "true" : "false";
203 param_list_set_non_empty(pl, "petitboot,write?", val, true);
205 if (!config->manual_console) {
206 val = config->boot_console ?: "";
207 param_list_set_non_empty(pl, "petitboot,console", val, true);
210 val = config->http_proxy ?: "";
211 param_list_set_non_empty(pl, "petitboot,http_proxy", val, true);
212 val = config->https_proxy ?: "";
213 param_list_set_non_empty(pl, "petitboot,https_proxy", val, true);
215 params_update_network_values(pl, "petitboot,network", config);
216 params_update_bootdev_values(pl, "petitboot,bootdevs", config);
219 static void config_set_ipmi_bootdev(struct config *config, enum ipmi_bootdev bootdev,
222 config->ipmi_bootdev = bootdev;
223 config->ipmi_bootdev_persistent = persistent;
225 if (bootdev == IPMI_BOOTDEV_SAFE)
226 config->safe_mode = true;
229 static int read_bootdev_sysparam(const char *name, uint8_t *val)
235 assert(strlen(sysparams_dir) + strlen(name) < sizeof(path));
236 snprintf(path, sizeof(path), "%s%s", sysparams_dir, name);
238 fd = open(path, O_RDONLY);
240 pb_debug("powerpc: can't access sysparam %s\n",
245 rc = read(fd, buf, sizeof(buf));
249 /* bootdev definitions should only be one byte in size */
251 pb_debug("powerpc: sysparam %s read returned %d\n",
256 pb_debug("powerpc: sysparam %s: 0x%02x\n", name, buf[0]);
258 if (!ipmi_bootdev_is_valid(buf[0]))
265 static int write_bootdev_sysparam(const char *name, uint8_t val)
270 assert(strlen(sysparams_dir) + strlen(name) < sizeof(path));
271 snprintf(path, sizeof(path), "%s%s", sysparams_dir, name);
273 fd = open(path, O_WRONLY);
275 pb_debug("powerpc: can't access sysparam %s for writing\n",
282 rc = write(fd, &val, sizeof(val));
283 if (rc == sizeof(val)) {
288 if (rc <= 0 && errno != EINTR) {
289 pb_log("powerpc: error updating sysparam %s: %s",
290 name, strerror(errno));
299 pb_debug("powerpc: set sysparam %s: 0x%02x\n", name, val);
304 static int clear_ipmi_bootdev_sysparams(
305 struct platform_powerpc *platform __attribute__((unused)),
309 /* invalidate default-boot-device setting */
310 write_bootdev_sysparam("default-boot-device", 0xff);
312 /* invalidate next-boot-device setting */
313 write_bootdev_sysparam("next-boot-device", 0xff);
318 static int get_ipmi_bootdev_sysparams(
319 struct platform_powerpc *platform __attribute__((unused)),
320 uint8_t *bootdev, bool *persistent)
322 uint8_t next_bootdev, default_bootdev;
323 bool next_valid, default_valid;
326 rc = read_bootdev_sysparam("next-boot-device", &next_bootdev);
327 next_valid = rc == 0;
329 rc = read_bootdev_sysparam("default-boot-device", &default_bootdev);
330 default_valid = rc == 0;
332 /* nothing valid? no need to change the config */
333 if (!next_valid && !default_valid)
336 *persistent = !next_valid;
337 *bootdev = next_valid ? next_bootdev : default_bootdev;
341 static int clear_ipmi_bootdev_ipmi(struct platform_powerpc *platform,
342 bool persistent __attribute__((unused)))
347 0x05, /* parameter selector: boot flags */
348 0x80, /* data 1: valid */
349 0x00, /* data 2: bootdev: no override */
350 0x00, /* data 3: system defaults */
351 0x00, /* data 4: no request for shared mode, mux defaults */
352 0x00, /* data 5: no instance request */
355 resp_len = sizeof(resp);
357 ipmi_transaction(platform->ipmi, IPMI_NETFN_CHASSIS,
358 IPMI_CMD_CHASSIS_SET_SYSTEM_BOOT_OPTIONS,
365 static int get_ipmi_bootdev_ipmi(struct platform_powerpc *platform,
366 uint8_t *bootdev, bool *persistent)
373 0x05, /* parameter selector: boot flags */
374 0x00, /* no set selector */
375 0x00, /* no block selector */
378 resp_len = sizeof(resp);
379 rc = ipmi_transaction(platform->ipmi, IPMI_NETFN_CHASSIS,
380 IPMI_CMD_CHASSIS_GET_SYSTEM_BOOT_OPTIONS,
385 pb_log("platform: error reading IPMI boot options\n");
389 if (resp_len != sizeof(resp)) {
390 pb_log("platform: unexpected length (%d) in "
391 "boot options response\n", resp_len);
395 debug_buf = format_buffer(platform, resp, resp_len);
396 pb_debug_fn("IPMI get_bootdev response:\n%s\n", debug_buf);
397 talloc_free(debug_buf);
400 pb_log("platform: non-zero completion code %d from IPMI req\n",
405 /* check for correct parameter version */
406 if ((resp[1] & 0xf) != 0x1) {
407 pb_log("platform: unexpected version (0x%x) in "
408 "boot options response\n", resp[0]);
412 /* check for valid paramters */
413 if (resp[2] & 0x80) {
414 pb_debug("platform: boot options are invalid/locked\n");
420 /* check for valid flags */
421 if (!(resp[3] & 0x80)) {
422 pb_debug("platform: boot flags are invalid, ignoring\n");
426 *persistent = resp[3] & 0x40;
427 *bootdev = (resp[4] >> 2) & 0x0f;
431 static int set_ipmi_os_boot_sensor(struct platform_powerpc *platform)
437 0x00, /* sensor number: os boot */
438 0xA9, /* operation: set everything */
439 0x00, /* sensor reading: none */
440 0x40, /* assertion mask lsb: set state 6 */
441 0x00, /* assertion mask msb: none */
442 0x00, /* deassertion mask lsb: none */
443 0x00, /* deassertion mask msb: none */
444 0x00, /* event data 1: none */
445 0x00, /* event data 2: none */
446 0x00, /* event data 3: none */
449 sensor_number = get_ipmi_sensor(platform, IPMI_SENSOR_ID_OS_BOOT);
450 if (sensor_number < 0) {
451 pb_log("Couldn't find OS boot sensor in device tree\n");
455 req[0] = sensor_number;
457 resp_len = sizeof(resp);
459 ipmi_transaction(platform->ipmi, IPMI_NETFN_SE,
463 ipmi_timeout); return 0;
468 static void get_ipmi_network_override(struct platform_powerpc *platform,
469 struct config *config)
471 uint16_t min_len = 12, resp_len = 53, version;
472 const uint32_t magic_value = 0x21706221;
473 uint8_t resp[resp_len];
479 0x61, /* parameter selector: OEM section (network) */
480 0x00, /* no set selector */
481 0x00, /* no block selector */
484 rc = ipmi_transaction(platform->ipmi, IPMI_NETFN_CHASSIS,
485 IPMI_CMD_CHASSIS_GET_SYSTEM_BOOT_OPTIONS,
490 debug_buf = format_buffer(platform, resp, resp_len);
491 pb_debug_fn("IPMI net override response:\n%s\n", debug_buf);
492 talloc_free(debug_buf);
495 pb_debug("IPMI network config option unavailable\n");
499 if (resp_len < min_len) {
500 pb_debug("IPMI net response too small\n");
505 pb_log("platform: non-zero completion code %d from IPMI network req\n",
510 /* Check for correct parameter version */
511 if ((resp[1] & 0xf) != 0x1) {
512 pb_log("platform: unexpected version (0x%x) in network override response\n",
517 /* Check that the parameters are valid */
518 if (resp[2] & 0x80) {
519 pb_debug("platform: network override is invalid/locked\n");
523 /* Check for valid parameters in the boot flags section */
524 if (!(resp[3] & 0x80)) {
525 pb_debug("platform: network override valid flag not set\n");
528 /* Read the persistent flag; if it is set we need to save this config */
529 persistent = resp[3] & 0x40;
531 pb_debug("platform: network override is persistent\n");
533 /* Check 4-byte cookie value */
535 memcpy(&cookie, &resp[i], sizeof(cookie));
536 cookie = __be32_to_cpu(cookie);
537 if (cookie != magic_value) {
538 pb_log_fn("Incorrect cookie %x\n", cookie);
543 /* Check 2-byte version number */
544 memcpy(&version, &resp[i], sizeof(version));
545 version = __be16_to_cpu(version);
546 i += sizeof(version);
548 pb_debug("Unexpected version: %u\n", version);
552 /* Interpret the rest of the interface config */
553 rc = parse_ipmi_interface_override(config, &resp[i], resp_len - i);
555 if (!rc && persistent) {
556 /* Write this new config to NVRAM */
557 params_update_network_values(platform->params,
558 "petitboot,network", config);
559 rc = write_nvram(platform);
561 pb_log("platform: Failed to save persistent interface override\n");
565 static void config_get_active_consoles(struct config *config)
568 char *fsp_prop = NULL;
570 config->n_consoles = 2;
571 config->consoles = talloc_array(config, char *, config->n_consoles);
572 if (!config->consoles)
575 config->consoles[0] = talloc_asprintf(config->consoles,
576 "/dev/hvc0 [IPMI / Serial]");
577 config->consoles[1] = talloc_asprintf(config->consoles,
580 fsp_prop = talloc_asprintf(config, "%sfsps", devtree_dir);
581 if (stat(fsp_prop, &sbuf) == 0) {
582 /* FSP based machines also have a separate serial console */
583 config->consoles = talloc_realloc(config, config->consoles,
584 char *, config->n_consoles + 1);
585 if (!config->consoles)
587 config->consoles[config->n_consoles++] = talloc_asprintf(
589 "/dev/hvc1 [Serial]");
594 config->n_consoles = 0;
595 pb_log("Failed to allocate memory for consoles\n");
598 static int load_config(struct platform *p, struct config *config)
600 struct platform_powerpc *platform = to_platform_powerpc(p);
603 rc = parse_nvram(platform);
605 pb_log_fn("Failed to parse nvram\n");
607 config_populate_all(config, platform->params);
609 if (platform->get_ipmi_bootdev) {
610 bool bootdev_persistent;
611 uint8_t bootdev = IPMI_BOOTDEV_INVALID;
612 rc = platform->get_ipmi_bootdev(platform, &bootdev,
613 &bootdev_persistent);
614 if (!rc && ipmi_bootdev_is_valid(bootdev)) {
615 config_set_ipmi_bootdev(config, bootdev,
621 get_ipmi_network_override(platform, config);
623 config_get_active_consoles(config);
628 static int save_config(struct platform *p, struct config *config)
630 struct platform_powerpc *platform = to_platform_powerpc(p);
631 struct config *defaults;
633 if (config->ipmi_bootdev == IPMI_BOOTDEV_INVALID &&
634 platform->clear_ipmi_bootdev) {
635 platform->clear_ipmi_bootdev(platform,
636 config->ipmi_bootdev_persistent);
637 config->ipmi_bootdev = IPMI_BOOTDEV_NONE;
638 config->ipmi_bootdev_persistent = false;
641 defaults = talloc_zero(platform, struct config);
642 config_set_defaults(defaults);
644 params_update_all(platform->params, config, defaults);
646 talloc_free(defaults);
647 return write_nvram(platform);
650 static void pre_boot(struct platform *p, const struct config *config)
652 struct platform_powerpc *platform = to_platform_powerpc(p);
654 if (!config->ipmi_bootdev_persistent && platform->clear_ipmi_bootdev)
655 platform->clear_ipmi_bootdev(platform, false);
657 if (platform->set_os_boot_sensor)
658 platform->set_os_boot_sensor(platform);
661 static int get_sysinfo(struct platform *p, struct system_info *sysinfo)
663 struct platform_powerpc *platform = p->platform_data;
664 char *buf, *filename;
667 filename = talloc_asprintf(platform, "%smodel", devtree_dir);
668 rc = read_file(platform, filename, &buf, &len);
670 sysinfo->type = talloc_steal(sysinfo, buf);
671 talloc_free(filename);
673 filename = talloc_asprintf(platform, "%ssystem-id", devtree_dir);
674 rc = read_file(platform, filename, &buf, &len);
676 sysinfo->identifier = talloc_steal(sysinfo, buf);
677 talloc_free(filename);
679 sysinfo->bmc_mac = talloc_zero_size(sysinfo, HWADDR_SIZE);
681 if (platform->ipmi) {
682 ipmi_get_bmc_mac(platform->ipmi, sysinfo->bmc_mac);
683 ipmi_get_bmc_versions(platform->ipmi, sysinfo);
686 if (platform->get_platform_versions)
687 platform->get_platform_versions(sysinfo);
692 static bool probe(struct platform *p, void *ctx)
694 struct platform_powerpc *platform;
699 /* we need a device tree */
700 rc = stat("/proc/device-tree", &statbuf);
704 if (!S_ISDIR(statbuf.st_mode))
707 platform = talloc_zero(ctx, struct platform_powerpc);
708 platform->params = talloc_zero(platform, struct param_list);
709 param_list_init(platform->params, common_known_params());
711 p->platform_data = platform;
713 bmc_present = stat("/proc/device-tree/bmc", &statbuf) == 0;
715 if (ipmi_present() && bmc_present) {
716 pb_debug("platform: using direct IPMI for IPMI paramters\n");
717 platform->ipmi = ipmi_open(platform);
718 platform->get_ipmi_bootdev = get_ipmi_bootdev_ipmi;
719 platform->clear_ipmi_bootdev = clear_ipmi_bootdev_ipmi;
720 platform->set_os_boot_sensor = set_ipmi_os_boot_sensor;
721 } else if (!stat(sysparams_dir, &statbuf)) {
722 pb_debug("platform: using sysparams for IPMI paramters\n");
723 platform->get_ipmi_bootdev = get_ipmi_bootdev_sysparams;
724 platform->clear_ipmi_bootdev = clear_ipmi_bootdev_sysparams;
727 pb_log("platform: no IPMI parameter support\n");
731 platform->get_platform_versions = hostboot_load_versions;
737 static struct platform platform_powerpc = {
739 .dhcp_arch_id = 0x000e,
741 .load_config = load_config,
742 .save_config = save_config,
743 .pre_boot = pre_boot,
744 .get_sysinfo = get_sysinfo,
747 register_platform(platform_powerpc);