Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions arch/x86/kvm/svm/svm.c
Original file line number Diff line number Diff line change
Expand Up @@ -5236,13 +5236,22 @@ static int kvm_hygon_arch_hypercall(struct kvm *kvm, u64 nr, u64 a0, u64 a1, u64
struct kvm_vpsp vpsp = {
.kvm = kvm,
.write_guest = kvm_write_guest,
.read_guest = kvm_read_guest
.read_guest = kvm_read_guest,
.gfn_to_pfn = gfn_to_pfn,
};

if (sev_guest(kvm)) {
vpsp.vm_handle = to_kvm_svm(kvm)->sev_info.handle;
vpsp.is_csv_guest = 1;
}

switch (nr) {
case KVM_HC_PSP_OP:
ret = kvm_pv_psp_op(&vpsp, a0, a1, a2, a3);
case KVM_HC_PSP_COPY_FORWARD_OP:
ret = kvm_pv_psp_copy_forward_op(&vpsp, a0, a1, a2);
break;
case KVM_HC_PSP_FORWARD_OP:
ret = kvm_pv_psp_forward_op(&vpsp, a0, a1, a2);
break;

default:
ret = -KVM_ENOSYS;
break;
Expand Down
9 changes: 7 additions & 2 deletions arch/x86/kvm/x86.c
Original file line number Diff line number Diff line change
Expand Up @@ -9895,7 +9895,10 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu)
}

if (static_call(kvm_x86_get_cpl)(vcpu) != 0 &&
!(is_x86_vendor_hygon() && (nr == KVM_HC_VM_ATTESTATION || nr == KVM_HC_PSP_OP))) {
!(is_x86_vendor_hygon() && (nr == KVM_HC_VM_ATTESTATION
|| nr == KVM_HC_PSP_OP_OBSOLETE
|| nr == KVM_HC_PSP_COPY_FORWARD_OP
|| nr == KVM_HC_PSP_FORWARD_OP))) {
ret = -KVM_EPERM;
goto out;
}
Expand Down Expand Up @@ -9932,7 +9935,9 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu)
kvm_sched_yield(vcpu, a0);
ret = 0;
break;
case KVM_HC_PSP_OP:
case KVM_HC_PSP_OP_OBSOLETE:
case KVM_HC_PSP_COPY_FORWARD_OP:
case KVM_HC_PSP_FORWARD_OP:
ret = -KVM_ENOSYS;
if (kvm_arch_hypercall)
ret = kvm_arch_hypercall(vcpu->kvm, nr, a0, a1, a2, a3);
Expand Down
101 changes: 90 additions & 11 deletions drivers/crypto/ccp/hygon/csv-dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <linux/psp.h>
#include <linux/psp-hygon.h>
#include <uapi/linux/psp-hygon.h>
#include <linux/bitfield.h>

#include <asm/csv.h>

