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