1 // © 2021 Qualcomm Innovation Center, Inc. All rights reserved.
2 //
3 // SPDX-License-Identifier: BSD-3-Clause
4 
5 #if defined(UNIT_TESTS)
6 
7 #include <assert.h>
8 #include <hyptypes.h>
9 
10 #include <hyprights.h>
11 
12 #include <atomic.h>
13 #include <cpulocal.h>
14 #include <cspace.h>
15 #include <object.h>
16 #include <partition.h>
17 #include <partition_alloc.h>
18 #include <spinlock.h>
19 
20 #include <asm/event.h>
21 
22 #include "event_handlers.h"
23 
24 static cspace_t	      *test_cspace;
25 static cap_id_t	       test_cspace_master_cap;
26 static _Atomic count_t test_cspace_wait_count;
27 static _Atomic count_t test_cspace_finish_count;
28 static _Atomic uint8_t test_cspace_revoke_flag;
29 
30 #define TEST_CAP_COPIES	     20U
31 #define TEST_CSPACE_MAX_CAPS ((PLATFORM_MAX_CORES * TEST_CAP_COPIES) + 1U)
32 
33 CPULOCAL_DECLARE_STATIC(cap_id_t, test_caps)[TEST_CAP_COPIES];
34 
35 void
tests_cspace_init(void)36 tests_cspace_init(void)
37 {
38 	cspace_ptr_result_t cspace_ret;
39 	object_ptr_t	    obj;
40 	cap_id_result_t	    cap_ret;
41 	error_t		    err;
42 
43 	cspace_create_t params = { NULL };
44 
45 	cspace_ret = partition_allocate_cspace(partition_get_private(), params);
46 	assert(cspace_ret.e == OK);
47 	test_cspace = cspace_ret.r;
48 	spinlock_acquire(&test_cspace->header.lock);
49 	err = cspace_configure(test_cspace, TEST_CSPACE_MAX_CAPS);
50 	spinlock_release(&test_cspace->header.lock);
51 	assert(err == OK);
52 	err = object_activate_cspace(test_cspace);
53 	assert(err == OK);
54 
55 	obj.cspace = test_cspace;
56 	cap_ret =
57 		cspace_create_master_cap(test_cspace, obj, OBJECT_TYPE_CSPACE);
58 	assert(cap_ret.e == OK);
59 	test_cspace_master_cap = cap_ret.r;
60 
61 	atomic_init(&test_cspace_wait_count, 0U);
62 	atomic_init(&test_cspace_finish_count, PLATFORM_MAX_CORES);
63 	atomic_init(&test_cspace_revoke_flag, 0U);
64 }
65 
66 static error_t
tests_cspace_cap_lookup(cap_id_t cap,cap_rights_t rights)67 tests_cspace_cap_lookup(cap_id_t cap, cap_rights_t rights)
68 {
69 	object_ptr_result_t ret = cspace_lookup_object(
70 		test_cspace, cap, OBJECT_TYPE_CSPACE, rights, true);
71 
72 	if (ret.e == OK) {
73 		assert(ret.r.cspace == test_cspace);
74 		object_put_cspace(ret.r.cspace);
75 	}
76 
77 	return ret.e;
78 }
79 
80 bool
tests_cspace_start(void)81 tests_cspace_start(void)
82 {
83 	cap_id_result_t	    cap_ret;
84 	cap_id_t	   *cap		  = CPULOCAL(test_caps);
85 	cap_rights_cspace_t cspace_rights = cap_rights_cspace_default();
86 	cap_rights_t	    rights;
87 	error_t		    err;
88 	const count_t	    num_delete = TEST_CAP_COPIES / 2U;
89 
90 	object_get_cspace_additional(test_cspace);
91 
92 	cap_rights_cspace_set_test(&cspace_rights, true);
93 	rights = cap_rights_cspace_raw(cspace_rights);
94 
95 	// Sync with other cores to maximise concurrent accesses
96 	(void)atomic_fetch_add_explicit(&test_cspace_wait_count, 1U,
97 					memory_order_relaxed);
98 	while (asm_event_load_before_wait(&test_cspace_wait_count) !=
99 	       PLATFORM_MAX_CORES) {
100 		asm_event_wait(&test_cspace_wait_count);
101 	}
102 
103 	for (count_t i = 0U; i < TEST_CAP_COPIES; i++) {
104 		cap_ret = cspace_copy_cap(test_cspace, test_cspace,
105 					  test_cspace_master_cap, rights);
106 		assert(cap_ret.e == OK);
107 		cap[i] = cap_ret.r;
108 	}
109 
110 	err = tests_cspace_cap_lookup(test_cspace_master_cap, rights);
111 	assert(err == OK);
112 
113 	for (count_t i = 0U; i < TEST_CAP_COPIES; i++) {
114 		err = tests_cspace_cap_lookup(cap[i], rights);
115 		assert(err == OK);
116 	}
117 
118 	cspace_rights = CAP_RIGHTS_CSPACE_ALL;
119 	rights	      = cap_rights_cspace_raw(cspace_rights);
120 
121 	err = tests_cspace_cap_lookup(test_cspace_master_cap, rights);
122 	assert(err == OK);
123 
124 	for (count_t i = 0U; i < TEST_CAP_COPIES; i++) {
125 		err = tests_cspace_cap_lookup(cap[i], rights);
126 		assert(err == ERROR_CSPACE_INSUFFICIENT_RIGHTS);
127 	}
128 
129 	for (count_t i = 0U; i < num_delete; i++) {
130 		err = cspace_delete_cap(test_cspace, cap[i]);
131 		assert(err == OK);
132 	}
133 
134 	if (atomic_fetch_sub_explicit(&test_cspace_finish_count, 1U,
135 				      memory_order_release) == 1U) {
136 		err = cspace_revoke_caps(test_cspace, test_cspace_master_cap);
137 		assert(err == OK);
138 
139 		err = cspace_delete_cap(test_cspace, test_cspace_master_cap);
140 		assert(err == OK);
141 
142 		asm_event_store_and_wake(&test_cspace_revoke_flag, 1U);
143 	} else {
144 		while (asm_event_load_before_wait(&test_cspace_revoke_flag) ==
145 		       0U) {
146 			asm_event_wait(&test_cspace_revoke_flag);
147 		}
148 	}
149 
150 	// Delete the revoked caps
151 	for (count_t i = num_delete; i < TEST_CAP_COPIES; i++) {
152 		err = cspace_delete_cap(test_cspace, cap[i]);
153 		assert(err == OK);
154 	}
155 
156 	object_put_cspace(test_cspace);
157 
158 	return false;
159 }
160 #else
161 
162 extern char unused;
163 
164 #endif
165