1 /*
2 * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <assert.h>
8 #include <common/debug.h>
9 #include <errno.h>
10 #include <inttypes.h>
11 #include <platform_def.h>
12 #include <stddef.h>
13 #include <trusty/arm_ffa.h>
14 #include <trusty/ffa_helpers.h>
15
16 #include "qemu_private.h"
17
18 #define NS_DRAM0_BITMAP_SIZE DIV_ROUND_UP_2EVAL(NS_DRAM0_SIZE, PAGE_SIZE * 8)
19 static uint8_t trusty_shmem_shared[NS_DRAM0_BITMAP_SIZE];
20 static uint8_t trusty_shmem_secure[NS_DRAM0_BITMAP_SIZE];
21
read_bit(uint8_t * bit_mask,size_t bit_num)22 static bool read_bit(uint8_t *bit_mask, size_t bit_num)
23 {
24 size_t i = bit_num / 8;
25 size_t m = 1U << (bit_num % 8);
26 return !!(bit_mask[i] & m);
27 }
28
write_bit(uint8_t * bit_mask,size_t bit_num,bool val)29 static void write_bit(uint8_t *bit_mask, size_t bit_num, bool val)
30 {
31 size_t i = bit_num / 8;
32 size_t m = 1U << (bit_num % 8);
33 if (val) {
34 bit_mask[i] |= m;
35 } else {
36 bit_mask[i] &= ~m;
37 }
38 }
39
mem_set_shared(bool shared,bool secure,unsigned long long base_pa,size_t size)40 static int mem_set_shared(bool shared, bool secure, unsigned long long base_pa,
41 size_t size)
42 {
43 unsigned long long page;
44 size_t i;
45
46 assert((size % PAGE_SIZE) == 0);
47
48 if (base_pa < NS_DRAM0_BASE ||
49 (base_pa - NS_DRAM0_BASE) + size > NS_DRAM0_SIZE) {
50 NOTICE("%s(%d, %d, 0x%llx, 0x%zx) invalid address range\n",
51 __func__, shared, secure, base_pa, size);
52 return -EINVAL;
53 }
54 for (page = (base_pa - NS_DRAM0_BASE) / PAGE_SIZE, i = 0;
55 i < size / PAGE_SIZE; page++, i++) {
56 bool was_shared = read_bit(trusty_shmem_shared, page);
57 bool was_secure = read_bit(trusty_shmem_secure, page);
58 assert(!was_secure || was_shared);
59 if (was_shared == shared) {
60 /* already shared or reclaimed */
61 NOTICE("%s(%d, %d, 0x%llx, 0x%zx) already set\n",
62 __func__, shared, secure, base_pa, size);
63 goto err;
64 }
65 assert(was_secure == (secure && !shared));
66 write_bit(trusty_shmem_shared, page, shared);
67 if (secure) {
68 /*
69 * For emulator testing purposes the memory
70 * is marked as secure, and communicated to
71 * Trusty as such, even though it is not.
72 */
73 write_bit(trusty_shmem_secure, page, shared);
74 }
75 }
76 return 0;
77
78 err:
79 while (i > 0) {
80 i--;
81 page--;
82 write_bit(trusty_shmem_shared, page, !shared);
83 if (secure) {
84 write_bit(trusty_shmem_secure, page, !shared);
85 }
86 }
87 return -EBUSY;
88 }
89
qemu_ffa_comp_set_shared(void * compv,bool shared,bool secure)90 int qemu_ffa_comp_set_shared(void *compv, bool shared, bool secure)
91 {
92 struct ffa_comp_mrd *comp = compv;
93 size_t count = comp->address_range_count;
94 struct ffa_cons_mrd *cons_mrd;
95 int ret = 0;
96 size_t i;
97
98 for (i = 0, cons_mrd = comp->address_range_array; i < count;
99 i++, cons_mrd++) {
100 ret = mem_set_shared(shared, secure, cons_mrd->address,
101 cons_mrd->page_count * PAGE_SIZE);
102 if (ret) {
103 goto err;
104 }
105 }
106
107 return 0;
108
109 err:
110 NOTICE("%s: %zu/%zu: failed to set shared %d secure %d for %"
111 PRIx64 " (%x)\n",
112 __func__, i, count, shared, secure, cons_mrd->address,
113 cons_mrd->page_count);
114 while (i > 0) {
115 i--;
116 cons_mrd--;
117 if (mem_set_shared(!shared, secure, cons_mrd->address,
118 cons_mrd->page_count * PAGE_SIZE)) {
119 /* Failed to revert change */
120 panic();
121 }
122 }
123 return ret;
124 }
125
plat_mem_set_shared(struct ffa_mtd * mtd,bool shared)126 int plat_mem_set_shared(struct ffa_mtd *mtd, bool shared)
127 {
128 struct ffa_comp_mrd *comp = trusty_ffa_mtd_get_comp_mrd(mtd);
129 bool secure = trusty_ffa_should_be_secure(mtd);
130 int ret;
131
132 ret = qemu_ffa_comp_set_shared(comp, shared, secure);
133 if (!ret && secure) {
134 mtd->memory_region_attributes &= ~FFA_MEM_ATTR_NONSECURE;
135 }
136 return ret;
137 }
138