1 // © 2021 Qualcomm Innovation Center, Inc. All rights reserved.
2 //
3 // SPDX-License-Identifier: BSD-3-Clause
4 
5 #include <hyptypes.h>
6 
7 #include <hypcall_def.h>
8 #include <hyprights.h>
9 
10 #include <atomic.h>
11 #include <compiler.h>
12 #include <cspace.h>
13 #include <cspace_lookup.h>
14 #include <object.h>
15 #include <partition.h>
16 #include <spinlock.h>
17 
18 #include <events/vic.h>
19 
20 #include "vic_base.h"
21 
22 error_t
hypercall_hwirq_bind_virq(cap_id_t hwirq_cap,cap_id_t vic_cap,virq_t virq)23 hypercall_hwirq_bind_virq(cap_id_t hwirq_cap, cap_id_t vic_cap, virq_t virq)
24 {
25 	error_t	  err;
26 	cspace_t *cspace = cspace_get_self();
27 
28 	hwirq_ptr_result_t hwirq_r = cspace_lookup_hwirq(
29 		cspace, hwirq_cap, CAP_RIGHTS_HWIRQ_BIND_VIC);
30 	if (compiler_unexpected(hwirq_r.e) != OK) {
31 		err = hwirq_r.e;
32 		goto out;
33 	}
34 
35 	vic_ptr_result_t vic_r =
36 		cspace_lookup_vic(cspace, vic_cap, CAP_RIGHTS_VIC_BIND_SOURCE);
37 	if (compiler_unexpected(vic_r.e) != OK) {
38 		err = vic_r.e;
39 		goto out_release_hwirq;
40 	}
41 
42 	err = trigger_vic_bind_hwirq_event(hwirq_r.r->action, vic_r.r,
43 					   hwirq_r.r, virq);
44 
45 	object_put_vic(vic_r.r);
46 out_release_hwirq:
47 	object_put_hwirq(hwirq_r.r);
48 out:
49 	return err;
50 }
51 
52 error_t
hypercall_hwirq_unbind_virq(cap_id_t hwirq_cap)53 hypercall_hwirq_unbind_virq(cap_id_t hwirq_cap)
54 {
55 	error_t	  err;
56 	cspace_t *cspace = cspace_get_self();
57 
58 	hwirq_ptr_result_t hwirq_r = cspace_lookup_hwirq(
59 		cspace, hwirq_cap, CAP_RIGHTS_HWIRQ_BIND_VIC);
60 	if (compiler_unexpected(hwirq_r.e) != OK) {
61 		err = hwirq_r.e;
62 		goto out;
63 	}
64 
65 	err = trigger_vic_unbind_hwirq_event(hwirq_r.r->action, hwirq_r.r);
66 
67 	object_put_hwirq(hwirq_r.r);
68 out:
69 	return err;
70 }
71 
72 error_t
hypercall_vic_configure(cap_id_t vic_cap,count_t max_vcpus,count_t max_virqs,vic_option_flags_t vic_options,count_t max_msis)73 hypercall_vic_configure(cap_id_t vic_cap, count_t max_vcpus, count_t max_virqs,
74 			vic_option_flags_t vic_options, count_t max_msis)
75 {
76 	error_t	      err;
77 	cspace_t     *cspace = cspace_get_self();
78 	object_type_t type;
79 
80 	object_ptr_result_t o = cspace_lookup_object_any(
81 		cspace, vic_cap, CAP_RIGHTS_GENERIC_OBJECT_ACTIVATE, &type);
82 	if (compiler_unexpected(o.e != OK)) {
83 		err = o.e;
84 		goto out_released;
85 	}
86 	if (type != OBJECT_TYPE_VIC) {
87 		err = ERROR_CSPACE_WRONG_OBJECT_TYPE;
88 		goto out_unlocked;
89 	}
90 	vic_t *vic = o.r.vic;
91 
92 	if (vic_option_flags_get_res0_0(&vic_options) != 0U) {
93 		err = ERROR_ARGUMENT_INVALID;
94 		goto out_unlocked;
95 	}
96 
97 	// For backwards compatibility, treat the max_msis argument as 0 if the
98 	// caller has not set the flag indicating that it is valid.
99 	if (!vic_option_flags_get_max_msis_valid(&vic_options)) {
100 		max_msis = 0U;
101 	}
102 
103 	spinlock_acquire(&vic->header.lock);
104 	if (atomic_load_relaxed(&vic->header.state) == OBJECT_STATE_INIT) {
105 		err = vic_configure(vic, max_vcpus, max_virqs, max_msis,
106 				    !vic_option_flags_get_disable_default_addr(
107 					    &vic_options));
108 	} else {
109 		err = ERROR_OBJECT_STATE;
110 	}
111 	spinlock_release(&vic->header.lock);
112 
113 out_unlocked:
114 	object_put(type, o.r);
115 out_released:
116 
117 	return err;
118 }
119 
120 error_t
hypercall_vic_attach_vcpu(cap_id_t vic_cap,cap_id_t vcpu_cap,index_t index)121 hypercall_vic_attach_vcpu(cap_id_t vic_cap, cap_id_t vcpu_cap, index_t index)
122 {
123 	error_t	  err;
124 	cspace_t *cspace = cspace_get_self();
125 
126 	vic_ptr_result_t vic_r =
127 		cspace_lookup_vic(cspace, vic_cap, CAP_RIGHTS_VIC_ATTACH_VCPU);
128 	if (compiler_unexpected(vic_r.e) != OK) {
129 		err = vic_r.e;
130 		goto out;
131 	}
132 
133 	object_type_t	    type;
134 	object_ptr_result_t o = cspace_lookup_object_any(
135 		cspace, vcpu_cap, CAP_RIGHTS_GENERIC_OBJECT_ACTIVATE, &type);
136 	if (compiler_unexpected(o.e != OK)) {
137 		err = o.e;
138 		goto out_release_vic;
139 	}
140 	if (type != OBJECT_TYPE_THREAD) {
141 		err = ERROR_CSPACE_WRONG_OBJECT_TYPE;
142 		goto out_release_vcpu;
143 	}
144 	thread_t *thread = o.r.thread;
145 
146 	spinlock_acquire(&thread->header.lock);
147 	if (atomic_load_relaxed(&thread->header.state) == OBJECT_STATE_INIT) {
148 		err = vic_attach_vcpu(vic_r.r, thread, index);
149 	} else {
150 		err = ERROR_OBJECT_STATE;
151 	}
152 	spinlock_release(&thread->header.lock);
153 
154 out_release_vcpu:
155 	object_put(type, o.r);
156 out_release_vic:
157 	object_put_vic(vic_r.r);
158 out:
159 	return err;
160 }
161 
162 error_t
hypercall_vic_bind_msi_source(cap_id_t vic_cap,cap_id_t msi_source_cap)163 hypercall_vic_bind_msi_source(cap_id_t vic_cap, cap_id_t msi_source_cap)
164 {
165 	error_t	  err;
166 	cspace_t *cspace = cspace_get_self();
167 
168 	vic_ptr_result_t vic_r =
169 		cspace_lookup_vic(cspace, vic_cap, CAP_RIGHTS_VIC_BIND_SOURCE);
170 	if (compiler_unexpected(vic_r.e) != OK) {
171 		err = vic_r.e;
172 		goto out;
173 	}
174 
175 	err = trigger_vic_bind_msi_source_event(vic_r.r, msi_source_cap);
176 
177 	object_put_vic(vic_r.r);
178 out:
179 	return err;
180 }
181