~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/riscv/kvm/vcpu_exit.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 /*
  3  * Copyright (C) 2019 Western Digital Corporation or its affiliates.
  4  *
  5  * Authors:
  6  *     Anup Patel <anup.patel@wdc.com>
  7  */
  8 
  9 #include <linux/kvm_host.h>
 10 #include <asm/csr.h>
 11 #include <asm/insn-def.h>
 12 
 13 static int gstage_page_fault(struct kvm_vcpu *vcpu, struct kvm_run *run,
 14                              struct kvm_cpu_trap *trap)
 15 {
 16         struct kvm_memory_slot *memslot;
 17         unsigned long hva, fault_addr;
 18         bool writable;
 19         gfn_t gfn;
 20         int ret;
 21 
 22         fault_addr = (trap->htval << 2) | (trap->stval & 0x3);
 23         gfn = fault_addr >> PAGE_SHIFT;
 24         memslot = gfn_to_memslot(vcpu->kvm, gfn);
 25         hva = gfn_to_hva_memslot_prot(memslot, gfn, &writable);
 26 
 27         if (kvm_is_error_hva(hva) ||
 28             (trap->scause == EXC_STORE_GUEST_PAGE_FAULT && !writable)) {
 29                 switch (trap->scause) {
 30                 case EXC_LOAD_GUEST_PAGE_FAULT:
 31                         return kvm_riscv_vcpu_mmio_load(vcpu, run,
 32                                                         fault_addr,
 33                                                         trap->htinst);
 34                 case EXC_STORE_GUEST_PAGE_FAULT:
 35                         return kvm_riscv_vcpu_mmio_store(vcpu, run,
 36                                                          fault_addr,
 37                                                          trap->htinst);
 38                 default:
 39                         return -EOPNOTSUPP;
 40                 };
 41         }
 42 
 43         ret = kvm_riscv_gstage_map(vcpu, memslot, fault_addr, hva,
 44                 (trap->scause == EXC_STORE_GUEST_PAGE_FAULT) ? true : false);
 45         if (ret < 0)
 46                 return ret;
 47 
 48         return 1;
 49 }
 50 
 51 /**
 52  * kvm_riscv_vcpu_unpriv_read -- Read machine word from Guest memory
 53  *
 54  * @vcpu: The VCPU pointer
 55  * @read_insn: Flag representing whether we are reading instruction
 56  * @guest_addr: Guest address to read
 57  * @trap: Output pointer to trap details
 58  */
 59 unsigned long kvm_riscv_vcpu_unpriv_read(struct kvm_vcpu *vcpu,
 60                                          bool read_insn,
 61                                          unsigned long guest_addr,
 62                                          struct kvm_cpu_trap *trap)
 63 {
 64         register unsigned long taddr asm("a0") = (unsigned long)trap;
 65         register unsigned long ttmp asm("a1");
 66         unsigned long flags, val, tmp, old_stvec, old_hstatus;
 67 
 68         local_irq_save(flags);
 69 
 70         old_hstatus = csr_swap(CSR_HSTATUS, vcpu->arch.guest_context.hstatus);
 71         old_stvec = csr_swap(CSR_STVEC, (ulong)&__kvm_riscv_unpriv_trap);
 72 
 73         if (read_insn) {
 74                 /*
 75                  * HLVX.HU instruction
 76                  * 0110010 00011 rs1 100 rd 1110011
 77                  */
 78                 asm volatile ("\n"
 79                         ".option push\n"
 80                         ".option norvc\n"
 81                         "add %[ttmp], %[taddr], 0\n"
 82                         HLVX_HU(%[val], %[addr])
 83                         "andi %[tmp], %[val], 3\n"
 84                         "addi %[tmp], %[tmp], -3\n"
 85                         "bne %[tmp], zero, 2f\n"
 86                         "addi %[addr], %[addr], 2\n"
 87                         HLVX_HU(%[tmp], %[addr])
 88                         "sll %[tmp], %[tmp], 16\n"
 89                         "add %[val], %[val], %[tmp]\n"
 90                         "2:\n"
 91                         ".option pop"
 92                 : [val] "=&r" (val), [tmp] "=&r" (tmp),
 93                   [taddr] "+&r" (taddr), [ttmp] "+&r" (ttmp),
 94                   [addr] "+&r" (guest_addr) : : "memory");
 95 
 96                 if (trap->scause == EXC_LOAD_PAGE_FAULT)
 97                         trap->scause = EXC_INST_PAGE_FAULT;
 98         } else {
 99                 /*
100                  * HLV.D instruction
101                  * 0110110 00000 rs1 100 rd 1110011
102                  *
103                  * HLV.W instruction
104                  * 0110100 00000 rs1 100 rd 1110011
105                  */
106                 asm volatile ("\n"
107                         ".option push\n"
108                         ".option norvc\n"
109                         "add %[ttmp], %[taddr], 0\n"
110 #ifdef CONFIG_64BIT
111                         HLV_D(%[val], %[addr])
112 #else
113                         HLV_W(%[val], %[addr])
114 #endif
115                         ".option pop"
116                 : [val] "=&r" (val),
117                   [taddr] "+&r" (taddr), [ttmp] "+&r" (ttmp)
118                 : [addr] "r" (guest_addr) : "memory");
119         }
120 
121         csr_write(CSR_STVEC, old_stvec);
122         csr_write(CSR_HSTATUS, old_hstatus);
123 
124         local_irq_restore(flags);
125 
126         return val;
127 }
128 
129 /**
130  * kvm_riscv_vcpu_trap_redirect -- Redirect trap to Guest
131  *
132  * @vcpu: The VCPU pointer
133  * @trap: Trap details
134  */
135 void kvm_riscv_vcpu_trap_redirect(struct kvm_vcpu *vcpu,
136                                   struct kvm_cpu_trap *trap)
137 {
138         unsigned long vsstatus = csr_read(CSR_VSSTATUS);
139 
140         /* Change Guest SSTATUS.SPP bit */
141         vsstatus &= ~SR_SPP;
142         if (vcpu->arch.guest_context.sstatus & SR_SPP)
143                 vsstatus |= SR_SPP;
144 
145         /* Change Guest SSTATUS.SPIE bit */
146         vsstatus &= ~SR_SPIE;
147         if (vsstatus & SR_SIE)
148                 vsstatus |= SR_SPIE;
149 
150         /* Clear Guest SSTATUS.SIE bit */
151         vsstatus &= ~SR_SIE;
152 
153         /* Update Guest SSTATUS */
154         csr_write(CSR_VSSTATUS, vsstatus);
155 
156         /* Update Guest SCAUSE, STVAL, and SEPC */
157         csr_write(CSR_VSCAUSE, trap->scause);
158         csr_write(CSR_VSTVAL, trap->stval);
159         csr_write(CSR_VSEPC, trap->sepc);
160 
161         /* Set Guest PC to Guest exception vector */
162         vcpu->arch.guest_context.sepc = csr_read(CSR_VSTVEC);
163 
164         /* Set Guest privilege mode to supervisor */
165         vcpu->arch.guest_context.sstatus |= SR_SPP;
166 }
167 
168 /*
169  * Return > 0 to return to guest, < 0 on error, 0 (and set exit_reason) on
170  * proper exit to userspace.
171  */
172 int kvm_riscv_vcpu_exit(struct kvm_vcpu *vcpu, struct kvm_run *run,
173                         struct kvm_cpu_trap *trap)
174 {
175         int ret;
176 
177         /* If we got host interrupt then do nothing */
178         if (trap->scause & CAUSE_IRQ_FLAG)
179                 return 1;
180 
181         /* Handle guest traps */
182         ret = -EFAULT;
183         run->exit_reason = KVM_EXIT_UNKNOWN;
184         switch (trap->scause) {
185         case EXC_INST_ILLEGAL:
186         case EXC_LOAD_MISALIGNED:
187         case EXC_STORE_MISALIGNED:
188         case EXC_LOAD_ACCESS:
189         case EXC_STORE_ACCESS:
190                 if (vcpu->arch.guest_context.hstatus & HSTATUS_SPV) {
191                         kvm_riscv_vcpu_trap_redirect(vcpu, trap);
192                         ret = 1;
193                 }
194                 break;
195         case EXC_VIRTUAL_INST_FAULT:
196                 if (vcpu->arch.guest_context.hstatus & HSTATUS_SPV)
197                         ret = kvm_riscv_vcpu_virtual_insn(vcpu, run, trap);
198                 break;
199         case EXC_INST_GUEST_PAGE_FAULT:
200         case EXC_LOAD_GUEST_PAGE_FAULT:
201         case EXC_STORE_GUEST_PAGE_FAULT:
202                 if (vcpu->arch.guest_context.hstatus & HSTATUS_SPV)
203                         ret = gstage_page_fault(vcpu, run, trap);
204                 break;
205         case EXC_SUPERVISOR_SYSCALL:
206                 if (vcpu->arch.guest_context.hstatus & HSTATUS_SPV)
207                         ret = kvm_riscv_vcpu_sbi_ecall(vcpu, run);
208                 break;
209         case EXC_BREAKPOINT:
210                 run->exit_reason = KVM_EXIT_DEBUG;
211                 ret = 0;
212                 break;
213         default:
214                 break;
215         }
216 
217         /* Print details in-case of error */
218         if (ret < 0) {
219                 kvm_err("VCPU exit error %d\n", ret);
220                 kvm_err("SEPC=0x%lx SSTATUS=0x%lx HSTATUS=0x%lx\n",
221                         vcpu->arch.guest_context.sepc,
222                         vcpu->arch.guest_context.sstatus,
223                         vcpu->arch.guest_context.hstatus);
224                 kvm_err("SCAUSE=0x%lx STVAL=0x%lx HTVAL=0x%lx HTINST=0x%lx\n",
225                         trap->scause, trap->stval, trap->htval, trap->htinst);
226         }
227 
228         return ret;
229 }
230 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php