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 */ |
30 | FMSTR_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 |
40 | static FMSTR_SIZE fmstr_tsaBuffSize; /* Dynamic TSA buffer size */ |
41 | static FMSTR_ADDR fmstr_tsaBuffAddr; /* Dynamic TSA buffer address */ |
42 | static FMSTR_SIZE fmstr_tsaTableIndex; |
43 | |
44 | #endif |
45 | |
46 | /****************************************************************************** |
47 | * |
48 | * @brief TSA Initialization |
49 | * |
50 | ******************************************************************************/ |
51 | static FMSTR_BOOL _FMSTR_IsMemoryMapped(const char *type, unsigned long info); |
52 | |
53 | FMSTR_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 | |
70 | FMSTR_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 |
98 | FMSTR_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 | |
114 | FMSTR_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 | |
185 | FMSTR_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 | |
251 | FMSTR_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 */ |
288 | static FMSTR_BOOL FMSTR_CheckMemSpace(FMSTR_ADDR addrUser, |
289 | FMSTR_SIZE sizeUser, |
290 | FMSTR_ADDR addrSafe, |
291 | FMSTR_SIZE sizeSafe); |
292 | |
293 | static 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 | |
326 | FMSTR_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. */ |
449 | static 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 */ |
463 | const 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 */ |
493 | FMSTR_BOOL FMSTR_SetUpTsaBuff(FMSTR_ADDR buffAddr, FMSTR_SIZE buffSize) |
494 | { |
495 | FMSTR_UNUSED(buffAddr); |
496 | FMSTR_UNUSED(buffSize); |
497 | return FMSTR_FALSE; |
498 | } |
499 | |
500 | FMSTR_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 | |