blob: 49d7b4a193e8cbdef3fcecb88a6bbad41e55b9cd [file] [log] [blame]
Peer Chen8d782ee2011-01-18 21:34:18 -05001/**
2 * Copyright (c) 2011 NVIDIA Corporation. All rights reserved.
3 *
4 * See file CREDITS for list of people who contributed to this
5 * project.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of
10 * the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20 * MA 02111-1307 USA
21 */
22
23/*
24 * parse.c - Parsing support for the cbootimage tool
25 */
26
27/*
28 * TODO / Notes
29 * - Add doxygen commentary
30 * - Do we have endian issues to deal with?
31 * - Add support for device configuration data
32 * - Add support for bad blocks
33 * - Add support for different allocation modes/strategies
34 * - Add support for multiple BCTs in journal block
35 * - Add support for other missing features.
36 */
37
38#include "parse.h"
39#include "cbootimage.h"
40#include "data_layout.h"
41#include "crypto.h"
42#include "set.h"
43
44/*
45 * Function prototypes
46 *
47 * ParseXXX() parses XXX in the input
48 * SetXXX() sets state based on the parsing results but does not perform
49 * any parsing of its own
50 * A ParseXXX() function may call other parse functions and set functions.
51 * A SetXXX() function may not call any parseing functions.
52 */
53
54static char *parse_u32(char *statement, u_int32_t *val);
Peer Chen7557d9b2011-02-24 09:29:23 -080055static char *parse_u8(char *statement, u_int32_t *val);
Peer Chen8d782ee2011-01-18 21:34:18 -050056static char *parse_filename(char *statement, char *name, int chars_remaining);
Peer Chen7557d9b2011-02-24 09:29:23 -080057static char *parse_enum(build_image_context *context,
58 char *statement,
59 enum_item *table,
60 u_int32_t *val);
61static char
62*parse_field_name(char *rest, field_item *field_table, field_item **field);
63static char
64*parse_field_value(build_image_context *context,
65 char *rest,
66 field_item *field,
67 u_int32_t *value);
Peer Chen8d782ee2011-01-18 21:34:18 -050068static int
69parse_array(build_image_context *context, parse_token token, char *rest);
70static int
71parse_bootloader(build_image_context *context, parse_token token, char *rest);
72static int
73parse_value_u32(build_image_context *context, parse_token token, char *rest);
74static int
75parse_bct_file(build_image_context *context, parse_token token, char *rest);
76static int
77parse_addon(build_image_context *context, parse_token token, char *rest);
78static char *parse_string(char *statement, char *uname, int chars_remaining);
79static char
80*parse_end_state(char *statement, char *uname, int chars_remaining);
Peer Chen7557d9b2011-02-24 09:29:23 -080081static int
82parse_dev_param(build_image_context *context, parse_token token, char *rest);
Peer Chen3a834ed2011-03-04 09:30:05 -080083static int
84parse_sdram_param(build_image_context *context, parse_token token, char *rest);
Peer Chen7557d9b2011-02-24 09:29:23 -080085
Peer Chen8d782ee2011-01-18 21:34:18 -050086static int process_statement(build_image_context *context, char *statement);
87
Peer Chen7557d9b2011-02-24 09:29:23 -080088static enum_item s_devtype_table[] =
89{
90 { "NvBootDevType_Sdmmc", nvbct_lib_id_dev_type_sdmmc },
91 { "NvBootDevType_Spi", nvbct_lib_id_dev_type_spi },
Peer Chen053d5782011-03-03 10:12:58 -080092 { "NvBootDevType_Nand", nvbct_lib_id_dev_type_nand },
Peer Chen7557d9b2011-02-24 09:29:23 -080093 { "Sdmmc", nvbct_lib_id_dev_type_sdmmc },
94 { "Spi", nvbct_lib_id_dev_type_spi },
Peer Chen053d5782011-03-03 10:12:58 -080095 { "Nand", nvbct_lib_id_dev_type_nand },
Peer Chen7557d9b2011-02-24 09:29:23 -080096
97 { NULL, 0 }
98};
99
100static enum_item s_sdmmc_data_width_table[] =
101{
102 {
103 "NvBootSdmmcDataWidth_4Bit",
104 nvbct_lib_id_sdmmc_data_width_4bit
105 },
106 {
107 "NvBootSdmmcDataWidth_8Bit",
108 nvbct_lib_id_sdmmc_data_width_8bit
109 },
110 { "4Bit", nvbct_lib_id_sdmmc_data_width_4bit },
111 { "8Bit", nvbct_lib_id_sdmmc_data_width_8bit },
112 { NULL, 0 }
113};
114
115static enum_item s_spi_clock_source_table[] =
116{
117 {
118 "NvBootSpiClockSource_PllPOut0",
119 nvbct_lib_id_spi_clock_source_pllp_out0
120 },
121 {
122 "NvBootSpiClockSource_PllCOut0",
123 nvbct_lib_id_spi_clock_source_pllc_out0
124 },
125 {
126 "NvBootSpiClockSource_PllMOut0",
127 nvbct_lib_id_spi_clock_source_pllm_out0
128 },
129 {
130 "NvBootSpiClockSource_ClockM",
131 nvbct_lib_id_spi_clock_source_clockm
132 },
133
134 { "ClockSource_PllPOut0", nvbct_lib_id_spi_clock_source_pllp_out0 },
135 { "ClockSource_PllCOut0", nvbct_lib_id_spi_clock_source_pllc_out0 },
136 { "ClockSource_PllMOut0", nvbct_lib_id_spi_clock_source_pllm_out0 },
137 { "ClockSource_ClockM", nvbct_lib_id_spi_clock_source_clockm },
138
139
140 { "PllPOut0", nvbct_lib_id_spi_clock_source_pllp_out0 },
141 { "PllCOut0", nvbct_lib_id_spi_clock_source_pllc_out0 },
142 { "PllMOut0", nvbct_lib_id_spi_clock_source_pllm_out0 },
143 { "ClockM", nvbct_lib_id_spi_clock_source_clockm },
144
145 { NULL, 0 }
146};
147
Peer Chen3a834ed2011-03-04 09:30:05 -0800148static enum_item s_nvboot_memory_type_table[] =
149{
150 { "NvBootMemoryType_None", nvbct_lib_id_memory_type_none },
151 { "NvBootMemoryType_Ddr2", nvbct_lib_id_memory_type_ddr2 },
152 { "NvBootMemoryType_Ddr", nvbct_lib_id_memory_type_ddr },
153 { "NvBootMemoryType_LpDdr2", nvbct_lib_id_memory_type_lpddr2 },
154 { "NvBootMemoryType_LpDdr", nvbct_lib_id_memory_type_lpddr },
155
156 { "None", nvbct_lib_id_memory_type_none },
157 { "Ddr2", nvbct_lib_id_memory_type_ddr2 },
158 { "Ddr", nvbct_lib_id_memory_type_ddr },
159 { "LpDdr2", nvbct_lib_id_memory_type_lpddr2 },
160 { "LpDdr", nvbct_lib_id_memory_type_lpddr },
161
162 { NULL, 0 }
163};
164
165static field_item s_sdram_field_table[] =
166{
167 { "MemoryType", token_memory_type,
168 field_type_enum, s_nvboot_memory_type_table },
169 { "PllMChargePumpSetupControl", token_pllm_charge_pump_setup_ctrl,
170 field_type_u32, NULL },
171 { "PllMLoopFilterSetupControl", token_pllm_loop_filter_setup_ctrl,
172 field_type_u32, NULL },
173 { "PllMInputDivider", token_pllm_input_divider,
174 field_type_u32, NULL },
175 { "PllMFeedbackDivider", token_pllm_feedback_divider,
176 field_type_u32, NULL },
177 { "PllMPostDivider", token_pllm_post_divider,
178 field_type_u32, NULL },
179 { "PllMStableTime", token_pllm_stable_time,
180 field_type_u32, NULL },
181 { "EmcClockDivider", token_emc_clock_divider,
182 field_type_u32, NULL },
183 { "EmcAutoCalInterval", token_emc_auto_cal_interval,
184 field_type_u32, NULL },
185 { "EmcAutoCalConfig", token_emc_auto_cal_config,
186 field_type_u32, NULL },
187 { "EmcAutoCalWait", token_emc_auto_cal_wait,
188 field_type_u32, NULL },
189 { "EmcPinProgramWait", token_emc_pin_program_wait,
190 field_type_u32, NULL },
191 { "EmcRc", token_emc_rc,
192 field_type_u32, NULL },
193 { "EmcRfc", token_emc_rfc,
194 field_type_u32, NULL },
195 { "EmcRas", token_emc_ras,
196 field_type_u32, NULL },
197 { "EmcRp", token_emc_rp,
198 field_type_u32, NULL },
199 { "EmcR2w", token_emc_r2w,
200 field_type_u32, NULL },
201 { "EmcW2r", token_emc_w2r,
202 field_type_u32, NULL },
203 { "EmcR2p", token_emc_r2p,
204 field_type_u32, NULL },
205 { "EmcW2p", token_emc_w2p,
206 field_type_u32, NULL },
207 { "EmcRrd", token_emc_rrd,
208 field_type_u32, NULL },
209 { "EmcRdRcd", token_emc_rd_rcd,
210 field_type_u32, NULL },
211 { "EmcWrRcd", token_emc_wr_rcd,
212 field_type_u32, NULL },
213 { "EmcRext", token_emc_rext,
214 field_type_u32, NULL },
215 { "EmcWdv", token_emc_wdv,
216 field_type_u32, NULL },
217 { "EmcQUseExtra", token_emc_quse_extra,
218 field_type_u32, NULL },
219 { "EmcQUse", token_emc_quse,
220 field_type_u32, NULL },
221 { "EmcQRst", token_emc_qrst,
222 field_type_u32, NULL },
223 { "EmcQSafe", token_emc_qsafe,
224 field_type_u32, NULL },
225 { "EmcRdv", token_emc_rdv,
226 field_type_u32, NULL },
227 { "EmcRefresh", token_emc_refresh,
228 field_type_u32, NULL },
229 { "EmcBurstRefreshNum", token_emc_burst_refresh_num,
230 field_type_u32, NULL },
231 { "EmcPdEx2Wr", token_emc_pdex2wr,
232 field_type_u32, NULL },
233 { "EmcPdEx2Rd", token_emc_pdex2rd,
234 field_type_u32, NULL },
235 { "EmcPChg2Pden", token_emc_pchg2pden,
236 field_type_u32, NULL },
237 { "EmcAct2Pden", token_emc_act2pden,
238 field_type_u32, NULL },
239 { "EmcAr2Pden", token_emc_ar2pden,
240 field_type_u32, NULL },
241 { "EmcRw2Pden", token_emc_rw2pden,
242 field_type_u32, NULL },
243 { "EmcTxsr", token_emc_txsr,
244 field_type_u32, NULL },
245 { "EmcTcke", token_emc_tcke,
246 field_type_u32, NULL },
247 { "EmcTfaw", token_emc_tfaw,
248 field_type_u32, NULL },
249 { "EmcTrpab", token_emc_trpab,
250 field_type_u32, NULL },
251 { "EmcTClkStable", token_emc_tclkstable,
252 field_type_u32, NULL },
253 { "EmcTClkStop", token_emc_tclkstop,
254 field_type_u32, NULL },
255 { "EmcTRefBw", token_emc_trefbw,
256 field_type_u32, NULL },
257 { "EmcFbioCfg1", token_emc_fbio_cfg1,
258 field_type_u32, NULL },
259 { "EmcFbioDqsibDlyMsb", token_emc_fbio_dqsib_dly_msb,
260 field_type_u32, NULL },
261 { "EmcFbioDqsibDly", token_emc_fbio_dqsib_dly,
262 field_type_u32, NULL },
263 { "EmcFbioQuseDlyMsb", token_emc_fbio_quse_dly_msb,
264 field_type_u32, NULL },
265 { "EmcFbioQuseDly", token_emc_fbio_quse_dly,
266 field_type_u32, NULL },
267 { "EmcFbioCfg5", token_emc_fbio_cfg5,
268 field_type_u32, NULL },
269 { "EmcFbioCfg6", token_emc_fbio_cfg6,
270 field_type_u32, NULL },
271 { "EmcFbioSpare", token_emc_fbio_spare,
272 field_type_u32, NULL },
273 { "EmcMrsResetDllWait", token_emc_mrs_reset_dll_wait,
274 field_type_u32, NULL },
275 { "EmcMrsResetDll", token_emc_mrs_reset_dll,
276 field_type_u32, NULL },
277 { "EmcMrsDdr2DllReset", token_emc_mrs_ddr2_dll_reset,
278 field_type_u32, NULL },
279 { "EmcMrs", token_emc_mrs,
280 field_type_u32, NULL },
281 { "EmcEmrsEmr2", token_emc_emrs_emr2,
282 field_type_u32, NULL },
283 { "EmcEmrsEmr3", token_emc_emrs_emr3,
284 field_type_u32, NULL },
285 { "EmcEmrsDdr2DllEnable", token_emc_emrs_ddr2_dll_enable,
286 field_type_u32, NULL },
287 { "EmcEmrsDdr2OcdCalib", token_emc_emrs_ddr2_ocd_calib,
288 field_type_u32, NULL },
289 { "EmcEmrs", token_emc_emrs,
290 field_type_u32, NULL },
291 { "EmcMrw1", token_emc_mrw1,
292 field_type_u32, NULL },
293 { "EmcMrw2", token_emc_mrw2,
294 field_type_u32, NULL },
295 { "EmcMrw3", token_emc_mrw3,
296 field_type_u32, NULL },
297 { "EmcMrwResetCommand", token_emc_mrw_reset_command,
298 field_type_u32, NULL },
299 { "EmcMrwResetNInitWait", token_emc_mrw_reset_ninit_wait,
300 field_type_u32, NULL },
301 { "EmcAdrCfg1", token_emc_adr_cfg1,
302 field_type_u32, NULL },
303 { "EmcAdrCfg", token_emc_adr_cfg,
304 field_type_u32, NULL },
305 { "McEmemCfg", token_mc_emem_Cfg,
306 field_type_u32, NULL },
307 { "McLowLatencyConfig", token_mc_lowlatency_config,
308 field_type_u32, NULL },
309 { "EmcCfg2", token_emc_cfg2,
310 field_type_u32, NULL },
311 { "EmcCfgDigDll", token_emc_cfg_dig_dll,
312 field_type_u32, NULL },
313 { "EmcCfgClktrim0", token_emc_cfg_clktrim0,
314 field_type_u32, NULL },
315 { "EmcCfgClktrim1", token_emc_cfg_clktrim1,
316 field_type_u32, NULL },
317 { "EmcCfgClktrim2", token_emc_cfg_clktrim2,
318 field_type_u32, NULL },
319 { "EmcCfg", token_emc_cfg,
320 field_type_u32, NULL },
321 { "EmcDbg", token_emc_dbg,
322 field_type_u32, NULL },
323 { "AhbArbitrationXbarCtrl", token_ahb_arbitration_xbar_ctrl,
324 field_type_u32, NULL },
325 { "EmcDllXformDqs", token_emc_dll_xform_dqs,
326 field_type_u32, NULL },
327 { "EmcDllXformQUse", token_emc_dll_xform_quse,
328 field_type_u32, NULL },
329 { "WarmBootWait", token_warm_boot_wait,
330 field_type_u32, NULL },
331 { "EmcCttTermCtrl", token_emc_ctt_term_ctrl,
332 field_type_u32, NULL },
333 { "EmcOdtWrite", token_emc_odt_write,
334 field_type_u32, NULL },
335 { "EmcOdtRead", token_emc_odt_read,
336 field_type_u32, NULL },
337 { "EmcZcalRefCnt", token_emc_zcal_ref_cnt,
338 field_type_u32, NULL },
339 { "EmcZcalWaitCnt", token_emc_zcal_wait_cnt,
340 field_type_u32, NULL },
341 { "EmcZcalMrwCmd", token_emc_zcal_mrw_cmd,
342 field_type_u32, NULL },
343 { "EmcMrwZqInitDev0", token_emc_mrw_zq_init_dev0,
344 field_type_u32, NULL },
345 { "EmcMrwZqInitDev1", token_emc_mrw_zq_init_dev1,
346 field_type_u32, NULL },
347 { "EmcMrwZqInitWait", token_emc_mrw_zq_init_wait,
348 field_type_u32, NULL },
349 { "EmcDdr2Wait", token_emc_ddr2_wait,
350 field_type_u32, NULL },
351 { "PmcDdrPwr", token_pmc_ddr_pwr,
352 field_type_u32, NULL },
353 { "ApbMiscGpXm2CfgAPadCtrl", token_apb_misc_gp_xm2cfga_pad_ctrl,
354 field_type_u32, NULL },
355 { "ApbMiscGpXm2CfgCPadCtrl2", token_apb_misc_gp_xm2cfgc_pad_ctrl2,
356 field_type_u32, NULL },
357 { "ApbMiscGpXm2CfgCPadCtrl", token_apb_misc_gp_xm2cfgc_pad_ctrl,
358 field_type_u32, NULL },
359 { "ApbMiscGpXm2CfgDPadCtrl2", token_apb_misc_gp_xm2cfgd_pad_ctrl2,
360 field_type_u32, NULL },
361 { "ApbMiscGpXm2CfgDPadCtrl", token_apb_misc_gp_xm2cfgd_pad_ctrl,
362 field_type_u32, NULL },
363 { "ApbMiscGpXm2ClkCfgPadCtrl", token_apb_misc_gp_xm2clkcfg_Pad_ctrl,
364 field_type_u32, NULL },
365 { "ApbMiscGpXm2CompPadCtrl", token_apb_misc_gp_xm2comp_pad_ctrl,
366 field_type_u32, NULL },
367 { "ApbMiscGpXm2VttGenPadCtrl", token_apb_misc_gp_xm2vttgen_pad_ctrl
368 ,field_type_u32, NULL },
369
370 { NULL, 0, 0, NULL }
371};
372
Peer Chen053d5782011-03-03 10:12:58 -0800373static field_item s_nand_table[] =
374{
375 { "ClockDivider", token_clock_divider, field_type_u32, NULL },
376 /* Note: NandTiming2 must appear before NandTiming, because NandTiming
377 * is a prefix of NandTiming2 and would otherwise match first.
378 */
379 { "NandTiming2", token_nand_timing2, field_type_u32, NULL },
380 { "NandTiming", token_nand_timing, field_type_u32, NULL },
381 { "BlockSizeLog2", token_block_size_log2, field_type_u32, NULL },
382 { "PageSizeLog2", token_page_size_log2, field_type_u32, NULL },
383 { NULL, 0, 0, NULL }
384};
385
Peer Chen7557d9b2011-02-24 09:29:23 -0800386static field_item s_sdmmc_table[] =
387{
388 { "ClockDivider", token_clock_divider, field_type_u32, NULL },
389 { "DataWidth", token_data_width,
390 field_type_enum, s_sdmmc_data_width_table },
391 { "MaxPowerClassSupported", token_max_power_class_supported,
392 field_type_u32, NULL },
393
394 { NULL, 0, 0, NULL }
395};
396
397static field_item s_spiflash_table[] =
398{
399 { "ReadCommandTypeFast", token_read_command_type_fast,
400 field_type_u8, NULL },
401 { "ClockDivider", token_clock_divider, field_type_u8, NULL },
402 { "ClockSource", token_clock_source,
403 field_type_enum, s_spi_clock_source_table },
404
405 { NULL, 0, 0, NULL }
406};
407
408static parse_subfield_item s_device_type_table[] =
409{
Peer Chen053d5782011-03-03 10:12:58 -0800410 { "NandParams.", token_nand_params,
411 s_nand_table, set_nand_param },
Peer Chen7557d9b2011-02-24 09:29:23 -0800412 { "SdmmcParams.", token_sdmmc_params,
413 s_sdmmc_table, set_sdmmc_param },
414 { "SpiFlashParams.", token_spiflash_params,
415 s_spiflash_table, set_spiflash_param },
416
417 { NULL, 0, NULL }
418};
419
Peer Chen8d782ee2011-01-18 21:34:18 -0500420static parse_item s_top_level_items[] =
421{
Peer Chen053d5782011-03-03 10:12:58 -0800422 { "Bctfile=", token_bct_file, parse_bct_file },
423 { "Attribute=", token_attribute, parse_value_u32 },
424 { "Attribute[", token_attribute, parse_array },
425 { "PageSize=", token_page_size, parse_value_u32 },
426 { "BlockSize=", token_block_size, parse_value_u32 },
427 { "PartitionSize=", token_partition_size, parse_value_u32 },
428 { "DevType[", token_dev_type, parse_array },
429 { "DeviceParam[", token_dev_param, parse_dev_param },
Peer Chen3a834ed2011-03-04 09:30:05 -0800430 { "SDRAM[", token_sdram, parse_sdram_param },
Peer Chen053d5782011-03-03 10:12:58 -0800431 { "BootLoader=", token_bootloader, parse_bootloader },
432 { "Redundancy=", token_redundancy, parse_value_u32 },
433 { "Version=", token_version, parse_value_u32 },
434 { "AddOn[", token_addon, parse_addon },
Peer Chen8d782ee2011-01-18 21:34:18 -0500435 { NULL, 0, NULL } /* Must be last */
436};
437
438/* Macro to simplify parser code a bit. */
439#define PARSE_COMMA(x) if (*rest != ',') return (x); rest++
440
441/* This parsing code was initially borrowed from nvcamera_config_parse.c. */
442/* Returns the address of the character after the parsed data. */
443static char *
444parse_u32(char *statement, u_int32_t *val)
445{
446 u_int32_t value = 0;
447
448 while (*statement=='0') {
449 statement++;
450 }
451
452 if (*statement=='x' || *statement=='X') {
453 statement++;
454 while (((*statement >= '0') && (*statement <= '9')) ||
455 ((*statement >= 'a') && (*statement <= 'f')) ||
456 ((*statement >= 'A') && (*statement <= 'F'))) {
457 value *= 16;
458 if ((*statement >= '0') && (*statement <= '9')) {
459 value += (*statement - '0');
460 } else if ((*statement >= 'A') &&
461 (*statement <= 'F')) {
462 value += ((*statement - 'A')+10);
463 } else {
464 value += ((*statement - 'a')+10);
465 }
466 statement++;
467 }
468 } else {
469 while (*statement >= '0' && *statement <= '9') {
470 value = value*10 + (*statement - '0');
471 statement++;
472 }
473 }
474 *val = value;
475 return statement;
476}
477
Peer Chen7557d9b2011-02-24 09:29:23 -0800478char *
479parse_u8(char *statement, u_int32_t *val)
480{
481 char *retval;
482
483 retval = parse_u32(statement, val);
484
485 if (*val > 0xff) {
486 printf("Warning: Parsed 8-bit value that exceeded 8-bits.\n");
487 printf(" Parsed value = %d. Remaining text = %s\n",
488 *val, retval);
489 }
490
491 return retval;
492}
493
494
Peer Chen8d782ee2011-01-18 21:34:18 -0500495/* This parsing code was initially borrowed from nvcamera_config_parse.c. */
496/* Returns the address of the character after the parsed data. */
497static char *
498parse_filename(char *statement, char *name, int chars_remaining)
499{
500 while (((*statement >= '0') && (*statement <= '9')) ||
501 ((*statement >= 'a') && (*statement <= 'z')) ||
502 ((*statement >= 'A') && (*statement <= 'Z')) ||
503 (*statement == '\\') ||
504 (*statement == '/' ) ||
505 (*statement == '~' ) ||
506 (*statement == '_' ) ||
507 (*statement == '-' ) ||
508 (*statement == '+' ) ||
509 (*statement == ':' ) ||
510 (*statement == '.' )) {
511 /* Check if the filename buffer is out of space, preserving one
512 * character to null terminate the string.
513 */
514 chars_remaining--;
515
516 if (chars_remaining < 1)
517 return NULL;
518 *name++ = *statement++;
519 }
520
521 /* Null terminate the filename. */
522 *name = '\0';
523
524 return statement;
525}
526
Peer Chen7557d9b2011-02-24 09:29:23 -0800527static char
528*parse_field_name(char *rest, field_item *field_table, field_item **field)
529{
530 u_int32_t i;
531 u_int32_t field_name_len = 0;
532
533 assert(field_table != NULL);
534 assert(rest != NULL);
535 assert(field != NULL);
536
537 while(*(rest + field_name_len) != '=')
538 field_name_len++;
539
540 /* Parse the field name. */
541 for (i = 0; field_table[i].name != NULL; i++) {
542 if ((strlen(field_table[i].name) == field_name_len) &&
543 !strncmp(field_table[i].name,
544 rest,
545 field_name_len)) {
546
547 *field = &(field_table[i]);
548 rest = rest + field_name_len;
549 return rest;
550 }
551 }
552
553 /* Field wasn't found or a parse error occurred. */
554 return NULL;
555}
556
557static char
558*parse_field_value(build_image_context *context,
559 char *rest,
560 field_item *field,
561 u_int32_t *value)
562{
563 assert(rest != NULL);
564 assert(field != NULL);
565 assert((field->type != field_type_enum)
566 || (field->enum_table != NULL));
567
568 switch (field->type) {
569 case field_type_enum:
570 rest = parse_enum(context, rest, field->enum_table, value);
571 break;
572
573 case field_type_u32:
574 rest = parse_u32(rest, value);
575 break;
576
577 case field_type_u8:
578 rest = parse_u8(rest, value);
579 break;
580
581 default:
582 printf("Unexpected field type %d at line %d\n",
583 field->type, __LINE__);
584 rest = NULL;
585 break;
586 }
587
588 return rest;
589}
590
591static char *
592parse_enum(build_image_context *context,
593 char *statement,
594 enum_item *table,
595 u_int32_t *val)
596{
597 int i;
598 char *rest;
599 int e;
600
601 for (i = 0; table[i].name != NULL; i++) {
602 if (!strncmp(table[i].name, statement,
603 strlen(table[i].name))) {
604 /* Lookup the correct value for the token. */
605 e = context->bctlib.get_value(table[i].value,
606 val, context->bct);
607 if (e) {
608 printf("Error looking up token %d.\n", table[i].value);
609 printf("\"%s\" is not valid for this chip.\n",
610 table[i].name);
611 *val = -1;
612 }
613
614 rest = statement + strlen(table[i].name);
615 return rest;
616 }
617 }
618 return parse_u32(statement, val);
619
620}
Peer Chen8d782ee2011-01-18 21:34:18 -0500621/*
622 * parse_bootloader(): Processes commands to set a bootloader.
623 */
624static int parse_bootloader(build_image_context *context,
625 parse_token token,
626 char *rest)
627{
628 char filename[MAX_BUFFER];
629 char e_state[MAX_STR_LEN];
630 u_int32_t load_addr;
631 u_int32_t entry_point;
632
633 assert(context != NULL);
634 assert(rest != NULL);
635
Peer Chen7557d9b2011-02-24 09:29:23 -0800636 if (context->generate_bct != 0)
637 return 0;
Peer Chen8d782ee2011-01-18 21:34:18 -0500638 /* Parse the file name. */
639 rest = parse_filename(rest, filename, MAX_BUFFER);
640 if (rest == NULL)
641 return 1;
642
643 PARSE_COMMA(1);
644
645 /* Parse the load address. */
646 rest = parse_u32(rest, &load_addr);
647 if (rest == NULL)
648 return 1;
649
650 PARSE_COMMA(1);
651
652 /* Parse the entry point. */
653 rest = parse_u32(rest, &entry_point);
654 if (rest == NULL)
655 return 1;
656
657 PARSE_COMMA(1);
658
659 /* Parse the end state. */
660 rest = parse_end_state(rest, e_state, MAX_STR_LEN);
661 if (rest == NULL)
662 return 1;
663 if (strncmp(e_state, "Complete", strlen("Complete")))
664 return 1;
665
666 /* Parsing has finished - set the bootloader */
667 return set_bootloader(context, filename, load_addr, entry_point);
668}
669
670/*
671 * parse_array(): Processes commands to set an array value.
672 */
673static int
674parse_array(build_image_context *context, parse_token token, char *rest)
675{
676 u_int32_t index;
677 u_int32_t value;
678
679 assert(context != NULL);
680 assert(rest != NULL);
681
682 /* Parse the index. */
683 rest = parse_u32(rest, &index);
684 if (rest == NULL)
685 return 1;
686
687 /* Parse the closing bracket. */
688 if (*rest != ']')
689 return 1;
690 rest++;
691
692 /* Parse the equals sign.*/
693 if (*rest != '=')
694 return 1;
695 rest++;
696
697 /* Parse the value based on the field table. */
698 switch(token) {
Peer Chen7557d9b2011-02-24 09:29:23 -0800699 case token_attribute:
700 rest = parse_u32(rest, &value);
701 break;
702 case token_dev_type:
703 rest = parse_enum(context, rest, s_devtype_table, &value);
704 break;
Peer Chen8d782ee2011-01-18 21:34:18 -0500705
Peer Chen7557d9b2011-02-24 09:29:23 -0800706 default:
707 /* Unknown token */
708 return 1;
Peer Chen8d782ee2011-01-18 21:34:18 -0500709 }
710
711 if (rest == NULL)
712 return 1;
713
714 /* Store the result. */
715 return context_set_array(context, index, token, value);
716}
717
718/*
719 * parse_value_u32(): General handler for setting u_int32_t values in config files.
720 */
721static int parse_value_u32(build_image_context *context,
722 parse_token token,
723 char *rest)
724{
725 u_int32_t value;
726
727 assert(context != NULL);
728 assert(rest != NULL);
729
730 rest = parse_u32(rest, &value);
731 if (rest == NULL)
732 return 1;
733
734 return context_set_value(context, token, value);
735}
736
737static int
738parse_bct_file(build_image_context *context, parse_token token, char *rest)
739{
740 char filename[MAX_BUFFER];
741
742 assert(context != NULL);
743 assert(rest != NULL);
744
745 /* Parse the file name. */
746 rest = parse_filename(rest, filename, MAX_BUFFER);
747 if (rest == NULL)
748 return 1;
749
750 /* Parsing has finished - set the bctfile */
751 context->bct_filename = filename;
752 /* Read the bct file to buffer */
753 read_bct_file(context);
754 return 0;
755}
756
757static char *
758parse_string(char *statement, char *uname, int chars_remaining)
759{
760 memset(uname, 0, chars_remaining);
761 while (((*statement >= '0') && (*statement <= '9')) ||
762 ((*statement >= 'A') && (*statement <= 'Z')) ||
763 ((*statement >= 'a') && (*statement <= 'z'))) {
764
765 *uname++ = *statement++;
766 if (--chars_remaining < 0) {
767 printf("String length beyond the boundary!!!");
768 return NULL;
769 }
770 }
771 *uname = '\0';
772 return statement;
773}
774
775static char *
776parse_end_state(char *statement, char *uname, int chars_remaining)
777{
778 while (((*statement >= 'a') && (*statement <= 'z')) ||
779 ((*statement >= 'A') && (*statement <= 'Z'))) {
780
781 *uname++ = *statement++;
782 if (--chars_remaining < 0)
783 return NULL;
784 }
785 *uname = '\0';
786 return statement;
787}
788
789
790/* Parse the addon component */
791static int
792parse_addon(build_image_context *context, parse_token token, char *rest)
793{
794 char filename[MAX_BUFFER];
795 char u_name[4];
796 char e_state[MAX_STR_LEN];
797 u_int32_t index;
798 u_int32_t item_attr;
799 u_int32_t others;
800 char other_str[MAX_STR_LEN];
801
802 assert(context != NULL);
803 assert(rest != NULL);
804
805 /* Parse the index. */
806 rest = parse_u32(rest, &index);
807 if (rest == NULL)
808 return 1;
809
810 /* Parse the closing bracket. */
811 if (*rest != ']')
812 return 1;
813 rest++;
814
815 /* Parse the equals sign.*/
816 if (*rest != '=')
817 return 1;
818 rest++;
819
820 rest = parse_filename(rest, filename, MAX_BUFFER);
821 if (rest == NULL)
822 return 1;
823 if (set_addon_filename(context, filename, index) != 0)
824 return 1;
825
826 PARSE_COMMA(1);
827
828 rest = parse_string(rest, u_name, 3);
829 if (rest == NULL) {
830 printf("Unique name should be 3 characters.\n");
831 return 1;
832 }
833 if (set_unique_name(context, u_name, index) != 0)
834 return 1;
835
836 PARSE_COMMA(1);
837
838 rest = parse_u32(rest, &item_attr);
839 if (rest == NULL)
840 return 1;
841 if (set_addon_attr(context, item_attr, index) != 0)
842 return 1;
843
844 PARSE_COMMA(1);
845
846 if (*rest == '0' && (*(rest + 1) == 'x' ||*(rest + 1) == 'X')) {
847 rest = parse_u32(rest, &others);
848 if (set_other_field(context, NULL, others, index) != 0)
849 return 1;
850 } else {
851 rest = parse_string(rest, other_str, 16);
852 if (set_other_field(context, other_str, 0, index) != 0)
853 return 1;
854 }
855 if (rest == NULL)
856 return 1;
857
858 PARSE_COMMA(1);
859
860 rest = parse_end_state(rest, e_state, MAX_STR_LEN);
861 if (rest == NULL)
862 return 1;
863 if (strncmp(e_state, "Complete", strlen("Complete")))
864 return 1;
865 return 0;
866}
867
Peer Chen7557d9b2011-02-24 09:29:23 -0800868static int
869parse_dev_param(build_image_context *context, parse_token token, char *rest)
870{
871 u_int32_t i;
872 u_int32_t value;
873 field_item *field;
874 u_int32_t index;
875 parse_subfield_item *device_item = NULL;
876
877 assert(context != NULL);
878 assert(rest != NULL);
879
880 /* Parse the index. */
881 rest = parse_u32(rest, &index);
882 if (rest == NULL)
883 return 1;
884
885 /* Parse the closing bracket. */
886 if (*rest != ']')
887 return 1;
888 rest++;
889
890 /* Parse the following '.' */
891 if (*rest != '.')
892 return 1;
893 rest++;
894
895 /* Parse the device name. */
896 for (i = 0; s_device_type_table[i].prefix != NULL; i++) {
897 if (!strncmp(s_device_type_table[i].prefix,
898 rest, strlen(s_device_type_table[i].prefix))) {
899
900 device_item = &(s_device_type_table[i]);
901 rest = rest + strlen(s_device_type_table[i].prefix);
902
903 /* Parse the field name. */
904 rest = parse_field_name(rest,
905 s_device_type_table[i].field_table,
906 &field);
907 if (rest == NULL)
908 return 1;
909
910 /* Parse the equals sign.*/
911 if (*rest != '=')
912 return 1;
913 rest++;
914
915 /* Parse the value based on the field table. */
916 rest = parse_field_value(context, rest, field, &value);
917 if (rest == NULL)
918 return 1;
919 return device_item->process(context,
920 index, field->token, value);
921 }
922 }
923
924 return 1;
925
926}
Peer Chen3a834ed2011-03-04 09:30:05 -0800927
928static int
929parse_sdram_param(build_image_context *context, parse_token token, char *rest)
930{
931 u_int32_t value;
932 field_item *field;
933 u_int32_t index;
934
935 assert(context != NULL);
936 assert(rest != NULL);
937
938 /* Parse the index. */
939 rest = parse_u32(rest, &index);
940 if (rest == NULL)
941 return 1;
942
943 /* Parse the closing bracket. */
944 if (*rest != ']')
945 return 1;
946 rest++;
947
948 /* Parse the following '.' */
949 if (*rest != '.')
950 return 1;
951 rest++;
952
953 /* Parse the field name. */
954 rest = parse_field_name(rest, s_sdram_field_table, &field);
955 if (rest == NULL)
956 return 1;
957
958 /* Parse the equals sign.*/
959 if (*rest != '=')
960 return 1;
961 rest++;
962
963 /* Parse the value based on the field table. */
964 rest = parse_field_value(context, rest, field, &value);
965 if (rest == NULL)
966 return 1;
967
968 /* Store the result. */
969 return set_sdram_param(context, index, field->token, value);
970
971}
Peer Chen8d782ee2011-01-18 21:34:18 -0500972/* Return 0 on success, 1 on error */
973static int
974process_statement(build_image_context *context, char *statement)
975{
976 int i;
977 char *rest;
978
979 for (i = 0; s_top_level_items[i].prefix != NULL; i++) {
980 if (!strncmp(s_top_level_items[i].prefix, statement,
981 strlen(s_top_level_items[i].prefix))) {
982 rest = statement + strlen(s_top_level_items[i].prefix);
983
984 return s_top_level_items[i].process(context,
985 s_top_level_items[i].token,
986 rest);
987 }
988 }
989
990 /* If this point was reached, there was a processing error. */
991 return 1;
992}
993
994/* Note: Basic parsing borrowed from nvcamera_config.c */
995void process_config_file(build_image_context *context)
996{
997 char buffer[MAX_BUFFER];
998 int space = 0;
999 char current;
1000 u_int8_t c_eol_comment_start = 0; // True after first slash
1001 u_int8_t comment = 0;
1002 u_int8_t string = 0;
1003 u_int8_t equal_encounter = 0;
1004
1005 assert(context != NULL);
1006 assert(context->config_file != NULL);
1007
1008 while ((current = fgetc(context->config_file)) !=EOF) {
1009 if (space >= (MAX_BUFFER-1)) {
1010 /* if we exceeded the max buffer size, it is likely
1011 due to a missing semi-colon at the end of a line */
1012 printf("Config file parsing error!");
1013 exit(1);
1014 }
1015
1016 /* Handle failure to complete "//" comment token.
1017 Insert the '/' into the busffer and proceed with
1018 processing the current character. */
1019 if (c_eol_comment_start && current != '/') {
1020 c_eol_comment_start = 0;
1021 buffer[space++] = '/';
1022 }
1023
1024 switch (current) {
1025 case '\"': /* " indicates start or end of a string */
1026 if (!comment) {
1027 string ^= 1;
1028 buffer[space++] = current;
1029 }
1030 break;
1031 case ';':
1032 if (!string && !comment) {
1033 buffer[space++] = '\0';
1034
1035 /* Process a statement. */
1036 if (process_statement(context, buffer)) {
1037 goto error;
1038 }
1039 space = 0;
1040 equal_encounter = 0;
1041 } else if (string) {
1042 buffer[space++] = current;
1043 }
1044 break;
1045
1046 case '/':
1047 if (!string && !comment) {
1048 if (c_eol_comment_start) {
1049 /* EOL comment started. */
1050 comment = 1;
1051 c_eol_comment_start = 0;
1052 } else {
1053 /* Potential start of eol comment. */
1054 c_eol_comment_start = 1;
1055 }
1056 } else if (!comment) {
1057 buffer[space++] = current;
1058 }
1059 break;
1060
1061 /* ignore whitespace. uses fallthrough */
1062 case '\n':
1063 case '\r': /* carriage returns end comments */
1064 string = 0;
1065 comment = 0;
1066 c_eol_comment_start = 0;
1067 case ' ':
1068 case '\t':
1069 if (string) {
1070 buffer[space++] = current;
1071 }
1072 break;
1073
1074 case '#':
1075 if (!string) {
1076 comment = 1;
1077 } else {
1078 buffer[space++] = current;
1079 }
1080 break;
1081
1082 default:
1083 if (!comment) {
1084 buffer[space++] = current;
1085 if (current == '=') {
1086 if (!equal_encounter) {
1087 equal_encounter = 1;
1088 } else {
1089 goto error;
1090 }
1091 }
1092 }
1093 break;
1094 }
1095 }
1096
1097 return;
1098
1099 error:
1100 printf("Error parsing: %s\n", buffer);
1101 exit(1);
1102}