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