1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright 2019 Broadcom.
4 */
5
6 #include <drivers/bcm/bnxt.h>
7 #include <io.h>
8 #include <kernel/pseudo_ta.h>
9 #include <mm/core_memprot.h>
10 #include <mm/core_mmu.h>
11 #include <string.h>
12 #include <trace.h>
13
14 #define ELOG_SERVICE_UUID \
15 { 0x6272636D, 0x2019, 0x0701, \
16 { 0x42, 0x43, 0x4D, 0x5F, 0x45, 0x4C, 0x4F, 0x47 } }
17
18 #define ELOG_TA_NAME "pta_bcm_elog.ta"
19
20 #define BCM_NITRO_FW_LOAD_ADDR 0x8ae00000
21 #define BCM_NITRO_CRASH_DUMP_BASE_ADDR 0x8b000000
22
23 /* Default ELOG buffer size 1MB */
24 #define DEFAULT_ELOG_BUFFER_SIZE 0x100000U
25
26 /*
27 * Get Error log memory dump
28 *
29 * [out] memref[0]: Destination
30 * [in] value[1].a: Offset
31 */
32 #define PTA_BCM_ELOG_CMD_GET_ELOG_MEM 1
33
34 /*
35 * Get nitro crash_dump memory
36 *
37 * [out] memref[0]: Destination
38 * [in] value[1].a: Offset
39 */
40 #define PTA_BCM_ELOG_CMD_GET_NITRO_CRASH_DUMP 2
41
42 /*
43 * Load nitro firmware memory
44 *
45 * [in] memref[0]: Nitro f/w image data
46 * [in] value[1].a: Offset for loading f/w image
47 * [in] value[2].a: Firmware image size
48 */
49 #define PTA_BCM_ELOG_CMD_LOAD_NITRO_FW 3
50
51 #define BCM_ELOG_GLOBAL_METADATA_SIG 0x45524c47
52
53 #define MAX_NITRO_CRASH_DUMP_MEM_SIZE 0x2000000
54 #define MAX_NITRO_FW_LOAD_MEM_SIZE 0x200000
55
56 /* Load Nitro fw image to SEC DDR memory */
pta_elog_load_nitro_fw(uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS])57 static TEE_Result pta_elog_load_nitro_fw(uint32_t param_types,
58 TEE_Param params[TEE_NUM_PARAMS])
59 {
60 TEE_Result res = TEE_SUCCESS;
61 paddr_t src_paddr = BCM_NITRO_FW_LOAD_ADDR + BNXT_IMG_SECMEM_OFFSET;
62 vaddr_t src_vaddr = 0;
63 uint32_t offset = 0;
64 size_t end_offs = 0;
65 size_t sz = 0;
66 char *buf = NULL;
67 uint32_t exp_param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
68 TEE_PARAM_TYPE_VALUE_INPUT,
69 TEE_PARAM_TYPE_VALUE_INPUT,
70 TEE_PARAM_TYPE_NONE);
71
72 if (exp_param_types != param_types) {
73 EMSG("Invalid Param types");
74 return TEE_ERROR_BAD_PARAMETERS;
75 }
76
77 /* Check if firmware file size exceeds reserved memory size */
78 if (params[2].value.a > MAX_NITRO_FW_LOAD_MEM_SIZE) {
79 EMSG("Invalid access");
80 return TEE_ERROR_EXCESS_DATA;
81 }
82
83 offset = params[1].value.a;
84 buf = params[0].memref.buffer;
85 sz = params[0].memref.size;
86
87 /*
88 * Check that we under no circumstances will attempt to write
89 * beyond BCM_NITRO_FW_LOAD_ADDR + MAX_NITRO_FW_LOAD_MEM_SIZE.
90 */
91 if (ADD_OVERFLOW(sz, offset, &end_offs) ||
92 end_offs > MAX_NITRO_FW_LOAD_MEM_SIZE - BNXT_IMG_SECMEM_OFFSET) {
93 EMSG("Invalid access");
94 return TEE_ERROR_ACCESS_DENIED;
95 }
96
97 src_vaddr = (vaddr_t)phys_to_virt((uintptr_t)src_paddr + offset,
98 MEM_AREA_RAM_SEC, sz);
99 if (!src_vaddr) {
100 EMSG("Not enough memory mapped");
101 return TEE_ERROR_BAD_PARAMETERS;
102 }
103
104 memcpy((char *)src_vaddr, buf, sz);
105
106 cache_op_inner(DCACHE_AREA_CLEAN, (void *)src_vaddr, sz);
107
108 return res;
109 }
110
get_dump_data(vaddr_t src,TEE_Param params[TEE_NUM_PARAMS])111 static uint32_t get_dump_data(vaddr_t src, TEE_Param params[TEE_NUM_PARAMS])
112 {
113 char *buf = NULL;
114 uint32_t sz = 0;
115
116 buf = params[0].memref.buffer;
117 sz = params[0].memref.size;
118
119 /*
120 * If request size exceeds default buf size
121 * override request size to default DEFAULT_ELOG_BUFFER_SIZE
122 */
123 if (sz > DEFAULT_ELOG_BUFFER_SIZE)
124 sz = DEFAULT_ELOG_BUFFER_SIZE;
125
126 DMSG("buf %p sz 0x%x", buf, sz);
127
128 memcpy(buf, (char *)src, sz);
129
130 params[0].memref.size = sz;
131
132 return sz;
133 }
134
135 /* Copy nitro crash dump data */
pta_elog_nitro_crash_dump(uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS])136 static TEE_Result pta_elog_nitro_crash_dump(uint32_t param_types,
137 TEE_Param params[TEE_NUM_PARAMS])
138 {
139 TEE_Result res = TEE_SUCCESS;
140 paddr_t src_paddr = BCM_NITRO_CRASH_DUMP_BASE_ADDR;
141 vaddr_t src_vaddr = 0;
142 uint32_t offset = 0;
143 uint32_t exp_param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_OUTPUT,
144 TEE_PARAM_TYPE_VALUE_INPUT,
145 TEE_PARAM_TYPE_NONE,
146 TEE_PARAM_TYPE_NONE);
147 uint32_t sz = 0;
148
149 if (exp_param_types != param_types) {
150 EMSG("Invalid Param types");
151 return TEE_ERROR_BAD_PARAMETERS;
152 }
153
154 offset = params[1].value.a;
155
156 /*
157 * Check if offset is within memory range reserved for nitro crash dump
158 * minus default size of buffer
159 */
160 if (offset > MAX_NITRO_CRASH_DUMP_MEM_SIZE - DEFAULT_ELOG_BUFFER_SIZE) {
161 EMSG("Invalid access");
162 return TEE_ERROR_ACCESS_DENIED;
163 }
164
165 sz = MIN(params[0].memref.size, DEFAULT_ELOG_BUFFER_SIZE);
166 src_vaddr = (vaddr_t)phys_to_virt((uintptr_t)src_paddr + offset,
167 MEM_AREA_RAM_SEC, sz);
168 if (!src_vaddr) {
169 EMSG("Not enough memory mapped");
170 return TEE_ERROR_BAD_PARAMETERS;
171 }
172
173 /* TODO : check if NITRO_CRASH_DUMP is available */
174
175 cache_op_inner(DCACHE_AREA_INVALIDATE, (void *)src_vaddr,
176 DEFAULT_ELOG_BUFFER_SIZE);
177
178 get_dump_data(src_vaddr, params);
179
180 return res;
181 }
182
183 /* Copy soc error log data */
pta_elog_dump(uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS])184 static TEE_Result pta_elog_dump(uint32_t param_types,
185 TEE_Param params[TEE_NUM_PARAMS])
186 {
187 TEE_Result res = TEE_SUCCESS;
188 paddr_t src_paddr = CFG_BCM_ELOG_BASE;
189 vaddr_t src_vaddr = 0;
190 uint32_t exp_param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_OUTPUT,
191 TEE_PARAM_TYPE_VALUE_INPUT,
192 TEE_PARAM_TYPE_NONE,
193 TEE_PARAM_TYPE_NONE);
194 uint32_t sz = 0;
195
196 if (exp_param_types != param_types) {
197 EMSG("Invalid Param types");
198 return TEE_ERROR_BAD_PARAMETERS;
199 }
200
201 sz = MIN(params[0].memref.size, DEFAULT_ELOG_BUFFER_SIZE);
202 src_vaddr = (vaddr_t)phys_to_virt(src_paddr, MEM_AREA_RAM_NSEC, sz);
203 if (!src_vaddr) {
204 EMSG("Not enough memory mapped");
205 return TEE_ERROR_BAD_PARAMETERS;
206 }
207
208 /* Validate if Error logs are present */
209 if ((*(uint32_t *)src_vaddr) != BCM_ELOG_GLOBAL_METADATA_SIG) {
210 EMSG("Elog Not setup");
211 return TEE_ERROR_NOT_SUPPORTED;
212 }
213
214 get_dump_data(src_vaddr, params);
215
216 return res;
217 }
218
invoke_command(void * session_context __unused,uint32_t cmd_id,uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS])219 static TEE_Result invoke_command(void *session_context __unused,
220 uint32_t cmd_id,
221 uint32_t param_types,
222 TEE_Param params[TEE_NUM_PARAMS])
223 {
224 TEE_Result res = TEE_SUCCESS;
225
226 DMSG("command entry point[%d] for \"%s\"", cmd_id, ELOG_TA_NAME);
227
228 switch (cmd_id) {
229 case PTA_BCM_ELOG_CMD_GET_ELOG_MEM:
230 res = pta_elog_dump(param_types, params);
231 break;
232 case PTA_BCM_ELOG_CMD_GET_NITRO_CRASH_DUMP:
233 res = pta_elog_nitro_crash_dump(param_types, params);
234 break;
235 case PTA_BCM_ELOG_CMD_LOAD_NITRO_FW:
236 res = pta_elog_load_nitro_fw(param_types, params);
237 break;
238 default:
239 EMSG("cmd: %d Not supported %s", cmd_id, ELOG_TA_NAME);
240 res = TEE_ERROR_NOT_SUPPORTED;
241 break;
242 }
243
244 return res;
245 }
246
247 pseudo_ta_register(.uuid = ELOG_SERVICE_UUID,
248 .name = ELOG_TA_NAME,
249 .flags = PTA_DEFAULT_FLAGS,
250 .invoke_command_entry_point = invoke_command);
251