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