• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2023 MediaTek Inc.
4  */
5 
6 #include <linux/device.h>
7 #include <linux/soc/mediatek/gzvm_drv.h>
8 #include <linux/sched.h>
9 #include <linux/rcuwait.h>
10 
11 /**
12  * gzvm_handle_guest_exception() - Handle guest exception
13  * @vcpu: Pointer to struct gzvm_vcpu_run in userspace
14  * Return:
15  * * true - This exception has been processed, no need to back to VMM.
16  * * false - This exception has not been processed, require userspace.
17  */
gzvm_handle_guest_exception(struct gzvm_vcpu * vcpu)18 bool gzvm_handle_guest_exception(struct gzvm_vcpu *vcpu)
19 {
20 	int ret;
21 
22 	for (int i = 0; i < ARRAY_SIZE(vcpu->run->exception.reserved); i++) {
23 		if (vcpu->run->exception.reserved[i])
24 			return false;
25 	}
26 
27 	switch (vcpu->run->exception.exception) {
28 	case GZVM_EXCEPTION_PAGE_FAULT:
29 		ret = gzvm_handle_page_fault(vcpu);
30 		break;
31 	case GZVM_EXCEPTION_UNKNOWN:
32 		fallthrough;
33 	default:
34 		ret = -EFAULT;
35 	}
36 
37 	if (!ret)
38 		return true;
39 	else
40 		return false;
41 }
42 
43 /**
44  * gzvm_handle_guest_hvc() - Handle guest hvc
45  * @vcpu: Pointer to struct gzvm_vcpu struct
46  * Return:
47  * * true - This hvc has been processed, no need to back to VMM.
48  * * false - This hvc has not been processed, require userspace.
49  */
gzvm_handle_guest_hvc(struct gzvm_vcpu * vcpu)50 bool gzvm_handle_guest_hvc(struct gzvm_vcpu *vcpu)
51 {
52 	unsigned long ipa;
53 	int ret;
54 
55 	switch (vcpu->run->hypercall.args[0]) {
56 	case GZVM_HVC_MEM_RELINQUISH:
57 		ipa = vcpu->run->hypercall.args[1];
58 		ret = gzvm_handle_relinquish(vcpu, ipa);
59 		return (ret == 0) ? true : false;
60 	default:
61 		return gzvm_arch_handle_guest_hvc(vcpu);
62 	}
63 }
64 
vcpu_block_wait(struct gzvm_vcpu * vcpu)65 static void vcpu_block_wait(struct gzvm_vcpu *vcpu)
66 {
67 	struct rcuwait *wait = &vcpu->wait;
68 
69 	prepare_to_rcuwait(wait);
70 
71 	while (true) {
72 		set_current_state(TASK_INTERRUPTIBLE);
73 		if (vcpu->idle_events.virtio_irq) {
74 			vcpu->idle_events.virtio_irq = 0;
75 			break;
76 		}
77 		if (vcpu->idle_events.vtimer_irq) {
78 			vcpu->idle_events.vtimer_irq = 0;
79 			break;
80 		}
81 		if (signal_pending(current))
82 			break;
83 		schedule();
84 	}
85 	finish_rcuwait(wait);
86 }
87 
88 /**
89  * gzvm_handle_guest_idle() - Handle guest vm entering idle
90  * @vcpu: Pointer to struct gzvm_vcpu struct
91  * Return:
92  */
gzvm_handle_guest_idle(struct gzvm_vcpu * vcpu)93 int gzvm_handle_guest_idle(struct gzvm_vcpu *vcpu)
94 {
95 	int ret = 0;
96 	u64 ns = 0;
97 
98 	ns = gzvm_vcpu_arch_get_timer_delay_ns(vcpu);
99 
100 	if (ns) {
101 		gzvm_vtimer_set(vcpu, ns);
102 		vcpu_block_wait(vcpu);
103 		gzvm_vtimer_release(vcpu);
104 	}
105 
106 	return ret;
107 }
108 
gzvm_handle_guest_ipi(struct gzvm_vcpu * vcpu)109 void gzvm_handle_guest_ipi(struct gzvm_vcpu *vcpu)
110 {
111 	gzvm_vcpu_wakeup_all(vcpu->gzvm);
112 }
113