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(¬if_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(¬if_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(¬if_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(¬if_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(¬if_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(¬if_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(¬if_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(¬if_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(¬if_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