diff --git a/include/platform.h b/include/platform.h
index 0b043856..412f8fc8 100644
--- a/include/platform.h
+++ b/include/platform.h
@@ -210,6 +210,8 @@ struct platform {
 					    uint32_t len);
 	int		(*nvram_write)(uint32_t dst, void *src, uint32_t len);
 
+	int (*secvar_init)(void);
+
 	/*
 	 * OCC timeout. This return how long we should wait for the OCC
 	 * before timing out. This lets us use a high value on larger FSP
diff --git a/include/secvar.h b/include/secvar.h
new file mode 100644
index 00000000..5514cfbe
--- /dev/null
+++ b/include/secvar.h
@@ -0,0 +1,46 @@
+/* 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 _SECVAR_DRIVER_
+#define _SECVAR_DRIVER_
+
+#include <stdint.h>
+
+struct secvar;
+
+struct secvar_storage_driver {
+        int (*load_bank)(struct list_head *bank, int section);
+        int (*write_bank)(struct list_head *bank, int section);
+        int (*store_init)(void);
+};
+
+struct secvar_backend_version {
+	int major;
+	int minor;
+} __packed;
+
+struct secvar_backend_driver {
+        int (*pre_process)(void);               // Perform any pre-processing stuff (e.g. determine secure boot state)
+        int (*process)(void);                   // Process all updates
+        int (*post_process)(void);              // Perform any post-processing stuff (e.g. derive/update variables)
+        int (*validate)(struct secvar *var);    // Validate a single variable, return boolean
+        char compatible[32];			// String to use for compatible in secvar node
+};
+
+
+int secvar_main(struct secvar_storage_driver, struct secvar_backend_driver);
+
+#endif
diff --git a/libstb/Makefile.inc b/libstb/Makefile.inc
index 6d54c5cd..d3f68496 100644
--- a/libstb/Makefile.inc
+++ b/libstb/Makefile.inc
@@ -8,11 +8,12 @@ LIBSTB_SRCS = container.c tpm_chip.c cvc.c secureboot.c trustedboot.c
 LIBSTB_OBJS = $(LIBSTB_SRCS:%.c=%.o)
 LIBSTB = $(LIBSTB_DIR)/built-in.a
 
+include $(SRC)/$(LIBSTB_DIR)/secvar/Makefile.inc
 include $(SRC)/$(LIBSTB_DIR)/mbedtls/Makefile.inc
 include $(SRC)/$(LIBSTB_DIR)/drivers/Makefile.inc
 include $(SRC)/$(LIBSTB_DIR)/tss/Makefile.inc
 
-$(LIBSTB): $(LIBSTB_OBJS:%=$(LIBSTB_DIR)/%) $(DRIVERS) $(TSS) $(MBEDTLS)
+$(LIBSTB): $(LIBSTB_OBJS:%=$(LIBSTB_DIR)/%) $(DRIVERS) $(TSS) $(SECVAR) $(MBEDTLS)
 
 libstb/create-container: libstb/create-container.c libstb/container-utils.c
 	$(call Q, HOSTCC ,$(HOSTCC) $(HOSTCFLAGS) \
diff --git a/libstb/secvar/Makefile.inc b/libstb/secvar/Makefile.inc
new file mode 100644
index 00000000..75870910
--- /dev/null
+++ b/libstb/secvar/Makefile.inc
@@ -0,0 +1,14 @@
+# -*-Makefile-*-
+
+SECVAR_DIR = libstb/secvar
+
+SUBDIRS += $(SECVAR_DIR)
+
+include $(SECVAR_DIR)/storage/Makefile.inc
+include $(SECVAR_DIR)/backend/Makefile.inc
+
+SECVAR_SRCS = secvar_main.c secvar_util.c
+SECVAR_OBJS = $(SECVAR_SRCS:%.c=%.o)
+SECVAR = $(SECVAR_DIR)/built-in.a
+
+$(SECVAR): $(SECVAR_OBJS:%=$(SECVAR_DIR)/%) $(SECVAR_STORAGE) $(SECVAR_BACKEND)
diff --git a/libstb/secvar/backend/Makefile.inc b/libstb/secvar/backend/Makefile.inc
new file mode 100644
index 00000000..7a7ca1f7
--- /dev/null
+++ b/libstb/secvar/backend/Makefile.inc
@@ -0,0 +1,11 @@
+# -*-Makefile-*-
+
+SECVAR_BACKEND_DIR = libstb/secvar/backend
+
+SUBDIRS += $(SECVAR_BACKEND_DIR)
+
+SECVAR_BACKEND_SRCS =
+SECVAR_BACKEND_OBJS = $(SECVAR_BACKEND_SRCS:%.c=%.o)
+SECVAR_BACKEND = $(SECVAR_BACKEND_DIR)/built-in.a
+
+$(SECVAR_BACKEND): $(SECVAR_BACKEND_OBJS:%=$(SECVAR_BACKEND_DIR)/%)
diff --git a/libstb/secvar/secvar.h b/libstb/secvar/secvar.h
new file mode 100644
index 00000000..3118278b
--- /dev/null
+++ b/libstb/secvar/secvar.h
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: Apache-2.0
+/* Copyright 2013-2019 IBM Corp. */
+
+#ifndef _SECVAR_H_
+#define _SECVAR_H_
+
+#include <ccan/list/list.h>
+#include <stdint.h>
+#include <secvar.h>
+
+#define SECVAR_MAX_KEY_LEN		1024
+#define SECVAR_MAX_DATA_SIZE		2048
+
+enum {
+	SECVAR_VARIABLE_BANK,
+	SECVAR_UPDATE_BANK,
+};
+
+
+struct secvar_node {
+	struct list_node link;
+	struct secvar *var;
+	uint64_t flags;		// Flag for how *var should be stored/allocated
+};
+
+#define SECVAR_FLAG_VOLATILE		0x1 // Instructs storage driver to ignore variable on writes
+#define SECVAR_FLAG_SECURE_STORAGE	0x2 // Hint for storage driver to select storage location
+
+struct secvar {
+	uint64_t key_len;
+	uint64_t data_size;
+	char key[SECVAR_MAX_KEY_LEN];
+	char data[0];
+};
+
+
+enum {
+	BACKEND_NONE = 0,
+	BACKEND_TC_COMPAT_V1,
+};
+
+extern struct list_head variable_bank;
+extern struct list_head update_bank;
+extern int secvar_enabled;
+extern int secvar_ready;
+extern struct secvar_storage_driver secvar_storage;
+extern struct secvar_backend_driver secvar_backend;
+
+// Check for secvar support, update secureboot DT compatible if so
+int probe_secvar(void);
+
+// To be called by the backend (at some point) to create the secure-mode devtree prop
+int secvar_set_secure_mode(uint64_t val);
+
+// Helper functions
+void clear_bank_list(struct list_head *bank);
+struct secvar_node *find_secvar(const char *key, uint64_t key_len, struct list_head *bank);
+int is_key_empty(const char *key, uint64_t key_len);
+int list_length(struct list_head *bank);
+
+#endif
diff --git a/libstb/secvar/secvar_main.c b/libstb/secvar/secvar_main.c
new file mode 100644
index 00000000..479c09e7
--- /dev/null
+++ b/libstb/secvar/secvar_main.c
@@ -0,0 +1,160 @@
+// SPDX-License-Identifier: Apache-2.0
+/* Copyright 2019 IBM Corp. */
+
+#ifndef pr_fmt
+#define pr_fmt(fmt) "SECVAR: " fmt
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <skiboot.h>
+#include <opal.h>
+#include <device.h>
+#include "secvar.h"
+
+struct list_head variable_bank;
+struct list_head update_bank;
+
+int secvar_enabled = 0;	// Set to 1 if secvar is supported
+int secvar_ready = 0;	// Set to 1 when base secvar inits correctly
+
+// To be filled in by platform.secvar_init
+struct secvar_storage_driver secvar_storage = {0};
+struct secvar_backend_driver secvar_backend = {0};
+
+// TODO: handle this better
+struct dt_node *secvar_node;
+
+int probe_secvar(void)
+{
+	struct dt_node *sb_node;
+	struct dt_property *sb_compat;
+
+	if (!platform.secvar_init)
+		return 0;
+
+	sb_node = dt_find_by_path(dt_root, "/ibm,secureboot/");
+	if (!sb_node)
+		return 1;
+
+	// TODO: create if doesn't exist?
+	sb_compat = (struct dt_property*) dt_find_property(sb_node, "compatible");
+	if (!sb_compat)
+		return 2;
+
+	strcpy(sb_compat->prop, "ibm,secureboot-v3");
+
+	return 0;
+}
+
+int secvar_set_secure_mode(uint64_t val)
+{
+	struct dt_property *node;
+
+	if (!secvar_node)
+		return -1;
+
+	node = (struct dt_property *) dt_find_property(secvar_node, "secure-mode");
+	if (!node)
+		return -2;
+
+	memcpy(node->prop, &val, sizeof(uint64_t));
+
+	return 0;
+}
+
+static void secvar_init_devnode(void)
+{
+	struct dt_node *sb_root;
+
+	sb_root = dt_find_by_path(dt_root, "/ibm,secureboot/");
+
+	secvar_node = dt_new(sb_root, "secvar");
+
+	dt_add_property_string(secvar_node, "compatible", secvar_backend.compatible);
+	dt_add_property_u64(secvar_node, "secure-mode", 0);
+}
+
+static void secvar_set_status(const char *status)
+{
+	struct dt_property *stat_prop;
+	if (!secvar_node)
+		return; // Fail boot?
+
+	stat_prop = (struct dt_property *) dt_find_property(secvar_node, "compatible");
+
+	if (stat_prop)
+		strcpy(stat_prop->prop, "ibm,secureboot-v3");
+	else
+		dt_add_property_string(secvar_node, "status", status);
+		// Fail boot if not successful?
+}
+
+int secvar_main(struct secvar_storage_driver storage_driver,
+               struct secvar_backend_driver backend_driver)
+{
+	int rc = OPAL_UNSUPPORTED;
+
+	secvar_storage = storage_driver;
+	secvar_backend = backend_driver;
+
+	secvar_init_devnode();
+
+	secvar_enabled = 1;
+
+	list_head_init(&variable_bank);
+	list_head_init(&update_bank);
+
+	rc = secvar_storage.store_init();
+	if (rc)
+		goto fail;
+
+
+	rc = secvar_storage.load_bank(&variable_bank, SECVAR_VARIABLE_BANK);
+	if (rc)
+		goto fail;
+
+	rc = secvar_storage.load_bank(&update_bank, SECVAR_UPDATE_BANK);
+	if (rc)
+		goto fail;
+
+	// At this point, base secvar is functional. Rest is up to the backend
+	secvar_ready = 1;
+
+	if (secvar_backend.pre_process)
+		rc = secvar_backend.pre_process();
+
+	// Process is required, error if it doesn't exist
+	if (!secvar_backend.process)
+		goto out;
+
+	rc = secvar_backend.process();
+	if (rc == OPAL_SUCCESS) {
+		dt_add_property(secvar_node, "update-status", &rc, sizeof(rc));
+		// TODO: Should being unable to write be a secvar/status = "fail"?
+		rc = secvar_storage.write_bank(&variable_bank, SECVAR_VARIABLE_BANK);
+		if (rc)
+			goto out;
+
+		rc = secvar_storage.write_bank(&update_bank, SECVAR_UPDATE_BANK);
+		if (rc)
+			goto out;
+	}
+	else
+		dt_add_property(secvar_node, "update-status", &rc, sizeof(rc));
+
+	// Last point of possible base secvar failure
+	secvar_set_status("okay");
+
+	if (secvar_backend.post_process)
+		rc = secvar_backend.post_process();
+	if (rc)
+		goto out;
+
+	return OPAL_SUCCESS;
+fail:
+	secvar_set_status("fail");
+out:
+	printf("Secure Variables Status %04x\n", rc);
+	return rc;
+}
diff --git a/libstb/secvar/secvar_util.c b/libstb/secvar/secvar_util.c
new file mode 100644
index 00000000..e3ceabda
--- /dev/null
+++ b/libstb/secvar/secvar_util.c
@@ -0,0 +1,70 @@
+// SPDX-License-Identifier: Apache-2.0
+/* Copyright 2019 IBM Corp. */
+
+#ifndef pr_fmt
+#define pr_fmt(fmt) "SECVAR: " fmt
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <skiboot.h>
+#include <opal.h>
+#include "secvar.h"
+
+void clear_bank_list(struct list_head *bank)
+{
+	struct secvar_node *node, *next;
+
+	if (!bank)
+		return;
+
+	list_for_each_safe(bank, node, next, link) {
+		list_del(&node->link);
+
+		if (node->var) {
+			free(node->var);
+		}
+
+		free(node);
+	}
+}
+
+struct secvar_node *find_secvar(const char *key, uint64_t key_len, struct list_head *bank)
+{
+	struct secvar_node *node = NULL;
+
+	list_for_each(bank, node, link) {
+		// Prevent matching shorter key subsets / bail early
+		if (key_len != node->var->key_len)
+			continue;
+		if (!memcmp(key, node->var->key, key_len)) {
+			return node;
+		}
+	}
+
+	return NULL;
+}
+
+
+int is_key_empty(const char *key, uint64_t key_len)
+{
+	int i;
+	for (i = 0; i < key_len; i++) {
+		if (key[i] != 0)
+			return 0;
+	}
+
+	return 1;
+}
+
+int list_length(struct list_head *bank)
+{
+	int ret = 0;
+	struct secvar_node *node;
+
+	list_for_each(bank, node, link) {
+		ret++;
+	}
+
+	return ret;
+}
diff --git a/libstb/secvar/storage/Makefile.inc b/libstb/secvar/storage/Makefile.inc
new file mode 100644
index 00000000..c107736e
--- /dev/null
+++ b/libstb/secvar/storage/Makefile.inc
@@ -0,0 +1,11 @@
+# -*-Makefile-*-
+
+SECVAR_STORAGE_DIR = libstb/secvar/storage
+
+SUBDIRS += $(SECVAR_STORAGE_DIR)
+
+SECVAR_STORAGE_SRCS =
+SECVAR_STORAGE_OBJS = $(SECVAR_STORAGE_SRCS:%.c=%.o)
+SECVAR_STORAGE = $(SECVAR_STORAGE_DIR)/built-in.a
+
+$(SECVAR_STORAGE): $(SECVAR_STORAGE_OBJS:%=$(SECVAR_STORAGE_DIR)/%)
