diff options
author | Jeremy Kerr <jk@ozlabs.org> | 2014-01-30 16:59:56 +0800 |
---|---|---|
committer | Jeremy Kerr <jk@ozlabs.org> | 2014-01-30 21:59:10 +0800 |
commit | 8cd03c27d3875beb15a489f1f05d0528408cef20 (patch) | |
tree | 332a8e6fa227f7bb8d4d802adf1b3ae723b962dd /discover/platform-powerpc.c | |
parent | 95a566908a5e02c51bd2af6b468df3fb9ad1bf75 (diff) | |
download | petitboot-8cd03c27d3875beb15a489f1f05d0528408cef20.zip petitboot-8cd03c27d3875beb15a489f1f05d0528408cef20.tar.gz |
platforms/powerpc: Add support for OPAL sysparams
PowerPC OPAL firmware's sysparam interface allows us to read the boot
device set over IPMI. This change implements support for IPMI bootdev
selection over the sysparams interface, using the new boot_priority
infrastructure.
Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
Diffstat (limited to 'discover/platform-powerpc.c')
-rw-r--r-- | discover/platform-powerpc.c | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/discover/platform-powerpc.c b/discover/platform-powerpc.c index b0a35a7..4eb2805 100644 --- a/discover/platform-powerpc.c +++ b/discover/platform-powerpc.c @@ -1,9 +1,11 @@ +#include <assert.h> #include <string.h> #include <stdlib.h> #include <limits.h> #include <sys/types.h> #include <sys/wait.h> +#include <sys/fcntl.h> #include <sys/stat.h> #include <talloc/talloc.h> @@ -14,6 +16,7 @@ #include "platform.h" static const char *partition = "common"; +static const char *sysparams_dir = "/sys/firmware/opal/sysparams"; struct param { char *name; @@ -504,6 +507,103 @@ static int update_config(struct platform_powerpc *platform, return write_nvram(platform); } +static void set_exclusive_devtype(struct config *config, + enum device_type devtype) +{ + config->n_boot_priorities = 2; + config->boot_priorities = talloc_realloc(config, + config->boot_priorities, struct boot_priority, + config->n_boot_priorities); + config->boot_priorities[0].type = devtype; + config->boot_priorities[0].priority = 0; + config->boot_priorities[1].type = DEVICE_TYPE_ANY; + config->boot_priorities[1].priority = -1; +} + +/* bootdev options that we recognise */ +enum ipmi_bootdev { + IPMI_BOOTDEV_NONE = 0x00, + IPMI_BOOTDEV_NETWORK = 0x01, + IPMI_BOOTDEV_DISK = 0x2, + IPMI_BOOTDEV_CDROM = 0x5, + IPMI_BOOTDEV_SETUP = 0x6, +}; + +static int read_bootdev_sysparam(const char *name, uint8_t *val) +{ + uint8_t buf[2]; + char path[50]; + int fd, rc; + + strcpy(path, sysparams_dir); + assert(strlen(name) < sizeof(path) - strlen(path)); + strcat(path, name); + + fd = open(path, O_RDONLY); + if (fd < 0) + return -1; + + rc = read(fd, buf, sizeof(buf)); + + close(fd); + + /* bootdev definitions should only be one byte in size */ + if (rc != 1) + return -1; + + switch (buf[0]) { + default: + return -1; + case IPMI_BOOTDEV_NONE: + case IPMI_BOOTDEV_NETWORK: + case IPMI_BOOTDEV_DISK: + case IPMI_BOOTDEV_CDROM: + case IPMI_BOOTDEV_SETUP: + *val = buf[0]; + } + + return 0; +} + +static void parse_opal_sysparams(struct config *config) +{ + uint8_t next_bootdev, default_bootdev; + bool next_valid, default_valid; + int rc; + + rc = read_bootdev_sysparam("next-boot-device", &next_bootdev); + next_valid = rc == 0; + + rc = read_bootdev_sysparam("default-boot-device", &default_bootdev); + default_valid = rc == 0; + + /* nothing valid? no need to change the config */ + if (!next_valid && !default_valid) + return; + + if (!next_valid) + next_bootdev = default_bootdev; + + /* todo: copy default to next */ + + switch (next_bootdev) { + case IPMI_BOOTDEV_NONE: + return; + case IPMI_BOOTDEV_DISK: + set_exclusive_devtype(config, DEVICE_TYPE_DISK); + break; + case IPMI_BOOTDEV_NETWORK: + set_exclusive_devtype(config, DEVICE_TYPE_NETWORK); + break; + case IPMI_BOOTDEV_CDROM: + set_exclusive_devtype(config, DEVICE_TYPE_OPTICAL); + break; + case IPMI_BOOTDEV_SETUP: + config->autoboot_enabled = false; + break; + } +} + static int load_config(struct platform *p, struct config *config) { struct platform_powerpc *platform = to_platform_powerpc(p); @@ -515,6 +615,8 @@ static int load_config(struct platform *p, struct config *config) populate_config(platform, config); + parse_opal_sysparams(config); + return 0; } |