1 /*
2 * Copyright (c) 2020 Google, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files
6 * (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24 /*
25 * This module registers smc handlers that are called by tests running in the
26 * client os. This api is currently only available if lib/sm is enabled.
27 */
28 #if WITH_LIB_SM
29
30 #include <arch/arch_ops.h>
31 #include <arch/ops.h>
32 #include <err.h>
33 #include <inttypes.h>
34 #include <kernel/vm.h>
35 #include <lib/sm.h>
36 #include <lib/sm/sm_err.h>
37 #include <lib/sm/smcall.h>
38 #include <lib/smc/smc.h>
39 #include <limits.h>
40 #include <lk/init.h>
41 #include <string.h>
42 #include <trace.h>
43
44 #include "stdcalltest.h"
45
args_get_id(struct smc32_args * args)46 static ext_mem_obj_id_t args_get_id(struct smc32_args* args) {
47 return (((uint64_t)args->params[1] << 32) | args->params[0]);
48 }
49
args_get_sz(struct smc32_args * args)50 static size_t args_get_sz(struct smc32_args* args) {
51 return (size_t)args->params[2];
52 }
53
54 /**
55 * stdcalltest_sharedmem_rw - Test shared memory buffer.
56 * @id: Shared memory id.
57 * @size: Size.
58 *
59 * Check that buffer contains the 64 bit integer sqequnce [0, 1, 2, ...,
60 * @size / 8 - 1] and modify sequence to [@size, @size - 1, size - 2, ...,
61 * @size - (@size / 8 - 1)].
62 *
63 * Return: 0 on success. SM_ERR_INVALID_PARAMETERS is buffer does not contain
64 * expected input pattern. SM_ERR_INTERNAL_FAILURE if @id could not be mapped.
65 */
stdcalltest_sharedmem_rw(ext_mem_client_id_t client_id,ext_mem_obj_id_t mem_obj_id,size_t size)66 static long stdcalltest_sharedmem_rw(ext_mem_client_id_t client_id,
67 ext_mem_obj_id_t mem_obj_id,
68 size_t size) {
69 struct vmm_aspace* aspace = vmm_get_kernel_aspace();
70 status_t ret;
71 long status;
72 void* va;
73 uint64_t* va64;
74
75 if (!IS_PAGE_ALIGNED(size)) {
76 return SM_ERR_INVALID_PARAMETERS;
77 }
78
79 ret = ext_mem_map_obj_id(aspace, "stdcalltest", client_id, mem_obj_id, 0, 0,
80 size, &va, PAGE_SIZE_SHIFT, 0,
81 ARCH_MMU_FLAG_PERM_NO_EXECUTE);
82 if (ret != NO_ERROR) {
83 status = SM_ERR_INTERNAL_FAILURE;
84 goto err_map;
85 }
86 va64 = va;
87
88 for (size_t i = 0; i < size / sizeof(*va64); i++) {
89 if (va64[i] != i) {
90 TRACEF("input mismatch at %zd, got 0x%" PRIx64
91 " instead of 0x%zx\n",
92 i, va64[i], i);
93 status = SM_ERR_INVALID_PARAMETERS;
94 goto err_input_mismatch;
95 }
96 va64[i] = size - i;
97 }
98 status = 0;
99
100 err_input_mismatch:
101 ret = vmm_free_region(aspace, (vaddr_t)va);
102 if (ret) {
103 status = SM_ERR_INTERNAL_FAILURE;
104 }
105 err_map:
106 return status;
107 }
108
109 #if ARCH_ARM64
110 long clobber_sve_asm(uint32_t byte_clobber);
111 long load_sve_asm(uint8_t* arr, uint64_t len);
112
113 #define SVE_VEC_LEN_BITS 128
114 #define SVE_NB_BYTE_VEC_LEN SVE_VEC_LEN_BITS / 8
115 #define SVE_SVE_REGS_COUNT 32
116
117 #define SMC_FC_TRNG_VERSION SMC_FASTCALL_NR(SMC_ENTITY_STD, 0x50)
118
119 static uint8_t sve_regs[SMP_MAX_CPUS][SVE_SVE_REGS_COUNT * SVE_NB_BYTE_VEC_LEN]
120 __attribute__((aligned(16)));
121
122 enum clobber_restore_error {
123 SVE_NO_ERROR = 0,
124 SVE_GENERIC_ERROR = 1,
125 SVE_REGISTER_NOT_RESTORED = 2,
126 SVE_ERROR_LONG_TYPE = LONG_MAX
127 };
128
stdcalltest_clobber_sve(struct smc32_args * args)129 long stdcalltest_clobber_sve(struct smc32_args* args) {
130 enum clobber_restore_error ret = SVE_NO_ERROR;
131 if (!arch_sve_supported()) {
132 /* test is OK, if there is no SVE there is nothing to assert but this is
133 * not an ERROR */
134 return ret;
135 }
136
137 uint64_t v_cpacr_el1 = arch_enable_sve();
138 uint cpuid = arch_curr_cpu_num();
139 long call_nb = args->params[1];
140
141 /* First Call on cpu needs to Clobber ASM registers */
142 if (call_nb == 1) {
143 ret = clobber_sve_asm(args->params[0]);
144 if (ret != SVE_NO_ERROR) {
145 panic("Failed to Clobber ARM SVE registers: %lx\n", ret);
146 ret = SVE_GENERIC_ERROR;
147 goto end_stdcalltest_clobber_sve;
148 }
149 }
150
151 /* Make sure registers are as expected */
152 const uint8_t EXPECTED = (uint8_t)args->params[0];
153 ret = load_sve_asm(sve_regs[cpuid], SVE_NB_BYTE_VEC_LEN);
154 if (ret != SVE_NO_ERROR) {
155 panic("Failed to Load ARM SVE registers: %lx\n", ret);
156 ret = SVE_GENERIC_ERROR;
157 goto end_stdcalltest_clobber_sve;
158 }
159
160 for (size_t idx = 0; idx < countof(sve_regs[cpuid]); ++idx) {
161 uint8_t val = sve_regs[cpuid][idx];
162
163 if (val != EXPECTED) {
164 ret = SVE_REGISTER_NOT_RESTORED;
165 goto end_stdcalltest_clobber_sve;
166 }
167 }
168
169 end_stdcalltest_clobber_sve:
170 ARM64_WRITE_SYSREG(cpacr_el1, v_cpacr_el1);
171 return ret;
172 }
173 #endif
174
stdcalltest_stdcall(struct smc32_args * args)175 static long stdcalltest_stdcall(struct smc32_args* args) {
176 switch (args->smc_nr) {
177 case SMC_SC_TEST_VERSION:
178 return TRUSTY_STDCALLTEST_API_VERSION;
179 case SMC_SC_TEST_SHARED_MEM_RW:
180 return stdcalltest_sharedmem_rw(args->client_id, args_get_id(args),
181 args_get_sz(args));
182 #if ARCH_ARM64
183 case SMC_SC_TEST_CLOBBER_SVE: {
184 return stdcalltest_clobber_sve(args);
185 }
186 #endif
187 default:
188 return SM_ERR_UNDEFINED_SMC;
189 }
190 }
191
192 static struct smc32_entity stdcalltest_sm_entity = {
193 .stdcall_handler = stdcalltest_stdcall,
194 };
195
stdcalltest_init(uint level)196 static void stdcalltest_init(uint level) {
197 int err;
198
199 err = sm_register_entity(SMC_ENTITY_TEST, &stdcalltest_sm_entity);
200 if (err) {
201 printf("trusty error register entity: %d\n", err);
202 }
203 }
204 LK_INIT_HOOK(stdcalltest, stdcalltest_init, LK_INIT_LEVEL_APPS);
205
206 #endif
207