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