| @@ -1397,6 +1397,84 @@ static int sev_send_cancel(struct kvm *kvm, struct kvm_sev_cmd *argp) · 1396 unmodified lines |
| 1397 | 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 | 1478 | int svm_mem_enc_op(struct kvm *kvm, void __user *argp) |
| 1401 | 1479 | { |
| 1402 | 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 | 1549 | case KVM_SEV_SEND_CANCEL: |
| 1472 | 1550 | r = sev_send_cancel(kvm, &sev_cmd); |
| 1473 | 1551 | break; |
| 1552 | + case KVM_SEV_RECEIVE_START: |
| 1553 | + r = sev_receive_start(kvm, &sev_cmd); |
| 1554 | + break; |
| 1474 | 1555 | default: |
| 1475 | 1556 | r = -EINVAL; |
| 1476 | 1557 | goto out; |