]>
Commit | Line | Data |
---|---|---|
d2912cb1 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
2a6170df BS |
2 | /* |
3 | * AMD Platform Security Processor (PSP) interface | |
4 | * | |
fa5cd1c7 | 5 | * Copyright (C) 2016,2018 Advanced Micro Devices, Inc. |
2a6170df BS |
6 | * |
7 | * Author: Brijesh Singh <brijesh.singh@amd.com> | |
2a6170df BS |
8 | */ |
9 | ||
10 | #include <linux/module.h> | |
11 | #include <linux/kernel.h> | |
12 | #include <linux/kthread.h> | |
13 | #include <linux/sched.h> | |
14 | #include <linux/interrupt.h> | |
15 | #include <linux/spinlock.h> | |
16 | #include <linux/spinlock_types.h> | |
17 | #include <linux/types.h> | |
18 | #include <linux/mutex.h> | |
19 | #include <linux/delay.h> | |
20 | #include <linux/hw_random.h> | |
21 | #include <linux/ccp.h> | |
edd303ff | 22 | #include <linux/firmware.h> |
2a6170df BS |
23 | |
24 | #include "sp-dev.h" | |
25 | #include "psp-dev.h" | |
26 | ||
edd303ff JN |
27 | #define SEV_VERSION_GREATER_OR_EQUAL(_maj, _min) \ |
28 | ((psp_master->api_major) >= _maj && \ | |
29 | (psp_master->api_minor) >= _min) | |
30 | ||
e9372060 JN |
31 | #define DEVICE_NAME "sev" |
32 | #define SEV_FW_FILE "amd/sev.fw" | |
33 | #define SEV_FW_NAME_SIZE 64 | |
200664d5 BS |
34 | |
35 | static DEFINE_MUTEX(sev_cmd_mutex); | |
36 | static struct sev_misc_dev *misc_dev; | |
37 | static struct psp_device *psp_master; | |
38 | ||
e82867fd BS |
39 | static int psp_cmd_timeout = 100; |
40 | module_param(psp_cmd_timeout, int, 0644); | |
41 | MODULE_PARM_DESC(psp_cmd_timeout, " default timeout value, in seconds, for PSP commands"); | |
42 | ||
43 | static int psp_probe_timeout = 5; | |
44 | module_param(psp_probe_timeout, int, 0644); | |
45 | MODULE_PARM_DESC(psp_probe_timeout, " default timeout value, in seconds, during PSP device probe"); | |
46 | ||
47 | static bool psp_dead; | |
48 | static int psp_timeout; | |
49 | ||
2a6170df BS |
50 | static struct psp_device *psp_alloc_struct(struct sp_device *sp) |
51 | { | |
52 | struct device *dev = sp->dev; | |
53 | struct psp_device *psp; | |
54 | ||
55 | psp = devm_kzalloc(dev, sizeof(*psp), GFP_KERNEL); | |
56 | if (!psp) | |
57 | return NULL; | |
58 | ||
59 | psp->dev = dev; | |
60 | psp->sp = sp; | |
61 | ||
62 | snprintf(psp->name, sizeof(psp->name), "psp-%u", sp->ord); | |
63 | ||
64 | return psp; | |
65 | } | |
66 | ||
67 | static irqreturn_t psp_irq_handler(int irq, void *data) | |
68 | { | |
200664d5 BS |
69 | struct psp_device *psp = data; |
70 | unsigned int status; | |
71 | int reg; | |
72 | ||
73 | /* Read the interrupt status: */ | |
ad01a984 | 74 | status = ioread32(psp->io_regs + psp->vdata->intsts_reg); |
200664d5 BS |
75 | |
76 | /* Check if it is command completion: */ | |
03af9124 | 77 | if (!(status & PSP_CMD_COMPLETE)) |
200664d5 BS |
78 | goto done; |
79 | ||
80 | /* Check if it is SEV command completion: */ | |
ad01a984 | 81 | reg = ioread32(psp->io_regs + psp->vdata->cmdresp_reg); |
200664d5 BS |
82 | if (reg & PSP_CMDRESP_RESP) { |
83 | psp->sev_int_rcvd = 1; | |
84 | wake_up(&psp->sev_int_queue); | |
85 | } | |
86 | ||
87 | done: | |
88 | /* Clear the interrupt status by writing the same value we read. */ | |
ad01a984 | 89 | iowrite32(status, psp->io_regs + psp->vdata->intsts_reg); |
200664d5 | 90 | |
2a6170df BS |
91 | return IRQ_HANDLED; |
92 | } | |
93 | ||
e82867fd BS |
94 | static int sev_wait_cmd_ioc(struct psp_device *psp, |
95 | unsigned int *reg, unsigned int timeout) | |
200664d5 | 96 | { |
e82867fd BS |
97 | int ret; |
98 | ||
99 | ret = wait_event_timeout(psp->sev_int_queue, | |
100 | psp->sev_int_rcvd, timeout * HZ); | |
101 | if (!ret) | |
102 | return -ETIMEDOUT; | |
103 | ||
ad01a984 | 104 | *reg = ioread32(psp->io_regs + psp->vdata->cmdresp_reg); |
e82867fd BS |
105 | |
106 | return 0; | |
200664d5 BS |
107 | } |
108 | ||
109 | static int sev_cmd_buffer_len(int cmd) | |
110 | { | |
111 | switch (cmd) { | |
112 | case SEV_CMD_INIT: return sizeof(struct sev_data_init); | |
113 | case SEV_CMD_PLATFORM_STATUS: return sizeof(struct sev_user_data_status); | |
114 | case SEV_CMD_PEK_CSR: return sizeof(struct sev_data_pek_csr); | |
115 | case SEV_CMD_PEK_CERT_IMPORT: return sizeof(struct sev_data_pek_cert_import); | |
116 | case SEV_CMD_PDH_CERT_EXPORT: return sizeof(struct sev_data_pdh_cert_export); | |
117 | case SEV_CMD_LAUNCH_START: return sizeof(struct sev_data_launch_start); | |
118 | case SEV_CMD_LAUNCH_UPDATE_DATA: return sizeof(struct sev_data_launch_update_data); | |
119 | case SEV_CMD_LAUNCH_UPDATE_VMSA: return sizeof(struct sev_data_launch_update_vmsa); | |
120 | case SEV_CMD_LAUNCH_FINISH: return sizeof(struct sev_data_launch_finish); | |
121 | case SEV_CMD_LAUNCH_MEASURE: return sizeof(struct sev_data_launch_measure); | |
122 | case SEV_CMD_ACTIVATE: return sizeof(struct sev_data_activate); | |
123 | case SEV_CMD_DEACTIVATE: return sizeof(struct sev_data_deactivate); | |
124 | case SEV_CMD_DECOMMISSION: return sizeof(struct sev_data_decommission); | |
125 | case SEV_CMD_GUEST_STATUS: return sizeof(struct sev_data_guest_status); | |
126 | case SEV_CMD_DBG_DECRYPT: return sizeof(struct sev_data_dbg); | |
127 | case SEV_CMD_DBG_ENCRYPT: return sizeof(struct sev_data_dbg); | |
128 | case SEV_CMD_SEND_START: return sizeof(struct sev_data_send_start); | |
129 | case SEV_CMD_SEND_UPDATE_DATA: return sizeof(struct sev_data_send_update_data); | |
130 | case SEV_CMD_SEND_UPDATE_VMSA: return sizeof(struct sev_data_send_update_vmsa); | |
131 | case SEV_CMD_SEND_FINISH: return sizeof(struct sev_data_send_finish); | |
132 | case SEV_CMD_RECEIVE_START: return sizeof(struct sev_data_receive_start); | |
133 | case SEV_CMD_RECEIVE_FINISH: return sizeof(struct sev_data_receive_finish); | |
134 | case SEV_CMD_RECEIVE_UPDATE_DATA: return sizeof(struct sev_data_receive_update_data); | |
135 | case SEV_CMD_RECEIVE_UPDATE_VMSA: return sizeof(struct sev_data_receive_update_vmsa); | |
136 | case SEV_CMD_LAUNCH_UPDATE_SECRET: return sizeof(struct sev_data_launch_secret); | |
edd303ff | 137 | case SEV_CMD_DOWNLOAD_FIRMWARE: return sizeof(struct sev_data_download_firmware); |
0b3a830b | 138 | case SEV_CMD_GET_ID: return sizeof(struct sev_data_get_id); |
200664d5 BS |
139 | default: return 0; |
140 | } | |
141 | ||
142 | return 0; | |
143 | } | |
144 | ||
145 | static int __sev_do_cmd_locked(int cmd, void *data, int *psp_ret) | |
146 | { | |
147 | struct psp_device *psp = psp_master; | |
148 | unsigned int phys_lsb, phys_msb; | |
149 | unsigned int reg, ret = 0; | |
150 | ||
151 | if (!psp) | |
152 | return -ENODEV; | |
153 | ||
e82867fd BS |
154 | if (psp_dead) |
155 | return -EBUSY; | |
156 | ||
200664d5 BS |
157 | /* Get the physical address of the command buffer */ |
158 | phys_lsb = data ? lower_32_bits(__psp_pa(data)) : 0; | |
159 | phys_msb = data ? upper_32_bits(__psp_pa(data)) : 0; | |
160 | ||
e82867fd BS |
161 | dev_dbg(psp->dev, "sev command id %#x buffer 0x%08x%08x timeout %us\n", |
162 | cmd, phys_msb, phys_lsb, psp_timeout); | |
200664d5 BS |
163 | |
164 | print_hex_dump_debug("(in): ", DUMP_PREFIX_OFFSET, 16, 2, data, | |
165 | sev_cmd_buffer_len(cmd), false); | |
166 | ||
ad01a984 TL |
167 | iowrite32(phys_lsb, psp->io_regs + psp->vdata->cmdbuff_addr_lo_reg); |
168 | iowrite32(phys_msb, psp->io_regs + psp->vdata->cmdbuff_addr_hi_reg); | |
200664d5 | 169 | |
f426d2b2 TL |
170 | psp->sev_int_rcvd = 0; |
171 | ||
200664d5 BS |
172 | reg = cmd; |
173 | reg <<= PSP_CMDRESP_CMD_SHIFT; | |
174 | reg |= PSP_CMDRESP_IOC; | |
ad01a984 | 175 | iowrite32(reg, psp->io_regs + psp->vdata->cmdresp_reg); |
200664d5 BS |
176 | |
177 | /* wait for command completion */ | |
e82867fd BS |
178 | ret = sev_wait_cmd_ioc(psp, ®, psp_timeout); |
179 | if (ret) { | |
180 | if (psp_ret) | |
181 | *psp_ret = 0; | |
182 | ||
183 | dev_err(psp->dev, "sev command %#x timed out, disabling PSP \n", cmd); | |
184 | psp_dead = true; | |
185 | ||
186 | return ret; | |
187 | } | |
188 | ||
189 | psp_timeout = psp_cmd_timeout; | |
200664d5 BS |
190 | |
191 | if (psp_ret) | |
192 | *psp_ret = reg & PSP_CMDRESP_ERR_MASK; | |
193 | ||
194 | if (reg & PSP_CMDRESP_ERR_MASK) { | |
195 | dev_dbg(psp->dev, "sev command %#x failed (%#010x)\n", | |
196 | cmd, reg & PSP_CMDRESP_ERR_MASK); | |
197 | ret = -EIO; | |
198 | } | |
199 | ||
200 | print_hex_dump_debug("(out): ", DUMP_PREFIX_OFFSET, 16, 2, data, | |
201 | sev_cmd_buffer_len(cmd), false); | |
202 | ||
203 | return ret; | |
204 | } | |
205 | ||
206 | static int sev_do_cmd(int cmd, void *data, int *psp_ret) | |
207 | { | |
208 | int rc; | |
209 | ||
210 | mutex_lock(&sev_cmd_mutex); | |
211 | rc = __sev_do_cmd_locked(cmd, data, psp_ret); | |
212 | mutex_unlock(&sev_cmd_mutex); | |
213 | ||
214 | return rc; | |
215 | } | |
216 | ||
217 | static int __sev_platform_init_locked(int *error) | |
218 | { | |
219 | struct psp_device *psp = psp_master; | |
220 | int rc = 0; | |
221 | ||
222 | if (!psp) | |
223 | return -ENODEV; | |
224 | ||
225 | if (psp->sev_state == SEV_STATE_INIT) | |
226 | return 0; | |
227 | ||
228 | rc = __sev_do_cmd_locked(SEV_CMD_INIT, &psp->init_cmd_buf, error); | |
229 | if (rc) | |
230 | return rc; | |
231 | ||
232 | psp->sev_state = SEV_STATE_INIT; | |
233 | dev_dbg(psp->dev, "SEV firmware initialized\n"); | |
234 | ||
235 | return rc; | |
236 | } | |
237 | ||
238 | int sev_platform_init(int *error) | |
239 | { | |
240 | int rc; | |
241 | ||
242 | mutex_lock(&sev_cmd_mutex); | |
243 | rc = __sev_platform_init_locked(error); | |
244 | mutex_unlock(&sev_cmd_mutex); | |
245 | ||
246 | return rc; | |
247 | } | |
248 | EXPORT_SYMBOL_GPL(sev_platform_init); | |
249 | ||
250 | static int __sev_platform_shutdown_locked(int *error) | |
251 | { | |
252 | int ret; | |
253 | ||
e385b5b7 | 254 | ret = __sev_do_cmd_locked(SEV_CMD_SHUTDOWN, NULL, error); |
200664d5 BS |
255 | if (ret) |
256 | return ret; | |
257 | ||
258 | psp_master->sev_state = SEV_STATE_UNINIT; | |
259 | dev_dbg(psp_master->dev, "SEV firmware shutdown\n"); | |
260 | ||
261 | return ret; | |
262 | } | |
263 | ||
264 | static int sev_platform_shutdown(int *error) | |
265 | { | |
266 | int rc; | |
267 | ||
268 | mutex_lock(&sev_cmd_mutex); | |
269 | rc = __sev_platform_shutdown_locked(NULL); | |
270 | mutex_unlock(&sev_cmd_mutex); | |
271 | ||
272 | return rc; | |
273 | } | |
274 | ||
2960f9a5 BS |
275 | static int sev_get_platform_state(int *state, int *error) |
276 | { | |
277 | int rc; | |
278 | ||
279 | rc = __sev_do_cmd_locked(SEV_CMD_PLATFORM_STATUS, | |
280 | &psp_master->status_cmd_buf, error); | |
281 | if (rc) | |
282 | return rc; | |
283 | ||
284 | *state = psp_master->status_cmd_buf.state; | |
285 | return rc; | |
286 | } | |
287 | ||
288 | static int sev_ioctl_do_reset(struct sev_issue_cmd *argp) | |
289 | { | |
290 | int state, rc; | |
291 | ||
292 | /* | |
293 | * The SEV spec requires that FACTORY_RESET must be issued in | |
294 | * UNINIT state. Before we go further lets check if any guest is | |
295 | * active. | |
296 | * | |
297 | * If FW is in WORKING state then deny the request otherwise issue | |
298 | * SHUTDOWN command do INIT -> UNINIT before issuing the FACTORY_RESET. | |
299 | * | |
300 | */ | |
301 | rc = sev_get_platform_state(&state, &argp->error); | |
302 | if (rc) | |
303 | return rc; | |
304 | ||
305 | if (state == SEV_STATE_WORKING) | |
306 | return -EBUSY; | |
307 | ||
308 | if (state == SEV_STATE_INIT) { | |
309 | rc = __sev_platform_shutdown_locked(&argp->error); | |
310 | if (rc) | |
311 | return rc; | |
312 | } | |
313 | ||
e385b5b7 | 314 | return __sev_do_cmd_locked(SEV_CMD_FACTORY_RESET, NULL, &argp->error); |
2960f9a5 BS |
315 | } |
316 | ||
efe1829b BS |
317 | static int sev_ioctl_do_platform_status(struct sev_issue_cmd *argp) |
318 | { | |
319 | struct sev_user_data_status *data = &psp_master->status_cmd_buf; | |
320 | int ret; | |
321 | ||
322 | ret = __sev_do_cmd_locked(SEV_CMD_PLATFORM_STATUS, data, &argp->error); | |
323 | if (ret) | |
324 | return ret; | |
325 | ||
326 | if (copy_to_user((void __user *)argp->data, data, sizeof(*data))) | |
327 | ret = -EFAULT; | |
328 | ||
329 | return ret; | |
330 | } | |
331 | ||
4d84b726 BS |
332 | static int sev_ioctl_do_pek_pdh_gen(int cmd, struct sev_issue_cmd *argp) |
333 | { | |
334 | int rc; | |
335 | ||
336 | if (psp_master->sev_state == SEV_STATE_UNINIT) { | |
337 | rc = __sev_platform_init_locked(&argp->error); | |
338 | if (rc) | |
339 | return rc; | |
340 | } | |
341 | ||
e385b5b7 | 342 | return __sev_do_cmd_locked(cmd, NULL, &argp->error); |
4d84b726 BS |
343 | } |
344 | ||
e7990356 BS |
345 | static int sev_ioctl_do_pek_csr(struct sev_issue_cmd *argp) |
346 | { | |
347 | struct sev_user_data_pek_csr input; | |
348 | struct sev_data_pek_csr *data; | |
349 | void *blob = NULL; | |
350 | int ret; | |
351 | ||
352 | if (copy_from_user(&input, (void __user *)argp->data, sizeof(input))) | |
353 | return -EFAULT; | |
354 | ||
355 | data = kzalloc(sizeof(*data), GFP_KERNEL); | |
356 | if (!data) | |
357 | return -ENOMEM; | |
358 | ||
359 | /* userspace wants to query CSR length */ | |
360 | if (!input.address || !input.length) | |
361 | goto cmd; | |
362 | ||
363 | /* allocate a physically contiguous buffer to store the CSR blob */ | |
96d4f267 | 364 | if (!access_ok(input.address, input.length) || |
e7990356 BS |
365 | input.length > SEV_FW_BLOB_MAX_SIZE) { |
366 | ret = -EFAULT; | |
367 | goto e_free; | |
368 | } | |
369 | ||
370 | blob = kmalloc(input.length, GFP_KERNEL); | |
371 | if (!blob) { | |
372 | ret = -ENOMEM; | |
373 | goto e_free; | |
374 | } | |
375 | ||
376 | data->address = __psp_pa(blob); | |
377 | data->len = input.length; | |
378 | ||
379 | cmd: | |
380 | if (psp_master->sev_state == SEV_STATE_UNINIT) { | |
381 | ret = __sev_platform_init_locked(&argp->error); | |
382 | if (ret) | |
383 | goto e_free_blob; | |
384 | } | |
385 | ||
386 | ret = __sev_do_cmd_locked(SEV_CMD_PEK_CSR, data, &argp->error); | |
387 | ||
388 | /* If we query the CSR length, FW responded with expected data. */ | |
389 | input.length = data->len; | |
390 | ||
391 | if (copy_to_user((void __user *)argp->data, &input, sizeof(input))) { | |
392 | ret = -EFAULT; | |
393 | goto e_free_blob; | |
394 | } | |
395 | ||
396 | if (blob) { | |
397 | if (copy_to_user((void __user *)input.address, blob, input.length)) | |
398 | ret = -EFAULT; | |
399 | } | |
400 | ||
401 | e_free_blob: | |
402 | kfree(blob); | |
403 | e_free: | |
404 | kfree(data); | |
405 | return ret; | |
406 | } | |
407 | ||
7360e4b1 BS |
408 | void *psp_copy_user_blob(u64 __user uaddr, u32 len) |
409 | { | |
7360e4b1 BS |
410 | if (!uaddr || !len) |
411 | return ERR_PTR(-EINVAL); | |
412 | ||
413 | /* verify that blob length does not exceed our limit */ | |
414 | if (len > SEV_FW_BLOB_MAX_SIZE) | |
415 | return ERR_PTR(-EINVAL); | |
416 | ||
6c51dddd | 417 | return memdup_user((void __user *)(uintptr_t)uaddr, len); |
7360e4b1 BS |
418 | } |
419 | EXPORT_SYMBOL_GPL(psp_copy_user_blob); | |
420 | ||
edd303ff JN |
421 | static int sev_get_api_version(void) |
422 | { | |
423 | struct sev_user_data_status *status; | |
b78d3795 | 424 | int error = 0, ret; |
edd303ff JN |
425 | |
426 | status = &psp_master->status_cmd_buf; | |
427 | ret = sev_platform_status(status, &error); | |
428 | if (ret) { | |
429 | dev_err(psp_master->dev, | |
430 | "SEV: failed to get status. Error: %#x\n", error); | |
431 | return 1; | |
432 | } | |
433 | ||
434 | psp_master->api_major = status->api_major; | |
435 | psp_master->api_minor = status->api_minor; | |
436 | psp_master->build = status->build; | |
f8903b3e | 437 | psp_master->sev_state = status->state; |
edd303ff JN |
438 | |
439 | return 0; | |
440 | } | |
441 | ||
5182f26f WY |
442 | static int sev_get_firmware(struct device *dev, |
443 | const struct firmware **firmware) | |
e9372060 JN |
444 | { |
445 | char fw_name_specific[SEV_FW_NAME_SIZE]; | |
446 | char fw_name_subset[SEV_FW_NAME_SIZE]; | |
447 | ||
448 | snprintf(fw_name_specific, sizeof(fw_name_specific), | |
449 | "amd/amd_sev_fam%.2xh_model%.2xh.sbin", | |
450 | boot_cpu_data.x86, boot_cpu_data.x86_model); | |
451 | ||
452 | snprintf(fw_name_subset, sizeof(fw_name_subset), | |
453 | "amd/amd_sev_fam%.2xh_model%.1xxh.sbin", | |
454 | boot_cpu_data.x86, (boot_cpu_data.x86_model & 0xf0) >> 4); | |
455 | ||
456 | /* Check for SEV FW for a particular model. | |
457 | * Ex. amd_sev_fam17h_model00h.sbin for Family 17h Model 00h | |
458 | * | |
459 | * or | |
460 | * | |
461 | * Check for SEV FW common to a subset of models. | |
462 | * Ex. amd_sev_fam17h_model0xh.sbin for | |
463 | * Family 17h Model 00h -- Family 17h Model 0Fh | |
464 | * | |
465 | * or | |
466 | * | |
467 | * Fall-back to using generic name: sev.fw | |
468 | */ | |
469 | if ((firmware_request_nowarn(firmware, fw_name_specific, dev) >= 0) || | |
470 | (firmware_request_nowarn(firmware, fw_name_subset, dev) >= 0) || | |
471 | (firmware_request_nowarn(firmware, SEV_FW_FILE, dev) >= 0)) | |
472 | return 0; | |
473 | ||
474 | return -ENOENT; | |
475 | } | |
476 | ||
edd303ff JN |
477 | /* Don't fail if SEV FW couldn't be updated. Continue with existing SEV FW */ |
478 | static int sev_update_firmware(struct device *dev) | |
479 | { | |
480 | struct sev_data_download_firmware *data; | |
481 | const struct firmware *firmware; | |
482 | int ret, error, order; | |
483 | struct page *p; | |
484 | u64 data_size; | |
485 | ||
e9372060 JN |
486 | if (sev_get_firmware(dev, &firmware) == -ENOENT) { |
487 | dev_dbg(dev, "No SEV firmware file present\n"); | |
edd303ff | 488 | return -1; |
e9372060 | 489 | } |
edd303ff JN |
490 | |
491 | /* | |
492 | * SEV FW expects the physical address given to it to be 32 | |
493 | * byte aligned. Memory allocated has structure placed at the | |
494 | * beginning followed by the firmware being passed to the SEV | |
495 | * FW. Allocate enough memory for data structure + alignment | |
496 | * padding + SEV FW. | |
497 | */ | |
498 | data_size = ALIGN(sizeof(struct sev_data_download_firmware), 32); | |
499 | ||
500 | order = get_order(firmware->size + data_size); | |
501 | p = alloc_pages(GFP_KERNEL, order); | |
502 | if (!p) { | |
503 | ret = -1; | |
504 | goto fw_err; | |
505 | } | |
506 | ||
507 | /* | |
508 | * Copy firmware data to a kernel allocated contiguous | |
509 | * memory region. | |
510 | */ | |
511 | data = page_address(p); | |
512 | memcpy(page_address(p) + data_size, firmware->data, firmware->size); | |
513 | ||
514 | data->address = __psp_pa(page_address(p) + data_size); | |
515 | data->len = firmware->size; | |
516 | ||
517 | ret = sev_do_cmd(SEV_CMD_DOWNLOAD_FIRMWARE, data, &error); | |
518 | if (ret) | |
519 | dev_dbg(dev, "Failed to update SEV firmware: %#x\n", error); | |
520 | else | |
521 | dev_info(dev, "SEV firmware update successful\n"); | |
522 | ||
523 | __free_pages(p, order); | |
524 | ||
525 | fw_err: | |
526 | release_firmware(firmware); | |
527 | ||
528 | return ret; | |
529 | } | |
530 | ||
7360e4b1 BS |
531 | static int sev_ioctl_do_pek_import(struct sev_issue_cmd *argp) |
532 | { | |
533 | struct sev_user_data_pek_cert_import input; | |
534 | struct sev_data_pek_cert_import *data; | |
535 | void *pek_blob, *oca_blob; | |
536 | int ret; | |
537 | ||
538 | if (copy_from_user(&input, (void __user *)argp->data, sizeof(input))) | |
539 | return -EFAULT; | |
540 | ||
541 | data = kzalloc(sizeof(*data), GFP_KERNEL); | |
542 | if (!data) | |
543 | return -ENOMEM; | |
544 | ||
545 | /* copy PEK certificate blobs from userspace */ | |
546 | pek_blob = psp_copy_user_blob(input.pek_cert_address, input.pek_cert_len); | |
547 | if (IS_ERR(pek_blob)) { | |
548 | ret = PTR_ERR(pek_blob); | |
549 | goto e_free; | |
550 | } | |
551 | ||
552 | data->pek_cert_address = __psp_pa(pek_blob); | |
553 | data->pek_cert_len = input.pek_cert_len; | |
554 | ||
555 | /* copy PEK certificate blobs from userspace */ | |
556 | oca_blob = psp_copy_user_blob(input.oca_cert_address, input.oca_cert_len); | |
557 | if (IS_ERR(oca_blob)) { | |
558 | ret = PTR_ERR(oca_blob); | |
559 | goto e_free_pek; | |
560 | } | |
561 | ||
562 | data->oca_cert_address = __psp_pa(oca_blob); | |
563 | data->oca_cert_len = input.oca_cert_len; | |
564 | ||
565 | /* If platform is not in INIT state then transition it to INIT */ | |
566 | if (psp_master->sev_state != SEV_STATE_INIT) { | |
567 | ret = __sev_platform_init_locked(&argp->error); | |
568 | if (ret) | |
569 | goto e_free_oca; | |
570 | } | |
571 | ||
572 | ret = __sev_do_cmd_locked(SEV_CMD_PEK_CERT_IMPORT, data, &argp->error); | |
573 | ||
574 | e_free_oca: | |
575 | kfree(oca_blob); | |
576 | e_free_pek: | |
577 | kfree(pek_blob); | |
578 | e_free: | |
579 | kfree(data); | |
580 | return ret; | |
581 | } | |
582 | ||
d6112ea0 SB |
583 | static int sev_ioctl_do_get_id2(struct sev_issue_cmd *argp) |
584 | { | |
585 | struct sev_user_data_get_id2 input; | |
586 | struct sev_data_get_id *data; | |
587 | void *id_blob = NULL; | |
588 | int ret; | |
589 | ||
590 | /* SEV GET_ID is available from SEV API v0.16 and up */ | |
591 | if (!SEV_VERSION_GREATER_OR_EQUAL(0, 16)) | |
592 | return -ENOTSUPP; | |
593 | ||
594 | if (copy_from_user(&input, (void __user *)argp->data, sizeof(input))) | |
595 | return -EFAULT; | |
596 | ||
597 | /* Check if we have write access to the userspace buffer */ | |
598 | if (input.address && | |
599 | input.length && | |
600 | !access_ok(input.address, input.length)) | |
601 | return -EFAULT; | |
602 | ||
603 | data = kzalloc(sizeof(*data), GFP_KERNEL); | |
604 | if (!data) | |
605 | return -ENOMEM; | |
606 | ||
607 | if (input.address && input.length) { | |
608 | id_blob = kmalloc(input.length, GFP_KERNEL); | |
609 | if (!id_blob) { | |
610 | kfree(data); | |
611 | return -ENOMEM; | |
612 | } | |
613 | ||
614 | data->address = __psp_pa(id_blob); | |
615 | data->len = input.length; | |
616 | } | |
617 | ||
618 | ret = __sev_do_cmd_locked(SEV_CMD_GET_ID, data, &argp->error); | |
619 | ||
620 | /* | |
621 | * Firmware will return the length of the ID value (either the minimum | |
622 | * required length or the actual length written), return it to the user. | |
623 | */ | |
624 | input.length = data->len; | |
625 | ||
626 | if (copy_to_user((void __user *)argp->data, &input, sizeof(input))) { | |
627 | ret = -EFAULT; | |
628 | goto e_free; | |
629 | } | |
630 | ||
631 | if (id_blob) { | |
632 | if (copy_to_user((void __user *)input.address, | |
633 | id_blob, data->len)) { | |
634 | ret = -EFAULT; | |
635 | goto e_free; | |
636 | } | |
637 | } | |
638 | ||
639 | e_free: | |
640 | kfree(id_blob); | |
641 | kfree(data); | |
642 | ||
643 | return ret; | |
644 | } | |
645 | ||
0b3a830b JN |
646 | static int sev_ioctl_do_get_id(struct sev_issue_cmd *argp) |
647 | { | |
648 | struct sev_data_get_id *data; | |
649 | u64 data_size, user_size; | |
650 | void *id_blob, *mem; | |
651 | int ret; | |
652 | ||
653 | /* SEV GET_ID available from SEV API v0.16 and up */ | |
654 | if (!SEV_VERSION_GREATER_OR_EQUAL(0, 16)) | |
655 | return -ENOTSUPP; | |
656 | ||
657 | /* SEV FW expects the buffer it fills with the ID to be | |
658 | * 8-byte aligned. Memory allocated should be enough to | |
659 | * hold data structure + alignment padding + memory | |
660 | * where SEV FW writes the ID. | |
661 | */ | |
662 | data_size = ALIGN(sizeof(struct sev_data_get_id), 8); | |
663 | user_size = sizeof(struct sev_user_data_get_id); | |
664 | ||
665 | mem = kzalloc(data_size + user_size, GFP_KERNEL); | |
666 | if (!mem) | |
667 | return -ENOMEM; | |
668 | ||
669 | data = mem; | |
670 | id_blob = mem + data_size; | |
671 | ||
672 | data->address = __psp_pa(id_blob); | |
673 | data->len = user_size; | |
674 | ||
675 | ret = __sev_do_cmd_locked(SEV_CMD_GET_ID, data, &argp->error); | |
676 | if (!ret) { | |
677 | if (copy_to_user((void __user *)argp->data, id_blob, data->len)) | |
678 | ret = -EFAULT; | |
679 | } | |
680 | ||
681 | kfree(mem); | |
682 | ||
683 | return ret; | |
684 | } | |
685 | ||
76a2b524 BS |
686 | static int sev_ioctl_do_pdh_export(struct sev_issue_cmd *argp) |
687 | { | |
688 | struct sev_user_data_pdh_cert_export input; | |
689 | void *pdh_blob = NULL, *cert_blob = NULL; | |
690 | struct sev_data_pdh_cert_export *data; | |
691 | int ret; | |
692 | ||
693 | if (copy_from_user(&input, (void __user *)argp->data, sizeof(input))) | |
694 | return -EFAULT; | |
695 | ||
696 | data = kzalloc(sizeof(*data), GFP_KERNEL); | |
697 | if (!data) | |
698 | return -ENOMEM; | |
699 | ||
700 | /* Userspace wants to query the certificate length. */ | |
701 | if (!input.pdh_cert_address || | |
702 | !input.pdh_cert_len || | |
703 | !input.cert_chain_address) | |
704 | goto cmd; | |
705 | ||
706 | /* Allocate a physically contiguous buffer to store the PDH blob. */ | |
707 | if ((input.pdh_cert_len > SEV_FW_BLOB_MAX_SIZE) || | |
96d4f267 | 708 | !access_ok(input.pdh_cert_address, input.pdh_cert_len)) { |
76a2b524 BS |
709 | ret = -EFAULT; |
710 | goto e_free; | |
711 | } | |
712 | ||
713 | /* Allocate a physically contiguous buffer to store the cert chain blob. */ | |
714 | if ((input.cert_chain_len > SEV_FW_BLOB_MAX_SIZE) || | |
96d4f267 | 715 | !access_ok(input.cert_chain_address, input.cert_chain_len)) { |
76a2b524 BS |
716 | ret = -EFAULT; |
717 | goto e_free; | |
718 | } | |
719 | ||
720 | pdh_blob = kmalloc(input.pdh_cert_len, GFP_KERNEL); | |
721 | if (!pdh_blob) { | |
722 | ret = -ENOMEM; | |
723 | goto e_free; | |
724 | } | |
725 | ||
726 | data->pdh_cert_address = __psp_pa(pdh_blob); | |
727 | data->pdh_cert_len = input.pdh_cert_len; | |
728 | ||
729 | cert_blob = kmalloc(input.cert_chain_len, GFP_KERNEL); | |
730 | if (!cert_blob) { | |
731 | ret = -ENOMEM; | |
732 | goto e_free_pdh; | |
733 | } | |
734 | ||
735 | data->cert_chain_address = __psp_pa(cert_blob); | |
736 | data->cert_chain_len = input.cert_chain_len; | |
737 | ||
738 | cmd: | |
739 | /* If platform is not in INIT state then transition it to INIT. */ | |
740 | if (psp_master->sev_state != SEV_STATE_INIT) { | |
741 | ret = __sev_platform_init_locked(&argp->error); | |
742 | if (ret) | |
743 | goto e_free_cert; | |
744 | } | |
745 | ||
746 | ret = __sev_do_cmd_locked(SEV_CMD_PDH_CERT_EXPORT, data, &argp->error); | |
747 | ||
748 | /* If we query the length, FW responded with expected data. */ | |
749 | input.cert_chain_len = data->cert_chain_len; | |
750 | input.pdh_cert_len = data->pdh_cert_len; | |
751 | ||
752 | if (copy_to_user((void __user *)argp->data, &input, sizeof(input))) { | |
753 | ret = -EFAULT; | |
754 | goto e_free_cert; | |
755 | } | |
756 | ||
757 | if (pdh_blob) { | |
758 | if (copy_to_user((void __user *)input.pdh_cert_address, | |
759 | pdh_blob, input.pdh_cert_len)) { | |
760 | ret = -EFAULT; | |
761 | goto e_free_cert; | |
762 | } | |
763 | } | |
764 | ||
765 | if (cert_blob) { | |
766 | if (copy_to_user((void __user *)input.cert_chain_address, | |
767 | cert_blob, input.cert_chain_len)) | |
768 | ret = -EFAULT; | |
769 | } | |
770 | ||
771 | e_free_cert: | |
772 | kfree(cert_blob); | |
773 | e_free_pdh: | |
774 | kfree(pdh_blob); | |
775 | e_free: | |
776 | kfree(data); | |
777 | return ret; | |
778 | } | |
779 | ||
200664d5 BS |
780 | static long sev_ioctl(struct file *file, unsigned int ioctl, unsigned long arg) |
781 | { | |
2960f9a5 BS |
782 | void __user *argp = (void __user *)arg; |
783 | struct sev_issue_cmd input; | |
784 | int ret = -EFAULT; | |
785 | ||
786 | if (!psp_master) | |
787 | return -ENODEV; | |
788 | ||
789 | if (ioctl != SEV_ISSUE_CMD) | |
790 | return -EINVAL; | |
791 | ||
792 | if (copy_from_user(&input, argp, sizeof(struct sev_issue_cmd))) | |
793 | return -EFAULT; | |
794 | ||
795 | if (input.cmd > SEV_MAX) | |
796 | return -EINVAL; | |
797 | ||
798 | mutex_lock(&sev_cmd_mutex); | |
799 | ||
800 | switch (input.cmd) { | |
801 | ||
802 | case SEV_FACTORY_RESET: | |
803 | ret = sev_ioctl_do_reset(&input); | |
804 | break; | |
efe1829b BS |
805 | case SEV_PLATFORM_STATUS: |
806 | ret = sev_ioctl_do_platform_status(&input); | |
807 | break; | |
4d84b726 BS |
808 | case SEV_PEK_GEN: |
809 | ret = sev_ioctl_do_pek_pdh_gen(SEV_CMD_PEK_GEN, &input); | |
810 | break; | |
77f65327 BS |
811 | case SEV_PDH_GEN: |
812 | ret = sev_ioctl_do_pek_pdh_gen(SEV_CMD_PDH_GEN, &input); | |
813 | break; | |
e7990356 BS |
814 | case SEV_PEK_CSR: |
815 | ret = sev_ioctl_do_pek_csr(&input); | |
816 | break; | |
7360e4b1 BS |
817 | case SEV_PEK_CERT_IMPORT: |
818 | ret = sev_ioctl_do_pek_import(&input); | |
819 | break; | |
76a2b524 BS |
820 | case SEV_PDH_CERT_EXPORT: |
821 | ret = sev_ioctl_do_pdh_export(&input); | |
822 | break; | |
0b3a830b | 823 | case SEV_GET_ID: |
d6112ea0 | 824 | pr_warn_once("SEV_GET_ID command is deprecated, use SEV_GET_ID2\n"); |
0b3a830b JN |
825 | ret = sev_ioctl_do_get_id(&input); |
826 | break; | |
d6112ea0 SB |
827 | case SEV_GET_ID2: |
828 | ret = sev_ioctl_do_get_id2(&input); | |
829 | break; | |
2960f9a5 BS |
830 | default: |
831 | ret = -EINVAL; | |
832 | goto out; | |
833 | } | |
834 | ||
835 | if (copy_to_user(argp, &input, sizeof(struct sev_issue_cmd))) | |
836 | ret = -EFAULT; | |
837 | out: | |
838 | mutex_unlock(&sev_cmd_mutex); | |
839 | ||
840 | return ret; | |
200664d5 BS |
841 | } |
842 | ||
843 | static const struct file_operations sev_fops = { | |
844 | .owner = THIS_MODULE, | |
845 | .unlocked_ioctl = sev_ioctl, | |
846 | }; | |
847 | ||
848 | int sev_platform_status(struct sev_user_data_status *data, int *error) | |
849 | { | |
850 | return sev_do_cmd(SEV_CMD_PLATFORM_STATUS, data, error); | |
851 | } | |
852 | EXPORT_SYMBOL_GPL(sev_platform_status); | |
853 | ||
854 | int sev_guest_deactivate(struct sev_data_deactivate *data, int *error) | |
855 | { | |
856 | return sev_do_cmd(SEV_CMD_DEACTIVATE, data, error); | |
857 | } | |
858 | EXPORT_SYMBOL_GPL(sev_guest_deactivate); | |
859 | ||
860 | int sev_guest_activate(struct sev_data_activate *data, int *error) | |
861 | { | |
862 | return sev_do_cmd(SEV_CMD_ACTIVATE, data, error); | |
863 | } | |
864 | EXPORT_SYMBOL_GPL(sev_guest_activate); | |
865 | ||
866 | int sev_guest_decommission(struct sev_data_decommission *data, int *error) | |
867 | { | |
868 | return sev_do_cmd(SEV_CMD_DECOMMISSION, data, error); | |
869 | } | |
870 | EXPORT_SYMBOL_GPL(sev_guest_decommission); | |
871 | ||
872 | int sev_guest_df_flush(int *error) | |
873 | { | |
e385b5b7 | 874 | return sev_do_cmd(SEV_CMD_DF_FLUSH, NULL, error); |
200664d5 BS |
875 | } |
876 | EXPORT_SYMBOL_GPL(sev_guest_df_flush); | |
877 | ||
878 | static void sev_exit(struct kref *ref) | |
879 | { | |
880 | struct sev_misc_dev *misc_dev = container_of(ref, struct sev_misc_dev, refcount); | |
881 | ||
882 | misc_deregister(&misc_dev->misc); | |
883 | } | |
884 | ||
885 | static int sev_misc_init(struct psp_device *psp) | |
886 | { | |
887 | struct device *dev = psp->dev; | |
888 | int ret; | |
889 | ||
890 | /* | |
891 | * SEV feature support can be detected on multiple devices but the SEV | |
892 | * FW commands must be issued on the master. During probe, we do not | |
893 | * know the master hence we create /dev/sev on the first device probe. | |
894 | * sev_do_cmd() finds the right master device to which to issue the | |
895 | * command to the firmware. | |
896 | */ | |
897 | if (!misc_dev) { | |
898 | struct miscdevice *misc; | |
899 | ||
900 | misc_dev = devm_kzalloc(dev, sizeof(*misc_dev), GFP_KERNEL); | |
901 | if (!misc_dev) | |
902 | return -ENOMEM; | |
903 | ||
904 | misc = &misc_dev->misc; | |
905 | misc->minor = MISC_DYNAMIC_MINOR; | |
906 | misc->name = DEVICE_NAME; | |
907 | misc->fops = &sev_fops; | |
908 | ||
909 | ret = misc_register(misc); | |
910 | if (ret) | |
911 | return ret; | |
912 | ||
913 | kref_init(&misc_dev->refcount); | |
914 | } else { | |
915 | kref_get(&misc_dev->refcount); | |
916 | } | |
917 | ||
918 | init_waitqueue_head(&psp->sev_int_queue); | |
919 | psp->sev_misc = misc_dev; | |
920 | dev_dbg(dev, "registered SEV device\n"); | |
921 | ||
922 | return 0; | |
923 | } | |
924 | ||
7df5218d | 925 | static int psp_check_sev_support(struct psp_device *psp) |
200664d5 BS |
926 | { |
927 | /* Check if device supports SEV feature */ | |
ad01a984 | 928 | if (!(ioread32(psp->io_regs + psp->vdata->feature_reg) & 1)) { |
7df5218d LT |
929 | dev_dbg(psp->dev, "psp does not support SEV\n"); |
930 | return -ENODEV; | |
200664d5 BS |
931 | } |
932 | ||
7df5218d | 933 | return 0; |
200664d5 BS |
934 | } |
935 | ||
2a6170df BS |
936 | int psp_dev_init(struct sp_device *sp) |
937 | { | |
938 | struct device *dev = sp->dev; | |
939 | struct psp_device *psp; | |
940 | int ret; | |
941 | ||
942 | ret = -ENOMEM; | |
943 | psp = psp_alloc_struct(sp); | |
944 | if (!psp) | |
945 | goto e_err; | |
946 | ||
947 | sp->psp_data = psp; | |
948 | ||
949 | psp->vdata = (struct psp_vdata *)sp->dev_vdata->psp_vdata; | |
950 | if (!psp->vdata) { | |
951 | ret = -ENODEV; | |
952 | dev_err(dev, "missing driver data\n"); | |
953 | goto e_err; | |
954 | } | |
955 | ||
ad01a984 | 956 | psp->io_regs = sp->io_map; |
2a6170df | 957 | |
7df5218d LT |
958 | ret = psp_check_sev_support(psp); |
959 | if (ret) | |
960 | goto e_disable; | |
961 | ||
2a6170df | 962 | /* Disable and clear interrupts until ready */ |
ad01a984 TL |
963 | iowrite32(0, psp->io_regs + psp->vdata->inten_reg); |
964 | iowrite32(-1, psp->io_regs + psp->vdata->intsts_reg); | |
2a6170df BS |
965 | |
966 | /* Request an irq */ | |
967 | ret = sp_request_psp_irq(psp->sp, psp_irq_handler, psp->name, psp); | |
968 | if (ret) { | |
969 | dev_err(dev, "psp: unable to allocate an IRQ\n"); | |
970 | goto e_err; | |
971 | } | |
972 | ||
7df5218d | 973 | ret = sev_misc_init(psp); |
200664d5 BS |
974 | if (ret) |
975 | goto e_irq; | |
976 | ||
2a6170df BS |
977 | if (sp->set_psp_master_device) |
978 | sp->set_psp_master_device(sp); | |
979 | ||
980 | /* Enable interrupt */ | |
ad01a984 | 981 | iowrite32(-1, psp->io_regs + psp->vdata->inten_reg); |
2a6170df | 982 | |
015c8c85 TL |
983 | dev_notice(dev, "psp enabled\n"); |
984 | ||
2a6170df BS |
985 | return 0; |
986 | ||
200664d5 BS |
987 | e_irq: |
988 | sp_free_psp_irq(psp->sp, psp); | |
2a6170df BS |
989 | e_err: |
990 | sp->psp_data = NULL; | |
991 | ||
992 | dev_notice(dev, "psp initialization failed\n"); | |
993 | ||
7df5218d LT |
994 | return ret; |
995 | ||
996 | e_disable: | |
997 | sp->psp_data = NULL; | |
998 | ||
2a6170df BS |
999 | return ret; |
1000 | } | |
1001 | ||
1002 | void psp_dev_destroy(struct sp_device *sp) | |
1003 | { | |
1004 | struct psp_device *psp = sp->psp_data; | |
1005 | ||
afb31cd2 TL |
1006 | if (!psp) |
1007 | return; | |
1008 | ||
200664d5 BS |
1009 | if (psp->sev_misc) |
1010 | kref_put(&misc_dev->refcount, sev_exit); | |
1011 | ||
2a6170df BS |
1012 | sp_free_psp_irq(sp, psp); |
1013 | } | |
200664d5 BS |
1014 | |
1015 | int sev_issue_cmd_external_user(struct file *filep, unsigned int cmd, | |
1016 | void *data, int *error) | |
1017 | { | |
1018 | if (!filep || filep->f_op != &sev_fops) | |
1019 | return -EBADF; | |
1020 | ||
1021 | return sev_do_cmd(cmd, data, error); | |
1022 | } | |
1023 | EXPORT_SYMBOL_GPL(sev_issue_cmd_external_user); | |
1024 | ||
1025 | void psp_pci_init(void) | |
1026 | { | |
200664d5 BS |
1027 | struct sp_device *sp; |
1028 | int error, rc; | |
1029 | ||
1030 | sp = sp_get_psp_master_device(); | |
1031 | if (!sp) | |
1032 | return; | |
1033 | ||
1034 | psp_master = sp->psp_data; | |
1035 | ||
e82867fd BS |
1036 | psp_timeout = psp_probe_timeout; |
1037 | ||
edd303ff JN |
1038 | if (sev_get_api_version()) |
1039 | goto err; | |
1040 | ||
f8903b3e SB |
1041 | /* |
1042 | * If platform is not in UNINIT state then firmware upgrade and/or | |
1043 | * platform INIT command will fail. These command require UNINIT state. | |
1044 | * | |
1045 | * In a normal boot we should never run into case where the firmware | |
1046 | * is not in UNINIT state on boot. But in case of kexec boot, a reboot | |
1047 | * may not go through a typical shutdown sequence and may leave the | |
1048 | * firmware in INIT or WORKING state. | |
1049 | */ | |
1050 | ||
1051 | if (psp_master->sev_state != SEV_STATE_UNINIT) { | |
1052 | sev_platform_shutdown(NULL); | |
1053 | psp_master->sev_state = SEV_STATE_UNINIT; | |
1054 | } | |
1055 | ||
edd303ff JN |
1056 | if (SEV_VERSION_GREATER_OR_EQUAL(0, 15) && |
1057 | sev_update_firmware(psp_master->dev) == 0) | |
1058 | sev_get_api_version(); | |
1059 | ||
200664d5 BS |
1060 | /* Initialize the platform */ |
1061 | rc = sev_platform_init(&error); | |
1062 | if (rc) { | |
1063 | dev_err(sp->dev, "SEV: failed to INIT error %#x\n", error); | |
f5a2aeb8 | 1064 | return; |
200664d5 BS |
1065 | } |
1066 | ||
edd303ff JN |
1067 | dev_info(sp->dev, "SEV API:%d.%d build:%d\n", psp_master->api_major, |
1068 | psp_master->api_minor, psp_master->build); | |
200664d5 | 1069 | |
200664d5 BS |
1070 | return; |
1071 | ||
1072 | err: | |
1073 | psp_master = NULL; | |
1074 | } | |
1075 | ||
1076 | void psp_pci_exit(void) | |
1077 | { | |
1078 | if (!psp_master) | |
1079 | return; | |
1080 | ||
1081 | sev_platform_shutdown(NULL); | |
1082 | } |