1 // SPDX-License-Identifier: GPL-2.0-only 2 /* Copyright(c) 2022 Intel Corporation. All rights reserved. */ 3 #include <linux/libnvdimm.h> 4 #include <linux/unaligned.h> 5 #include <linux/module.h> 6 #include <linux/async.h> 7 #include <linux/slab.h> 8 #include <linux/memregion.h> 9 #include "cxlmem.h" 10 #include "cxl.h" 11 12 static unsigned long cxl_pmem_get_security_flags(struct nvdimm *nvdimm, 13 enum nvdimm_passphrase_type ptype) 14 { 15 struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm); 16 struct cxl_memdev *cxlmd = cxl_nvd->cxlmd; 17 struct cxl_mailbox *cxl_mbox = &cxlmd->cxlds->cxl_mbox; 18 struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds); 19 unsigned long security_flags = 0; 20 struct cxl_get_security_output { 21 __le32 flags; 22 } out; 23 struct cxl_mbox_cmd mbox_cmd; 24 u32 sec_out; 25 int rc; 26 27 mbox_cmd = (struct cxl_mbox_cmd) { 28 .opcode = CXL_MBOX_OP_GET_SECURITY_STATE, 29 .size_out = sizeof(out), 30 .payload_out = &out, 31 }; 32 33 rc = cxl_internal_send_cmd(cxl_mbox, &mbox_cmd); 34 if (rc < 0) 35 return 0; 36 37 sec_out = le32_to_cpu(out.flags); 38 /* cache security state */ 39 mds->security.state = sec_out; 40 41 if (ptype == NVDIMM_MASTER) { 42 if (sec_out & CXL_PMEM_SEC_STATE_MASTER_PASS_SET) 43 set_bit(NVDIMM_SECURITY_UNLOCKED, &security_flags); 44 else 45 set_bit(NVDIMM_SECURITY_DISABLED, &security_flags); 46 if (sec_out & CXL_PMEM_SEC_STATE_MASTER_PLIMIT) 47 set_bit(NVDIMM_SECURITY_FROZEN, &security_flags); 48 return security_flags; 49 } 50 51 if (sec_out & CXL_PMEM_SEC_STATE_USER_PASS_SET) { 52 if (sec_out & CXL_PMEM_SEC_STATE_FROZEN || 53 sec_out & CXL_PMEM_SEC_STATE_USER_PLIMIT) 54 set_bit(NVDIMM_SECURITY_FROZEN, &security_flags); 55 56 if (sec_out & CXL_PMEM_SEC_STATE_LOCKED) 57 set_bit(NVDIMM_SECURITY_LOCKED, &security_flags); 58 else 59 set_bit(NVDIMM_SECURITY_UNLOCKED, &security_flags); 60 } else { 61 set_bit(NVDIMM_SECURITY_DISABLED, &security_flags); 62 } 63 64 return security_flags; 65 } 66 67 static int cxl_pmem_security_change_key(struct nvdimm *nvdimm, 68 const struct nvdimm_key_data *old_data, 69 const struct nvdimm_key_data *new_data, 70 enum nvdimm_passphrase_type ptype) 71 { 72 struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm); 73 struct cxl_memdev *cxlmd = cxl_nvd->cxlmd; 74 struct cxl_mailbox *cxl_mbox = &cxlmd->cxlds->cxl_mbox; 75 struct cxl_mbox_cmd mbox_cmd; 76 struct cxl_set_pass set_pass; 77 78 set_pass = (struct cxl_set_pass) { 79 .type = ptype == NVDIMM_MASTER ? CXL_PMEM_SEC_PASS_MASTER : 80 CXL_PMEM_SEC_PASS_USER, 81 }; 82 memcpy(set_pass.old_pass, old_data->data, NVDIMM_PASSPHRASE_LEN); 83 memcpy(set_pass.new_pass, new_data->data, NVDIMM_PASSPHRASE_LEN); 84 85 mbox_cmd = (struct cxl_mbox_cmd) { 86 .opcode = CXL_MBOX_OP_SET_PASSPHRASE, 87 .size_in = sizeof(set_pass), 88 .payload_in = &set_pass, 89 }; 90 91 return cxl_internal_send_cmd(cxl_mbox, &mbox_cmd); 92 } 93 94 static int __cxl_pmem_security_disable(struct nvdimm *nvdimm, 95 const struct nvdimm_key_data *key_data, 96 enum nvdimm_passphrase_type ptype) 97 { 98 struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm); 99 struct cxl_memdev *cxlmd = cxl_nvd->cxlmd; 100 struct cxl_mailbox *cxl_mbox = &cxlmd->cxlds->cxl_mbox; 101 struct cxl_disable_pass dis_pass; 102 struct cxl_mbox_cmd mbox_cmd; 103 104 dis_pass = (struct cxl_disable_pass) { 105 .type = ptype == NVDIMM_MASTER ? CXL_PMEM_SEC_PASS_MASTER : 106 CXL_PMEM_SEC_PASS_USER, 107 }; 108 memcpy(dis_pass.pass, key_data->data, NVDIMM_PASSPHRASE_LEN); 109 110 mbox_cmd = (struct cxl_mbox_cmd) { 111 .opcode = CXL_MBOX_OP_DISABLE_PASSPHRASE, 112 .size_in = sizeof(dis_pass), 113 .payload_in = &dis_pass, 114 }; 115 116 return cxl_internal_send_cmd(cxl_mbox, &mbox_cmd); 117 } 118 119 static int cxl_pmem_security_disable(struct nvdimm *nvdimm, 120 const struct nvdimm_key_data *key_data) 121 { 122 return __cxl_pmem_security_disable(nvdimm, key_data, NVDIMM_USER); 123 } 124 125 static int cxl_pmem_security_disable_master(struct nvdimm *nvdimm, 126 const struct nvdimm_key_data *key_data) 127 { 128 return __cxl_pmem_security_disable(nvdimm, key_data, NVDIMM_MASTER); 129 } 130 131 static int cxl_pmem_security_freeze(struct nvdimm *nvdimm) 132 { 133 struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm); 134 struct cxl_memdev *cxlmd = cxl_nvd->cxlmd; 135 struct cxl_mailbox *cxl_mbox = &cxlmd->cxlds->cxl_mbox; 136 struct cxl_mbox_cmd mbox_cmd = { 137 .opcode = CXL_MBOX_OP_FREEZE_SECURITY, 138 }; 139 140 return cxl_internal_send_cmd(cxl_mbox, &mbox_cmd); 141 } 142 143 static int cxl_pmem_security_unlock(struct nvdimm *nvdimm, 144 const struct nvdimm_key_data *key_data) 145 { 146 struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm); 147 struct cxl_memdev *cxlmd = cxl_nvd->cxlmd; 148 struct cxl_mailbox *cxl_mbox = &cxlmd->cxlds->cxl_mbox; 149 u8 pass[NVDIMM_PASSPHRASE_LEN]; 150 struct cxl_mbox_cmd mbox_cmd; 151 int rc; 152 153 memcpy(pass, key_data->data, NVDIMM_PASSPHRASE_LEN); 154 mbox_cmd = (struct cxl_mbox_cmd) { 155 .opcode = CXL_MBOX_OP_UNLOCK, 156 .size_in = NVDIMM_PASSPHRASE_LEN, 157 .payload_in = pass, 158 }; 159 160 rc = cxl_internal_send_cmd(cxl_mbox, &mbox_cmd); 161 if (rc < 0) 162 return rc; 163 164 return 0; 165 } 166 167 static int cxl_pmem_security_passphrase_erase(struct nvdimm *nvdimm, 168 const struct nvdimm_key_data *key, 169 enum nvdimm_passphrase_type ptype) 170 { 171 struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm); 172 struct cxl_memdev *cxlmd = cxl_nvd->cxlmd; 173 struct cxl_mailbox *cxl_mbox = &cxlmd->cxlds->cxl_mbox; 174 struct cxl_mbox_cmd mbox_cmd; 175 struct cxl_pass_erase erase; 176 int rc; 177 178 erase = (struct cxl_pass_erase) { 179 .type = ptype == NVDIMM_MASTER ? CXL_PMEM_SEC_PASS_MASTER : 180 CXL_PMEM_SEC_PASS_USER, 181 }; 182 memcpy(erase.pass, key->data, NVDIMM_PASSPHRASE_LEN); 183 mbox_cmd = (struct cxl_mbox_cmd) { 184 .opcode = CXL_MBOX_OP_PASSPHRASE_SECURE_ERASE, 185 .size_in = sizeof(erase), 186 .payload_in = &erase, 187 }; 188 189 rc = cxl_internal_send_cmd(cxl_mbox, &mbox_cmd); 190 if (rc < 0) 191 return rc; 192 193 return 0; 194 } 195 196 static const struct nvdimm_security_ops __cxl_security_ops = { 197 .get_flags = cxl_pmem_get_security_flags, 198 .change_key = cxl_pmem_security_change_key, 199 .disable = cxl_pmem_security_disable, 200 .freeze = cxl_pmem_security_freeze, 201 .unlock = cxl_pmem_security_unlock, 202 .erase = cxl_pmem_security_passphrase_erase, 203 .disable_master = cxl_pmem_security_disable_master, 204 }; 205 206 const struct nvdimm_security_ops *cxl_security_ops = &__cxl_security_ops; 207