discover: Move generic config routines to platform
[petitboot] / discover / platform-powerpc.c
1
2 #include <assert.h>
3 #include <string.h>
4 #include <stdlib.h>
5 #include <errno.h>
6 #include <fcntl.h>
7 #include <sys/types.h>
8 #include <sys/wait.h>
9 #include <sys/stat.h>
10 #include <asm/byteorder.h>
11
12 #include <file/file.h>
13 #include <talloc/talloc.h>
14 #include <list/list.h>
15 #include <log/log.h>
16 #include <process/process.h>
17
18 #include "hostboot.h"
19 #include "platform.h"
20 #include "ipmi.h"
21 #include "dt.h"
22
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/";
26
27 struct platform_powerpc {
28         struct param_list params;
29         struct ipmi     *ipmi;
30         bool            ipmi_bootdev_persistent;
31         int             (*get_ipmi_bootdev)(
32                                 struct platform_powerpc *platform,
33                                 uint8_t *bootdev, bool *persistent);
34         int             (*clear_ipmi_bootdev)(
35                                 struct platform_powerpc *platform,
36                                 bool persistent);
37         int             (*set_os_boot_sensor)(
38                                 struct platform_powerpc *platform);
39         void            (*get_platform_versions)(struct system_info *info);
40 };
41
42 #define to_platform_powerpc(p) \
43         (struct platform_powerpc *)(p->platform_data)
44
45 static int parse_nvram_params(struct platform_powerpc *platform,
46                 char *buf, int len)
47 {
48         char *pos, *name, *value;
49         unsigned int paramlen;
50         int i, count;
51
52         /* discard 2 header lines:
53          * "common" partiton"
54          * ------------------
55          */
56         pos = buf;
57         count = 0;
58
59         for (i = 0; i < len; i++) {
60                 if (pos[i] == '\n')
61                         count++;
62                 if (count == 2)
63                         break;
64         }
65
66         if (i == len) {
67                 fprintf(stderr, "failure parsing nvram output\n");
68                 return -1;
69         }
70
71         for (pos = buf + i; pos < buf + len; pos += paramlen + 1) {
72                 unsigned int namelen;
73                 char *newline;
74
75                 newline = strchr(pos, '\n');
76                 if (!newline)
77                         break;
78
79                 *newline = '\0';
80
81                 paramlen = strlen(pos);
82
83                 name = pos;
84                 value = strchr(pos, '=');
85                 if (!value)
86                         continue;
87
88                 namelen = value - name;
89                 if (namelen == 0)
90                         continue;
91
92                 if (!param_list_is_known_n(&platform->params, name, namelen))
93                         continue;
94
95                 *value = '\0';
96                 value++;
97
98                 param_list_set(&platform->params, name, value, false);
99         }
100
101         return 0;
102 }
103
104 static int parse_nvram(struct platform_powerpc *platform)
105 {
106         struct process_stdout *stdout;
107         const char *argv[5];
108         int rc;
109
110         argv[0] = "nvram";
111         argv[1] = "--print-config";
112         argv[2] = "--partition";
113         argv[3] = partition;
114         argv[4] = NULL;
115
116         rc = process_get_stdout_argv(NULL, &stdout, argv);
117
118         if (rc) {
119                 fprintf(stderr, "nvram process returned "
120                                 "non-zero exit status\n");
121                 rc = -1;
122         } else {
123                 rc = parse_nvram_params(platform, stdout->buf, stdout->len);
124         }
125
126         talloc_free(stdout);
127         return rc;
128 }
129
130 static int write_nvram(struct platform_powerpc *platform)
131 {
132         struct process *process;
133         struct param *param;
134         const char *argv[6];
135         int rc = 0;
136
137         argv[0] = "nvram";
138         argv[1] = "--update-config";
139         argv[2] = NULL;
140         argv[3] = "--partition";
141         argv[4] = partition;
142         argv[5] = NULL;
143
144         process = process_create(platform);
145         process->path = "nvram";
146         process->argv = argv;
147
148         param_list_for_each(&platform->params, param) {
149                 char *paramstr;
150
151                 if (!param->modified)
152                         continue;
153
154                 paramstr = talloc_asprintf(platform, "%s=%s",
155                                 param->name, param->value);
156                 argv[2] = paramstr;
157
158                 rc = process_run_sync(process);
159
160                 talloc_free(paramstr);
161
162                 if (rc || !process_exit_ok(process)) {
163                         rc = -1;
164                         pb_log("nvram update process returned "
165                                         "non-zero exit status\n");
166                         break;
167                 }
168         }
169
170         process_release(process);
171         return rc;
172 }
173
174 static char *interface_config_str(void *ctx, struct interface_config *config)
175 {
176         char *str;
177
178         /* todo: HWADDR size is hardcoded as 6, but we may need to handle
179          * different hardware address formats */
180         str = talloc_asprintf(ctx, "%02x:%02x:%02x:%02x:%02x:%02x,",
181                         config->hwaddr[0], config->hwaddr[1],
182                         config->hwaddr[2], config->hwaddr[3],
183                         config->hwaddr[4], config->hwaddr[5]);
184
185         if (config->ignore) {
186                 str = talloc_asprintf_append(str, "ignore");
187
188         } else if (config->method == CONFIG_METHOD_DHCP) {
189                 str = talloc_asprintf_append(str, "dhcp");
190
191         } else if (config->method == CONFIG_METHOD_STATIC) {
192                 str = talloc_asprintf_append(str, "static,%s%s%s%s%s",
193                                 config->static_config.address,
194                                 config->static_config.gateway ? "," : "",
195                                 config->static_config.gateway ?: "",
196                                 config->static_config.url ? "," : "",
197                                 config->static_config.url ?: "");
198         }
199         return str;
200 }
201
202 static char *dns_config_str(void *ctx, const char **dns_servers, int n)
203 {
204         char *str;
205         int i;
206
207         str = talloc_strdup(ctx, "dns,");
208         for (i = 0; i < n; i++) {
209                 str = talloc_asprintf_append(str, "%s%s",
210                                 i == 0 ? "" : ",",
211                                 dns_servers[i]);
212         }
213
214         return str;
215 }
216
217 static void update_network_config(struct param_list *pl, const char *param_name,
218         const struct config *config)
219 {
220         unsigned int i;
221         char *val;
222
223         /*
224          * Don't store IPMI overrides to NVRAM. If this was a persistent
225          * override it was already stored in NVRAM by
226          * get_ipmi_network_override()
227          */
228         if (config->network.n_interfaces &&
229                 config->network.interfaces[0]->override)
230                 return;
231
232         val = talloc_strdup(pl, "");
233
234         for (i = 0; i < config->network.n_interfaces; i++) {
235                 char *iface_str = interface_config_str(pl,
236                                         config->network.interfaces[i]);
237                 val = talloc_asprintf_append(val, "%s%s",
238                                 *val == '\0' ? "" : " ", iface_str);
239                 talloc_free(iface_str);
240         }
241
242         if (config->network.n_dns_servers) {
243                 char *dns_str = dns_config_str(pl,
244                                                 config->network.dns_servers,
245                                                 config->network.n_dns_servers);
246                 val = talloc_asprintf_append(val, "%s%s",
247                                 *val == '\0' ? "" : " ", dns_str);
248                 talloc_free(dns_str);
249         }
250
251         param_list_set_non_empty(pl, param_name, val, true);
252
253         talloc_free(val);
254 }
255
256 static void update_bootdev_config(struct param_list *pl, const char *param_name,
257         const struct config *config)
258 {
259         char *val = NULL, *boot_str = NULL, *tmp = NULL;
260         struct autoboot_option *opt;
261         const char delim = ' ';
262         unsigned int i;
263
264         if (!config->n_autoboot_opts)
265                 val = "";
266
267         for (i = 0; i < config->n_autoboot_opts; i++) {
268                 opt = &config->autoboot_opts[i];
269                 switch (opt->boot_type) {
270                         case BOOT_DEVICE_TYPE:
271                                 boot_str = talloc_asprintf(config, "%s%c",
272                                                 device_type_name(opt->type),
273                                                 delim);
274                                 break;
275                         case BOOT_DEVICE_UUID:
276                                 boot_str = talloc_asprintf(config, "uuid:%s%c",
277                                                 opt->uuid, delim);
278                                 break;
279                         }
280                         tmp = val = talloc_asprintf_append(val, "%s", boot_str);
281         }
282
283         param_list_set_non_empty(pl, param_name, val, true);
284
285         talloc_free(tmp);
286         if (boot_str)
287                 talloc_free(boot_str);
288 }
289
290 static void update_config(struct param_list *pl, struct config *config,
291         const struct config *defaults)
292 {
293         char *tmp = NULL;
294         const char *val;
295
296         if (config->autoboot_enabled == defaults->autoboot_enabled)
297                 val = "";
298         else
299                 val = config->autoboot_enabled ? "true" : "false";
300
301         param_list_set_non_empty(pl, "auto-boot?", val, true);
302
303         if (config->autoboot_timeout_sec == defaults->autoboot_timeout_sec)
304                 val = "";
305         else
306                 val = tmp = talloc_asprintf(pl, "%d",
307                         config->autoboot_timeout_sec);
308
309         param_list_set_non_empty(pl, "petitboot,timeout", val, true);
310         if (tmp)
311                 talloc_free(tmp);
312
313         val = config->lang ?: "";
314         param_list_set_non_empty(pl, "petitboot,language", val, true);
315
316         if (config->allow_writes == defaults->allow_writes)
317                 val = "";
318         else
319                 val = config->allow_writes ? "true" : "false";
320         param_list_set_non_empty(pl, "petitboot,write?", val, true);
321
322         if (!config->manual_console) {
323                 val = config->boot_console ?: "";
324                 param_list_set_non_empty(pl, "petitboot,console", val, true);
325         }
326
327         val = config->http_proxy ?: "";
328         param_list_set_non_empty(pl, "petitboot,http_proxy", val, true);
329         val = config->https_proxy ?: "";
330         param_list_set_non_empty(pl, "petitboot,https_proxy", val, true);
331
332         update_network_config(pl, "petitboot,network", config);
333         update_bootdev_config(pl, "petitboot,bootdevs", config);
334 }
335
336 static void config_set_ipmi_bootdev(struct config *config, enum ipmi_bootdev bootdev,
337                 bool persistent)
338 {
339         config->ipmi_bootdev = bootdev;
340         config->ipmi_bootdev_persistent = persistent;
341
342         if (bootdev == IPMI_BOOTDEV_SAFE)
343                 config->safe_mode = true;
344 }
345
346 static int read_bootdev_sysparam(const char *name, uint8_t *val)
347 {
348         uint8_t buf[2];
349         char path[50];
350         int fd, rc;
351
352         assert(strlen(sysparams_dir) + strlen(name) < sizeof(path));
353         snprintf(path, sizeof(path), "%s%s", sysparams_dir, name);
354
355         fd = open(path, O_RDONLY);
356         if (fd < 0) {
357                 pb_debug("powerpc: can't access sysparam %s\n",
358                                 name);
359                 return -1;
360         }
361
362         rc = read(fd, buf, sizeof(buf));
363
364         close(fd);
365
366         /* bootdev definitions should only be one byte in size */
367         if (rc != 1) {
368                 pb_debug("powerpc: sysparam %s read returned %d\n",
369                                 name, rc);
370                 return -1;
371         }
372
373         pb_debug("powerpc: sysparam %s: 0x%02x\n", name, buf[0]);
374
375         if (!ipmi_bootdev_is_valid(buf[0]))
376                 return -1;
377
378         *val = buf[0];
379         return 0;
380 }
381
382 static int write_bootdev_sysparam(const char *name, uint8_t val)
383 {
384         char path[50];
385         int fd, rc;
386
387         assert(strlen(sysparams_dir) + strlen(name) < sizeof(path));
388         snprintf(path, sizeof(path), "%s%s", sysparams_dir, name);
389
390         fd = open(path, O_WRONLY);
391         if (fd < 0) {
392                 pb_debug("powerpc: can't access sysparam %s for writing\n",
393                                 name);
394                 return -1;
395         }
396
397         for (;;) {
398                 errno = 0;
399                 rc = write(fd, &val, sizeof(val));
400                 if (rc == sizeof(val)) {
401                         rc = 0;
402                         break;
403                 }
404
405                 if (rc <= 0 && errno != EINTR) {
406                         pb_log("powerpc: error updating sysparam %s: %s",
407                                         name, strerror(errno));
408                         rc = -1;
409                         break;
410                 }
411         }
412
413         close(fd);
414
415         if (!rc)
416                 pb_debug("powerpc: set sysparam %s: 0x%02x\n", name, val);
417
418         return rc;
419 }
420
421 static int clear_ipmi_bootdev_sysparams(
422                 struct platform_powerpc *platform __attribute__((unused)),
423                 bool persistent)
424 {
425         if (persistent) {
426                 /* invalidate default-boot-device setting */
427                 write_bootdev_sysparam("default-boot-device", 0xff);
428         } else {
429                 /* invalidate next-boot-device setting */
430                 write_bootdev_sysparam("next-boot-device", 0xff);
431         }
432         return 0;
433 }
434
435 static int get_ipmi_bootdev_sysparams(
436                 struct platform_powerpc *platform __attribute__((unused)),
437                 uint8_t *bootdev, bool *persistent)
438 {
439         uint8_t next_bootdev, default_bootdev;
440         bool next_valid, default_valid;
441         int rc;
442
443         rc = read_bootdev_sysparam("next-boot-device", &next_bootdev);
444         next_valid = rc == 0;
445
446         rc = read_bootdev_sysparam("default-boot-device", &default_bootdev);
447         default_valid = rc == 0;
448
449         /* nothing valid? no need to change the config */
450         if (!next_valid && !default_valid)
451                 return -1;
452
453         *persistent = !next_valid;
454         *bootdev = next_valid ? next_bootdev : default_bootdev;
455         return 0;
456 }
457
458 static int clear_ipmi_bootdev_ipmi(struct platform_powerpc *platform,
459                                    bool persistent __attribute__((unused)))
460 {
461         uint16_t resp_len;
462         uint8_t resp[1];
463         uint8_t req[] = {
464                 0x05, /* parameter selector: boot flags */
465                 0x80, /* data 1: valid */
466                 0x00, /* data 2: bootdev: no override */
467                 0x00, /* data 3: system defaults */
468                 0x00, /* data 4: no request for shared mode, mux defaults */
469                 0x00, /* data 5: no instance request */
470         };
471
472         resp_len = sizeof(resp);
473
474         ipmi_transaction(platform->ipmi, IPMI_NETFN_CHASSIS,
475                         IPMI_CMD_CHASSIS_SET_SYSTEM_BOOT_OPTIONS,
476                         req, sizeof(req),
477                         resp, &resp_len,
478                         ipmi_timeout);
479         return 0;
480 }
481
482 static int get_ipmi_bootdev_ipmi(struct platform_powerpc *platform,
483                 uint8_t *bootdev, bool *persistent)
484 {
485         uint16_t resp_len;
486         uint8_t resp[8];
487         int rc;
488         uint8_t req[] = {
489                 0x05, /* parameter selector: boot flags */
490                 0x00, /* no set selector */
491                 0x00, /* no block selector */
492         };
493
494         resp_len = sizeof(resp);
495         rc = ipmi_transaction(platform->ipmi, IPMI_NETFN_CHASSIS,
496                         IPMI_CMD_CHASSIS_GET_SYSTEM_BOOT_OPTIONS,
497                         req, sizeof(req),
498                         resp, &resp_len,
499                         ipmi_timeout);
500         if (rc) {
501                 pb_log("platform: error reading IPMI boot options\n");
502                 return -1;
503         }
504
505         if (resp_len != sizeof(resp)) {
506                 pb_log("platform: unexpected length (%d) in "
507                                 "boot options response\n", resp_len);
508                 return -1;
509         }
510
511         pb_debug("IPMI get_bootdev response:\n");
512         for (int i = 0; i < resp_len; i++)
513                 pb_debug("%x ", resp[i]);
514         pb_debug("\n");
515
516         if (resp[0] != 0) {
517                 pb_log("platform: non-zero completion code %d from IPMI req\n",
518                                 resp[0]);
519                 return -1;
520         }
521
522         /* check for correct parameter version */
523         if ((resp[1] & 0xf) != 0x1) {
524                 pb_log("platform: unexpected version (0x%x) in "
525                                 "boot options response\n", resp[0]);
526                 return -1;
527         }
528
529         /* check for valid paramters */
530         if (resp[2] & 0x80) {
531                 pb_debug("platform: boot options are invalid/locked\n");
532                 return -1;
533         }
534
535         *persistent = false;
536
537         /* check for valid flags */
538         if (!(resp[3] & 0x80)) {
539                 pb_debug("platform: boot flags are invalid, ignoring\n");
540                 return -1;
541         }
542
543         *persistent = resp[3] & 0x40;
544         *bootdev = (resp[4] >> 2) & 0x0f;
545         return 0;
546 }
547
548 static int set_ipmi_os_boot_sensor(struct platform_powerpc *platform)
549 {
550         int sensor_number;
551         uint16_t resp_len;
552         uint8_t resp[1];
553         uint8_t req[] = {
554                 0x00, /* sensor number: os boot */
555                 0xA9, /* operation: set everything */
556                 0x00, /* sensor reading: none */
557                 0x40, /* assertion mask lsb: set state 6 */
558                 0x00, /* assertion mask msb: none */
559                 0x00, /* deassertion mask lsb: none */
560                 0x00, /* deassertion mask msb: none */
561                 0x00, /* event data 1: none */
562                 0x00, /* event data 2: none */
563                 0x00, /* event data 3: none */
564         };
565
566         sensor_number = get_ipmi_sensor(platform, IPMI_SENSOR_ID_OS_BOOT);
567         if (sensor_number < 0) {
568                 pb_log("Couldn't find OS boot sensor in device tree\n");
569                 return -1;
570         }
571
572         req[0] = sensor_number;
573
574         resp_len = sizeof(resp);
575
576         ipmi_transaction(platform->ipmi, IPMI_NETFN_SE,
577                         IPMI_CMD_SENSOR_SET,
578                         req, sizeof(req),
579                         resp, &resp_len,
580                         ipmi_timeout); return 0;
581
582         return 0;
583 }
584
585 static void get_ipmi_network_override(struct platform_powerpc *platform,
586                         struct config *config)
587 {
588         uint16_t min_len = 12, resp_len = 53, version;
589         const uint32_t magic_value = 0x21706221;
590         uint8_t resp[resp_len];
591         uint32_t cookie;
592         bool persistent;
593         int i, rc;
594         uint8_t req[] = {
595                 0x61, /* parameter selector: OEM section (network) */
596                 0x00, /* no set selector */
597                 0x00, /* no block selector */
598         };
599
600         rc = ipmi_transaction(platform->ipmi, IPMI_NETFN_CHASSIS,
601                         IPMI_CMD_CHASSIS_GET_SYSTEM_BOOT_OPTIONS,
602                         req, sizeof(req),
603                         resp, &resp_len,
604                         ipmi_timeout);
605
606         pb_debug("IPMI net override resp [%d][%d]:\n", rc, resp_len);
607         if (resp_len > 0) {
608                 for (i = 0; i < resp_len; i++) {
609                         pb_debug(" %02x", resp[i]);
610                         if (i && (i + 1) % 16 == 0 && i != resp_len - 1)
611                                 pb_debug("\n");
612                         else if (i && (i + 1) % 8 == 0)
613                                 pb_debug(" ");
614                 }
615                 pb_debug("\n");
616         }
617
618         if (rc) {
619                 pb_debug("IPMI network config option unavailable\n");
620                 return;
621         }
622
623         if (resp_len < min_len) {
624                 pb_debug("IPMI net response too small\n");
625                 return;
626         }
627
628         if (resp[0] != 0) {
629                 pb_log("platform: non-zero completion code %d from IPMI network req\n",
630                        resp[0]);
631                 return;
632         }
633
634         /* Check for correct parameter version */
635         if ((resp[1] & 0xf) != 0x1) {
636                 pb_log("platform: unexpected version (0x%x) in network override response\n",
637                        resp[0]);
638                 return;
639         }
640
641         /* Check that the parameters are valid */
642         if (resp[2] & 0x80) {
643                 pb_debug("platform: network override is invalid/locked\n");
644                 return;
645         }
646
647         /* Check for valid parameters in the boot flags section */
648         if (!(resp[3] & 0x80)) {
649                 pb_debug("platform: network override valid flag not set\n");
650                 return;
651         }
652         /* Read the persistent flag; if it is set we need to save this config */
653         persistent = resp[3] & 0x40;
654         if (persistent)
655                 pb_debug("platform: network override is persistent\n");
656
657         /* Check 4-byte cookie value */
658         i = 4;
659         memcpy(&cookie, &resp[i], sizeof(cookie));
660         cookie = __be32_to_cpu(cookie);
661         if (cookie != magic_value) {
662                 pb_log_fn("Incorrect cookie %x\n", cookie);
663                 return;
664         }
665         i += sizeof(cookie);
666
667         /* Check 2-byte version number */
668         memcpy(&version, &resp[i], sizeof(version));
669         version = __be16_to_cpu(version);
670         i += sizeof(version);
671         if (version != 1) {
672                 pb_debug("Unexpected version: %u\n", version);
673                 return;
674         }
675
676         /* Interpret the rest of the interface config */
677         rc = parse_ipmi_interface_override(config, &resp[i], resp_len - i);
678
679         if (!rc && persistent) {
680                 /* Write this new config to NVRAM */
681                 update_network_config(&platform->params, "petitboot,network",
682                         config);
683                 rc = write_nvram(platform);
684                 if (rc)
685                         pb_log("platform: Failed to save persistent interface override\n");
686         }
687 }
688
689 static void config_get_active_consoles(struct config *config)
690 {
691         struct stat sbuf;
692         char *fsp_prop = NULL;
693
694         config->n_consoles = 2;
695         config->consoles = talloc_array(config, char *, config->n_consoles);
696         if (!config->consoles)
697                 goto err;
698
699         config->consoles[0] = talloc_asprintf(config->consoles,
700                                         "/dev/hvc0 [IPMI / Serial]");
701         config->consoles[1] = talloc_asprintf(config->consoles,
702                                         "/dev/tty1 [VGA]");
703
704         fsp_prop = talloc_asprintf(config, "%sfsps", devtree_dir);
705         if (stat(fsp_prop, &sbuf) == 0) {
706                 /* FSP based machines also have a separate serial console */
707                 config->consoles = talloc_realloc(config, config->consoles,
708                                                 char *, config->n_consoles + 1);
709                 if (!config->consoles)
710                         goto err;
711                 config->consoles[config->n_consoles++] = talloc_asprintf(
712                                                 config->consoles,
713                                                 "/dev/hvc1 [Serial]");
714         }
715
716         return;
717 err:
718         config->n_consoles = 0;
719         pb_log("Failed to allocate memory for consoles\n");
720 }
721
722 static int load_config(struct platform *p, struct config *config)
723 {
724         struct platform_powerpc *platform = to_platform_powerpc(p);
725         int rc;
726
727         rc = parse_nvram(platform);
728         if (rc)
729                 pb_log_fn("Failed to parse nvram\n");
730
731         config_populate_all(config, &platform->params);
732
733         if (platform->get_ipmi_bootdev) {
734                 bool bootdev_persistent;
735                 uint8_t bootdev = IPMI_BOOTDEV_INVALID;
736                 rc = platform->get_ipmi_bootdev(platform, &bootdev,
737                                 &bootdev_persistent);
738                 if (!rc && ipmi_bootdev_is_valid(bootdev)) {
739                         config_set_ipmi_bootdev(config, bootdev,
740                                 bootdev_persistent);
741                 }
742         }
743
744         if (platform->ipmi)
745                 get_ipmi_network_override(platform, config);
746
747         config_get_active_consoles(config);
748
749         return 0;
750 }
751
752 static int save_config(struct platform *p, struct config *config)
753 {
754         struct platform_powerpc *platform = to_platform_powerpc(p);
755         struct config *defaults;
756
757         if (config->ipmi_bootdev == IPMI_BOOTDEV_INVALID &&
758             platform->clear_ipmi_bootdev) {
759                 platform->clear_ipmi_bootdev(platform,
760                                 config->ipmi_bootdev_persistent);
761                 config->ipmi_bootdev = IPMI_BOOTDEV_NONE;
762                 config->ipmi_bootdev_persistent = false;
763         }
764
765         defaults = talloc_zero(platform, struct config);
766         config_set_defaults(defaults);
767
768         update_config(&platform->params, config, defaults);
769
770         talloc_free(defaults);
771         return write_nvram(platform);
772 }
773
774 static void pre_boot(struct platform *p, const struct config *config)
775 {
776         struct platform_powerpc *platform = to_platform_powerpc(p);
777
778         if (!config->ipmi_bootdev_persistent && platform->clear_ipmi_bootdev)
779                 platform->clear_ipmi_bootdev(platform, false);
780
781         if (platform->set_os_boot_sensor)
782                 platform->set_os_boot_sensor(platform);
783 }
784
785 static int get_sysinfo(struct platform *p, struct system_info *sysinfo)
786 {
787         struct platform_powerpc *platform = p->platform_data;
788         char *buf, *filename;
789         int len, rc;
790
791         filename = talloc_asprintf(platform, "%smodel", devtree_dir);
792         rc = read_file(platform, filename, &buf, &len);
793         if (rc == 0)
794                 sysinfo->type = talloc_steal(sysinfo, buf);
795         talloc_free(filename);
796
797         filename = talloc_asprintf(platform, "%ssystem-id", devtree_dir);
798         rc = read_file(platform, filename, &buf, &len);
799         if (rc == 0)
800                 sysinfo->identifier = talloc_steal(sysinfo, buf);
801         talloc_free(filename);
802
803         sysinfo->bmc_mac = talloc_zero_size(sysinfo, HWADDR_SIZE);
804
805         if (platform->ipmi) {
806                 ipmi_get_bmc_mac(platform->ipmi, sysinfo->bmc_mac);
807                 ipmi_get_bmc_versions(platform->ipmi, sysinfo);
808         }
809
810         if (platform->get_platform_versions)
811                 platform->get_platform_versions(sysinfo);
812
813         return 0;
814 }
815
816 static bool probe(struct platform *p, void *ctx)
817 {
818         struct platform_powerpc *platform;
819         struct stat statbuf;
820         bool bmc_present;
821         int rc;
822
823         /* we need a device tree */
824         rc = stat("/proc/device-tree", &statbuf);
825         if (rc)
826                 return false;
827
828         if (!S_ISDIR(statbuf.st_mode))
829                 return false;
830
831         platform = talloc_zero(ctx, struct platform_powerpc);
832         param_list_init(&platform->params, common_known_params());
833
834         p->platform_data = platform;
835
836         bmc_present = stat("/proc/device-tree/bmc", &statbuf) == 0;
837
838         if (ipmi_present() && bmc_present) {
839                 pb_debug("platform: using direct IPMI for IPMI paramters\n");
840                 platform->ipmi = ipmi_open(platform);
841                 platform->get_ipmi_bootdev = get_ipmi_bootdev_ipmi;
842                 platform->clear_ipmi_bootdev = clear_ipmi_bootdev_ipmi;
843                 platform->set_os_boot_sensor = set_ipmi_os_boot_sensor;
844         } else if (!stat(sysparams_dir, &statbuf)) {
845                 pb_debug("platform: using sysparams for IPMI paramters\n");
846                 platform->get_ipmi_bootdev = get_ipmi_bootdev_sysparams;
847                 platform->clear_ipmi_bootdev = clear_ipmi_bootdev_sysparams;
848
849         } else {
850                 pb_log("platform: no IPMI parameter support\n");
851         }
852
853         if (bmc_present)
854                 platform->get_platform_versions = hostboot_load_versions;
855
856         return true;
857 }
858
859
860 static struct platform platform_powerpc = {
861         .name                   = "powerpc",
862         .dhcp_arch_id           = 0x000e,
863         .probe                  = probe,
864         .load_config            = load_config,
865         .save_config            = save_config,
866         .pre_boot               = pre_boot,
867         .get_sysinfo            = get_sysinfo,
868 };
869
870 register_platform(platform_powerpc);