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 0b0ae196..1451cb00 100644
--- a/include/opal-api.h
+++ b/include/opal-api.h
@@ -232,7 +232,12 @@
 #define OPAL_XIVE_GET_VP_STATE			170 /* Get NVT state */
 #define OPAL_NPU_MEM_ALLOC			171
 #define OPAL_NPU_MEM_RELEASE			172
-#define OPAL_LAST				172
+#define OPAL_SECVAR_GET				173
+#define OPAL_SECVAR_GET_SIZE			174
+#define OPAL_SECVAR_GET_NEXT			175
+#define OPAL_SECVAR_ENQUEUE_UPDATE		176
+#define OPAL_SECVAR_BACKEND			177
+#define OPAL_LAST				177
 
 #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 75870910..50316b48 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_SRCS = secvar_main.c secvar_util.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..88275401
--- /dev/null
+++ b/libstb/secvar/secvar_api.c
@@ -0,0 +1,248 @@
+/* Copyright 2019 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) "SECVAR_API: " fmt
+#endif
+
+#include <opal.h>
+#include "secvar.h"
+
+
+static int64_t opal_secvar_get(uint64_t k_key, uint64_t k_key_len, uint64_t k_metadata, uint64_t k_metadata_size, uint64_t k_data, uint64_t k_data_size)
+{
+	struct secvar_node *node;
+
+	char *key = (char *) k_key;
+	uint64_t key_len = (uint64_t) k_key_len;
+	void *metadata = (void*) k_metadata;
+	uint64_t *metadata_size = (uint64_t *) k_metadata_size;
+	void *data = (void *) k_data;
+	uint64_t *data_size = (uint64_t *) k_data_size;
+
+	int64_t rc = OPAL_SUCCESS;
+
+	if (!secvar_enabled)
+		return OPAL_UNSUPPORTED;
+	if (!key)
+		return OPAL_PARAMETER;
+	if (key_len == 0)
+		return OPAL_PARAMETER;
+	// buffer and size must both be valid OR both must be NULL
+	if ((!!metadata) != (!!metadata_size))
+		return OPAL_PARAMETER;
+	if ((!!data) != (!!data_size))
+		return OPAL_PARAMETER;
+
+	node = find_secvar(key, key_len, &variable_bank);
+
+	if (!node)
+		return OPAL_EMPTY; // Variable not found, bail early
+
+	if (metadata) {
+		if (*metadata_size < node->var->metadata_size)
+			rc = OPAL_PARTIAL;
+		else
+			memcpy(metadata, node->var->metadata, node->var->metadata_size);
+		*metadata_size = node->var->metadata_size;
+	}
+
+	if (data) {
+		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, 6);
+
+
+static int64_t opal_secvar_get_size(uint64_t k_key, uint64_t k_key_len, uint64_t k_metadata_size, uint64_t k_data_size)
+{
+	struct secvar_node *node;
+
+	char *key = (char *) k_key;
+	uint64_t *metadata_size = (uint64_t *) k_metadata_size;
+	uint64_t *data_size = (uint64_t *) k_data_size;
+
+	if (!secvar_enabled)
+		return OPAL_UNSUPPORTED;
+	if (!key)
+		return OPAL_PARAMETER;
+	if (k_key_len == 0)
+		return OPAL_PARAMETER;
+	if ((!metadata_size) && (!data_size)) // Should return at least one of them
+		return OPAL_PARAMETER;
+
+	node = find_secvar(key, k_key_len, &variable_bank);
+	if (!node)
+		return OPAL_EMPTY;
+
+	if (metadata_size)
+		*metadata_size = node->var->metadata_size;
+	if (data_size)
+		*data_size = node->var->data_size;
+
+	return OPAL_SUCCESS;
+}
+opal_call(OPAL_SECVAR_GET_SIZE, opal_secvar_get_size, 4);
+
+
+
+static int64_t opal_secvar_get_next(uint64_t k_key, uint64_t k_key_len, uint64_t k_key_size)
+{
+	struct secvar_node *node;
+
+	char *key = (char *) k_key;
+	uint64_t *key_len = (uint64_t *) k_key_len;
+	uint64_t key_size = k_key_size;
+	int i = 0;
+
+	if (!secvar_enabled)
+		return OPAL_UNSUPPORTED;
+	if (!key_len)
+		return OPAL_PARAMETER;
+	if (key_size == 0)
+		return OPAL_PARAMETER;
+	if (*key_len > SECVAR_MAX_KEY_LEN)
+		return OPAL_PARAMETER;
+	if (*key_len > key_size)
+		return OPAL_PARAMETER;
+	if (!key)
+		return OPAL_PARAMETER;
+
+	// This should fall through if *key_len == 0, otherwise check for empty
+	for (i = 0; i < *key_len; i++) {
+		// If the buffer is not empty, we assume it is a key
+		if (key[i] != 0) {
+			goto have_key;
+		}
+	}
+
+	node = list_top(&variable_bank, struct secvar_node, link);
+	goto send_var;
+
+have_key:
+	// Non-empty string
+	node = find_secvar(key, *key_len, &variable_bank);
+	if (!node)
+		return OPAL_PARAMETER;
+
+	node = list_next(&variable_bank, node, link);
+
+send_var:
+	if (!node)
+		return OPAL_EMPTY;
+
+	if (key_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(uint64_t k_key, uint64_t k_key_len, uint64_t k_metadata, uint64_t k_metadata_size, uint64_t k_data, uint64_t k_data_size)
+{
+	struct secvar_node *node;
+
+	char *key = (char *) k_key;
+	uint64_t key_len = (uint64_t) k_key_len;
+	void *metadata = (void*) k_metadata;
+	uint64_t metadata_size = (uint64_t) k_metadata_size;
+	void *data = (void *) k_data;
+	uint64_t data_size = (uint64_t) k_data_size;
+
+	if (!secvar_enabled)
+		return OPAL_UNSUPPORTED;
+	if (!key)
+		return OPAL_PARAMETER;
+	if (key_len == 0)
+		return OPAL_PARAMETER;
+	if (key_len > SECVAR_MAX_KEY_LEN)
+		return OPAL_PARAMETER;
+	if (metadata && (metadata_size > SECVAR_MAX_METADATA_SIZE))
+		return OPAL_PARAMETER;
+	if (!data)
+		return OPAL_PARAMETER;
+	if (data_size == 0)
+		return OPAL_PARAMETER;	// we don't support variable deletion this way
+	if (data_size > SECVAR_MAX_DATA_SIZE)
+		return OPAL_PARAMETER;
+
+	// Key should not be empty
+	if (is_key_empty(key, key_len)) {
+		return OPAL_PARAMETER;
+	}
+
+	node = zalloc(sizeof(struct secvar_node));
+	if (!node)
+		return OPAL_NO_MEM;
+
+	node->var = zalloc(sizeof(struct secvar));
+	if (!node->var)
+		return OPAL_NO_MEM;
+	node->var->flags = SECVAR_FLAG_DYN_ALLOC;
+
+	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;
+
+	if (metadata) {
+		memcpy(node->var->metadata, metadata, metadata_size);
+		node->var->metadata_size = metadata_size;
+	}
+	else {
+		memset(node->var->metadata, 0x00, SECVAR_MAX_METADATA_SIZE);
+		node->var->metadata_size = 0;
+	}
+
+	list_add_tail(&update_bank, &node->link);
+
+	if (!secvar_storage.write_bank)
+		return OPAL_HARDWARE;
+
+	secvar_storage.write_bank(&update_bank, SECVAR_UPDATE_BANK);
+
+	return OPAL_SUCCESS;
+}
+opal_call(OPAL_SECVAR_ENQUEUE_UPDATE, opal_secvar_enqueue_update, 6);
+
+
+static int64_t opal_secvar_backend(uint64_t k_backend)
+{
+	uint64_t *backend = (uint64_t *) k_backend;
+
+	if (!secvar_enabled)
+		return OPAL_UNSUPPORTED;
+	if (!secvar_backend.version)
+		return OPAL_UNSUPPORTED;
+	if (!backend)
+		return OPAL_PARAMETER;
+
+	*backend = secvar_backend.version;
+
+	return OPAL_SUCCESS;
+}
+opal_call(OPAL_SECVAR_BACKEND, opal_secvar_backend, 1);
