cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

vcpu_sbi.c (4936B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (c) 2019 Western Digital Corporation or its affiliates.
      4 *
      5 * Authors:
      6 *     Atish Patra <atish.patra@wdc.com>
      7 */
      8
      9#include <linux/errno.h>
     10#include <linux/err.h>
     11#include <linux/kvm_host.h>
     12#include <asm/sbi.h>
     13#include <asm/kvm_vcpu_sbi.h>
     14
     15static int kvm_linux_err_map_sbi(int err)
     16{
     17	switch (err) {
     18	case 0:
     19		return SBI_SUCCESS;
     20	case -EPERM:
     21		return SBI_ERR_DENIED;
     22	case -EINVAL:
     23		return SBI_ERR_INVALID_PARAM;
     24	case -EFAULT:
     25		return SBI_ERR_INVALID_ADDRESS;
     26	case -EOPNOTSUPP:
     27		return SBI_ERR_NOT_SUPPORTED;
     28	case -EALREADY:
     29		return SBI_ERR_ALREADY_AVAILABLE;
     30	default:
     31		return SBI_ERR_FAILURE;
     32	};
     33}
     34
     35#ifdef CONFIG_RISCV_SBI_V01
     36extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_v01;
     37#else
     38static const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_v01 = {
     39	.extid_start = -1UL,
     40	.extid_end = -1UL,
     41	.handler = NULL,
     42};
     43#endif
     44extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_base;
     45extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_time;
     46extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_ipi;
     47extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_rfence;
     48extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_srst;
     49extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_hsm;
     50extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_experimental;
     51extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_vendor;
     52
     53static const struct kvm_vcpu_sbi_extension *sbi_ext[] = {
     54	&vcpu_sbi_ext_v01,
     55	&vcpu_sbi_ext_base,
     56	&vcpu_sbi_ext_time,
     57	&vcpu_sbi_ext_ipi,
     58	&vcpu_sbi_ext_rfence,
     59	&vcpu_sbi_ext_srst,
     60	&vcpu_sbi_ext_hsm,
     61	&vcpu_sbi_ext_experimental,
     62	&vcpu_sbi_ext_vendor,
     63};
     64
     65void kvm_riscv_vcpu_sbi_forward(struct kvm_vcpu *vcpu, struct kvm_run *run)
     66{
     67	struct kvm_cpu_context *cp = &vcpu->arch.guest_context;
     68
     69	vcpu->arch.sbi_context.return_handled = 0;
     70	vcpu->stat.ecall_exit_stat++;
     71	run->exit_reason = KVM_EXIT_RISCV_SBI;
     72	run->riscv_sbi.extension_id = cp->a7;
     73	run->riscv_sbi.function_id = cp->a6;
     74	run->riscv_sbi.args[0] = cp->a0;
     75	run->riscv_sbi.args[1] = cp->a1;
     76	run->riscv_sbi.args[2] = cp->a2;
     77	run->riscv_sbi.args[3] = cp->a3;
     78	run->riscv_sbi.args[4] = cp->a4;
     79	run->riscv_sbi.args[5] = cp->a5;
     80	run->riscv_sbi.ret[0] = cp->a0;
     81	run->riscv_sbi.ret[1] = cp->a1;
     82}
     83
     84void kvm_riscv_vcpu_sbi_system_reset(struct kvm_vcpu *vcpu,
     85				     struct kvm_run *run,
     86				     u32 type, u64 reason)
     87{
     88	unsigned long i;
     89	struct kvm_vcpu *tmp;
     90
     91	kvm_for_each_vcpu(i, tmp, vcpu->kvm)
     92		tmp->arch.power_off = true;
     93	kvm_make_all_cpus_request(vcpu->kvm, KVM_REQ_SLEEP);
     94
     95	memset(&run->system_event, 0, sizeof(run->system_event));
     96	run->system_event.type = type;
     97	run->system_event.ndata = 1;
     98	run->system_event.data[0] = reason;
     99	run->exit_reason = KVM_EXIT_SYSTEM_EVENT;
    100}
    101
    102int kvm_riscv_vcpu_sbi_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
    103{
    104	struct kvm_cpu_context *cp = &vcpu->arch.guest_context;
    105
    106	/* Handle SBI return only once */
    107	if (vcpu->arch.sbi_context.return_handled)
    108		return 0;
    109	vcpu->arch.sbi_context.return_handled = 1;
    110
    111	/* Update return values */
    112	cp->a0 = run->riscv_sbi.ret[0];
    113	cp->a1 = run->riscv_sbi.ret[1];
    114
    115	/* Move to next instruction */
    116	vcpu->arch.guest_context.sepc += 4;
    117
    118	return 0;
    119}
    120
    121const struct kvm_vcpu_sbi_extension *kvm_vcpu_sbi_find_ext(unsigned long extid)
    122{
    123	int i = 0;
    124
    125	for (i = 0; i < ARRAY_SIZE(sbi_ext); i++) {
    126		if (sbi_ext[i]->extid_start <= extid &&
    127		    sbi_ext[i]->extid_end >= extid)
    128			return sbi_ext[i];
    129	}
    130
    131	return NULL;
    132}
    133
    134int kvm_riscv_vcpu_sbi_ecall(struct kvm_vcpu *vcpu, struct kvm_run *run)
    135{
    136	int ret = 1;
    137	bool next_sepc = true;
    138	bool userspace_exit = false;
    139	struct kvm_cpu_context *cp = &vcpu->arch.guest_context;
    140	const struct kvm_vcpu_sbi_extension *sbi_ext;
    141	struct kvm_cpu_trap utrap = { 0 };
    142	unsigned long out_val = 0;
    143	bool ext_is_v01 = false;
    144
    145	sbi_ext = kvm_vcpu_sbi_find_ext(cp->a7);
    146	if (sbi_ext && sbi_ext->handler) {
    147#ifdef CONFIG_RISCV_SBI_V01
    148		if (cp->a7 >= SBI_EXT_0_1_SET_TIMER &&
    149		    cp->a7 <= SBI_EXT_0_1_SHUTDOWN)
    150			ext_is_v01 = true;
    151#endif
    152		ret = sbi_ext->handler(vcpu, run, &out_val, &utrap, &userspace_exit);
    153	} else {
    154		/* Return error for unsupported SBI calls */
    155		cp->a0 = SBI_ERR_NOT_SUPPORTED;
    156		goto ecall_done;
    157	}
    158
    159	/* Handle special error cases i.e trap, exit or userspace forward */
    160	if (utrap.scause) {
    161		/* No need to increment sepc or exit ioctl loop */
    162		ret = 1;
    163		utrap.sepc = cp->sepc;
    164		kvm_riscv_vcpu_trap_redirect(vcpu, &utrap);
    165		next_sepc = false;
    166		goto ecall_done;
    167	}
    168
    169	/* Exit ioctl loop or Propagate the error code the guest */
    170	if (userspace_exit) {
    171		next_sepc = false;
    172		ret = 0;
    173	} else {
    174		/**
    175		 * SBI extension handler always returns an Linux error code. Convert
    176		 * it to the SBI specific error code that can be propagated the SBI
    177		 * caller.
    178		 */
    179		ret = kvm_linux_err_map_sbi(ret);
    180		cp->a0 = ret;
    181		ret = 1;
    182	}
    183ecall_done:
    184	if (next_sepc)
    185		cp->sepc += 4;
    186	if (!ext_is_v01)
    187		cp->a1 = out_val;
    188
    189	return ret;
    190}