Expand Down Expand Up @@ -663,12 +664,12 @@ static int vpsp_dequeue_cmd(int prio, int index,
* Populate the command from the virtual machine to the queue to
* support execution in ringbuffer mode
*/
static int vpsp_fill_cmd_queue(uint32_t vid, int prio, int cmd, void *data, uint16_t flags)
static int vpsp_fill_cmd_queue(int prio, int cmd, phys_addr_t phy_addr, uint16_t flags)
{
struct csv_cmdptr_entry cmdptr = { };
int index = -1;

cmdptr.cmd_buf_ptr = PUT_PSP_VID(__psp_pa(data), vid);
cmdptr.cmd_buf_ptr = phy_addr;
cmdptr.cmd_id = cmd;
cmdptr.cmd_flags = flags;

Expand Down Expand Up @@ -968,12 +969,91 @@ static int vpsp_rb_check_and_cmd_prio_parse(uint8_t *prio,
return rb_supported;
}

int __vpsp_do_cmd_locked(uint32_t vid, int cmd, void *data, int *psp_ret);
static int __vpsp_do_cmd_locked(int cmd, phys_addr_t phy_addr, int *psp_ret)
{
struct psp_device *psp = psp_master;
struct sev_device *sev;
unsigned int phys_lsb, phys_msb;
unsigned int reg, ret = 0;

if (!psp || !psp->sev_data)
return -ENODEV;

if (*hygon_psp_hooks.psp_dead)
return -EBUSY;

sev = psp->sev_data;

/* Get the physical address of the command buffer */
phys_lsb = phy_addr ? lower_32_bits(phy_addr) : 0;
phys_msb = phy_addr ? upper_32_bits(phy_addr) : 0;

dev_dbg(sev->dev, "sev command id %#x buffer 0x%08x%08x timeout %us\n",
cmd, phys_msb, phys_lsb, *hygon_psp_hooks.psp_timeout);

iowrite32(phys_lsb, sev->io_regs + sev->vdata->cmdbuff_addr_lo_reg);
iowrite32(phys_msb, sev->io_regs + sev->vdata->cmdbuff_addr_hi_reg);

sev->int_rcvd = 0;

reg = FIELD_PREP(SEV_CMDRESP_CMD, cmd) | SEV_CMDRESP_IOC;
iowrite32(reg, sev->io_regs + sev->vdata->cmdresp_reg);

/* wait for command completion */
ret = hygon_psp_hooks.sev_wait_cmd_ioc(sev, &reg, *hygon_psp_hooks.psp_timeout);
if (ret) {
if (psp_ret)
*psp_ret = 0;

dev_err(sev->dev, "sev command %#x timed out, disabling PSP\n", cmd);
*hygon_psp_hooks.psp_dead = true;

return ret;
}

*hygon_psp_hooks.psp_timeout = *hygon_psp_hooks.psp_cmd_timeout;

if (psp_ret)
*psp_ret = FIELD_GET(PSP_CMDRESP_STS, reg);

if (FIELD_GET(PSP_CMDRESP_STS, reg)) {
dev_dbg(sev->dev, "sev command %#x failed (%#010lx)\n",
cmd, FIELD_GET(PSP_CMDRESP_STS, reg));
ret = -EIO;
}

return ret;
}

int vpsp_do_cmd(int cmd, phys_addr_t phy_addr, int *psp_ret)
{
int rc;
int mutex_enabled = READ_ONCE(hygon_psp_hooks.psp_mutex_enabled);

if (is_vendor_hygon() && mutex_enabled) {
if (psp_mutex_lock_timeout(&hygon_psp_hooks.psp_misc->data_pg_aligned->mb_mutex,
PSP_MUTEX_TIMEOUT) != 1) {
return -EBUSY;
}
} else {
mutex_lock(hygon_psp_hooks.sev_cmd_mutex);
}

rc = __vpsp_do_cmd_locked(cmd, phy_addr, psp_ret);

if (is_vendor_hygon() && mutex_enabled)
psp_mutex_unlock(&hygon_psp_hooks.psp_misc->data_pg_aligned->mb_mutex);
else
mutex_unlock(hygon_psp_hooks.sev_cmd_mutex);

return rc;
}

/*
* Try to obtain the result again by the command index, this
* interface is used in ringbuffer mode
*/
int vpsp_try_get_result(uint32_t vid, uint8_t prio, uint32_t index, void *data,
int vpsp_try_get_result(uint8_t prio, uint32_t index, phys_addr_t phy_addr,
struct vpsp_ret *psp_ret)
{
int ret = 0;
Expand All @@ -996,8 +1076,7 @@ int vpsp_try_get_result(uint32_t vid, uint8_t prio, uint32_t index, void *data,
/* dequeue command from queue*/
vpsp_dequeue_cmd(prio, index, &cmd);

ret = __vpsp_do_cmd_locked(vid, cmd.cmd_id, data,
(int *)psp_ret);
ret = __vpsp_do_cmd_locked(cmd.cmd_id, phy_addr, (int *)psp_ret);
psp_ret->status = VPSP_FINISH;
vpsp_psp_mutex_unlock();
if (unlikely(ret)) {
Expand Down Expand Up @@ -1040,7 +1119,7 @@ EXPORT_SYMBOL_GPL(vpsp_try_get_result);
* vpsp_try_get_result interface will be used to obtain the result
* later again
*/
int vpsp_try_do_cmd(uint32_t vid, int cmd, void *data, struct vpsp_ret *psp_ret)
int vpsp_try_do_cmd(int cmd, phys_addr_t phy_addr, struct vpsp_ret *psp_ret)
{
int ret = 0;
int rb_supported;
Expand All @@ -1055,10 +1134,10 @@ int vpsp_try_do_cmd(uint32_t vid, int cmd, void *data, struct vpsp_ret *psp_ret)
(struct vpsp_cmd *)&cmd);
if (rb_supported) {
/* fill command in ringbuffer's queue and get index */
index = vpsp_fill_cmd_queue(vid, prio, cmd, data, 0);
index = vpsp_fill_cmd_queue(prio, cmd, phy_addr, 0);
if (unlikely(index < 0)) {
/* do mailbox command if queuing failed*/
ret = vpsp_do_cmd(vid, cmd, data, (int *)psp_ret);
ret = vpsp_do_cmd(cmd, phy_addr, (int *)psp_ret);
if (unlikely(ret)) {
if (ret == -EIO) {
ret = 0;
Expand All @@ -1074,14 +1153,14 @@ int vpsp_try_do_cmd(uint32_t vid, int cmd, void *data, struct vpsp_ret *psp_ret)
}

/* try to get result from the ringbuffer command */
ret = vpsp_try_get_result(vid, prio, index, data, psp_ret);
ret = vpsp_try_get_result(prio, index, phy_addr, psp_ret);
if (unlikely(ret)) {
pr_err("[%s]: vpsp_try_get_result failed %d\n", __func__, ret);
goto end;
}
} else {
/* mailbox mode */
ret = vpsp_do_cmd(vid, cmd, data, (int *)psp_ret);
ret = vpsp_do_cmd(cmd, phy_addr, (int *)psp_ret);
if (unlikely(ret)) {
if (ret == -EIO) {
ret = 0;
Expand Down
Loading