Callisto4Bootloader: lib/c4_parser.c Source File

Callisto4Bootloader

c4_parser.c
Go to the documentation of this file.
1
14 /*******************************************************************************
15 * Includes
16 ******************************************************************************/
17
18 #include "c4_privilege_modes.h"
19 #include "c4_parser.h"
20 #include "c4_qspi.h"
21 #include "platform-memory-map.h"
22 #include "fsl_debug_console.h"
23 #include <string.h>
24 #include <stdio.h>
25 #include <ctype.h>
26
27 /*******************************************************************************
28 * External Definitions
29 ******************************************************************************/
30
31 extern const char *const config_addr;
32
33 /*******************************************************************************
34 * Defines
35 ******************************************************************************/
36
38 static const uint8_t CFG_VER_MAJ = 0;
39
41 static const uint8_t CFG_VER_MIN = 1;
42
44 static const uint32_t HASH_MULTIPLIER=37;
45
47 static const uint32_t HASH_SALT=0xfeedb4be;
48
49 /*******************************************************************************
50 * Structures
51 ******************************************************************************/
52
53 /*******************************************************************************
54 * Prototypes
55 ******************************************************************************/
56
60 void printConfigExample();
61
65 void printConfigHelp();
66
75 exit_code_t checkConfigVersion(const char *ver);
76
86 exit_code_t verifyConfigChecksum(const char * cfg_file, size_t file_len);
87
97 exit_code_t writeConfigChecksum(const char * cfg_file, size_t file_len);
98
109 static uint32_t calc_checksum(volatile const unsigned char *pvBase, uint32_t uiNumBytes);
110
111 /*******************************************************************************
112 * Variables
113 ******************************************************************************/
114
116 const char C4_parseStrings[NUM_PARSE_TERMS+1][32] = {
117 #define CALLISTO_PARSER(Id, Text, Desc, Exa) \
118 Text,
119 PARSER_KEYWORDS
120 #undef CALLISTO_PARSER
121 "Number of Parse terms"
122 };
123
124
126 static const char C4_helpStrings[NUM_PARSE_TERMS+1][512] = {
127 #define CALLISTO_PARSER(Id, Text, Desc, Exa) \
128 Desc,
129 PARSER_KEYWORDS
130 #undef CALLISTO_PARSER
131 "Total number of parse terms"
132 };
134 static const char C4_exampleStrings[NUM_PARSE_TERMS+1][64] = {
135 #define CALLISTO_PARSER(Id, Text, Desc, Exa) \
136 Text""Exa,
137 PARSER_KEYWORDS
138 #undef CALLISTO_PARSER
139 "N/A"
140 };
141
142 /*******************************************************************************
143 * Interface Implementation
144 ******************************************************************************/
145
146 exit_code_t GetConfig(const char *mem, uint32_t mem_len, E_parseIndices_t field, char *val)
147 {
148 exit_code_t rc = C4_ERR_FIELD_NOT_FOUND;
149
150 char str[mem_len];// Calculate maximum length field 526 (256 bytes + 1 (:) + 1 (data length) + 2 (address) + 1 (checksum) + 2 (\r\n) ) * 2
151
152 strncpy(str, (char *)mem, mem_len);
153
154 // Check that we have a printable character or space character at the beginning
155 // of the file string.
156 if (!isgraph((int)(*str)) && !isspace((int)(*str)))
157 {
158 printConfigHelp();
159 return C4_ERR_FILE_NOT_FOUND;
160 }
161
162 *val = '\0';
163 char * pch;
164
165 pch = strtok (str,"=\r\n");
166
167 // File must start with file identifier.
168 if (strcmp(pch, C4_parseStrings[C4_BOOT_CONFIG_PARSER_START]) == 0)
169 {
170 pch = strtok (NULL, "\r\n");
171 rc = checkConfigVersion(pch);
172 pch = strtok (NULL, "=\r\n");
173 }
174 while ((NULL != pch) && (C4_ERR_OK == rc))
175 {
176 E_parseIndices_t i;
177 for (i = C4_BOOT_CONFIG_PARSER_START; i <= C4_BOOT_CONFIG_PARSER_END; ++i)
178 {
179 // If this string matches the current index in the list of strings
180 if(strcmp(pch, C4_parseStrings[i]) == 0)
181 {
182 if (field == i) // this is the one that we are looking for
183 {
184 // get token and add to return string.
185 pch = strtok (NULL, "\r\n");
186 strcat(val, pch);
187 strcat(val, " ");
188 rc = C4_ERR_OK;
189 }
190 else if (C4_BOOT_CONFIG_PARSER_END == i)
191 {
192 // get checksum and test
193 pch = strtok (NULL, "=\r\n");
194 if (pch)
195 {
196 rc = ((C4_ERR_OK == rc) ?
197 verifyConfigChecksum(mem, (size_t)(pch - str)) :
198 rc);
199 }
200 }
201 else
202 {
203 // get next token
204 pch = strtok (NULL, "\r\n");
205 }
206 break;
207 }
208 }
209
210 // have we exhausted the list of parse items?
211 if (NUM_PARSE_TERMS == i)
212 {
213 printf("Field \"%s\"\n", pch);
214 printConfigHelp();
215 rc = C4_ERR_FIELD_UNDEFINED;
216 break;
217 }
218
219 pch = strtok (NULL,"=\r\n");
220 }
221
222 return rc;
223 }
224
225
226 /*******************************************************************************/
227
228 exit_code_t SetConfig(const char *mem, uint32_t mem_len, E_parseIndices_t field, const char *val/*, uint32_t val_len*/, file_op_t op)
229 {
230 exit_code_t rc = C4_ERR_FIELD_NOT_FOUND;
231
232 char str[mem_len];// Calculate maximum length field 526 (256 bytes + 1 (:) + 1 (data length) + 2 (address) + 1 (checksum) + 2 (\r\n) ) * 2
233
234 strncpy(str, (char *)mem, mem_len);
235
236 // Check that we have a printable character or space character at the beginning
237 // of the file string.
238 if (!isgraph((int)(*str))&& !isspace((int)(*str)))
239 return C4_ERR_FILE_NOT_FOUND;
240
241 char *pch;
242 C4_PRINT ("Splitting string \"%s\" into tokens:\n", str);
243 pch = strtok (str,"=\r\n");
244 // File must start with file identifier.
245 if (strcmp(pch, C4_parseStrings[C4_BOOT_CONFIG_PARSER_START]) == 0)
246 {
247 pch = strtok (NULL, "\r\n");
248 rc = checkConfigVersion(pch);
249 pch = strtok (NULL, "=\r\n");
250 }
251 while ((NULL != pch) && (C4_ERR_OK == rc))
252 {
253 E_parseIndices_t i;
254 for (i = C4_BOOT_CONFIG_PARSER_START; i <= C4_BOOT_CONFIG_PARSER_END; ++i)
255 {
256 // If this string matches the current index in the list of strings
257 if(strcmp(pch, C4_parseStrings[i]) == 0)
258 {
259 if (field == i) // this is the one that we are looking for
260 {
261 pch = strtok (NULL, "\r\n");
262 switch(op) {
263 case E_NOOP:
264 // do nothing
265 break;
266
267 case E_APPEND:
268 if (0 == strcmp(val, pch))
269 {
270 C4_PRINT("match found \"%s\" \"%s\"\n", val, pch);
271 op = E_NOOP;
272 break;
273 }
274 // replace existing value.
275 // fall through
276 case E_REPLACE:
277 if (strlen(pch) < strlen(val))
278 rc = C4_ERR_SYNTAX;
279 else
280 {
281 // strncpy(pch, val, mem_len);
282 uintptr_t dst = (uint32_t)mem + (uint32_t)pch - (uint32_t)str;
283 C4_PRINT("\"%s\"\n - writing \"%s\" %d bytes at 0x%08x\n",
284 pch, val, strlen(val), dst);
285 rc = C4_QSPI_write(dst, strlen(val), (const uint8_t *)val);
286 }
287 break;
288 case E_EXTEND:
289 if (0 == strcmp(val, pch))
290 {
291 C4_PRINT("match found \"%s\" \"%s\"\n", val, pch);
292 op = E_NOOP;
293 }
294 break;
295 case E_REMOVE:
296 // pch points to the start of the field value and is NULL terminated.
297 // Only delete it if the value matches.
298 if (0 != strcmp(val, pch))
299 {
300 // destination is the beginning of the current keyword
301 // Offset in QSPI (mem) is calculated by adding the difference between pch and str and subtracting the keyword length.
302 const uintptr_t dst = (const uintptr_t)mem + (const uintptr_t)pch - (const uintptr_t)str - strlen(C4_parseStrings[i]) - 1;
303
304 // source is the beginning of the next keyword
305 // Offset in QSPI (mem) is calculated by adding the difference between pch and str and adding the value length.
306 const char * src = (const char *)((const uintptr_t)mem + (const uintptr_t)pch - (const uintptr_t)str + strlen(pch) + 1);
307 C4_PRINT("removing from 0x%08x to 0x%p\r\n", dst, src);
308
309 // Add one to the string length to write NULL as well
310 rc = C4_QSPI_write(dst, strlen(src) + 1, (const uint8_t *)src);
311 }
312 break;
313
314 default:
315 // C4_PRINT(" field = \"%s\"\n", val);
316 break;
317 }
318 }
319 else if (C4_BOOT_CONFIG_PARSER_END == i)
320 {
321 // check whether there is anything left for append or extend operations to perform.
322 if ((E_EXTEND == op) || (E_APPEND == op))
323 {
324 // destination is the beginning of the current keyword
325 uintptr_t dst = (uint32_t)mem + (uint32_t)pch - (uint32_t)str;
326 // source is constructed from new keyword and remaining values.
327 char src[64] = "\0";
328 sprintf(src, "%s=%s\n%s", C4_parseStrings[field], val,(char *)dst);
329 C4_PRINT("appending from \"%s\" to 0x%08x\r\n", src, dst);
330
331 // Add one to the string length to write NULL as well
332 rc = C4_QSPI_write(dst, strlen(src) + 1, (const uint8_t *)src);
333 }
334 // get checksum and test
335 pch = strtok (NULL, "=\r\n");
336 if (pch)
337 {
338 rc = ((C4_ERR_OK == rc) ?
339 writeConfigChecksum(mem, (size_t)(pch - str)) :
340 rc);
341 }
342 }
343 else
344 {
345 // get next token
346 pch = strtok (NULL, "\r\n");
347 }
348 break;
349 }
350 }
351
352 // have we exhausted the list of parse items?
353 if (NUM_PARSE_TERMS == i)
354 {
355 printf("Field \"%s\"\n", pch);
356 printConfigHelp();
357 rc = C4_ERR_FIELD_UNDEFINED;
358 break;
359 }
360
361 pch = strtok (NULL,"=\r\n");
362 }
363 #if 0
364 while (pch != NULL)
365 {
366 // C4_PRINT ("%s\n",pch);
367 if (strcmp(pch, "RemsdaqBootConfig") == 0)
368 {
369 pch = strtok (NULL, "=\r\n");
370 C4_PRINT(" version = %s\n", pch);
371 rc = C4_ERR_VERSION;
372 }
373 else if (strcmp(pch, field) == 0)
374 {
375 pch = strtok (NULL, "\r\n");
376 // C4_PRINT(" field = \"%s\" -> \"%s\"\n", pch, val);
377 switch(op) {
378 case E_REPLACE:
379 if (strlen(pch) < strlen(val))
380 rc = C4_ERR_SYNTAX;
381 else
382 {
383 // strncpy(pch, val, mem_len);
384 uintptr_t dst = (uint32_t)mem + (uint32_t)pch - (uint32_t)str;
385 C4_PRINT("\"%s\"\n - writing \"%s\" %d bytes at 0x%08x\n",
386 pch, val, strlen(val), dst);
387 C4_QSPI_write(dst, strlen(val), (const uint8_t *)val);
388 }
389 break;
390 case E_APPEND:
391 // fall through
392 case E_EXTEND:
393 C4_PRINT(" operation %d Not Implemented\n", op);
394 rc = C4_ERR_NOT_IMPLEMENTED;
395 break;
396 default:
397 // C4_PRINT(" field = \"%s\"\n", val);
398 break;
399
400 }
401 rc = C4_ERR_OK;
402 }
403 else if (strcmp(pch, "EndConfig") == 0)
404 {
405 C4_PRINT("end of config\n");
406 break;
407 }
408
409 pch = strtok (NULL,"=\r\n");
410 }
411 #endif /* 0 */
412 return rc;
413 }
414
415
416 /*******************************************************************************
417 * Local Functions
418 ******************************************************************************/
419
420 void printConfigHelp()
421 {
422 printf("C4 Parse help:\n");
423 for (E_parseIndices_t i = 0; i < NUM_PARSE_TERMS; ++i)
424 {
425 printf("%s:\n\t %s\n", C4_parseStrings[i], C4_helpStrings[i]);
426 }
427
428 printConfigExample();
429 }
430
431 /*******************************************************************************/
432
433 void printConfigExample()
434 {
435 printf("CallistoBootloader_data to be located in QSPI Flash at 0x%08x\n -------\n", QSPI_BOOTLOADERx_CONFIG);
436 for (E_parseIndices_t i = 0; i < NUM_PARSE_TERMS; ++i)
437 {
438 printf("%s\n", C4_exampleStrings[i]);
439 }
440 }
441
442 /*******************************************************************************/
443
444 exit_code_t checkConfigVersion(const char *ver)
445 {
446 exit_code_t rc = C4_ERR_OK;
447
448 uint32_t version[3] = {0,0,0};
449
450 sscanf(ver, "%ld.%ld", version, version + 1);
451
452 if ((CFG_VER_MAJ != version[0]) ||
453 (CFG_VER_MIN < version[1]))
454 rc = C4_ERR_VERSION;
455
456 return rc;
457 }
458
459 /*******************************************************************************/
460
461 exit_code_t verifyConfigChecksum(const char * cfg_file, size_t file_len)
462 {
463 uint32_t chk = strtoul(cfg_file+file_len, NULL, 16);
464 uint32_t sum = calc_checksum((const uint8_t *)cfg_file, file_len);
465 PRINTF ("chksum 0x%08lx vs 0x%08lx\n", chk, sum);
466 return ((sum == chk) ? C4_ERR_OK : C4_ERR_FAILED);
467 }
468
469
470 /*******************************************************************************/
471
472 exit_code_t writeConfigChecksum(const char * cfg_file, size_t file_len)
473 {
474 exit_code_t rc = C4_ERR_OK;
475 uint32_t chk = strtoul(cfg_file+file_len, NULL, 16);
476
477 uint32_t sum = calc_checksum((const uint8_t *)cfg_file, file_len);
478 PRINTF ("chksum 0x%08lx vs 0x%08lx\n", chk, sum);
479 if (sum != chk)
480 {
481 uintptr_t dst = (uintptr_t)cfg_file + file_len;
482
483 char val[11] = {'\0'};
484 sprintf(val,"0x%lx", sum);
485 C4_PRINT("\n - writing \"%s\" %d bytes at 0x%08x\n",
486 val, strlen(val), dst);
487 rc = C4_QSPI_write(dst, strlen(val), (const uint8_t *)val);
488 }
489 return rc;
490 }
491
492
493 /*******************************************************************************/
494
495 static uint32_t calc_checksum(volatile const unsigned char *pvBase, uint32_t uiNumBytes)
496 {
497 unsigned int h = HASH_SALT;
498
499 for (; uiNumBytes--; ++pvBase)
500 h = HASH_MULTIPLIER * h + *pvBase;
501 return h;
502 }
HASH_SALT
static const uint32_t HASH_SALT
Salt for hash function.
Definition: c4_parser.c:44
PARSER_KEYWORDS
#define PARSER_KEYWORDS
definition of parser keywords.
Definition: c4_parser.h:34
NULL
#define NULL
Definition: bootloader_common.h:26
E_APPEND
Definition: c4_parser.h:73
file_op_t
file_op_t
file operation type.
Definition: c4_parser.h:70
SetConfig
exit_code_t SetConfig(const char *mem, uint32_t mem_len, E_parseIndices_t field, const char *val, file_op_t op)
Set value in the specified memory location.
Definition: c4_parser.c:221
NUM_PARSE_TERMS
Definition: c4_parser.h:66
printConfigHelp
void printConfigHelp()
Print out config file description.
Definition: c4_parser.c:412
C4_exampleStrings
static const char C4_exampleStrings[NUM_PARSE_TERMS+1][64]
Array of strings to construct example config file.
Definition: c4_parser.c:128
i
volatile int i
Definition: excep_test.c:17
C4_parseStrings
const char C4_parseStrings[NUM_PARSE_TERMS+1][32]
Array of strings to use in parser.
Definition: c4_parser.c:110
PRINTF
#define PRINTF(f,...)
Definition: c4_privilege_modes.c:20
E_EXTEND
Definition: c4_parser.h:74
GetConfig
exit_code_t GetConfig(const char *mem, uint32_t mem_len, E_parseIndices_t field, char *val)
Parse the specified memory location.
Definition: c4_parser.c:139
C4_QSPI_write
exit_code_t C4_QSPI_write(uintptr_t addr, size_t len, const uint8_t *pData)
Write data to QSPI flash memory.
Definition: c4_qspi.c:230
c4_qspi.h
Interface to QSPI Flash.
exit_code_t
exit_code_t
Enumeration of error codes.
Definition: c4_error_codes.h:96
E_parseIndices_t
E_parseIndices_t
Enumeration of parser items.
Definition: c4_parser.h:59
CFG_VER_MAJ
static const uint8_t CFG_VER_MAJ
Config file major version numbers.
Definition: c4_parser.c:35
E_REMOVE
Definition: c4_parser.h:75
checkConfigVersion
exit_code_t checkConfigVersion(const char *ver)
Check the file version.
Definition: c4_parser.c:436
C4_PRINT
#define C4_PRINT(...)
Wrapper to call print as a privileged operation.
Definition: c4_privilege_modes.h:109
E_NOOP
Definition: c4_parser.h:71
calc_checksum
static uint32_t calc_checksum(volatile const unsigned char *pvBase, uint32_t uiNumBytes)
Calculate a config header checksum.
Definition: c4_parser.c:487
config_addr
const char *const config_addr
CFG_VER_MIN
static const uint8_t CFG_VER_MIN
Config file minor version number.
Definition: c4_parser.c:38
HASH_MULTIPLIER
static const uint32_t HASH_MULTIPLIER
Multiplier for hash function.
Definition: c4_parser.c:41
printConfigExample
void printConfigExample()
Print out config file example.
Definition: c4_parser.c:425
c4_parser.h
Interface to simple parser.
c4_privilege_modes.h
Provide mechanisms to specify which stack to use and for the processor to operate in Unprivileged mod...
writeConfigChecksum
exit_code_t writeConfigChecksum(const char *cfg_file, size_t file_len)
Write checksum.
Definition: c4_parser.c:464
verifyConfigChecksum
exit_code_t verifyConfigChecksum(const char *cfg_file, size_t file_len)
Verify the checksum.
Definition: c4_parser.c:453
E_REPLACE
Definition: c4_parser.h:72
C4_helpStrings
static const char C4_helpStrings[NUM_PARSE_TERMS+1][512]
Array of description strings to use in parser help.
Definition: c4_parser.c:120