diff --git a/ccan/list/list.h b/ccan/list/list.h
index 7cd3a83e..fdeddeb4 100644
--- a/ccan/list/list.h
+++ b/ccan/list/list.h
@@ -523,4 +523,42 @@ static inline struct list_node *list_node_from_off_(void *ptr, size_t off)
 	(container_off_var(var, member) +		\
 	 check_type(var->member, struct list_node))
 
+
+#if HAVE_TYPEOF
+#define list_typeof(var) typeof(var)
+#else
+#define list_typeof(var) void *
+#endif
+
+
+/* Returns member, or NULL if at end of list. */
+static inline void *list_entry_or_null(const struct list_head *h,
+                                      const struct list_node *n,
+                                      size_t off)
+{
+       if (n == &h->n)
+               return NULL;
+       return (char *)n - off;
+}
+
+/**
+ * list_next - get the next entry in a list
+ * @h: the list_head
+ * @i: a pointer to an entry in the list.
+ * @member: the list_node member of the structure
+ *
+ * If @i was the last entry in the list, returns NULL.
+ *
+ * Example:
+ *     struct child *second;
+ *     second = list_next(&parent->children, first, list);
+ *     if (!second)
+ *             printf("No second child!\n");
+ */
+#define list_next(h, i, member)                                                \
+       ((list_typeof(i))list_entry_or_null(list_debug(h),              \
+                                           (i)->member.next,           \
+                                           list_off_var_((i), member)))
+
+
 #endif /* CCAN_LIST_H */
diff --git a/include/opal-api.h b/include/opal-api.h
index ad913bfa..60f4b850 100644
--- a/include/opal-api.h
+++ b/include/opal-api.h
@@ -222,7 +222,10 @@
 #define OPAL_MPIPL_UPDATE			173
 #define OPAL_MPIPL_REGISTER_TAG			174
 #define OPAL_MPIPL_QUERY_TAG			175
-#define OPAL_LAST				175
+#define OPAL_SECVAR_GET				176
+#define OPAL_SECVAR_GET_NEXT			177
+#define OPAL_SECVAR_ENQUEUE_UPDATE		178
+#define OPAL_LAST				178
 
 #define QUIESCE_HOLD			1 /* Spin all calls at entry */
 #define QUIESCE_REJECT			2 /* Fail all calls with OPAL_BUSY */
diff --git a/libstb/secvar/Makefile.inc b/libstb/secvar/Makefile.inc
index e36186b5..737b77d2 100644
--- a/libstb/secvar/Makefile.inc
+++ b/libstb/secvar/Makefile.inc
@@ -7,7 +7,7 @@ SUBDIRS += $(SECVAR_DIR)
 include $(SECVAR_DIR)/storage/Makefile.inc
 include $(SECVAR_DIR)/backend/Makefile.inc
 
-SECVAR_SRCS = secvar_main.c secvar_util.c secvar_devtree.c secvar_tpmnv.c
+SECVAR_SRCS = secvar_main.c secvar_util.c secvar_devtree.c secvar_tpmnv.c secvar_api.c
 SECVAR_OBJS = $(SECVAR_SRCS:%.c=%.o)
 SECVAR = $(SECVAR_DIR)/built-in.a
 
