summaryrefslogtreecommitdiffstats
path: root/discover/platform-powerpc.c
diff options
context:
space:
mode:
Diffstat (limited to 'discover/platform-powerpc.c')
-rw-r--r--discover/platform-powerpc.c187
1 files changed, 140 insertions, 47 deletions
diff --git a/discover/platform-powerpc.c b/discover/platform-powerpc.c
index 5d7cc59..c6ab416 100644
--- a/discover/platform-powerpc.c
+++ b/discover/platform-powerpc.c
@@ -21,6 +21,7 @@
#include "platform.h"
#include "ipmi.h"
#include "dt.h"
+#include "elf.h"
static const char *partition = "common";
static const char *sysparams_dir = "/sys/firmware/opal/sysparams/";
@@ -222,6 +223,13 @@ static void params_update_all(struct param_list *pl,
params_update_network_values(pl, "petitboot,network", config);
params_update_bootdev_values(pl, "petitboot,bootdevs", config);
+
+ if (config->preboot_check_enabled == defaults->preboot_check_enabled)
+ val = "";
+ else
+ val = config->preboot_check_enabled ? "true" : "false";
+
+ param_list_set_non_empty(pl, "petitboot,preboot-check", val, true);
}
static void config_set_ipmi_bootdev(struct config *config, enum ipmi_bootdev bootdev,
@@ -437,10 +445,10 @@ static int get_ipmi_bootdev_ipmi(struct platform_powerpc *platform,
}
static int get_ipmi_boot_mailbox_block(struct platform_powerpc *platform,
- char *buf, uint8_t block)
+ mbox_t *mailbox, uint8_t block)
{
size_t blocksize = 16;
- uint8_t resp[3 + 16];
+ ipmi_mbox_response_t ipmi_mbox_resp = { .cc = 0xFF };
uint16_t resp_len;
char *debug_buf;
int rc;
@@ -449,60 +457,71 @@ static int get_ipmi_boot_mailbox_block(struct platform_powerpc *platform,
block, /* set selector */
0x00, /* no block selector */
};
+ size_t ipmi_header_len = sizeof(ipmi_mbox_response_t) - sizeof(mbox_t);
- resp_len = sizeof(resp);
+ resp_len = sizeof(ipmi_mbox_response_t);
rc = ipmi_transaction(platform->ipmi, IPMI_NETFN_CHASSIS,
IPMI_CMD_CHASSIS_GET_SYSTEM_BOOT_OPTIONS,
req, sizeof(req),
- resp, &resp_len,
+ (uint8_t*)&ipmi_mbox_resp, &resp_len,
ipmi_timeout);
if (rc) {
pb_log("platform: error reading IPMI boot options\n");
return -1;
}
- if (resp_len < sizeof(resp)) {
- if (resp_len < 3) {
- pb_log("platform: unexpected length (%d) in "
- "boot options mailbox response\n",
- resp_len);
- return -1;
- }
-
- if (resp_len == 4) {
- pb_debug_fn("block %hu empty\n", block);
- return 0;
- }
+ if (resp_len > sizeof(ipmi_mbox_response_t)) {
+ pb_debug("platform: invalid mailbox response size!\n");
+ return -1;
+ }
- blocksize = sizeof(resp) - 3;
- pb_debug_fn("Mailbox block %hu returns only %zu bytes in block\n",
- block, blocksize);
+ if (resp_len < ipmi_header_len) {
+ pb_log("platform: unexpected length (%d) in "
+ "boot options mailbox response\n",
+ resp_len);
+ return -1;
}
- debug_buf = format_buffer(platform, resp, resp_len);
+ blocksize = resp_len - ipmi_header_len;
+ pb_debug_fn("Mailbox block %hu returns only %zu bytes in block\n",
+ block, blocksize);
+
+ debug_buf = format_buffer(platform, (uint8_t*)&ipmi_mbox_resp, resp_len);
pb_debug_fn("IPMI bootdev mailbox block %hu:\n%s\n", block, debug_buf);
talloc_free(debug_buf);
- if (resp[0] != 0) {
+ if (ipmi_mbox_resp.cc != 0) {
pb_log("platform: non-zero completion code %d from IPMI req\n",
- resp[0]);
+ ipmi_mbox_resp.cc);
return -1;
}
/* check for correct parameter version */
- if ((resp[1] & 0xf) != 0x1) {
+ if ((ipmi_mbox_resp.param_version & 0xf) != 0x1) {
pb_log("platform: unexpected version (0x%x) in "
- "boot mailbox response\n", resp[0]);
+ "boot mailbox response\n", ipmi_mbox_resp.param_version);
return -1;
}
/* check for valid paramters */
- if (resp[2] & 0x80) {
+ if (ipmi_mbox_resp.param_valid & 0x80) {
pb_debug("platform: boot mailbox parameters are invalid/locked\n");
return -1;
}
- memcpy(buf, &resp[3], blocksize);
+ /* check for block number */
+ if (ipmi_mbox_resp.block_selector != block) {
+ pb_debug("platform: returned boot mailbox block doesn't match "
+ "requested\n");
+ return -1;
+ }
+
+ if (!blocksize) {
+ pb_debug_fn("block %hu empty\n", block);
+ return 0;
+ }
+
+ memcpy(mailbox, &ipmi_mbox_resp.mbox, blocksize);
return blocksize;
}
@@ -511,12 +530,10 @@ static int get_ipmi_boot_mailbox(struct platform_powerpc *platform,
char **buf)
{
char *mailbox_buffer, *prefix;
- const size_t blocksize = 16;
- char block_buffer[blocksize];
+ mbox_t mailbox;
size_t mailbox_size;
int content_size;
uint8_t i;
- int rc;
mailbox_buffer = NULL;
mailbox_size = 0;
@@ -527,15 +544,16 @@ static int get_ipmi_boot_mailbox(struct platform_powerpc *platform,
* on higher numbers.
*/
for (i = 0; i < UCHAR_MAX; i++) {
- rc = get_ipmi_boot_mailbox_block(platform, block_buffer, i);
- if (rc < 3 && i == 0) {
+ uint8_t *boot_opt_data;
+ int block_size = get_ipmi_boot_mailbox_block(platform, &mailbox, i);
+ if (block_size < CHASSIS_BOOT_MBOX_IANA_SZ && i == 0) {
/*
* Immediate failure, no blocks read or missing IANA
* number.
*/
return -1;
}
- if (rc < 1) {
+ if (block_size < 1) {
/* Error or no bytes read */
break;
}
@@ -543,28 +561,33 @@ static int get_ipmi_boot_mailbox(struct platform_powerpc *platform,
if (i == 0) {
/*
* The first three bytes of block zero are an IANA
- * Enterprise ID number. Check it matches the IBM
- * number, '2'.
+ * Enterprise ID number
*/
- if (block_buffer[0] != 0x02 ||
- block_buffer[1] != 0x00 ||
- block_buffer[2] != 0x00) {
+ block_size -= CHASSIS_BOOT_MBOX_IANA_SZ;
+ boot_opt_data = &mailbox.b0.data;
+
+ /* Check IANA matches the IBM number, '2' */
+ if (mailbox.b0.iana[0] != 0x02 ||
+ mailbox.b0.iana[1] != 0x00 ||
+ mailbox.b0.iana[2] != 0x00) {
pb_log_fn("IANA number unrecognised: 0x%x:0x%x:0x%x\n",
- block_buffer[0],
- block_buffer[1],
- block_buffer[2]);
+ mailbox.b0.iana[0],
+ mailbox.b0.iana[1],
+ mailbox.b0.iana[2]);
return -1;
}
+ } else {
+ boot_opt_data = &mailbox.data;
}
mailbox_buffer = talloc_realloc(platform, mailbox_buffer,
- char, mailbox_size + rc);
+ char, mailbox_size + block_size);
if (!mailbox_buffer) {
pb_log_fn("Failed to allocate mailbox buffer\n");
return -1;
}
- memcpy(mailbox_buffer + mailbox_size, block_buffer, rc);
- mailbox_size += rc;
+ memcpy(mailbox_buffer + mailbox_size, boot_opt_data, block_size);
+ mailbox_size += block_size;
}
if (i < 5)
@@ -574,10 +597,10 @@ static int get_ipmi_boot_mailbox(struct platform_powerpc *platform,
else
pb_debug_fn("%hu blocks read (%zu bytes)\n", i, mailbox_size);
- if (mailbox_size < 3 + strlen("petitboot,bootdevs="))
+ if (mailbox_size < strlen("petitboot,bootdevs="))
return -1;
- prefix = talloc_strndup(mailbox_buffer, mailbox_buffer + 3,
+ prefix = talloc_strndup(mailbox_buffer, mailbox_buffer,
strlen("petitboot,bootdevs="));
if (!prefix) {
pb_log_fn("Couldn't check prefix\n");
@@ -595,9 +618,9 @@ static int get_ipmi_boot_mailbox(struct platform_powerpc *platform,
}
/* Don't include IANA number in buffer */
- content_size = mailbox_size - 3 - strlen("petitboot,bootdevs=");
+ content_size = mailbox_size - strlen("petitboot,bootdevs=");
*buf = talloc_memdup(platform,
- mailbox_buffer + 3 + strlen("petitboot,bootdevs="),
+ mailbox_buffer + strlen("petitboot,bootdevs="),
content_size + 1);
(*buf)[content_size] = '\0';
@@ -923,6 +946,72 @@ static void pre_boot(struct platform *p, const struct config *config)
platform->set_os_boot_sensor(platform);
}
+static bool preboot_check(struct platform *p,
+ const struct config *config,
+ const char *image,
+ char **err_msg)
+{
+ struct platform_powerpc *platform = p->platform_data;
+ unsigned int *ppc_cap_bitmap = NULL;
+ bool ultravisor_enabled;
+ struct stat statbuf;
+ bool ret = true;
+
+ /* check if ultravisor-system is enabled */
+ ultravisor_enabled = stat("/proc/device-tree/ibm,ultravisor",
+ &statbuf) == 0;
+
+ /* if ultravisor-system is disabled, continue the boot process */
+ if (!ultravisor_enabled)
+ return true;
+
+ ppc_cap_bitmap = elf_getnote_desc(elf_open_image(image),
+ POWERPC_ELFNOTE_NAMESPACE,
+ PPC_ELFNOTE_CAPABILITIES);
+
+ if ((ppc_cap_bitmap) && (*ppc_cap_bitmap & PPCCAP_ULTRAVISOR_BIT)) {
+ pb_debug("kernel capabilities: ultravisor mode found.\n");
+ } else {
+ ret = false;
+ pb_log_fn("kernel capabilities failed:"
+ " IBM Ultravisor mode is required.\n");
+ *err_msg = talloc_strdup(platform, "IBM Ultravisor capability"
+ " not found");
+ }
+ free(ppc_cap_bitmap);
+
+ /* if preboot_check is disabled, continue the boot process */
+ if (!config->preboot_check_enabled)
+ return true;
+
+ return ret;
+}
+
+static void get_sysinfo_stb(struct platform_powerpc *platform,
+ struct system_info *sysinfo)
+{
+ char *filename;
+ unsigned int i;
+ int rc;
+ struct {
+ const char *name;
+ bool *flag;
+ } props[] = {
+ { "secure-enabled", &sysinfo->stb_fw_enforcing },
+ { "trusted-enabled", &sysinfo->stb_fw_measurement },
+ { "os-secureboot-enforcing", &sysinfo->stb_os_enforcing },
+ };
+
+ for (i = 0; i < ARRAY_SIZE(props); i++) {
+ struct stat statbuf;
+ filename = talloc_asprintf(platform, "%sibm,secureboot/%s",
+ devtree_dir, props[i].name);
+ rc = stat(filename, &statbuf);
+ *props[i].flag = (rc == 0);
+ talloc_free(filename);
+ }
+}
+
static int get_sysinfo(struct platform *p, struct system_info *sysinfo)
{
struct platform_powerpc *platform = p->platform_data;
@@ -951,6 +1040,9 @@ static int get_sysinfo(struct platform *p, struct system_info *sysinfo)
if (platform->get_platform_versions)
platform->get_platform_versions(sysinfo);
+ get_sysinfo_stb(platform, sysinfo);
+
+
return 0;
}
@@ -1028,6 +1120,7 @@ static struct platform platform_powerpc = {
.get_sysinfo = get_sysinfo,
.restrict_clients = restrict_clients,
.set_password = set_password,
+ .preboot_check = preboot_check,
};
register_platform(platform_powerpc);
OpenPOWER on IntegriCloud