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