summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/nvdimm/dimm_devs.c2
-rw-r--r--tools/testing/nvdimm/Kbuild1
-rw-r--r--tools/testing/nvdimm/dimm_devs.c41
-rw-r--r--tools/testing/nvdimm/test/nfit.c180
4 files changed, 223 insertions, 1 deletions
diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c
index bd3f156463b1..4890310df874 100644
--- a/drivers/nvdimm/dimm_devs.c
+++ b/drivers/nvdimm/dimm_devs.c
@@ -370,7 +370,7 @@ static ssize_t available_slots_show(struct device *dev,
}
static DEVICE_ATTR_RO(available_slots);
-static ssize_t security_show(struct device *dev,
+__weak ssize_t security_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct nvdimm *nvdimm = to_nvdimm(dev);
diff --git a/tools/testing/nvdimm/Kbuild b/tools/testing/nvdimm/Kbuild
index 33ea40777205..10ddf223055b 100644
--- a/tools/testing/nvdimm/Kbuild
+++ b/tools/testing/nvdimm/Kbuild
@@ -81,6 +81,7 @@ libnvdimm-$(CONFIG_BTT) += $(NVDIMM_SRC)/btt_devs.o
libnvdimm-$(CONFIG_NVDIMM_PFN) += $(NVDIMM_SRC)/pfn_devs.o
libnvdimm-$(CONFIG_NVDIMM_DAX) += $(NVDIMM_SRC)/dax_devs.o
libnvdimm-$(CONFIG_NVDIMM_KEYS) += $(NVDIMM_SRC)/security.o
+libnvdimm-y += dimm_devs.o
libnvdimm-y += libnvdimm_test.o
libnvdimm-y += config_check.o
diff --git a/tools/testing/nvdimm/dimm_devs.c b/tools/testing/nvdimm/dimm_devs.c
new file mode 100644
index 000000000000..e75238404555
--- /dev/null
+++ b/tools/testing/nvdimm/dimm_devs.c
@@ -0,0 +1,41 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright Intel Corp. 2018 */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/nd.h>
+#include "pmem.h"
+#include "pfn.h"
+#include "nd.h"
+#include "nd-core.h"
+
+ssize_t security_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct nvdimm *nvdimm = to_nvdimm(dev);
+
+ /*
+ * For the test version we need to poll the "hardware" in order
+ * to get the updated status for unlock testing.
+ */
+ nvdimm->sec.state = nvdimm_security_state(nvdimm, false);
+ nvdimm->sec.ext_state = nvdimm_security_state(nvdimm, true);
+
+ switch (nvdimm->sec.state) {
+ case NVDIMM_SECURITY_DISABLED:
+ return sprintf(buf, "disabled\n");
+ case NVDIMM_SECURITY_UNLOCKED:
+ return sprintf(buf, "unlocked\n");
+ case NVDIMM_SECURITY_LOCKED:
+ return sprintf(buf, "locked\n");
+ case NVDIMM_SECURITY_FROZEN:
+ return sprintf(buf, "frozen\n");
+ case NVDIMM_SECURITY_OVERWRITE:
+ return sprintf(buf, "overwrite\n");
+ default:
+ return -ENOTTY;
+ }
+
+ return -ENOTTY;
+}
+
diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c
index 01ec04bf91b5..30f89fd740d9 100644
--- a/tools/testing/nvdimm/test/nfit.c
+++ b/tools/testing/nvdimm/test/nfit.c
@@ -142,6 +142,10 @@ static u32 handle[] = {
static unsigned long dimm_fail_cmd_flags[ARRAY_SIZE(handle)];
static int dimm_fail_cmd_code[ARRAY_SIZE(handle)];
+struct nfit_test_sec {
+ u8 state;
+ u8 passphrase[32];
+} dimm_sec_info[NUM_DCR];
static const struct nd_intel_smart smart_def = {
.flags = ND_INTEL_SMART_HEALTH_VALID
@@ -933,6 +937,138 @@ static int override_return_code(int dimm, unsigned int func, int rc)
return rc;
}
+static int nd_intel_test_cmd_security_status(struct nfit_test *t,
+ struct nd_intel_get_security_state *nd_cmd,
+ unsigned int buf_len, int dimm)
+{
+ struct device *dev = &t->pdev.dev;
+ struct nfit_test_sec *sec = &dimm_sec_info[dimm];
+
+ nd_cmd->status = 0;
+ nd_cmd->state = sec->state;
+ dev_dbg(dev, "security state (%#x) returned\n", nd_cmd->state);
+
+ return 0;
+}
+
+static int nd_intel_test_cmd_unlock_unit(struct nfit_test *t,
+ struct nd_intel_unlock_unit *nd_cmd,
+ unsigned int buf_len, int dimm)
+{
+ struct device *dev = &t->pdev.dev;
+ struct nfit_test_sec *sec = &dimm_sec_info[dimm];
+
+ if (!(sec->state & ND_INTEL_SEC_STATE_LOCKED) ||
+ (sec->state & ND_INTEL_SEC_STATE_FROZEN)) {
+ nd_cmd->status = ND_INTEL_STATUS_INVALID_STATE;
+ dev_dbg(dev, "unlock unit: invalid state: %#x\n",
+ sec->state);
+ } else if (memcmp(nd_cmd->passphrase, sec->passphrase,
+ ND_INTEL_PASSPHRASE_SIZE) != 0) {
+ nd_cmd->status = ND_INTEL_STATUS_INVALID_PASS;
+ dev_dbg(dev, "unlock unit: invalid passphrase\n");
+ } else {
+ nd_cmd->status = 0;
+ sec->state = ND_INTEL_SEC_STATE_ENABLED;
+ dev_dbg(dev, "Unit unlocked\n");
+ }
+
+ dev_dbg(dev, "unlocking status returned: %#x\n", nd_cmd->status);
+ return 0;
+}
+
+static int nd_intel_test_cmd_set_pass(struct nfit_test *t,
+ struct nd_intel_set_passphrase *nd_cmd,
+ unsigned int buf_len, int dimm)
+{
+ struct device *dev = &t->pdev.dev;
+ struct nfit_test_sec *sec = &dimm_sec_info[dimm];
+
+ if (sec->state & ND_INTEL_SEC_STATE_FROZEN) {
+ nd_cmd->status = ND_INTEL_STATUS_INVALID_STATE;
+ dev_dbg(dev, "set passphrase: wrong security state\n");
+ } else if (memcmp(nd_cmd->old_pass, sec->passphrase,
+ ND_INTEL_PASSPHRASE_SIZE) != 0) {
+ nd_cmd->status = ND_INTEL_STATUS_INVALID_PASS;
+ dev_dbg(dev, "set passphrase: wrong passphrase\n");
+ } else {
+ memcpy(sec->passphrase, nd_cmd->new_pass,
+ ND_INTEL_PASSPHRASE_SIZE);
+ sec->state |= ND_INTEL_SEC_STATE_ENABLED;
+ nd_cmd->status = 0;
+ dev_dbg(dev, "passphrase updated\n");
+ }
+
+ return 0;
+}
+
+static int nd_intel_test_cmd_freeze_lock(struct nfit_test *t,
+ struct nd_intel_freeze_lock *nd_cmd,
+ unsigned int buf_len, int dimm)
+{
+ struct device *dev = &t->pdev.dev;
+ struct nfit_test_sec *sec = &dimm_sec_info[dimm];
+
+ if (!(sec->state & ND_INTEL_SEC_STATE_ENABLED)) {
+ nd_cmd->status = ND_INTEL_STATUS_INVALID_STATE;
+ dev_dbg(dev, "freeze lock: wrong security state\n");
+ } else {
+ sec->state |= ND_INTEL_SEC_STATE_FROZEN;
+ nd_cmd->status = 0;
+ dev_dbg(dev, "security frozen\n");
+ }
+
+ return 0;
+}
+
+static int nd_intel_test_cmd_disable_pass(struct nfit_test *t,
+ struct nd_intel_disable_passphrase *nd_cmd,
+ unsigned int buf_len, int dimm)
+{
+ struct device *dev = &t->pdev.dev;
+ struct nfit_test_sec *sec = &dimm_sec_info[dimm];
+
+ if (!(sec->state & ND_INTEL_SEC_STATE_ENABLED) ||
+ (sec->state & ND_INTEL_SEC_STATE_FROZEN)) {
+ nd_cmd->status = ND_INTEL_STATUS_INVALID_STATE;
+ dev_dbg(dev, "disable passphrase: wrong security state\n");
+ } else if (memcmp(nd_cmd->passphrase, sec->passphrase,
+ ND_INTEL_PASSPHRASE_SIZE) != 0) {
+ nd_cmd->status = ND_INTEL_STATUS_INVALID_PASS;
+ dev_dbg(dev, "disable passphrase: wrong passphrase\n");
+ } else {
+ memset(sec->passphrase, 0, ND_INTEL_PASSPHRASE_SIZE);
+ sec->state = 0;
+ dev_dbg(dev, "disable passphrase: done\n");
+ }
+
+ return 0;
+}
+
+static int nd_intel_test_cmd_secure_erase(struct nfit_test *t,
+ struct nd_intel_secure_erase *nd_cmd,
+ unsigned int buf_len, int dimm)
+{
+ struct device *dev = &t->pdev.dev;
+ struct nfit_test_sec *sec = &dimm_sec_info[dimm];
+
+ if (!(sec->state & ND_INTEL_SEC_STATE_ENABLED) ||
+ (sec->state & ND_INTEL_SEC_STATE_FROZEN)) {
+ nd_cmd->status = ND_INTEL_STATUS_INVALID_STATE;
+ dev_dbg(dev, "secure erase: wrong security state\n");
+ } else if (memcmp(nd_cmd->passphrase, sec->passphrase,
+ ND_INTEL_PASSPHRASE_SIZE) != 0) {
+ nd_cmd->status = ND_INTEL_STATUS_INVALID_PASS;
+ dev_dbg(dev, "secure erase: wrong passphrase\n");
+ } else {
+ memset(sec->passphrase, 0, ND_INTEL_PASSPHRASE_SIZE);
+ sec->state = 0;
+ dev_dbg(dev, "secure erase: done\n");
+ }
+
+ return 0;
+}
+
static int get_dimm(struct nfit_mem *nfit_mem, unsigned int func)
{
int i;
@@ -980,6 +1116,30 @@ static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc,
return i;
switch (func) {
+ case NVDIMM_INTEL_GET_SECURITY_STATE:
+ rc = nd_intel_test_cmd_security_status(t,
+ buf, buf_len, i);
+ break;
+ case NVDIMM_INTEL_UNLOCK_UNIT:
+ rc = nd_intel_test_cmd_unlock_unit(t,
+ buf, buf_len, i);
+ break;
+ case NVDIMM_INTEL_SET_PASSPHRASE:
+ rc = nd_intel_test_cmd_set_pass(t,
+ buf, buf_len, i);
+ break;
+ case NVDIMM_INTEL_DISABLE_PASSPHRASE:
+ rc = nd_intel_test_cmd_disable_pass(t,
+ buf, buf_len, i);
+ break;
+ case NVDIMM_INTEL_FREEZE_LOCK:
+ rc = nd_intel_test_cmd_freeze_lock(t,
+ buf, buf_len, i);
+ break;
+ case NVDIMM_INTEL_SECURE_ERASE:
+ rc = nd_intel_test_cmd_secure_erase(t,
+ buf, buf_len, i);
+ break;
case ND_INTEL_ENABLE_LSS_STATUS:
rc = nd_intel_test_cmd_set_lss_status(t,
buf, buf_len);
@@ -1313,10 +1473,22 @@ static ssize_t fail_cmd_code_store(struct device *dev, struct device_attribute *
}
static DEVICE_ATTR_RW(fail_cmd_code);
+static ssize_t lock_dimm_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ int dimm = dimm_name_to_id(dev);
+ struct nfit_test_sec *sec = &dimm_sec_info[dimm];
+
+ sec->state = ND_INTEL_SEC_STATE_ENABLED | ND_INTEL_SEC_STATE_LOCKED;
+ return size;
+}
+static DEVICE_ATTR_WO(lock_dimm);
+
static struct attribute *nfit_test_dimm_attributes[] = {
&dev_attr_fail_cmd.attr,
&dev_attr_fail_cmd_code.attr,
&dev_attr_handle.attr,
+ &dev_attr_lock_dimm.attr,
NULL,
};
@@ -2195,6 +2367,14 @@ static void nfit_test0_setup(struct nfit_test *t)
set_bit(ND_INTEL_FW_FINISH_UPDATE, &acpi_desc->dimm_cmd_force_en);
set_bit(ND_INTEL_FW_FINISH_QUERY, &acpi_desc->dimm_cmd_force_en);
set_bit(ND_INTEL_ENABLE_LSS_STATUS, &acpi_desc->dimm_cmd_force_en);
+ set_bit(NVDIMM_INTEL_GET_SECURITY_STATE,
+ &acpi_desc->dimm_cmd_force_en);
+ set_bit(NVDIMM_INTEL_SET_PASSPHRASE, &acpi_desc->dimm_cmd_force_en);
+ set_bit(NVDIMM_INTEL_DISABLE_PASSPHRASE,
+ &acpi_desc->dimm_cmd_force_en);
+ set_bit(NVDIMM_INTEL_UNLOCK_UNIT, &acpi_desc->dimm_cmd_force_en);
+ set_bit(NVDIMM_INTEL_FREEZE_LOCK, &acpi_desc->dimm_cmd_force_en);
+ set_bit(NVDIMM_INTEL_SECURE_ERASE, &acpi_desc->dimm_cmd_force_en);
}
static void nfit_test1_setup(struct nfit_test *t)