@@ -4,7 +4,7 @@ LIBSTB_DIR = libstb
SUBDIRS += $(LIBSTB_DIR)
-LIBSTB_SRCS = container.c tpm_chip.c cvc.c secureboot.c trustedboot.c
+LIBSTB_SRCS = container.c tpm_chip.c cvc.c secureboot.c trustedboot.c secboot_part.c
LIBSTB_OBJS = $(LIBSTB_SRCS:%.c=%.o)
LIBSTB = $(LIBSTB_DIR)/built-in.a
new file mode 100644
@@ -0,0 +1,249 @@
+/* Copyright 2013-2018 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef pr_fmt
+#define pr_fmt(fmt) "SECBOOT_PART: " fmt
+#endif
+
+#include <skiboot.h>
+#include "secboot_part.h"
+
+struct secboot_section_item {
+ const char *name; /* null terminated string */
+ uint32_t size;
+ char data[0];
+} __packed;
+
+struct secboot_section_header {
+ uint8_t version;
+ uint32_t reserved;
+ uint32_t size;
+} __packed;
+
+struct secboot_section {
+ struct secboot_section_header header;
+ struct secboot_section_item item[0]; // section_item place holder
+ // followed by other section items up to section size:
+ // SECBOOT_BANK_SIZE if it is bank section; or
+ // SECBOOT_QUEUE_SIZE if it is an update queue section
+} __packed;
+
+struct secboot_header {
+ uint32_t magic_number;
+ uint8_t version;
+} __packed;
+
+struct secboot_part {
+ struct secboot_header header;
+ struct secboot_section bank[0]; // section_header place holder
+ // followed by bank1 section
+ // followed by update queue section
+} __packed;
+
+//#define SECBOOT_SECTION_SIZE(p) (sizeof(section_header) + p->size)
+/* 0x5053424b = "PSBK" or Power Secure Boot Keystore */
+#define SECBOOT_MAGIC_NUMBER 0x5053424b
+#define SECBOOT_VERSION 1
+#define SECBOOT_MINIMUM_SIZE (sizeof(struct secboot_header) + SECBOOT_BANK_SIZE*2 + SECBOOT_QUEUE_SIZE)
+
+#define SECBOOT_BANK_VERSION 1
+#define SECBOOT_BANK_SIZE 0xb400 // 45 KB
+
+#define SECBOOT_QUEUE_VERSION 1
+#define SECBOOT_QUEUE_SIZE 0x7800 // 30 KB
+
+static struct secboot_part *secboot = NULL;
+static uint32_t secboot_size = 0;
+
+/* Indicates if the secboot partition data can be consumed */
+static bool secboot_valid = false;
+
+static struct secboot_section *active_bank = NULL;
+static struct secboot_section *staging_bank = NULL;
+static struct secboot_section *update_queue = NULL;
+
+static int secboot_part_format(void)
+{
+ struct secboot_section *section;
+ int rc;
+
+ if (!platform.secboot_write)
+ return -1;
+
+ memset(secboot, 0, secboot_size);
+
+ /* INITIALIZE THE HEADERS */
+
+ /* secboot header */
+ secboot->header.magic_number = SECBOOT_MAGIC_NUMBER;
+ secboot->header.version = SECBOOT_VERSION;
+
+ /* bank0 section header */
+ section = secboot->bank;
+ section->header.version = SECBOOT_BANK_VERSION;
+ section->header.reserved = 0;
+ section->header.size = SECBOOT_BANK_SIZE;
+
+ /* bank1 section header */
+ section = (struct secboot_section*)((uint8_t*) section + SECBOOT_BANK_SIZE);
+ section->header.version = SECBOOT_BANK_VERSION;
+ section->header.reserved = 0;
+ section->header.size = SECBOOT_BANK_SIZE;
+
+ /* update queue section header */
+ section = (struct secboot_section*)((uint8_t*) section + SECBOOT_BANK_SIZE);
+ section->header.version = SECBOOT_QUEUE_VERSION;
+ section->header.reserved = 0;
+ section->header.size = SECBOOT_QUEUE_SIZE;
+
+ /* write the whole thing back to PNOR */
+ rc = platform.secboot_write(0, secboot, secboot_size);
+ if (rc)
+ return -1;
+
+ prlog(PR_INFO, "formatted\n");
+ secboot_valid = true;
+
+ return 0;
+}
+
+/*
+ * Check that the keystore layout is sane. If not, we re-format the lot of it
+ */
+static int secboot_part_validate(void)
+{
+ if (secboot->header.magic_number != SECBOOT_MAGIC_NUMBER) {
+ prlog(PR_ERR, "magic number 0x%x mismatch, expected 0x%x\n",
+ secboot->header.magic_number, SECBOOT_MAGIC_NUMBER);
+ return -1;
+ }
+ if (secboot->header.version != SECBOOT_VERSION) {
+ prlog(PR_ERR, "secboot version %d not supported, expected %d\n",
+ secboot->header.version, SECBOOT_VERSION);
+ return -1;
+ }
+
+ /*
+ * No need to check the staging bank version, we may overwrite it at
+ * runtime but we don't consume it
+ */
+
+ active_bank = secboot->bank;
+ if (active_bank->header.version != SECBOOT_BANK_VERSION) {
+ prlog(PR_ERR, "active bank version %d not supported, expected %d\n",
+ active_bank->header.version, SECBOOT_BANK_VERSION);
+ return -1;
+ }
+
+ staging_bank = active_bank;
+ update_queue = (struct secboot_section*)((uint8_t*) secboot->bank + secboot->bank->header.size);
+ update_queue = (struct secboot_section*)((uint8_t*) update_queue + update_queue->header.size);
+
+ if (update_queue->header.version != SECBOOT_QUEUE_VERSION) {
+ prlog(PR_ERR, "update queue version %d not supported, expected %d\n",
+ update_queue->header.version, SECBOOT_QUEUE_VERSION);
+ return -1;
+ }
+
+ prlog(PR_INFO, "secboot partition valid\n");
+ secboot_valid = true;
+ return 0;
+}
+
+
+int secboot_part_init()
+{
+ int rc;
+
+ /* Already initialized */
+ if (secboot)
+ return 0;
+
+ if (!platform.secboot_info)
+ return -1;
+ rc = platform.secboot_info(&secboot_size);
+ if (rc) {
+ prlog(PR_ERR, "error %d retrieving keystore info\n", rc);
+ return -1;
+ }
+ if (SECBOOT_MINIMUM_SIZE > secboot_size) {
+ prlog(PR_ERR, "secboot partition %d KB too small. min=%ld\n",
+ secboot_size >> 10, SECBOOT_MINIMUM_SIZE);
+ return -1;
+ }
+
+ prlog(PR_INFO, "size is %d KB\n", secboot_size >> 10);
+
+ /*
+ * We allocate the pnor secboot image with 4k alignment to make the
+ * FSP backend job's easier
+ */
+ secboot = memalign(0x1000, secboot_size);
+ if (!secboot) {
+ prlog(PR_ERR, "failed to allocate the secboot partition buffer\n");
+ secboot_size = 0;
+ return -1;
+ }
+
+ /* Read it in */
+ rc = platform.secboot_read(secboot, 0, secboot_size);
+ if (rc) {
+ prlog(PR_ERR, "failed to read the secboot partition, rc=%d\n", rc);
+ goto out_free;
+ }
+
+ /*
+ * TODO:
+ * 1. Can we assume that the secboot partition is zeroed out in MFG?
+ */
+ if (secboot->header.magic_number == 0xffffffff ||
+ secboot->header.version == 0xff ||
+ secboot->header.magic_number == 0x00000000) {
+ rc = secboot_part_format();
+ if (rc)
+ goto out_free;
+ }
+
+ rc = secboot_part_validate();
+ if (rc)
+ goto out_free;
+
+ /* secboot header */
+ prlog(PR_INFO, "secboot->magic_number 0x%x\n", secboot->header.magic_number);
+ prlog(PR_INFO, "secboot->version %d\n", secboot->header.version);
+ /* active bank header */
+ prlog(PR_INFO, "active->version %d\n", active_bank->header.version);
+ prlog(PR_INFO, "active->reserved 0x%x\n", active_bank->header.reserved);
+ prlog(PR_INFO, "active->size %d KB\n", active_bank->header.size >> 10);
+ /* staging bank header */
+ prlog(PR_INFO, "staging->version %d\n", staging_bank->header.version);
+ prlog(PR_INFO, "staging->reserved 0x%x\n", staging_bank->header.reserved);
+ prlog(PR_INFO, "staging->size %d KB\n", staging_bank->header.size >> 10);
+ /* update queue header */
+ prlog(PR_INFO, "queue->version %d\n", update_queue->header.version);
+ prlog(PR_INFO, "queue->reserved 0x%x\n", update_queue->header.reserved);
+ prlog(PR_INFO, "queue->size %d KB\n", update_queue->header.size >> 10);
+
+ return 0;
+
+out_free:
+ if (secboot) {
+ free(secboot);
+ secboot = NULL;
+ secboot_size = 0;
+ }
+ return -1;
+}
new file mode 100644
@@ -0,0 +1,22 @@
+/* Copyright 2013-2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __SECBOOT_PART_H
+#define __SECBOOT_PART_H
+
+int secboot_part_init(void);
+
+#endif /* __SECBOOT_PART_H */