blob: 0879c8367bd40ab0dbbc14d654880e70c5c7c3e4 [file] [log] [blame]
/*
* Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <common/debug.h>
#include <errno.h>
#include <inttypes.h>
#include <platform_def.h>
#include <stddef.h>
#include <trusty/arm_ffa.h>
#include <trusty/ffa_helpers.h>
#include "qemu_private.h"
#define NS_DRAM0_BITMAP_SIZE DIV_ROUND_UP_2EVAL(NS_DRAM0_SIZE, PAGE_SIZE * 8)
static uint8_t trusty_shmem_shared[NS_DRAM0_BITMAP_SIZE];
static uint8_t trusty_shmem_secure[NS_DRAM0_BITMAP_SIZE];
static bool read_bit(uint8_t *bit_mask, size_t bit_num)
{
size_t i = bit_num / 8;
size_t m = 1U << (bit_num % 8);
return !!(bit_mask[i] & m);
}
static void write_bit(uint8_t *bit_mask, size_t bit_num, bool val)
{
size_t i = bit_num / 8;
size_t m = 1U << (bit_num % 8);
if (val) {
bit_mask[i] |= m;
} else {
bit_mask[i] &= ~m;
}
}
static int mem_set_shared(bool shared, bool secure, unsigned long long base_pa,
size_t size)
{
unsigned long long page;
size_t i;
assert((size % PAGE_SIZE) == 0);
if (base_pa < NS_DRAM0_BASE ||
(base_pa - NS_DRAM0_BASE) + size > NS_DRAM0_SIZE) {
NOTICE("%s(%d, %d, 0x%llx, 0x%zx) invalid address range\n",
__func__, shared, secure, base_pa, size);
return -EINVAL;
}
for (page = (base_pa - NS_DRAM0_BASE) / PAGE_SIZE, i = 0;
i < size / PAGE_SIZE; page++, i++) {
bool was_shared = read_bit(trusty_shmem_shared, page);
bool was_secure = read_bit(trusty_shmem_secure, page);
assert(!was_secure || was_shared);
if (was_shared == shared) {
/* already shared or reclaimed */
NOTICE("%s(%d, %d, 0x%llx, 0x%zx) already set\n",
__func__, shared, secure, base_pa, size);
goto err;
}
assert(was_secure == (secure && !shared));
write_bit(trusty_shmem_shared, page, shared);
if (secure) {
/*
* For emulator testing purposes the memory
* is marked as secure, and communicated to
* Trusty as such, even though it is not.
*/
write_bit(trusty_shmem_secure, page, shared);
}
}
return 0;
err:
while (i > 0) {
i--;
page--;
write_bit(trusty_shmem_shared, page, !shared);
if (secure) {
write_bit(trusty_shmem_secure, page, !shared);
}
}
return -EBUSY;
}
int qemu_ffa_comp_set_shared(void *compv, bool shared, bool secure)
{
struct ffa_comp_mrd *comp = compv;
size_t count = comp->address_range_count;
struct ffa_cons_mrd *cons_mrd;
int ret = 0;
size_t i;
for (i = 0, cons_mrd = comp->address_range_array; i < count;
i++, cons_mrd++) {
ret = mem_set_shared(shared, secure, cons_mrd->address,
cons_mrd->page_count * PAGE_SIZE);
if (ret) {
goto err;
}
}
return 0;
err:
NOTICE("%s: %zu/%zu: failed to set shared %d secure %d for %"
PRIx64 " (%x)\n",
__func__, i, count, shared, secure, cons_mrd->address,
cons_mrd->page_count);
while (i > 0) {
i--;
cons_mrd--;
if (mem_set_shared(!shared, secure, cons_mrd->address,
cons_mrd->page_count * PAGE_SIZE)) {
/* Failed to revert change */
panic();
}
}
return ret;
}
int plat_mem_set_shared(struct ffa_mtd *mtd, bool shared)
{
struct ffa_comp_mrd *comp = trusty_ffa_mtd_get_comp_mrd(mtd);
bool secure = trusty_ffa_should_be_secure(mtd);
int ret;
ret = qemu_ffa_comp_set_shared(comp, shared, secure);
if (!ret && secure) {
mtd->memory_region_attributes &= ~FFA_MEM_ATTR_NONSECURE;
}
return ret;
}