xref: /linux/drivers/acpi/nfit/intel.c (revision 64e77c8c047fb91ea8c7800c1238108a72f0bf9c)
1f2989396SDave Jiang // SPDX-License-Identifier: GPL-2.0
2f2989396SDave Jiang /* Copyright(c) 2018 Intel Corporation. All rights reserved. */
3f2989396SDave Jiang #include <linux/libnvdimm.h>
4f2989396SDave Jiang #include <linux/ndctl.h>
5f2989396SDave Jiang #include <linux/acpi.h>
64c6926a2SDave Jiang #include <asm/smp.h>
7f2989396SDave Jiang #include "intel.h"
8f2989396SDave Jiang #include "nfit.h"
9f2989396SDave Jiang 
10f2989396SDave Jiang static enum nvdimm_security_state intel_security_state(struct nvdimm *nvdimm)
11f2989396SDave Jiang {
12f2989396SDave Jiang 	struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
13f2989396SDave Jiang 	struct {
14f2989396SDave Jiang 		struct nd_cmd_pkg pkg;
15f2989396SDave Jiang 		struct nd_intel_get_security_state cmd;
16f2989396SDave Jiang 	} nd_cmd = {
17f2989396SDave Jiang 		.pkg = {
18f2989396SDave Jiang 			.nd_command = NVDIMM_INTEL_GET_SECURITY_STATE,
19f2989396SDave Jiang 			.nd_family = NVDIMM_FAMILY_INTEL,
20f2989396SDave Jiang 			.nd_size_out =
21f2989396SDave Jiang 				sizeof(struct nd_intel_get_security_state),
22f2989396SDave Jiang 			.nd_fw_size =
23f2989396SDave Jiang 				sizeof(struct nd_intel_get_security_state),
24f2989396SDave Jiang 		},
25f2989396SDave Jiang 	};
26f2989396SDave Jiang 	int rc;
27f2989396SDave Jiang 
28f2989396SDave Jiang 	if (!test_bit(NVDIMM_INTEL_GET_SECURITY_STATE, &nfit_mem->dsm_mask))
29f2989396SDave Jiang 		return -ENXIO;
30f2989396SDave Jiang 
31f2989396SDave Jiang 	rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL);
32f2989396SDave Jiang 	if (rc < 0)
33f2989396SDave Jiang 		return rc;
34f2989396SDave Jiang 	if (nd_cmd.cmd.status)
35f2989396SDave Jiang 		return -EIO;
36f2989396SDave Jiang 
37f2989396SDave Jiang 	/* check and see if security is enabled and locked */
38f2989396SDave Jiang 	if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_UNSUPPORTED)
39f2989396SDave Jiang 		return -ENXIO;
40f2989396SDave Jiang 	else if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_ENABLED) {
41f2989396SDave Jiang 		if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_LOCKED)
42f2989396SDave Jiang 			return NVDIMM_SECURITY_LOCKED;
43f2989396SDave Jiang 		else if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_FROZEN ||
44f2989396SDave Jiang 				nd_cmd.cmd.state & ND_INTEL_SEC_STATE_PLIMIT)
45f2989396SDave Jiang 			return NVDIMM_SECURITY_FROZEN;
46f2989396SDave Jiang 		else
47f2989396SDave Jiang 			return NVDIMM_SECURITY_UNLOCKED;
48f2989396SDave Jiang 	}
49f2989396SDave Jiang 	return NVDIMM_SECURITY_DISABLED;
50f2989396SDave Jiang }
51f2989396SDave Jiang 
5237833fb7SDave Jiang static int intel_security_freeze(struct nvdimm *nvdimm)
5337833fb7SDave Jiang {
5437833fb7SDave Jiang 	struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
5537833fb7SDave Jiang 	struct {
5637833fb7SDave Jiang 		struct nd_cmd_pkg pkg;
5737833fb7SDave Jiang 		struct nd_intel_freeze_lock cmd;
5837833fb7SDave Jiang 	} nd_cmd = {
5937833fb7SDave Jiang 		.pkg = {
6037833fb7SDave Jiang 			.nd_command = NVDIMM_INTEL_FREEZE_LOCK,
6137833fb7SDave Jiang 			.nd_family = NVDIMM_FAMILY_INTEL,
6237833fb7SDave Jiang 			.nd_size_out = ND_INTEL_STATUS_SIZE,
6337833fb7SDave Jiang 			.nd_fw_size = ND_INTEL_STATUS_SIZE,
6437833fb7SDave Jiang 		},
6537833fb7SDave Jiang 	};
6637833fb7SDave Jiang 	int rc;
6737833fb7SDave Jiang 
6837833fb7SDave Jiang 	if (!test_bit(NVDIMM_INTEL_FREEZE_LOCK, &nfit_mem->dsm_mask))
6937833fb7SDave Jiang 		return -ENOTTY;
7037833fb7SDave Jiang 
7137833fb7SDave Jiang 	rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL);
7237833fb7SDave Jiang 	if (rc < 0)
7337833fb7SDave Jiang 		return rc;
7437833fb7SDave Jiang 	if (nd_cmd.cmd.status)
7537833fb7SDave Jiang 		return -EIO;
7637833fb7SDave Jiang 	return 0;
7737833fb7SDave Jiang }
7837833fb7SDave Jiang 
794c6926a2SDave Jiang static int intel_security_change_key(struct nvdimm *nvdimm,
804c6926a2SDave Jiang 		const struct nvdimm_key_data *old_data,
814c6926a2SDave Jiang 		const struct nvdimm_key_data *new_data)
824c6926a2SDave Jiang {
834c6926a2SDave Jiang 	struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
844c6926a2SDave Jiang 	struct {
854c6926a2SDave Jiang 		struct nd_cmd_pkg pkg;
864c6926a2SDave Jiang 		struct nd_intel_set_passphrase cmd;
874c6926a2SDave Jiang 	} nd_cmd = {
884c6926a2SDave Jiang 		.pkg = {
894c6926a2SDave Jiang 			.nd_command = NVDIMM_INTEL_SET_PASSPHRASE,
904c6926a2SDave Jiang 			.nd_family = NVDIMM_FAMILY_INTEL,
914c6926a2SDave Jiang 			.nd_size_in = ND_INTEL_PASSPHRASE_SIZE * 2,
924c6926a2SDave Jiang 			.nd_size_out = ND_INTEL_STATUS_SIZE,
934c6926a2SDave Jiang 			.nd_fw_size = ND_INTEL_STATUS_SIZE,
944c6926a2SDave Jiang 		},
954c6926a2SDave Jiang 	};
964c6926a2SDave Jiang 	int rc;
974c6926a2SDave Jiang 
984c6926a2SDave Jiang 	if (!test_bit(NVDIMM_INTEL_SET_PASSPHRASE, &nfit_mem->dsm_mask))
994c6926a2SDave Jiang 		return -ENOTTY;
1004c6926a2SDave Jiang 
1014c6926a2SDave Jiang 	if (old_data)
1024c6926a2SDave Jiang 		memcpy(nd_cmd.cmd.old_pass, old_data->data,
1034c6926a2SDave Jiang 				sizeof(nd_cmd.cmd.old_pass));
1044c6926a2SDave Jiang 	memcpy(nd_cmd.cmd.new_pass, new_data->data,
1054c6926a2SDave Jiang 			sizeof(nd_cmd.cmd.new_pass));
1064c6926a2SDave Jiang 	rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL);
1074c6926a2SDave Jiang 	if (rc < 0)
1084c6926a2SDave Jiang 		return rc;
1094c6926a2SDave Jiang 
1104c6926a2SDave Jiang 	switch (nd_cmd.cmd.status) {
1114c6926a2SDave Jiang 	case 0:
1124c6926a2SDave Jiang 		return 0;
1134c6926a2SDave Jiang 	case ND_INTEL_STATUS_INVALID_PASS:
1144c6926a2SDave Jiang 		return -EINVAL;
1154c6926a2SDave Jiang 	case ND_INTEL_STATUS_NOT_SUPPORTED:
1164c6926a2SDave Jiang 		return -EOPNOTSUPP;
1174c6926a2SDave Jiang 	case ND_INTEL_STATUS_INVALID_STATE:
1184c6926a2SDave Jiang 	default:
1194c6926a2SDave Jiang 		return -EIO;
1204c6926a2SDave Jiang 	}
1214c6926a2SDave Jiang }
1224c6926a2SDave Jiang 
1234c6926a2SDave Jiang static void nvdimm_invalidate_cache(void);
1244c6926a2SDave Jiang 
1254c6926a2SDave Jiang static int intel_security_unlock(struct nvdimm *nvdimm,
1264c6926a2SDave Jiang 		const struct nvdimm_key_data *key_data)
1274c6926a2SDave Jiang {
1284c6926a2SDave Jiang 	struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
1294c6926a2SDave Jiang 	struct {
1304c6926a2SDave Jiang 		struct nd_cmd_pkg pkg;
1314c6926a2SDave Jiang 		struct nd_intel_unlock_unit cmd;
1324c6926a2SDave Jiang 	} nd_cmd = {
1334c6926a2SDave Jiang 		.pkg = {
1344c6926a2SDave Jiang 			.nd_command = NVDIMM_INTEL_UNLOCK_UNIT,
1354c6926a2SDave Jiang 			.nd_family = NVDIMM_FAMILY_INTEL,
1364c6926a2SDave Jiang 			.nd_size_in = ND_INTEL_PASSPHRASE_SIZE,
1374c6926a2SDave Jiang 			.nd_size_out = ND_INTEL_STATUS_SIZE,
1384c6926a2SDave Jiang 			.nd_fw_size = ND_INTEL_STATUS_SIZE,
1394c6926a2SDave Jiang 		},
1404c6926a2SDave Jiang 	};
1414c6926a2SDave Jiang 	int rc;
1424c6926a2SDave Jiang 
1434c6926a2SDave Jiang 	if (!test_bit(NVDIMM_INTEL_UNLOCK_UNIT, &nfit_mem->dsm_mask))
1444c6926a2SDave Jiang 		return -ENOTTY;
1454c6926a2SDave Jiang 
1464c6926a2SDave Jiang 	memcpy(nd_cmd.cmd.passphrase, key_data->data,
1474c6926a2SDave Jiang 			sizeof(nd_cmd.cmd.passphrase));
1484c6926a2SDave Jiang 	rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL);
1494c6926a2SDave Jiang 	if (rc < 0)
1504c6926a2SDave Jiang 		return rc;
1514c6926a2SDave Jiang 	switch (nd_cmd.cmd.status) {
1524c6926a2SDave Jiang 	case 0:
1534c6926a2SDave Jiang 		break;
1544c6926a2SDave Jiang 	case ND_INTEL_STATUS_INVALID_PASS:
1554c6926a2SDave Jiang 		return -EINVAL;
1564c6926a2SDave Jiang 	default:
1574c6926a2SDave Jiang 		return -EIO;
1584c6926a2SDave Jiang 	}
1594c6926a2SDave Jiang 
1604c6926a2SDave Jiang 	/* DIMM unlocked, invalidate all CPU caches before we read it */
1614c6926a2SDave Jiang 	nvdimm_invalidate_cache();
1624c6926a2SDave Jiang 
1634c6926a2SDave Jiang 	return 0;
1644c6926a2SDave Jiang }
1654c6926a2SDave Jiang 
16603b65b22SDave Jiang static int intel_security_disable(struct nvdimm *nvdimm,
16703b65b22SDave Jiang 		const struct nvdimm_key_data *key_data)
16803b65b22SDave Jiang {
16903b65b22SDave Jiang 	int rc;
17003b65b22SDave Jiang 	struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
17103b65b22SDave Jiang 	struct {
17203b65b22SDave Jiang 		struct nd_cmd_pkg pkg;
17303b65b22SDave Jiang 		struct nd_intel_disable_passphrase cmd;
17403b65b22SDave Jiang 	} nd_cmd = {
17503b65b22SDave Jiang 		.pkg = {
17603b65b22SDave Jiang 			.nd_command = NVDIMM_INTEL_DISABLE_PASSPHRASE,
17703b65b22SDave Jiang 			.nd_family = NVDIMM_FAMILY_INTEL,
17803b65b22SDave Jiang 			.nd_size_in = ND_INTEL_PASSPHRASE_SIZE,
17903b65b22SDave Jiang 			.nd_size_out = ND_INTEL_STATUS_SIZE,
18003b65b22SDave Jiang 			.nd_fw_size = ND_INTEL_STATUS_SIZE,
18103b65b22SDave Jiang 		},
18203b65b22SDave Jiang 	};
18303b65b22SDave Jiang 
18403b65b22SDave Jiang 	if (!test_bit(NVDIMM_INTEL_DISABLE_PASSPHRASE, &nfit_mem->dsm_mask))
18503b65b22SDave Jiang 		return -ENOTTY;
18603b65b22SDave Jiang 
18703b65b22SDave Jiang 	memcpy(nd_cmd.cmd.passphrase, key_data->data,
18803b65b22SDave Jiang 			sizeof(nd_cmd.cmd.passphrase));
18903b65b22SDave Jiang 	rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL);
19003b65b22SDave Jiang 	if (rc < 0)
19103b65b22SDave Jiang 		return rc;
19203b65b22SDave Jiang 
19303b65b22SDave Jiang 	switch (nd_cmd.cmd.status) {
19403b65b22SDave Jiang 	case 0:
19503b65b22SDave Jiang 		break;
19603b65b22SDave Jiang 	case ND_INTEL_STATUS_INVALID_PASS:
19703b65b22SDave Jiang 		return -EINVAL;
19803b65b22SDave Jiang 	case ND_INTEL_STATUS_INVALID_STATE:
19903b65b22SDave Jiang 	default:
20003b65b22SDave Jiang 		return -ENXIO;
20103b65b22SDave Jiang 	}
20203b65b22SDave Jiang 
20303b65b22SDave Jiang 	return 0;
20403b65b22SDave Jiang }
20503b65b22SDave Jiang 
206*64e77c8cSDave Jiang static int intel_security_erase(struct nvdimm *nvdimm,
207*64e77c8cSDave Jiang 		const struct nvdimm_key_data *key)
208*64e77c8cSDave Jiang {
209*64e77c8cSDave Jiang 	int rc;
210*64e77c8cSDave Jiang 	struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
211*64e77c8cSDave Jiang 	struct {
212*64e77c8cSDave Jiang 		struct nd_cmd_pkg pkg;
213*64e77c8cSDave Jiang 		struct nd_intel_secure_erase cmd;
214*64e77c8cSDave Jiang 	} nd_cmd = {
215*64e77c8cSDave Jiang 		.pkg = {
216*64e77c8cSDave Jiang 			.nd_family = NVDIMM_FAMILY_INTEL,
217*64e77c8cSDave Jiang 			.nd_size_in = ND_INTEL_PASSPHRASE_SIZE,
218*64e77c8cSDave Jiang 			.nd_size_out = ND_INTEL_STATUS_SIZE,
219*64e77c8cSDave Jiang 			.nd_fw_size = ND_INTEL_STATUS_SIZE,
220*64e77c8cSDave Jiang 			.nd_command = NVDIMM_INTEL_SECURE_ERASE,
221*64e77c8cSDave Jiang 		},
222*64e77c8cSDave Jiang 	};
223*64e77c8cSDave Jiang 
224*64e77c8cSDave Jiang 	if (!test_bit(NVDIMM_INTEL_SECURE_ERASE, &nfit_mem->dsm_mask))
225*64e77c8cSDave Jiang 		return -ENOTTY;
226*64e77c8cSDave Jiang 
227*64e77c8cSDave Jiang 	/* flush all cache before we erase DIMM */
228*64e77c8cSDave Jiang 	nvdimm_invalidate_cache();
229*64e77c8cSDave Jiang 	memcpy(nd_cmd.cmd.passphrase, key->data,
230*64e77c8cSDave Jiang 			sizeof(nd_cmd.cmd.passphrase));
231*64e77c8cSDave Jiang 	rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL);
232*64e77c8cSDave Jiang 	if (rc < 0)
233*64e77c8cSDave Jiang 		return rc;
234*64e77c8cSDave Jiang 
235*64e77c8cSDave Jiang 	switch (nd_cmd.cmd.status) {
236*64e77c8cSDave Jiang 	case 0:
237*64e77c8cSDave Jiang 		break;
238*64e77c8cSDave Jiang 	case ND_INTEL_STATUS_NOT_SUPPORTED:
239*64e77c8cSDave Jiang 		return -EOPNOTSUPP;
240*64e77c8cSDave Jiang 	case ND_INTEL_STATUS_INVALID_PASS:
241*64e77c8cSDave Jiang 		return -EINVAL;
242*64e77c8cSDave Jiang 	case ND_INTEL_STATUS_INVALID_STATE:
243*64e77c8cSDave Jiang 	default:
244*64e77c8cSDave Jiang 		return -ENXIO;
245*64e77c8cSDave Jiang 	}
246*64e77c8cSDave Jiang 
247*64e77c8cSDave Jiang 	/* DIMM erased, invalidate all CPU caches before we read it */
248*64e77c8cSDave Jiang 	nvdimm_invalidate_cache();
249*64e77c8cSDave Jiang 	return 0;
250*64e77c8cSDave Jiang }
251*64e77c8cSDave Jiang 
2524c6926a2SDave Jiang /*
2534c6926a2SDave Jiang  * TODO: define a cross arch wbinvd equivalent when/if
2544c6926a2SDave Jiang  * NVDIMM_FAMILY_INTEL command support arrives on another arch.
2554c6926a2SDave Jiang  */
2564c6926a2SDave Jiang #ifdef CONFIG_X86
2574c6926a2SDave Jiang static void nvdimm_invalidate_cache(void)
2584c6926a2SDave Jiang {
2594c6926a2SDave Jiang 	wbinvd_on_all_cpus();
2604c6926a2SDave Jiang }
2614c6926a2SDave Jiang #else
2624c6926a2SDave Jiang static void nvdimm_invalidate_cache(void)
2634c6926a2SDave Jiang {
2644c6926a2SDave Jiang 	WARN_ON_ONCE("cache invalidation required after unlock\n");
2654c6926a2SDave Jiang }
2664c6926a2SDave Jiang #endif
2674c6926a2SDave Jiang 
268f2989396SDave Jiang static const struct nvdimm_security_ops __intel_security_ops = {
269f2989396SDave Jiang 	.state = intel_security_state,
27037833fb7SDave Jiang 	.freeze = intel_security_freeze,
2714c6926a2SDave Jiang 	.change_key = intel_security_change_key,
27203b65b22SDave Jiang 	.disable = intel_security_disable,
2734c6926a2SDave Jiang #ifdef CONFIG_X86
2744c6926a2SDave Jiang 	.unlock = intel_security_unlock,
275*64e77c8cSDave Jiang 	.erase = intel_security_erase,
2764c6926a2SDave Jiang #endif
277f2989396SDave Jiang };
2784c6926a2SDave Jiang 
279f2989396SDave Jiang const struct nvdimm_security_ops *intel_security_ops = &__intel_security_ops;
280