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