18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2020-2022 Loongson Technology Corporation Limited 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/kvm_host.h> 78c2ecf20Sopenharmony_ci#include <asm/inst.h> 88c2ecf20Sopenharmony_ci#include <asm/numa.h> 98c2ecf20Sopenharmony_ci#include "kvmcpu.h" 108c2ecf20Sopenharmony_ci#include "intc/ls3a_ipi.h" 118c2ecf20Sopenharmony_ci#include "intc/ls3a_ext_irq.h" 128c2ecf20Sopenharmony_ci#include "ls_irq.h" 138c2ecf20Sopenharmony_ci#include "kvm_compat.h" 148c2ecf20Sopenharmony_ci#include "kvmcsr.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#define CASE_READ_SW_GCSR(csr, regid, csrid) \ 178c2ecf20Sopenharmony_ci do { \ 188c2ecf20Sopenharmony_ci if (regid == csrid) { \ 198c2ecf20Sopenharmony_ci return kvm_read_sw_gcsr(csr, csrid); \ 208c2ecf20Sopenharmony_ci } \ 218c2ecf20Sopenharmony_ci } while (0) 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ciunsigned long _kvm_emu_read_csr(struct kvm_vcpu *vcpu, int csrid) 248c2ecf20Sopenharmony_ci{ 258c2ecf20Sopenharmony_ci struct loongarch_csrs *csr = vcpu->arch.csr; 268c2ecf20Sopenharmony_ci unsigned long val = 0; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci CASE_READ_SW_GCSR(csr, csrid, KVM_CSR_MERRCTL); 298c2ecf20Sopenharmony_ci CASE_READ_SW_GCSR(csr, csrid, KVM_CSR_MERRINFO1); 308c2ecf20Sopenharmony_ci CASE_READ_SW_GCSR(csr, csrid, KVM_CSR_MERRINFO2); 318c2ecf20Sopenharmony_ci CASE_READ_SW_GCSR(csr, csrid, KVM_CSR_MERRENTRY); 328c2ecf20Sopenharmony_ci CASE_READ_SW_GCSR(csr, csrid, KVM_CSR_MERRERA); 338c2ecf20Sopenharmony_ci CASE_READ_SW_GCSR(csr, csrid, KVM_CSR_MERRSAVE); 348c2ecf20Sopenharmony_ci /* read sw csr when not config pmu to guest */ 358c2ecf20Sopenharmony_ci CASE_READ_SW_GCSR(csr, csrid, KVM_CSR_PERFCTRL0); 368c2ecf20Sopenharmony_ci CASE_READ_SW_GCSR(csr, csrid, KVM_CSR_PERFCTRL1); 378c2ecf20Sopenharmony_ci CASE_READ_SW_GCSR(csr, csrid, KVM_CSR_PERFCTRL2); 388c2ecf20Sopenharmony_ci CASE_READ_SW_GCSR(csr, csrid, KVM_CSR_PERFCTRL3); 398c2ecf20Sopenharmony_ci CASE_READ_SW_GCSR(csr, csrid, KVM_CSR_PERFCNTR0); 408c2ecf20Sopenharmony_ci CASE_READ_SW_GCSR(csr, csrid, KVM_CSR_PERFCNTR1); 418c2ecf20Sopenharmony_ci CASE_READ_SW_GCSR(csr, csrid, KVM_CSR_PERFCNTR2); 428c2ecf20Sopenharmony_ci CASE_READ_SW_GCSR(csr, csrid, KVM_CSR_PERFCNTR3); 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci val = 0; 458c2ecf20Sopenharmony_ci if (csrid < 4096) 468c2ecf20Sopenharmony_ci val = kvm_read_sw_gcsr(csr, csrid); 478c2ecf20Sopenharmony_ci else 488c2ecf20Sopenharmony_ci pr_warn_once("Unsupport csrread 0x%x with pc %lx\n", 498c2ecf20Sopenharmony_ci csrid, vcpu->arch.pc); 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci return val; 528c2ecf20Sopenharmony_ci} 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci#define CASE_WRITE_SW_GCSR(csr, regid, csrid, val) \ 558c2ecf20Sopenharmony_ci do { \ 568c2ecf20Sopenharmony_ci if (regid == csrid) { \ 578c2ecf20Sopenharmony_ci kvm_write_sw_gcsr(csr, csrid, val); \ 588c2ecf20Sopenharmony_ci return ; \ 598c2ecf20Sopenharmony_ci } \ 608c2ecf20Sopenharmony_ci } while (0) 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_civoid _kvm_emu_write_csr(struct kvm_vcpu *vcpu, int csrid, 638c2ecf20Sopenharmony_ci unsigned long val) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci struct loongarch_csrs *csr = vcpu->arch.csr; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci CASE_WRITE_SW_GCSR(csr, csrid, KVM_CSR_MERRCTL, val); 688c2ecf20Sopenharmony_ci CASE_WRITE_SW_GCSR(csr, csrid, KVM_CSR_MERRINFO1, val); 698c2ecf20Sopenharmony_ci CASE_WRITE_SW_GCSR(csr, csrid, KVM_CSR_MERRINFO2, val); 708c2ecf20Sopenharmony_ci CASE_WRITE_SW_GCSR(csr, csrid, KVM_CSR_MERRENTRY, val); 718c2ecf20Sopenharmony_ci CASE_WRITE_SW_GCSR(csr, csrid, KVM_CSR_MERRERA, val); 728c2ecf20Sopenharmony_ci CASE_WRITE_SW_GCSR(csr, csrid, KVM_CSR_MERRSAVE, val); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci /* give pmu register to guest when config perfctrl */ 758c2ecf20Sopenharmony_ci CASE_WRITE_HW_PMU(vcpu, csr, csrid, KVM_CSR_PERFCTRL0, val); 768c2ecf20Sopenharmony_ci CASE_WRITE_HW_PMU(vcpu, csr, csrid, KVM_CSR_PERFCTRL1, val); 778c2ecf20Sopenharmony_ci CASE_WRITE_HW_PMU(vcpu, csr, csrid, KVM_CSR_PERFCTRL2, val); 788c2ecf20Sopenharmony_ci CASE_WRITE_HW_PMU(vcpu, csr, csrid, KVM_CSR_PERFCTRL3, val); 798c2ecf20Sopenharmony_ci /* write sw pmu csr if not config ctrl */ 808c2ecf20Sopenharmony_ci CASE_WRITE_SW_GCSR(csr, csrid, KVM_CSR_PERFCNTR0, val); 818c2ecf20Sopenharmony_ci CASE_WRITE_SW_GCSR(csr, csrid, KVM_CSR_PERFCNTR1, val); 828c2ecf20Sopenharmony_ci CASE_WRITE_SW_GCSR(csr, csrid, KVM_CSR_PERFCNTR2, val); 838c2ecf20Sopenharmony_ci CASE_WRITE_SW_GCSR(csr, csrid, KVM_CSR_PERFCNTR3, val); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci if (csrid < 4096) 878c2ecf20Sopenharmony_ci kvm_write_sw_gcsr(csr, csrid, val); 888c2ecf20Sopenharmony_ci else 898c2ecf20Sopenharmony_ci pr_warn_once("Unsupport csrwrite 0x%x with pc %lx\n", 908c2ecf20Sopenharmony_ci csrid, vcpu->arch.pc); 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci#define CASE_CHANGE_SW_GCSR(csr, regid, csrid, mask, val) \ 948c2ecf20Sopenharmony_ci do { \ 958c2ecf20Sopenharmony_ci if (regid == csrid) { \ 968c2ecf20Sopenharmony_ci kvm_change_sw_gcsr(csr, csrid, mask, val); \ 978c2ecf20Sopenharmony_ci return ; \ 988c2ecf20Sopenharmony_ci } \ 998c2ecf20Sopenharmony_ci } while (0) 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_civoid _kvm_emu_xchg_csr(struct kvm_vcpu *vcpu, int csrid, 1028c2ecf20Sopenharmony_ci unsigned long csr_mask, unsigned long val) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci struct loongarch_csrs *csr = vcpu->arch.csr; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci CASE_CHANGE_SW_GCSR(csr, csrid, KVM_CSR_IMPCTL1, csr_mask, val); 1078c2ecf20Sopenharmony_ci CASE_CHANGE_SW_GCSR(csr, csrid, KVM_CSR_MERRCTL, csr_mask, val); 1088c2ecf20Sopenharmony_ci CASE_CHANGE_SW_GCSR(csr, csrid, KVM_CSR_MERRINFO1, csr_mask, val); 1098c2ecf20Sopenharmony_ci CASE_CHANGE_SW_GCSR(csr, csrid, KVM_CSR_MERRINFO2, csr_mask, val); 1108c2ecf20Sopenharmony_ci CASE_CHANGE_SW_GCSR(csr, csrid, KVM_CSR_MERRENTRY, csr_mask, val); 1118c2ecf20Sopenharmony_ci CASE_CHANGE_SW_GCSR(csr, csrid, KVM_CSR_MERRERA, csr_mask, val); 1128c2ecf20Sopenharmony_ci CASE_CHANGE_SW_GCSR(csr, csrid, KVM_CSR_MERRSAVE, csr_mask, val); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci if (csrid < 4096) { 1158c2ecf20Sopenharmony_ci unsigned long orig; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci orig = kvm_read_sw_gcsr(csr, csrid); 1188c2ecf20Sopenharmony_ci orig &= ~csr_mask; 1198c2ecf20Sopenharmony_ci orig |= val & csr_mask; 1208c2ecf20Sopenharmony_ci kvm_write_sw_gcsr(csr, csrid, orig); 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci pr_warn_once("Unsupport csrxchg 0x%x with pc %lx\n", 1238c2ecf20Sopenharmony_ci csrid, vcpu->arch.pc); 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ciint _kvm_getcsr(struct kvm_vcpu *vcpu, unsigned int id, u64 *v, int force) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci struct loongarch_csrs *csr = vcpu->arch.csr; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_CRMD, v); 1318c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_PRMD, v); 1328c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_EUEN, v); 1338c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_MISC, v); 1348c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_ECFG, v); 1358c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_ESTAT, v); 1368c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_ERA, v); 1378c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_BADV, v); 1388c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_BADI, v); 1398c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_EENTRY, v); 1408c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_TLBIDX, v); 1418c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_TLBEHI, v); 1428c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_TLBELO0, v); 1438c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_TLBELO1, v); 1448c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_ASID, v); 1458c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_PGDL, v); 1468c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_PGDH, v); 1478c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_PWCTL0, v); 1488c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_PWCTL1, v); 1498c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_STLBPGSIZE, v); 1508c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_RVACFG, v); 1518c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_CPUID, v); 1528c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_PRCFG1, v); 1538c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_PRCFG2, v); 1548c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_PRCFG3, v); 1558c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_KS0, v); 1568c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_KS1, v); 1578c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_KS2, v); 1588c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_KS3, v); 1598c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_KS4, v); 1608c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_KS5, v); 1618c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_KS6, v); 1628c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_KS7, v); 1638c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_TMID, v); 1648c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_TCFG, v); 1658c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_TVAL, v); 1668c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_CNTC, v); 1678c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_LLBCTL, v); 1688c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_TLBRENTRY, v); 1698c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_TLBRBADV, v); 1708c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_TLBRERA, v); 1718c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_TLBRSAVE, v); 1728c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_TLBRELO0, v); 1738c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_TLBRELO1, v); 1748c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_TLBREHI, v); 1758c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_TLBRPRMD, v); 1768c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_DMWIN0, v); 1778c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_DMWIN1, v); 1788c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_DMWIN2, v); 1798c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_DMWIN3, v); 1808c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_MWPS, v); 1818c2ecf20Sopenharmony_ci GET_HW_GCSR(id, KVM_CSR_FWPS, v); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci GET_SW_GCSR(csr, id, KVM_CSR_IMPCTL1, v); 1848c2ecf20Sopenharmony_ci GET_SW_GCSR(csr, id, KVM_CSR_IMPCTL2, v); 1858c2ecf20Sopenharmony_ci GET_SW_GCSR(csr, id, KVM_CSR_MERRCTL, v); 1868c2ecf20Sopenharmony_ci GET_SW_GCSR(csr, id, KVM_CSR_MERRINFO1, v); 1878c2ecf20Sopenharmony_ci GET_SW_GCSR(csr, id, KVM_CSR_MERRINFO2, v); 1888c2ecf20Sopenharmony_ci GET_SW_GCSR(csr, id, KVM_CSR_MERRENTRY, v); 1898c2ecf20Sopenharmony_ci GET_SW_GCSR(csr, id, KVM_CSR_MERRERA, v); 1908c2ecf20Sopenharmony_ci GET_SW_GCSR(csr, id, KVM_CSR_MERRSAVE, v); 1918c2ecf20Sopenharmony_ci GET_SW_GCSR(csr, id, KVM_CSR_CTAG, v); 1928c2ecf20Sopenharmony_ci GET_SW_GCSR(csr, id, KVM_CSR_DEBUG, v); 1938c2ecf20Sopenharmony_ci GET_SW_GCSR(csr, id, KVM_CSR_DERA, v); 1948c2ecf20Sopenharmony_ci GET_SW_GCSR(csr, id, KVM_CSR_DESAVE, v); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci GET_SW_GCSR(csr, id, KVM_CSR_TINTCLR, v); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci if (force && (id < CSR_ALL_SIZE)) { 1998c2ecf20Sopenharmony_ci *v = kvm_read_sw_gcsr(csr, id); 2008c2ecf20Sopenharmony_ci return 0; 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci return -1; 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ciint _kvm_setcsr(struct kvm_vcpu *vcpu, unsigned int id, u64 *v, int force) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci struct loongarch_csrs *csr = vcpu->arch.csr; 2098c2ecf20Sopenharmony_ci int ret; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci SET_HW_GCSR(csr, id, KVM_CSR_CRMD, v); 2128c2ecf20Sopenharmony_ci SET_HW_GCSR(csr, id, KVM_CSR_PRMD, v); 2138c2ecf20Sopenharmony_ci SET_HW_GCSR(csr, id, KVM_CSR_EUEN, v); 2148c2ecf20Sopenharmony_ci SET_HW_GCSR(csr, id, KVM_CSR_MISC, v); 2158c2ecf20Sopenharmony_ci SET_HW_GCSR(csr, id, KVM_CSR_ECFG, v); 2168c2ecf20Sopenharmony_ci SET_HW_GCSR(csr, id, KVM_CSR_ERA, v); 2178c2ecf20Sopenharmony_ci SET_HW_GCSR(csr, id, KVM_CSR_BADV, v); 2188c2ecf20Sopenharmony_ci SET_HW_GCSR(csr, id, KVM_CSR_BADI, v); 2198c2ecf20Sopenharmony_ci SET_HW_GCSR(csr, id, KVM_CSR_EENTRY, v); 2208c2ecf20Sopenharmony_ci SET_HW_GCSR(csr, id, KVM_CSR_TLBIDX, v); 2218c2ecf20Sopenharmony_ci SET_HW_GCSR(csr, id, KVM_CSR_TLBEHI, v); 2228c2ecf20Sopenharmony_ci SET_HW_GCSR(csr, id, KVM_CSR_TLBELO0, v); 2238c2ecf20Sopenharmony_ci SET_HW_GCSR(csr, id, KVM_CSR_TLBELO1, v); 2248c2ecf20Sopenharmony_ci SET_HW_GCSR(csr, id, KVM_CSR_ASID, v); 2258c2ecf20Sopenharmony_ci SET_HW_GCSR(csr, id, KVM_CSR_PGDL, v); 2268c2ecf20Sopenharmony_ci SET_HW_GCSR(csr, id, KVM_CSR_PGDH, v); 2278c2ecf20Sopenharmony_ci SET_HW_GCSR(csr, id, KVM_CSR_PWCTL0, v); 2288c2ecf20Sopenharmony_ci SET_HW_GCSR(csr, id, KVM_CSR_PWCTL1, v); 2298c2ecf20Sopenharmony_ci SET_HW_GCSR(csr, id, KVM_CSR_STLBPGSIZE, v); 2308c2ecf20Sopenharmony_ci SET_HW_GCSR(csr, id, KVM_CSR_RVACFG, v); 2318c2ecf20Sopenharmony_ci SET_HW_GCSR(csr, id, KVM_CSR_CPUID, v); 2328c2ecf20Sopenharmony_ci SET_HW_GCSR(csr, id, KVM_CSR_KS0, v); 2338c2ecf20Sopenharmony_ci SET_HW_GCSR(csr, id, KVM_CSR_KS1, v); 2348c2ecf20Sopenharmony_ci SET_HW_GCSR(csr, id, KVM_CSR_KS2, v); 2358c2ecf20Sopenharmony_ci SET_HW_GCSR(csr, id, KVM_CSR_KS3, v); 2368c2ecf20Sopenharmony_ci SET_HW_GCSR(csr, id, KVM_CSR_KS4, v); 2378c2ecf20Sopenharmony_ci SET_HW_GCSR(csr, id, KVM_CSR_KS5, v); 2388c2ecf20Sopenharmony_ci SET_HW_GCSR(csr, id, KVM_CSR_KS6, v); 2398c2ecf20Sopenharmony_ci SET_HW_GCSR(csr, id, KVM_CSR_KS7, v); 2408c2ecf20Sopenharmony_ci SET_HW_GCSR(csr, id, KVM_CSR_TMID, v); 2418c2ecf20Sopenharmony_ci SET_HW_GCSR(csr, id, KVM_CSR_TCFG, v); 2428c2ecf20Sopenharmony_ci SET_HW_GCSR(csr, id, KVM_CSR_TVAL, v); 2438c2ecf20Sopenharmony_ci SET_HW_GCSR(csr, id, KVM_CSR_CNTC, v); 2448c2ecf20Sopenharmony_ci SET_HW_GCSR(csr, id, KVM_CSR_LLBCTL, v); 2458c2ecf20Sopenharmony_ci SET_HW_GCSR(csr, id, KVM_CSR_TLBRENTRY, v); 2468c2ecf20Sopenharmony_ci SET_HW_GCSR(csr, id, KVM_CSR_TLBRBADV, v); 2478c2ecf20Sopenharmony_ci SET_HW_GCSR(csr, id, KVM_CSR_TLBRERA, v); 2488c2ecf20Sopenharmony_ci SET_HW_GCSR(csr, id, KVM_CSR_TLBRSAVE, v); 2498c2ecf20Sopenharmony_ci SET_HW_GCSR(csr, id, KVM_CSR_TLBRELO0, v); 2508c2ecf20Sopenharmony_ci SET_HW_GCSR(csr, id, KVM_CSR_TLBRELO1, v); 2518c2ecf20Sopenharmony_ci SET_HW_GCSR(csr, id, KVM_CSR_TLBREHI, v); 2528c2ecf20Sopenharmony_ci SET_HW_GCSR(csr, id, KVM_CSR_TLBRPRMD, v); 2538c2ecf20Sopenharmony_ci SET_HW_GCSR(csr, id, KVM_CSR_DMWIN0, v); 2548c2ecf20Sopenharmony_ci SET_HW_GCSR(csr, id, KVM_CSR_DMWIN1, v); 2558c2ecf20Sopenharmony_ci SET_HW_GCSR(csr, id, KVM_CSR_DMWIN2, v); 2568c2ecf20Sopenharmony_ci SET_HW_GCSR(csr, id, KVM_CSR_DMWIN3, v); 2578c2ecf20Sopenharmony_ci SET_HW_GCSR(csr, id, KVM_CSR_MWPS, v); 2588c2ecf20Sopenharmony_ci SET_HW_GCSR(csr, id, KVM_CSR_FWPS, v); 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci SET_SW_GCSR(csr, id, KVM_CSR_IMPCTL1, v); 2618c2ecf20Sopenharmony_ci SET_SW_GCSR(csr, id, KVM_CSR_IMPCTL2, v); 2628c2ecf20Sopenharmony_ci SET_SW_GCSR(csr, id, KVM_CSR_MERRCTL, v); 2638c2ecf20Sopenharmony_ci SET_SW_GCSR(csr, id, KVM_CSR_MERRINFO1, v); 2648c2ecf20Sopenharmony_ci SET_SW_GCSR(csr, id, KVM_CSR_MERRINFO2, v); 2658c2ecf20Sopenharmony_ci SET_SW_GCSR(csr, id, KVM_CSR_MERRENTRY, v); 2668c2ecf20Sopenharmony_ci SET_SW_GCSR(csr, id, KVM_CSR_MERRERA, v); 2678c2ecf20Sopenharmony_ci SET_SW_GCSR(csr, id, KVM_CSR_MERRSAVE, v); 2688c2ecf20Sopenharmony_ci SET_SW_GCSR(csr, id, KVM_CSR_CTAG, v); 2698c2ecf20Sopenharmony_ci SET_SW_GCSR(csr, id, KVM_CSR_DEBUG, v); 2708c2ecf20Sopenharmony_ci SET_SW_GCSR(csr, id, KVM_CSR_DERA, v); 2718c2ecf20Sopenharmony_ci SET_SW_GCSR(csr, id, KVM_CSR_DESAVE, v); 2728c2ecf20Sopenharmony_ci SET_SW_GCSR(csr, id, KVM_CSR_PRCFG1, v); 2738c2ecf20Sopenharmony_ci SET_SW_GCSR(csr, id, KVM_CSR_PRCFG2, v); 2748c2ecf20Sopenharmony_ci SET_SW_GCSR(csr, id, KVM_CSR_PRCFG3, v); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci SET_SW_GCSR(csr, id, KVM_CSR_PGD, v); 2778c2ecf20Sopenharmony_ci SET_SW_GCSR(csr, id, KVM_CSR_TINTCLR, v); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci ret = -1; 2808c2ecf20Sopenharmony_ci switch (id) { 2818c2ecf20Sopenharmony_ci case KVM_CSR_ESTAT: 2828c2ecf20Sopenharmony_ci kvm_write_gcsr_estat(*v); 2838c2ecf20Sopenharmony_ci /* estat IP0~IP7 inject through guestexcept */ 2848c2ecf20Sopenharmony_ci kvm_write_csr_gintc(((*v) >> 2) & 0xff); 2858c2ecf20Sopenharmony_ci ret = 0; 2868c2ecf20Sopenharmony_ci break; 2878c2ecf20Sopenharmony_ci default: 2888c2ecf20Sopenharmony_ci if (force && (id < CSR_ALL_SIZE)) { 2898c2ecf20Sopenharmony_ci kvm_set_sw_gcsr(csr, id, *v); 2908c2ecf20Sopenharmony_ci ret = 0; 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci break; 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci return ret; 2968c2ecf20Sopenharmony_ci} 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_cistruct kvm_iocsr { 2998c2ecf20Sopenharmony_ci u32 start, end; 3008c2ecf20Sopenharmony_ci int (*get) (struct kvm_run *run, struct kvm_vcpu *vcpu, u32 addr, u64 *res); 3018c2ecf20Sopenharmony_ci int (*set) (struct kvm_run *run, struct kvm_vcpu *vcpu, u32 addr, u64 val); 3028c2ecf20Sopenharmony_ci}; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_cistatic struct kvm_iocsr_entry *_kvm_find_iocsr(struct kvm *kvm, u32 addr) 3058c2ecf20Sopenharmony_ci{ 3068c2ecf20Sopenharmony_ci int i = 0; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci for (i = 0; i < IOCSR_MAX; i++) { 3098c2ecf20Sopenharmony_ci if (addr == kvm->arch.iocsr[i].addr) 3108c2ecf20Sopenharmony_ci return &kvm->arch.iocsr[i]; 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci return NULL; 3148c2ecf20Sopenharmony_ci} 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_cistatic int kvm_iocsr_common_get(struct kvm_run *run, struct kvm_vcpu *vcpu, 3178c2ecf20Sopenharmony_ci u32 addr, u64 *res) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci int r = EMULATE_FAIL; 3208c2ecf20Sopenharmony_ci struct kvm_iocsr_entry *entry; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci spin_lock(&vcpu->kvm->arch.iocsr_lock); 3238c2ecf20Sopenharmony_ci entry = _kvm_find_iocsr(vcpu->kvm, addr); 3248c2ecf20Sopenharmony_ci if (entry) { 3258c2ecf20Sopenharmony_ci r = EMULATE_DONE; 3268c2ecf20Sopenharmony_ci *res = entry->data; 3278c2ecf20Sopenharmony_ci } 3288c2ecf20Sopenharmony_ci spin_unlock(&vcpu->kvm->arch.iocsr_lock); 3298c2ecf20Sopenharmony_ci return r; 3308c2ecf20Sopenharmony_ci} 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_cistatic int kvm_iocsr_common_set(struct kvm_run *run, struct kvm_vcpu *vcpu, 3338c2ecf20Sopenharmony_ci u32 addr, u64 val) 3348c2ecf20Sopenharmony_ci{ 3358c2ecf20Sopenharmony_ci int r = EMULATE_FAIL; 3368c2ecf20Sopenharmony_ci struct kvm_iocsr_entry *entry; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci spin_lock(&vcpu->kvm->arch.iocsr_lock); 3398c2ecf20Sopenharmony_ci entry = _kvm_find_iocsr(vcpu->kvm, addr); 3408c2ecf20Sopenharmony_ci if (entry) { 3418c2ecf20Sopenharmony_ci r = EMULATE_DONE; 3428c2ecf20Sopenharmony_ci entry->data = val; 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci spin_unlock(&vcpu->kvm->arch.iocsr_lock); 3458c2ecf20Sopenharmony_ci return r; 3468c2ecf20Sopenharmony_ci} 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_cistatic int kvm_misc_set(struct kvm_run *run, struct kvm_vcpu *vcpu, u32 addr, 3498c2ecf20Sopenharmony_ci u64 val) 3508c2ecf20Sopenharmony_ci{ 3518c2ecf20Sopenharmony_ci return kvm_iocsr_common_set(run, vcpu, addr, val); 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_cistatic int kvm_ipi_get(struct kvm_run *run, struct kvm_vcpu *vcpu, u32 addr, 3558c2ecf20Sopenharmony_ci u64 *res) 3568c2ecf20Sopenharmony_ci{ 3578c2ecf20Sopenharmony_ci int ret; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci ++vcpu->stat.rdcsr_ipi_access_exits; 3608c2ecf20Sopenharmony_ci run->mmio.phys_addr = KVM_IPI_REG_ADDRESS(vcpu->vcpu_id, (addr & 0xff)); 3618c2ecf20Sopenharmony_ci ret = kvm_io_bus_read(vcpu, KVM_MMIO_BUS, run->mmio.phys_addr, 3628c2ecf20Sopenharmony_ci run->mmio.len, res); 3638c2ecf20Sopenharmony_ci if (ret) { 3648c2ecf20Sopenharmony_ci run->mmio.is_write = 0; 3658c2ecf20Sopenharmony_ci vcpu->mmio_needed = 1; 3668c2ecf20Sopenharmony_ci vcpu->mmio_is_write = 0; 3678c2ecf20Sopenharmony_ci return EMULATE_DO_MMIO; 3688c2ecf20Sopenharmony_ci } 3698c2ecf20Sopenharmony_ci return EMULATE_DONE; 3708c2ecf20Sopenharmony_ci} 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_cistatic int kvm_extioi_isr_get(struct kvm_run *run, struct kvm_vcpu *vcpu, 3738c2ecf20Sopenharmony_ci u32 addr, u64 *res) 3748c2ecf20Sopenharmony_ci{ 3758c2ecf20Sopenharmony_ci int ret; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci run->mmio.phys_addr = EXTIOI_PERCORE_ADDR(vcpu->vcpu_id, (addr & 0xff)); 3788c2ecf20Sopenharmony_ci ret = kvm_io_bus_read(vcpu, KVM_MMIO_BUS, run->mmio.phys_addr, 3798c2ecf20Sopenharmony_ci run->mmio.len, res); 3808c2ecf20Sopenharmony_ci if (ret) { 3818c2ecf20Sopenharmony_ci run->mmio.is_write = 0; 3828c2ecf20Sopenharmony_ci vcpu->mmio_needed = 1; 3838c2ecf20Sopenharmony_ci vcpu->mmio_is_write = 0; 3848c2ecf20Sopenharmony_ci return EMULATE_FAIL; 3858c2ecf20Sopenharmony_ci } 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci return EMULATE_DONE; 3888c2ecf20Sopenharmony_ci} 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_cistatic int kvm_ipi_set(struct kvm_run *run, struct kvm_vcpu *vcpu, u32 addr, 3918c2ecf20Sopenharmony_ci u64 val) 3928c2ecf20Sopenharmony_ci{ 3938c2ecf20Sopenharmony_ci int ret; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci run->mmio.phys_addr = KVM_IPI_REG_ADDRESS(vcpu->vcpu_id, (addr & 0xff)); 3968c2ecf20Sopenharmony_ci ret = kvm_io_bus_write(vcpu, KVM_MMIO_BUS, run->mmio.phys_addr, 3978c2ecf20Sopenharmony_ci run->mmio.len, &val); 3988c2ecf20Sopenharmony_ci if (ret < 0) { 3998c2ecf20Sopenharmony_ci run->mmio.is_write = 1; 4008c2ecf20Sopenharmony_ci vcpu->mmio_needed = 1; 4018c2ecf20Sopenharmony_ci vcpu->mmio_is_write = 1; 4028c2ecf20Sopenharmony_ci return EMULATE_DO_MMIO; 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci return EMULATE_DONE; 4068c2ecf20Sopenharmony_ci} 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_cistatic int kvm_extioi_set(struct kvm_run *run, struct kvm_vcpu *vcpu, u32 addr, 4098c2ecf20Sopenharmony_ci u64 val) 4108c2ecf20Sopenharmony_ci{ 4118c2ecf20Sopenharmony_ci int ret; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci if ((addr & 0x1f00) == KVM_IOCSR_EXTIOI_ISR_BASE) { 4148c2ecf20Sopenharmony_ci run->mmio.phys_addr = EXTIOI_PERCORE_ADDR(vcpu->vcpu_id, (addr & 0xff)); 4158c2ecf20Sopenharmony_ci } else { 4168c2ecf20Sopenharmony_ci run->mmio.phys_addr = EXTIOI_ADDR((addr & 0x1fff)); 4178c2ecf20Sopenharmony_ci } 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci ret = kvm_io_bus_write(vcpu, KVM_MMIO_BUS, run->mmio.phys_addr, 4208c2ecf20Sopenharmony_ci run->mmio.len, &val); 4218c2ecf20Sopenharmony_ci if (ret < 0) { 4228c2ecf20Sopenharmony_ci memcpy(run->mmio.data, &val, run->mmio.len); 4238c2ecf20Sopenharmony_ci run->mmio.is_write = 1; 4248c2ecf20Sopenharmony_ci vcpu->mmio_needed = 1; 4258c2ecf20Sopenharmony_ci vcpu->mmio_is_write = 1; 4268c2ecf20Sopenharmony_ci return EMULATE_DO_MMIO; 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci return EMULATE_DONE; 4308c2ecf20Sopenharmony_ci} 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_cistatic int kvm_nop_set(struct kvm_run *run, struct kvm_vcpu *vcpu, u32 addr, 4338c2ecf20Sopenharmony_ci u64 val) 4348c2ecf20Sopenharmony_ci{ 4358c2ecf20Sopenharmony_ci return EMULATE_DONE; 4368c2ecf20Sopenharmony_ci} 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci/* we put these iocsrs with access frequency, from high to low */ 4398c2ecf20Sopenharmony_cistatic struct kvm_iocsr kvm_iocsrs[] = { 4408c2ecf20Sopenharmony_ci /* extioi iocsr */ 4418c2ecf20Sopenharmony_ci {KVM_IOCSR_EXTIOI_EN_BASE, KVM_IOCSR_EXTIOI_EN_BASE + 0x100, 4428c2ecf20Sopenharmony_ci NULL, kvm_extioi_set}, 4438c2ecf20Sopenharmony_ci {KVM_IOCSR_EXTIOI_NODEMAP_BASE, KVM_IOCSR_EXTIOI_NODEMAP_BASE+0x28, 4448c2ecf20Sopenharmony_ci NULL, kvm_extioi_set}, 4458c2ecf20Sopenharmony_ci {KVM_IOCSR_EXTIOI_ROUTE_BASE, KVM_IOCSR_EXTIOI_ROUTE_BASE + 0x100, 4468c2ecf20Sopenharmony_ci NULL, kvm_extioi_set}, 4478c2ecf20Sopenharmony_ci {KVM_IOCSR_EXTIOI_ISR_BASE, KVM_IOCSR_EXTIOI_ISR_BASE + 0x1c, 4488c2ecf20Sopenharmony_ci kvm_extioi_isr_get, kvm_extioi_set}, 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci {KVM_IOCSR_IPI_STATUS, KVM_IOCSR_IPI_STATUS + 0x40, 4518c2ecf20Sopenharmony_ci kvm_ipi_get, kvm_ipi_set}, 4528c2ecf20Sopenharmony_ci {KVM_IOCSR_IPI_SEND, KVM_IOCSR_IPI_SEND + 0x1, 4538c2ecf20Sopenharmony_ci NULL, kvm_ipi_set}, 4548c2ecf20Sopenharmony_ci {KVM_IOCSR_MBUF_SEND, KVM_IOCSR_MBUF_SEND + 0x1, 4558c2ecf20Sopenharmony_ci NULL, kvm_ipi_set}, 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci {KVM_IOCSR_FEATURES, KVM_IOCSR_FEATURES + 0x1, 4588c2ecf20Sopenharmony_ci kvm_iocsr_common_get, kvm_nop_set}, 4598c2ecf20Sopenharmony_ci {KVM_IOCSR_VENDOR, KVM_IOCSR_VENDOR + 0x1, 4608c2ecf20Sopenharmony_ci kvm_iocsr_common_get, kvm_nop_set}, 4618c2ecf20Sopenharmony_ci {KVM_IOCSR_CPUNAME, KVM_IOCSR_CPUNAME + 0x1, 4628c2ecf20Sopenharmony_ci kvm_iocsr_common_get, kvm_nop_set}, 4638c2ecf20Sopenharmony_ci {KVM_IOCSR_NODECNT, KVM_IOCSR_NODECNT + 0x1, 4648c2ecf20Sopenharmony_ci kvm_iocsr_common_get, kvm_nop_set}, 4658c2ecf20Sopenharmony_ci {KVM_IOCSR_MISC_FUNC, KVM_IOCSR_MISC_FUNC + 0x1, 4668c2ecf20Sopenharmony_ci kvm_iocsr_common_get, kvm_misc_set}, 4678c2ecf20Sopenharmony_ci}; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_cistatic int _kvm_emu_iocsr_read(struct kvm_run *run, struct kvm_vcpu *vcpu, 4708c2ecf20Sopenharmony_ci u32 addr, u64 *res) 4718c2ecf20Sopenharmony_ci{ 4728c2ecf20Sopenharmony_ci enum emulation_result er = EMULATE_FAIL; 4738c2ecf20Sopenharmony_ci int i = 0; 4748c2ecf20Sopenharmony_ci struct kvm_iocsr *iocsr = NULL; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci if (!irqchip_in_kernel(vcpu->kvm)) { 4778c2ecf20Sopenharmony_ci run->iocsr_io.len = run->mmio.len; 4788c2ecf20Sopenharmony_ci run->iocsr_io.phys_addr = addr; 4798c2ecf20Sopenharmony_ci run->iocsr_io.is_write = 0; 4808c2ecf20Sopenharmony_ci return EMULATE_DO_IOCSR; 4818c2ecf20Sopenharmony_ci } 4828c2ecf20Sopenharmony_ci for (i = 0; i < sizeof(kvm_iocsrs) / sizeof(struct kvm_iocsr); i++) { 4838c2ecf20Sopenharmony_ci iocsr = &kvm_iocsrs[i]; 4848c2ecf20Sopenharmony_ci if (addr >= iocsr->start && addr < iocsr->end) { 4858c2ecf20Sopenharmony_ci if (iocsr->get) 4868c2ecf20Sopenharmony_ci er = iocsr->get(run, vcpu, addr, res); 4878c2ecf20Sopenharmony_ci } 4888c2ecf20Sopenharmony_ci } 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci if (er != EMULATE_DONE) 4918c2ecf20Sopenharmony_ci kvm_debug("%s iocsr 0x%x not support in kvm\n", __func__, addr); 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci return er; 4948c2ecf20Sopenharmony_ci} 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_cistatic int _kvm_emu_iocsr_write(struct kvm_run *run, struct kvm_vcpu *vcpu, 4978c2ecf20Sopenharmony_ci u32 addr, u64 val) 4988c2ecf20Sopenharmony_ci{ 4998c2ecf20Sopenharmony_ci enum emulation_result er = EMULATE_FAIL; 5008c2ecf20Sopenharmony_ci int i = 0; 5018c2ecf20Sopenharmony_ci struct kvm_iocsr *iocsr = NULL; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci if (!irqchip_in_kernel(vcpu->kvm)) { 5048c2ecf20Sopenharmony_ci run->iocsr_io.len = run->mmio.len; 5058c2ecf20Sopenharmony_ci memcpy(run->iocsr_io.data, &val, run->iocsr_io.len); 5068c2ecf20Sopenharmony_ci run->iocsr_io.phys_addr = addr; 5078c2ecf20Sopenharmony_ci run->iocsr_io.is_write = 1; 5088c2ecf20Sopenharmony_ci return EMULATE_DO_IOCSR; 5098c2ecf20Sopenharmony_ci } 5108c2ecf20Sopenharmony_ci for (i = 0; i < sizeof(kvm_iocsrs) / sizeof(struct kvm_iocsr); i++) { 5118c2ecf20Sopenharmony_ci iocsr = &kvm_iocsrs[i]; 5128c2ecf20Sopenharmony_ci if (addr >= iocsr->start && addr < iocsr->end) { 5138c2ecf20Sopenharmony_ci if (iocsr->set) 5148c2ecf20Sopenharmony_ci er = iocsr->set(run, vcpu, addr, val); 5158c2ecf20Sopenharmony_ci } 5168c2ecf20Sopenharmony_ci } 5178c2ecf20Sopenharmony_ci if (er != EMULATE_DONE) 5188c2ecf20Sopenharmony_ci kvm_debug("%s iocsr 0x%x not support in kvm\n", __func__, addr); 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci return er; 5218c2ecf20Sopenharmony_ci} 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci/* all iocsr operation should in kvm, no mmio */ 5248c2ecf20Sopenharmony_ciint _kvm_emu_iocsr(larch_inst inst, 5258c2ecf20Sopenharmony_ci struct kvm_run *run, struct kvm_vcpu *vcpu) 5268c2ecf20Sopenharmony_ci{ 5278c2ecf20Sopenharmony_ci u32 rd, rj, opcode; 5288c2ecf20Sopenharmony_ci u32 val; 5298c2ecf20Sopenharmony_ci u64 res = 0; 5308c2ecf20Sopenharmony_ci int ret; 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci /* 5338c2ecf20Sopenharmony_ci * Each IOCSR with different opcode 5348c2ecf20Sopenharmony_ci */ 5358c2ecf20Sopenharmony_ci rd = inst.reg2_format.rd; 5368c2ecf20Sopenharmony_ci rj = inst.reg2_format.rj; 5378c2ecf20Sopenharmony_ci opcode = inst.reg2_format.opcode; 5388c2ecf20Sopenharmony_ci val = vcpu->arch.gprs[rj]; 5398c2ecf20Sopenharmony_ci res = vcpu->arch.gprs[rd]; 5408c2ecf20Sopenharmony_ci /* LoongArch is Little endian */ 5418c2ecf20Sopenharmony_ci switch (opcode) { 5428c2ecf20Sopenharmony_ci case iocsrrdb_op: 5438c2ecf20Sopenharmony_ci run->mmio.len = 1; 5448c2ecf20Sopenharmony_ci ret = _kvm_emu_iocsr_read(run, vcpu, val, &res); 5458c2ecf20Sopenharmony_ci vcpu->arch.gprs[rd] = (u8) res; 5468c2ecf20Sopenharmony_ci break; 5478c2ecf20Sopenharmony_ci case iocsrrdh_op: 5488c2ecf20Sopenharmony_ci run->mmio.len = 2; 5498c2ecf20Sopenharmony_ci ret = _kvm_emu_iocsr_read(run, vcpu, val, &res); 5508c2ecf20Sopenharmony_ci vcpu->arch.gprs[rd] = (u16) res; 5518c2ecf20Sopenharmony_ci break; 5528c2ecf20Sopenharmony_ci case iocsrrdw_op: 5538c2ecf20Sopenharmony_ci run->mmio.len = 4; 5548c2ecf20Sopenharmony_ci ret = _kvm_emu_iocsr_read(run, vcpu, val, &res); 5558c2ecf20Sopenharmony_ci vcpu->arch.gprs[rd] = (u32) res; 5568c2ecf20Sopenharmony_ci break; 5578c2ecf20Sopenharmony_ci case iocsrrdd_op: 5588c2ecf20Sopenharmony_ci run->mmio.len = 8; 5598c2ecf20Sopenharmony_ci ret = _kvm_emu_iocsr_read(run, vcpu, val, &res); 5608c2ecf20Sopenharmony_ci vcpu->arch.gprs[rd] = res; 5618c2ecf20Sopenharmony_ci break; 5628c2ecf20Sopenharmony_ci case iocsrwrb_op: 5638c2ecf20Sopenharmony_ci run->mmio.len = 1; 5648c2ecf20Sopenharmony_ci ret = _kvm_emu_iocsr_write(run, vcpu, val, (u8)res); 5658c2ecf20Sopenharmony_ci break; 5668c2ecf20Sopenharmony_ci case iocsrwrh_op: 5678c2ecf20Sopenharmony_ci run->mmio.len = 2; 5688c2ecf20Sopenharmony_ci ret = _kvm_emu_iocsr_write(run, vcpu, val, (u16)res); 5698c2ecf20Sopenharmony_ci break; 5708c2ecf20Sopenharmony_ci case iocsrwrw_op: 5718c2ecf20Sopenharmony_ci run->mmio.len = 4; 5728c2ecf20Sopenharmony_ci ret = _kvm_emu_iocsr_write(run, vcpu, val, (u32)res); 5738c2ecf20Sopenharmony_ci break; 5748c2ecf20Sopenharmony_ci case iocsrwrd_op: 5758c2ecf20Sopenharmony_ci run->mmio.len = 8; 5768c2ecf20Sopenharmony_ci ret = _kvm_emu_iocsr_write(run, vcpu, val, res); 5778c2ecf20Sopenharmony_ci break; 5788c2ecf20Sopenharmony_ci default: 5798c2ecf20Sopenharmony_ci ret = EMULATE_FAIL; 5808c2ecf20Sopenharmony_ci break; 5818c2ecf20Sopenharmony_ci } 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci if (ret == EMULATE_DO_IOCSR) { 5848c2ecf20Sopenharmony_ci vcpu->arch.io_gpr = rd; 5858c2ecf20Sopenharmony_ci } 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci return ret; 5888c2ecf20Sopenharmony_ci} 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ciint _kvm_complete_iocsr_read(struct kvm_vcpu *vcpu, struct kvm_run *run) 5918c2ecf20Sopenharmony_ci{ 5928c2ecf20Sopenharmony_ci unsigned long *gpr = &vcpu->arch.gprs[vcpu->arch.io_gpr]; 5938c2ecf20Sopenharmony_ci enum emulation_result er = EMULATE_DONE; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci switch (run->iocsr_io.len) { 5968c2ecf20Sopenharmony_ci case 8: 5978c2ecf20Sopenharmony_ci *gpr = *(s64 *)run->iocsr_io.data; 5988c2ecf20Sopenharmony_ci break; 5998c2ecf20Sopenharmony_ci case 4: 6008c2ecf20Sopenharmony_ci *gpr = *(int *)run->iocsr_io.data; 6018c2ecf20Sopenharmony_ci break; 6028c2ecf20Sopenharmony_ci case 2: 6038c2ecf20Sopenharmony_ci *gpr = *(short *)run->iocsr_io.data; 6048c2ecf20Sopenharmony_ci break; 6058c2ecf20Sopenharmony_ci case 1: 6068c2ecf20Sopenharmony_ci *gpr = *(char *) run->iocsr_io.data; 6078c2ecf20Sopenharmony_ci break; 6088c2ecf20Sopenharmony_ci default: 6098c2ecf20Sopenharmony_ci kvm_err("Bad IOCSR length: %d,addr is 0x%lx", 6108c2ecf20Sopenharmony_ci run->iocsr_io.len, vcpu->arch.badv); 6118c2ecf20Sopenharmony_ci er = EMULATE_FAIL; 6128c2ecf20Sopenharmony_ci break; 6138c2ecf20Sopenharmony_ci } 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci return er; 6168c2ecf20Sopenharmony_ci} 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ciint _kvm_get_iocsr(struct kvm *kvm, struct kvm_iocsr_entry *__user argp) 6198c2ecf20Sopenharmony_ci{ 6208c2ecf20Sopenharmony_ci struct kvm_iocsr_entry *entry, tmp; 6218c2ecf20Sopenharmony_ci int r = -EFAULT; 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci if (copy_from_user(&tmp, argp, sizeof(tmp))) 6248c2ecf20Sopenharmony_ci goto out; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci spin_lock(&kvm->arch.iocsr_lock); 6278c2ecf20Sopenharmony_ci entry = _kvm_find_iocsr(kvm, tmp.addr); 6288c2ecf20Sopenharmony_ci if (entry != NULL) 6298c2ecf20Sopenharmony_ci tmp.data = entry->data; 6308c2ecf20Sopenharmony_ci spin_unlock(&kvm->arch.iocsr_lock); 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci if (entry) 6338c2ecf20Sopenharmony_ci r = copy_to_user(argp, &tmp, sizeof(tmp)); 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ciout: 6368c2ecf20Sopenharmony_ci return r; 6378c2ecf20Sopenharmony_ci} 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ciint _kvm_set_iocsr(struct kvm *kvm, struct kvm_iocsr_entry *__user argp) 6408c2ecf20Sopenharmony_ci{ 6418c2ecf20Sopenharmony_ci struct kvm_iocsr_entry *entry, tmp; 6428c2ecf20Sopenharmony_ci int r = -EFAULT; 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci if (copy_from_user(&tmp, argp, sizeof(tmp))) 6458c2ecf20Sopenharmony_ci goto out; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci spin_lock(&kvm->arch.iocsr_lock); 6488c2ecf20Sopenharmony_ci entry = _kvm_find_iocsr(kvm, tmp.addr); 6498c2ecf20Sopenharmony_ci if (entry != NULL) { 6508c2ecf20Sopenharmony_ci r = 0; 6518c2ecf20Sopenharmony_ci entry->data = tmp.data; 6528c2ecf20Sopenharmony_ci } 6538c2ecf20Sopenharmony_ci spin_unlock(&kvm->arch.iocsr_lock); 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ciout: 6568c2ecf20Sopenharmony_ci return r; 6578c2ecf20Sopenharmony_ci} 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_cistatic struct kvm_iocsr_entry iocsr_array[IOCSR_MAX] = { 6608c2ecf20Sopenharmony_ci {KVM_IOCSR_FEATURES, .data = KVM_IOCSRF_NODECNT|KVM_IOCSRF_MSI 6618c2ecf20Sopenharmony_ci |KVM_IOCSRF_EXTIOI|KVM_IOCSRF_CSRIPI|KVM_IOCSRF_VM}, 6628c2ecf20Sopenharmony_ci {KVM_IOCSR_VENDOR, .data = 0x6e6f73676e6f6f4c}, /* Loongson */ 6638c2ecf20Sopenharmony_ci {KVM_IOCSR_CPUNAME, .data = 0x303030354133}, /* 3A5000 */ 6648c2ecf20Sopenharmony_ci {KVM_IOCSR_NODECNT, .data = 0x4}, 6658c2ecf20Sopenharmony_ci {KVM_IOCSR_MISC_FUNC, .data = 0x0}, 6668c2ecf20Sopenharmony_ci}; 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ciint _kvm_init_iocsr(struct kvm *kvm) 6698c2ecf20Sopenharmony_ci{ 6708c2ecf20Sopenharmony_ci int i = 0; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci spin_lock_init(&kvm->arch.iocsr_lock); 6738c2ecf20Sopenharmony_ci for (i = 0; i < IOCSR_MAX; i++) { 6748c2ecf20Sopenharmony_ci kvm->arch.iocsr[i].addr = iocsr_array[i].addr; 6758c2ecf20Sopenharmony_ci kvm->arch.iocsr[i].data = iocsr_array[i].data; 6768c2ecf20Sopenharmony_ci } 6778c2ecf20Sopenharmony_ci return 0; 6788c2ecf20Sopenharmony_ci} 679