// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2018 - os kernal * Author: fire3 yangzh * linhn */ #include #include #include static unsigned long mmio_read_buf(char *buf, unsigned int len) { unsigned long data = 0; union { u16 hword; u32 word; u64 dword; } tmp; switch (len) { case 1: data = buf[0]; break; case 2: memcpy(&tmp.hword, buf, len); data = tmp.hword; break; case 4: memcpy(&tmp.word, buf, len); data = tmp.word; break; case 8: memcpy(&tmp.dword, buf, len); data = tmp.dword; break; } return data; } int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run) { unsigned long data; unsigned int len; if (!run->mmio.is_write) { len = run->mmio.len; if (len > sizeof(unsigned long)) return -EINVAL; data = mmio_read_buf(run->mmio.data, len); vcpu_set_reg(vcpu, vcpu->arch.mmio_decode.rt, data); } vcpu->arch.regs.pc += 4; return 0; } int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run, struct hcall_args *hargs) { int ret; run->mmio.phys_addr = hargs->arg1 & 0xfffffffffffffUL; sw64_decode(vcpu, hargs->arg2, run); if (run->mmio.is_write) ret = kvm_io_bus_write(vcpu, KVM_MMIO_BUS, run->mmio.phys_addr, run->mmio.len, run->mmio.data); else ret = kvm_io_bus_read(vcpu, KVM_MMIO_BUS, run->mmio.phys_addr, run->mmio.len, run->mmio.data); if (!ret) { /* We handled the access successfully in the kernel. */ kvm_handle_mmio_return(vcpu, run); return 1; } run->exit_reason = KVM_EXIT_MMIO; return 0; }