diff --git a/libstb/secvar/secvar_api.c b/libstb/secvar/secvar_api.c
new file mode 100644
index 00000000..02954590
--- /dev/null
+++ b/libstb/secvar/secvar_api.c
@@ -0,0 +1,158 @@
+// SPDX-License-Identifier: Apache-2.0
+/* Copyright 2019 IBM Corp. */
+
+#ifndef pr_fmt
+#define pr_fmt(fmt) "SECVAR_API: " fmt
+#endif
+
+#include <opal.h>
+#include "secvar.h"
+
+
+static int64_t opal_secvar_get(const char *key, uint64_t key_len, void *data, uint64_t *data_size)
+{
+	struct secvar_node *node;
+	int64_t rc = OPAL_SUCCESS;
+
+	if (!secvar_enabled)
+		return OPAL_UNSUPPORTED;
+	if (!secvar_ready)
+		return OPAL_RESOURCE;
+	if (!key)
+		return OPAL_PARAMETER;
+	if (key_len == 0)
+		return OPAL_PARAMETER;
+	// Data size must be set, data is optional for size query
+	if (!data_size)
+		return OPAL_PARAMETER;
+
+	node = find_secvar(key, key_len, &variable_bank);
+
+	if (!node)
+		return OPAL_EMPTY; // Variable not found, bail early
+
+	if (!data)
+		rc = OPAL_SUCCESS;
+	else if (*data_size < node->var->data_size)
+		rc = OPAL_PARTIAL;
+	else
+		memcpy(data, node->var->data, node->var->data_size);
+
+	*data_size = node->var->data_size;
+
+	return rc;
+}
+opal_call(OPAL_SECVAR_GET, opal_secvar_get, 4);
+
+
+static int64_t opal_secvar_get_next(char *key, uint64_t *key_len, uint64_t key_buf_size)
+{
+	struct secvar_node *node;
+
+	if (!secvar_enabled)
+		return OPAL_UNSUPPORTED;
+	if (!secvar_ready)
+		return OPAL_RESOURCE;
+	if (!key_len)
+		return OPAL_PARAMETER;
+	if (key_buf_size == 0)
+		return OPAL_PARAMETER;
+	if (*key_len > SECVAR_MAX_KEY_LEN)
+		return OPAL_PARAMETER;
+	if (*key_len > key_buf_size)
+		return OPAL_PARAMETER;
+	if (!key)
+		return OPAL_PARAMETER;
+
+	if (!is_key_empty(key, *key_len)) {
+		node = find_secvar(key, *key_len, &variable_bank);
+		if (!node)
+			return OPAL_PARAMETER;
+
+		node = list_next(&variable_bank, node, link);
+	} else
+		node = list_top(&variable_bank, struct secvar_node, link);
+
+	if (!node)
+		return OPAL_EMPTY;
+
+	if (key_buf_size < node->var->key_len) {
+		*key_len = node->var->key_len;
+		return OPAL_PARTIAL;
+	}
+
+	*key_len = node->var->key_len;
+	memcpy(key, node->var->key, node->var->key_len);
+
+	return OPAL_SUCCESS;
+}
+opal_call(OPAL_SECVAR_GET_NEXT, opal_secvar_get_next, 3);
+
+
+static int64_t opal_secvar_enqueue_update(const char *key, uint64_t key_len, void *data, uint64_t data_size)
+{
+	struct secvar_node *node;
+
+	if (!secvar_enabled)
+		return OPAL_UNSUPPORTED;
+	if (!secvar_ready)
+		return OPAL_RESOURCE;
+	if (!secvar_storage.write_bank)
+		return OPAL_HARDWARE;
+	if (!key)
+		return OPAL_PARAMETER;
+	if (key_len == 0)
+		return OPAL_PARAMETER;
+	if (key_len > SECVAR_MAX_KEY_LEN)
+		return OPAL_PARAMETER;
+	if ((!data) && (data_size != 0))
+		return OPAL_PARAMETER;
+	if (data_size > secvar_storage.max_var_size)
+		return OPAL_PARAMETER;
+
+	// Key should not be empty
+	if (is_key_empty(key, key_len))
+		return OPAL_PARAMETER;
+
+	node = find_secvar(key, key_len, &update_bank);
+
+	// Unstage an update
+	if (data_size == 0) {
+		if (!node)
+			return OPAL_EMPTY;
+
+		if (node->var)
+			free(node->var);
+		list_del(&node->link);
+		free(node);
+		goto out;
+	}
+
+	if (node) {
+		list_del(&node->link);
+		// Realloc var if too small
+		if (node->size < data_size) {
+			if (realloc_secvar(node, data_size))
+				return OPAL_NO_MEM;
+		}
+		else
+			memset(node->var, 0x00, sizeof(struct secvar) + node->var->data_size);
+	} else {
+		node = alloc_secvar(data_size);
+		if (!node)
+			return OPAL_NO_MEM;
+	}
+
+	memcpy(node->var->key, key, key_len);
+	node->var->key_len = key_len;
+	memcpy(node->var->data, data, data_size);
+	node->var->data_size = data_size;
+
+	list_add_tail(&update_bank, &node->link);
+
+out:
+	secvar_storage.write_bank(&update_bank, SECVAR_UPDATE_BANK);
+
+	return OPAL_SUCCESS;
+}
+opal_call(OPAL_SECVAR_ENQUEUE_UPDATE, opal_secvar_enqueue_update, 4);
