1/*
2 * Copyright (c) 2007-2015 Freescale Semiconductor, Inc.
3 * Copyright 2018-2020 NXP
4 *
5 * License: NXP LA_OPT_NXP_Software_License
6 *
7 * NXP Confidential. This software is owned or controlled by NXP and may
8 * only be used strictly in accordance with the applicable license terms.
9 * By expressly accepting such terms or by downloading, installing,
10 * activating and/or otherwise using the software, you are agreeing that
11 * you have read, and that you agree to comply with and are bound by,
12 * such license terms. If you do not agree to be bound by the applicable
13 * license terms, then you may not retain, install, activate or otherwise
14 * use the software. This code may only be used in a microprocessor,
15 * microcontroller, sensor or digital signal processor ("NXP Product")
16 * supplied directly or indirectly from NXP. See the full NXP Software
17 * License Agreement in license/LA_OPT_NXP_Software_License.pdf
18 *
19 * FreeMASTER Communication Driver - TSA
20 */
21
22#include "freemaster.h"
23#include "freemaster_private.h"
24#include "freemaster_protocol.h"
25#include "freemaster_utils.h"
26
27#if FMSTR_USE_TSA > 0 && FMSTR_DISABLE == 0
28
29/* global variables */
30FMSTR_TSA_CDECL char FMSTR_TSA_POINTER[] = {
31 (char)(0xe0 |
32 (sizeof(void *) == 2 ?
33 0x01 :
34 sizeof(void *) == 4 ?
35 0x02 :
36 sizeof(void *) == 8 ? 0x03 : 0x00)), /* size of pointer is not 2,4 nor 8 (probably S12 platform) */
37 (char)0}; /* string-terminating zero */
38
39#if FMSTR_USE_TSA_DYNAMIC > 0
40static FMSTR_SIZE fmstr_tsaBuffSize; /* Dynamic TSA buffer size */
41static FMSTR_ADDR fmstr_tsaBuffAddr; /* Dynamic TSA buffer address */
42static FMSTR_SIZE fmstr_tsaTableIndex;
43
44#endif
45
46/******************************************************************************
47 *
48 * @brief TSA Initialization
49 *
50 ******************************************************************************/
51static FMSTR_BOOL _FMSTR_IsMemoryMapped(const char *type, unsigned long info);
52
53FMSTR_BOOL FMSTR_InitTsa(void)
54{
55#if FMSTR_USE_TSA_DYNAMIC > 0
56 fmstr_tsaTableIndex = 0;
57 fmstr_tsaBuffSize = 0;
58 fmstr_tsaBuffAddr = (FMSTR_ADDR)NULL;
59#endif
60
61 return FMSTR_TRUE;
62}
63
64/******************************************************************************
65 *
66 * @brief Assigning memory to dynamic TSA table
67 *
68 ******************************************************************************/
69
70FMSTR_BOOL FMSTR_SetUpTsaBuff(FMSTR_ADDR buffAddr, FMSTR_SIZE buffSize)
71{
72#if FMSTR_USE_TSA_DYNAMIC > 0
73 /* only allow to clear or set when cleared */
74 if (FMSTR_ADDR_VALID(buffAddr) == FMSTR_FALSE || FMSTR_ADDR_VALID(fmstr_tsaBuffAddr) == FMSTR_FALSE)
75 {
76 /* TSA table must be aligned on pointer size */
77 FMSTR_SIZE alignment = FMSTR_GetAlignmentCorrection(buffAddr, sizeof(void *));
78 fmstr_tsaBuffAddr = buffAddr + alignment;
79 fmstr_tsaBuffSize = buffSize - alignment;
80 return FMSTR_TRUE;
81 }
82 else
83 {
84 return FMSTR_FALSE;
85 }
86#else
87 return FMSTR_FALSE;
88#endif
89}
90
91/******************************************************************************
92 *
93 * @brief Retrieving entry from dynamic TSA table
94 *
95 ******************************************************************************/
96
97#if FMSTR_USE_TSA_DYNAMIC > 0
98FMSTR_TSA_FUNC_PROTO(dynamic_tsa)
99{
100 if (tableSize != NULL)
101 {
102 *tableSize = (FMSTR_SIZE)(fmstr_tsaTableIndex * sizeof(FMSTR_TSA_ENTRY));
103 }
104 return (const FMSTR_TSA_ENTRY *)FMSTR_CAST_ADDR_TO_PTR(fmstr_tsaBuffAddr);
105}
106#endif
107
108/******************************************************************************
109 *
110 * @brief Add entry to a dynamic TSA table
111 *
112 ******************************************************************************/
113
114FMSTR_BOOL FMSTR_TsaAddVar(FMSTR_TSATBL_STRPTR tsaName,
115 FMSTR_TSATBL_STRPTR tsaType,
116 FMSTR_TSATBL_VOIDPTR varAddr,
117 FMSTR_SIZE32 varSize,
118 FMSTR_SIZE flags)
119{
120#if FMSTR_USE_TSA_DYNAMIC > 0
121 /* the new TSA table entry must fit into the memory buffer */
122 if (((fmstr_tsaTableIndex + 1U) * sizeof(FMSTR_TSA_ENTRY)) <= fmstr_tsaBuffSize)
123 {
124 FMSTR_TSATBL_VOIDPTR info = FMSTR_TSA_INFO2(varSize, flags);
125 FMSTR_TSA_ENTRY *pItem;
126 FMSTR_SIZE i;
127
128 /* Check if this record is already in table */
129 for (i = 0; i < fmstr_tsaTableIndex; i++)
130 {
131 pItem = &((FMSTR_TSA_ENTRY *)FMSTR_CAST_ADDR_TO_PTR(fmstr_tsaBuffAddr))[i];
132
133 if (FMSTR_StrCmp(pItem->name.p, tsaName) != 0)
134 {
135 continue; /* name is different */
136 }
137 if (pItem->type.p != tsaType)
138 {
139 continue; /* type is different */
140 }
141 if (pItem->addr.p != varAddr)
142 {
143 continue; /* address is different */
144 }
145 if (pItem->info.p != info)
146 {
147 continue; /* size or attributes are different */
148 }
149
150 /* the same entry already exists, consider it added okay */
151 return FMSTR_TRUE;
152 }
153
154 /* add the entry to the last-used position */
155 pItem = &((FMSTR_TSA_ENTRY *)FMSTR_CAST_ADDR_TO_PTR(fmstr_tsaBuffAddr))[i];
156
157 pItem->name.p = FMSTR_TSATBL_STRPTR_CAST(tsaName);
158 pItem->type.p = FMSTR_TSATBL_STRPTR_CAST(tsaType);
159 pItem->addr.p = FMSTR_TSATBL_VOIDPTR_CAST(varAddr);
160 pItem->info.p = FMSTR_TSATBL_VOIDPTR_CAST(info);
161 fmstr_tsaTableIndex++;
162 return FMSTR_TRUE;
163 }
164 else
165 {
166 return FMSTR_FALSE;
167 }
168#else
169 return FMSTR_FALSE;
170#endif
171}
172
173/******************************************************************************
174 *
175 * @brief Handling GETTSAINFO and GETTSAINFO_EX command
176 *
177 * @param msgBuffIO - original command (in) and response buffer (out)
178 * @param retStatus - response status
179 *
180 * @return As all command handlers, the return value should be the buffer
181 * pointer where the response output finished (except checksum)
182 *
183 ******************************************************************************/
184
185FMSTR_BPTR FMSTR_GetTsaInfo(FMSTR_BPTR msgBuffIO, FMSTR_U8 *retStatus)
186{
187 volatile FMSTR_BPTR response = msgBuffIO;
188 const FMSTR_TSA_ENTRY *tsaTbl;
189 FMSTR_SIZE tblIndex;
190 FMSTR_SIZE tblSize = 0U;
191 FMSTR_U8 tblFlags;
192
193 FMSTR_ASSERT(msgBuffIO != NULL);
194 FMSTR_ASSERT(retStatus != NULL);
195
196 /* Get ULEB index of table the PC is requesting */
197 msgBuffIO = FMSTR_SizeFromBuffer(&tblIndex, msgBuffIO);
198 FMSTR_UNUSED(msgBuffIO);
199
200 /* TSA flags */
201 tblFlags = FMSTR_TSA_VERSION | FMSTR_TSA_FLAGS;
202
203 /* sizeof TSA table entry items */
204 /*lint -e{506,774} constant value boolean */
205 if ((sizeof(void *)) == 2U)
206 {
207 tblFlags |= FMSTR_TSA_INFO_ADRSIZE_16;
208 }
209 else
210 {
211 if ((sizeof(void *)) <= 4U)
212 {
213 tblFlags |= FMSTR_TSA_INFO_ADRSIZE_32;
214 }
215 else
216 {
217 tblFlags |= FMSTR_TSA_INFO_ADRSIZE_64;
218 }
219 }
220
221 /* flags */
222 response = FMSTR_ValueToBuffer8(response, tblFlags);
223
224 /* get the table (or NULL if no table on given index) */
225 tsaTbl = FMSTR_TsaGetTable(tblIndex, &tblSize);
226
227 /* table size in bytes */
228 tblSize *= FMSTR_CFG_BUS_WIDTH;
229 response = FMSTR_SizeToBuffer(response, tblSize);
230
231 /* table address */
232 response = FMSTR_AddressToBuffer(response, FMSTR_CAST_PTR_TO_ADDR(tsaTbl));
233
234 /* success */
235 *retStatus = FMSTR_STS_OK | FMSTR_STSF_VARLEN;
236 return response;
237}
238
239/******************************************************************************
240 *
241 * @brief Handling GETSTRLEN and GETSTRLEN_EX commands
242 *
243 * @param msgBuffIO - original command (in) and response buffer (out)
244 * @param retStatus - response status
245 *
246 * @return As all command handlers, the return value should be the buffer
247 * pointer where the response output finished (except checksum)
248 *
249 ******************************************************************************/
250
251FMSTR_BPTR FMSTR_GetStringLen(FMSTR_BPTR msgBuffIO, FMSTR_U8 *retStatus)
252{
253 FMSTR_BPTR response = msgBuffIO;
254 FMSTR_ADDR strAddr;
255 FMSTR_SIZE len = 0U;
256
257 FMSTR_ASSERT(msgBuffIO != NULL);
258 FMSTR_ASSERT(retStatus != NULL);
259
260 msgBuffIO = FMSTR_AddressFromBuffer(&strAddr, msgBuffIO);
261 FMSTR_UNUSED(msgBuffIO);
262
263 len = FMSTR_StrLen((FMSTR_CHAR *)strAddr);
264
265 /* return strign size in bytes (even on 16bit DSP) */
266 len *= FMSTR_CFG_BUS_WIDTH;
267
268 /* success */
269 *retStatus = FMSTR_STS_OK | FMSTR_STSF_VARLEN;
270 return FMSTR_SizeToBuffer(response, len);
271}
272
273/******************************************************************************
274 *
275 * @brief Helper (inline) function for TSA memory region check
276 *
277 * @param addrUser - address of region to be checked
278 * @param sizeUser - size of region to be checked
279 * @param addrSafe - address of known "safe" region
280 * @param sizeSafe - size of safe region
281 *
282 * @return This function returns non-zero if given user space is safe
283 * (i.e. it lies in given safe space)
284 *
285 ******************************************************************************/
286
287/* declare function prototype */
288static FMSTR_BOOL FMSTR_CheckMemSpace(FMSTR_ADDR addrUser,
289 FMSTR_SIZE sizeUser,
290 FMSTR_ADDR addrSafe,
291 FMSTR_SIZE sizeSafe);
292
293static FMSTR_BOOL FMSTR_CheckMemSpace(FMSTR_ADDR addrUser,
294 FMSTR_SIZE sizeUser,
295 FMSTR_ADDR addrSafe,
296 FMSTR_SIZE sizeSafe)
297{
298 FMSTR_BOOL ret = FMSTR_FALSE;
299
300#ifdef __HCS12X__
301 /* convert from logical to global if needed */
302 addrUser = FMSTR_FixHcs12xAddr(addrUser);
303 addrSafe = FMSTR_FixHcs12xAddr(addrSafe);
304#endif
305
306 if (addrUser >= addrSafe)
307 {
308 ret = (FMSTR_BOOL)(((addrUser + sizeUser) <= (addrSafe + sizeSafe)) ? FMSTR_TRUE : FMSTR_FALSE);
309 }
310
311 return ret;
312}
313
314/******************************************************************************
315 *
316 * @brief Check wether given memory region is "safe" (covered by TSA)
317 *
318 * @param varAddr - address of the memory to be checked
319 * @param varSize - size of the memory to be checked
320 * @param writeAccess - write access is required
321 *
322 * @return This function returns non-zero if user space is safe
323 *
324 ******************************************************************************/
325
326FMSTR_BOOL FMSTR_CheckTsaSpace(FMSTR_ADDR varAddr, FMSTR_SIZE varSize, FMSTR_BOOL writeAccess)
327{
328 const FMSTR_TSA_ENTRY *pte;
329 FMSTR_SIZE tableIndex;
330 FMSTR_SIZE i, cnt;
331 unsigned long info;
332 const char *type;
333
334#if FMSTR_CFG_BUS_WIDTH >= 2U
335 /* TSA tables use sizeof() operator which returns size in "bus-widths" (e.g. 56F8xx) */
336 varSize = (varSize + 1) / FMSTR_CFG_BUS_WIDTH;
337#endif
338
339 /* to be as fast as possible during normal operation,
340 check variable entries in all tables first */
341 tableIndex = 0U;
342 while ((pte = FMSTR_TsaGetTable(tableIndex, &cnt)) != NULL)
343 {
344 /* number of items in a table */
345 cnt /= (FMSTR_SIZE)sizeof(FMSTR_TSA_ENTRY);
346
347 /* all table entries */
348 for (i = 0U; i < cnt; i++)
349 {
350 if (sizeof(pte->addr.p) < sizeof(pte->addr.n))
351 {
352 info = (unsigned long)pte->info.n;
353 }
354 else
355 {
356 info = (unsigned long)pte->info.p;
357 }
358
359 type = pte->type.p;
360
361 /* variable entry only (also check read-write flag) */
362 if (_FMSTR_IsMemoryMapped(type, info) != FMSTR_FALSE &&
363 (writeAccess == FMSTR_FALSE || ((info & FMSTR_TSA_INFO_VAR_MASK) == FMSTR_TSA_INFO_RW_VAR)))
364 {
365 /* need to take the larger of the two in union (will be optimized by compiler anyway) */
366 if (sizeof(pte->addr.p) < sizeof(pte->addr.n))
367 {
368 if (FMSTR_CheckMemSpace(varAddr, varSize, pte->addr.n, (FMSTR_SIZE)(info >> 2)) != FMSTR_FALSE)
369 {
370 return FMSTR_TRUE; /* access granted! */
371 }
372 }
373 else
374 {
375 if (FMSTR_CheckMemSpace(varAddr, varSize, (FMSTR_ADDR)pte->addr.p, (FMSTR_SIZE)(info >> 2)) !=
376 FMSTR_FALSE)
377 {
378 return FMSTR_TRUE; /* access granted! */
379 }
380 }
381 }
382
383 pte++;
384 }
385
386 tableIndex++;
387 }
388
389 /* no more writable memory chunks available */
390 if (writeAccess != FMSTR_FALSE)
391 {
392 return FMSTR_FALSE;
393 }
394
395 /* allow reading of recorder buffer */
396#if FMSTR_USE_RECORDER > 0
397 if (FMSTR_IsInRecBuffer(varAddr, varSize) != FMSTR_FALSE)
398 {
399 return FMSTR_TRUE;
400 }
401#endif
402
403 /* allow reading of any C-constant string referenced in TSA tables */
404 tableIndex = 0U;
405 while ((pte = FMSTR_TsaGetTable(tableIndex, &cnt)) != NULL)
406 {
407 /* allow reading of the TSA table itself */
408 if (FMSTR_CheckMemSpace(varAddr, varSize, (FMSTR_ADDR)(FMSTR_TSA_ENTRY *)pte, cnt) != FMSTR_FALSE)
409 {
410 return FMSTR_TRUE;
411 }
412
413 /* number of items in a table */
414 cnt /= (FMSTR_SIZE)sizeof(FMSTR_TSA_ENTRY);
415
416 /* all table entries */
417 for (i = 0U; i < cnt; i++)
418 {
419 /* system strings are always accessible as C-pointers */
420 if (pte->name.p != NULL)
421 {
422 if (FMSTR_CheckMemSpace(varAddr, varSize, (FMSTR_ADDR)(pte->name.p), FMSTR_StrLen(pte->name.p)) !=
423 FMSTR_FALSE)
424 {
425 return FMSTR_TRUE;
426 }
427 }
428
429 if (pte->type.p != NULL)
430 {
431 if (FMSTR_CheckMemSpace(varAddr, varSize, (FMSTR_ADDR)(pte->type.p), FMSTR_StrLen(pte->type.p)) !=
432 FMSTR_FALSE)
433 {
434 return FMSTR_TRUE;
435 }
436 }
437
438 pte++;
439 }
440
441 tableIndex++;
442 }
443
444 /* no valid TSA entry found => not-safe to access the memory */
445 return FMSTR_FALSE;
446}
447
448/* Check type of the entry. */
449static FMSTR_BOOL _FMSTR_IsMemoryMapped(const char *type, unsigned long info)
450{
451 FMSTR_ASSERT(type != NULL);
452
453 /* If type is special non-memory type or memeber structure (0b00 in info) */
454 if (type[0] == FMSTR_TSA_SPECIAL_NOMEM[0] || (info & FMSTR_TSA_INFO_VAR_MASK) == 0U)
455 {
456 return FMSTR_FALSE;
457 }
458
459 return FMSTR_TRUE;
460}
461
462/* Find TSA table row with user resource by resource ID */
463const FMSTR_TSA_ENTRY *FMSTR_FindUresInTsa(FMSTR_ADDR resourceId)
464{
465 const FMSTR_TSA_ENTRY *pte;
466 FMSTR_SIZE tableIndex;
467 FMSTR_SIZE i, cnt;
468
469 tableIndex = 0U;
470 while ((pte = FMSTR_TsaGetTable(tableIndex, &cnt)) != NULL)
471 {
472 /* number of items in a table */
473 cnt /= (FMSTR_SIZE)sizeof(FMSTR_TSA_ENTRY);
474
475 /* all table entries */
476 for (i = 0U; i < cnt; i++)
477 {
478 if (pte->addr.n == resourceId)
479 {
480 return pte;
481 }
482 }
483
484 tableIndex++;
485 }
486
487 return NULL;
488}
489
490#else /* (FMSTR_USE_TSA) && (!(FMSTR_DISABLE)) */
491
492/* use void TSA API functions */
493FMSTR_BOOL FMSTR_SetUpTsaBuff(FMSTR_ADDR buffAddr, FMSTR_SIZE buffSize)
494{
495 FMSTR_UNUSED(buffAddr);
496 FMSTR_UNUSED(buffSize);
497 return FMSTR_FALSE;
498}
499
500FMSTR_BOOL FMSTR_TsaAddVar(FMSTR_TSATBL_STRPTR tsaName,
501 FMSTR_TSATBL_STRPTR tsaType,
502 FMSTR_TSATBL_VOIDPTR varAddr,
503 FMSTR_SIZE32 varSize,
504 FMSTR_SIZE flags)
505{
506 FMSTR_UNUSED(tsaName);
507 FMSTR_UNUSED(tsaType);
508 FMSTR_UNUSED(varAddr);
509 FMSTR_UNUSED(varSize);
510 FMSTR_UNUSED(flags);
511 return FMSTR_FALSE;
512}
513
514/*lint -efile(766, freemaster_protocol.h) include file is not used in this case */
515
516#endif /* (FMSTR_USE_TSA) && (!(FMSTR_DISABLE)) */
517