• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2020 - Google Inc
4  * Author: Andrew Scull <ascull@google.com>
5  */
6 
7 #include <hyp/switch.h>
8 
9 #include <asm/kvm_asm.h>
10 #include <asm/kvm_emulate.h>
11 #include <asm/kvm_host.h>
12 #include <asm/kvm_hyp.h>
13 #include <asm/kvm_mmu.h>
14 
15 #include <kvm/arm_hypercalls.h>
16 
handle_host_hcall(unsigned long func_id,struct kvm_cpu_context * host_ctxt)17 static void handle_host_hcall(unsigned long func_id,
18 			      struct kvm_cpu_context *host_ctxt)
19 {
20 	unsigned long ret = 0;
21 
22 	switch (func_id) {
23 	case KVM_HOST_SMCCC_FUNC(__kvm_vcpu_run): {
24 		unsigned long r1 = host_ctxt->regs.regs[1];
25 		struct kvm_vcpu *vcpu = (struct kvm_vcpu *)r1;
26 
27 		ret = __kvm_vcpu_run(kern_hyp_va(vcpu));
28 		break;
29 	}
30 	case KVM_HOST_SMCCC_FUNC(__kvm_flush_vm_context):
31 		__kvm_flush_vm_context();
32 		break;
33 	case KVM_HOST_SMCCC_FUNC(__kvm_tlb_flush_vmid_ipa): {
34 		unsigned long r1 = host_ctxt->regs.regs[1];
35 		struct kvm_s2_mmu *mmu = (struct kvm_s2_mmu *)r1;
36 		phys_addr_t ipa = host_ctxt->regs.regs[2];
37 		int level = host_ctxt->regs.regs[3];
38 
39 		__kvm_tlb_flush_vmid_ipa(kern_hyp_va(mmu), ipa, level);
40 		break;
41 	}
42 	case KVM_HOST_SMCCC_FUNC(__kvm_tlb_flush_vmid): {
43 		unsigned long r1 = host_ctxt->regs.regs[1];
44 		struct kvm_s2_mmu *mmu = (struct kvm_s2_mmu *)r1;
45 
46 		__kvm_tlb_flush_vmid(kern_hyp_va(mmu));
47 		break;
48 	}
49 	case KVM_HOST_SMCCC_FUNC(__kvm_flush_cpu_context): {
50 		unsigned long r1 = host_ctxt->regs.regs[1];
51 		struct kvm_s2_mmu *mmu = (struct kvm_s2_mmu *)r1;
52 
53 		__kvm_flush_cpu_context(kern_hyp_va(mmu));
54 		break;
55 	}
56 	case KVM_HOST_SMCCC_FUNC(__kvm_timer_set_cntvoff): {
57 		u64 cntvoff = host_ctxt->regs.regs[1];
58 
59 		__kvm_timer_set_cntvoff(cntvoff);
60 		break;
61 	}
62 	case KVM_HOST_SMCCC_FUNC(__kvm_enable_ssbs):
63 		__kvm_enable_ssbs();
64 		break;
65 	case KVM_HOST_SMCCC_FUNC(__vgic_v3_get_ich_vtr_el2):
66 		ret = __vgic_v3_get_ich_vtr_el2();
67 		break;
68 	case KVM_HOST_SMCCC_FUNC(__vgic_v3_read_vmcr):
69 		ret = __vgic_v3_read_vmcr();
70 		break;
71 	case KVM_HOST_SMCCC_FUNC(__vgic_v3_write_vmcr): {
72 		u32 vmcr = host_ctxt->regs.regs[1];
73 
74 		__vgic_v3_write_vmcr(vmcr);
75 		break;
76 	}
77 	case KVM_HOST_SMCCC_FUNC(__vgic_v3_init_lrs):
78 		__vgic_v3_init_lrs();
79 		break;
80 	case KVM_HOST_SMCCC_FUNC(__kvm_get_mdcr_el2):
81 		ret = __kvm_get_mdcr_el2();
82 		break;
83 	case KVM_HOST_SMCCC_FUNC(__vgic_v3_save_aprs): {
84 		unsigned long r1 = host_ctxt->regs.regs[1];
85 		struct vgic_v3_cpu_if *cpu_if = (struct vgic_v3_cpu_if *)r1;
86 
87 		__vgic_v3_save_aprs(kern_hyp_va(cpu_if));
88 		break;
89 	}
90 	case KVM_HOST_SMCCC_FUNC(__vgic_v3_restore_aprs): {
91 		unsigned long r1 = host_ctxt->regs.regs[1];
92 		struct vgic_v3_cpu_if *cpu_if = (struct vgic_v3_cpu_if *)r1;
93 
94 		__vgic_v3_restore_aprs(kern_hyp_va(cpu_if));
95 		break;
96 	}
97 	default:
98 		/* Invalid host HVC. */
99 		host_ctxt->regs.regs[0] = SMCCC_RET_NOT_SUPPORTED;
100 		return;
101 	}
102 
103 	host_ctxt->regs.regs[0] = SMCCC_RET_SUCCESS;
104 	host_ctxt->regs.regs[1] = ret;
105 }
106 
handle_trap(struct kvm_cpu_context * host_ctxt)107 void handle_trap(struct kvm_cpu_context *host_ctxt)
108 {
109 	u64 esr = read_sysreg_el2(SYS_ESR);
110 	unsigned long func_id;
111 
112 	if (ESR_ELx_EC(esr) != ESR_ELx_EC_HVC64)
113 		hyp_panic();
114 
115 	func_id = host_ctxt->regs.regs[0];
116 	handle_host_hcall(func_id, host_ctxt);
117 }
118