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