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