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