162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* Copyright(c) 2022 Intel Corporation. All rights reserved. */ 362306a36Sopenharmony_ci#include <linux/libnvdimm.h> 462306a36Sopenharmony_ci#include <asm/unaligned.h> 562306a36Sopenharmony_ci#include <linux/module.h> 662306a36Sopenharmony_ci#include <linux/async.h> 762306a36Sopenharmony_ci#include <linux/slab.h> 862306a36Sopenharmony_ci#include <linux/memregion.h> 962306a36Sopenharmony_ci#include "cxlmem.h" 1062306a36Sopenharmony_ci#include "cxl.h" 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_cistatic unsigned long cxl_pmem_get_security_flags(struct nvdimm *nvdimm, 1362306a36Sopenharmony_ci enum nvdimm_passphrase_type ptype) 1462306a36Sopenharmony_ci{ 1562306a36Sopenharmony_ci struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm); 1662306a36Sopenharmony_ci struct cxl_memdev *cxlmd = cxl_nvd->cxlmd; 1762306a36Sopenharmony_ci struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds); 1862306a36Sopenharmony_ci unsigned long security_flags = 0; 1962306a36Sopenharmony_ci struct cxl_get_security_output { 2062306a36Sopenharmony_ci __le32 flags; 2162306a36Sopenharmony_ci } out; 2262306a36Sopenharmony_ci struct cxl_mbox_cmd mbox_cmd; 2362306a36Sopenharmony_ci u32 sec_out; 2462306a36Sopenharmony_ci int rc; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci mbox_cmd = (struct cxl_mbox_cmd) { 2762306a36Sopenharmony_ci .opcode = CXL_MBOX_OP_GET_SECURITY_STATE, 2862306a36Sopenharmony_ci .size_out = sizeof(out), 2962306a36Sopenharmony_ci .payload_out = &out, 3062306a36Sopenharmony_ci }; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci rc = cxl_internal_send_cmd(mds, &mbox_cmd); 3362306a36Sopenharmony_ci if (rc < 0) 3462306a36Sopenharmony_ci return 0; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci sec_out = le32_to_cpu(out.flags); 3762306a36Sopenharmony_ci /* cache security state */ 3862306a36Sopenharmony_ci mds->security.state = sec_out; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci if (ptype == NVDIMM_MASTER) { 4162306a36Sopenharmony_ci if (sec_out & CXL_PMEM_SEC_STATE_MASTER_PASS_SET) 4262306a36Sopenharmony_ci set_bit(NVDIMM_SECURITY_UNLOCKED, &security_flags); 4362306a36Sopenharmony_ci else 4462306a36Sopenharmony_ci set_bit(NVDIMM_SECURITY_DISABLED, &security_flags); 4562306a36Sopenharmony_ci if (sec_out & CXL_PMEM_SEC_STATE_MASTER_PLIMIT) 4662306a36Sopenharmony_ci set_bit(NVDIMM_SECURITY_FROZEN, &security_flags); 4762306a36Sopenharmony_ci return security_flags; 4862306a36Sopenharmony_ci } 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci if (sec_out & CXL_PMEM_SEC_STATE_USER_PASS_SET) { 5162306a36Sopenharmony_ci if (sec_out & CXL_PMEM_SEC_STATE_FROZEN || 5262306a36Sopenharmony_ci sec_out & CXL_PMEM_SEC_STATE_USER_PLIMIT) 5362306a36Sopenharmony_ci set_bit(NVDIMM_SECURITY_FROZEN, &security_flags); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci if (sec_out & CXL_PMEM_SEC_STATE_LOCKED) 5662306a36Sopenharmony_ci set_bit(NVDIMM_SECURITY_LOCKED, &security_flags); 5762306a36Sopenharmony_ci else 5862306a36Sopenharmony_ci set_bit(NVDIMM_SECURITY_UNLOCKED, &security_flags); 5962306a36Sopenharmony_ci } else { 6062306a36Sopenharmony_ci set_bit(NVDIMM_SECURITY_DISABLED, &security_flags); 6162306a36Sopenharmony_ci } 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci return security_flags; 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistatic int cxl_pmem_security_change_key(struct nvdimm *nvdimm, 6762306a36Sopenharmony_ci const struct nvdimm_key_data *old_data, 6862306a36Sopenharmony_ci const struct nvdimm_key_data *new_data, 6962306a36Sopenharmony_ci enum nvdimm_passphrase_type ptype) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm); 7262306a36Sopenharmony_ci struct cxl_memdev *cxlmd = cxl_nvd->cxlmd; 7362306a36Sopenharmony_ci struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds); 7462306a36Sopenharmony_ci struct cxl_mbox_cmd mbox_cmd; 7562306a36Sopenharmony_ci struct cxl_set_pass set_pass; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci set_pass = (struct cxl_set_pass) { 7862306a36Sopenharmony_ci .type = ptype == NVDIMM_MASTER ? CXL_PMEM_SEC_PASS_MASTER : 7962306a36Sopenharmony_ci CXL_PMEM_SEC_PASS_USER, 8062306a36Sopenharmony_ci }; 8162306a36Sopenharmony_ci memcpy(set_pass.old_pass, old_data->data, NVDIMM_PASSPHRASE_LEN); 8262306a36Sopenharmony_ci memcpy(set_pass.new_pass, new_data->data, NVDIMM_PASSPHRASE_LEN); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci mbox_cmd = (struct cxl_mbox_cmd) { 8562306a36Sopenharmony_ci .opcode = CXL_MBOX_OP_SET_PASSPHRASE, 8662306a36Sopenharmony_ci .size_in = sizeof(set_pass), 8762306a36Sopenharmony_ci .payload_in = &set_pass, 8862306a36Sopenharmony_ci }; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci return cxl_internal_send_cmd(mds, &mbox_cmd); 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cistatic int __cxl_pmem_security_disable(struct nvdimm *nvdimm, 9462306a36Sopenharmony_ci const struct nvdimm_key_data *key_data, 9562306a36Sopenharmony_ci enum nvdimm_passphrase_type ptype) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm); 9862306a36Sopenharmony_ci struct cxl_memdev *cxlmd = cxl_nvd->cxlmd; 9962306a36Sopenharmony_ci struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds); 10062306a36Sopenharmony_ci struct cxl_disable_pass dis_pass; 10162306a36Sopenharmony_ci struct cxl_mbox_cmd mbox_cmd; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci dis_pass = (struct cxl_disable_pass) { 10462306a36Sopenharmony_ci .type = ptype == NVDIMM_MASTER ? CXL_PMEM_SEC_PASS_MASTER : 10562306a36Sopenharmony_ci CXL_PMEM_SEC_PASS_USER, 10662306a36Sopenharmony_ci }; 10762306a36Sopenharmony_ci memcpy(dis_pass.pass, key_data->data, NVDIMM_PASSPHRASE_LEN); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci mbox_cmd = (struct cxl_mbox_cmd) { 11062306a36Sopenharmony_ci .opcode = CXL_MBOX_OP_DISABLE_PASSPHRASE, 11162306a36Sopenharmony_ci .size_in = sizeof(dis_pass), 11262306a36Sopenharmony_ci .payload_in = &dis_pass, 11362306a36Sopenharmony_ci }; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci return cxl_internal_send_cmd(mds, &mbox_cmd); 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cistatic int cxl_pmem_security_disable(struct nvdimm *nvdimm, 11962306a36Sopenharmony_ci const struct nvdimm_key_data *key_data) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci return __cxl_pmem_security_disable(nvdimm, key_data, NVDIMM_USER); 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic int cxl_pmem_security_disable_master(struct nvdimm *nvdimm, 12562306a36Sopenharmony_ci const struct nvdimm_key_data *key_data) 12662306a36Sopenharmony_ci{ 12762306a36Sopenharmony_ci return __cxl_pmem_security_disable(nvdimm, key_data, NVDIMM_MASTER); 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic int cxl_pmem_security_freeze(struct nvdimm *nvdimm) 13162306a36Sopenharmony_ci{ 13262306a36Sopenharmony_ci struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm); 13362306a36Sopenharmony_ci struct cxl_memdev *cxlmd = cxl_nvd->cxlmd; 13462306a36Sopenharmony_ci struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds); 13562306a36Sopenharmony_ci struct cxl_mbox_cmd mbox_cmd = { 13662306a36Sopenharmony_ci .opcode = CXL_MBOX_OP_FREEZE_SECURITY, 13762306a36Sopenharmony_ci }; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci return cxl_internal_send_cmd(mds, &mbox_cmd); 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cistatic int cxl_pmem_security_unlock(struct nvdimm *nvdimm, 14362306a36Sopenharmony_ci const struct nvdimm_key_data *key_data) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm); 14662306a36Sopenharmony_ci struct cxl_memdev *cxlmd = cxl_nvd->cxlmd; 14762306a36Sopenharmony_ci struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds); 14862306a36Sopenharmony_ci u8 pass[NVDIMM_PASSPHRASE_LEN]; 14962306a36Sopenharmony_ci struct cxl_mbox_cmd mbox_cmd; 15062306a36Sopenharmony_ci int rc; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci memcpy(pass, key_data->data, NVDIMM_PASSPHRASE_LEN); 15362306a36Sopenharmony_ci mbox_cmd = (struct cxl_mbox_cmd) { 15462306a36Sopenharmony_ci .opcode = CXL_MBOX_OP_UNLOCK, 15562306a36Sopenharmony_ci .size_in = NVDIMM_PASSPHRASE_LEN, 15662306a36Sopenharmony_ci .payload_in = pass, 15762306a36Sopenharmony_ci }; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci rc = cxl_internal_send_cmd(mds, &mbox_cmd); 16062306a36Sopenharmony_ci if (rc < 0) 16162306a36Sopenharmony_ci return rc; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci return 0; 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistatic int cxl_pmem_security_passphrase_erase(struct nvdimm *nvdimm, 16762306a36Sopenharmony_ci const struct nvdimm_key_data *key, 16862306a36Sopenharmony_ci enum nvdimm_passphrase_type ptype) 16962306a36Sopenharmony_ci{ 17062306a36Sopenharmony_ci struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm); 17162306a36Sopenharmony_ci struct cxl_memdev *cxlmd = cxl_nvd->cxlmd; 17262306a36Sopenharmony_ci struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds); 17362306a36Sopenharmony_ci struct cxl_mbox_cmd mbox_cmd; 17462306a36Sopenharmony_ci struct cxl_pass_erase erase; 17562306a36Sopenharmony_ci int rc; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci erase = (struct cxl_pass_erase) { 17862306a36Sopenharmony_ci .type = ptype == NVDIMM_MASTER ? CXL_PMEM_SEC_PASS_MASTER : 17962306a36Sopenharmony_ci CXL_PMEM_SEC_PASS_USER, 18062306a36Sopenharmony_ci }; 18162306a36Sopenharmony_ci memcpy(erase.pass, key->data, NVDIMM_PASSPHRASE_LEN); 18262306a36Sopenharmony_ci mbox_cmd = (struct cxl_mbox_cmd) { 18362306a36Sopenharmony_ci .opcode = CXL_MBOX_OP_PASSPHRASE_SECURE_ERASE, 18462306a36Sopenharmony_ci .size_in = sizeof(erase), 18562306a36Sopenharmony_ci .payload_in = &erase, 18662306a36Sopenharmony_ci }; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci rc = cxl_internal_send_cmd(mds, &mbox_cmd); 18962306a36Sopenharmony_ci if (rc < 0) 19062306a36Sopenharmony_ci return rc; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci return 0; 19362306a36Sopenharmony_ci} 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_cistatic const struct nvdimm_security_ops __cxl_security_ops = { 19662306a36Sopenharmony_ci .get_flags = cxl_pmem_get_security_flags, 19762306a36Sopenharmony_ci .change_key = cxl_pmem_security_change_key, 19862306a36Sopenharmony_ci .disable = cxl_pmem_security_disable, 19962306a36Sopenharmony_ci .freeze = cxl_pmem_security_freeze, 20062306a36Sopenharmony_ci .unlock = cxl_pmem_security_unlock, 20162306a36Sopenharmony_ci .erase = cxl_pmem_security_passphrase_erase, 20262306a36Sopenharmony_ci .disable_master = cxl_pmem_security_disable_master, 20362306a36Sopenharmony_ci}; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ciconst struct nvdimm_security_ops *cxl_security_ops = &__cxl_security_ops; 206