| @@ -1397,6 +1397,84 @@ static int sev_send_cancel(struct kvm *kvm, struct kvm_sev_cmd *argp) · 1396 unmodified lines |
| 1397 | return ret; | 1397 | return ret; |
| 1398 | } | 1398 | } |
| 1399 | | 1399 | |
| | 1400 | static int sev_receive_start(struct kvm *kvm, struct kvm_sev_cmd *argp) |
| | 1401 | { |
| | 1402 | struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info; |
| | 1403 | struct sev_data_receive_start *start; |
| | 1404 | struct kvm_sev_receive_start params; |
| | 1405 | int *error = &argp->error; |
| | 1406 | void *session_data; |
| | 1407 | void *pdh_data; |
| | 1408 | int ret; |
| | 1409 | |
| | 1410 | if (!sev_guest(kvm)) |
| | 1411 | return -ENOTTY; |
| | 1412 | |
| | 1413 | /* Get parameter from the userspace */ |
| | 1414 | if (copy_from_user(¶ms, (void __user *)(uintptr_t)argp->data, |
| | 1415 | sizeof(struct kvm_sev_receive_start))) |
| | 1416 | return -EFAULT; |
| | 1417 | |
| | 1418 | /* some sanity checks */ |
| | 1419 | if (!params.pdh_uaddr || !params.pdh_len || |
| | 1420 | !params.session_uaddr || !params.session_len) |
| | 1421 | return -EINVAL; |
| | 1422 | |
| | 1423 | pdh_data = psp_copy_user_blob(params.pdh_uaddr, params.pdh_len); |
| | 1424 | if (IS_ERR(pdh_data)) |
| | 1425 | return PTR_ERR(pdh_data); |
| | 1426 | |
| | 1427 | session_data = psp_copy_user_blob(params.session_uaddr, |
| | 1428 | params.session_len); |
| | 1429 | if (IS_ERR(session_data)) { |
| | 1430 | ret = PTR_ERR(session_data); |
| | 1431 | goto e_free_pdh; |
| | 1432 | } |
| | 1433 | |
| | 1434 | ret = -ENOMEM; |
| | 1435 | start = kzalloc(sizeof(*start), GFP_KERNEL); |
| | 1436 | if (!start) |
| | 1437 | goto e_free_session; |
| | 1438 | |
| | 1439 | start->handle = params.handle; |
| | 1440 | start->policy = params.policy; |
| | 1441 | start->pdh_cert_address = __psp_pa(pdh_data); |
| | 1442 | start->pdh_cert_len = params.pdh_len; |
| | 1443 | start->session_address = __psp_pa(session_data); |
| | 1444 | start->session_len = params.session_len; |
| | 1445 | |
| | 1446 | /* create memory encryption context */ |
| | 1447 | ret = __sev_issue_cmd(argp->sev_fd, SEV_CMD_RECEIVE_START, start, |
| | 1448 | error); |
| | 1449 | if (ret) |
| | 1450 | goto e_free; |
| | 1451 | |
| | 1452 | /* Bind ASID to this guest */ |
| | 1453 | ret = sev_bind_asid(kvm, start->handle, error); |
| | 1454 | if (ret) |
| | 1455 | goto e_free; |
| | 1456 | |
| | 1457 | params.handle = start->handle; |
| | 1458 | if (copy_to_user((void __user *)(uintptr_t)argp->data, |
| | 1459 | ¶ms, sizeof(struct kvm_sev_receive_start))) { |
| | 1460 | ret = -EFAULT; |
| | 1461 | sev_unbind_asid(kvm, start->handle); |
| | 1462 | goto e_free; |
| | 1463 | } |
| | 1464 | |
| | 1465 | sev->handle = start->handle; |
| | 1466 | sev->fd = argp->sev_fd; |
| | 1467 | |
| | 1468 | e_free: |
| | 1469 | kfree(start); |
| | 1470 | e_free_session: |
| | 1471 | kfree(session_data); |
| | 1472 | e_free_pdh: |
| | 1473 | kfree(pdh_data); |
| | 1474 | |
| | 1475 | return ret; |
| | 1476 | } |
| | 1477 | |
| 1400 | int svm_mem_enc_op(struct kvm *kvm, void __user *argp) | 1478 | int svm_mem_enc_op(struct kvm *kvm, void __user *argp) |
| 1401 | { | 1479 | { |
| 1402 | struct kvm_sev_cmd sev_cmd; | 1480 | struct kvm_sev_cmd sev_cmd; |
| @@ -1471,6 +1549,9 @@ int svm_mem_enc_op(struct kvm *kvm, void __user *argp) · 68 unmodified lines |
| 1471 | case KVM_SEV_SEND_CANCEL: | 1549 | case KVM_SEV_SEND_CANCEL: |
| 1472 | r = sev_send_cancel(kvm, &sev_cmd); | 1550 | r = sev_send_cancel(kvm, &sev_cmd); |
| 1473 | break; | 1551 | break; |
| | 1552 | case KVM_SEV_RECEIVE_START: |
| | 1553 | r = sev_receive_start(kvm, &sev_cmd); |
| | 1554 | break; |
| 1474 | default: | 1555 | default: |
| 1475 | r = -EINVAL; | 1556 | r = -EINVAL; |
| 1476 | goto out; | 1557 | goto out; |