Skip to content

Commit

Permalink
core: notif_default: support ns-virtualization
Browse files Browse the repository at this point in the history
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
yuvraj1803 committed Dec 20, 2024
1 parent 98761c2 commit dd127cb
Showing 1 changed file with 101 additions and 30 deletions.
131 changes: 101 additions & 30 deletions core/kernel/notif_default.c
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(&notif_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(&notif_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(&notif_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(&notif_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(&notif_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(&notif_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(&notif_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(&notif_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(&notif_vm_bitmap_id,
sizeof(struct notif_vm_bitmap), NULL))
panic("virt_add_guest_spec_data");
return TEE_SUCCESS;
}
nex_service_init(notif_init);

0 comments on commit dd127cb

Please sign in to comment.