diff --git a/fs/Kconfig b/fs/Kconfig
index 5976eb33535f..19ea28143428 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -276,6 +276,7 @@ config ARCH_HAS_GIGANTIC_PAGE
 
 source "fs/configfs/Kconfig"
 source "fs/efivarfs/Kconfig"
+source "fs/fwsecurityfs/Kconfig"
 
 endmenu
 
diff --git a/fs/Makefile b/fs/Makefile
index 208a74e0b00e..5792cd0443cb 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -137,6 +137,7 @@ obj-$(CONFIG_F2FS_FS)		+= f2fs/
 obj-$(CONFIG_CEPH_FS)		+= ceph/
 obj-$(CONFIG_PSTORE)		+= pstore/
 obj-$(CONFIG_EFIVAR_FS)		+= efivarfs/
+obj-$(CONFIG_FWSECURITYFS)		+= fwsecurityfs/
 obj-$(CONFIG_EROFS_FS)		+= erofs/
 obj-$(CONFIG_VBOXSF_FS)		+= vboxsf/
 obj-$(CONFIG_ZONEFS_FS)		+= zonefs/
diff --git a/fs/fwsecurityfs/Kconfig b/fs/fwsecurityfs/Kconfig
new file mode 100644
index 000000000000..f1665511eeb9
--- /dev/null
+++ b/fs/fwsecurityfs/Kconfig
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Copyright (C) 2022 IBM Corporation
+# Author: Nayna Jain <nayna@linux.ibm.com>
+#
+
+config FWSECURITYFS
+	bool "Enable the fwsecurityfs filesystem"
+	help
+	  This will build the fwsecurityfs file system which is recommended
+	  to be mounted on /sys/firmware/security. This can be used by
+	  platforms to expose their variables which are managed by firmware.
+
+	  If you are unsure how to answer this question, answer N.
diff --git a/fs/fwsecurityfs/Makefile b/fs/fwsecurityfs/Makefile
new file mode 100644
index 000000000000..b9931d180178
--- /dev/null
+++ b/fs/fwsecurityfs/Makefile
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Copyright (C) 2022 IBM Corporation
+# Author: Nayna Jain <nayna@linux.ibm.com>
+#
+# Makefile for the firmware security filesystem
+
+obj-$(CONFIG_FWSECURITYFS)		+= fwsecurityfs.o
+
+fwsecurityfs-objs			:= inode.o super.o
diff --git a/fs/fwsecurityfs/inode.c b/fs/fwsecurityfs/inode.c
new file mode 100644
index 000000000000..5d06dc0de059
--- /dev/null
+++ b/fs/fwsecurityfs/inode.c
@@ -0,0 +1,159 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2022 IBM Corporation
+ * Author: Nayna Jain <nayna@linux.ibm.com>
+ */
+
+#include <linux/sysfs.h>
+#include <linux/kobject.h>
+#include <linux/fs.h>
+#include <linux/fs_context.h>
+#include <linux/mount.h>
+#include <linux/pagemap.h>
+#include <linux/init.h>
+#include <linux/namei.h>
+#include <linux/security.h>
+#include <linux/lsm_hooks.h>
+#include <linux/magic.h>
+#include <linux/ctype.h>
+#include <linux/fwsecurityfs.h>
+
+#include "internal.h"
+
+int fwsecurityfs_remove_file(struct dentry *dentry)
+{
+	drop_nlink(d_inode(dentry));
+	dput(dentry);
+	return 0;
+};
+EXPORT_SYMBOL_GPL(fwsecurityfs_remove_file);
+
+int fwsecurityfs_create_file(const char *name, umode_t mode,
+					u16 filesize, struct dentry *parent,
+					struct dentry *dentry,
+					const struct file_operations *fops)
+{
+	struct inode *inode;
+	int error;
+	struct inode *dir;
+
+	if (!parent)
+		return -EINVAL;
+
+	dir = d_inode(parent);
+	pr_debug("securityfs: creating file '%s'\n", name);
+
+	inode = new_inode(dir->i_sb);
+	if (!inode) {
+		error = -ENOMEM;
+		goto out1;
+	}
+
+	inode->i_ino = get_next_ino();
+	inode->i_mode = mode;
+	inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
+
+	if (fops)
+		inode->i_fop = fops;
+	else
+		inode->i_fop = &simple_dir_operations;
+
+	if (!dentry) {
+		dentry = fwsecurityfs_alloc_dentry(parent, name);
+		if (IS_ERR(dentry)) {
+			error = PTR_ERR(dentry);
+			goto out;
+		}
+	}
+
+	inode_lock(inode);
+	i_size_write(inode, filesize);
+	d_instantiate(dentry, inode);
+	dget(dentry);
+	d_add(dentry, inode);
+	inode_unlock(inode);
+	return 0;
+
+out1:
+	if (dentry)
+		dput(dentry);
+out:
+	return error;
+}
+EXPORT_SYMBOL_GPL(fwsecurityfs_create_file);
+
+struct dentry *fwsecurityfs_create_dir(const char *name, umode_t mode,
+				       struct dentry *parent,
+				       const struct inode_operations *iops)
+{
+	struct dentry *dentry;
+	struct inode *inode;
+	int error;
+	struct inode *dir;
+	struct super_block *fwsecsb;
+
+	if (!parent) {
+		fwsecsb = fwsecurityfs_get_superblock();
+		if (!fwsecsb)
+			return ERR_PTR(-EIO);
+		parent = fwsecsb->s_root;
+	}
+
+	dir = d_inode(parent);
+
+	inode_lock(dir);
+	dentry = lookup_one_len(name, parent, strlen(name));
+	if (IS_ERR(dentry))
+		goto out;
+
+	inode = new_inode(dir->i_sb);
+	if (!inode) {
+		error = -ENOMEM;
+		goto out1;
+	}
+
+	inode->i_ino = get_next_ino();
+	inode->i_mode = mode;
+	inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
+	if (iops)
+		inode->i_op = iops;
+	else
+		inode->i_op = &simple_dir_inode_operations;
+	inode->i_fop = &simple_dir_operations;
+	inc_nlink(inode);
+	inc_nlink(dir);
+	d_instantiate(dentry, inode);
+	dget(dentry);
+	inode_unlock(dir);
+	return dentry;
+
+out1:
+	dput(dentry);
+	dentry = ERR_PTR(error);
+out:
+	inode_unlock(dir);
+	return dentry;
+}
+EXPORT_SYMBOL_GPL(fwsecurityfs_create_dir);
+
+int fwsecurityfs_remove_dir(struct dentry *dentry)
+{
+	struct inode *dir;
+
+	if (!dentry || IS_ERR(dentry))
+		return -EINVAL;
+
+	if (!d_is_dir(dentry))
+		return -EPERM;
+
+	dir = d_inode(dentry->d_parent);
+	inode_lock(dir);
+	if (simple_positive(dentry)) {
+		simple_rmdir(dir, dentry);
+		dput(dentry);
+	}
+	inode_unlock(dir);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(fwsecurityfs_remove_dir);
diff --git a/fs/fwsecurityfs/internal.h b/fs/fwsecurityfs/internal.h
new file mode 100644
index 000000000000..b73f6d4b9504
--- /dev/null
+++ b/fs/fwsecurityfs/internal.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2022 IBM Corporation
+ * Author: Nayna Jain <nayna@linux.ibm.com>
+ */
+
+#ifndef __FWSECURITYFS_INTERNAL_H
+#define __FWSECURITYFS_INTERNAL_H
+
+struct dentry *fwsecurityfs_alloc_dentry(struct dentry *parent,
+					 const char *name);
+
+#endif
diff --git a/fs/fwsecurityfs/super.c b/fs/fwsecurityfs/super.c
new file mode 100644
index 000000000000..9930889c22a5
--- /dev/null
+++ b/fs/fwsecurityfs/super.c
@@ -0,0 +1,154 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2022 IBM Corporation
+ * Author: Nayna Jain <nayna@linux.ibm.com>
+ */
+
+#include <linux/sysfs.h>
+#include <linux/kobject.h>
+#include <linux/fs.h>
+#include <linux/fs_context.h>
+#include <linux/mount.h>
+#include <linux/pagemap.h>
+#include <linux/init.h>
+#include <linux/namei.h>
+#include <linux/security.h>
+#include <linux/lsm_hooks.h>
+#include <linux/magic.h>
+#include <linux/ctype.h>
+#include <linux/fwsecurityfs.h>
+
+#include "internal.h"
+
+static struct super_block *fwsecsb;
+
+struct super_block *fwsecurityfs_get_superblock(void)
+{
+	return fwsecsb;
+}
+
+static int fwsecurityfs_d_hash(const struct dentry *dir, struct qstr *this)
+{
+	unsigned long hash;
+	int i;
+
+	hash = init_name_hash(dir);
+	for (i = 0; i < this->len; i++)
+		hash = partial_name_hash(tolower(this->name[i]), hash);
+	this->hash = end_name_hash(hash);
+
+	return 0;
+}
+
+static int fwsecurityfs_d_compare(const struct dentry *dentry,
+				  unsigned int len, const char *str,
+				  const struct qstr *name)
+{
+	int i;
+	int result = 1;
+
+	if (len != name->len)
+		goto out;
+	for (i = 0; i < len; i++) {
+		if (tolower(str[i]) != tolower(name->name[i]))
+			goto out;
+	}
+	result = 0;
+out:
+	return result;
+}
+
+struct dentry *fwsecurityfs_alloc_dentry(struct dentry *parent, const char *name)
+{
+	struct dentry *d;
+	struct qstr q;
+	int err;
+
+	q.name = name;
+	q.len = strlen(name);
+
+	err = fwsecurityfs_d_hash(parent, &q);
+	if (err)
+		return ERR_PTR(err);
+
+	d = d_alloc(parent, &q);
+	if (d)
+		return d;
+
+	return ERR_PTR(-ENOMEM);
+}
+
+static const struct dentry_operations fwsecurityfs_d_ops = {
+	.d_compare = fwsecurityfs_d_compare,
+	.d_hash = fwsecurityfs_d_hash,
+	.d_delete = always_delete_dentry,
+};
+
+static const struct super_operations securityfs_super_operations = {
+	.statfs = simple_statfs,
+	.drop_inode = generic_delete_inode,
+};
+
+static int fwsecurityfs_fill_super(struct super_block *sb,
+				   struct fs_context *fc)
+{
+	static const struct tree_descr files[] = {{""}};
+	int error;
+
+	error = simple_fill_super(sb, FWSECURITYFS_MAGIC, files);
+	if (error)
+		return error;
+
+	sb->s_d_op = &fwsecurityfs_d_ops;
+
+	fwsecsb = sb;
+
+	error = arch_fwsecurity_init();
+	if (error)
+		pr_err("arch specific firmware initialization failed\n");
+
+	return 0;
+}
+
+static int fwsecurityfs_get_tree(struct fs_context *fc)
+{
+	return get_tree_single(fc, fwsecurityfs_fill_super);
+}
+
+static const struct fs_context_operations fwsecurityfs_context_ops = {
+	.get_tree	= fwsecurityfs_get_tree,
+};
+
+static int fwsecurityfs_init_fs_context(struct fs_context *fc)
+{
+	fc->ops = &fwsecurityfs_context_ops;
+	return 0;
+}
+
+static struct file_system_type fs_type = {
+	.owner =	THIS_MODULE,
+	.name =		"fwsecurityfs",
+	.init_fs_context = fwsecurityfs_init_fs_context,
+	.kill_sb =	kill_litter_super,
+};
+
+static int __init fwsecurityfs_init(void)
+{
+	int retval;
+
+	retval = sysfs_create_mount_point(firmware_kobj, "security");
+	if (retval)
+		return retval;
+
+	retval = register_filesystem(&fs_type);
+	if (retval) {
+		sysfs_remove_mount_point(firmware_kobj, "security");
+		return retval;
+	}
+
+	return 0;
+}
+core_initcall(fwsecurityfs_init);
+MODULE_DESCRIPTION("Firmware Security Filesystem");
+MODULE_AUTHOR("Nayna Jain");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/fwsecurityfs.h b/include/linux/fwsecurityfs.h
new file mode 100644
index 000000000000..c079ce939f42
--- /dev/null
+++ b/include/linux/fwsecurityfs.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2022 IBM Corporation
+ * Author: Nayna Jain <nayna@linux.ibm.com>
+ */
+
+#ifndef _FWSECURITYFS_H_
+#define _FWSECURITYFS_H_
+
+#include <linux/ctype.h>
+#include <linux/fs.h>
+
+struct super_block *fwsecurityfs_get_superblock(void);
+int fwsecurityfs_create_file(const char *name, umode_t mode,
+					u16 filesize, struct dentry *parent,
+					struct dentry *dentry,
+					const struct file_operations *fops);
+int fwsecurityfs_remove_file(struct dentry *dentry);
+struct dentry *fwsecurityfs_create_dir(const char *name, umode_t mode,
+				       struct dentry *parent,
+				       const struct inode_operations *iops);
+int fwsecurityfs_remove_dir(struct dentry *dentry);
+
+static int arch_fwsecurity_init(void)
+{
+	return 0;
+}
+
+#endif /* _FWSECURITYFS_H_ */
diff --git a/include/uapi/linux/magic.h b/include/uapi/linux/magic.h
index f724129c0425..3c6754937e15 100644
--- a/include/uapi/linux/magic.h
+++ b/include/uapi/linux/magic.h
@@ -53,6 +53,7 @@
 #define QNX4_SUPER_MAGIC	0x002f		/* qnx4 fs detection */
 #define QNX6_SUPER_MAGIC	0x68191122	/* qnx6 fs detection */
 #define AFS_FS_MAGIC		0x6B414653
+#define FWSECURITYFS_MAGIC         0x5345434e      /* "SECM" */
 
 
 #define REISERFS_SUPER_MAGIC	0x52654973	/* used by gcc */
