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 */ 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 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 */ 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 */ 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 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