/* * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #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; }