// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2023 MediaTek Inc. */ #include #include #include #include /** * gzvm_handle_guest_exception() - Handle guest exception * @vcpu: Pointer to struct gzvm_vcpu_run in userspace * Return: * * true - This exception has been processed, no need to back to VMM. * * false - This exception has not been processed, require userspace. */ bool gzvm_handle_guest_exception(struct gzvm_vcpu *vcpu) { int ret; for (int i = 0; i < ARRAY_SIZE(vcpu->run->exception.reserved); i++) { if (vcpu->run->exception.reserved[i]) return false; } switch (vcpu->run->exception.exception) { case GZVM_EXCEPTION_PAGE_FAULT: ret = gzvm_handle_page_fault(vcpu); break; case GZVM_EXCEPTION_UNKNOWN: fallthrough; default: ret = -EFAULT; } if (!ret) return true; else return false; } /** * gzvm_handle_guest_hvc() - Handle guest hvc * @vcpu: Pointer to struct gzvm_vcpu struct * Return: * * true - This hvc has been processed, no need to back to VMM. * * false - This hvc has not been processed, require userspace. */ bool gzvm_handle_guest_hvc(struct gzvm_vcpu *vcpu) { unsigned long ipa; int ret; switch (vcpu->run->hypercall.args[0]) { case GZVM_HVC_MEM_RELINQUISH: ipa = vcpu->run->hypercall.args[1]; ret = gzvm_handle_relinquish(vcpu, ipa); return (ret == 0) ? true : false; default: return gzvm_arch_handle_guest_hvc(vcpu); } } static void vcpu_block_wait(struct gzvm_vcpu *vcpu) { struct rcuwait *wait = &vcpu->wait; prepare_to_rcuwait(wait); while (true) { set_current_state(TASK_INTERRUPTIBLE); if (vcpu->idle_events.virtio_irq) { vcpu->idle_events.virtio_irq = 0; break; } if (vcpu->idle_events.vtimer_irq) { vcpu->idle_events.vtimer_irq = 0; break; } if (signal_pending(current)) break; schedule(); } finish_rcuwait(wait); } /** * gzvm_handle_guest_idle() - Handle guest vm entering idle * @vcpu: Pointer to struct gzvm_vcpu struct * Return: */ int gzvm_handle_guest_idle(struct gzvm_vcpu *vcpu) { int ret = 0; u64 ns = 0; ns = gzvm_vcpu_arch_get_timer_delay_ns(vcpu); if (ns) { gzvm_vtimer_set(vcpu, ns); vcpu_block_wait(vcpu); gzvm_vtimer_release(vcpu); } return ret; } void gzvm_handle_guest_ipi(struct gzvm_vcpu *vcpu) { gzvm_vcpu_wakeup_all(vcpu->gzvm); }