18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2020 - Google Inc 48c2ecf20Sopenharmony_ci * Author: Andrew Scull <ascull@google.com> 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <hyp/switch.h> 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <asm/kvm_asm.h> 108c2ecf20Sopenharmony_ci#include <asm/kvm_emulate.h> 118c2ecf20Sopenharmony_ci#include <asm/kvm_host.h> 128c2ecf20Sopenharmony_ci#include <asm/kvm_hyp.h> 138c2ecf20Sopenharmony_ci#include <asm/kvm_mmu.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <kvm/arm_hypercalls.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_cistatic void handle_host_hcall(unsigned long func_id, 188c2ecf20Sopenharmony_ci struct kvm_cpu_context *host_ctxt) 198c2ecf20Sopenharmony_ci{ 208c2ecf20Sopenharmony_ci unsigned long ret = 0; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci switch (func_id) { 238c2ecf20Sopenharmony_ci case KVM_HOST_SMCCC_FUNC(__kvm_vcpu_run): { 248c2ecf20Sopenharmony_ci unsigned long r1 = host_ctxt->regs.regs[1]; 258c2ecf20Sopenharmony_ci struct kvm_vcpu *vcpu = (struct kvm_vcpu *)r1; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci ret = __kvm_vcpu_run(kern_hyp_va(vcpu)); 288c2ecf20Sopenharmony_ci break; 298c2ecf20Sopenharmony_ci } 308c2ecf20Sopenharmony_ci case KVM_HOST_SMCCC_FUNC(__kvm_flush_vm_context): 318c2ecf20Sopenharmony_ci __kvm_flush_vm_context(); 328c2ecf20Sopenharmony_ci break; 338c2ecf20Sopenharmony_ci case KVM_HOST_SMCCC_FUNC(__kvm_tlb_flush_vmid_ipa): { 348c2ecf20Sopenharmony_ci unsigned long r1 = host_ctxt->regs.regs[1]; 358c2ecf20Sopenharmony_ci struct kvm_s2_mmu *mmu = (struct kvm_s2_mmu *)r1; 368c2ecf20Sopenharmony_ci phys_addr_t ipa = host_ctxt->regs.regs[2]; 378c2ecf20Sopenharmony_ci int level = host_ctxt->regs.regs[3]; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci __kvm_tlb_flush_vmid_ipa(kern_hyp_va(mmu), ipa, level); 408c2ecf20Sopenharmony_ci break; 418c2ecf20Sopenharmony_ci } 428c2ecf20Sopenharmony_ci case KVM_HOST_SMCCC_FUNC(__kvm_tlb_flush_vmid): { 438c2ecf20Sopenharmony_ci unsigned long r1 = host_ctxt->regs.regs[1]; 448c2ecf20Sopenharmony_ci struct kvm_s2_mmu *mmu = (struct kvm_s2_mmu *)r1; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci __kvm_tlb_flush_vmid(kern_hyp_va(mmu)); 478c2ecf20Sopenharmony_ci break; 488c2ecf20Sopenharmony_ci } 498c2ecf20Sopenharmony_ci case KVM_HOST_SMCCC_FUNC(__kvm_flush_cpu_context): { 508c2ecf20Sopenharmony_ci unsigned long r1 = host_ctxt->regs.regs[1]; 518c2ecf20Sopenharmony_ci struct kvm_s2_mmu *mmu = (struct kvm_s2_mmu *)r1; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci __kvm_flush_cpu_context(kern_hyp_va(mmu)); 548c2ecf20Sopenharmony_ci break; 558c2ecf20Sopenharmony_ci } 568c2ecf20Sopenharmony_ci case KVM_HOST_SMCCC_FUNC(__kvm_timer_set_cntvoff): { 578c2ecf20Sopenharmony_ci u64 cntvoff = host_ctxt->regs.regs[1]; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci __kvm_timer_set_cntvoff(cntvoff); 608c2ecf20Sopenharmony_ci break; 618c2ecf20Sopenharmony_ci } 628c2ecf20Sopenharmony_ci case KVM_HOST_SMCCC_FUNC(__kvm_enable_ssbs): 638c2ecf20Sopenharmony_ci __kvm_enable_ssbs(); 648c2ecf20Sopenharmony_ci break; 658c2ecf20Sopenharmony_ci case KVM_HOST_SMCCC_FUNC(__vgic_v3_get_ich_vtr_el2): 668c2ecf20Sopenharmony_ci ret = __vgic_v3_get_ich_vtr_el2(); 678c2ecf20Sopenharmony_ci break; 688c2ecf20Sopenharmony_ci case KVM_HOST_SMCCC_FUNC(__vgic_v3_read_vmcr): 698c2ecf20Sopenharmony_ci ret = __vgic_v3_read_vmcr(); 708c2ecf20Sopenharmony_ci break; 718c2ecf20Sopenharmony_ci case KVM_HOST_SMCCC_FUNC(__vgic_v3_write_vmcr): { 728c2ecf20Sopenharmony_ci u32 vmcr = host_ctxt->regs.regs[1]; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci __vgic_v3_write_vmcr(vmcr); 758c2ecf20Sopenharmony_ci break; 768c2ecf20Sopenharmony_ci } 778c2ecf20Sopenharmony_ci case KVM_HOST_SMCCC_FUNC(__vgic_v3_init_lrs): 788c2ecf20Sopenharmony_ci __vgic_v3_init_lrs(); 798c2ecf20Sopenharmony_ci break; 808c2ecf20Sopenharmony_ci case KVM_HOST_SMCCC_FUNC(__kvm_get_mdcr_el2): 818c2ecf20Sopenharmony_ci ret = __kvm_get_mdcr_el2(); 828c2ecf20Sopenharmony_ci break; 838c2ecf20Sopenharmony_ci case KVM_HOST_SMCCC_FUNC(__vgic_v3_save_aprs): { 848c2ecf20Sopenharmony_ci unsigned long r1 = host_ctxt->regs.regs[1]; 858c2ecf20Sopenharmony_ci struct vgic_v3_cpu_if *cpu_if = (struct vgic_v3_cpu_if *)r1; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci __vgic_v3_save_aprs(kern_hyp_va(cpu_if)); 888c2ecf20Sopenharmony_ci break; 898c2ecf20Sopenharmony_ci } 908c2ecf20Sopenharmony_ci case KVM_HOST_SMCCC_FUNC(__vgic_v3_restore_aprs): { 918c2ecf20Sopenharmony_ci unsigned long r1 = host_ctxt->regs.regs[1]; 928c2ecf20Sopenharmony_ci struct vgic_v3_cpu_if *cpu_if = (struct vgic_v3_cpu_if *)r1; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci __vgic_v3_restore_aprs(kern_hyp_va(cpu_if)); 958c2ecf20Sopenharmony_ci break; 968c2ecf20Sopenharmony_ci } 978c2ecf20Sopenharmony_ci default: 988c2ecf20Sopenharmony_ci /* Invalid host HVC. */ 998c2ecf20Sopenharmony_ci host_ctxt->regs.regs[0] = SMCCC_RET_NOT_SUPPORTED; 1008c2ecf20Sopenharmony_ci return; 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci host_ctxt->regs.regs[0] = SMCCC_RET_SUCCESS; 1048c2ecf20Sopenharmony_ci host_ctxt->regs.regs[1] = ret; 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_civoid handle_trap(struct kvm_cpu_context *host_ctxt) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci u64 esr = read_sysreg_el2(SYS_ESR); 1108c2ecf20Sopenharmony_ci unsigned long func_id; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci if (ESR_ELx_EC(esr) != ESR_ELx_EC_HVC64) 1138c2ecf20Sopenharmony_ci hyp_panic(); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci func_id = host_ctxt->regs.regs[0]; 1168c2ecf20Sopenharmony_ci handle_host_hcall(func_id, host_ctxt); 1178c2ecf20Sopenharmony_ci} 118