@@ -198,6 +198,45 @@ static int64_t opal_get_next_variable(uint64_t k_varname, uint64_t k_size, uint6
opal_call(OPAL_GET_NEXT_VARIABLE, opal_get_next_variable, 3);
+// Cleanup function to empty out a bank list
+static void clear_bank_list(struct list_head *head)
+{
+ struct keystore_variable *node, *next;
+
+ list_for_each_safe(head, node, next, link) {
+ free(node->name);
+ free(node->data);
+ list_del(&node->link);
+ free(node);
+ }
+}
+
+
+static int64_t opal_secboot_commit(uint64_t section)
+{
+ int ret = OPAL_SUCCESS;
+
+ CHECK_KEYSTORE_READY;
+
+ if (section & ACTIVE_BANK) {
+ ret = secboot_part_serialize_and_write(&active_bank_list, ACTIVE_BANK);
+ }
+
+ if (section & UPDATE_QUEUE) {
+ ret = secboot_part_serialize_and_write(&update_queue_list, UPDATE_QUEUE);
+ }
+
+ if (section & CLEAR_QUEUE) {
+ ret = secboot_part_serialize_and_write(NULL, CLEAR_QUEUE);
+ // Do we want to clear the in-memory queue even if the above fails?
+ clear_bank_list(&update_queue_list);
+ }
+
+ return (ret) ? OPAL_RESOURCE : OPAL_SUCCESS;
+}
+opal_call(OPAL_SECBOOT_COMMIT, opal_secboot_commit, 1);
+
+
int keystore_init(void)
{
int rc;
@@ -231,6 +231,63 @@ int secboot_part_build_keystore(struct list_head *active, struct list_head *uque
}
+static int write_variable(char *target, struct keystore_variable *var)
+{
+ char *cur = target;
+
+ prlog(PR_INFO, "Writing variable '%s'\n", var->name);
+
+ *((uint64_t*) cur) = var->name_size; cur += sizeof(uint64_t);
+ *((uint64_t*) cur) = var->data_size; cur += sizeof(uint64_t);
+ memcpy(cur, var->name, var->name_size);
+ cur += var->name_size;
+ memcpy(cur, var->data, var->data_size);
+ cur += var->data_size;
+
+ return cur - target;
+}
+
+
+int secboot_part_serialize_and_write(struct list_head *head, int section)
+{
+ struct keystore_variable *var;
+ char *cur = NULL, *end = NULL;
+
+ switch(section) {
+ case ACTIVE_BANK:
+ cur = (char*) active_bank->item;
+ end = ((char*) active_bank) + SECBOOT_BANK_SIZE;
+ break;
+ case UPDATE_QUEUE:
+ cur = (char*) update_queue->item;
+ end = ((char*) update_queue) + SECBOOT_QUEUE_SIZE;;
+ break;
+
+ case CLEAR_QUEUE:
+ memset(update_queue->item, 0x00, SECBOOT_QUEUE_SIZE - sizeof(struct secboot_section)); // header?
+ goto out; // Skip the serialization of variables
+
+ default: return -1;
+ }
+
+ if (!head) return -1; // head should not be NULL with section != CLEAR_QUEUE
+
+ prlog(PR_INFO, "cur = %p\n", cur);
+ list_for_each(head, var, link) {
+ cur += write_variable(cur, var);
+ }
+ prlog(PR_INFO, "cur = %p\n", cur);
+
+ memset(cur, 0x00, end-cur); // Clear the rest of the bank
+
+out:
+ prlog(PR_INFO,"performing write\n");
+ platform.secboot_write(0, secboot, secboot_size);
+
+ return 0;
+}
+
+
int secboot_part_init()
{
int rc;
@@ -19,5 +19,6 @@
int secboot_part_init(void);
int secboot_part_build_keystore(struct list_head* active, struct list_head* uqueue);
+int secboot_part_serialize_and_write(struct list_head *head, int section);
#endif /* __SECBOOT_PART_H */
The opal_secboot_commit runtime service serializes an in-memory keystore bank and writes it out to the appropriate offset in the secboot partition. There are three options for the section flag: the two in-memory keystore banks ACTIVE_BANK and UPDATE_QUEUE, and a third option CLEAR_QUEUE. The first two flags function almost the same, serialize their respective list and write the blob to PNOR. CLEAR_QUEUE is a special case for use after the update queue has been processed by the kernel and no longer needed, therefore flushing the list and zeroing out the region in the secboot partition. This patch also introduces the secboot_serialize_and_write operation, which takes in a keystore bank list and handles the appropriate serialization logic. This function may be tweaked in the future to accomodate platform specific changes. For example, p9 may implement this function to write variables or other bits of data to the TPM, whereas platforms with lockable flash may not need to do this. NOTE: Right now, this is written to allow for a composite flag to allow for multiple operations to be handled by a single Opal call, however the call itself does not intelligently handle multiple operations -- that is, the call will not lump the serialized blobs into a single PNOR write. This is partially due to the nature of the secboot partition, as this may not all be one contiguous blob Signed-off-by: Eric Richter <erichte@linux.ibm.com> --- libstb/keystore.c | 39 +++++++++++++++++++++++++++++++++++ libstb/secboot_part.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++ libstb/secboot_part.h | 1 + 3 files changed, 97 insertions(+)