@@ -16,6 +16,52 @@
#include <acpi/nfit.h>
#include "nfit.h"
+static int intel_dimm_security_freeze_lock(struct nvdimm_bus *nvdimm_bus,
+ struct nvdimm *nvdimm)
+{
+ struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus);
+ int cmd_rc, rc = 0, pkg_size;
+ struct nd_intel_freeze_lock *cmd;
+ struct nd_cmd_pkg *pkg;
+ struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
+
+ if (!test_bit(NVDIMM_INTEL_FREEZE_LOCK, &nfit_mem->dsm_mask))
+ return -ENOTTY;
+
+ pkg_size = sizeof(*pkg) + sizeof(*cmd);
+ pkg = kzalloc(pkg_size, GFP_KERNEL);
+ if (!pkg)
+ return -ENOMEM;
+
+ pkg->nd_command = NVDIMM_INTEL_FREEZE_LOCK;
+ pkg->nd_family = NVDIMM_FAMILY_INTEL;
+ pkg->nd_size_in = 0;
+ pkg->nd_size_out = ND_INTEL_STATUS_SIZE;
+ pkg->nd_fw_size = pkg->nd_size_out;
+ cmd = (struct nd_intel_freeze_lock *)&pkg->nd_payload;
+ rc = nd_desc->ndctl(nd_desc, nvdimm, ND_CMD_CALL, pkg,
+ sizeof(pkg_size), &cmd_rc);
+ if (rc < 0)
+ goto out;
+ if (cmd_rc < 0) {
+ rc = cmd_rc;
+ goto out;
+ }
+
+ switch (cmd->status) {
+ case 0:
+ break;
+ case ND_INTEL_STATUS_INVALID_STATE:
+ default:
+ rc = -ENXIO;
+ goto out;
+ }
+
+ out:
+ kfree(pkg);
+ return rc;
+}
+
static int intel_dimm_security_disable(struct nvdimm_bus *nvdimm_bus,
struct nvdimm *nvdimm, const char *pass)
{
@@ -244,4 +290,5 @@ struct nvdimm_security_ops intel_security_ops = {
.unlock = intel_dimm_security_unlock,
.change_key = intel_dimm_security_update_passphrase,
.disable = intel_dimm_security_disable,
+ .freeze_lock = intel_dimm_security_freeze_lock,
};
@@ -85,6 +85,26 @@ int nvdimm_security_get_state(struct device *dev)
&nvdimm->state);
}
+static int nvdimm_security_freeze_lock(struct device *dev)
+{
+ struct nvdimm *nvdimm = to_nvdimm(dev);
+ struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev);
+ int rc;
+
+ if (!nvdimm->security_ops)
+ return 0;
+
+ if (nvdimm->state == NVDIMM_SECURITY_UNSUPPORTED)
+ return 0;
+
+ rc = nvdimm->security_ops->freeze_lock(nvdimm_bus, nvdimm);
+ if (rc < 0)
+ return rc;
+
+ nvdimm_security_get_state(dev);
+ return 0;
+}
+
static int nvdimm_security_disable(struct device *dev)
{
struct nvdimm *nvdimm = to_nvdimm(dev);
@@ -628,6 +648,8 @@ static ssize_t security_store(struct device *dev,
rc = nvdimm_security_change_key(dev);
else if (strcmp(buf, "disable") == 0 || strcmp(buf, "disable\n") == 0)
rc = nvdimm_security_disable(dev);
+ else if (strcmp(buf, "freeze") == 0 || strcmp(buf, "freeze\n") == 0)
+ rc = nvdimm_security_freeze_lock(dev);
else
return -EINVAL;
@@ -179,6 +179,8 @@ struct nvdimm_security_ops {
const char *new_pass);
int (*disable)(struct nvdimm_bus *nvdimm_bus,
struct nvdimm *nvdimm, const char *pass);
+ int (*freeze_lock)(struct nvdimm_bus *nvdimm_bus,
+ struct nvdimm *nvdimm);
};
void badrange_init(struct badrange *badrange);
Adding support for freeze security on Intel nvdimm. This locks out any changes to security for the DIMM unless a reboot is done. This is triggered by writing "freeze" to the "security" sysfs attribute. libnvdimm will support the generic freeze_lock API call. Signed-off-by: Dave Jiang <dave.jiang@intel.com> --- drivers/acpi/nfit/intel.c | 47 ++++++++++++++++++++++++++++++++++++++++++++ drivers/nvdimm/dimm_devs.c | 22 +++++++++++++++++++++ include/linux/libnvdimm.h | 2 ++ 3 files changed, 71 insertions(+)