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