-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
core: notif_default: support ns-virtualization
Add support for CFG_NS_VIRTUALIZATION=y in the default notification implementation used with the SMC ABI. virt_add_guest_spec_data() is used to add struct notif_vm_bitmap for bookkeeping per guest, similarly to the implementation for the FF-A ABI. This takes care of and removes the assert for "!guest" in notif_send_async(). Signed-off-by: Jens Wiklander <[email protected]> Signed-off-by: Yuvraj Sakshith <[email protected]> Tested-by: Yuvraj Sakshith <[email protected]>
- Loading branch information
1 parent
98761c2
commit dd127cb
Showing
1 changed file
with
101 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,97 +1,168 @@ | ||
// SPDX-License-Identifier: BSD-2-Clause | ||
/* | ||
* Copyright (c) 2021-2023, Linaro Limited | ||
* Copyright (c) 2021-2024, Linaro Limited | ||
*/ | ||
|
||
#include <assert.h> | ||
#include <bitstring.h> | ||
#include <config.h> | ||
#include <initcall.h> | ||
#include <kernel/interrupt.h> | ||
#include <kernel/notif.h> | ||
#include <kernel/spinlock.h> | ||
#include <kernel/virtualization.h> | ||
#include <trace.h> | ||
#include <types_ext.h> | ||
|
||
static bitstr_t bit_decl(notif_values, NOTIF_ASYNC_VALUE_MAX + 1); | ||
static bitstr_t bit_decl(notif_alloc_values, NOTIF_ASYNC_VALUE_MAX + 1); | ||
struct notif_vm_bitmap { | ||
bool alloc_values_inited; | ||
bitstr_t bit_decl(values, NOTIF_ASYNC_VALUE_MAX + 1); | ||
bitstr_t bit_decl(alloc_values, NOTIF_ASYNC_VALUE_MAX + 1); | ||
}; | ||
|
||
static unsigned int notif_default_lock = SPINLOCK_UNLOCK; | ||
/* Id used to look up the guest specific struct notif_vm_bitmap */ | ||
static unsigned int notif_vm_bitmap_id __nex_bss; | ||
/* Notification state when ns-virtualization isn't enabled */ | ||
static struct notif_vm_bitmap default_notif_vm_bitmap; | ||
|
||
static struct notif_vm_bitmap *get_notif_vm_bitmap(struct guest_partition *prtn) | ||
{ | ||
if (IS_ENABLED(CFG_NS_VIRTUALIZATION)) { | ||
if (!prtn) | ||
return NULL; | ||
return virt_get_guest_spec_data(prtn, notif_vm_bitmap_id); | ||
} | ||
return &default_notif_vm_bitmap; | ||
} | ||
|
||
TEE_Result notif_alloc_async_value(uint32_t *val) | ||
{ | ||
static bool alloc_values_inited; | ||
struct guest_partition *prtn = NULL; | ||
struct notif_vm_bitmap *nvb = NULL; | ||
TEE_Result res = TEE_SUCCESS; | ||
uint32_t old_itr_status = 0; | ||
int bit = 0; | ||
|
||
assert(interrupt_can_raise_pi(interrupt_get_main_chip())); | ||
|
||
prtn = virt_get_current_guest(); | ||
nvb = get_notif_vm_bitmap(prtn); | ||
if (!nvb) { | ||
res = TEE_ERROR_BAD_PARAMETERS; | ||
goto out; | ||
} | ||
|
||
old_itr_status = cpu_spin_lock_xsave(¬if_default_lock); | ||
|
||
if (!alloc_values_inited) { | ||
bit_set(notif_alloc_values, NOTIF_VALUE_DO_BOTTOM_HALF); | ||
alloc_values_inited = true; | ||
if (!nvb->alloc_values_inited) { | ||
bit_set(nvb->alloc_values, NOTIF_VALUE_DO_BOTTOM_HALF); | ||
nvb->alloc_values_inited = true; | ||
} | ||
|
||
bit_ffc(notif_alloc_values, (int)NOTIF_ASYNC_VALUE_MAX + 1, &bit); | ||
if (bit >= 0) { | ||
*val = bit; | ||
bit_set(notif_alloc_values, bit); | ||
bit_ffc(nvb->alloc_values, (int)NOTIF_ASYNC_VALUE_MAX + 1, &bit); | ||
if (bit < 0) { | ||
res = TEE_ERROR_OUT_OF_MEMORY; | ||
goto out_unlock; | ||
} | ||
*val = bit; | ||
bit_set(nvb->alloc_values, bit); | ||
|
||
out_unlock: | ||
cpu_spin_unlock_xrestore(¬if_default_lock, old_itr_status); | ||
out: | ||
virt_put_guest(prtn); | ||
|
||
if (bit < 0) | ||
return TEE_ERROR_OUT_OF_MEMORY; | ||
|
||
return TEE_SUCCESS; | ||
return res; | ||
} | ||
|
||
void notif_free_async_value(uint32_t val) | ||
{ | ||
struct guest_partition *prtn = NULL; | ||
struct notif_vm_bitmap *nvb = NULL; | ||
uint32_t old_itr_status = 0; | ||
|
||
prtn = virt_get_current_guest(); | ||
nvb = get_notif_vm_bitmap(prtn); | ||
if (!nvb) | ||
goto out; | ||
|
||
old_itr_status = cpu_spin_lock_xsave(¬if_default_lock); | ||
|
||
assert(val < NOTIF_ASYNC_VALUE_MAX); | ||
assert(bit_test(notif_alloc_values, val)); | ||
bit_clear(notif_alloc_values, val); | ||
assert(bit_test(nvb->alloc_values, val)); | ||
bit_clear(nvb->alloc_values, val); | ||
|
||
cpu_spin_unlock_xrestore(¬if_default_lock, old_itr_status); | ||
out: | ||
virt_put_guest(prtn); | ||
} | ||
|
||
uint32_t notif_get_value(bool *value_valid, bool *value_pending) | ||
{ | ||
struct guest_partition *prtn = NULL; | ||
struct notif_vm_bitmap *nvb = NULL; | ||
uint32_t old_itr_status = 0; | ||
uint32_t res = 0; | ||
int bit = 0; | ||
int bit = -1; | ||
|
||
prtn = virt_get_current_guest(); | ||
nvb = get_notif_vm_bitmap(prtn); | ||
if (!nvb) { | ||
*value_valid = false; | ||
goto out; | ||
} | ||
|
||
old_itr_status = cpu_spin_lock_xsave(¬if_default_lock); | ||
|
||
bit_ffs(notif_values, (int)NOTIF_ASYNC_VALUE_MAX + 1, &bit); | ||
bit_ffs(nvb->values, (int)NOTIF_ASYNC_VALUE_MAX + 1, &bit); | ||
*value_valid = (bit >= 0); | ||
if (!*value_valid) { | ||
*value_pending = false; | ||
goto out; | ||
} | ||
if (!*value_valid) | ||
goto out_unlock; | ||
|
||
res = bit; | ||
bit_clear(notif_values, res); | ||
bit_ffs(notif_values, (int)NOTIF_ASYNC_VALUE_MAX + 1, &bit); | ||
*value_pending = (bit >= 0); | ||
out: | ||
bit_clear(nvb->values, res); | ||
bit_ffs(nvb->values, (int)NOTIF_ASYNC_VALUE_MAX + 1, &bit); | ||
|
||
out_unlock: | ||
cpu_spin_unlock_xrestore(¬if_default_lock, old_itr_status); | ||
out: | ||
virt_put_guest(prtn); | ||
*value_pending = (bit >= 0); | ||
|
||
return res; | ||
} | ||
|
||
void notif_send_async(uint32_t value, uint16_t guest_id __maybe_unused) | ||
void notif_send_async(uint32_t value, uint16_t guest_id) | ||
{ | ||
struct guest_partition *prtn = NULL; | ||
struct notif_vm_bitmap *nvb = NULL; | ||
uint32_t old_itr_status = 0; | ||
struct itr_chip *itr_chip = interrupt_get_main_chip(); | ||
|
||
assert(value <= NOTIF_ASYNC_VALUE_MAX && !guest_id); | ||
assert(value <= NOTIF_ASYNC_VALUE_MAX); | ||
|
||
prtn = virt_get_guest(guest_id); | ||
nvb = get_notif_vm_bitmap(prtn); | ||
if (!nvb) | ||
goto out; | ||
|
||
old_itr_status = cpu_spin_lock_xsave(¬if_default_lock); | ||
|
||
bit_set(notif_values, value); | ||
bit_set(nvb->values, value); | ||
interrupt_raise_pi(itr_chip, CFG_CORE_ASYNC_NOTIF_GIC_INTID); | ||
|
||
cpu_spin_unlock_xrestore(¬if_default_lock, old_itr_status); | ||
out: | ||
virt_put_guest(prtn); | ||
} | ||
|
||
static TEE_Result notif_init(void) | ||
{ | ||
if (IS_ENABLED(CFG_NS_VIRTUALIZATION) && | ||
virt_add_guest_spec_data(¬if_vm_bitmap_id, | ||
sizeof(struct notif_vm_bitmap), NULL)) | ||
panic("virt_add_guest_spec_data"); | ||
return TEE_SUCCESS; | ||
} | ||
nex_service_init(notif_init); |