xref: /optee_os/core/kernel/notif_default.c (revision 45fecab081173ef58b1cb14b6ddf6892b0b9d3f6)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2021-2024, Linaro Limited
4  */
5 
6 #include <assert.h>
7 #include <bitstring.h>
8 #include <config.h>
9 #include <initcall.h>
10 #include <kernel/interrupt.h>
11 #include <kernel/notif.h>
12 #include <kernel/spinlock.h>
13 #include <kernel/virtualization.h>
14 #include <trace.h>
15 #include <types_ext.h>
16 
17 struct notif_vm_bitmap {
18 	bool alloc_values_inited;
19 	bitstr_t bit_decl(values, NOTIF_ASYNC_VALUE_MAX + 1);
20 	bitstr_t bit_decl(alloc_values, NOTIF_ASYNC_VALUE_MAX + 1);
21 };
22 
23 static unsigned int notif_default_lock = SPINLOCK_UNLOCK;
24 /* Id used to look up the guest specific struct notif_vm_bitmap */
25 static unsigned int notif_vm_bitmap_id __nex_bss;
26 /* Notification state when ns-virtualization isn't enabled */
27 static struct notif_vm_bitmap default_notif_vm_bitmap;
28 
29 static struct notif_vm_bitmap *get_notif_vm_bitmap(struct guest_partition *prtn)
30 {
31 	if (IS_ENABLED(CFG_NS_VIRTUALIZATION)) {
32 		if (!prtn)
33 			return NULL;
34 		return virt_get_guest_spec_data(prtn, notif_vm_bitmap_id);
35 	}
36 	return &default_notif_vm_bitmap;
37 }
38 
39 TEE_Result notif_alloc_async_value(uint32_t *val)
40 {
41 	struct guest_partition *prtn = NULL;
42 	struct notif_vm_bitmap *nvb = NULL;
43 	TEE_Result res = TEE_SUCCESS;
44 	uint32_t old_itr_status = 0;
45 	int bit = 0;
46 
47 	assert(interrupt_can_raise_pi(interrupt_get_main_chip()));
48 
49 	prtn = virt_get_current_guest();
50 	nvb = get_notif_vm_bitmap(prtn);
51 	if (!nvb) {
52 		res = TEE_ERROR_BAD_PARAMETERS;
53 		goto out;
54 	}
55 
56 	old_itr_status = cpu_spin_lock_xsave(&notif_default_lock);
57 
58 	if (!nvb->alloc_values_inited) {
59 		bit_set(nvb->alloc_values, NOTIF_VALUE_DO_BOTTOM_HALF);
60 		nvb->alloc_values_inited = true;
61 	}
62 
63 	bit_ffc(nvb->alloc_values, (int)NOTIF_ASYNC_VALUE_MAX + 1, &bit);
64 	if (bit < 0) {
65 		res = TEE_ERROR_OUT_OF_MEMORY;
66 		goto out_unlock;
67 	}
68 	*val = bit;
69 	bit_set(nvb->alloc_values, bit);
70 
71 out_unlock:
72 	cpu_spin_unlock_xrestore(&notif_default_lock, old_itr_status);
73 out:
74 	virt_put_guest(prtn);
75 
76 	return res;
77 }
78 
79 void notif_free_async_value(uint32_t val)
80 {
81 	struct guest_partition *prtn = NULL;
82 	struct notif_vm_bitmap *nvb = NULL;
83 	uint32_t old_itr_status = 0;
84 
85 	prtn = virt_get_current_guest();
86 	nvb = get_notif_vm_bitmap(prtn);
87 	if (!nvb)
88 		goto out;
89 
90 	old_itr_status = cpu_spin_lock_xsave(&notif_default_lock);
91 
92 	assert(val < NOTIF_ASYNC_VALUE_MAX);
93 	assert(bit_test(nvb->alloc_values, val));
94 	bit_clear(nvb->alloc_values, val);
95 
96 	cpu_spin_unlock_xrestore(&notif_default_lock, old_itr_status);
97 out:
98 	virt_put_guest(prtn);
99 }
100 
101 uint32_t notif_get_value(bool *value_valid, bool *value_pending)
102 {
103 	struct guest_partition *prtn = NULL;
104 	struct notif_vm_bitmap *nvb = NULL;
105 	uint32_t old_itr_status = 0;
106 	uint32_t res = 0;
107 	int bit = -1;
108 
109 	prtn = virt_get_current_guest();
110 	nvb = get_notif_vm_bitmap(prtn);
111 	if (!nvb) {
112 		*value_valid = false;
113 		goto out;
114 	}
115 
116 	old_itr_status = cpu_spin_lock_xsave(&notif_default_lock);
117 
118 	bit_ffs(nvb->values, (int)NOTIF_ASYNC_VALUE_MAX + 1, &bit);
119 	*value_valid = (bit >= 0);
120 	if (!*value_valid)
121 		goto out_unlock;
122 
123 	res = bit;
124 	bit_clear(nvb->values, res);
125 	bit_ffs(nvb->values, (int)NOTIF_ASYNC_VALUE_MAX + 1, &bit);
126 
127 out_unlock:
128 	cpu_spin_unlock_xrestore(&notif_default_lock, old_itr_status);
129 out:
130 	virt_put_guest(prtn);
131 	*value_pending = (bit >= 0);
132 
133 	return res;
134 }
135 
136 void notif_send_async(uint32_t value, uint16_t guest_id)
137 {
138 	struct guest_partition *prtn = NULL;
139 	struct notif_vm_bitmap *nvb = NULL;
140 	uint32_t old_itr_status = 0;
141 	struct itr_chip *itr_chip = interrupt_get_main_chip();
142 
143 	assert(value <= NOTIF_ASYNC_VALUE_MAX);
144 
145 	prtn = virt_get_guest(guest_id);
146 	nvb = get_notif_vm_bitmap(prtn);
147 	if (!nvb)
148 		goto out;
149 
150 	old_itr_status = cpu_spin_lock_xsave(&notif_default_lock);
151 
152 	bit_set(nvb->values, value);
153 	interrupt_raise_pi(itr_chip, CFG_CORE_ASYNC_NOTIF_GIC_INTID);
154 
155 	cpu_spin_unlock_xrestore(&notif_default_lock, old_itr_status);
156 out:
157 	virt_put_guest(prtn);
158 }
159 
160 static TEE_Result notif_init(void)
161 {
162 	if (IS_ENABLED(CFG_NS_VIRTUALIZATION) &&
163 	    virt_add_guest_spec_data(&notif_vm_bitmap_id,
164 				     sizeof(struct notif_vm_bitmap), NULL))
165 		panic("virt_add_guest_spec_data");
166 	return TEE_SUCCESS;
167 }
168 nex_service_init(notif_init);
169